Bitcoin ABC  0.28.12
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, config, 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  const ArgsManager &args{EnsureAnyArgsman(request.context)};
1341  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1342  LOCK(cs_main);
1343  Chainstate &active_chainstate = chainman.ActiveChainstate();
1344 
1345  const CBlockIndex &tip{
1346  *CHECK_NONFATAL(active_chainstate.m_chain.Tip())};
1347  const int height{tip.nHeight};
1348 
1349  UniValue obj(UniValue::VOBJ);
1350  obj.pushKV("chain", chainparams.NetworkIDString());
1351  obj.pushKV("blocks", height);
1352  obj.pushKV("headers", chainman.m_best_header
1353  ? chainman.m_best_header->nHeight
1354  : -1);
1355  obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex());
1356  obj.pushKV("difficulty", GetDifficulty(&tip));
1357  obj.pushKV("time", tip.GetBlockTime());
1358  obj.pushKV("mediantime", tip.GetMedianTimePast());
1359  obj.pushKV(
1360  "verificationprogress",
1361  GuessVerificationProgress(chainman.GetParams().TxData(), &tip));
1362  obj.pushKV("initialblockdownload",
1363  active_chainstate.IsInitialBlockDownload());
1364  obj.pushKV("chainwork", tip.nChainWork.GetHex());
1365  obj.pushKV("size_on_disk",
1366  chainman.m_blockman.CalculateCurrentUsage());
1367  obj.pushKV("pruned", chainman.m_blockman.IsPruneMode());
1368 
1369  if (chainman.m_blockman.IsPruneMode()) {
1370  obj.pushKV("pruneheight",
1372 
1373  // if 0, execution bypasses the whole if block.
1374  bool automatic_pruning{args.GetIntArg("-prune", 0) != 1};
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(config, state,
1558  pblockindex);
1559 
1560  if (!state.IsValid()) {
1562  }
1563 
1564  // Block to make sure wallet/indexers sync before returning
1566 
1567  return NullUniValue;
1568  },
1569  };
1570 }
1571 
1573  return RPCHelpMan{
1574  "invalidateblock",
1575  "Permanently marks a block as invalid, as if it violated a consensus "
1576  "rule.\n",
1577  {
1579  "the hash of the block to mark as invalid"},
1580  },
1582  RPCExamples{HelpExampleCli("invalidateblock", "\"blockhash\"") +
1583  HelpExampleRpc("invalidateblock", "\"blockhash\"")},
1584  [&](const RPCHelpMan &self, const Config &config,
1585  const JSONRPCRequest &request) -> UniValue {
1586  const BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1587  BlockValidationState state;
1588 
1589  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1590  CBlockIndex *pblockindex;
1591  {
1592  LOCK(cs_main);
1593  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1594  if (!pblockindex) {
1596  "Block not found");
1597  }
1598  }
1599  chainman.ActiveChainstate().InvalidateBlock(config, state,
1600  pblockindex);
1601 
1602  if (state.IsValid()) {
1603  chainman.ActiveChainstate().ActivateBestChain(config, state);
1604  }
1605 
1606  if (!state.IsValid()) {
1607  throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
1608  }
1609 
1610  // Block to make sure wallet/indexers sync before returning
1612 
1613  return NullUniValue;
1614  },
1615  };
1616 }
1617 
1619  return RPCHelpMan{
1620  "parkblock",
1621  "Marks a block as parked.\n",
1622  {
1624  "the hash of the block to park"},
1625  },
1627  RPCExamples{HelpExampleCli("parkblock", "\"blockhash\"") +
1628  HelpExampleRpc("parkblock", "\"blockhash\"")},
1629  [&](const RPCHelpMan &self, const Config &config,
1630  const JSONRPCRequest &request) -> UniValue {
1631  const std::string strHash = request.params[0].get_str();
1632  const BlockHash hash(uint256S(strHash));
1633  BlockValidationState state;
1634 
1635  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1636  Chainstate &active_chainstate = chainman.ActiveChainstate();
1637  CBlockIndex *pblockindex = nullptr;
1638  {
1639  LOCK(cs_main);
1640  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1641  if (!pblockindex) {
1643  "Block not found");
1644  }
1645 
1646  if (active_chainstate.IsBlockAvalancheFinalized(pblockindex)) {
1647  // Reset avalanche finalization if we park a finalized
1648  // block.
1649  active_chainstate.ClearAvalancheFinalizedBlock();
1650  }
1651  }
1652 
1653  active_chainstate.ParkBlock(config, state, pblockindex);
1654 
1655  if (state.IsValid()) {
1656  active_chainstate.ActivateBestChain(config, state);
1657  }
1658 
1659  if (!state.IsValid()) {
1661  }
1662 
1663  // Block to make sure wallet/indexers sync before returning
1665 
1666  return NullUniValue;
1667  },
1668  };
1669 }
1670 
1672  return RPCHelpMan{
1673  "reconsiderblock",
1674  "Removes invalidity status of a block, its ancestors and its"
1675  "descendants, reconsider them for activation.\n"
1676  "This can be used to undo the effects of invalidateblock.\n",
1677  {
1679  "the hash of the block to reconsider"},
1680  },
1682  RPCExamples{HelpExampleCli("reconsiderblock", "\"blockhash\"") +
1683  HelpExampleRpc("reconsiderblock", "\"blockhash\"")},
1684  [&](const RPCHelpMan &self, const Config &config,
1685  const JSONRPCRequest &request) -> UniValue {
1686  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1687  const BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1688 
1689  {
1690  LOCK(cs_main);
1691  CBlockIndex *pblockindex =
1692  chainman.m_blockman.LookupBlockIndex(hash);
1693  if (!pblockindex) {
1695  "Block not found");
1696  }
1697 
1698  chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex);
1699  }
1700 
1701  BlockValidationState state;
1702  chainman.ActiveChainstate().ActivateBestChain(config, state);
1703 
1704  if (!state.IsValid()) {
1705  throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
1706  }
1707 
1708  // Block to make sure wallet/indexers sync before returning
1710 
1711  return NullUniValue;
1712  },
1713  };
1714 }
1715 
1717  return RPCHelpMan{
1718  "unparkblock",
1719  "Removes parked status of a block and its descendants, reconsider "
1720  "them for activation.\n"
1721  "This can be used to undo the effects of parkblock.\n",
1722  {
1724  "the hash of the block to unpark"},
1725  },
1727  RPCExamples{HelpExampleCli("unparkblock", "\"blockhash\"") +
1728  HelpExampleRpc("unparkblock", "\"blockhash\"")},
1729  [&](const RPCHelpMan &self, const Config &config,
1730  const JSONRPCRequest &request) -> UniValue {
1731  const std::string strHash = request.params[0].get_str();
1732  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1733  const BlockHash hash(uint256S(strHash));
1734  Chainstate &active_chainstate = chainman.ActiveChainstate();
1735 
1736  {
1737  LOCK(cs_main);
1738 
1739  CBlockIndex *pblockindex =
1740  chainman.m_blockman.LookupBlockIndex(hash);
1741  if (!pblockindex) {
1743  "Block not found");
1744  }
1745 
1746  if (!pblockindex->nStatus.isOnParkedChain()) {
1747  // Block to unpark is not parked so there is nothing to do.
1748  return NullUniValue;
1749  }
1750 
1751  const CBlockIndex *tip = active_chainstate.m_chain.Tip();
1752  if (tip) {
1753  const CBlockIndex *ancestor =
1754  LastCommonAncestor(tip, pblockindex);
1755  if (active_chainstate.IsBlockAvalancheFinalized(ancestor)) {
1756  // Only reset avalanche finalization if we unpark a
1757  // block that might conflict with avalanche finalized
1758  // blocks.
1759  active_chainstate.ClearAvalancheFinalizedBlock();
1760  }
1761  }
1762 
1763  active_chainstate.UnparkBlockAndChildren(pblockindex);
1764  }
1765 
1766  BlockValidationState state;
1767  active_chainstate.ActivateBestChain(config, state);
1768 
1769  if (!state.IsValid()) {
1771  }
1772 
1773  // Block to make sure wallet/indexers sync before returning
1775 
1776  return NullUniValue;
1777  },
1778  };
1779 }
1780 
1782  return RPCHelpMan{
1783  "getchaintxstats",
1784  "Compute statistics about the total number and rate of transactions "
1785  "in the chain.\n",
1786  {
1787  {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{"one month"},
1788  "Size of the window in number of blocks"},
1789  {"blockhash", RPCArg::Type::STR_HEX,
1790  RPCArg::DefaultHint{"chain tip"},
1791  "The hash of the block that ends the window."},
1792  },
1794  "",
1795  "",
1796  {
1797  {RPCResult::Type::NUM_TIME, "time",
1798  "The timestamp for the final block in the window, "
1799  "expressed in " +
1800  UNIX_EPOCH_TIME},
1801  {RPCResult::Type::NUM, "txcount",
1802  "The total number of transactions in the chain up to "
1803  "that point"},
1804  {RPCResult::Type::STR_HEX, "window_final_block_hash",
1805  "The hash of the final block in the window"},
1806  {RPCResult::Type::NUM, "window_final_block_height",
1807  "The height of the final block in the window."},
1808  {RPCResult::Type::NUM, "window_block_count",
1809  "Size of the window in number of blocks"},
1810  {RPCResult::Type::NUM, "window_tx_count",
1811  "The number of transactions in the window. Only "
1812  "returned if \"window_block_count\" is > 0"},
1813  {RPCResult::Type::NUM, "window_interval",
1814  "The elapsed time in the window in seconds. Only "
1815  "returned if \"window_block_count\" is > 0"},
1816  {RPCResult::Type::NUM, "txrate",
1817  "The average rate of transactions per second in the "
1818  "window. Only returned if \"window_interval\" is > 0"},
1819  }},
1820  RPCExamples{HelpExampleCli("getchaintxstats", "") +
1821  HelpExampleRpc("getchaintxstats", "2016")},
1822  [&](const RPCHelpMan &self, const Config &config,
1823  const JSONRPCRequest &request) -> UniValue {
1824  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1825  const CBlockIndex *pindex;
1826 
1827  // By default: 1 month
1828  int blockcount =
1829  30 * 24 * 60 * 60 /
1830  config.GetChainParams().GetConsensus().nPowTargetSpacing;
1831 
1832  if (request.params[1].isNull()) {
1833  LOCK(cs_main);
1834  pindex = chainman.ActiveTip();
1835  } else {
1836  BlockHash hash(ParseHashV(request.params[1], "blockhash"));
1837  LOCK(cs_main);
1838  pindex = chainman.m_blockman.LookupBlockIndex(hash);
1839  if (!pindex) {
1841  "Block not found");
1842  }
1843  if (!chainman.ActiveChain().Contains(pindex)) {
1845  "Block is not in main chain");
1846  }
1847  }
1848 
1849  CHECK_NONFATAL(pindex != nullptr);
1850 
1851  if (request.params[0].isNull()) {
1852  blockcount =
1853  std::max(0, std::min(blockcount, pindex->nHeight - 1));
1854  } else {
1855  blockcount = request.params[0].get_int();
1856 
1857  if (blockcount < 0 ||
1858  (blockcount > 0 && blockcount >= pindex->nHeight)) {
1860  "Invalid block count: "
1861  "should be between 0 and "
1862  "the block's height - 1");
1863  }
1864  }
1865 
1866  const CBlockIndex &past_block{*CHECK_NONFATAL(
1867  pindex->GetAncestor(pindex->nHeight - blockcount))};
1868  const int64_t nTimeDiff{pindex->GetMedianTimePast() -
1869  past_block.GetMedianTimePast()};
1870  const int nTxDiff =
1871  pindex->GetChainTxCount() - past_block.GetChainTxCount();
1872 
1873  UniValue ret(UniValue::VOBJ);
1874  ret.pushKV("time", pindex->GetBlockTime());
1875  ret.pushKV("txcount", pindex->GetChainTxCount());
1876  ret.pushKV("window_final_block_hash",
1877  pindex->GetBlockHash().GetHex());
1878  ret.pushKV("window_final_block_height", pindex->nHeight);
1879  ret.pushKV("window_block_count", blockcount);
1880  if (blockcount > 0) {
1881  ret.pushKV("window_tx_count", nTxDiff);
1882  ret.pushKV("window_interval", nTimeDiff);
1883  if (nTimeDiff > 0) {
1884  ret.pushKV("txrate", double(nTxDiff) / nTimeDiff);
1885  }
1886  }
1887 
1888  return ret;
1889  },
1890  };
1891 }
1892 
1893 template <typename T>
1894 static T CalculateTruncatedMedian(std::vector<T> &scores) {
1895  size_t size = scores.size();
1896  if (size == 0) {
1897  return T();
1898  }
1899 
1900  std::sort(scores.begin(), scores.end());
1901  if (size % 2 == 0) {
1902  return (scores[size / 2 - 1] + scores[size / 2]) / 2;
1903  } else {
1904  return scores[size / 2];
1905  }
1906 }
1907 
1908 template <typename T> static inline bool SetHasKeys(const std::set<T> &set) {
1909  return false;
1910 }
1911 template <typename T, typename Tk, typename... Args>
1912 static inline bool SetHasKeys(const std::set<T> &set, const Tk &key,
1913  const Args &...args) {
1914  return (set.count(key) != 0) || SetHasKeys(set, args...);
1915 }
1916 
1917 // outpoint (needed for the utxo index) + nHeight + fCoinBase
1918 static constexpr size_t PER_UTXO_OVERHEAD =
1919  sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);
1920 
1922  const auto &ticker = Currency::get().ticker;
1923  return RPCHelpMan{
1924  "getblockstats",
1925  "Compute per block statistics for a given window. All amounts are "
1926  "in " +
1927  ticker +
1928  ".\n"
1929  "It won't work for some heights with pruning.\n",
1930  {
1931  {"hash_or_height",
1934  "The block hash or height of the target block",
1935  "",
1936  {"", "string or numeric"}},
1937  {"stats",
1939  RPCArg::DefaultHint{"all values"},
1940  "Values to plot (see result below)",
1941  {
1943  "Selected statistic"},
1945  "Selected statistic"},
1946  },
1947  "stats"},
1948  },
1949  RPCResult{
1951  "",
1952  "",
1953  {
1954  {RPCResult::Type::NUM, "avgfee", "Average fee in the block"},
1955  {RPCResult::Type::NUM, "avgfeerate",
1956  "Average feerate (in satoshis per virtual byte)"},
1957  {RPCResult::Type::NUM, "avgtxsize", "Average transaction size"},
1958  {RPCResult::Type::STR_HEX, "blockhash",
1959  "The block hash (to check for potential reorgs)"},
1960  {RPCResult::Type::NUM, "height", "The height of the block"},
1961  {RPCResult::Type::NUM, "ins",
1962  "The number of inputs (excluding coinbase)"},
1963  {RPCResult::Type::NUM, "maxfee", "Maximum fee in the block"},
1964  {RPCResult::Type::NUM, "maxfeerate",
1965  "Maximum feerate (in satoshis per virtual byte)"},
1966  {RPCResult::Type::NUM, "maxtxsize", "Maximum transaction size"},
1967  {RPCResult::Type::NUM, "medianfee",
1968  "Truncated median fee in the block"},
1969  {RPCResult::Type::NUM, "medianfeerate",
1970  "Truncated median feerate (in " + ticker + " per byte)"},
1971  {RPCResult::Type::NUM, "mediantime",
1972  "The block median time past"},
1973  {RPCResult::Type::NUM, "mediantxsize",
1974  "Truncated median transaction size"},
1975  {RPCResult::Type::NUM, "minfee", "Minimum fee in the block"},
1976  {RPCResult::Type::NUM, "minfeerate",
1977  "Minimum feerate (in satoshis per virtual byte)"},
1978  {RPCResult::Type::NUM, "mintxsize", "Minimum transaction size"},
1979  {RPCResult::Type::NUM, "outs", "The number of outputs"},
1980  {RPCResult::Type::NUM, "subsidy", "The block subsidy"},
1981  {RPCResult::Type::NUM, "time", "The block time"},
1982  {RPCResult::Type::NUM, "total_out",
1983  "Total amount in all outputs (excluding coinbase and thus "
1984  "reward [ie subsidy + totalfee])"},
1985  {RPCResult::Type::NUM, "total_size",
1986  "Total size of all non-coinbase transactions"},
1987  {RPCResult::Type::NUM, "totalfee", "The fee total"},
1988  {RPCResult::Type::NUM, "txs",
1989  "The number of transactions (including coinbase)"},
1990  {RPCResult::Type::NUM, "utxo_increase",
1991  "The increase/decrease in the number of unspent outputs"},
1992  {RPCResult::Type::NUM, "utxo_size_inc",
1993  "The increase/decrease in size for the utxo index (not "
1994  "discounting op_return and similar)"},
1995  }},
1996  RPCExamples{
1998  "getblockstats",
1999  R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
2000  HelpExampleCli("getblockstats",
2001  R"(1000 '["minfeerate","avgfeerate"]')") +
2003  "getblockstats",
2004  R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") +
2005  HelpExampleRpc("getblockstats",
2006  R"(1000, ["minfeerate","avgfeerate"])")},
2007  [&](const RPCHelpMan &self, const Config &config,
2008  const JSONRPCRequest &request) -> UniValue {
2009  ChainstateManager &chainman = EnsureAnyChainman(request.context);
2010  const CBlockIndex &pindex{*CHECK_NONFATAL(
2011  ParseHashOrHeight(request.params[0], chainman))};
2012 
2013  std::set<std::string> stats;
2014  if (!request.params[1].isNull()) {
2015  const UniValue stats_univalue = request.params[1].get_array();
2016  for (unsigned int i = 0; i < stats_univalue.size(); i++) {
2017  const std::string stat = stats_univalue[i].get_str();
2018  stats.insert(stat);
2019  }
2020  }
2021 
2022  const CBlock &block =
2023  GetBlockChecked(config, chainman.m_blockman, &pindex);
2024  const CBlockUndo &blockUndo =
2025  GetUndoChecked(chainman.m_blockman, &pindex);
2026 
2027  // Calculate everything if nothing selected (default)
2028  const bool do_all = stats.size() == 0;
2029  const bool do_mediantxsize =
2030  do_all || stats.count("mediantxsize") != 0;
2031  const bool do_medianfee = do_all || stats.count("medianfee") != 0;
2032  const bool do_medianfeerate =
2033  do_all || stats.count("medianfeerate") != 0;
2034  const bool loop_inputs =
2035  do_all || do_medianfee || do_medianfeerate ||
2036  SetHasKeys(stats, "utxo_size_inc", "totalfee", "avgfee",
2037  "avgfeerate", "minfee", "maxfee", "minfeerate",
2038  "maxfeerate");
2039  const bool loop_outputs =
2040  do_all || loop_inputs || stats.count("total_out");
2041  const bool do_calculate_size =
2042  do_mediantxsize || loop_inputs ||
2043  SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize",
2044  "maxtxsize");
2045 
2046  const int64_t blockMaxSize = config.GetMaxBlockSize();
2047  Amount maxfee = Amount::zero();
2048  Amount maxfeerate = Amount::zero();
2049  Amount minfee = MAX_MONEY;
2050  Amount minfeerate = MAX_MONEY;
2051  Amount total_out = Amount::zero();
2052  Amount totalfee = Amount::zero();
2053  int64_t inputs = 0;
2054  int64_t maxtxsize = 0;
2055  int64_t mintxsize = blockMaxSize;
2056  int64_t outputs = 0;
2057  int64_t total_size = 0;
2058  int64_t utxo_size_inc = 0;
2059  std::vector<Amount> fee_array;
2060  std::vector<Amount> feerate_array;
2061  std::vector<int64_t> txsize_array;
2062 
2063  for (size_t i = 0; i < block.vtx.size(); ++i) {
2064  const auto &tx = block.vtx.at(i);
2065  outputs += tx->vout.size();
2066  Amount tx_total_out = Amount::zero();
2067  if (loop_outputs) {
2068  for (const CTxOut &out : tx->vout) {
2069  tx_total_out += out.nValue;
2070  utxo_size_inc +=
2073  }
2074  }
2075 
2076  if (tx->IsCoinBase()) {
2077  continue;
2078  }
2079 
2080  // Don't count coinbase's fake input
2081  inputs += tx->vin.size();
2082  // Don't count coinbase reward
2083  total_out += tx_total_out;
2084 
2085  int64_t tx_size = 0;
2086  if (do_calculate_size) {
2087  tx_size = tx->GetTotalSize();
2088  if (do_mediantxsize) {
2089  txsize_array.push_back(tx_size);
2090  }
2091  maxtxsize = std::max(maxtxsize, tx_size);
2092  mintxsize = std::min(mintxsize, tx_size);
2093  total_size += tx_size;
2094  }
2095 
2096  if (loop_inputs) {
2097  Amount tx_total_in = Amount::zero();
2098  const auto &txundo = blockUndo.vtxundo.at(i - 1);
2099  for (const Coin &coin : txundo.vprevout) {
2100  const CTxOut &prevoutput = coin.GetTxOut();
2101 
2102  tx_total_in += prevoutput.nValue;
2103  utxo_size_inc -=
2104  GetSerializeSize(prevoutput, PROTOCOL_VERSION) +
2106  }
2107 
2108  Amount txfee = tx_total_in - tx_total_out;
2109  CHECK_NONFATAL(MoneyRange(txfee));
2110  if (do_medianfee) {
2111  fee_array.push_back(txfee);
2112  }
2113  maxfee = std::max(maxfee, txfee);
2114  minfee = std::min(minfee, txfee);
2115  totalfee += txfee;
2116 
2117  Amount feerate = txfee / tx_size;
2118  if (do_medianfeerate) {
2119  feerate_array.push_back(feerate);
2120  }
2121  maxfeerate = std::max(maxfeerate, feerate);
2122  minfeerate = std::min(minfeerate, feerate);
2123  }
2124  }
2125 
2126  UniValue ret_all(UniValue::VOBJ);
2127  ret_all.pushKV("avgfee",
2128  block.vtx.size() > 1
2129  ? (totalfee / int((block.vtx.size() - 1)))
2130  : Amount::zero());
2131  ret_all.pushKV("avgfeerate", total_size > 0
2132  ? (totalfee / total_size)
2133  : Amount::zero());
2134  ret_all.pushKV("avgtxsize",
2135  (block.vtx.size() > 1)
2136  ? total_size / (block.vtx.size() - 1)
2137  : 0);
2138  ret_all.pushKV("blockhash", pindex.GetBlockHash().GetHex());
2139  ret_all.pushKV("height", (int64_t)pindex.nHeight);
2140  ret_all.pushKV("ins", inputs);
2141  ret_all.pushKV("maxfee", maxfee);
2142  ret_all.pushKV("maxfeerate", maxfeerate);
2143  ret_all.pushKV("maxtxsize", maxtxsize);
2144  ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
2145  ret_all.pushKV("medianfeerate",
2146  CalculateTruncatedMedian(feerate_array));
2147  ret_all.pushKV("mediantime", pindex.GetMedianTimePast());
2148  ret_all.pushKV("mediantxsize",
2149  CalculateTruncatedMedian(txsize_array));
2150  ret_all.pushKV("minfee",
2151  minfee == MAX_MONEY ? Amount::zero() : minfee);
2152  ret_all.pushKV("minfeerate", minfeerate == MAX_MONEY
2153  ? Amount::zero()
2154  : minfeerate);
2155  ret_all.pushKV("mintxsize",
2156  mintxsize == blockMaxSize ? 0 : mintxsize);
2157  ret_all.pushKV("outs", outputs);
2158  ret_all.pushKV("subsidy", GetBlockSubsidy(pindex.nHeight,
2159  chainman.GetConsensus()));
2160  ret_all.pushKV("time", pindex.GetBlockTime());
2161  ret_all.pushKV("total_out", total_out);
2162  ret_all.pushKV("total_size", total_size);
2163  ret_all.pushKV("totalfee", totalfee);
2164  ret_all.pushKV("txs", (int64_t)block.vtx.size());
2165  ret_all.pushKV("utxo_increase", outputs - inputs);
2166  ret_all.pushKV("utxo_size_inc", utxo_size_inc);
2167 
2168  if (do_all) {
2169  return ret_all;
2170  }
2171 
2172  UniValue ret(UniValue::VOBJ);
2173  for (const std::string &stat : stats) {
2174  const UniValue &value = ret_all[stat];
2175  if (value.isNull()) {
2176  throw JSONRPCError(
2178  strprintf("Invalid selected statistic %s", stat));
2179  }
2180  ret.pushKV(stat, value);
2181  }
2182  return ret;
2183  },
2184  };
2185 }
2186 
2187 namespace {
2189 static bool FindScriptPubKey(std::atomic<int> &scan_progress,
2190  const std::atomic<bool> &should_abort,
2191  int64_t &count, CCoinsViewCursor *cursor,
2192  const std::set<CScript> &needles,
2193  std::map<COutPoint, Coin> &out_results,
2194  std::function<void()> &interruption_point) {
2195  scan_progress = 0;
2196  count = 0;
2197  while (cursor->Valid()) {
2198  COutPoint key;
2199  Coin coin;
2200  if (!cursor->GetKey(key) || !cursor->GetValue(coin)) {
2201  return false;
2202  }
2203  if (++count % 8192 == 0) {
2204  interruption_point();
2205  if (should_abort) {
2206  // allow to abort the scan via the abort reference
2207  return false;
2208  }
2209  }
2210  if (count % 256 == 0) {
2211  // update progress reference every 256 item
2212  const TxId &txid = key.GetTxId();
2213  uint32_t high = 0x100 * *txid.begin() + *(txid.begin() + 1);
2214  scan_progress = int(high * 100.0 / 65536.0 + 0.5);
2215  }
2216  if (needles.count(coin.GetTxOut().scriptPubKey)) {
2217  out_results.emplace(key, coin);
2218  }
2219  cursor->Next();
2220  }
2221  scan_progress = 100;
2222  return true;
2223 }
2224 } // namespace
2225 
2227 static std::atomic<int> g_scan_progress;
2228 static std::atomic<bool> g_scan_in_progress;
2229 static std::atomic<bool> g_should_abort_scan;
2231 private:
2233 
2234 public:
2236 
2237  bool reserve() {
2239  if (g_scan_in_progress.exchange(true)) {
2240  return false;
2241  }
2242  m_could_reserve = true;
2243  return true;
2244  }
2245 
2247  if (m_could_reserve) {
2248  g_scan_in_progress = false;
2249  }
2250  }
2251 };
2252 
2254  const auto &ticker = Currency::get().ticker;
2255  return RPCHelpMan{
2256  "scantxoutset",
2257  "Scans the unspent transaction output set for entries that match "
2258  "certain output descriptors.\n"
2259  "Examples of output descriptors are:\n"
2260  " addr(<address>) Outputs whose scriptPubKey "
2261  "corresponds to the specified address (does not include P2PK)\n"
2262  " raw(<hex script>) Outputs whose scriptPubKey "
2263  "equals the specified hex scripts\n"
2264  " combo(<pubkey>) P2PK and P2PKH outputs for "
2265  "the given pubkey\n"
2266  " pkh(<pubkey>) P2PKH outputs for the given "
2267  "pubkey\n"
2268  " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for "
2269  "the given threshold and pubkeys\n"
2270  "\nIn the above, <pubkey> either refers to a fixed public key in "
2271  "hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
2272  "or more path elements separated by \"/\", and optionally ending in "
2273  "\"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
2274  "unhardened or hardened child keys.\n"
2275  "In the latter case, a range needs to be specified by below if "
2276  "different from 1000.\n"
2277  "For more information on output descriptors, see the documentation in "
2278  "the doc/descriptors.md file.\n",
2279  {
2281  "The action to execute\n"
2282  " \"start\" for starting a "
2283  "scan\n"
2284  " \"abort\" for aborting the "
2285  "current scan (returns true when abort was successful)\n"
2286  " \"status\" for "
2287  "progress report (in %) of the current scan"},
2288  {"scanobjects",
2291  "Array of scan objects. Required for \"start\" action\n"
2292  " Every scan object is either a "
2293  "string descriptor or an object:",
2294  {
2296  "An output descriptor"},
2297  {
2298  "",
2301  "An object with output descriptor and metadata",
2302  {
2304  "An output descriptor"},
2305  {"range", RPCArg::Type::RANGE, RPCArg::Default{1000},
2306  "The range of HD chain indexes to explore (either "
2307  "end or [begin,end])"},
2308  },
2309  },
2310  },
2311  "[scanobjects,...]"},
2312  },
2313  {
2314  RPCResult{"When action=='abort'", RPCResult::Type::BOOL, "", ""},
2315  RPCResult{"When action=='status' and no scan is in progress",
2316  RPCResult::Type::NONE, "", ""},
2317  RPCResult{
2318  "When action=='status' and scan is in progress",
2320  "",
2321  "",
2322  {
2323  {RPCResult::Type::NUM, "progress", "The scan progress"},
2324  }},
2325  RPCResult{
2326  "When action=='start'",
2328  "",
2329  "",
2330  {
2331  {RPCResult::Type::BOOL, "success",
2332  "Whether the scan was completed"},
2333  {RPCResult::Type::NUM, "txouts",
2334  "The number of unspent transaction outputs scanned"},
2335  {RPCResult::Type::NUM, "height",
2336  "The current block height (index)"},
2337  {RPCResult::Type::STR_HEX, "bestblock",
2338  "The hash of the block at the tip of the chain"},
2340  "unspents",
2341  "",
2342  {
2344  "",
2345  "",
2346  {
2347  {RPCResult::Type::STR_HEX, "txid",
2348  "The transaction id"},
2349  {RPCResult::Type::NUM, "vout", "The vout value"},
2350  {RPCResult::Type::STR_HEX, "scriptPubKey",
2351  "The script key"},
2352  {RPCResult::Type::STR, "desc",
2353  "A specialized descriptor for the matched "
2354  "scriptPubKey"},
2355  {RPCResult::Type::STR_AMOUNT, "amount",
2356  "The total amount in " + ticker +
2357  " of the unspent output"},
2358  {RPCResult::Type::NUM, "height",
2359  "Height of the unspent transaction output"},
2360  }},
2361  }},
2362  {RPCResult::Type::STR_AMOUNT, "total_amount",
2363  "The total amount of all found unspent outputs in " +
2364  ticker},
2365  }},
2366  },
2367  RPCExamples{""},
2368  [&](const RPCHelpMan &self, const Config &config,
2369  const JSONRPCRequest &request) -> UniValue {
2370  RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR});
2371 
2372  UniValue result(UniValue::VOBJ);
2373  if (request.params[0].get_str() == "status") {
2374  CoinsViewScanReserver reserver;
2375  if (reserver.reserve()) {
2376  // no scan in progress
2377  return NullUniValue;
2378  }
2379  result.pushKV("progress", g_scan_progress.load());
2380  return result;
2381  } else if (request.params[0].get_str() == "abort") {
2382  CoinsViewScanReserver reserver;
2383  if (reserver.reserve()) {
2384  // reserve was possible which means no scan was running
2385  return false;
2386  }
2387  // set the abort flag
2388  g_should_abort_scan = true;
2389  return true;
2390  } else if (request.params[0].get_str() == "start") {
2391  CoinsViewScanReserver reserver;
2392  if (!reserver.reserve()) {
2394  "Scan already in progress, use action "
2395  "\"abort\" or \"status\"");
2396  }
2397 
2398  if (request.params.size() < 2) {
2400  "scanobjects argument is required for "
2401  "the start action");
2402  }
2403 
2404  std::set<CScript> needles;
2405  std::map<CScript, std::string> descriptors;
2406  Amount total_in = Amount::zero();
2407 
2408  // loop through the scan objects
2409  for (const UniValue &scanobject :
2410  request.params[1].get_array().getValues()) {
2411  FlatSigningProvider provider;
2412  auto scripts =
2413  EvalDescriptorStringOrObject(scanobject, provider);
2414  for (const auto &script : scripts) {
2415  std::string inferred =
2416  InferDescriptor(script, provider)->ToString();
2417  needles.emplace(script);
2418  descriptors.emplace(std::move(script),
2419  std::move(inferred));
2420  }
2421  }
2422 
2423  // Scan the unspent transaction output set for inputs
2424  UniValue unspents(UniValue::VARR);
2425  std::vector<CTxOut> input_txos;
2426  std::map<COutPoint, Coin> coins;
2427  g_should_abort_scan = false;
2428  g_scan_progress = 0;
2429  int64_t count = 0;
2430  std::unique_ptr<CCoinsViewCursor> pcursor;
2431  const CBlockIndex *tip;
2432  NodeContext &node = EnsureAnyNodeContext(request.context);
2433  {
2434  ChainstateManager &chainman = EnsureChainman(node);
2435  LOCK(cs_main);
2436  Chainstate &active_chainstate = chainman.ActiveChainstate();
2437  active_chainstate.ForceFlushStateToDisk();
2438  pcursor = CHECK_NONFATAL(std::unique_ptr<CCoinsViewCursor>(
2439  active_chainstate.CoinsDB().Cursor()));
2440  tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
2441  }
2442  bool res = FindScriptPubKey(
2443  g_scan_progress, g_should_abort_scan, count, pcursor.get(),
2444  needles, coins, node.rpc_interruption_point);
2445  result.pushKV("success", res);
2446  result.pushKV("txouts", count);
2447  result.pushKV("height", tip->nHeight);
2448  result.pushKV("bestblock", tip->GetBlockHash().GetHex());
2449 
2450  for (const auto &it : coins) {
2451  const COutPoint &outpoint = it.first;
2452  const Coin &coin = it.second;
2453  const CTxOut &txo = coin.GetTxOut();
2454  input_txos.push_back(txo);
2455  total_in += txo.nValue;
2456 
2457  UniValue unspent(UniValue::VOBJ);
2458  unspent.pushKV("txid", outpoint.GetTxId().GetHex());
2459  unspent.pushKV("vout", int32_t(outpoint.GetN()));
2460  unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
2461  unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
2462  unspent.pushKV("amount", txo.nValue);
2463  unspent.pushKV("height", int32_t(coin.GetHeight()));
2464 
2465  unspents.push_back(unspent);
2466  }
2467  result.pushKV("unspents", unspents);
2468  result.pushKV("total_amount", total_in);
2469  } else {
2470  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid command");
2471  }
2472  return result;
2473  },
2474  };
2475 }
2476 
2478  return RPCHelpMan{
2479  "getblockfilter",
2480  "Retrieve a BIP 157 content filter for a particular block.\n",
2481  {
2483  "The hash of the block"},
2484  {"filtertype", RPCArg::Type::STR, RPCArg::Default{"basic"},
2485  "The type name of the filter"},
2486  },
2488  "",
2489  "",
2490  {
2491  {RPCResult::Type::STR_HEX, "filter",
2492  "the hex-encoded filter data"},
2493  {RPCResult::Type::STR_HEX, "header",
2494  "the hex-encoded filter header"},
2495  }},
2496  RPCExamples{
2497  HelpExampleCli("getblockfilter",
2498  "\"00000000c937983704a73af28acdec37b049d214a"
2499  "dbda81d7e2a3dd146f6ed09\" \"basic\"") +
2500  HelpExampleRpc("getblockfilter",
2501  "\"00000000c937983704a73af28acdec37b049d214adbda81d7"
2502  "e2a3dd146f6ed09\", \"basic\"")},
2503  [&](const RPCHelpMan &self, const Config &config,
2504  const JSONRPCRequest &request) -> UniValue {
2505  const BlockHash block_hash(
2506  ParseHashV(request.params[0], "blockhash"));
2507  std::string filtertype_name = "basic";
2508  if (!request.params[1].isNull()) {
2509  filtertype_name = request.params[1].get_str();
2510  }
2511 
2512  BlockFilterType filtertype;
2513  if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2515  "Unknown filtertype");
2516  }
2517 
2518  BlockFilterIndex *index = GetBlockFilterIndex(filtertype);
2519  if (!index) {
2521  "Index is not enabled for filtertype " +
2522  filtertype_name);
2523  }
2524 
2525  const CBlockIndex *block_index;
2526  bool block_was_connected;
2527  {
2528  ChainstateManager &chainman =
2529  EnsureAnyChainman(request.context);
2530  LOCK(cs_main);
2531  block_index = chainman.m_blockman.LookupBlockIndex(block_hash);
2532  if (!block_index) {
2534  "Block not found");
2535  }
2536  block_was_connected =
2537  block_index->IsValid(BlockValidity::SCRIPTS);
2538  }
2539 
2540  bool index_ready = index->BlockUntilSyncedToCurrentChain();
2541 
2542  BlockFilter filter;
2543  uint256 filter_header;
2544  if (!index->LookupFilter(block_index, filter) ||
2545  !index->LookupFilterHeader(block_index, filter_header)) {
2546  int err_code;
2547  std::string errmsg = "Filter not found.";
2548 
2549  if (!block_was_connected) {
2550  err_code = RPC_INVALID_ADDRESS_OR_KEY;
2551  errmsg += " Block was not connected to active chain.";
2552  } else if (!index_ready) {
2553  err_code = RPC_MISC_ERROR;
2554  errmsg += " Block filters are still in the process of "
2555  "being indexed.";
2556  } else {
2557  err_code = RPC_INTERNAL_ERROR;
2558  errmsg += " This error is unexpected and indicates index "
2559  "corruption.";
2560  }
2561 
2562  throw JSONRPCError(err_code, errmsg);
2563  }
2564 
2565  UniValue ret(UniValue::VOBJ);
2566  ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
2567  ret.pushKV("header", filter_header.GetHex());
2568  return ret;
2569  },
2570  };
2571 }
2572 
2579  return RPCHelpMan{
2580  "dumptxoutset",
2581  "Write the serialized UTXO set to disk.\n",
2582  {
2584  "path to the output file. If relative, will be prefixed by "
2585  "datadir."},
2586  },
2588  "",
2589  "",
2590  {
2591  {RPCResult::Type::NUM, "coins_written",
2592  "the number of coins written in the snapshot"},
2593  {RPCResult::Type::STR_HEX, "base_hash",
2594  "the hash of the base of the snapshot"},
2595  {RPCResult::Type::NUM, "base_height",
2596  "the height of the base of the snapshot"},
2597  {RPCResult::Type::STR, "path",
2598  "the absolute path that the snapshot was written to"},
2599  {RPCResult::Type::STR_HEX, "txoutset_hash",
2600  "the hash of the UTXO set contents"},
2601  {RPCResult::Type::NUM, "nchaintx",
2602  "the number of transactions in the chain up to and "
2603  "including the base block"},
2604  }},
2605  RPCExamples{HelpExampleCli("dumptxoutset", "utxo.dat")},
2606  [&](const RPCHelpMan &self, const Config &config,
2607  const JSONRPCRequest &request) -> UniValue {
2608  const ArgsManager &args{EnsureAnyArgsman(request.context)};
2609  const fs::path path = fsbridge::AbsPathJoin(
2610  args.GetDataDirNet(), fs::u8path(request.params[0].get_str()));
2611  // Write to a temporary path and then move into `path` on completion
2612  // to avoid confusion due to an interruption.
2613  const fs::path temppath = fsbridge::AbsPathJoin(
2614  args.GetDataDirNet(),
2615  fs::u8path(request.params[0].get_str() + ".incomplete"));
2616 
2617  if (fs::exists(path)) {
2619  path.u8string() +
2620  " already exists. If you are sure this "
2621  "is what you want, "
2622  "move it out of the way first");
2623  }
2624 
2625  FILE *file{fsbridge::fopen(temppath, "wb")};
2626  AutoFile afile{file};
2627  NodeContext &node = EnsureAnyNodeContext(request.context);
2628  UniValue result = CreateUTXOSnapshot(
2629  node, node.chainman->ActiveChainstate(), afile, path, temppath);
2630  fs::rename(temppath, path);
2631 
2632  return result;
2633  },
2634  };
2635 }
2636 
2638  AutoFile &afile, const fs::path &path,
2639  const fs::path &temppath) {
2640  std::unique_ptr<CCoinsViewCursor> pcursor;
2641  std::optional<CCoinsStats> maybe_stats;
2642  const CBlockIndex *tip;
2643 
2644  {
2645  // We need to lock cs_main to ensure that the coinsdb isn't
2646  // written to between (i) flushing coins cache to disk
2647  // (coinsdb), (ii) getting stats based upon the coinsdb, and
2648  // (iii) constructing a cursor to the coinsdb for use below this
2649  // block.
2650  //
2651  // Cursors returned by leveldb iterate over snapshots, so the
2652  // contents of the pcursor will not be affected by simultaneous
2653  // writes during use below this block.
2654  //
2655  // See discussion here:
2656  // https://github.com/bitcoin/bitcoin/pull/15606#discussion_r274479369
2657  //
2658  LOCK(::cs_main);
2659 
2660  chainstate.ForceFlushStateToDisk();
2661 
2662  maybe_stats = GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman,
2663  CoinStatsHashType::HASH_SERIALIZED,
2664  node.rpc_interruption_point);
2665  if (!maybe_stats) {
2666  throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
2667  }
2668 
2669  pcursor =
2670  std::unique_ptr<CCoinsViewCursor>(chainstate.CoinsDB().Cursor());
2671  tip = CHECK_NONFATAL(
2672  chainstate.m_blockman.LookupBlockIndex(maybe_stats->hashBlock));
2673  }
2674 
2676  strprintf("writing UTXO snapshot at height %s (%s) to file %s (via %s)",
2677  tip->nHeight, tip->GetBlockHash().ToString(),
2678  fs::PathToString(path), fs::PathToString(temppath)));
2679 
2680  SnapshotMetadata metadata{tip->GetBlockHash(), maybe_stats->coins_count,
2681  uint64_t(tip->GetChainTxCount())};
2682 
2683  afile << metadata;
2684 
2685  COutPoint key;
2686  Coin coin;
2687  unsigned int iter{0};
2688 
2689  while (pcursor->Valid()) {
2690  if (iter % 5000 == 0) {
2691  node.rpc_interruption_point();
2692  }
2693  ++iter;
2694  if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
2695  afile << key;
2696  afile << coin;
2697  }
2698 
2699  pcursor->Next();
2700  }
2701 
2702  afile.fclose();
2703 
2704  UniValue result(UniValue::VOBJ);
2705  result.pushKV("coins_written", maybe_stats->coins_count);
2706  result.pushKV("base_hash", tip->GetBlockHash().ToString());
2707  result.pushKV("base_height", tip->nHeight);
2708  result.pushKV("path", path.u8string());
2709  result.pushKV("txoutset_hash", maybe_stats->hashSerialized.ToString());
2710  // Cast required because univalue doesn't have serialization specified for
2711  // `unsigned int`, nChainTx's type.
2712  result.pushKV("nchaintx", uint64_t{tip->nChainTx});
2713  return result;
2714 }
2715 
2717  // clang-format off
2718  static const CRPCCommand commands[] = {
2719  // category actor (function)
2720  // ------------------ ----------------------
2721  { "blockchain", getbestblockhash, },
2722  { "blockchain", getblock, },
2723  { "blockchain", getblockfrompeer, },
2724  { "blockchain", getblockchaininfo, },
2725  { "blockchain", getblockcount, },
2726  { "blockchain", getblockhash, },
2727  { "blockchain", getblockheader, },
2728  { "blockchain", getblockstats, },
2729  { "blockchain", getchaintips, },
2730  { "blockchain", getchaintxstats, },
2731  { "blockchain", getdifficulty, },
2732  { "blockchain", gettxout, },
2733  { "blockchain", gettxoutsetinfo, },
2734  { "blockchain", pruneblockchain, },
2735  { "blockchain", verifychain, },
2736  { "blockchain", preciousblock, },
2737  { "blockchain", scantxoutset, },
2738  { "blockchain", getblockfilter, },
2739 
2740  /* Not shown in help */
2741  { "hidden", invalidateblock, },
2742  { "hidden", parkblock, },
2743  { "hidden", reconsiderblock, },
2744  { "hidden", syncwithvalidationinterfacequeue, },
2745  { "hidden", dumptxoutset, },
2746  { "hidden", unparkblock, },
2747  { "hidden", waitfornewblock, },
2748  { "hidden", waitforblock, },
2749  { "hidden", waitforblockheight, },
2750  };
2751  // clang-format on
2752  for (const auto &c : commands) {
2753  t.appendCommand(c.name, &c);
2754  }
2755 }
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:545
int fclose()
Definition: streams.h:558
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:199
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:578
VerifyDBResult VerifyDB(Chainstate &chainstate, const Config &config, 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:653
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:762
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:795
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 ParkBlock(const Config &config, BlockValidationState &state, CBlockIndex *pindex) LOCKS_EXCLUDED(cs_main) EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex
Park a block.
bool ActivateBestChain(const Config &config, BlockValidationState &state, std::shared_ptr< const CBlock > pblock=nullptr) 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:788
node::BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all Chainstate instances.
Definition: validation.h:726
void ClearAvalancheFinalizedBlock() EXCLUSIVE_LOCKS_REQUIRED(!cs_avalancheFinalizedBlockIndex)
Clear avalanche finalization.
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:1164
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1361
const CChainParams & GetParams() const
Definition: validation.h:1257
node::BlockMap & BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:1371
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1364
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1367
const Consensus::Params & GetConsensus() const
Definition: validation.h:1260
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1283
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:83
std::string ToString() const
Definition: uint256.h:78
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:68
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:192
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:189
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:127
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:166
size_t GetSerializeSize(const T &t, int nVersion=0)
Definition: serialize.h:1276
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:141
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:101
void PruneBlockFilesManual(Chainstate &active_chainstate, int nManualPruneHeight)
Prune block files up to a given height.
static const unsigned int DEFAULT_CHECKLEVEL
Definition: validation.h:100
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:98
static const signed int DEFAULT_CHECKBLOCKS
Definition: validation.h:99
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