Bitcoin ABC  0.29.2
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 <config.h>
13 #include <consensus/amount.h>
14 #include <consensus/params.h>
15 #include <consensus/validation.h>
16 #include <core_io.h>
17 #include <fs.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/strencodings.h>
39 #include <util/translation.h>
40 #include <validation.h>
41 #include <validationinterface.h>
42 #include <warnings.h>
43 
44 #include <condition_variable>
45 #include <cstdint>
46 #include <memory>
47 #include <mutex>
48 
49 using node::BlockManager;
50 using node::CCoinsStats;
52 using node::GetUTXOStats;
53 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.get_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  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].get_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].get_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].get_int();
389 
390  if (!request.params[1].isNull()) {
391  timeout = request.params[1].get_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  "\nAttempt 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_EMPTY, "", /*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].get_int64()};
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].get_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 
636 static CBlock GetBlockChecked(const Config &config, BlockManager &blockman,
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 (!ReadBlockFromDisk(block, pblockindex,
648  config.GetChainParams().GetConsensus())) {
649  // Block not found on disk. This could be because we have the block
650  // header in our index but not yet have the block or did not accept the
651  // block. Or if the block was pruned right after we released the lock
652  // above.
653  throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
654  }
655 
656  return block;
657 }
658 
660  const CBlockIndex *pblockindex) {
661  CBlockUndo blockUndo;
662 
663  {
664  LOCK(cs_main);
665  if (blockman.IsBlockPruned(pblockindex)) {
667  "Undo data not available (pruned data)");
668  }
669  }
670 
671  if (!UndoReadFromDisk(blockUndo, pblockindex)) {
672  throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
673  }
674 
675  return blockUndo;
676 }
677 
679  return RPCHelpMan{
680  "getblock",
681  "If verbosity is 0 or false, returns a string that is serialized, "
682  "hex-encoded data for block 'hash'.\n"
683  "If verbosity is 1 or true, returns an Object with information about "
684  "block <hash>.\n"
685  "If verbosity is 2, returns an Object with information about block "
686  "<hash> and information about each transaction.\n",
687  {
689  "The block hash"},
690  {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1},
691  "0 for hex-encoded data, 1 for a json object, and 2 for json "
692  "object with transaction data"},
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].get_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(config, 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].get_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 = node::GetFirstStoredBlock(block);
886 
887  return static_cast<uint64_t>(last_block->nHeight);
888  },
889  };
890 }
891 
892 static CoinStatsHashType ParseHashType(const std::string &hash_type_input) {
893  if (hash_type_input == "hash_serialized") {
894  return CoinStatsHashType::HASH_SERIALIZED;
895  } else if (hash_type_input == "muhash") {
896  return CoinStatsHashType::MUHASH;
897  } else if (hash_type_input == "none") {
899  } else {
900  throw JSONRPCError(
902  strprintf("%s is not a valid hash_type", hash_type_input));
903  }
904 }
905 
907  return RPCHelpMan{
908  "gettxoutsetinfo",
909  "Returns statistics about the unspent transaction output set.\n"
910  "Note this call may take some time if you are not using "
911  "coinstatsindex.\n",
912  {
913  {"hash_type", RPCArg::Type::STR, RPCArg::Default{"hash_serialized"},
914  "Which UTXO set hash should be calculated. Options: "
915  "'hash_serialized' (the legacy algorithm), 'muhash', 'none'."},
916  {"hash_or_height",
919  "The block hash or height of the target height (only available "
920  "with coinstatsindex).",
921  "",
922  {"", "string or numeric"}},
923  {"use_index", RPCArg::Type::BOOL, RPCArg::Default{true},
924  "Use coinstatsindex, if available."},
925  },
926  RPCResult{
928  "",
929  "",
930  {
931  {RPCResult::Type::NUM, "height",
932  "The current block height (index)"},
933  {RPCResult::Type::STR_HEX, "bestblock",
934  "The hash of the block at the tip of the chain"},
935  {RPCResult::Type::NUM, "txouts",
936  "The number of unspent transaction outputs"},
937  {RPCResult::Type::NUM, "bogosize",
938  "Database-independent, meaningless metric indicating "
939  "the UTXO set size"},
940  {RPCResult::Type::STR_HEX, "hash_serialized",
941  /* optional */ true,
942  "The serialized hash (only present if 'hash_serialized' "
943  "hash_type is chosen)"},
944  {RPCResult::Type::STR_HEX, "muhash", /* optional */ true,
945  "The serialized hash (only present if 'muhash' "
946  "hash_type is chosen)"},
947  {RPCResult::Type::NUM, "transactions",
948  "The number of transactions with unspent outputs (not "
949  "available when coinstatsindex is used)"},
950  {RPCResult::Type::NUM, "disk_size",
951  "The estimated size of the chainstate on disk (not "
952  "available when coinstatsindex is used)"},
953  {RPCResult::Type::STR_AMOUNT, "total_amount",
954  "The total amount"},
955  {RPCResult::Type::STR_AMOUNT, "total_unspendable_amount",
956  "The total amount of coins permanently excluded from the UTXO "
957  "set (only available if coinstatsindex is used)"},
959  "block_info",
960  "Info on amounts in the block at this block height (only "
961  "available if coinstatsindex is used)",
962  {{RPCResult::Type::STR_AMOUNT, "prevout_spent",
963  "Total amount of all prevouts spent in this block"},
964  {RPCResult::Type::STR_AMOUNT, "coinbase",
965  "Coinbase subsidy amount of this block"},
966  {RPCResult::Type::STR_AMOUNT, "new_outputs_ex_coinbase",
967  "Total amount of new outputs created by this block"},
968  {RPCResult::Type::STR_AMOUNT, "unspendable",
969  "Total amount of unspendable outputs created in this block"},
971  "unspendables",
972  "Detailed view of the unspendable categories",
973  {
974  {RPCResult::Type::STR_AMOUNT, "genesis_block",
975  "The unspendable amount of the Genesis block subsidy"},
976  {RPCResult::Type::STR_AMOUNT, "bip30",
977  "Transactions overridden by duplicates (no longer "
978  "possible with BIP30)"},
979  {RPCResult::Type::STR_AMOUNT, "scripts",
980  "Amounts sent to scripts that are unspendable (for "
981  "example OP_RETURN outputs)"},
982  {RPCResult::Type::STR_AMOUNT, "unclaimed_rewards",
983  "Fee rewards that miners did not claim in their "
984  "coinbase transaction"},
985  }}}},
986  }},
987  RPCExamples{
988  HelpExampleCli("gettxoutsetinfo", "") +
989  HelpExampleCli("gettxoutsetinfo", R"("none")") +
990  HelpExampleCli("gettxoutsetinfo", R"("none" 1000)") +
992  "gettxoutsetinfo",
993  R"("none" '"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"')") +
994  HelpExampleRpc("gettxoutsetinfo", "") +
995  HelpExampleRpc("gettxoutsetinfo", R"("none")") +
996  HelpExampleRpc("gettxoutsetinfo", R"("none", 1000)") +
998  "gettxoutsetinfo",
999  R"("none", "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09")")},
1000  [&](const RPCHelpMan &self, const Config &config,
1001  const JSONRPCRequest &request) -> UniValue {
1002  UniValue ret(UniValue::VOBJ);
1003 
1004  const CBlockIndex *pindex{nullptr};
1005  const CoinStatsHashType hash_type{
1006  request.params[0].isNull()
1007  ? CoinStatsHashType::HASH_SERIALIZED
1008  : ParseHashType(request.params[0].get_str())};
1009  bool index_requested =
1010  request.params[2].isNull() || request.params[2].get_bool();
1011 
1012  NodeContext &node = EnsureAnyNodeContext(request.context);
1013  ChainstateManager &chainman = EnsureChainman(node);
1014  Chainstate &active_chainstate = chainman.ActiveChainstate();
1015  active_chainstate.ForceFlushStateToDisk();
1016 
1017  CCoinsView *coins_view;
1018  BlockManager *blockman;
1019  {
1020  LOCK(::cs_main);
1021  coins_view = &active_chainstate.CoinsDB();
1022  blockman = &active_chainstate.m_blockman;
1023  pindex = blockman->LookupBlockIndex(coins_view->GetBestBlock());
1024  }
1025 
1026  if (!request.params[1].isNull()) {
1027  if (!g_coin_stats_index) {
1029  "Querying specific block heights "
1030  "requires coinstatsindex");
1031  }
1032 
1033  if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1035  "hash_serialized hash type cannot be "
1036  "queried for a specific block");
1037  }
1038 
1039  pindex = ParseHashOrHeight(request.params[1], chainman);
1040  }
1041 
1042  if (index_requested && g_coin_stats_index) {
1043  if (!g_coin_stats_index->BlockUntilSyncedToCurrentChain()) {
1044  const IndexSummary summary{
1045  g_coin_stats_index->GetSummary()};
1046 
1047  // If a specific block was requested and the index has
1048  // already synced past that height, we can return the data
1049  // already even though the index is not fully synced yet.
1050  if (pindex->nHeight > summary.best_block_height) {
1051  throw JSONRPCError(
1053  strprintf(
1054  "Unable to get data because coinstatsindex is "
1055  "still syncing. Current height: %d",
1056  summary.best_block_height));
1057  }
1058  }
1059  }
1060 
1061  const std::optional<CCoinsStats> maybe_stats = GetUTXOStats(
1062  coins_view, *blockman, hash_type, node.rpc_interruption_point,
1063  pindex, index_requested);
1064  if (maybe_stats.has_value()) {
1065  const CCoinsStats &stats = maybe_stats.value();
1066  ret.pushKV("height", int64_t(stats.nHeight));
1067  ret.pushKV("bestblock", stats.hashBlock.GetHex());
1068  ret.pushKV("txouts", int64_t(stats.nTransactionOutputs));
1069  ret.pushKV("bogosize", int64_t(stats.nBogoSize));
1070  if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1071  ret.pushKV("hash_serialized",
1072  stats.hashSerialized.GetHex());
1073  }
1074  if (hash_type == CoinStatsHashType::MUHASH) {
1075  ret.pushKV("muhash", stats.hashSerialized.GetHex());
1076  }
1077  ret.pushKV("total_amount", stats.nTotalAmount);
1078  if (!stats.index_used) {
1079  ret.pushKV("transactions",
1080  static_cast<int64_t>(stats.nTransactions));
1081  ret.pushKV("disk_size", stats.nDiskSize);
1082  } else {
1083  ret.pushKV("total_unspendable_amount",
1084  stats.total_unspendable_amount);
1085 
1086  CCoinsStats prev_stats{};
1087  if (pindex->nHeight > 0) {
1088  const std::optional<CCoinsStats> maybe_prev_stats =
1089  GetUTXOStats(coins_view, *blockman, hash_type,
1090  node.rpc_interruption_point,
1091  pindex->pprev, index_requested);
1092  if (!maybe_prev_stats) {
1094  "Unable to read UTXO set");
1095  }
1096  prev_stats = maybe_prev_stats.value();
1097  }
1098 
1099  UniValue block_info(UniValue::VOBJ);
1100  block_info.pushKV(
1101  "prevout_spent",
1103  prev_stats.total_prevout_spent_amount);
1104  block_info.pushKV("coinbase",
1105  stats.total_coinbase_amount -
1106  prev_stats.total_coinbase_amount);
1107  block_info.pushKV(
1108  "new_outputs_ex_coinbase",
1110  prev_stats.total_new_outputs_ex_coinbase_amount);
1111  block_info.pushKV("unspendable",
1112  stats.total_unspendable_amount -
1113  prev_stats.total_unspendable_amount);
1114 
1115  UniValue unspendables(UniValue::VOBJ);
1116  unspendables.pushKV(
1117  "genesis_block",
1119  prev_stats.total_unspendables_genesis_block);
1120  unspendables.pushKV(
1121  "bip30", stats.total_unspendables_bip30 -
1122  prev_stats.total_unspendables_bip30);
1123  unspendables.pushKV(
1124  "scripts", stats.total_unspendables_scripts -
1125  prev_stats.total_unspendables_scripts);
1126  unspendables.pushKV(
1127  "unclaimed_rewards",
1129  prev_stats.total_unspendables_unclaimed_rewards);
1130  block_info.pushKV("unspendables", unspendables);
1131 
1132  ret.pushKV("block_info", block_info);
1133  }
1134  } else {
1136  "Unable to read UTXO set");
1137  }
1138  return ret;
1139  },
1140  };
1141 }
1142 
1144  return RPCHelpMan{
1145  "gettxout",
1146  "Returns details about an unspent transaction output.\n",
1147  {
1149  "The transaction id"},
1150  {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
1151  {"include_mempool", RPCArg::Type::BOOL, RPCArg::Default{true},
1152  "Whether to include the mempool. Note that an unspent output that "
1153  "is spent in the mempool won't appear."},
1154  },
1155  {
1156  RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "",
1157  ""},
1158  RPCResult{
1159  "Otherwise",
1161  "",
1162  "",
1163  {
1164  {RPCResult::Type::STR_HEX, "bestblock",
1165  "The hash of the block at the tip of the chain"},
1166  {RPCResult::Type::NUM, "confirmations",
1167  "The number of confirmations"},
1168  {RPCResult::Type::STR_AMOUNT, "value",
1169  "The transaction value in " + Currency::get().ticker},
1171  "scriptPubKey",
1172  "",
1173  {
1174  {RPCResult::Type::STR_HEX, "asm", ""},
1175  {RPCResult::Type::STR_HEX, "hex", ""},
1176  {RPCResult::Type::NUM, "reqSigs",
1177  "Number of required signatures"},
1178  {RPCResult::Type::STR_HEX, "type",
1179  "The type, eg pubkeyhash"},
1181  "addresses",
1182  "array of eCash addresses",
1183  {{RPCResult::Type::STR, "address", "eCash address"}}},
1184  }},
1185  {RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
1186  }},
1187  },
1188  RPCExamples{"\nGet unspent transactions\n" +
1189  HelpExampleCli("listunspent", "") + "\nView the details\n" +
1190  HelpExampleCli("gettxout", "\"txid\" 1") +
1191  "\nAs a JSON-RPC call\n" +
1192  HelpExampleRpc("gettxout", "\"txid\", 1")},
1193  [&](const RPCHelpMan &self, const Config &config,
1194  const JSONRPCRequest &request) -> UniValue {
1195  NodeContext &node = EnsureAnyNodeContext(request.context);
1196  ChainstateManager &chainman = EnsureChainman(node);
1197  LOCK(cs_main);
1198 
1199  UniValue ret(UniValue::VOBJ);
1200 
1201  TxId txid(ParseHashV(request.params[0], "txid"));
1202  int n = request.params[1].get_int();
1203  COutPoint out(txid, n);
1204  bool fMempool = true;
1205  if (!request.params[2].isNull()) {
1206  fMempool = request.params[2].get_bool();
1207  }
1208 
1209  Coin coin;
1210  Chainstate &active_chainstate = chainman.ActiveChainstate();
1211  CCoinsViewCache *coins_view = &active_chainstate.CoinsTip();
1212 
1213  if (fMempool) {
1214  const CTxMemPool &mempool = EnsureMemPool(node);
1215  LOCK(mempool.cs);
1216  CCoinsViewMemPool view(coins_view, mempool);
1217  if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
1218  return NullUniValue;
1219  }
1220  } else {
1221  if (!coins_view->GetCoin(out, coin)) {
1222  return NullUniValue;
1223  }
1224  }
1225 
1226  const CBlockIndex *pindex =
1227  active_chainstate.m_blockman.LookupBlockIndex(
1228  coins_view->GetBestBlock());
1229  ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
1230  if (coin.GetHeight() == MEMPOOL_HEIGHT) {
1231  ret.pushKV("confirmations", 0);
1232  } else {
1233  ret.pushKV("confirmations",
1234  int64_t(pindex->nHeight - coin.GetHeight() + 1));
1235  }
1236  ret.pushKV("value", coin.GetTxOut().nValue);
1238  ScriptPubKeyToUniv(coin.GetTxOut().scriptPubKey, o, true);
1239  ret.pushKV("scriptPubKey", o);
1240  ret.pushKV("coinbase", coin.IsCoinBase());
1241 
1242  return ret;
1243  },
1244  };
1245 }
1246 
1248  return RPCHelpMan{
1249  "verifychain",
1250  "Verifies blockchain database.\n",
1251  {
1252  {"checklevel", RPCArg::Type::NUM,
1254  strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL)},
1255  strprintf("How thorough the block verification is:\n - %s",
1256  Join(CHECKLEVEL_DOC, "\n- "))},
1257  {"nblocks", RPCArg::Type::NUM,
1259  "The number of blocks to check."},
1260  },
1262  "Verification finished successfully. If false, check "
1263  "debug.log for reason."},
1264  RPCExamples{HelpExampleCli("verifychain", "") +
1265  HelpExampleRpc("verifychain", "")},
1266  [&](const RPCHelpMan &self, const Config &config,
1267  const JSONRPCRequest &request) -> UniValue {
1268  const int check_level(request.params[0].isNull()
1270  : request.params[0].get_int());
1271  const int check_depth{request.params[1].isNull()
1273  : request.params[1].get_int()};
1274 
1275  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1276  LOCK(cs_main);
1277 
1278  Chainstate &active_chainstate = chainman.ActiveChainstate();
1279  return CVerifyDB().VerifyDB(
1280  active_chainstate, active_chainstate.CoinsTip(),
1281  check_level, 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("pruneheight",
1371 
1372  const bool automatic_pruning{
1373  chainman.m_blockman.GetPruneTarget() !=
1374  BlockManager::PRUNE_TARGET_MANUAL};
1375  obj.pushKV("automatic_pruning", automatic_pruning);
1376  if (automatic_pruning) {
1377  obj.pushKV("prune_target_size",
1378  chainman.m_blockman.GetPruneTarget());
1379  }
1380  }
1381 
1382  obj.pushKV("warnings", GetWarnings(false).original);
1383  return obj;
1384  },
1385  };
1386 }
1387 
1390  bool operator()(const CBlockIndex *a, const CBlockIndex *b) const {
1391  // Make sure that unequal blocks with the same height do not compare
1392  // equal. Use the pointers themselves to make a distinction.
1393  if (a->nHeight != b->nHeight) {
1394  return (a->nHeight > b->nHeight);
1395  }
1396 
1397  return a < b;
1398  }
1399 };
1400 
1402  return RPCHelpMan{
1403  "getchaintips",
1404  "Return information about all known tips in the block tree, including "
1405  "the main chain as well as orphaned branches.\n",
1406  {},
1407  RPCResult{
1409  "",
1410  "",
1412  "",
1413  "",
1414  {
1415  {RPCResult::Type::NUM, "height", "height of the chain tip"},
1416  {RPCResult::Type::STR_HEX, "hash", "block hash of the tip"},
1417  {RPCResult::Type::NUM, "branchlen",
1418  "zero for main chain, otherwise length of branch connecting "
1419  "the tip to the main chain"},
1420  {RPCResult::Type::STR, "status",
1421  "status of the chain, \"active\" for the main chain\n"
1422  "Possible values for status:\n"
1423  "1. \"invalid\" This branch contains at "
1424  "least one invalid block\n"
1425  "2. \"parked\" This branch contains at "
1426  "least one parked block\n"
1427  "3. \"headers-only\" Not all blocks for this "
1428  "branch are available, but the headers are valid\n"
1429  "4. \"valid-headers\" All blocks are available for "
1430  "this branch, but they were never fully validated\n"
1431  "5. \"valid-fork\" This branch is not part of "
1432  "the active chain, but is fully validated\n"
1433  "6. \"active\" This is the tip of the "
1434  "active main chain, which is certainly valid"},
1435  }}}},
1436  RPCExamples{HelpExampleCli("getchaintips", "") +
1437  HelpExampleRpc("getchaintips", "")},
1438  [&](const RPCHelpMan &self, const Config &config,
1439  const JSONRPCRequest &request) -> UniValue {
1440  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1441  LOCK(cs_main);
1442  CChain &active_chain = chainman.ActiveChain();
1443 
1455  std::set<const CBlockIndex *, CompareBlocksByHeight> setTips;
1456  std::set<const CBlockIndex *> setOrphans;
1457  std::set<const CBlockIndex *> setPrevs;
1458 
1459  for (const auto &[_, block_index] : chainman.BlockIndex()) {
1460  if (!active_chain.Contains(&block_index)) {
1461  setOrphans.insert(&block_index);
1462  setPrevs.insert(block_index.pprev);
1463  }
1464  }
1465 
1466  for (std::set<const CBlockIndex *>::iterator it =
1467  setOrphans.begin();
1468  it != setOrphans.end(); ++it) {
1469  if (setPrevs.erase(*it) == 0) {
1470  setTips.insert(*it);
1471  }
1472  }
1473 
1474  // Always report the currently active tip.
1475  setTips.insert(active_chain.Tip());
1476 
1477  /* Construct the output array. */
1478  UniValue res(UniValue::VARR);
1479  for (const CBlockIndex *block : setTips) {
1480  UniValue obj(UniValue::VOBJ);
1481  obj.pushKV("height", block->nHeight);
1482  obj.pushKV("hash", block->phashBlock->GetHex());
1483 
1484  const int branchLen =
1485  block->nHeight - active_chain.FindFork(block)->nHeight;
1486  obj.pushKV("branchlen", branchLen);
1487 
1488  std::string status;
1489  if (active_chain.Contains(block)) {
1490  // This block is part of the currently active chain.
1491  status = "active";
1492  } else if (block->nStatus.isInvalid()) {
1493  // This block or one of its ancestors is invalid.
1494  status = "invalid";
1495  } else if (block->nStatus.isOnParkedChain()) {
1496  // This block or one of its ancestors is parked.
1497  status = "parked";
1498  } else if (!block->HaveTxsDownloaded()) {
1499  // This block cannot be connected because full block data
1500  // for it or one of its parents is missing.
1501  status = "headers-only";
1502  } else if (block->IsValid(BlockValidity::SCRIPTS)) {
1503  // This block is fully validated, but no longer part of the
1504  // active chain. It was probably the active block once, but
1505  // was reorganized.
1506  status = "valid-fork";
1507  } else if (block->IsValid(BlockValidity::TREE)) {
1508  // The headers for this block are valid, but it has not been
1509  // validated. It was probably never part of the most-work
1510  // chain.
1511  status = "valid-headers";
1512  } else {
1513  // No clue.
1514  status = "unknown";
1515  }
1516  obj.pushKV("status", status);
1517 
1518  res.push_back(obj);
1519  }
1520 
1521  return res;
1522  },
1523  };
1524 }
1525 
1527  return RPCHelpMan{
1528  "preciousblock",
1529  "Treats a block as if it were received before others with the same "
1530  "work.\n"
1531  "\nA later preciousblock call can override the effect of an earlier "
1532  "one.\n"
1533  "\nThe effects of preciousblock are not retained across restarts.\n",
1534  {
1536  "the hash of the block to mark as precious"},
1537  },
1539  RPCExamples{HelpExampleCli("preciousblock", "\"blockhash\"") +
1540  HelpExampleRpc("preciousblock", "\"blockhash\"")},
1541  [&](const RPCHelpMan &self, const Config &config,
1542  const JSONRPCRequest &request) -> UniValue {
1543  BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1544  CBlockIndex *pblockindex;
1545 
1546  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1547  {
1548  LOCK(cs_main);
1549  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1550  if (!pblockindex) {
1552  "Block not found");
1553  }
1554  }
1555 
1556  BlockValidationState state;
1557  chainman.ActiveChainstate().PreciousBlock(state, pblockindex);
1558 
1559  if (!state.IsValid()) {
1561  }
1562 
1563  // Block to make sure wallet/indexers sync before returning
1565 
1566  return NullUniValue;
1567  },
1568  };
1569 }
1570 
1572  return RPCHelpMan{
1573  "invalidateblock",
1574  "Permanently marks a block as invalid, as if it violated a consensus "
1575  "rule.\n",
1576  {
1578  "the hash of the block to mark as invalid"},
1579  },
1581  RPCExamples{HelpExampleCli("invalidateblock", "\"blockhash\"") +
1582  HelpExampleRpc("invalidateblock", "\"blockhash\"")},
1583  [&](const RPCHelpMan &self, const Config &config,
1584  const JSONRPCRequest &request) -> UniValue {
1585  const BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1586  BlockValidationState state;
1587 
1588  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1589  CBlockIndex *pblockindex;
1590  {
1591  LOCK(cs_main);
1592  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1593  if (!pblockindex) {
1595  "Block not found");
1596  }
1597  }
1598  chainman.ActiveChainstate().InvalidateBlock(state, pblockindex);
1599 
1600  if (state.IsValid()) {
1601  chainman.ActiveChainstate().ActivateBestChain(state);
1602  }
1603 
1604  if (!state.IsValid()) {
1605  throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
1606  }
1607 
1608  // Block to make sure wallet/indexers sync before returning
1610 
1611  return NullUniValue;
1612  },
1613  };
1614 }
1615 
1617  return RPCHelpMan{
1618  "parkblock",
1619  "Marks a block as parked.\n",
1620  {
1622  "the hash of the block to park"},
1623  },
1625  RPCExamples{HelpExampleCli("parkblock", "\"blockhash\"") +
1626  HelpExampleRpc("parkblock", "\"blockhash\"")},
1627  [&](const RPCHelpMan &self, const Config &config,
1628  const JSONRPCRequest &request) -> UniValue {
1629  const std::string strHash = request.params[0].get_str();
1630  const BlockHash hash(uint256S(strHash));
1631  BlockValidationState state;
1632 
1633  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1634  Chainstate &active_chainstate = chainman.ActiveChainstate();
1635  CBlockIndex *pblockindex = nullptr;
1636  {
1637  LOCK(cs_main);
1638  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1639  if (!pblockindex) {
1641  "Block not found");
1642  }
1643 
1644  if (active_chainstate.IsBlockAvalancheFinalized(pblockindex)) {
1645  // Reset avalanche finalization if we park a finalized
1646  // block.
1647  active_chainstate.ClearAvalancheFinalizedBlock();
1648  }
1649  }
1650 
1651  active_chainstate.ParkBlock(state, pblockindex);
1652 
1653  if (state.IsValid()) {
1654  active_chainstate.ActivateBestChain(state);
1655  }
1656 
1657  if (!state.IsValid()) {
1659  }
1660 
1661  // Block to make sure wallet/indexers sync before returning
1663 
1664  return NullUniValue;
1665  },
1666  };
1667 }
1668 
1670  return RPCHelpMan{
1671  "reconsiderblock",
1672  "Removes invalidity status of a block, its ancestors and its"
1673  "descendants, reconsider them for activation.\n"
1674  "This can be used to undo the effects of invalidateblock.\n",
1675  {
1677  "the hash of the block to reconsider"},
1678  },
1680  RPCExamples{HelpExampleCli("reconsiderblock", "\"blockhash\"") +
1681  HelpExampleRpc("reconsiderblock", "\"blockhash\"")},
1682  [&](const RPCHelpMan &self, const Config &config,
1683  const JSONRPCRequest &request) -> UniValue {
1684  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1685  const BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1686 
1687  {
1688  LOCK(cs_main);
1689  CBlockIndex *pblockindex =
1690  chainman.m_blockman.LookupBlockIndex(hash);
1691  if (!pblockindex) {
1693  "Block not found");
1694  }
1695 
1696  chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex);
1697  }
1698 
1699  BlockValidationState state;
1700  chainman.ActiveChainstate().ActivateBestChain(state);
1701 
1702  if (!state.IsValid()) {
1703  throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
1704  }
1705 
1706  // Block to make sure wallet/indexers sync before returning
1708 
1709  return NullUniValue;
1710  },
1711  };
1712 }
1713 
1715  return RPCHelpMan{
1716  "unparkblock",
1717  "Removes parked status of a block and its descendants, reconsider "
1718  "them for activation.\n"
1719  "This can be used to undo the effects of parkblock.\n",
1720  {
1722  "the hash of the block to unpark"},
1723  },
1725  RPCExamples{HelpExampleCli("unparkblock", "\"blockhash\"") +
1726  HelpExampleRpc("unparkblock", "\"blockhash\"")},
1727  [&](const RPCHelpMan &self, const Config &config,
1728  const JSONRPCRequest &request) -> UniValue {
1729  const std::string strHash = request.params[0].get_str();
1730  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1731  const BlockHash hash(uint256S(strHash));
1732  Chainstate &active_chainstate = chainman.ActiveChainstate();
1733 
1734  {
1735  LOCK(cs_main);
1736 
1737  CBlockIndex *pblockindex =
1738  chainman.m_blockman.LookupBlockIndex(hash);
1739  if (!pblockindex) {
1741  "Block not found");
1742  }
1743 
1744  if (!pblockindex->nStatus.isOnParkedChain()) {
1745  // Block to unpark is not parked so there is nothing to do.
1746  return NullUniValue;
1747  }
1748 
1749  const CBlockIndex *tip = active_chainstate.m_chain.Tip();
1750  if (tip) {
1751  const CBlockIndex *ancestor =
1752  LastCommonAncestor(tip, pblockindex);
1753  if (active_chainstate.IsBlockAvalancheFinalized(ancestor)) {
1754  // Only reset avalanche finalization if we unpark a
1755  // block that might conflict with avalanche finalized
1756  // blocks.
1757  active_chainstate.ClearAvalancheFinalizedBlock();
1758  }
1759  }
1760 
1761  active_chainstate.UnparkBlockAndChildren(pblockindex);
1762  }
1763 
1764  BlockValidationState state;
1765  active_chainstate.ActivateBestChain(state);
1766 
1767  if (!state.IsValid()) {
1769  }
1770 
1771  // Block to make sure wallet/indexers sync before returning
1773 
1774  return NullUniValue;
1775  },
1776  };
1777 }
1778 
1780  return RPCHelpMan{
1781  "getchaintxstats",
1782  "Compute statistics about the total number and rate of transactions "
1783  "in the chain.\n",
1784  {
1785  {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{"one month"},
1786  "Size of the window in number of blocks"},
1787  {"blockhash", RPCArg::Type::STR_HEX,
1788  RPCArg::DefaultHint{"chain tip"},
1789  "The hash of the block that ends the window."},
1790  },
1792  "",
1793  "",
1794  {
1795  {RPCResult::Type::NUM_TIME, "time",
1796  "The timestamp for the final block in the window, "
1797  "expressed in " +
1798  UNIX_EPOCH_TIME},
1799  {RPCResult::Type::NUM, "txcount",
1800  "The total number of transactions in the chain up to "
1801  "that point"},
1802  {RPCResult::Type::STR_HEX, "window_final_block_hash",
1803  "The hash of the final block in the window"},
1804  {RPCResult::Type::NUM, "window_final_block_height",
1805  "The height of the final block in the window."},
1806  {RPCResult::Type::NUM, "window_block_count",
1807  "Size of the window in number of blocks"},
1808  {RPCResult::Type::NUM, "window_tx_count",
1809  "The number of transactions in the window. Only "
1810  "returned if \"window_block_count\" is > 0"},
1811  {RPCResult::Type::NUM, "window_interval",
1812  "The elapsed time in the window in seconds. Only "
1813  "returned if \"window_block_count\" is > 0"},
1814  {RPCResult::Type::NUM, "txrate",
1815  "The average rate of transactions per second in the "
1816  "window. Only returned if \"window_interval\" is > 0"},
1817  }},
1818  RPCExamples{HelpExampleCli("getchaintxstats", "") +
1819  HelpExampleRpc("getchaintxstats", "2016")},
1820  [&](const RPCHelpMan &self, const Config &config,
1821  const JSONRPCRequest &request) -> UniValue {
1822  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1823  const CBlockIndex *pindex;
1824 
1825  // By default: 1 month
1826  int blockcount =
1827  30 * 24 * 60 * 60 /
1828  config.GetChainParams().GetConsensus().nPowTargetSpacing;
1829 
1830  if (request.params[1].isNull()) {
1831  LOCK(cs_main);
1832  pindex = chainman.ActiveTip();
1833  } else {
1834  BlockHash hash(ParseHashV(request.params[1], "blockhash"));
1835  LOCK(cs_main);
1836  pindex = chainman.m_blockman.LookupBlockIndex(hash);
1837  if (!pindex) {
1839  "Block not found");
1840  }
1841  if (!chainman.ActiveChain().Contains(pindex)) {
1843  "Block is not in main chain");
1844  }
1845  }
1846 
1847  CHECK_NONFATAL(pindex != nullptr);
1848 
1849  if (request.params[0].isNull()) {
1850  blockcount =
1851  std::max(0, std::min(blockcount, pindex->nHeight - 1));
1852  } else {
1853  blockcount = request.params[0].get_int();
1854 
1855  if (blockcount < 0 ||
1856  (blockcount > 0 && blockcount >= pindex->nHeight)) {
1858  "Invalid block count: "
1859  "should be between 0 and "
1860  "the block's height - 1");
1861  }
1862  }
1863 
1864  const CBlockIndex &past_block{*CHECK_NONFATAL(
1865  pindex->GetAncestor(pindex->nHeight - blockcount))};
1866  const int64_t nTimeDiff{pindex->GetMedianTimePast() -
1867  past_block.GetMedianTimePast()};
1868  const int nTxDiff =
1869  pindex->GetChainTxCount() - past_block.GetChainTxCount();
1870 
1871  UniValue ret(UniValue::VOBJ);
1872  ret.pushKV("time", pindex->GetBlockTime());
1873  ret.pushKV("txcount", pindex->GetChainTxCount());
1874  ret.pushKV("window_final_block_hash",
1875  pindex->GetBlockHash().GetHex());
1876  ret.pushKV("window_final_block_height", pindex->nHeight);
1877  ret.pushKV("window_block_count", blockcount);
1878  if (blockcount > 0) {
1879  ret.pushKV("window_tx_count", nTxDiff);
1880  ret.pushKV("window_interval", nTimeDiff);
1881  if (nTimeDiff > 0) {
1882  ret.pushKV("txrate", double(nTxDiff) / nTimeDiff);
1883  }
1884  }
1885 
1886  return ret;
1887  },
1888  };
1889 }
1890 
1891 template <typename T>
1892 static T CalculateTruncatedMedian(std::vector<T> &scores) {
1893  size_t size = scores.size();
1894  if (size == 0) {
1895  return T();
1896  }
1897 
1898  std::sort(scores.begin(), scores.end());
1899  if (size % 2 == 0) {
1900  return (scores[size / 2 - 1] + scores[size / 2]) / 2;
1901  } else {
1902  return scores[size / 2];
1903  }
1904 }
1905 
1906 template <typename T> static inline bool SetHasKeys(const std::set<T> &set) {
1907  return false;
1908 }
1909 template <typename T, typename Tk, typename... Args>
1910 static inline bool SetHasKeys(const std::set<T> &set, const Tk &key,
1911  const Args &...args) {
1912  return (set.count(key) != 0) || SetHasKeys(set, args...);
1913 }
1914 
1915 // outpoint (needed for the utxo index) + nHeight + fCoinBase
1916 static constexpr size_t PER_UTXO_OVERHEAD =
1917  sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);
1918 
1920  const auto &ticker = Currency::get().ticker;
1921  return RPCHelpMan{
1922  "getblockstats",
1923  "Compute per block statistics for a given window. All amounts are "
1924  "in " +
1925  ticker +
1926  ".\n"
1927  "It won't work for some heights with pruning.\n",
1928  {
1929  {"hash_or_height",
1932  "The block hash or height of the target block",
1933  "",
1934  {"", "string or numeric"}},
1935  {"stats",
1937  RPCArg::DefaultHint{"all values"},
1938  "Values to plot (see result below)",
1939  {
1941  "Selected statistic"},
1943  "Selected statistic"},
1944  },
1945  "stats"},
1946  },
1947  RPCResult{
1949  "",
1950  "",
1951  {
1952  {RPCResult::Type::NUM, "avgfee", "Average fee in the block"},
1953  {RPCResult::Type::NUM, "avgfeerate",
1954  "Average feerate (in satoshis per virtual byte)"},
1955  {RPCResult::Type::NUM, "avgtxsize", "Average transaction size"},
1956  {RPCResult::Type::STR_HEX, "blockhash",
1957  "The block hash (to check for potential reorgs)"},
1958  {RPCResult::Type::NUM, "height", "The height of the block"},
1959  {RPCResult::Type::NUM, "ins",
1960  "The number of inputs (excluding coinbase)"},
1961  {RPCResult::Type::NUM, "maxfee", "Maximum fee in the block"},
1962  {RPCResult::Type::NUM, "maxfeerate",
1963  "Maximum feerate (in satoshis per virtual byte)"},
1964  {RPCResult::Type::NUM, "maxtxsize", "Maximum transaction size"},
1965  {RPCResult::Type::NUM, "medianfee",
1966  "Truncated median fee in the block"},
1967  {RPCResult::Type::NUM, "medianfeerate",
1968  "Truncated median feerate (in " + ticker + " per byte)"},
1969  {RPCResult::Type::NUM, "mediantime",
1970  "The block median time past"},
1971  {RPCResult::Type::NUM, "mediantxsize",
1972  "Truncated median transaction size"},
1973  {RPCResult::Type::NUM, "minfee", "Minimum fee in the block"},
1974  {RPCResult::Type::NUM, "minfeerate",
1975  "Minimum feerate (in satoshis per virtual byte)"},
1976  {RPCResult::Type::NUM, "mintxsize", "Minimum transaction size"},
1977  {RPCResult::Type::NUM, "outs", "The number of outputs"},
1978  {RPCResult::Type::NUM, "subsidy", "The block subsidy"},
1979  {RPCResult::Type::NUM, "time", "The block time"},
1980  {RPCResult::Type::NUM, "total_out",
1981  "Total amount in all outputs (excluding coinbase and thus "
1982  "reward [ie subsidy + totalfee])"},
1983  {RPCResult::Type::NUM, "total_size",
1984  "Total size of all non-coinbase transactions"},
1985  {RPCResult::Type::NUM, "totalfee", "The fee total"},
1986  {RPCResult::Type::NUM, "txs",
1987  "The number of transactions (including coinbase)"},
1988  {RPCResult::Type::NUM, "utxo_increase",
1989  "The increase/decrease in the number of unspent outputs"},
1990  {RPCResult::Type::NUM, "utxo_size_inc",
1991  "The increase/decrease in size for the utxo index (not "
1992  "discounting op_return and similar)"},
1993  }},
1994  RPCExamples{
1996  "getblockstats",
1997  R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
1998  HelpExampleCli("getblockstats",
1999  R"(1000 '["minfeerate","avgfeerate"]')") +
2001  "getblockstats",
2002  R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") +
2003  HelpExampleRpc("getblockstats",
2004  R"(1000, ["minfeerate","avgfeerate"])")},
2005  [&](const RPCHelpMan &self, const Config &config,
2006  const JSONRPCRequest &request) -> UniValue {
2007  ChainstateManager &chainman = EnsureAnyChainman(request.context);
2008  const CBlockIndex &pindex{*CHECK_NONFATAL(
2009  ParseHashOrHeight(request.params[0], chainman))};
2010 
2011  std::set<std::string> stats;
2012  if (!request.params[1].isNull()) {
2013  const UniValue stats_univalue = request.params[1].get_array();
2014  for (unsigned int i = 0; i < stats_univalue.size(); i++) {
2015  const std::string stat = stats_univalue[i].get_str();
2016  stats.insert(stat);
2017  }
2018  }
2019 
2020  const CBlock &block =
2021  GetBlockChecked(config, chainman.m_blockman, &pindex);
2022  const CBlockUndo &blockUndo =
2023  GetUndoChecked(chainman.m_blockman, &pindex);
2024 
2025  // Calculate everything if nothing selected (default)
2026  const bool do_all = stats.size() == 0;
2027  const bool do_mediantxsize =
2028  do_all || stats.count("mediantxsize") != 0;
2029  const bool do_medianfee = do_all || stats.count("medianfee") != 0;
2030  const bool do_medianfeerate =
2031  do_all || stats.count("medianfeerate") != 0;
2032  const bool loop_inputs =
2033  do_all || do_medianfee || do_medianfeerate ||
2034  SetHasKeys(stats, "utxo_size_inc", "totalfee", "avgfee",
2035  "avgfeerate", "minfee", "maxfee", "minfeerate",
2036  "maxfeerate");
2037  const bool loop_outputs =
2038  do_all || loop_inputs || stats.count("total_out");
2039  const bool do_calculate_size =
2040  do_mediantxsize || loop_inputs ||
2041  SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize",
2042  "maxtxsize");
2043 
2044  const int64_t blockMaxSize = config.GetMaxBlockSize();
2045  Amount maxfee = Amount::zero();
2046  Amount maxfeerate = Amount::zero();
2047  Amount minfee = MAX_MONEY;
2048  Amount minfeerate = MAX_MONEY;
2049  Amount total_out = Amount::zero();
2050  Amount totalfee = Amount::zero();
2051  int64_t inputs = 0;
2052  int64_t maxtxsize = 0;
2053  int64_t mintxsize = blockMaxSize;
2054  int64_t outputs = 0;
2055  int64_t total_size = 0;
2056  int64_t utxo_size_inc = 0;
2057  std::vector<Amount> fee_array;
2058  std::vector<Amount> feerate_array;
2059  std::vector<int64_t> txsize_array;
2060 
2061  for (size_t i = 0; i < block.vtx.size(); ++i) {
2062  const auto &tx = block.vtx.at(i);
2063  outputs += tx->vout.size();
2064  Amount tx_total_out = Amount::zero();
2065  if (loop_outputs) {
2066  for (const CTxOut &out : tx->vout) {
2067  tx_total_out += out.nValue;
2068  utxo_size_inc +=
2071  }
2072  }
2073 
2074  if (tx->IsCoinBase()) {
2075  continue;
2076  }
2077 
2078  // Don't count coinbase's fake input
2079  inputs += tx->vin.size();
2080  // Don't count coinbase reward
2081  total_out += tx_total_out;
2082 
2083  int64_t tx_size = 0;
2084  if (do_calculate_size) {
2085  tx_size = tx->GetTotalSize();
2086  if (do_mediantxsize) {
2087  txsize_array.push_back(tx_size);
2088  }
2089  maxtxsize = std::max(maxtxsize, tx_size);
2090  mintxsize = std::min(mintxsize, tx_size);
2091  total_size += tx_size;
2092  }
2093 
2094  if (loop_inputs) {
2095  Amount tx_total_in = Amount::zero();
2096  const auto &txundo = blockUndo.vtxundo.at(i - 1);
2097  for (const Coin &coin : txundo.vprevout) {
2098  const CTxOut &prevoutput = coin.GetTxOut();
2099 
2100  tx_total_in += prevoutput.nValue;
2101  utxo_size_inc -=
2102  GetSerializeSize(prevoutput, PROTOCOL_VERSION) +
2104  }
2105 
2106  Amount txfee = tx_total_in - tx_total_out;
2107  CHECK_NONFATAL(MoneyRange(txfee));
2108  if (do_medianfee) {
2109  fee_array.push_back(txfee);
2110  }
2111  maxfee = std::max(maxfee, txfee);
2112  minfee = std::min(minfee, txfee);
2113  totalfee += txfee;
2114 
2115  Amount feerate = txfee / tx_size;
2116  if (do_medianfeerate) {
2117  feerate_array.push_back(feerate);
2118  }
2119  maxfeerate = std::max(maxfeerate, feerate);
2120  minfeerate = std::min(minfeerate, feerate);
2121  }
2122  }
2123 
2124  UniValue ret_all(UniValue::VOBJ);
2125  ret_all.pushKV("avgfee",
2126  block.vtx.size() > 1
2127  ? (totalfee / int((block.vtx.size() - 1)))
2128  : Amount::zero());
2129  ret_all.pushKV("avgfeerate", total_size > 0
2130  ? (totalfee / total_size)
2131  : Amount::zero());
2132  ret_all.pushKV("avgtxsize",
2133  (block.vtx.size() > 1)
2134  ? total_size / (block.vtx.size() - 1)
2135  : 0);
2136  ret_all.pushKV("blockhash", pindex.GetBlockHash().GetHex());
2137  ret_all.pushKV("height", (int64_t)pindex.nHeight);
2138  ret_all.pushKV("ins", inputs);
2139  ret_all.pushKV("maxfee", maxfee);
2140  ret_all.pushKV("maxfeerate", maxfeerate);
2141  ret_all.pushKV("maxtxsize", maxtxsize);
2142  ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
2143  ret_all.pushKV("medianfeerate",
2144  CalculateTruncatedMedian(feerate_array));
2145  ret_all.pushKV("mediantime", pindex.GetMedianTimePast());
2146  ret_all.pushKV("mediantxsize",
2147  CalculateTruncatedMedian(txsize_array));
2148  ret_all.pushKV("minfee",
2149  minfee == MAX_MONEY ? Amount::zero() : minfee);
2150  ret_all.pushKV("minfeerate", minfeerate == MAX_MONEY
2151  ? Amount::zero()
2152  : minfeerate);
2153  ret_all.pushKV("mintxsize",
2154  mintxsize == blockMaxSize ? 0 : mintxsize);
2155  ret_all.pushKV("outs", outputs);
2156  ret_all.pushKV("subsidy", GetBlockSubsidy(pindex.nHeight,
2157  chainman.GetConsensus()));
2158  ret_all.pushKV("time", pindex.GetBlockTime());
2159  ret_all.pushKV("total_out", total_out);
2160  ret_all.pushKV("total_size", total_size);
2161  ret_all.pushKV("totalfee", totalfee);
2162  ret_all.pushKV("txs", (int64_t)block.vtx.size());
2163  ret_all.pushKV("utxo_increase", outputs - inputs);
2164  ret_all.pushKV("utxo_size_inc", utxo_size_inc);
2165 
2166  if (do_all) {
2167  return ret_all;
2168  }
2169 
2170  UniValue ret(UniValue::VOBJ);
2171  for (const std::string &stat : stats) {
2172  const UniValue &value = ret_all[stat];
2173  if (value.isNull()) {
2174  throw JSONRPCError(
2176  strprintf("Invalid selected statistic %s", stat));
2177  }
2178  ret.pushKV(stat, value);
2179  }
2180  return ret;
2181  },
2182  };
2183 }
2184 
2185 namespace {
2187 static bool FindScriptPubKey(std::atomic<int> &scan_progress,
2188  const std::atomic<bool> &should_abort,
2189  int64_t &count, CCoinsViewCursor *cursor,
2190  const std::set<CScript> &needles,
2191  std::map<COutPoint, Coin> &out_results,
2192  std::function<void()> &interruption_point) {
2193  scan_progress = 0;
2194  count = 0;
2195  while (cursor->Valid()) {
2196  COutPoint key;
2197  Coin coin;
2198  if (!cursor->GetKey(key) || !cursor->GetValue(coin)) {
2199  return false;
2200  }
2201  if (++count % 8192 == 0) {
2202  interruption_point();
2203  if (should_abort) {
2204  // allow to abort the scan via the abort reference
2205  return false;
2206  }
2207  }
2208  if (count % 256 == 0) {
2209  // update progress reference every 256 item
2210  const TxId &txid = key.GetTxId();
2211  uint32_t high = 0x100 * *txid.begin() + *(txid.begin() + 1);
2212  scan_progress = int(high * 100.0 / 65536.0 + 0.5);
2213  }
2214  if (needles.count(coin.GetTxOut().scriptPubKey)) {
2215  out_results.emplace(key, coin);
2216  }
2217  cursor->Next();
2218  }
2219  scan_progress = 100;
2220  return true;
2221 }
2222 } // namespace
2223 
2225 static std::atomic<int> g_scan_progress;
2226 static std::atomic<bool> g_scan_in_progress;
2227 static std::atomic<bool> g_should_abort_scan;
2229 private:
2231 
2232 public:
2234 
2235  bool reserve() {
2237  if (g_scan_in_progress.exchange(true)) {
2238  return false;
2239  }
2240  m_could_reserve = true;
2241  return true;
2242  }
2243 
2245  if (m_could_reserve) {
2246  g_scan_in_progress = false;
2247  }
2248  }
2249 };
2250 
2252  const auto &ticker = Currency::get().ticker;
2253  return RPCHelpMan{
2254  "scantxoutset",
2255  "Scans the unspent transaction output set for entries that match "
2256  "certain output descriptors.\n"
2257  "Examples of output descriptors are:\n"
2258  " addr(<address>) Outputs whose scriptPubKey "
2259  "corresponds to the specified address (does not include P2PK)\n"
2260  " raw(<hex script>) Outputs whose scriptPubKey "
2261  "equals the specified hex scripts\n"
2262  " combo(<pubkey>) P2PK and P2PKH outputs for "
2263  "the given pubkey\n"
2264  " pkh(<pubkey>) P2PKH outputs for the given "
2265  "pubkey\n"
2266  " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for "
2267  "the given threshold and pubkeys\n"
2268  "\nIn the above, <pubkey> either refers to a fixed public key in "
2269  "hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
2270  "or more path elements separated by \"/\", and optionally ending in "
2271  "\"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
2272  "unhardened or hardened child keys.\n"
2273  "In the latter case, a range needs to be specified by below if "
2274  "different from 1000.\n"
2275  "For more information on output descriptors, see the documentation in "
2276  "the doc/descriptors.md file.\n",
2277  {
2279  "The action to execute\n"
2280  " \"start\" for starting a "
2281  "scan\n"
2282  " \"abort\" for aborting the "
2283  "current scan (returns true when abort was successful)\n"
2284  " \"status\" for "
2285  "progress report (in %) of the current scan"},
2286  {"scanobjects",
2289  "Array of scan objects. Required for \"start\" action\n"
2290  " Every scan object is either a "
2291  "string descriptor or an object:",
2292  {
2294  "An output descriptor"},
2295  {
2296  "",
2299  "An object with output descriptor and metadata",
2300  {
2302  "An output descriptor"},
2303  {"range", RPCArg::Type::RANGE, RPCArg::Default{1000},
2304  "The range of HD chain indexes to explore (either "
2305  "end or [begin,end])"},
2306  },
2307  },
2308  },
2309  "[scanobjects,...]"},
2310  },
2311  {
2312  RPCResult{"When action=='abort'", RPCResult::Type::BOOL, "", ""},
2313  RPCResult{"When action=='status' and no scan is in progress",
2314  RPCResult::Type::NONE, "", ""},
2315  RPCResult{
2316  "When action=='status' and scan is in progress",
2318  "",
2319  "",
2320  {
2321  {RPCResult::Type::NUM, "progress", "The scan progress"},
2322  }},
2323  RPCResult{
2324  "When action=='start'",
2326  "",
2327  "",
2328  {
2329  {RPCResult::Type::BOOL, "success",
2330  "Whether the scan was completed"},
2331  {RPCResult::Type::NUM, "txouts",
2332  "The number of unspent transaction outputs scanned"},
2333  {RPCResult::Type::NUM, "height",
2334  "The current block height (index)"},
2335  {RPCResult::Type::STR_HEX, "bestblock",
2336  "The hash of the block at the tip of the chain"},
2338  "unspents",
2339  "",
2340  {
2342  "",
2343  "",
2344  {
2345  {RPCResult::Type::STR_HEX, "txid",
2346  "The transaction id"},
2347  {RPCResult::Type::NUM, "vout", "The vout value"},
2348  {RPCResult::Type::STR_HEX, "scriptPubKey",
2349  "The script key"},
2350  {RPCResult::Type::STR, "desc",
2351  "A specialized descriptor for the matched "
2352  "scriptPubKey"},
2353  {RPCResult::Type::STR_AMOUNT, "amount",
2354  "The total amount in " + ticker +
2355  " of the unspent output"},
2356  {RPCResult::Type::NUM, "height",
2357  "Height of the unspent transaction output"},
2358  }},
2359  }},
2360  {RPCResult::Type::STR_AMOUNT, "total_amount",
2361  "The total amount of all found unspent outputs in " +
2362  ticker},
2363  }},
2364  },
2365  RPCExamples{""},
2366  [&](const RPCHelpMan &self, const Config &config,
2367  const JSONRPCRequest &request) -> UniValue {
2368  RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR});
2369 
2370  UniValue result(UniValue::VOBJ);
2371  if (request.params[0].get_str() == "status") {
2372  CoinsViewScanReserver reserver;
2373  if (reserver.reserve()) {
2374  // no scan in progress
2375  return NullUniValue;
2376  }
2377  result.pushKV("progress", g_scan_progress.load());
2378  return result;
2379  } else if (request.params[0].get_str() == "abort") {
2380  CoinsViewScanReserver reserver;
2381  if (reserver.reserve()) {
2382  // reserve was possible which means no scan was running
2383  return false;
2384  }
2385  // set the abort flag
2386  g_should_abort_scan = true;
2387  return true;
2388  } else if (request.params[0].get_str() == "start") {
2389  CoinsViewScanReserver reserver;
2390  if (!reserver.reserve()) {
2392  "Scan already in progress, use action "
2393  "\"abort\" or \"status\"");
2394  }
2395 
2396  if (request.params.size() < 2) {
2398  "scanobjects argument is required for "
2399  "the start action");
2400  }
2401 
2402  std::set<CScript> needles;
2403  std::map<CScript, std::string> descriptors;
2404  Amount total_in = Amount::zero();
2405 
2406  // loop through the scan objects
2407  for (const UniValue &scanobject :
2408  request.params[1].get_array().getValues()) {
2409  FlatSigningProvider provider;
2410  auto scripts =
2411  EvalDescriptorStringOrObject(scanobject, provider);
2412  for (const auto &script : scripts) {
2413  std::string inferred =
2414  InferDescriptor(script, provider)->ToString();
2415  needles.emplace(script);
2416  descriptors.emplace(std::move(script),
2417  std::move(inferred));
2418  }
2419  }
2420 
2421  // Scan the unspent transaction output set for inputs
2422  UniValue unspents(UniValue::VARR);
2423  std::vector<CTxOut> input_txos;
2424  std::map<COutPoint, Coin> coins;
2425  g_should_abort_scan = false;
2426  g_scan_progress = 0;
2427  int64_t count = 0;
2428  std::unique_ptr<CCoinsViewCursor> pcursor;
2429  const CBlockIndex *tip;
2430  NodeContext &node = EnsureAnyNodeContext(request.context);
2431  {
2432  ChainstateManager &chainman = EnsureChainman(node);
2433  LOCK(cs_main);
2434  Chainstate &active_chainstate = chainman.ActiveChainstate();
2435  active_chainstate.ForceFlushStateToDisk();
2436  pcursor = CHECK_NONFATAL(std::unique_ptr<CCoinsViewCursor>(
2437  active_chainstate.CoinsDB().Cursor()));
2438  tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
2439  }
2440  bool res = FindScriptPubKey(
2441  g_scan_progress, g_should_abort_scan, count, pcursor.get(),
2442  needles, coins, node.rpc_interruption_point);
2443  result.pushKV("success", res);
2444  result.pushKV("txouts", count);
2445  result.pushKV("height", tip->nHeight);
2446  result.pushKV("bestblock", tip->GetBlockHash().GetHex());
2447 
2448  for (const auto &it : coins) {
2449  const COutPoint &outpoint = it.first;
2450  const Coin &coin = it.second;
2451  const CTxOut &txo = coin.GetTxOut();
2452  input_txos.push_back(txo);
2453  total_in += txo.nValue;
2454 
2455  UniValue unspent(UniValue::VOBJ);
2456  unspent.pushKV("txid", outpoint.GetTxId().GetHex());
2457  unspent.pushKV("vout", int32_t(outpoint.GetN()));
2458  unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
2459  unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
2460  unspent.pushKV("amount", txo.nValue);
2461  unspent.pushKV("height", int32_t(coin.GetHeight()));
2462 
2463  unspents.push_back(unspent);
2464  }
2465  result.pushKV("unspents", unspents);
2466  result.pushKV("total_amount", total_in);
2467  } else {
2468  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid command");
2469  }
2470  return result;
2471  },
2472  };
2473 }
2474 
2476  return RPCHelpMan{
2477  "getblockfilter",
2478  "Retrieve a BIP 157 content filter for a particular block.\n",
2479  {
2481  "The hash of the block"},
2482  {"filtertype", RPCArg::Type::STR, RPCArg::Default{"basic"},
2483  "The type name of the filter"},
2484  },
2486  "",
2487  "",
2488  {
2489  {RPCResult::Type::STR_HEX, "filter",
2490  "the hex-encoded filter data"},
2491  {RPCResult::Type::STR_HEX, "header",
2492  "the hex-encoded filter header"},
2493  }},
2494  RPCExamples{
2495  HelpExampleCli("getblockfilter",
2496  "\"00000000c937983704a73af28acdec37b049d214a"
2497  "dbda81d7e2a3dd146f6ed09\" \"basic\"") +
2498  HelpExampleRpc("getblockfilter",
2499  "\"00000000c937983704a73af28acdec37b049d214adbda81d7"
2500  "e2a3dd146f6ed09\", \"basic\"")},
2501  [&](const RPCHelpMan &self, const Config &config,
2502  const JSONRPCRequest &request) -> UniValue {
2503  const BlockHash block_hash(
2504  ParseHashV(request.params[0], "blockhash"));
2505  std::string filtertype_name = "basic";
2506  if (!request.params[1].isNull()) {
2507  filtertype_name = request.params[1].get_str();
2508  }
2509 
2510  BlockFilterType filtertype;
2511  if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2513  "Unknown filtertype");
2514  }
2515 
2516  BlockFilterIndex *index = GetBlockFilterIndex(filtertype);
2517  if (!index) {
2519  "Index is not enabled for filtertype " +
2520  filtertype_name);
2521  }
2522 
2523  const CBlockIndex *block_index;
2524  bool block_was_connected;
2525  {
2526  ChainstateManager &chainman =
2527  EnsureAnyChainman(request.context);
2528  LOCK(cs_main);
2529  block_index = chainman.m_blockman.LookupBlockIndex(block_hash);
2530  if (!block_index) {
2532  "Block not found");
2533  }
2534  block_was_connected =
2535  block_index->IsValid(BlockValidity::SCRIPTS);
2536  }
2537 
2538  bool index_ready = index->BlockUntilSyncedToCurrentChain();
2539 
2540  BlockFilter filter;
2541  uint256 filter_header;
2542  if (!index->LookupFilter(block_index, filter) ||
2543  !index->LookupFilterHeader(block_index, filter_header)) {
2544  int err_code;
2545  std::string errmsg = "Filter not found.";
2546 
2547  if (!block_was_connected) {
2548  err_code = RPC_INVALID_ADDRESS_OR_KEY;
2549  errmsg += " Block was not connected to active chain.";
2550  } else if (!index_ready) {
2551  err_code = RPC_MISC_ERROR;
2552  errmsg += " Block filters are still in the process of "
2553  "being indexed.";
2554  } else {
2555  err_code = RPC_INTERNAL_ERROR;
2556  errmsg += " This error is unexpected and indicates index "
2557  "corruption.";
2558  }
2559 
2560  throw JSONRPCError(err_code, errmsg);
2561  }
2562 
2563  UniValue ret(UniValue::VOBJ);
2564  ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
2565  ret.pushKV("header", filter_header.GetHex());
2566  return ret;
2567  },
2568  };
2569 }
2570 
2577  return RPCHelpMan{
2578  "dumptxoutset",
2579  "Write the serialized UTXO set to disk.\n",
2580  {
2582  "path to the output file. If relative, will be prefixed by "
2583  "datadir."},
2584  },
2586  "",
2587  "",
2588  {
2589  {RPCResult::Type::NUM, "coins_written",
2590  "the number of coins written in the snapshot"},
2591  {RPCResult::Type::STR_HEX, "base_hash",
2592  "the hash of the base of the snapshot"},
2593  {RPCResult::Type::NUM, "base_height",
2594  "the height of the base of the snapshot"},
2595  {RPCResult::Type::STR, "path",
2596  "the absolute path that the snapshot was written to"},
2597  {RPCResult::Type::STR_HEX, "txoutset_hash",
2598  "the hash of the UTXO set contents"},
2599  {RPCResult::Type::NUM, "nchaintx",
2600  "the number of transactions in the chain up to and "
2601  "including the base block"},
2602  }},
2603  RPCExamples{HelpExampleCli("dumptxoutset", "utxo.dat")},
2604  [&](const RPCHelpMan &self, const Config &config,
2605  const JSONRPCRequest &request) -> UniValue {
2606  const ArgsManager &args{EnsureAnyArgsman(request.context)};
2607  const fs::path path = fsbridge::AbsPathJoin(
2608  args.GetDataDirNet(), fs::u8path(request.params[0].get_str()));
2609  // Write to a temporary path and then move into `path` on completion
2610  // to avoid confusion due to an interruption.
2611  const fs::path temppath = fsbridge::AbsPathJoin(
2612  args.GetDataDirNet(),
2613  fs::u8path(request.params[0].get_str() + ".incomplete"));
2614 
2615  if (fs::exists(path)) {
2617  path.u8string() +
2618  " already exists. If you are sure this "
2619  "is what you want, "
2620  "move it out of the way first");
2621  }
2622 
2623  FILE *file{fsbridge::fopen(temppath, "wb")};
2624  AutoFile afile{file};
2625  NodeContext &node = EnsureAnyNodeContext(request.context);
2626  UniValue result = CreateUTXOSnapshot(
2627  node, node.chainman->ActiveChainstate(), afile, path, temppath);
2628  fs::rename(temppath, path);
2629 
2630  return result;
2631  },
2632  };
2633 }
2634 
2636  AutoFile &afile, const fs::path &path,
2637  const fs::path &temppath) {
2638  std::unique_ptr<CCoinsViewCursor> pcursor;
2639  std::optional<CCoinsStats> maybe_stats;
2640  const CBlockIndex *tip;
2641 
2642  {
2643  // We need to lock cs_main to ensure that the coinsdb isn't
2644  // written to between (i) flushing coins cache to disk
2645  // (coinsdb), (ii) getting stats based upon the coinsdb, and
2646  // (iii) constructing a cursor to the coinsdb for use below this
2647  // block.
2648  //
2649  // Cursors returned by leveldb iterate over snapshots, so the
2650  // contents of the pcursor will not be affected by simultaneous
2651  // writes during use below this block.
2652  //
2653  // See discussion here:
2654  // https://github.com/bitcoin/bitcoin/pull/15606#discussion_r274479369
2655  //
2656  LOCK(::cs_main);
2657 
2658  chainstate.ForceFlushStateToDisk();
2659 
2660  maybe_stats = GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman,
2661  CoinStatsHashType::HASH_SERIALIZED,
2662  node.rpc_interruption_point);
2663  if (!maybe_stats) {
2664  throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
2665  }
2666 
2667  pcursor =
2668  std::unique_ptr<CCoinsViewCursor>(chainstate.CoinsDB().Cursor());
2669  tip = CHECK_NONFATAL(
2670  chainstate.m_blockman.LookupBlockIndex(maybe_stats->hashBlock));
2671  }
2672 
2674  strprintf("writing UTXO snapshot at height %s (%s) to file %s (via %s)",
2675  tip->nHeight, tip->GetBlockHash().ToString(),
2676  fs::PathToString(path), fs::PathToString(temppath)));
2677 
2678  SnapshotMetadata metadata{tip->GetBlockHash(), maybe_stats->coins_count,
2679  uint64_t(tip->GetChainTxCount())};
2680 
2681  afile << metadata;
2682 
2683  COutPoint key;
2684  Coin coin;
2685  unsigned int iter{0};
2686 
2687  while (pcursor->Valid()) {
2688  if (iter % 5000 == 0) {
2689  node.rpc_interruption_point();
2690  }
2691  ++iter;
2692  if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
2693  afile << key;
2694  afile << coin;
2695  }
2696 
2697  pcursor->Next();
2698  }
2699 
2700  afile.fclose();
2701 
2702  UniValue result(UniValue::VOBJ);
2703  result.pushKV("coins_written", maybe_stats->coins_count);
2704  result.pushKV("base_hash", tip->GetBlockHash().ToString());
2705  result.pushKV("base_height", tip->nHeight);
2706  result.pushKV("path", path.u8string());
2707  result.pushKV("txoutset_hash", maybe_stats->hashSerialized.ToString());
2708  // Cast required because univalue doesn't have serialization specified for
2709  // `unsigned int`, nChainTx's type.
2710  result.pushKV("nchaintx", uint64_t{tip->nChainTx});
2711  return result;
2712 }
2713 
2715  // clang-format off
2716  static const CRPCCommand commands[] = {
2717  // category actor (function)
2718  // ------------------ ----------------------
2719  { "blockchain", getbestblockhash, },
2720  { "blockchain", getblock, },
2721  { "blockchain", getblockfrompeer, },
2722  { "blockchain", getblockchaininfo, },
2723  { "blockchain", getblockcount, },
2724  { "blockchain", getblockhash, },
2725  { "blockchain", getblockheader, },
2726  { "blockchain", getblockstats, },
2727  { "blockchain", getchaintips, },
2728  { "blockchain", getchaintxstats, },
2729  { "blockchain", getdifficulty, },
2730  { "blockchain", gettxout, },
2731  { "blockchain", gettxoutsetinfo, },
2732  { "blockchain", pruneblockchain, },
2733  { "blockchain", verifychain, },
2734  { "blockchain", preciousblock, },
2735  { "blockchain", scantxoutset, },
2736  { "blockchain", getblockfilter, },
2737 
2738  /* Not shown in help */
2739  { "hidden", invalidateblock, },
2740  { "hidden", parkblock, },
2741  { "hidden", reconsiderblock, },
2742  { "hidden", syncwithvalidationinterfacequeue, },
2743  { "hidden", dumptxoutset, },
2744  { "hidden", unparkblock, },
2745  { "hidden", waitfornewblock, },
2746  { "hidden", waitforblock, },
2747  { "hidden", waitforblockheight, },
2748  };
2749  // clang-format on
2750  for (const auto &c : commands) {
2751  t.appendCommand(c.name, &c);
2752  }
2753 }
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:678
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:906
static RPCHelpMan getblockstats()
static CoinStatsHashType ParseHashType(const std::string &hash_type_input)
Definition: blockchain.cpp:892
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:659
static RPCHelpMan getblockfilter()
static RPCHelpMan getbestblockhash()
Definition: blockchain.cpp:216
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
static CBlock GetBlockChecked(const Config &config, BlockManager &blockman, const CBlockIndex *pblockindex)
Definition: blockchain.cpp:636
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:116
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:37
#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:26
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:213
uint256 hashMerkleRoot
Definition: blockindex.h:92
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: blockindex.h:33
CBlockHeader GetBlockHeader() const
Definition: blockindex.h:134
arith_uint256 nChainWork
(memory only) Total amount of work (expected number of hashes) in the chain up to and including this ...
Definition: blockindex.h:52
int64_t GetChainTxCount() const
Get the number of transaction in the chain so far.
Definition: blockindex.h:152
uint32_t nTime
Definition: blockindex.h:93
uint32_t nNonce
Definition: blockindex.h:95
int64_t GetBlockTime() const
Definition: blockindex.h:178
int64_t GetMedianTimePast() const
Definition: blockindex.h:190
uint32_t nBits
Definition: blockindex.h:94
unsigned int nTx
Number of transactions in this block.
Definition: blockindex.h:61
int32_t nVersion
block header
Definition: blockindex.h:91
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition: blockindex.cpp:71
BlockHash GetBlockHash() const
Definition: blockindex.h:147
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: blockindex.h:39
unsigned int nChainTx
(memory only) Number of transactions in the chain up to and including this block.
Definition: blockindex.h:78
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:140
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:156
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:66
int Height() const
Return the maximal height in the chain.
Definition: chain.h:192
const CBlockIndex * FindFork(const CBlockIndex *pindex) const
Find the last common block between this chain and a block index entry.
Definition: chain.cpp:53
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
Definition: chain.h:172
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
Definition: chainparams.h:74
std::string NetworkIDString() const
Return the BIP70 network string (main, test or regtest)
Definition: chainparams.h:121
const ChainTxData & TxData() const
Definition: chainparams.h:134
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:86
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:203
BlockHash GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:210
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: coins.cpp:91
Cursor for iterating over CoinsView state.
Definition: coins.h:127
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:216
Abstract view on the open txout dataset.
Definition: coins.h:147
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:589
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: txmempool.cpp:592
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:183
void appendCommand(const std::string &name, const CRPCCommand *pcmd)
Appends a CRPCCommand to the dispatch table.
Definition: server.cpp:330
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:129
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:554
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:629
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:738
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:771
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.
bool ActivateBestChain(BlockValidationState &state, std::shared_ptr< const CBlock > pblock=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.
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:764
node::BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all Chainstate instances.
Definition: validation.h:702
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:1144
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1351
const CChainParams & GetParams() const
Definition: validation.h:1238
node::BlockMap & BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:1361
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1354
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1357
const Consensus::Params & GetConsensus() const
Definition: validation.h:1241
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1273
A UTXO entry.
Definition: coins.h:27
uint32_t GetHeight() const
Definition: coins.h:44
bool IsCoinBase() const
Definition: coins.h:45
CTxOut & GetTxOut()
Definition: coins.h:48
Definition: config.h:17
virtual const CChainParams & GetChainParams() const =0
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.
const std::string & get_str() const
@ VOBJ
Definition: univalue.h:27
@ VARR
Definition: univalue.h:27
bool isNull() const
Definition: univalue.h:89
size_t size() const
Definition: univalue.h:80
const std::vector< UniValue > & getValues() const
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
const UniValue & get_array() const
bool pushKV(const std::string &key, const UniValue &val)
Definition: univalue.cpp:133
bool isNum() const
Definition: univalue.h:94
int get_int() const
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:67
CBlockIndex * LookupBlockIndex(const BlockHash &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
uint64_t GetPruneTarget() const
Attempt to stay below this number of bytes of block files.
Definition: blockstorage.h:201
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:198
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:210
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:28
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:37
Definition: init.h:28
const CBlockIndex * GetFirstStoredBlock(const CBlockIndex *start_block)
CoinStatsHashType
Definition: coinstats.h:26
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos, const Consensus::Params &params)
Functions for disk access for blocks.
bool UndoReadFromDisk(CBlockUndo &blockundo, const CBlockIndex *pindex)
std::optional< CCoinsStats > GetUTXOStats(CCoinsView *view, BlockManager &blockman, 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:186
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:57
@ 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
void RPCTypeCheck(const UniValue &params, const std::list< UniValueType > &typesExpected, bool fAllowNull)
Type-check arguments; throws JSONRPCError if wrong type given.
Definition: util.cpp:24
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:175
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:1060
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:192
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:20
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded values (throws error if not hex).
Definition: util.cpp:98
@ 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:381
int RPCSerializationFlags()
Retrieves any serialization flags requested in command line argument.
Definition: server.cpp:606
ArgsManager & EnsureAnyArgsman(const std::any &context)
Definition: server_util.cpp:46
ChainstateManager & EnsureAnyChainman(const std::any &context)
Definition: server_util.cpp:57
NodeContext & EnsureAnyNodeContext(const std::any &context)
Definition: server_util.cpp:19
PeerManager & EnsurePeerman(const NodeContext &node)
Definition: server_util.cpp:70
CTxMemPool & EnsureMemPool(const NodeContext &node)
Definition: server_util.cpp:27
ChainstateManager & EnsureChainman(const NodeContext &node)
Definition: server_util.cpp:50
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:54
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
Definition: util.h:173
@ OMITTED
Optional argument with default value omitted because they are implicitly clear.
@ NO
Required arg.
@ 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.
@ OBJ_EMPTY
Special type to allow empty OBJ.
A TxId is the identifier of a transaction.
Definition: txid.h:14
Amount total_coinbase_amount
Total cumulative amount of coinbase outputs up to and including this block.
Definition: coinstats.h:63
Amount total_unspendables_genesis_block
The unspendable coinbase amount from the genesis block.
Definition: coinstats.h:65
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:73
Amount nTotalAmount
Definition: coinstats.h:40
uint64_t nBogoSize
Definition: coinstats.h:37
uint64_t nDiskSize
Definition: coinstats.h:39
Amount total_prevout_spent_amount
Total cumulative amount of prevouts spent up to and including this block.
Definition: coinstats.h:57
bool index_used
Signals if the coinstatsindex was used to retrieve the statistics.
Definition: coinstats.h:46
Amount total_unspendable_amount
Total cumulative amount of unspendable coins up to and including this block.
Definition: coinstats.h:55
Amount total_new_outputs_ex_coinbase_amount
Total cumulative amount of outputs created up to and including this block.
Definition: coinstats.h:60
BlockHash hashBlock
Definition: coinstats.h:34
Amount total_unspendables_bip30
The two unspendable coinbase outputs total amount caused by BIP30.
Definition: coinstats.h:67
uint64_t nTransactions
Definition: coinstats.h:35
uint64_t nTransactionOutputs
Definition: coinstats.h:36
uint256 hashSerialized
Definition: coinstats.h:38
Amount total_unspendables_scripts
Total cumulative amount of outputs sent to unspendable scripts (OP_RETURN for example) up to and incl...
Definition: coinstats.h:70
NodeContext struct containing references to chain state and connection state.
Definition: context.h:38
#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:13
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:99
void PruneBlockFilesManual(Chainstate &active_chainstate, int nManualPruneHeight)
Prune block files up to a given height.
static const unsigned int DEFAULT_CHECKLEVEL
Definition: validation.h:97
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:95
static const signed int DEFAULT_CHECKBLOCKS
Definition: validation.h:96
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