Bitcoin ABC  0.26.3
P2P Digital Currency
blockchain.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2019 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include <rpc/blockchain.h>
7 
8 #include <blockfilter.h>
9 #include <chain.h>
10 #include <chainparams.h>
11 #include <coins.h>
12 #include <common/args.h>
13 #include <config.h>
14 #include <consensus/amount.h>
15 #include <consensus/params.h>
16 #include <consensus/validation.h>
17 #include <core_io.h>
18 #include <hash.h>
19 #include <index/blockfilterindex.h>
20 #include <index/coinstatsindex.h>
21 #include <logging/timer.h>
22 #include <net.h>
23 #include <net_processing.h>
24 #include <node/blockstorage.h>
25 #include <node/coinstats.h>
26 #include <node/context.h>
27 #include <node/utxo_snapshot.h>
28 #include <primitives/transaction.h>
29 #include <rpc/server.h>
30 #include <rpc/server_util.h>
31 #include <rpc/util.h>
32 #include <script/descriptor.h>
33 #include <streams.h>
34 #include <txdb.h>
35 #include <txmempool.h>
36 #include <undo.h>
37 #include <util/check.h>
38 #include <util/fs.h>
39 #include <util/strencodings.h>
40 #include <util/translation.h>
41 #include <validation.h>
42 #include <validationinterface.h>
43 #include <warnings.h>
44 
45 #include <condition_variable>
46 #include <cstdint>
47 #include <memory>
48 #include <mutex>
49 
52 
53 using node::BlockManager;
54 using node::GetUTXOStats;
55 using node::NodeContext;
57 
58 struct CUpdatedBlock {
60  int height;
61 };
62 
64 static std::condition_variable cond_blockchange;
66 
70 double GetDifficulty(const CBlockIndex *blockindex) {
71  CHECK_NONFATAL(blockindex);
72 
73  int nShift = (blockindex->nBits >> 24) & 0xff;
74  double dDiff = double(0x0000ffff) / double(blockindex->nBits & 0x00ffffff);
75 
76  while (nShift < 29) {
77  dDiff *= 256.0;
78  nShift++;
79  }
80  while (nShift > 29) {
81  dDiff /= 256.0;
82  nShift--;
83  }
84 
85  return dDiff;
86 }
87 
88 static int ComputeNextBlockAndDepth(const CBlockIndex *tip,
89  const CBlockIndex *blockindex,
90  const CBlockIndex *&next) {
91  next = tip->GetAncestor(blockindex->nHeight + 1);
92  if (next && next->pprev == blockindex) {
93  return tip->nHeight - blockindex->nHeight + 1;
94  }
95  next = nullptr;
96  return blockindex == tip ? 1 : -1;
97 }
98 
99 static const CBlockIndex *ParseHashOrHeight(const UniValue &param,
100  ChainstateManager &chainman) {
101  LOCK(::cs_main);
102  CChain &active_chain = chainman.ActiveChain();
103 
104  if (param.isNum()) {
105  const int height{param.getInt<int>()};
106  if (height < 0) {
107  throw JSONRPCError(
109  strprintf("Target block height %d is negative", height));
110  }
111  const int current_tip{active_chain.Height()};
112  if (height > current_tip) {
113  throw JSONRPCError(
115  strprintf("Target block height %d after current tip %d", height,
116  current_tip));
117  }
118 
119  return active_chain[height];
120  } else {
121  const BlockHash hash{ParseHashV(param, "hash_or_height")};
122  const CBlockIndex *pindex = chainman.m_blockman.LookupBlockIndex(hash);
123 
124  if (!pindex) {
125  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
126  }
127 
128  return pindex;
129  }
130 }
132  const CBlockIndex *blockindex) {
133  // Serialize passed information without accessing chain state of the active
134  // chain!
135  // For performance reasons
137 
138  UniValue result(UniValue::VOBJ);
139  result.pushKV("hash", blockindex->GetBlockHash().GetHex());
140  const CBlockIndex *pnext;
141  int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
142  result.pushKV("confirmations", confirmations);
143  result.pushKV("height", blockindex->nHeight);
144  result.pushKV("version", blockindex->nVersion);
145  result.pushKV("versionHex", strprintf("%08x", blockindex->nVersion));
146  result.pushKV("merkleroot", blockindex->hashMerkleRoot.GetHex());
147  result.pushKV("time", int64_t(blockindex->nTime));
148  result.pushKV("mediantime", int64_t(blockindex->GetMedianTimePast()));
149  result.pushKV("nonce", uint64_t(blockindex->nNonce));
150  result.pushKV("bits", strprintf("%08x", blockindex->nBits));
151  result.pushKV("difficulty", GetDifficulty(blockindex));
152  result.pushKV("chainwork", blockindex->nChainWork.GetHex());
153  result.pushKV("nTx", uint64_t(blockindex->nTx));
154 
155  if (blockindex->pprev) {
156  result.pushKV("previousblockhash",
157  blockindex->pprev->GetBlockHash().GetHex());
158  }
159  if (pnext) {
160  result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
161  }
162  return result;
163 }
164 
165 UniValue blockToJSON(BlockManager &blockman, const CBlock &block,
166  const CBlockIndex *tip, const CBlockIndex *blockindex,
167  bool txDetails) {
168  UniValue result = blockheaderToJSON(tip, blockindex);
169 
170  result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION));
172  if (txDetails) {
173  CBlockUndo blockUndo;
174  const bool is_not_pruned{
175  WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))};
176  const bool have_undo{is_not_pruned &&
177  blockman.UndoReadFromDisk(blockUndo, *blockindex)};
178  for (size_t i = 0; i < block.vtx.size(); ++i) {
179  const CTransactionRef &tx = block.vtx.at(i);
180  // coinbase transaction (i == 0) doesn't have undo data
181  const CTxUndo *txundo =
182  (have_undo && i) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
183  UniValue objTx(UniValue::VOBJ);
184  TxToUniv(*tx, BlockHash(), objTx, true, RPCSerializationFlags(),
185  txundo);
186  txs.push_back(objTx);
187  }
188  } else {
189  for (const CTransactionRef &tx : block.vtx) {
190  txs.push_back(tx->GetId().GetHex());
191  }
192  }
193  result.pushKV("tx", txs);
194 
195  return result;
196 }
197 
199  return RPCHelpMan{
200  "getblockcount",
201  "Returns the height of the most-work fully-validated chain.\n"
202  "The genesis block has height 0.\n",
203  {},
204  RPCResult{RPCResult::Type::NUM, "", "The current block count"},
205  RPCExamples{HelpExampleCli("getblockcount", "") +
206  HelpExampleRpc("getblockcount", "")},
207  [&](const RPCHelpMan &self, const Config &config,
208  const JSONRPCRequest &request) -> UniValue {
209  ChainstateManager &chainman = EnsureAnyChainman(request.context);
210  LOCK(cs_main);
211  return chainman.ActiveHeight();
212  },
213  };
214 }
215 
217  return RPCHelpMan{
218  "getbestblockhash",
219  "Returns the hash of the best (tip) block in the "
220  "most-work fully-validated chain.\n",
221  {},
222  RPCResult{RPCResult::Type::STR_HEX, "", "the block hash, hex-encoded"},
223  RPCExamples{HelpExampleCli("getbestblockhash", "") +
224  HelpExampleRpc("getbestblockhash", "")},
225  [&](const RPCHelpMan &self, const Config &config,
226  const JSONRPCRequest &request) -> UniValue {
227  ChainstateManager &chainman = EnsureAnyChainman(request.context);
228  LOCK(cs_main);
229  return chainman.ActiveTip()->GetBlockHash().GetHex();
230  },
231  };
232 }
233 
234 void RPCNotifyBlockChange(const CBlockIndex *pindex) {
235  if (pindex) {
237  latestblock.hash = pindex->GetBlockHash();
238  latestblock.height = pindex->nHeight;
239  }
240  cond_blockchange.notify_all();
241 }
242 
244  return RPCHelpMan{
245  "waitfornewblock",
246  "Waits for a specific new block and returns useful info about it.\n"
247  "\nReturns the current block on timeout or exit.\n",
248  {
249  {"timeout", RPCArg::Type::NUM, RPCArg::Default{0},
250  "Time in milliseconds to wait for a response. 0 indicates no "
251  "timeout."},
252  },
254  "",
255  "",
256  {
257  {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
258  {RPCResult::Type::NUM, "height", "Block height"},
259  }},
260  RPCExamples{HelpExampleCli("waitfornewblock", "1000") +
261  HelpExampleRpc("waitfornewblock", "1000")},
262  [&](const RPCHelpMan &self, const Config &config,
263  const JSONRPCRequest &request) -> UniValue {
264  int timeout = 0;
265  if (!request.params[0].isNull()) {
266  timeout = request.params[0].getInt<int>();
267  }
268 
269  CUpdatedBlock block;
270  {
271  WAIT_LOCK(cs_blockchange, lock);
272  block = latestblock;
273  if (timeout) {
274  cond_blockchange.wait_for(
275  lock, std::chrono::milliseconds(timeout),
277  return latestblock.height != block.height ||
278  latestblock.hash != block.hash ||
279  !IsRPCRunning();
280  });
281  } else {
282  cond_blockchange.wait(
283  lock,
285  return latestblock.height != block.height ||
286  latestblock.hash != block.hash ||
287  !IsRPCRunning();
288  });
289  }
290  block = latestblock;
291  }
293  ret.pushKV("hash", block.hash.GetHex());
294  ret.pushKV("height", block.height);
295  return ret;
296  },
297  };
298 }
299 
301  return RPCHelpMan{
302  "waitforblock",
303  "Waits for a specific new block and returns useful info about it.\n"
304  "\nReturns the current block on timeout or exit.\n",
305  {
307  "Block hash to wait for."},
308  {"timeout", RPCArg::Type::NUM, RPCArg::Default{0},
309  "Time in milliseconds to wait for a response. 0 indicates no "
310  "timeout."},
311  },
313  "",
314  "",
315  {
316  {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
317  {RPCResult::Type::NUM, "height", "Block height"},
318  }},
319  RPCExamples{HelpExampleCli("waitforblock",
320  "\"0000000000079f8ef3d2c688c244eb7a4570b24c9"
321  "ed7b4a8c619eb02596f8862\" 1000") +
322  HelpExampleRpc("waitforblock",
323  "\"0000000000079f8ef3d2c688c244eb7a4570b24c9"
324  "ed7b4a8c619eb02596f8862\", 1000")},
325  [&](const RPCHelpMan &self, const Config &config,
326  const JSONRPCRequest &request) -> UniValue {
327  int timeout = 0;
328 
329  BlockHash hash(ParseHashV(request.params[0], "blockhash"));
330 
331  if (!request.params[1].isNull()) {
332  timeout = request.params[1].getInt<int>();
333  }
334 
335  CUpdatedBlock block;
336  {
337  WAIT_LOCK(cs_blockchange, lock);
338  if (timeout) {
339  cond_blockchange.wait_for(
340  lock, std::chrono::milliseconds(timeout),
342  return latestblock.hash == hash || !IsRPCRunning();
343  });
344  } else {
345  cond_blockchange.wait(
346  lock,
348  return latestblock.hash == hash || !IsRPCRunning();
349  });
350  }
351  block = latestblock;
352  }
353 
355  ret.pushKV("hash", block.hash.GetHex());
356  ret.pushKV("height", block.height);
357  return ret;
358  },
359  };
360 }
361 
363  return RPCHelpMan{
364  "waitforblockheight",
365  "Waits for (at least) block height and returns the height and "
366  "hash\nof the current tip.\n"
367  "\nReturns the current block on timeout or exit.\n",
368  {
370  "Block height to wait for."},
371  {"timeout", RPCArg::Type::NUM, RPCArg::Default{0},
372  "Time in milliseconds to wait for a response. 0 indicates no "
373  "timeout."},
374  },
376  "",
377  "",
378  {
379  {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
380  {RPCResult::Type::NUM, "height", "Block height"},
381  }},
382  RPCExamples{HelpExampleCli("waitforblockheight", "100 1000") +
383  HelpExampleRpc("waitforblockheight", "100, 1000")},
384  [&](const RPCHelpMan &self, const Config &config,
385  const JSONRPCRequest &request) -> UniValue {
386  int timeout = 0;
387 
388  int height = request.params[0].getInt<int>();
389 
390  if (!request.params[1].isNull()) {
391  timeout = request.params[1].getInt<int>();
392  }
393 
394  CUpdatedBlock block;
395  {
396  WAIT_LOCK(cs_blockchange, lock);
397  if (timeout) {
398  cond_blockchange.wait_for(
399  lock, std::chrono::milliseconds(timeout),
401  return latestblock.height >= height ||
402  !IsRPCRunning();
403  });
404  } else {
405  cond_blockchange.wait(
406  lock,
408  return latestblock.height >= height ||
409  !IsRPCRunning();
410  });
411  }
412  block = latestblock;
413  }
415  ret.pushKV("hash", block.hash.GetHex());
416  ret.pushKV("height", block.height);
417  return ret;
418  },
419  };
420 }
421 
423  return RPCHelpMan{
424  "syncwithvalidationinterfacequeue",
425  "Waits for the validation interface queue to catch up on everything "
426  "that was there when we entered this function.\n",
427  {},
429  RPCExamples{HelpExampleCli("syncwithvalidationinterfacequeue", "") +
430  HelpExampleRpc("syncwithvalidationinterfacequeue", "")},
431  [&](const RPCHelpMan &self, const Config &config,
432  const JSONRPCRequest &request) -> UniValue {
434  return NullUniValue;
435  },
436  };
437 }
438 
440  return RPCHelpMan{
441  "getdifficulty",
442  "Returns the proof-of-work difficulty as a multiple of the minimum "
443  "difficulty.\n",
444  {},
446  "the proof-of-work difficulty as a multiple of the minimum "
447  "difficulty."},
448  RPCExamples{HelpExampleCli("getdifficulty", "") +
449  HelpExampleRpc("getdifficulty", "")},
450  [&](const RPCHelpMan &self, const Config &config,
451  const JSONRPCRequest &request) -> UniValue {
452  ChainstateManager &chainman = EnsureAnyChainman(request.context);
453  LOCK(cs_main);
454  return GetDifficulty(chainman.ActiveTip());
455  },
456  };
457 }
458 
460  return RPCHelpMan{
461  "getblockfrompeer",
462  "Attempt to fetch block from a given peer.\n"
463  "\nWe must have the header for this block, e.g. using submitheader.\n"
464  "Subsequent calls for the same block and a new peer will cause the "
465  "response from the previous peer to be ignored.\n"
466  "\nReturns an empty JSON object if the request was successfully "
467  "scheduled.",
468  {
470  "The block hash to try to fetch"},
472  "The peer to fetch it from (see getpeerinfo for peer IDs)"},
473  },
474  RPCResult{RPCResult::Type::OBJ, "", /*optional=*/false, "", {}},
475  RPCExamples{HelpExampleCli("getblockfrompeer",
476  "\"00000000c937983704a73af28acdec37b049d214a"
477  "dbda81d7e2a3dd146f6ed09\" 0") +
478  HelpExampleRpc("getblockfrompeer",
479  "\"00000000c937983704a73af28acdec37b049d214a"
480  "dbda81d7e2a3dd146f6ed09\" 0")},
481  [&](const RPCHelpMan &self, const Config &config,
482  const JSONRPCRequest &request) -> UniValue {
483  const NodeContext &node = EnsureAnyNodeContext(request.context);
485  PeerManager &peerman = EnsurePeerman(node);
486 
487  const BlockHash block_hash{
488  ParseHashV(request.params[0], "blockhash")};
489  const NodeId peer_id{request.params[1].getInt<int64_t>()};
490 
491  const CBlockIndex *const index = WITH_LOCK(
492  cs_main,
493  return chainman.m_blockman.LookupBlockIndex(block_hash););
494 
495  if (!index) {
496  throw JSONRPCError(RPC_MISC_ERROR, "Block header missing");
497  }
498 
499  if (WITH_LOCK(::cs_main, return index->nStatus.hasData())) {
500  throw JSONRPCError(RPC_MISC_ERROR, "Block already downloaded");
501  }
502 
503  if (const auto err{peerman.FetchBlock(config, peer_id, *index)}) {
504  throw JSONRPCError(RPC_MISC_ERROR, err.value());
505  }
506  return UniValue::VOBJ;
507  },
508  };
509 }
510 
512  return RPCHelpMan{
513  "getblockhash",
514  "Returns hash of block in best-block-chain at height provided.\n",
515  {
517  "The height index"},
518  },
519  RPCResult{RPCResult::Type::STR_HEX, "", "The block hash"},
520  RPCExamples{HelpExampleCli("getblockhash", "1000") +
521  HelpExampleRpc("getblockhash", "1000")},
522  [&](const RPCHelpMan &self, const Config &config,
523  const JSONRPCRequest &request) -> UniValue {
524  ChainstateManager &chainman = EnsureAnyChainman(request.context);
525  LOCK(cs_main);
526  const CChain &active_chain = chainman.ActiveChain();
527 
528  int nHeight = request.params[0].getInt<int>();
529  if (nHeight < 0 || nHeight > active_chain.Height()) {
531  "Block height out of range");
532  }
533 
534  const CBlockIndex *pblockindex = active_chain[nHeight];
535  return pblockindex->GetBlockHash().GetHex();
536  },
537  };
538 }
539 
541  return RPCHelpMan{
542  "getblockheader",
543  "If verbose is false, returns a string that is serialized, hex-encoded "
544  "data for blockheader 'hash'.\n"
545  "If verbose is true, returns an Object with information about "
546  "blockheader <hash>.\n",
547  {
549  "The block hash"},
550  {"verbose", RPCArg::Type::BOOL, RPCArg::Default{true},
551  "true for a json object, false for the hex-encoded data"},
552  },
553  {
554  RPCResult{
555  "for verbose = true",
557  "",
558  "",
559  {
560  {RPCResult::Type::STR_HEX, "hash",
561  "the block hash (same as provided)"},
562  {RPCResult::Type::NUM, "confirmations",
563  "The number of confirmations, or -1 if the block is not "
564  "on the main chain"},
565  {RPCResult::Type::NUM, "height",
566  "The block height or index"},
567  {RPCResult::Type::NUM, "version", "The block version"},
568  {RPCResult::Type::STR_HEX, "versionHex",
569  "The block version formatted in hexadecimal"},
570  {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
571  {RPCResult::Type::NUM_TIME, "time",
572  "The block time expressed in " + UNIX_EPOCH_TIME},
573  {RPCResult::Type::NUM_TIME, "mediantime",
574  "The median block time expressed in " + UNIX_EPOCH_TIME},
575  {RPCResult::Type::NUM, "nonce", "The nonce"},
576  {RPCResult::Type::STR_HEX, "bits", "The bits"},
577  {RPCResult::Type::NUM, "difficulty", "The difficulty"},
578  {RPCResult::Type::STR_HEX, "chainwork",
579  "Expected number of hashes required to produce the "
580  "current chain"},
581  {RPCResult::Type::NUM, "nTx",
582  "The number of transactions in the block"},
583  {RPCResult::Type::STR_HEX, "previousblockhash",
584  /* optional */ true,
585  "The hash of the previous block (if available)"},
586  {RPCResult::Type::STR_HEX, "nextblockhash",
587  /* optional */ true,
588  "The hash of the next block (if available)"},
589  }},
590  RPCResult{"for verbose=false", RPCResult::Type::STR_HEX, "",
591  "A string that is serialized, hex-encoded data for block "
592  "'hash'"},
593  },
594  RPCExamples{HelpExampleCli("getblockheader",
595  "\"00000000c937983704a73af28acdec37b049d214a"
596  "dbda81d7e2a3dd146f6ed09\"") +
597  HelpExampleRpc("getblockheader",
598  "\"00000000c937983704a73af28acdec37b049d214a"
599  "dbda81d7e2a3dd146f6ed09\"")},
600  [&](const RPCHelpMan &self, const Config &config,
601  const JSONRPCRequest &request) -> UniValue {
602  BlockHash hash(ParseHashV(request.params[0], "hash"));
603 
604  bool fVerbose = true;
605  if (!request.params[1].isNull()) {
606  fVerbose = request.params[1].get_bool();
607  }
608 
609  const CBlockIndex *pblockindex;
610  const CBlockIndex *tip;
611  {
612  ChainstateManager &chainman =
613  EnsureAnyChainman(request.context);
614  LOCK(cs_main);
615  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
616  tip = chainman.ActiveTip();
617  }
618 
619  if (!pblockindex) {
621  "Block not found");
622  }
623 
624  if (!fVerbose) {
626  ssBlock << pblockindex->GetBlockHeader();
627  std::string strHex = HexStr(ssBlock);
628  return strHex;
629  }
630 
631  return blockheaderToJSON(tip, pblockindex);
632  },
633  };
634 }
635 
637  const CBlockIndex *pblockindex) {
638  CBlock block;
639  {
640  LOCK(cs_main);
641  if (blockman.IsBlockPruned(pblockindex)) {
643  "Block not available (pruned data)");
644  }
645  }
646 
647  if (!blockman.ReadBlockFromDisk(block, *pblockindex)) {
648  // Block not found on disk. This could be because we have the block
649  // header in our index but not yet have the block or did not accept the
650  // block. Or if the block was pruned right after we released the lock
651  // above.
652  throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
653  }
654 
655  return block;
656 }
657 
659  const CBlockIndex *pblockindex) {
660  CBlockUndo blockUndo;
661 
662  {
663  LOCK(cs_main);
664  if (blockman.IsBlockPruned(pblockindex)) {
666  "Undo data not available (pruned data)");
667  }
668  }
669 
670  if (!blockman.UndoReadFromDisk(blockUndo, *pblockindex)) {
671  throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
672  }
673 
674  return blockUndo;
675 }
676 
678  return RPCHelpMan{
679  "getblock",
680  "If verbosity is 0 or false, returns a string that is serialized, "
681  "hex-encoded data for block 'hash'.\n"
682  "If verbosity is 1 or true, returns an Object with information about "
683  "block <hash>.\n"
684  "If verbosity is 2, returns an Object with information about block "
685  "<hash> and information about each transaction.\n",
686  {
688  "The block hash"},
689  {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1},
690  "0 for hex-encoded data, 1 for a json object, and 2 for json "
691  "object with transaction data",
692  RPCArgOptions{.skip_type_check = true}},
693  },
694  {
695  RPCResult{"for verbosity = 0", RPCResult::Type::STR_HEX, "",
696  "A string that is serialized, hex-encoded data for block "
697  "'hash'"},
698  RPCResult{
699  "for verbosity = 1",
701  "",
702  "",
703  {
704  {RPCResult::Type::STR_HEX, "hash",
705  "the block hash (same as provided)"},
706  {RPCResult::Type::NUM, "confirmations",
707  "The number of confirmations, or -1 if the block is not "
708  "on the main chain"},
709  {RPCResult::Type::NUM, "size", "The block size"},
710  {RPCResult::Type::NUM, "height",
711  "The block height or index"},
712  {RPCResult::Type::NUM, "version", "The block version"},
713  {RPCResult::Type::STR_HEX, "versionHex",
714  "The block version formatted in hexadecimal"},
715  {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
717  "tx",
718  "The transaction ids",
719  {{RPCResult::Type::STR_HEX, "", "The transaction id"}}},
720  {RPCResult::Type::NUM_TIME, "time",
721  "The block time expressed in " + UNIX_EPOCH_TIME},
722  {RPCResult::Type::NUM_TIME, "mediantime",
723  "The median block time expressed in " + UNIX_EPOCH_TIME},
724  {RPCResult::Type::NUM, "nonce", "The nonce"},
725  {RPCResult::Type::STR_HEX, "bits", "The bits"},
726  {RPCResult::Type::NUM, "difficulty", "The difficulty"},
727  {RPCResult::Type::STR_HEX, "chainwork",
728  "Expected number of hashes required to produce the chain "
729  "up to this block (in hex)"},
730  {RPCResult::Type::NUM, "nTx",
731  "The number of transactions in the block"},
732  {RPCResult::Type::STR_HEX, "previousblockhash",
733  /* optional */ true,
734  "The hash of the previous block (if available)"},
735  {RPCResult::Type::STR_HEX, "nextblockhash",
736  /* optional */ true,
737  "The hash of the next block (if available)"},
738  }},
739  RPCResult{"for verbosity = 2",
741  "",
742  "",
743  {
745  "Same output as verbosity = 1"},
747  "tx",
748  "",
749  {
751  "",
752  "",
753  {
755  "The transactions in the format of the "
756  "getrawtransaction RPC. Different from "
757  "verbosity = 1 \"tx\" result"},
759  "The transaction fee in " +
761  ", omitted if block undo data is not "
762  "available"},
763  }},
764  }},
765  }},
766  },
767  RPCExamples{
768  HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d"
769  "214adbda81d7e2a3dd146f6ed09\"") +
770  HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d"
771  "214adbda81d7e2a3dd146f6ed09\"")},
772  [&](const RPCHelpMan &self, const Config &config,
773  const JSONRPCRequest &request) -> UniValue {
774  BlockHash hash(ParseHashV(request.params[0], "blockhash"));
775 
776  int verbosity = 1;
777  if (!request.params[1].isNull()) {
778  if (request.params[1].isNum()) {
779  verbosity = request.params[1].getInt<int>();
780  } else {
781  verbosity = request.params[1].get_bool() ? 1 : 0;
782  }
783  }
784 
785  const CBlockIndex *pblockindex;
786  const CBlockIndex *tip;
787  ChainstateManager &chainman = EnsureAnyChainman(request.context);
788  {
789  LOCK(cs_main);
790  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
791  tip = chainman.ActiveTip();
792 
793  if (!pblockindex) {
795  "Block not found");
796  }
797  }
798 
799  const CBlock block =
800  GetBlockChecked(chainman.m_blockman, pblockindex);
801 
802  if (verbosity <= 0) {
803  CDataStream ssBlock(SER_NETWORK,
805  ssBlock << block;
806  std::string strHex = HexStr(ssBlock);
807  return strHex;
808  }
809 
810  return blockToJSON(chainman.m_blockman, block, tip, pblockindex,
811  verbosity >= 2);
812  },
813  };
814 }
815 
817  return RPCHelpMan{
818  "pruneblockchain",
819  "",
820  {
822  "The block height to prune up to. May be set to a discrete "
823  "height, or to a " +
825  "\n"
826  " to prune blocks whose block time is at "
827  "least 2 hours older than the provided timestamp."},
828  },
829  RPCResult{RPCResult::Type::NUM, "", "Height of the last block pruned"},
830  RPCExamples{HelpExampleCli("pruneblockchain", "1000") +
831  HelpExampleRpc("pruneblockchain", "1000")},
832  [&](const RPCHelpMan &self, const Config &config,
833  const JSONRPCRequest &request) -> UniValue {
834  ChainstateManager &chainman = EnsureAnyChainman(request.context);
835  if (!chainman.m_blockman.IsPruneMode()) {
836  throw JSONRPCError(
838  "Cannot prune blocks because node is not in prune mode.");
839  }
840 
841  LOCK(cs_main);
842  Chainstate &active_chainstate = chainman.ActiveChainstate();
843  CChain &active_chain = active_chainstate.m_chain;
844 
845  int heightParam = request.params[0].getInt<int>();
846  if (heightParam < 0) {
848  "Negative block height.");
849  }
850 
851  // Height value more than a billion is too high to be a block
852  // height, and too low to be a block time (corresponds to timestamp
853  // from Sep 2001).
854  if (heightParam > 1000000000) {
855  // Add a 2 hour buffer to include blocks which might have had
856  // old timestamps
857  const CBlockIndex *pindex = active_chain.FindEarliestAtLeast(
858  heightParam - TIMESTAMP_WINDOW, 0);
859  if (!pindex) {
861  "Could not find block with at least the "
862  "specified timestamp.");
863  }
864  heightParam = pindex->nHeight;
865  }
866 
867  unsigned int height = (unsigned int)heightParam;
868  unsigned int chainHeight = (unsigned int)active_chain.Height();
869  if (chainHeight < config.GetChainParams().PruneAfterHeight()) {
871  "Blockchain is too short for pruning.");
872  } else if (height > chainHeight) {
873  throw JSONRPCError(
875  "Blockchain is shorter than the attempted prune height.");
876  } else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
878  "Attempt to prune blocks close to the tip. "
879  "Retaining the minimum number of blocks.\n");
880  height = chainHeight - MIN_BLOCKS_TO_KEEP;
881  }
882 
883  PruneBlockFilesManual(active_chainstate, height);
884  const CBlockIndex &block{*CHECK_NONFATAL(active_chain.Tip())};
885  const CBlockIndex *last_block{
886  active_chainstate.m_blockman.GetFirstStoredBlock(block)};
887 
888  return static_cast<uint64_t>(last_block->nHeight);
889  },
890  };
891 }
892 
893 static CoinStatsHashType ParseHashType(const std::string &hash_type_input) {
894  if (hash_type_input == "hash_serialized") {
895  return CoinStatsHashType::HASH_SERIALIZED;
896  } else if (hash_type_input == "muhash") {
897  return CoinStatsHashType::MUHASH;
898  } else if (hash_type_input == "none") {
900  } else {
901  throw JSONRPCError(
903  strprintf("%s is not a valid hash_type", hash_type_input));
904  }
905 }
906 
908  return RPCHelpMan{
909  "gettxoutsetinfo",
910  "Returns statistics about the unspent transaction output set.\n"
911  "Note this call may take some time if you are not using "
912  "coinstatsindex.\n",
913  {
914  {"hash_type", RPCArg::Type::STR, RPCArg::Default{"hash_serialized"},
915  "Which UTXO set hash should be calculated. Options: "
916  "'hash_serialized' (the legacy algorithm), 'muhash', 'none'."},
917  {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::OMITTED,
918  "The block hash or height of the target height (only available "
919  "with coinstatsindex).",
921  .type_str = {"", "string or numeric"}}},
922  {"use_index", RPCArg::Type::BOOL, RPCArg::Default{true},
923  "Use coinstatsindex, if available."},
924  },
925  RPCResult{
927  "",
928  "",
929  {
930  {RPCResult::Type::NUM, "height",
931  "The current block height (index)"},
932  {RPCResult::Type::STR_HEX, "bestblock",
933  "The hash of the block at the tip of the chain"},
934  {RPCResult::Type::NUM, "txouts",
935  "The number of unspent transaction outputs"},
936  {RPCResult::Type::NUM, "bogosize",
937  "Database-independent, meaningless metric indicating "
938  "the UTXO set size"},
939  {RPCResult::Type::STR_HEX, "hash_serialized",
940  /* optional */ true,
941  "The serialized hash (only present if 'hash_serialized' "
942  "hash_type is chosen)"},
943  {RPCResult::Type::STR_HEX, "muhash", /* optional */ true,
944  "The serialized hash (only present if 'muhash' "
945  "hash_type is chosen)"},
946  {RPCResult::Type::NUM, "transactions",
947  "The number of transactions with unspent outputs (not "
948  "available when coinstatsindex is used)"},
949  {RPCResult::Type::NUM, "disk_size",
950  "The estimated size of the chainstate on disk (not "
951  "available when coinstatsindex is used)"},
952  {RPCResult::Type::STR_AMOUNT, "total_amount",
953  "The total amount"},
954  {RPCResult::Type::STR_AMOUNT, "total_unspendable_amount",
955  "The total amount of coins permanently excluded from the UTXO "
956  "set (only available if coinstatsindex is used)"},
958  "block_info",
959  "Info on amounts in the block at this block height (only "
960  "available if coinstatsindex is used)",
961  {{RPCResult::Type::STR_AMOUNT, "prevout_spent",
962  "Total amount of all prevouts spent in this block"},
963  {RPCResult::Type::STR_AMOUNT, "coinbase",
964  "Coinbase subsidy amount of this block"},
965  {RPCResult::Type::STR_AMOUNT, "new_outputs_ex_coinbase",
966  "Total amount of new outputs created by this block"},
967  {RPCResult::Type::STR_AMOUNT, "unspendable",
968  "Total amount of unspendable outputs created in this block"},
970  "unspendables",
971  "Detailed view of the unspendable categories",
972  {
973  {RPCResult::Type::STR_AMOUNT, "genesis_block",
974  "The unspendable amount of the Genesis block subsidy"},
975  {RPCResult::Type::STR_AMOUNT, "bip30",
976  "Transactions overridden by duplicates (no longer "
977  "possible with BIP30)"},
978  {RPCResult::Type::STR_AMOUNT, "scripts",
979  "Amounts sent to scripts that are unspendable (for "
980  "example OP_RETURN outputs)"},
981  {RPCResult::Type::STR_AMOUNT, "unclaimed_rewards",
982  "Fee rewards that miners did not claim in their "
983  "coinbase transaction"},
984  }}}},
985  }},
986  RPCExamples{
987  HelpExampleCli("gettxoutsetinfo", "") +
988  HelpExampleCli("gettxoutsetinfo", R"("none")") +
989  HelpExampleCli("gettxoutsetinfo", R"("none" 1000)") +
991  "gettxoutsetinfo",
992  R"("none" '"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"')") +
993  HelpExampleRpc("gettxoutsetinfo", "") +
994  HelpExampleRpc("gettxoutsetinfo", R"("none")") +
995  HelpExampleRpc("gettxoutsetinfo", R"("none", 1000)") +
997  "gettxoutsetinfo",
998  R"("none", "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09")")},
999  [&](const RPCHelpMan &self, const Config &config,
1000  const JSONRPCRequest &request) -> UniValue {
1001  UniValue ret(UniValue::VOBJ);
1002 
1003  const CBlockIndex *pindex{nullptr};
1004  const CoinStatsHashType hash_type{
1005  request.params[0].isNull()
1006  ? CoinStatsHashType::HASH_SERIALIZED
1007  : ParseHashType(request.params[0].get_str())};
1008  bool index_requested =
1009  request.params[2].isNull() || request.params[2].get_bool();
1010 
1011  NodeContext &node = EnsureAnyNodeContext(request.context);
1012  ChainstateManager &chainman = EnsureChainman(node);
1013  Chainstate &active_chainstate = chainman.ActiveChainstate();
1014  active_chainstate.ForceFlushStateToDisk();
1015 
1016  CCoinsView *coins_view;
1017  BlockManager *blockman;
1018  {
1019  LOCK(::cs_main);
1020  coins_view = &active_chainstate.CoinsDB();
1021  blockman = &active_chainstate.m_blockman;
1022  pindex = blockman->LookupBlockIndex(coins_view->GetBestBlock());
1023  }
1024 
1025  if (!request.params[1].isNull()) {
1026  if (!g_coin_stats_index) {
1028  "Querying specific block heights "
1029  "requires coinstatsindex");
1030  }
1031 
1032  if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1034  "hash_serialized hash type cannot be "
1035  "queried for a specific block");
1036  }
1037 
1038  pindex = ParseHashOrHeight(request.params[1], chainman);
1039  }
1040 
1041  if (index_requested && g_coin_stats_index) {
1042  if (!g_coin_stats_index->BlockUntilSyncedToCurrentChain()) {
1043  const IndexSummary summary{
1044  g_coin_stats_index->GetSummary()};
1045 
1046  // If a specific block was requested and the index has
1047  // already synced past that height, we can return the data
1048  // already even though the index is not fully synced yet.
1049  if (pindex->nHeight > summary.best_block_height) {
1050  throw JSONRPCError(
1052  strprintf(
1053  "Unable to get data because coinstatsindex is "
1054  "still syncing. Current height: %d",
1055  summary.best_block_height));
1056  }
1057  }
1058  }
1059 
1060  const std::optional<CCoinsStats> maybe_stats = GetUTXOStats(
1061  coins_view, *blockman, hash_type, node.rpc_interruption_point,
1062  pindex, index_requested);
1063  if (maybe_stats.has_value()) {
1064  const CCoinsStats &stats = maybe_stats.value();
1065  ret.pushKV("height", int64_t(stats.nHeight));
1066  ret.pushKV("bestblock", stats.hashBlock.GetHex());
1067  ret.pushKV("txouts", int64_t(stats.nTransactionOutputs));
1068  ret.pushKV("bogosize", int64_t(stats.nBogoSize));
1069  if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1070  ret.pushKV("hash_serialized",
1071  stats.hashSerialized.GetHex());
1072  }
1073  if (hash_type == CoinStatsHashType::MUHASH) {
1074  ret.pushKV("muhash", stats.hashSerialized.GetHex());
1075  }
1076  ret.pushKV("total_amount", stats.nTotalAmount);
1077  if (!stats.index_used) {
1078  ret.pushKV("transactions",
1079  static_cast<int64_t>(stats.nTransactions));
1080  ret.pushKV("disk_size", stats.nDiskSize);
1081  } else {
1082  ret.pushKV("total_unspendable_amount",
1083  stats.total_unspendable_amount);
1084 
1085  CCoinsStats prev_stats{};
1086  if (pindex->nHeight > 0) {
1087  const std::optional<CCoinsStats> maybe_prev_stats =
1088  GetUTXOStats(coins_view, *blockman, hash_type,
1089  node.rpc_interruption_point,
1090  pindex->pprev, index_requested);
1091  if (!maybe_prev_stats) {
1093  "Unable to read UTXO set");
1094  }
1095  prev_stats = maybe_prev_stats.value();
1096  }
1097 
1098  UniValue block_info(UniValue::VOBJ);
1099  block_info.pushKV(
1100  "prevout_spent",
1102  prev_stats.total_prevout_spent_amount);
1103  block_info.pushKV("coinbase",
1104  stats.total_coinbase_amount -
1105  prev_stats.total_coinbase_amount);
1106  block_info.pushKV(
1107  "new_outputs_ex_coinbase",
1109  prev_stats.total_new_outputs_ex_coinbase_amount);
1110  block_info.pushKV("unspendable",
1111  stats.total_unspendable_amount -
1112  prev_stats.total_unspendable_amount);
1113 
1114  UniValue unspendables(UniValue::VOBJ);
1115  unspendables.pushKV(
1116  "genesis_block",
1118  prev_stats.total_unspendables_genesis_block);
1119  unspendables.pushKV(
1120  "bip30", stats.total_unspendables_bip30 -
1121  prev_stats.total_unspendables_bip30);
1122  unspendables.pushKV(
1123  "scripts", stats.total_unspendables_scripts -
1124  prev_stats.total_unspendables_scripts);
1125  unspendables.pushKV(
1126  "unclaimed_rewards",
1128  prev_stats.total_unspendables_unclaimed_rewards);
1129  block_info.pushKV("unspendables", unspendables);
1130 
1131  ret.pushKV("block_info", block_info);
1132  }
1133  } else {
1135  "Unable to read UTXO set");
1136  }
1137  return ret;
1138  },
1139  };
1140 }
1141 
1143  return RPCHelpMan{
1144  "gettxout",
1145  "Returns details about an unspent transaction output.\n",
1146  {
1148  "The transaction id"},
1149  {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
1150  {"include_mempool", RPCArg::Type::BOOL, RPCArg::Default{true},
1151  "Whether to include the mempool. Note that an unspent output that "
1152  "is spent in the mempool won't appear."},
1153  },
1154  {
1155  RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "",
1156  ""},
1157  RPCResult{
1158  "Otherwise",
1160  "",
1161  "",
1162  {
1163  {RPCResult::Type::STR_HEX, "bestblock",
1164  "The hash of the block at the tip of the chain"},
1165  {RPCResult::Type::NUM, "confirmations",
1166  "The number of confirmations"},
1167  {RPCResult::Type::STR_AMOUNT, "value",
1168  "The transaction value in " + Currency::get().ticker},
1170  "scriptPubKey",
1171  "",
1172  {
1173  {RPCResult::Type::STR_HEX, "asm", ""},
1174  {RPCResult::Type::STR_HEX, "hex", ""},
1175  {RPCResult::Type::NUM, "reqSigs",
1176  "Number of required signatures"},
1177  {RPCResult::Type::STR_HEX, "type",
1178  "The type, eg pubkeyhash"},
1180  "addresses",
1181  "array of eCash addresses",
1182  {{RPCResult::Type::STR, "address", "eCash address"}}},
1183  }},
1184  {RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
1185  }},
1186  },
1187  RPCExamples{"\nGet unspent transactions\n" +
1188  HelpExampleCli("listunspent", "") + "\nView the details\n" +
1189  HelpExampleCli("gettxout", "\"txid\" 1") +
1190  "\nAs a JSON-RPC call\n" +
1191  HelpExampleRpc("gettxout", "\"txid\", 1")},
1192  [&](const RPCHelpMan &self, const Config &config,
1193  const JSONRPCRequest &request) -> UniValue {
1194  NodeContext &node = EnsureAnyNodeContext(request.context);
1195  ChainstateManager &chainman = EnsureChainman(node);
1196  LOCK(cs_main);
1197 
1198  UniValue ret(UniValue::VOBJ);
1199 
1200  TxId txid(ParseHashV(request.params[0], "txid"));
1201  int n = request.params[1].getInt<int>();
1202  COutPoint out(txid, n);
1203  bool fMempool = true;
1204  if (!request.params[2].isNull()) {
1205  fMempool = request.params[2].get_bool();
1206  }
1207 
1208  Coin coin;
1209  Chainstate &active_chainstate = chainman.ActiveChainstate();
1210  CCoinsViewCache *coins_view = &active_chainstate.CoinsTip();
1211 
1212  if (fMempool) {
1213  const CTxMemPool &mempool = EnsureMemPool(node);
1214  LOCK(mempool.cs);
1215  CCoinsViewMemPool view(coins_view, mempool);
1216  if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
1217  return NullUniValue;
1218  }
1219  } else {
1220  if (!coins_view->GetCoin(out, coin)) {
1221  return NullUniValue;
1222  }
1223  }
1224 
1225  const CBlockIndex *pindex =
1226  active_chainstate.m_blockman.LookupBlockIndex(
1227  coins_view->GetBestBlock());
1228  ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
1229  if (coin.GetHeight() == MEMPOOL_HEIGHT) {
1230  ret.pushKV("confirmations", 0);
1231  } else {
1232  ret.pushKV("confirmations",
1233  int64_t(pindex->nHeight - coin.GetHeight() + 1));
1234  }
1235  ret.pushKV("value", coin.GetTxOut().nValue);
1237  ScriptPubKeyToUniv(coin.GetTxOut().scriptPubKey, o, true);
1238  ret.pushKV("scriptPubKey", o);
1239  ret.pushKV("coinbase", coin.IsCoinBase());
1240 
1241  return ret;
1242  },
1243  };
1244 }
1245 
1247  return RPCHelpMan{
1248  "verifychain",
1249  "Verifies blockchain database.\n",
1250  {
1251  {"checklevel", RPCArg::Type::NUM,
1253  strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL)},
1254  strprintf("How thorough the block verification is:\n - %s",
1255  Join(CHECKLEVEL_DOC, "\n- "))},
1256  {"nblocks", RPCArg::Type::NUM,
1258  "The number of blocks to check."},
1259  },
1261  "Verification finished successfully. If false, check "
1262  "debug.log for reason."},
1263  RPCExamples{HelpExampleCli("verifychain", "") +
1264  HelpExampleRpc("verifychain", "")},
1265  [&](const RPCHelpMan &self, const Config &config,
1266  const JSONRPCRequest &request) -> UniValue {
1267  const int check_level{request.params[0].isNull()
1269  : request.params[0].getInt<int>()};
1270  const int check_depth{request.params[1].isNull()
1272  : request.params[1].getInt<int>()};
1273 
1274  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1275  LOCK(cs_main);
1276 
1277  Chainstate &active_chainstate = chainman.ActiveChainstate();
1278  return CVerifyDB(chainman.GetNotifications())
1279  .VerifyDB(active_chainstate,
1280  active_chainstate.CoinsTip(), check_level,
1281  check_depth) == VerifyDBResult::SUCCESS;
1282  },
1283  };
1284 }
1285 
1287  return RPCHelpMan{
1288  "getblockchaininfo",
1289  "Returns an object containing various state info regarding blockchain "
1290  "processing.\n",
1291  {},
1292  RPCResult{
1294  "",
1295  "",
1296  {
1297  {RPCResult::Type::STR, "chain",
1298  "current network name (main, test, regtest)"},
1299  {RPCResult::Type::NUM, "blocks",
1300  "the height of the most-work fully-validated chain. The "
1301  "genesis block has height 0"},
1302  {RPCResult::Type::NUM, "headers",
1303  "the current number of headers we have validated"},
1304  {RPCResult::Type::STR, "bestblockhash",
1305  "the hash of the currently best block"},
1306  {RPCResult::Type::NUM, "difficulty", "the current difficulty"},
1307  {RPCResult::Type::NUM_TIME, "time",
1308  "The block time expressed in " + UNIX_EPOCH_TIME},
1309  {RPCResult::Type::NUM_TIME, "mediantime",
1310  "The median block time expressed in " + UNIX_EPOCH_TIME},
1311  {RPCResult::Type::NUM, "verificationprogress",
1312  "estimate of verification progress [0..1]"},
1313  {RPCResult::Type::BOOL, "initialblockdownload",
1314  "(debug information) estimate of whether this node is in "
1315  "Initial Block Download mode"},
1316  {RPCResult::Type::STR_HEX, "chainwork",
1317  "total amount of work in active chain, in hexadecimal"},
1318  {RPCResult::Type::NUM, "size_on_disk",
1319  "the estimated size of the block and undo files on disk"},
1320  {RPCResult::Type::BOOL, "pruned",
1321  "if the blocks are subject to pruning"},
1322  {RPCResult::Type::NUM, "pruneheight",
1323  "lowest-height complete block stored (only present if pruning "
1324  "is enabled)"},
1325  {RPCResult::Type::BOOL, "automatic_pruning",
1326  "whether automatic pruning is enabled (only present if "
1327  "pruning is enabled)"},
1328  {RPCResult::Type::NUM, "prune_target_size",
1329  "the target size used by pruning (only present if automatic "
1330  "pruning is enabled)"},
1331  {RPCResult::Type::STR, "warnings",
1332  "any network and blockchain warnings"},
1333  }},
1334  RPCExamples{HelpExampleCli("getblockchaininfo", "") +
1335  HelpExampleRpc("getblockchaininfo", "")},
1336  [&](const RPCHelpMan &self, const Config &config,
1337  const JSONRPCRequest &request) -> UniValue {
1338  const CChainParams &chainparams = config.GetChainParams();
1339 
1340  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1341  LOCK(cs_main);
1342  Chainstate &active_chainstate = chainman.ActiveChainstate();
1343 
1344  const CBlockIndex &tip{
1345  *CHECK_NONFATAL(active_chainstate.m_chain.Tip())};
1346  const int height{tip.nHeight};
1347 
1348  UniValue obj(UniValue::VOBJ);
1349  obj.pushKV("chain", chainparams.NetworkIDString());
1350  obj.pushKV("blocks", height);
1351  obj.pushKV("headers", chainman.m_best_header
1352  ? chainman.m_best_header->nHeight
1353  : -1);
1354  obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex());
1355  obj.pushKV("difficulty", GetDifficulty(&tip));
1356  obj.pushKV("time", tip.GetBlockTime());
1357  obj.pushKV("mediantime", tip.GetMedianTimePast());
1358  obj.pushKV(
1359  "verificationprogress",
1360  GuessVerificationProgress(chainman.GetParams().TxData(), &tip));
1361  obj.pushKV("initialblockdownload",
1362  active_chainstate.IsInitialBlockDownload());
1363  obj.pushKV("chainwork", tip.nChainWork.GetHex());
1364  obj.pushKV("size_on_disk",
1365  chainman.m_blockman.CalculateCurrentUsage());
1366  obj.pushKV("pruned", chainman.m_blockman.IsPruneMode());
1367 
1368  if (chainman.m_blockman.IsPruneMode()) {
1369  obj.pushKV(
1370  "pruneheight",
1371  chainman.m_blockman.GetFirstStoredBlock(tip)->nHeight);
1372 
1373  const bool automatic_pruning{
1374  chainman.m_blockman.GetPruneTarget() !=
1375  BlockManager::PRUNE_TARGET_MANUAL};
1376  obj.pushKV("automatic_pruning", automatic_pruning);
1377  if (automatic_pruning) {
1378  obj.pushKV("prune_target_size",
1379  chainman.m_blockman.GetPruneTarget());
1380  }
1381  }
1382 
1383  obj.pushKV("warnings", GetWarnings(false).original);
1384  return obj;
1385  },
1386  };
1387 }
1388 
1391  bool operator()(const CBlockIndex *a, const CBlockIndex *b) const {
1392  // Make sure that unequal blocks with the same height do not compare
1393  // equal. Use the pointers themselves to make a distinction.
1394  if (a->nHeight != b->nHeight) {
1395  return (a->nHeight > b->nHeight);
1396  }
1397 
1398  return a < b;
1399  }
1400 };
1401 
1403  return RPCHelpMan{
1404  "getchaintips",
1405  "Return information about all known tips in the block tree, including "
1406  "the main chain as well as orphaned branches.\n",
1407  {},
1408  RPCResult{
1410  "",
1411  "",
1413  "",
1414  "",
1415  {
1416  {RPCResult::Type::NUM, "height", "height of the chain tip"},
1417  {RPCResult::Type::STR_HEX, "hash", "block hash of the tip"},
1418  {RPCResult::Type::NUM, "branchlen",
1419  "zero for main chain, otherwise length of branch connecting "
1420  "the tip to the main chain"},
1421  {RPCResult::Type::STR, "status",
1422  "status of the chain, \"active\" for the main chain\n"
1423  "Possible values for status:\n"
1424  "1. \"invalid\" This branch contains at "
1425  "least one invalid block\n"
1426  "2. \"parked\" This branch contains at "
1427  "least one parked block\n"
1428  "3. \"headers-only\" Not all blocks for this "
1429  "branch are available, but the headers are valid\n"
1430  "4. \"valid-headers\" All blocks are available for "
1431  "this branch, but they were never fully validated\n"
1432  "5. \"valid-fork\" This branch is not part of "
1433  "the active chain, but is fully validated\n"
1434  "6. \"active\" This is the tip of the "
1435  "active main chain, which is certainly valid"},
1436  }}}},
1437  RPCExamples{HelpExampleCli("getchaintips", "") +
1438  HelpExampleRpc("getchaintips", "")},
1439  [&](const RPCHelpMan &self, const Config &config,
1440  const JSONRPCRequest &request) -> UniValue {
1441  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1442  LOCK(cs_main);
1443  CChain &active_chain = chainman.ActiveChain();
1444 
1456  std::set<const CBlockIndex *, CompareBlocksByHeight> setTips;
1457  std::set<const CBlockIndex *> setOrphans;
1458  std::set<const CBlockIndex *> setPrevs;
1459 
1460  for (const auto &[_, block_index] : chainman.BlockIndex()) {
1461  if (!active_chain.Contains(&block_index)) {
1462  setOrphans.insert(&block_index);
1463  setPrevs.insert(block_index.pprev);
1464  }
1465  }
1466 
1467  for (std::set<const CBlockIndex *>::iterator it =
1468  setOrphans.begin();
1469  it != setOrphans.end(); ++it) {
1470  if (setPrevs.erase(*it) == 0) {
1471  setTips.insert(*it);
1472  }
1473  }
1474 
1475  // Always report the currently active tip.
1476  setTips.insert(active_chain.Tip());
1477 
1478  /* Construct the output array. */
1479  UniValue res(UniValue::VARR);
1480  for (const CBlockIndex *block : setTips) {
1481  UniValue obj(UniValue::VOBJ);
1482  obj.pushKV("height", block->nHeight);
1483  obj.pushKV("hash", block->phashBlock->GetHex());
1484 
1485  const int branchLen =
1486  block->nHeight - active_chain.FindFork(block)->nHeight;
1487  obj.pushKV("branchlen", branchLen);
1488 
1489  std::string status;
1490  if (active_chain.Contains(block)) {
1491  // This block is part of the currently active chain.
1492  status = "active";
1493  } else if (block->nStatus.isInvalid()) {
1494  // This block or one of its ancestors is invalid.
1495  status = "invalid";
1496  } else if (block->nStatus.isOnParkedChain()) {
1497  // This block or one of its ancestors is parked.
1498  status = "parked";
1499  } else if (!block->HaveTxsDownloaded()) {
1500  // This block cannot be connected because full block data
1501  // for it or one of its parents is missing.
1502  status = "headers-only";
1503  } else if (block->IsValid(BlockValidity::SCRIPTS)) {
1504  // This block is fully validated, but no longer part of the
1505  // active chain. It was probably the active block once, but
1506  // was reorganized.
1507  status = "valid-fork";
1508  } else if (block->IsValid(BlockValidity::TREE)) {
1509  // The headers for this block are valid, but it has not been
1510  // validated. It was probably never part of the most-work
1511  // chain.
1512  status = "valid-headers";
1513  } else {
1514  // No clue.
1515  status = "unknown";
1516  }
1517  obj.pushKV("status", status);
1518 
1519  res.push_back(obj);
1520  }
1521 
1522  return res;
1523  },
1524  };
1525 }
1526 
1528  return RPCHelpMan{
1529  "preciousblock",
1530  "Treats a block as if it were received before others with the same "
1531  "work.\n"
1532  "\nA later preciousblock call can override the effect of an earlier "
1533  "one.\n"
1534  "\nThe effects of preciousblock are not retained across restarts.\n",
1535  {
1537  "the hash of the block to mark as precious"},
1538  },
1540  RPCExamples{HelpExampleCli("preciousblock", "\"blockhash\"") +
1541  HelpExampleRpc("preciousblock", "\"blockhash\"")},
1542  [&](const RPCHelpMan &self, const Config &config,
1543  const JSONRPCRequest &request) -> UniValue {
1544  BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1545  CBlockIndex *pblockindex;
1546 
1547  NodeContext &node = EnsureAnyNodeContext(request.context);
1548  ChainstateManager &chainman = EnsureChainman(node);
1549  {
1550  LOCK(cs_main);
1551  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1552  if (!pblockindex) {
1554  "Block not found");
1555  }
1556  }
1557 
1558  BlockValidationState state;
1559  chainman.ActiveChainstate().PreciousBlock(state, pblockindex,
1560  node.avalanche.get());
1561 
1562  if (!state.IsValid()) {
1564  }
1565 
1566  // Block to make sure wallet/indexers sync before returning
1568 
1569  return NullUniValue;
1570  },
1571  };
1572 }
1573 
1575  return RPCHelpMan{
1576  "invalidateblock",
1577  "Permanently marks a block as invalid, as if it violated a consensus "
1578  "rule.\n",
1579  {
1581  "the hash of the block to mark as invalid"},
1582  },
1584  RPCExamples{HelpExampleCli("invalidateblock", "\"blockhash\"") +
1585  HelpExampleRpc("invalidateblock", "\"blockhash\"")},
1586  [&](const RPCHelpMan &self, const Config &config,
1587  const JSONRPCRequest &request) -> UniValue {
1588  const BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1589  BlockValidationState state;
1590 
1591  NodeContext &node = EnsureAnyNodeContext(request.context);
1592  ChainstateManager &chainman = EnsureChainman(node);
1593  CBlockIndex *pblockindex;
1594  {
1595  LOCK(cs_main);
1596  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1597  if (!pblockindex) {
1599  "Block not found");
1600  }
1601  }
1602  chainman.ActiveChainstate().InvalidateBlock(state, pblockindex);
1603 
1604  if (state.IsValid()) {
1605  chainman.ActiveChainstate().ActivateBestChain(
1606  state, /*pblock=*/nullptr, node.avalanche.get());
1607  }
1608 
1609  if (!state.IsValid()) {
1610  throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
1611  }
1612 
1613  // Block to make sure wallet/indexers sync before returning
1615 
1616  return NullUniValue;
1617  },
1618  };
1619 }
1620 
1622  return RPCHelpMan{
1623  "parkblock",
1624  "Marks a block as parked.\n",
1625  {
1627  "the hash of the block to park"},
1628  },
1630  RPCExamples{HelpExampleCli("parkblock", "\"blockhash\"") +
1631  HelpExampleRpc("parkblock", "\"blockhash\"")},
1632  [&](const RPCHelpMan &self, const Config &config,
1633  const JSONRPCRequest &request) -> UniValue {
1634  const std::string strHash = request.params[0].get_str();
1635  const BlockHash hash(uint256S(strHash));
1636  BlockValidationState state;
1637 
1638  NodeContext &node = EnsureAnyNodeContext(request.context);
1639  ChainstateManager &chainman = EnsureChainman(node);
1640  Chainstate &active_chainstate = chainman.ActiveChainstate();
1641  CBlockIndex *pblockindex = nullptr;
1642  {
1643  LOCK(cs_main);
1644  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1645  if (!pblockindex) {
1647  "Block not found");
1648  }
1649 
1650  if (active_chainstate.IsBlockAvalancheFinalized(pblockindex)) {
1651  // Reset avalanche finalization if we park a finalized
1652  // block.
1653  active_chainstate.ClearAvalancheFinalizedBlock();
1654  }
1655  }
1656 
1657  active_chainstate.ParkBlock(state, pblockindex);
1658 
1659  if (state.IsValid()) {
1660  active_chainstate.ActivateBestChain(state, /*pblock=*/nullptr,
1661  node.avalanche.get());
1662  }
1663 
1664  if (!state.IsValid()) {
1666  }
1667 
1668  // Block to make sure wallet/indexers sync before returning
1670 
1671  return NullUniValue;
1672  },
1673  };
1674 }
1675 
1677  return RPCHelpMan{
1678  "reconsiderblock",
1679  "Removes invalidity status of a block, its ancestors and its"
1680  "descendants, reconsider them for activation.\n"
1681  "This can be used to undo the effects of invalidateblock.\n",
1682  {
1684  "the hash of the block to reconsider"},
1685  },
1687  RPCExamples{HelpExampleCli("reconsiderblock", "\"blockhash\"") +
1688  HelpExampleRpc("reconsiderblock", "\"blockhash\"")},
1689  [&](const RPCHelpMan &self, const Config &config,
1690  const JSONRPCRequest &request) -> UniValue {
1691  NodeContext &node = EnsureAnyNodeContext(request.context);
1692  ChainstateManager &chainman = EnsureChainman(node);
1693  const BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1694 
1695  {
1696  LOCK(cs_main);
1697  CBlockIndex *pblockindex =
1698  chainman.m_blockman.LookupBlockIndex(hash);
1699  if (!pblockindex) {
1701  "Block not found");
1702  }
1703 
1704  chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex);
1705  }
1706 
1707  BlockValidationState state;
1708  chainman.ActiveChainstate().ActivateBestChain(
1709  state, /*pblock=*/nullptr, node.avalanche.get());
1710 
1711  if (!state.IsValid()) {
1712  throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
1713  }
1714 
1715  // Block to make sure wallet/indexers sync before returning
1717 
1718  return NullUniValue;
1719  },
1720  };
1721 }
1722 
1724  return RPCHelpMan{
1725  "unparkblock",
1726  "Removes parked status of a block and its descendants, reconsider "
1727  "them for activation.\n"
1728  "This can be used to undo the effects of parkblock.\n",
1729  {
1731  "the hash of the block to unpark"},
1732  },
1734  RPCExamples{HelpExampleCli("unparkblock", "\"blockhash\"") +
1735  HelpExampleRpc("unparkblock", "\"blockhash\"")},
1736  [&](const RPCHelpMan &self, const Config &config,
1737  const JSONRPCRequest &request) -> UniValue {
1738  const std::string strHash = request.params[0].get_str();
1739  NodeContext &node = EnsureAnyNodeContext(request.context);
1740  ChainstateManager &chainman = EnsureChainman(node);
1741  const BlockHash hash(uint256S(strHash));
1742  Chainstate &active_chainstate = chainman.ActiveChainstate();
1743 
1744  {
1745  LOCK(cs_main);
1746 
1747  CBlockIndex *pblockindex =
1748  chainman.m_blockman.LookupBlockIndex(hash);
1749  if (!pblockindex) {
1751  "Block not found");
1752  }
1753 
1754  if (!pblockindex->nStatus.isOnParkedChain()) {
1755  // Block to unpark is not parked so there is nothing to do.
1756  return NullUniValue;
1757  }
1758 
1759  const CBlockIndex *tip = active_chainstate.m_chain.Tip();
1760  if (tip) {
1761  const CBlockIndex *ancestor =
1762  LastCommonAncestor(tip, pblockindex);
1763  if (active_chainstate.IsBlockAvalancheFinalized(ancestor)) {
1764  // Only reset avalanche finalization if we unpark a
1765  // block that might conflict with avalanche finalized
1766  // blocks.
1767  active_chainstate.ClearAvalancheFinalizedBlock();
1768  }
1769  }
1770 
1771  active_chainstate.UnparkBlockAndChildren(pblockindex);
1772  }
1773 
1774  BlockValidationState state;
1775  active_chainstate.ActivateBestChain(state, /*pblock=*/nullptr,
1776  node.avalanche.get());
1777 
1778  if (!state.IsValid()) {
1780  }
1781 
1782  // Block to make sure wallet/indexers sync before returning
1784 
1785  return NullUniValue;
1786  },
1787  };
1788 }
1789 
1791  return RPCHelpMan{
1792  "getchaintxstats",
1793  "Compute statistics about the total number and rate of transactions "
1794  "in the chain.\n",
1795  {
1796  {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{"one month"},
1797  "Size of the window in number of blocks"},
1798  {"blockhash", RPCArg::Type::STR_HEX,
1799  RPCArg::DefaultHint{"chain tip"},
1800  "The hash of the block that ends the window."},
1801  },
1803  "",
1804  "",
1805  {
1806  {RPCResult::Type::NUM_TIME, "time",
1807  "The timestamp for the final block in the window, "
1808  "expressed in " +
1809  UNIX_EPOCH_TIME},
1810  {RPCResult::Type::NUM, "txcount",
1811  "The total number of transactions in the chain up to "
1812  "that point"},
1813  {RPCResult::Type::STR_HEX, "window_final_block_hash",
1814  "The hash of the final block in the window"},
1815  {RPCResult::Type::NUM, "window_final_block_height",
1816  "The height of the final block in the window."},
1817  {RPCResult::Type::NUM, "window_block_count",
1818  "Size of the window in number of blocks"},
1819  {RPCResult::Type::NUM, "window_tx_count",
1820  "The number of transactions in the window. Only "
1821  "returned if \"window_block_count\" is > 0"},
1822  {RPCResult::Type::NUM, "window_interval",
1823  "The elapsed time in the window in seconds. Only "
1824  "returned if \"window_block_count\" is > 0"},
1825  {RPCResult::Type::NUM, "txrate",
1826  "The average rate of transactions per second in the "
1827  "window. Only returned if \"window_interval\" is > 0"},
1828  }},
1829  RPCExamples{HelpExampleCli("getchaintxstats", "") +
1830  HelpExampleRpc("getchaintxstats", "2016")},
1831  [&](const RPCHelpMan &self, const Config &config,
1832  const JSONRPCRequest &request) -> UniValue {
1833  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1834  const CBlockIndex *pindex;
1835 
1836  // By default: 1 month
1837  int blockcount =
1838  30 * 24 * 60 * 60 /
1839  config.GetChainParams().GetConsensus().nPowTargetSpacing;
1840 
1841  if (request.params[1].isNull()) {
1842  LOCK(cs_main);
1843  pindex = chainman.ActiveTip();
1844  } else {
1845  BlockHash hash(ParseHashV(request.params[1], "blockhash"));
1846  LOCK(cs_main);
1847  pindex = chainman.m_blockman.LookupBlockIndex(hash);
1848  if (!pindex) {
1850  "Block not found");
1851  }
1852  if (!chainman.ActiveChain().Contains(pindex)) {
1854  "Block is not in main chain");
1855  }
1856  }
1857 
1858  CHECK_NONFATAL(pindex != nullptr);
1859 
1860  if (request.params[0].isNull()) {
1861  blockcount =
1862  std::max(0, std::min(blockcount, pindex->nHeight - 1));
1863  } else {
1864  blockcount = request.params[0].getInt<int>();
1865 
1866  if (blockcount < 0 ||
1867  (blockcount > 0 && blockcount >= pindex->nHeight)) {
1869  "Invalid block count: "
1870  "should be between 0 and "
1871  "the block's height - 1");
1872  }
1873  }
1874 
1875  const CBlockIndex &past_block{*CHECK_NONFATAL(
1876  pindex->GetAncestor(pindex->nHeight - blockcount))};
1877  const int64_t nTimeDiff{pindex->GetMedianTimePast() -
1878  past_block.GetMedianTimePast()};
1879  const int nTxDiff =
1880  pindex->GetChainTxCount() - past_block.GetChainTxCount();
1881 
1882  UniValue ret(UniValue::VOBJ);
1883  ret.pushKV("time", pindex->GetBlockTime());
1884  ret.pushKV("txcount", pindex->GetChainTxCount());
1885  ret.pushKV("window_final_block_hash",
1886  pindex->GetBlockHash().GetHex());
1887  ret.pushKV("window_final_block_height", pindex->nHeight);
1888  ret.pushKV("window_block_count", blockcount);
1889  if (blockcount > 0) {
1890  ret.pushKV("window_tx_count", nTxDiff);
1891  ret.pushKV("window_interval", nTimeDiff);
1892  if (nTimeDiff > 0) {
1893  ret.pushKV("txrate", double(nTxDiff) / nTimeDiff);
1894  }
1895  }
1896 
1897  return ret;
1898  },
1899  };
1900 }
1901 
1902 template <typename T>
1903 static T CalculateTruncatedMedian(std::vector<T> &scores) {
1904  size_t size = scores.size();
1905  if (size == 0) {
1906  return T();
1907  }
1908 
1909  std::sort(scores.begin(), scores.end());
1910  if (size % 2 == 0) {
1911  return (scores[size / 2 - 1] + scores[size / 2]) / 2;
1912  } else {
1913  return scores[size / 2];
1914  }
1915 }
1916 
1917 template <typename T> static inline bool SetHasKeys(const std::set<T> &set) {
1918  return false;
1919 }
1920 template <typename T, typename Tk, typename... Args>
1921 static inline bool SetHasKeys(const std::set<T> &set, const Tk &key,
1922  const Args &...args) {
1923  return (set.count(key) != 0) || SetHasKeys(set, args...);
1924 }
1925 
1926 // outpoint (needed for the utxo index) + nHeight + fCoinBase
1927 static constexpr size_t PER_UTXO_OVERHEAD =
1928  sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);
1929 
1931  const auto &ticker = Currency::get().ticker;
1932  return RPCHelpMan{
1933  "getblockstats",
1934  "Compute per block statistics for a given window. All amounts are "
1935  "in " +
1936  ticker +
1937  ".\n"
1938  "It won't work for some heights with pruning.\n",
1939  {
1940  {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO,
1941  "The block hash or height of the target block",
1943  .type_str = {"", "string or numeric"}}},
1944  {"stats",
1946  RPCArg::DefaultHint{"all values"},
1947  "Values to plot (see result below)",
1948  {
1950  "Selected statistic"},
1952  "Selected statistic"},
1953  },
1954  RPCArgOptions{.oneline_description = "stats"}},
1955  },
1956  RPCResult{
1958  "",
1959  "",
1960  {
1961  {RPCResult::Type::NUM, "avgfee", "Average fee in the block"},
1962  {RPCResult::Type::NUM, "avgfeerate",
1963  "Average feerate (in satoshis per virtual byte)"},
1964  {RPCResult::Type::NUM, "avgtxsize", "Average transaction size"},
1965  {RPCResult::Type::STR_HEX, "blockhash",
1966  "The block hash (to check for potential reorgs)"},
1967  {RPCResult::Type::NUM, "height", "The height of the block"},
1968  {RPCResult::Type::NUM, "ins",
1969  "The number of inputs (excluding coinbase)"},
1970  {RPCResult::Type::NUM, "maxfee", "Maximum fee in the block"},
1971  {RPCResult::Type::NUM, "maxfeerate",
1972  "Maximum feerate (in satoshis per virtual byte)"},
1973  {RPCResult::Type::NUM, "maxtxsize", "Maximum transaction size"},
1974  {RPCResult::Type::NUM, "medianfee",
1975  "Truncated median fee in the block"},
1976  {RPCResult::Type::NUM, "medianfeerate",
1977  "Truncated median feerate (in " + ticker + " per byte)"},
1978  {RPCResult::Type::NUM, "mediantime",
1979  "The block median time past"},
1980  {RPCResult::Type::NUM, "mediantxsize",
1981  "Truncated median transaction size"},
1982  {RPCResult::Type::NUM, "minfee", "Minimum fee in the block"},
1983  {RPCResult::Type::NUM, "minfeerate",
1984  "Minimum feerate (in satoshis per virtual byte)"},
1985  {RPCResult::Type::NUM, "mintxsize", "Minimum transaction size"},
1986  {RPCResult::Type::NUM, "outs", "The number of outputs"},
1987  {RPCResult::Type::NUM, "subsidy", "The block subsidy"},
1988  {RPCResult::Type::NUM, "time", "The block time"},
1989  {RPCResult::Type::NUM, "total_out",
1990  "Total amount in all outputs (excluding coinbase and thus "
1991  "reward [ie subsidy + totalfee])"},
1992  {RPCResult::Type::NUM, "total_size",
1993  "Total size of all non-coinbase transactions"},
1994  {RPCResult::Type::NUM, "totalfee", "The fee total"},
1995  {RPCResult::Type::NUM, "txs",
1996  "The number of transactions (including coinbase)"},
1997  {RPCResult::Type::NUM, "utxo_increase",
1998  "The increase/decrease in the number of unspent outputs"},
1999  {RPCResult::Type::NUM, "utxo_size_inc",
2000  "The increase/decrease in size for the utxo index (not "
2001  "discounting op_return and similar)"},
2002  }},
2003  RPCExamples{
2005  "getblockstats",
2006  R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
2007  HelpExampleCli("getblockstats",
2008  R"(1000 '["minfeerate","avgfeerate"]')") +
2010  "getblockstats",
2011  R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") +
2012  HelpExampleRpc("getblockstats",
2013  R"(1000, ["minfeerate","avgfeerate"])")},
2014  [&](const RPCHelpMan &self, const Config &config,
2015  const JSONRPCRequest &request) -> UniValue {
2016  ChainstateManager &chainman = EnsureAnyChainman(request.context);
2017  const CBlockIndex &pindex{*CHECK_NONFATAL(
2018  ParseHashOrHeight(request.params[0], chainman))};
2019 
2020  std::set<std::string> stats;
2021  if (!request.params[1].isNull()) {
2022  const UniValue stats_univalue = request.params[1].get_array();
2023  for (unsigned int i = 0; i < stats_univalue.size(); i++) {
2024  const std::string stat = stats_univalue[i].get_str();
2025  stats.insert(stat);
2026  }
2027  }
2028 
2029  const CBlock &block = GetBlockChecked(chainman.m_blockman, &pindex);
2030  const CBlockUndo &blockUndo =
2031  GetUndoChecked(chainman.m_blockman, &pindex);
2032 
2033  // Calculate everything if nothing selected (default)
2034  const bool do_all = stats.size() == 0;
2035  const bool do_mediantxsize =
2036  do_all || stats.count("mediantxsize") != 0;
2037  const bool do_medianfee = do_all || stats.count("medianfee") != 0;
2038  const bool do_medianfeerate =
2039  do_all || stats.count("medianfeerate") != 0;
2040  const bool loop_inputs =
2041  do_all || do_medianfee || do_medianfeerate ||
2042  SetHasKeys(stats, "utxo_size_inc", "totalfee", "avgfee",
2043  "avgfeerate", "minfee", "maxfee", "minfeerate",
2044  "maxfeerate");
2045  const bool loop_outputs =
2046  do_all || loop_inputs || stats.count("total_out");
2047  const bool do_calculate_size =
2048  do_mediantxsize || loop_inputs ||
2049  SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize",
2050  "maxtxsize");
2051 
2052  const int64_t blockMaxSize = config.GetMaxBlockSize();
2053  Amount maxfee = Amount::zero();
2054  Amount maxfeerate = Amount::zero();
2055  Amount minfee = MAX_MONEY;
2056  Amount minfeerate = MAX_MONEY;
2057  Amount total_out = Amount::zero();
2058  Amount totalfee = Amount::zero();
2059  int64_t inputs = 0;
2060  int64_t maxtxsize = 0;
2061  int64_t mintxsize = blockMaxSize;
2062  int64_t outputs = 0;
2063  int64_t total_size = 0;
2064  int64_t utxo_size_inc = 0;
2065  std::vector<Amount> fee_array;
2066  std::vector<Amount> feerate_array;
2067  std::vector<int64_t> txsize_array;
2068 
2069  for (size_t i = 0; i < block.vtx.size(); ++i) {
2070  const auto &tx = block.vtx.at(i);
2071  outputs += tx->vout.size();
2072  Amount tx_total_out = Amount::zero();
2073  if (loop_outputs) {
2074  for (const CTxOut &out : tx->vout) {
2075  tx_total_out += out.nValue;
2076  utxo_size_inc +=
2079  }
2080  }
2081 
2082  if (tx->IsCoinBase()) {
2083  continue;
2084  }
2085 
2086  // Don't count coinbase's fake input
2087  inputs += tx->vin.size();
2088  // Don't count coinbase reward
2089  total_out += tx_total_out;
2090 
2091  int64_t tx_size = 0;
2092  if (do_calculate_size) {
2093  tx_size = tx->GetTotalSize();
2094  if (do_mediantxsize) {
2095  txsize_array.push_back(tx_size);
2096  }
2097  maxtxsize = std::max(maxtxsize, tx_size);
2098  mintxsize = std::min(mintxsize, tx_size);
2099  total_size += tx_size;
2100  }
2101 
2102  if (loop_inputs) {
2103  Amount tx_total_in = Amount::zero();
2104  const auto &txundo = blockUndo.vtxundo.at(i - 1);
2105  for (const Coin &coin : txundo.vprevout) {
2106  const CTxOut &prevoutput = coin.GetTxOut();
2107 
2108  tx_total_in += prevoutput.nValue;
2109  utxo_size_inc -=
2110  GetSerializeSize(prevoutput, PROTOCOL_VERSION) +
2112  }
2113 
2114  Amount txfee = tx_total_in - tx_total_out;
2115  CHECK_NONFATAL(MoneyRange(txfee));
2116  if (do_medianfee) {
2117  fee_array.push_back(txfee);
2118  }
2119  maxfee = std::max(maxfee, txfee);
2120  minfee = std::min(minfee, txfee);
2121  totalfee += txfee;
2122 
2123  Amount feerate = txfee / tx_size;
2124  if (do_medianfeerate) {
2125  feerate_array.push_back(feerate);
2126  }
2127  maxfeerate = std::max(maxfeerate, feerate);
2128  minfeerate = std::min(minfeerate, feerate);
2129  }
2130  }
2131 
2132  UniValue ret_all(UniValue::VOBJ);
2133  ret_all.pushKV("avgfee",
2134  block.vtx.size() > 1
2135  ? (totalfee / int((block.vtx.size() - 1)))
2136  : Amount::zero());
2137  ret_all.pushKV("avgfeerate", total_size > 0
2138  ? (totalfee / total_size)
2139  : Amount::zero());
2140  ret_all.pushKV("avgtxsize",
2141  (block.vtx.size() > 1)
2142  ? total_size / (block.vtx.size() - 1)
2143  : 0);
2144  ret_all.pushKV("blockhash", pindex.GetBlockHash().GetHex());
2145  ret_all.pushKV("height", (int64_t)pindex.nHeight);
2146  ret_all.pushKV("ins", inputs);
2147  ret_all.pushKV("maxfee", maxfee);
2148  ret_all.pushKV("maxfeerate", maxfeerate);
2149  ret_all.pushKV("maxtxsize", maxtxsize);
2150  ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
2151  ret_all.pushKV("medianfeerate",
2152  CalculateTruncatedMedian(feerate_array));
2153  ret_all.pushKV("mediantime", pindex.GetMedianTimePast());
2154  ret_all.pushKV("mediantxsize",
2155  CalculateTruncatedMedian(txsize_array));
2156  ret_all.pushKV("minfee",
2157  minfee == MAX_MONEY ? Amount::zero() : minfee);
2158  ret_all.pushKV("minfeerate", minfeerate == MAX_MONEY
2159  ? Amount::zero()
2160  : minfeerate);
2161  ret_all.pushKV("mintxsize",
2162  mintxsize == blockMaxSize ? 0 : mintxsize);
2163  ret_all.pushKV("outs", outputs);
2164  ret_all.pushKV("subsidy", GetBlockSubsidy(pindex.nHeight,
2165  chainman.GetConsensus()));
2166  ret_all.pushKV("time", pindex.GetBlockTime());
2167  ret_all.pushKV("total_out", total_out);
2168  ret_all.pushKV("total_size", total_size);
2169  ret_all.pushKV("totalfee", totalfee);
2170  ret_all.pushKV("txs", (int64_t)block.vtx.size());
2171  ret_all.pushKV("utxo_increase", outputs - inputs);
2172  ret_all.pushKV("utxo_size_inc", utxo_size_inc);
2173 
2174  if (do_all) {
2175  return ret_all;
2176  }
2177 
2178  UniValue ret(UniValue::VOBJ);
2179  for (const std::string &stat : stats) {
2180  const UniValue &value = ret_all[stat];
2181  if (value.isNull()) {
2182  throw JSONRPCError(
2184  strprintf("Invalid selected statistic %s", stat));
2185  }
2186  ret.pushKV(stat, value);
2187  }
2188  return ret;
2189  },
2190  };
2191 }
2192 
2193 namespace {
2195 static bool FindScriptPubKey(std::atomic<int> &scan_progress,
2196  const std::atomic<bool> &should_abort,
2197  int64_t &count, CCoinsViewCursor *cursor,
2198  const std::set<CScript> &needles,
2199  std::map<COutPoint, Coin> &out_results,
2200  std::function<void()> &interruption_point) {
2201  scan_progress = 0;
2202  count = 0;
2203  while (cursor->Valid()) {
2204  COutPoint key;
2205  Coin coin;
2206  if (!cursor->GetKey(key) || !cursor->GetValue(coin)) {
2207  return false;
2208  }
2209  if (++count % 8192 == 0) {
2210  interruption_point();
2211  if (should_abort) {
2212  // allow to abort the scan via the abort reference
2213  return false;
2214  }
2215  }
2216  if (count % 256 == 0) {
2217  // update progress reference every 256 item
2218  const TxId &txid = key.GetTxId();
2219  uint32_t high = 0x100 * *txid.begin() + *(txid.begin() + 1);
2220  scan_progress = int(high * 100.0 / 65536.0 + 0.5);
2221  }
2222  if (needles.count(coin.GetTxOut().scriptPubKey)) {
2223  out_results.emplace(key, coin);
2224  }
2225  cursor->Next();
2226  }
2227  scan_progress = 100;
2228  return true;
2229 }
2230 } // namespace
2231 
2233 static std::atomic<int> g_scan_progress;
2234 static std::atomic<bool> g_scan_in_progress;
2235 static std::atomic<bool> g_should_abort_scan;
2237 private:
2239 
2240 public:
2242 
2243  bool reserve() {
2245  if (g_scan_in_progress.exchange(true)) {
2246  return false;
2247  }
2248  m_could_reserve = true;
2249  return true;
2250  }
2251 
2253  if (m_could_reserve) {
2254  g_scan_in_progress = false;
2255  }
2256  }
2257 };
2258 
2260  const auto &ticker = Currency::get().ticker;
2261  return RPCHelpMan{
2262  "scantxoutset",
2263  "Scans the unspent transaction output set for entries that match "
2264  "certain output descriptors.\n"
2265  "Examples of output descriptors are:\n"
2266  " addr(<address>) Outputs whose scriptPubKey "
2267  "corresponds to the specified address (does not include P2PK)\n"
2268  " raw(<hex script>) Outputs whose scriptPubKey "
2269  "equals the specified hex scripts\n"
2270  " combo(<pubkey>) P2PK and P2PKH outputs for "
2271  "the given pubkey\n"
2272  " pkh(<pubkey>) P2PKH outputs for the given "
2273  "pubkey\n"
2274  " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for "
2275  "the given threshold and pubkeys\n"
2276  "\nIn the above, <pubkey> either refers to a fixed public key in "
2277  "hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
2278  "or more path elements separated by \"/\", and optionally ending in "
2279  "\"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
2280  "unhardened or hardened child keys.\n"
2281  "In the latter case, a range needs to be specified by below if "
2282  "different from 1000.\n"
2283  "For more information on output descriptors, see the documentation in "
2284  "the doc/descriptors.md file.\n",
2285  {
2287  "The action to execute\n"
2288  " \"start\" for starting a "
2289  "scan\n"
2290  " \"abort\" for aborting the "
2291  "current scan (returns true when abort was successful)\n"
2292  " \"status\" for "
2293  "progress report (in %) of the current scan"},
2294  {"scanobjects",
2297  "Array of scan objects. Required for \"start\" action\n"
2298  " Every scan object is either a "
2299  "string descriptor or an object:",
2300  {
2302  "An output descriptor"},
2303  {
2304  "",
2307  "An object with output descriptor and metadata",
2308  {
2310  "An output descriptor"},
2311  {"range", RPCArg::Type::RANGE, RPCArg::Default{1000},
2312  "The range of HD chain indexes to explore (either "
2313  "end or [begin,end])"},
2314  },
2315  },
2316  },
2317  RPCArgOptions{.oneline_description = "[scanobjects,...]"}},
2318  },
2319  {
2320  RPCResult{"When action=='abort'", RPCResult::Type::BOOL, "", ""},
2321  RPCResult{"When action=='status' and no scan is in progress",
2322  RPCResult::Type::NONE, "", ""},
2323  RPCResult{
2324  "When action=='status' and scan is in progress",
2326  "",
2327  "",
2328  {
2329  {RPCResult::Type::NUM, "progress", "The scan progress"},
2330  }},
2331  RPCResult{
2332  "When action=='start'",
2334  "",
2335  "",
2336  {
2337  {RPCResult::Type::BOOL, "success",
2338  "Whether the scan was completed"},
2339  {RPCResult::Type::NUM, "txouts",
2340  "The number of unspent transaction outputs scanned"},
2341  {RPCResult::Type::NUM, "height",
2342  "The current block height (index)"},
2343  {RPCResult::Type::STR_HEX, "bestblock",
2344  "The hash of the block at the tip of the chain"},
2346  "unspents",
2347  "",
2348  {
2350  "",
2351  "",
2352  {
2353  {RPCResult::Type::STR_HEX, "txid",
2354  "The transaction id"},
2355  {RPCResult::Type::NUM, "vout", "The vout value"},
2356  {RPCResult::Type::STR_HEX, "scriptPubKey",
2357  "The script key"},
2358  {RPCResult::Type::STR, "desc",
2359  "A specialized descriptor for the matched "
2360  "scriptPubKey"},
2361  {RPCResult::Type::STR_AMOUNT, "amount",
2362  "The total amount in " + ticker +
2363  " of the unspent output"},
2364  {RPCResult::Type::NUM, "height",
2365  "Height of the unspent transaction output"},
2366  }},
2367  }},
2368  {RPCResult::Type::STR_AMOUNT, "total_amount",
2369  "The total amount of all found unspent outputs in " +
2370  ticker},
2371  }},
2372  },
2373  RPCExamples{""},
2374  [&](const RPCHelpMan &self, const Config &config,
2375  const JSONRPCRequest &request) -> UniValue {
2376  UniValue result(UniValue::VOBJ);
2377  if (request.params[0].get_str() == "status") {
2378  CoinsViewScanReserver reserver;
2379  if (reserver.reserve()) {
2380  // no scan in progress
2381  return NullUniValue;
2382  }
2383  result.pushKV("progress", g_scan_progress.load());
2384  return result;
2385  } else if (request.params[0].get_str() == "abort") {
2386  CoinsViewScanReserver reserver;
2387  if (reserver.reserve()) {
2388  // reserve was possible which means no scan was running
2389  return false;
2390  }
2391  // set the abort flag
2392  g_should_abort_scan = true;
2393  return true;
2394  } else if (request.params[0].get_str() == "start") {
2395  CoinsViewScanReserver reserver;
2396  if (!reserver.reserve()) {
2398  "Scan already in progress, use action "
2399  "\"abort\" or \"status\"");
2400  }
2401 
2402  if (request.params.size() < 2) {
2404  "scanobjects argument is required for "
2405  "the start action");
2406  }
2407 
2408  std::set<CScript> needles;
2409  std::map<CScript, std::string> descriptors;
2410  Amount total_in = Amount::zero();
2411 
2412  // loop through the scan objects
2413  for (const UniValue &scanobject :
2414  request.params[1].get_array().getValues()) {
2415  FlatSigningProvider provider;
2416  auto scripts =
2417  EvalDescriptorStringOrObject(scanobject, provider);
2418  for (CScript &script : scripts) {
2419  std::string inferred =
2420  InferDescriptor(script, provider)->ToString();
2421  needles.emplace(script);
2422  descriptors.emplace(std::move(script),
2423  std::move(inferred));
2424  }
2425  }
2426 
2427  // Scan the unspent transaction output set for inputs
2428  UniValue unspents(UniValue::VARR);
2429  std::vector<CTxOut> input_txos;
2430  std::map<COutPoint, Coin> coins;
2431  g_should_abort_scan = false;
2432  g_scan_progress = 0;
2433  int64_t count = 0;
2434  std::unique_ptr<CCoinsViewCursor> pcursor;
2435  const CBlockIndex *tip;
2436  NodeContext &node = EnsureAnyNodeContext(request.context);
2437  {
2438  ChainstateManager &chainman = EnsureChainman(node);
2439  LOCK(cs_main);
2440  Chainstate &active_chainstate = chainman.ActiveChainstate();
2441  active_chainstate.ForceFlushStateToDisk();
2442  pcursor = CHECK_NONFATAL(std::unique_ptr<CCoinsViewCursor>(
2443  active_chainstate.CoinsDB().Cursor()));
2444  tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
2445  }
2446  bool res = FindScriptPubKey(
2447  g_scan_progress, g_should_abort_scan, count, pcursor.get(),
2448  needles, coins, node.rpc_interruption_point);
2449  result.pushKV("success", res);
2450  result.pushKV("txouts", count);
2451  result.pushKV("height", tip->nHeight);
2452  result.pushKV("bestblock", tip->GetBlockHash().GetHex());
2453 
2454  for (const auto &it : coins) {
2455  const COutPoint &outpoint = it.first;
2456  const Coin &coin = it.second;
2457  const CTxOut &txo = coin.GetTxOut();
2458  input_txos.push_back(txo);
2459  total_in += txo.nValue;
2460 
2461  UniValue unspent(UniValue::VOBJ);
2462  unspent.pushKV("txid", outpoint.GetTxId().GetHex());
2463  unspent.pushKV("vout", int32_t(outpoint.GetN()));
2464  unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
2465  unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
2466  unspent.pushKV("amount", txo.nValue);
2467  unspent.pushKV("height", int32_t(coin.GetHeight()));
2468 
2469  unspents.push_back(unspent);
2470  }
2471  result.pushKV("unspents", unspents);
2472  result.pushKV("total_amount", total_in);
2473  } else {
2474  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid command");
2475  }
2476  return result;
2477  },
2478  };
2479 }
2480 
2482  return RPCHelpMan{
2483  "getblockfilter",
2484  "Retrieve a BIP 157 content filter for a particular block.\n",
2485  {
2487  "The hash of the block"},
2488  {"filtertype", RPCArg::Type::STR, RPCArg::Default{"basic"},
2489  "The type name of the filter"},
2490  },
2492  "",
2493  "",
2494  {
2495  {RPCResult::Type::STR_HEX, "filter",
2496  "the hex-encoded filter data"},
2497  {RPCResult::Type::STR_HEX, "header",
2498  "the hex-encoded filter header"},
2499  }},
2500  RPCExamples{
2501  HelpExampleCli("getblockfilter",
2502  "\"00000000c937983704a73af28acdec37b049d214a"
2503  "dbda81d7e2a3dd146f6ed09\" \"basic\"") +
2504  HelpExampleRpc("getblockfilter",
2505  "\"00000000c937983704a73af28acdec37b049d214adbda81d7"
2506  "e2a3dd146f6ed09\", \"basic\"")},
2507  [&](const RPCHelpMan &self, const Config &config,
2508  const JSONRPCRequest &request) -> UniValue {
2509  const BlockHash block_hash(
2510  ParseHashV(request.params[0], "blockhash"));
2511  std::string filtertype_name = "basic";
2512  if (!request.params[1].isNull()) {
2513  filtertype_name = request.params[1].get_str();
2514  }
2515 
2516  BlockFilterType filtertype;
2517  if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2519  "Unknown filtertype");
2520  }
2521 
2522  BlockFilterIndex *index = GetBlockFilterIndex(filtertype);
2523  if (!index) {
2525  "Index is not enabled for filtertype " +
2526  filtertype_name);
2527  }
2528 
2529  const CBlockIndex *block_index;
2530  bool block_was_connected;
2531  {
2532  ChainstateManager &chainman =
2533  EnsureAnyChainman(request.context);
2534  LOCK(cs_main);
2535  block_index = chainman.m_blockman.LookupBlockIndex(block_hash);
2536  if (!block_index) {
2538  "Block not found");
2539  }
2540  block_was_connected =
2541  block_index->IsValid(BlockValidity::SCRIPTS);
2542  }
2543 
2544  bool index_ready = index->BlockUntilSyncedToCurrentChain();
2545 
2546  BlockFilter filter;
2547  uint256 filter_header;
2548  if (!index->LookupFilter(block_index, filter) ||
2549  !index->LookupFilterHeader(block_index, filter_header)) {
2550  int err_code;
2551  std::string errmsg = "Filter not found.";
2552 
2553  if (!block_was_connected) {
2554  err_code = RPC_INVALID_ADDRESS_OR_KEY;
2555  errmsg += " Block was not connected to active chain.";
2556  } else if (!index_ready) {
2557  err_code = RPC_MISC_ERROR;
2558  errmsg += " Block filters are still in the process of "
2559  "being indexed.";
2560  } else {
2561  err_code = RPC_INTERNAL_ERROR;
2562  errmsg += " This error is unexpected and indicates index "
2563  "corruption.";
2564  }
2565 
2566  throw JSONRPCError(err_code, errmsg);
2567  }
2568 
2569  UniValue ret(UniValue::VOBJ);
2570  ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
2571  ret.pushKV("header", filter_header.GetHex());
2572  return ret;
2573  },
2574  };
2575 }
2576 
2583  return RPCHelpMan{
2584  "dumptxoutset",
2585  "Write the serialized UTXO set to disk.\n",
2586  {
2588  "path to the output file. If relative, will be prefixed by "
2589  "datadir."},
2590  },
2592  "",
2593  "",
2594  {
2595  {RPCResult::Type::NUM, "coins_written",
2596  "the number of coins written in the snapshot"},
2597  {RPCResult::Type::STR_HEX, "base_hash",
2598  "the hash of the base of the snapshot"},
2599  {RPCResult::Type::NUM, "base_height",
2600  "the height of the base of the snapshot"},
2601  {RPCResult::Type::STR, "path",
2602  "the absolute path that the snapshot was written to"},
2603  {RPCResult::Type::STR_HEX, "txoutset_hash",
2604  "the hash of the UTXO set contents"},
2605  {RPCResult::Type::NUM, "nchaintx",
2606  "the number of transactions in the chain up to and "
2607  "including the base block"},
2608  }},
2609  RPCExamples{HelpExampleCli("dumptxoutset", "utxo.dat")},
2610  [&](const RPCHelpMan &self, const Config &config,
2611  const JSONRPCRequest &request) -> UniValue {
2612  const ArgsManager &args{EnsureAnyArgsman(request.context)};
2613  const fs::path path = fsbridge::AbsPathJoin(
2614  args.GetDataDirNet(), fs::u8path(request.params[0].get_str()));
2615  // Write to a temporary path and then move into `path` on completion
2616  // to avoid confusion due to an interruption.
2617  const fs::path temppath = fsbridge::AbsPathJoin(
2618  args.GetDataDirNet(),
2619  fs::u8path(request.params[0].get_str() + ".incomplete"));
2620 
2621  if (fs::exists(path)) {
2623  path.u8string() +
2624  " already exists. If you are sure this "
2625  "is what you want, "
2626  "move it out of the way first");
2627  }
2628 
2629  FILE *file{fsbridge::fopen(temppath, "wb")};
2630  AutoFile afile{file};
2631  NodeContext &node = EnsureAnyNodeContext(request.context);
2632  UniValue result = CreateUTXOSnapshot(
2633  node, node.chainman->ActiveChainstate(), afile, path, temppath);
2634  fs::rename(temppath, path);
2635 
2636  return result;
2637  },
2638  };
2639 }
2640 
2642  AutoFile &afile, const fs::path &path,
2643  const fs::path &temppath) {
2644  std::unique_ptr<CCoinsViewCursor> pcursor;
2645  std::optional<CCoinsStats> maybe_stats;
2646  const CBlockIndex *tip;
2647 
2648  {
2649  // We need to lock cs_main to ensure that the coinsdb isn't
2650  // written to between (i) flushing coins cache to disk
2651  // (coinsdb), (ii) getting stats based upon the coinsdb, and
2652  // (iii) constructing a cursor to the coinsdb for use below this
2653  // block.
2654  //
2655  // Cursors returned by leveldb iterate over snapshots, so the
2656  // contents of the pcursor will not be affected by simultaneous
2657  // writes during use below this block.
2658  //
2659  // See discussion here:
2660  // https://github.com/bitcoin/bitcoin/pull/15606#discussion_r274479369
2661  //
2662  LOCK(::cs_main);
2663 
2664  chainstate.ForceFlushStateToDisk();
2665 
2666  maybe_stats = GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman,
2667  CoinStatsHashType::HASH_SERIALIZED,
2668  node.rpc_interruption_point);
2669  if (!maybe_stats) {
2670  throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
2671  }
2672 
2673  pcursor =
2674  std::unique_ptr<CCoinsViewCursor>(chainstate.CoinsDB().Cursor());
2675  tip = CHECK_NONFATAL(
2676  chainstate.m_blockman.LookupBlockIndex(maybe_stats->hashBlock));
2677  }
2678 
2680  strprintf("writing UTXO snapshot at height %s (%s) to file %s (via %s)",
2681  tip->nHeight, tip->GetBlockHash().ToString(),
2682  fs::PathToString(path), fs::PathToString(temppath)));
2683 
2684  SnapshotMetadata metadata{tip->GetBlockHash(), maybe_stats->coins_count,
2685  uint64_t(tip->GetChainTxCount())};
2686 
2687  afile << metadata;
2688 
2689  COutPoint key;
2690  Coin coin;
2691  unsigned int iter{0};
2692 
2693  while (pcursor->Valid()) {
2694  if (iter % 5000 == 0) {
2695  node.rpc_interruption_point();
2696  }
2697  ++iter;
2698  if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
2699  afile << key;
2700  afile << coin;
2701  }
2702 
2703  pcursor->Next();
2704  }
2705 
2706  afile.fclose();
2707 
2708  UniValue result(UniValue::VOBJ);
2709  result.pushKV("coins_written", maybe_stats->coins_count);
2710  result.pushKV("base_hash", tip->GetBlockHash().ToString());
2711  result.pushKV("base_height", tip->nHeight);
2712  result.pushKV("path", path.u8string());
2713  result.pushKV("txoutset_hash", maybe_stats->hashSerialized.ToString());
2714  // Cast required because univalue doesn't have serialization specified for
2715  // `unsigned int`, nChainTx's type.
2716  result.pushKV("nchaintx", uint64_t{tip->nChainTx});
2717  return result;
2718 }
2719 
2721  // clang-format off
2722  static const CRPCCommand commands[] = {
2723  // category actor (function)
2724  // ------------------ ----------------------
2725  { "blockchain", getbestblockhash, },
2726  { "blockchain", getblock, },
2727  { "blockchain", getblockfrompeer, },
2728  { "blockchain", getblockchaininfo, },
2729  { "blockchain", getblockcount, },
2730  { "blockchain", getblockhash, },
2731  { "blockchain", getblockheader, },
2732  { "blockchain", getblockstats, },
2733  { "blockchain", getchaintips, },
2734  { "blockchain", getchaintxstats, },
2735  { "blockchain", getdifficulty, },
2736  { "blockchain", gettxout, },
2737  { "blockchain", gettxoutsetinfo, },
2738  { "blockchain", pruneblockchain, },
2739  { "blockchain", verifychain, },
2740  { "blockchain", preciousblock, },
2741  { "blockchain", scantxoutset, },
2742  { "blockchain", getblockfilter, },
2743 
2744  /* Not shown in help */
2745  { "hidden", invalidateblock, },
2746  { "hidden", parkblock, },
2747  { "hidden", reconsiderblock, },
2748  { "hidden", syncwithvalidationinterfacequeue, },
2749  { "hidden", dumptxoutset, },
2750  { "hidden", unparkblock, },
2751  { "hidden", waitfornewblock, },
2752  { "hidden", waitforblock, },
2753  { "hidden", waitforblockheight, },
2754  };
2755  // clang-format on
2756  for (const auto &c : commands) {
2757  t.appendCommand(c.name, &c);
2758  }
2759 }
bool MoneyRange(const Amount nValue)
Definition: amount.h:166
static constexpr Amount MAX_MONEY
No amount larger than this (in satoshi) is valid.
Definition: amount.h:165
RPCHelpMan gettxout()
static RPCHelpMan getblock()
Definition: blockchain.cpp:677
static int ComputeNextBlockAndDepth(const CBlockIndex *tip, const CBlockIndex *blockindex, const CBlockIndex *&next)
Definition: blockchain.cpp:88
static RPCHelpMan getdifficulty()
Definition: blockchain.cpp:439
static std::atomic< bool > g_scan_in_progress
static bool SetHasKeys(const std::set< T > &set)
static RPCHelpMan reconsiderblock()
static T CalculateTruncatedMedian(std::vector< T > &scores)
static RPCHelpMan invalidateblock()
static RPCHelpMan syncwithvalidationinterfacequeue()
Definition: blockchain.cpp:422
static RPCHelpMan getchaintips()
static RPCHelpMan gettxoutsetinfo()
Definition: blockchain.cpp:907
static RPCHelpMan getblockstats()
static CoinStatsHashType ParseHashType(const std::string &hash_type_input)
Definition: blockchain.cpp:893
static RPCHelpMan preciousblock()
static constexpr size_t PER_UTXO_OVERHEAD
double GetDifficulty(const CBlockIndex *blockindex)
Calculate the difficulty for a given block index.
Definition: blockchain.cpp:70
static RPCHelpMan scantxoutset()
static std::condition_variable cond_blockchange
Definition: blockchain.cpp:64
static std::atomic< int > g_scan_progress
RAII object to prevent concurrency issue when scanning the txout set.
static CBlockUndo GetUndoChecked(BlockManager &blockman, const CBlockIndex *pblockindex)
Definition: blockchain.cpp:658
static RPCHelpMan getblockfilter()
static RPCHelpMan getbestblockhash()
Definition: blockchain.cpp:216
static CBlock GetBlockChecked(BlockManager &blockman, const CBlockIndex *pblockindex)
Definition: blockchain.cpp:636
RPCHelpMan getblockchaininfo()
UniValue blockToJSON(BlockManager &blockman, const CBlock &block, const CBlockIndex *tip, const CBlockIndex *blockindex, bool txDetails)
Block description to JSON.
Definition: blockchain.cpp:165
static RPCHelpMan getchaintxstats()
static RPCHelpMan waitforblock()
Definition: blockchain.cpp:300
static RPCHelpMan getblockfrompeer()
Definition: blockchain.cpp:459
static const CBlockIndex * ParseHashOrHeight(const UniValue &param, ChainstateManager &chainman)
Definition: blockchain.cpp:99
static RPCHelpMan getblockhash()
Definition: blockchain.cpp:511
void RegisterBlockchainRPCCommands(CRPCTable &t)
static RPCHelpMan verifychain()
static std::atomic< bool > g_should_abort_scan
RPCHelpMan unparkblock()
UniValue blockheaderToJSON(const CBlockIndex *tip, const CBlockIndex *blockindex)
Block header to JSON.
Definition: blockchain.cpp:131
static RPCHelpMan waitforblockheight()
Definition: blockchain.cpp:362
static RPCHelpMan pruneblockchain()
Definition: blockchain.cpp:816
static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange)
static RPCHelpMan getblockheader()
Definition: blockchain.cpp:540
RPCHelpMan parkblock()
UniValue CreateUTXOSnapshot(NodeContext &node, Chainstate &chainstate, AutoFile &afile, const fs::path &path, const fs::path &temppath)
Helper to create UTXO snapshots given a chainstate and a file handle.
static GlobalMutex cs_blockchange
Definition: blockchain.cpp:63
static RPCHelpMan dumptxoutset()
Serialize the UTXO set to a file for loading elsewhere.
static RPCHelpMan getblockcount()
Definition: blockchain.cpp:198
static RPCHelpMan waitfornewblock()
Definition: blockchain.cpp:243
void RPCNotifyBlockChange(const CBlockIndex *pindex)
Callback for when block tip changed.
Definition: blockchain.cpp:234
bool BlockFilterTypeByName(const std::string &name, BlockFilterType &filter_type)
Find a filter type by its human-readable name.
BlockFilterType
Definition: blockfilter.h:88
BlockFilterIndex * GetBlockFilterIndex(BlockFilterType filter_type)
Get a block filter index by type.
@ SCRIPTS
Scripts & signatures ok.
@ TREE
All parent headers found, difficulty matches, timestamp >= median previous, checkpoint.
const CBlockIndex * LastCommonAncestor(const CBlockIndex *pa, const CBlockIndex *pb)
Find the last common ancestor two blocks have.
Definition: chain.cpp:112
static constexpr int64_t TIMESTAMP_WINDOW
Timestamp window used as a grace period by code that compares external timestamps (such as timestamps...
Definition: chain.h:36
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:53
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:528
int fclose()
Definition: streams.h:541
Complete block filter struct as defined in BIP 157.
Definition: blockfilter.h:111
const std::vector< uint8_t > & GetEncodedFilter() const
Definition: blockfilter.h:134
BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of bloc...
bool LookupFilter(const CBlockIndex *block_index, BlockFilter &filter_out) const
Get a single filter by block.
bool LookupFilterHeader(const CBlockIndex *block_index, uint256 &header_out) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_headers_cache)
Get a single filter header by block.
Definition: block.h:60
std::vector< CTransactionRef > vtx
Definition: block.h:63
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: blockindex.h:25
bool IsValid(enum BlockValidity nUpTo=BlockValidity::TRANSACTIONS) const EXCLUSIVE_LOCKS_REQUIRED(
Check whether this block index entry is valid up to the passed validity level.
Definition: blockindex.h:211
uint256 hashMerkleRoot
Definition: blockindex.h:91
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: blockindex.h:32
CBlockHeader GetBlockHeader() const
Definition: blockindex.h:133
arith_uint256 nChainWork
(memory only) Total amount of work (expected number of hashes) in the chain up to and including this ...
Definition: blockindex.h:51
int64_t GetChainTxCount() const
Get the number of transaction in the chain so far.
Definition: blockindex.h:154
uint32_t nTime
Definition: blockindex.h:92
uint32_t nNonce
Definition: blockindex.h:94
int64_t GetBlockTime() const
Definition: blockindex.h:180
int64_t GetMedianTimePast() const
Definition: blockindex.h:192
uint32_t nBits
Definition: blockindex.h:93
unsigned int nTx
Number of transactions in this block.
Definition: blockindex.h:60
int32_t nVersion
block header
Definition: blockindex.h:90
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition: blockindex.cpp:78
BlockHash GetBlockHash() const
Definition: blockindex.h:146
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: blockindex.h:38
unsigned int nChainTx
(memory only) Number of transactions in the chain up to and including this block.
Definition: blockindex.h:77
Undo information for a CBlock.
Definition: undo.h:73
std::vector< CTxUndo > vtxundo
Definition: undo.h:76
An in-memory indexed chain of blocks.
Definition: chain.h:134
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:150
CBlockIndex * FindEarliestAtLeast(int64_t nTime, int height) const
Find the earliest block with timestamp equal or greater than the given time and height equal or great...
Definition: chain.cpp:62
int Height() const
Return the maximal height in the chain.
Definition: chain.h:186
const CBlockIndex * FindFork(const CBlockIndex *pindex) const
Find the last common block between this chain and a block index entry.
Definition: chain.cpp:49
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
Definition: chain.h:166
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
Definition: chainparams.h:80
std::string NetworkIDString() const
Return the BIP70 network string (main, test or regtest)
Definition: chainparams.h:127
const ChainTxData & TxData() const
Definition: chainparams.h:140
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:221
BlockHash GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:214
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: coins.cpp:95
Cursor for iterating over CoinsView state.
Definition: coins.h:143
virtual void Next()=0
virtual bool Valid() const =0
virtual bool GetKey(COutPoint &key) const =0
virtual bool GetValue(Coin &coin) const =0
CCoinsViewCursor * Cursor() const override
Get a cursor to iterate over the whole state.
Definition: txdb.cpp:208
Abstract view on the open txout dataset.
Definition: coins.h:163
virtual BlockHash GetBestBlock() const
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:16
CCoinsView that brings transactions from a mempool into view.
Definition: txmempool.h:591
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: txmempool.cpp:607
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:177
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:20
uint32_t GetN() const
Definition: transaction.h:36
const TxId & GetTxId() const
Definition: transaction.h:35
RPC command dispatcher.
Definition: server.h:194
void appendCommand(const std::string &name, const CRPCCommand *pcmd)
Appends a CRPCCommand to the dispatch table.
Definition: server.cpp:327
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:431
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:209
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:296
bool isSpent(const COutPoint &outpoint) const
Definition: txmempool.cpp:130
An output of a transaction.
Definition: transaction.h:128
CScript scriptPubKey
Definition: transaction.h:131
Amount nValue
Definition: transaction.h:130
Restore the UTXO in a Coin at a given COutPoint.
Definition: undo.h:62
RAII wrapper for VerifyDB: Verify consistency of the block and coin databases.
Definition: validation.h:551
VerifyDBResult VerifyDB(Chainstate &chainstate, CCoinsView &coinsview, int nCheckLevel, int nCheckDepth) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Definition: validation.h:630
bool IsBlockAvalancheFinalized(const CBlockIndex *pindex) const EXCLUSIVE_LOCKS_REQUIRED(!cs_avalancheFinalizedBlockIndex)
Checks if a block is finalized by avalanche voting.
CChain m_chain
The current chain of blockheaders we consult and build on.
Definition: validation.h:739
bool IsInitialBlockDownload() const
Check whether we are doing an initial block download (synchronizing from disk or network)
CCoinsViewDB & CoinsDB() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:772
void ForceFlushStateToDisk()
Unconditionally flush all changes to disk.
void UnparkBlockAndChildren(CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Remove parked status from a block and its descendants.
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:765
node::BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all Chainstate instances.
Definition: validation.h:703
bool ActivateBestChain(BlockValidationState &state, std::shared_ptr< const CBlock > pblock=nullptr, avalanche::Processor *const avalanche=nullptr, bool skip_checkblockindex=false) EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex
Find the best known block, and make it the tip of the block chain.
void ClearAvalancheFinalizedBlock() EXCLUSIVE_LOCKS_REQUIRED(!cs_avalancheFinalizedBlockIndex)
Clear avalanche finalization.
bool ParkBlock(BlockValidationState &state, CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex
Park a block.
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:1153
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1363
const CChainParams & GetParams() const
Definition: validation.h:1247
node::BlockMap & BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:1373
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1366
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1369
kernel::Notifications & GetNotifications() const
Definition: validation.h:1262
const Consensus::Params & GetConsensus() const
Definition: validation.h:1250
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1285
A UTXO entry.
Definition: coins.h:28
uint32_t GetHeight() const
Definition: coins.h:45
bool IsCoinBase() const
Definition: coins.h:46
CTxOut & GetTxOut()
Definition: coins.h:49
Definition: config.h:19
Different type to mark Mutex at global scope.
Definition: sync.h:144
virtual std::optional< std::string > FetchBlock(const Config &config, NodeId peer_id, const CBlockIndex &block_index)=0
Attempt to manually fetch block from a given peer.
void push_back(UniValue val)
Definition: univalue.cpp:96
const std::string & get_str() const
@ VOBJ
Definition: univalue.h:31
@ VARR
Definition: univalue.h:32
bool isNull() const
Definition: univalue.h:104
size_t size() const
Definition: univalue.h:92
const std::vector< UniValue > & getValues() const
Int getInt() const
Definition: univalue.h:157
const UniValue & get_array() const
bool isNum() const
Definition: univalue.h:109
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:115
bool IsValid() const
Definition: validation.h:112
std::string GetRejectReason() const
Definition: validation.h:116
std::string ToString() const
Definition: validation.h:118
uint8_t * begin()
Definition: uint256.h:85
std::string ToString() const
Definition: uint256.h:80
std::string GetHex() const
Definition: uint256.cpp:16
std::string GetHex() const
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
std::string u8string() const
Definition: fs.h:72
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
Definition: blockstorage.h:74
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos) const
Functions for disk access for blocks.
CBlockIndex * LookupBlockIndex(const BlockHash &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
bool UndoReadFromDisk(CBlockUndo &blockundo, const CBlockIndex &index) const
uint64_t GetPruneTarget() const
Attempt to stay below this number of bytes of block files.
Definition: blockstorage.h:238
uint64_t CalculateCurrentUsage()
Calculate the amount of disk space the block & undo files currently use.
bool IsPruneMode() const
Whether running in -prune mode.
Definition: blockstorage.h:235
Metadata describing a serialized version of a UTXO set from which an assumeutxo Chainstate can be con...
Definition: utxo_snapshot.h:21
256-bit opaque blob.
Definition: uint256.h:129
std::unique_ptr< CoinStatsIndex > g_coin_stats_index
The global UTXO set hash object.
void TxToUniv(const CTransaction &tx, const BlockHash &hashBlock, UniValue &entry, bool include_hex=true, int serialize_flags=0, const CTxUndo *txundo=nullptr)
Definition: core_write.cpp:217
void ScriptPubKeyToUniv(const CScript &scriptPubKey, UniValue &out, bool fIncludeHex)
Definition: core_write.cpp:190
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:7
std::unique_ptr< Descriptor > InferDescriptor(const CScript &script, const SigningProvider &provider)
Find a descriptor for the specified script, using information from provider where possible.
#define LogPrint(category,...)
Definition: logging.h:211
unsigned int nHeight
@ RPC
Definition: logging.h:47
@ NONE
Definition: logging.h:39
static path u8path(const std::string &utf8_str)
Definition: fs.h:90
static bool exists(const path &p)
Definition: fs.h:102
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition: fs.h:142
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:30
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:39
CoinStatsHashType
Definition: coinstats.h:23
Definition: init.h:28
std::optional< kernel::CCoinsStats > GetUTXOStats(CCoinsView *view, BlockManager &blockman, kernel::CoinStatsHashType hash_type, const std::function< void()> &interruption_point, const CBlockIndex *pindex, bool index_requested)
Calculate statistics about the unspent transaction output set.
Definition: coinstats.cpp:16
int64_t NodeId
Definition: nodeid.h:10
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:315
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:58
@ RPC_MISC_ERROR
General application defined errors std::exception thrown in command handling.
Definition: protocol.h:38
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:46
@ RPC_INTERNAL_ERROR
Definition: protocol.h:33
@ RPC_DATABASE_ERROR
Database error.
Definition: protocol.h:48
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:42
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:150
std::vector< CScript > EvalDescriptorStringOrObject(const UniValue &scanobject, FlatSigningProvider &provider)
Evaluate a descriptor given as a string, or as a {"desc":...,"range":...} object, with default range ...
Definition: util.cpp:1290
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:167
const std::string UNIX_EPOCH_TIME
String used to describe UNIX epoch time in documentation, factored out to a constant for consistency.
Definition: util.cpp:22
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded values (throws error if not hex).
Definition: util.cpp:73
@ SER_NETWORK
Definition: serialize.h:152
size_t GetSerializeSize(const T &t, int nVersion=0)
Definition: serialize.h:1258
bool IsRPCRunning()
Query whether RPC is running.
Definition: server.cpp:378
int RPCSerializationFlags()
Retrieves any serialization flags requested in command line argument.
Definition: server.cpp:679
ArgsManager & EnsureAnyArgsman(const std::any &context)
Definition: server_util.cpp:48
ChainstateManager & EnsureAnyChainman(const std::any &context)
Definition: server_util.cpp:59
NodeContext & EnsureAnyNodeContext(const std::any &context)
Definition: server_util.cpp:21
PeerManager & EnsurePeerman(const NodeContext &node)
Definition: server_util.cpp:72
CTxMemPool & EnsureMemPool(const NodeContext &node)
Definition: server_util.cpp:29
ChainstateManager & EnsureChainman(const NodeContext &node)
Definition: server_util.cpp:52
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
auto Join(const std::vector< T > &list, const BaseType &separator, UnaryOp unary_op) -> decltype(unary_op(list.at(0)))
Join a list of items.
Definition: string.h:53
Definition: amount.h:19
static constexpr Amount zero() noexcept
Definition: amount.h:32
A BlockHash is a unqiue identifier for a block.
Definition: blockhash.h:13
BlockHash hash
Definition: blockchain.cpp:59
Comparison function for sorting the getchaintips heads.
bool operator()(const CBlockIndex *a, const CBlockIndex *b) const
static const Currency & get()
Definition: amount.cpp:18
std::string ticker
Definition: amount.h:150
@ RANGE
Special type that is a NUM or [NUM,NUM].
@ STR_HEX
Special type that is a STR with only hex chars.
std::string DefaultHint
Hint for default value.
Definition: util.h:195
@ OMITTED
The arg is optional for one of two reasons:
@ NO
Required arg.
std::string oneline_description
Should be empty unless it is supposed to override the auto-generated summary line.
Definition: util.h:128
bool skip_type_check
Definition: util.h:125
@ ELISION
Special type to denote elision (...)
@ NUM_TIME
Special numeric to denote unix epoch time.
@ STR_HEX
Special string with only hex chars.
@ STR_AMOUNT
Special string to represent a floating point amount.
A TxId is the identifier of a transaction.
Definition: txid.h:14
uint64_t nDiskSize
Definition: coinstats.h:36
Amount total_unspendables_scripts
Total cumulative amount of outputs sent to unspendable scripts (OP_RETURN for example) up to and incl...
Definition: coinstats.h:67
Amount total_coinbase_amount
Total cumulative amount of coinbase outputs up to and including this block.
Definition: coinstats.h:60
Amount total_unspendables_genesis_block
The unspendable coinbase amount from the genesis block.
Definition: coinstats.h:62
uint64_t nTransactions
Definition: coinstats.h:32
uint64_t nTransactionOutputs
Definition: coinstats.h:33
uint64_t nBogoSize
Definition: coinstats.h:34
bool index_used
Signals if the coinstatsindex was used to retrieve the statistics.
Definition: coinstats.h:43
Amount total_unspendables_bip30
The two unspendable coinbase outputs total amount caused by BIP30.
Definition: coinstats.h:64
Amount total_prevout_spent_amount
Total cumulative amount of prevouts spent up to and including this block.
Definition: coinstats.h:54
BlockHash hashBlock
Definition: coinstats.h:31
Amount total_unspendables_unclaimed_rewards
Total cumulative amount of coins lost due to unclaimed miner rewards up to and including this block.
Definition: coinstats.h:70
uint256 hashSerialized
Definition: coinstats.h:35
Amount total_new_outputs_ex_coinbase_amount
Total cumulative amount of outputs created up to and including this block.
Definition: coinstats.h:57
Amount total_unspendable_amount
Total cumulative amount of unspendable coins up to and including this block.
Definition: coinstats.h:52
NodeContext struct containing references to chain state and connection state.
Definition: context.h:43
#define WAIT_LOCK(cs, name)
Definition: sync.h:317
#define AssertLockNotHeld(cs)
Definition: sync.h:163
#define LOCK(cs)
Definition: sync.h:306
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:357
static int count
Definition: tests.c:31
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:56
#define LOG_TIME_SECONDS(end_msg)
Definition: timer.h:103
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1202
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:68
static const uint32_t MEMPOOL_HEIGHT
Fake height value used in Coins to signify they are only in the memory pool(since 0....
Definition: txmempool.h:45
uint256 uint256S(const char *str)
uint256 from const char *.
Definition: uint256.h:143
const UniValue NullUniValue
Definition: univalue.cpp:16
Amount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams)
double GuessVerificationProgress(const ChainTxData &data, const CBlockIndex *pindex)
Guess how far we are in the verification process at the given block index require cs_main if pindex h...
const std::vector< std::string > CHECKLEVEL_DOC
Documentation for argument 'checklevel'.
Definition: validation.cpp:97
void PruneBlockFilesManual(Chainstate &active_chainstate, int nManualPruneHeight)
Prune block files up to a given height.
static constexpr int DEFAULT_CHECKLEVEL
Definition: validation.h:96
static const unsigned int MIN_BLOCKS_TO_KEEP
Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ActiveChain().Tip() will not be pr...
Definition: validation.h:94
static const signed int DEFAULT_CHECKBLOCKS
Definition: validation.h:95
void SyncWithValidationInterfaceQueue()
This is a synonym for the following, which asserts certain locks are not held: std::promise<void> pro...
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:11
bilingual_str GetWarnings(bool verbose)
Format a string that describes several potential problems detected by the core.
Definition: warnings.cpp:41