Bitcoin ABC  0.29.4
P2P Digital Currency
blockchain.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2019 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include <rpc/blockchain.h>
7 
8 #include <blockfilter.h>
9 #include <chain.h>
10 #include <chainparams.h>
11 #include <coins.h>
12 #include <common/args.h>
13 #include <config.h>
14 #include <consensus/amount.h>
15 #include <consensus/params.h>
16 #include <consensus/validation.h>
17 #include <core_io.h>
18 #include <hash.h>
19 #include <index/blockfilterindex.h>
20 #include <index/coinstatsindex.h>
21 #include <logging/timer.h>
22 #include <net.h>
23 #include <net_processing.h>
24 #include <node/blockstorage.h>
25 #include <node/coinstats.h>
26 #include <node/context.h>
27 #include <node/utxo_snapshot.h>
28 #include <primitives/transaction.h>
29 #include <rpc/server.h>
30 #include <rpc/server_util.h>
31 #include <rpc/util.h>
32 #include <script/descriptor.h>
33 #include <streams.h>
34 #include <txdb.h>
35 #include <txmempool.h>
36 #include <undo.h>
37 #include <util/check.h>
38 #include <util/fs.h>
39 #include <util/strencodings.h>
40 #include <util/translation.h>
41 #include <validation.h>
42 #include <validationinterface.h>
43 #include <warnings.h>
44 
45 #include <condition_variable>
46 #include <cstdint>
47 #include <memory>
48 #include <mutex>
49 
52 
53 using node::BlockManager;
54 using node::GetUTXOStats;
55 using node::NodeContext;
57 
58 struct CUpdatedBlock {
60  int height;
61 };
62 
64 static std::condition_variable cond_blockchange;
66 
70 double GetDifficulty(const CBlockIndex *blockindex) {
71  CHECK_NONFATAL(blockindex);
72 
73  int nShift = (blockindex->nBits >> 24) & 0xff;
74  double dDiff = double(0x0000ffff) / double(blockindex->nBits & 0x00ffffff);
75 
76  while (nShift < 29) {
77  dDiff *= 256.0;
78  nShift++;
79  }
80  while (nShift > 29) {
81  dDiff /= 256.0;
82  nShift--;
83  }
84 
85  return dDiff;
86 }
87 
88 static int ComputeNextBlockAndDepth(const CBlockIndex *tip,
89  const CBlockIndex *blockindex,
90  const CBlockIndex *&next) {
91  next = tip->GetAncestor(blockindex->nHeight + 1);
92  if (next && next->pprev == blockindex) {
93  return tip->nHeight - blockindex->nHeight + 1;
94  }
95  next = nullptr;
96  return blockindex == tip ? 1 : -1;
97 }
98 
99 static const CBlockIndex *ParseHashOrHeight(const UniValue &param,
100  ChainstateManager &chainman) {
101  LOCK(::cs_main);
102  CChain &active_chain = chainman.ActiveChain();
103 
104  if (param.isNum()) {
105  const int height{param.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  blockman.UndoReadFromDisk(blockUndo, *blockindex)};
178  for (size_t i = 0; i < block.vtx.size(); ++i) {
179  const CTransactionRef &tx = block.vtx.at(i);
180  // coinbase transaction (i == 0) doesn't have undo data
181  const CTxUndo *txundo =
182  (have_undo && i) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
183  UniValue objTx(UniValue::VOBJ);
184  TxToUniv(*tx, BlockHash(), objTx, true, RPCSerializationFlags(),
185  txundo);
186  txs.push_back(objTx);
187  }
188  } else {
189  for (const CTransactionRef &tx : block.vtx) {
190  txs.push_back(tx->GetId().GetHex());
191  }
192  }
193  result.pushKV("tx", txs);
194 
195  return result;
196 }
197 
199  return RPCHelpMan{
200  "getblockcount",
201  "Returns the height of the most-work fully-validated chain.\n"
202  "The genesis block has height 0.\n",
203  {},
204  RPCResult{RPCResult::Type::NUM, "", "The current block count"},
205  RPCExamples{HelpExampleCli("getblockcount", "") +
206  HelpExampleRpc("getblockcount", "")},
207  [&](const RPCHelpMan &self, const Config &config,
208  const JSONRPCRequest &request) -> UniValue {
209  ChainstateManager &chainman = EnsureAnyChainman(request.context);
210  LOCK(cs_main);
211  return chainman.ActiveHeight();
212  },
213  };
214 }
215 
217  return RPCHelpMan{
218  "getbestblockhash",
219  "Returns the hash of the best (tip) block in the "
220  "most-work fully-validated chain.\n",
221  {},
222  RPCResult{RPCResult::Type::STR_HEX, "", "the block hash, hex-encoded"},
223  RPCExamples{HelpExampleCli("getbestblockhash", "") +
224  HelpExampleRpc("getbestblockhash", "")},
225  [&](const RPCHelpMan &self, const Config &config,
226  const JSONRPCRequest &request) -> UniValue {
227  ChainstateManager &chainman = EnsureAnyChainman(request.context);
228  LOCK(cs_main);
229  return chainman.ActiveTip()->GetBlockHash().GetHex();
230  },
231  };
232 }
233 
234 void RPCNotifyBlockChange(const CBlockIndex *pindex) {
235  if (pindex) {
237  latestblock.hash = pindex->GetBlockHash();
238  latestblock.height = pindex->nHeight;
239  }
240  cond_blockchange.notify_all();
241 }
242 
244  return RPCHelpMan{
245  "waitfornewblock",
246  "Waits for a specific new block and returns useful info about it.\n"
247  "\nReturns the current block on timeout or exit.\n",
248  {
249  {"timeout", RPCArg::Type::NUM, RPCArg::Default{0},
250  "Time in milliseconds to wait for a response. 0 indicates no "
251  "timeout."},
252  },
254  "",
255  "",
256  {
257  {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
258  {RPCResult::Type::NUM, "height", "Block height"},
259  }},
260  RPCExamples{HelpExampleCli("waitfornewblock", "1000") +
261  HelpExampleRpc("waitfornewblock", "1000")},
262  [&](const RPCHelpMan &self, const Config &config,
263  const JSONRPCRequest &request) -> UniValue {
264  int timeout = 0;
265  if (!request.params[0].isNull()) {
266  timeout = request.params[0].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 
637  const CBlockIndex *pblockindex) {
638  CBlock block;
639  {
640  LOCK(cs_main);
641  if (blockman.IsBlockPruned(pblockindex)) {
643  "Block not available (pruned data)");
644  }
645  }
646 
647  if (!blockman.ReadBlockFromDisk(block, *pblockindex)) {
648  // Block not found on disk. This could be because we have the block
649  // header in our index but not yet have the block or did not accept the
650  // block. Or if the block was pruned right after we released the lock
651  // above.
652  throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
653  }
654 
655  return block;
656 }
657 
659  const CBlockIndex *pblockindex) {
660  CBlockUndo blockUndo;
661 
662  {
663  LOCK(cs_main);
664  if (blockman.IsBlockPruned(pblockindex)) {
666  "Undo data not available (pruned data)");
667  }
668  }
669 
670  if (!blockman.UndoReadFromDisk(blockUndo, *pblockindex)) {
671  throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
672  }
673 
674  return blockUndo;
675 }
676 
678  return RPCHelpMan{
679  "getblock",
680  "If verbosity is 0 or false, returns a string that is serialized, "
681  "hex-encoded data for block 'hash'.\n"
682  "If verbosity is 1 or true, returns an Object with information about "
683  "block <hash>.\n"
684  "If verbosity is 2, returns an Object with information about block "
685  "<hash> and information about each transaction.\n",
686  {
688  "The block hash"},
689  {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1},
690  "0 for hex-encoded data, 1 for a json object, and 2 for json "
691  "object with transaction data"},
692  },
693  {
694  RPCResult{"for verbosity = 0", RPCResult::Type::STR_HEX, "",
695  "A string that is serialized, hex-encoded data for block "
696  "'hash'"},
697  RPCResult{
698  "for verbosity = 1",
700  "",
701  "",
702  {
703  {RPCResult::Type::STR_HEX, "hash",
704  "the block hash (same as provided)"},
705  {RPCResult::Type::NUM, "confirmations",
706  "The number of confirmations, or -1 if the block is not "
707  "on the main chain"},
708  {RPCResult::Type::NUM, "size", "The block size"},
709  {RPCResult::Type::NUM, "height",
710  "The block height or index"},
711  {RPCResult::Type::NUM, "version", "The block version"},
712  {RPCResult::Type::STR_HEX, "versionHex",
713  "The block version formatted in hexadecimal"},
714  {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
716  "tx",
717  "The transaction ids",
718  {{RPCResult::Type::STR_HEX, "", "The transaction id"}}},
719  {RPCResult::Type::NUM_TIME, "time",
720  "The block time expressed in " + UNIX_EPOCH_TIME},
721  {RPCResult::Type::NUM_TIME, "mediantime",
722  "The median block time expressed in " + UNIX_EPOCH_TIME},
723  {RPCResult::Type::NUM, "nonce", "The nonce"},
724  {RPCResult::Type::STR_HEX, "bits", "The bits"},
725  {RPCResult::Type::NUM, "difficulty", "The difficulty"},
726  {RPCResult::Type::STR_HEX, "chainwork",
727  "Expected number of hashes required to produce the chain "
728  "up to this block (in hex)"},
729  {RPCResult::Type::NUM, "nTx",
730  "The number of transactions in the block"},
731  {RPCResult::Type::STR_HEX, "previousblockhash",
732  /* optional */ true,
733  "The hash of the previous block (if available)"},
734  {RPCResult::Type::STR_HEX, "nextblockhash",
735  /* optional */ true,
736  "The hash of the next block (if available)"},
737  }},
738  RPCResult{"for verbosity = 2",
740  "",
741  "",
742  {
744  "Same output as verbosity = 1"},
746  "tx",
747  "",
748  {
750  "",
751  "",
752  {
754  "The transactions in the format of the "
755  "getrawtransaction RPC. Different from "
756  "verbosity = 1 \"tx\" result"},
758  "The transaction fee in " +
760  ", omitted if block undo data is not "
761  "available"},
762  }},
763  }},
764  }},
765  },
766  RPCExamples{
767  HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d"
768  "214adbda81d7e2a3dd146f6ed09\"") +
769  HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d"
770  "214adbda81d7e2a3dd146f6ed09\"")},
771  [&](const RPCHelpMan &self, const Config &config,
772  const JSONRPCRequest &request) -> UniValue {
773  BlockHash hash(ParseHashV(request.params[0], "blockhash"));
774 
775  int verbosity = 1;
776  if (!request.params[1].isNull()) {
777  if (request.params[1].isNum()) {
778  verbosity = request.params[1].get_int();
779  } else {
780  verbosity = request.params[1].get_bool() ? 1 : 0;
781  }
782  }
783 
784  const CBlockIndex *pblockindex;
785  const CBlockIndex *tip;
786  ChainstateManager &chainman = EnsureAnyChainman(request.context);
787  {
788  LOCK(cs_main);
789  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
790  tip = chainman.ActiveTip();
791 
792  if (!pblockindex) {
794  "Block not found");
795  }
796  }
797 
798  const CBlock block =
799  GetBlockChecked(chainman.m_blockman, pblockindex);
800 
801  if (verbosity <= 0) {
802  CDataStream ssBlock(SER_NETWORK,
804  ssBlock << block;
805  std::string strHex = HexStr(ssBlock);
806  return strHex;
807  }
808 
809  return blockToJSON(chainman.m_blockman, block, tip, pblockindex,
810  verbosity >= 2);
811  },
812  };
813 }
814 
816  return RPCHelpMan{
817  "pruneblockchain",
818  "",
819  {
821  "The block height to prune up to. May be set to a discrete "
822  "height, or to a " +
824  "\n"
825  " to prune blocks whose block time is at "
826  "least 2 hours older than the provided timestamp."},
827  },
828  RPCResult{RPCResult::Type::NUM, "", "Height of the last block pruned"},
829  RPCExamples{HelpExampleCli("pruneblockchain", "1000") +
830  HelpExampleRpc("pruneblockchain", "1000")},
831  [&](const RPCHelpMan &self, const Config &config,
832  const JSONRPCRequest &request) -> UniValue {
833  ChainstateManager &chainman = EnsureAnyChainman(request.context);
834  if (!chainman.m_blockman.IsPruneMode()) {
835  throw JSONRPCError(
837  "Cannot prune blocks because node is not in prune mode.");
838  }
839 
840  LOCK(cs_main);
841  Chainstate &active_chainstate = chainman.ActiveChainstate();
842  CChain &active_chain = active_chainstate.m_chain;
843 
844  int heightParam = request.params[0].get_int();
845  if (heightParam < 0) {
847  "Negative block height.");
848  }
849 
850  // Height value more than a billion is too high to be a block
851  // height, and too low to be a block time (corresponds to timestamp
852  // from Sep 2001).
853  if (heightParam > 1000000000) {
854  // Add a 2 hour buffer to include blocks which might have had
855  // old timestamps
856  const CBlockIndex *pindex = active_chain.FindEarliestAtLeast(
857  heightParam - TIMESTAMP_WINDOW, 0);
858  if (!pindex) {
860  "Could not find block with at least the "
861  "specified timestamp.");
862  }
863  heightParam = pindex->nHeight;
864  }
865 
866  unsigned int height = (unsigned int)heightParam;
867  unsigned int chainHeight = (unsigned int)active_chain.Height();
868  if (chainHeight < config.GetChainParams().PruneAfterHeight()) {
870  "Blockchain is too short for pruning.");
871  } else if (height > chainHeight) {
872  throw JSONRPCError(
874  "Blockchain is shorter than the attempted prune height.");
875  } else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
877  "Attempt to prune blocks close to the tip. "
878  "Retaining the minimum number of blocks.\n");
879  height = chainHeight - MIN_BLOCKS_TO_KEEP;
880  }
881 
882  PruneBlockFilesManual(active_chainstate, height);
883  const CBlockIndex &block{*CHECK_NONFATAL(active_chain.Tip())};
884  const CBlockIndex *last_block{
885  active_chainstate.m_blockman.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(chainman.GetNotifications())
1280  .VerifyDB(active_chainstate,
1281  active_chainstate.CoinsTip(), check_level,
1282  check_depth) == VerifyDBResult::SUCCESS;
1283  },
1284  };
1285 }
1286 
1288  return RPCHelpMan{
1289  "getblockchaininfo",
1290  "Returns an object containing various state info regarding blockchain "
1291  "processing.\n",
1292  {},
1293  RPCResult{
1295  "",
1296  "",
1297  {
1298  {RPCResult::Type::STR, "chain",
1299  "current network name (main, test, regtest)"},
1300  {RPCResult::Type::NUM, "blocks",
1301  "the height of the most-work fully-validated chain. The "
1302  "genesis block has height 0"},
1303  {RPCResult::Type::NUM, "headers",
1304  "the current number of headers we have validated"},
1305  {RPCResult::Type::STR, "bestblockhash",
1306  "the hash of the currently best block"},
1307  {RPCResult::Type::NUM, "difficulty", "the current difficulty"},
1308  {RPCResult::Type::NUM_TIME, "time",
1309  "The block time expressed in " + UNIX_EPOCH_TIME},
1310  {RPCResult::Type::NUM_TIME, "mediantime",
1311  "The median block time expressed in " + UNIX_EPOCH_TIME},
1312  {RPCResult::Type::NUM, "verificationprogress",
1313  "estimate of verification progress [0..1]"},
1314  {RPCResult::Type::BOOL, "initialblockdownload",
1315  "(debug information) estimate of whether this node is in "
1316  "Initial Block Download mode"},
1317  {RPCResult::Type::STR_HEX, "chainwork",
1318  "total amount of work in active chain, in hexadecimal"},
1319  {RPCResult::Type::NUM, "size_on_disk",
1320  "the estimated size of the block and undo files on disk"},
1321  {RPCResult::Type::BOOL, "pruned",
1322  "if the blocks are subject to pruning"},
1323  {RPCResult::Type::NUM, "pruneheight",
1324  "lowest-height complete block stored (only present if pruning "
1325  "is enabled)"},
1326  {RPCResult::Type::BOOL, "automatic_pruning",
1327  "whether automatic pruning is enabled (only present if "
1328  "pruning is enabled)"},
1329  {RPCResult::Type::NUM, "prune_target_size",
1330  "the target size used by pruning (only present if automatic "
1331  "pruning is enabled)"},
1332  {RPCResult::Type::STR, "warnings",
1333  "any network and blockchain warnings"},
1334  }},
1335  RPCExamples{HelpExampleCli("getblockchaininfo", "") +
1336  HelpExampleRpc("getblockchaininfo", "")},
1337  [&](const RPCHelpMan &self, const Config &config,
1338  const JSONRPCRequest &request) -> UniValue {
1339  const CChainParams &chainparams = config.GetChainParams();
1340 
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(
1371  "pruneheight",
1372  chainman.m_blockman.GetFirstStoredBlock(tip)->nHeight);
1373 
1374  const bool automatic_pruning{
1375  chainman.m_blockman.GetPruneTarget() !=
1376  BlockManager::PRUNE_TARGET_MANUAL};
1377  obj.pushKV("automatic_pruning", automatic_pruning);
1378  if (automatic_pruning) {
1379  obj.pushKV("prune_target_size",
1380  chainman.m_blockman.GetPruneTarget());
1381  }
1382  }
1383 
1384  obj.pushKV("warnings", GetWarnings(false).original);
1385  return obj;
1386  },
1387  };
1388 }
1389 
1392  bool operator()(const CBlockIndex *a, const CBlockIndex *b) const {
1393  // Make sure that unequal blocks with the same height do not compare
1394  // equal. Use the pointers themselves to make a distinction.
1395  if (a->nHeight != b->nHeight) {
1396  return (a->nHeight > b->nHeight);
1397  }
1398 
1399  return a < b;
1400  }
1401 };
1402 
1404  return RPCHelpMan{
1405  "getchaintips",
1406  "Return information about all known tips in the block tree, including "
1407  "the main chain as well as orphaned branches.\n",
1408  {},
1409  RPCResult{
1411  "",
1412  "",
1414  "",
1415  "",
1416  {
1417  {RPCResult::Type::NUM, "height", "height of the chain tip"},
1418  {RPCResult::Type::STR_HEX, "hash", "block hash of the tip"},
1419  {RPCResult::Type::NUM, "branchlen",
1420  "zero for main chain, otherwise length of branch connecting "
1421  "the tip to the main chain"},
1422  {RPCResult::Type::STR, "status",
1423  "status of the chain, \"active\" for the main chain\n"
1424  "Possible values for status:\n"
1425  "1. \"invalid\" This branch contains at "
1426  "least one invalid block\n"
1427  "2. \"parked\" This branch contains at "
1428  "least one parked block\n"
1429  "3. \"headers-only\" Not all blocks for this "
1430  "branch are available, but the headers are valid\n"
1431  "4. \"valid-headers\" All blocks are available for "
1432  "this branch, but they were never fully validated\n"
1433  "5. \"valid-fork\" This branch is not part of "
1434  "the active chain, but is fully validated\n"
1435  "6. \"active\" This is the tip of the "
1436  "active main chain, which is certainly valid"},
1437  }}}},
1438  RPCExamples{HelpExampleCli("getchaintips", "") +
1439  HelpExampleRpc("getchaintips", "")},
1440  [&](const RPCHelpMan &self, const Config &config,
1441  const JSONRPCRequest &request) -> UniValue {
1442  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1443  LOCK(cs_main);
1444  CChain &active_chain = chainman.ActiveChain();
1445 
1457  std::set<const CBlockIndex *, CompareBlocksByHeight> setTips;
1458  std::set<const CBlockIndex *> setOrphans;
1459  std::set<const CBlockIndex *> setPrevs;
1460 
1461  for (const auto &[_, block_index] : chainman.BlockIndex()) {
1462  if (!active_chain.Contains(&block_index)) {
1463  setOrphans.insert(&block_index);
1464  setPrevs.insert(block_index.pprev);
1465  }
1466  }
1467 
1468  for (std::set<const CBlockIndex *>::iterator it =
1469  setOrphans.begin();
1470  it != setOrphans.end(); ++it) {
1471  if (setPrevs.erase(*it) == 0) {
1472  setTips.insert(*it);
1473  }
1474  }
1475 
1476  // Always report the currently active tip.
1477  setTips.insert(active_chain.Tip());
1478 
1479  /* Construct the output array. */
1480  UniValue res(UniValue::VARR);
1481  for (const CBlockIndex *block : setTips) {
1482  UniValue obj(UniValue::VOBJ);
1483  obj.pushKV("height", block->nHeight);
1484  obj.pushKV("hash", block->phashBlock->GetHex());
1485 
1486  const int branchLen =
1487  block->nHeight - active_chain.FindFork(block)->nHeight;
1488  obj.pushKV("branchlen", branchLen);
1489 
1490  std::string status;
1491  if (active_chain.Contains(block)) {
1492  // This block is part of the currently active chain.
1493  status = "active";
1494  } else if (block->nStatus.isInvalid()) {
1495  // This block or one of its ancestors is invalid.
1496  status = "invalid";
1497  } else if (block->nStatus.isOnParkedChain()) {
1498  // This block or one of its ancestors is parked.
1499  status = "parked";
1500  } else if (!block->HaveTxsDownloaded()) {
1501  // This block cannot be connected because full block data
1502  // for it or one of its parents is missing.
1503  status = "headers-only";
1504  } else if (block->IsValid(BlockValidity::SCRIPTS)) {
1505  // This block is fully validated, but no longer part of the
1506  // active chain. It was probably the active block once, but
1507  // was reorganized.
1508  status = "valid-fork";
1509  } else if (block->IsValid(BlockValidity::TREE)) {
1510  // The headers for this block are valid, but it has not been
1511  // validated. It was probably never part of the most-work
1512  // chain.
1513  status = "valid-headers";
1514  } else {
1515  // No clue.
1516  status = "unknown";
1517  }
1518  obj.pushKV("status", status);
1519 
1520  res.push_back(obj);
1521  }
1522 
1523  return res;
1524  },
1525  };
1526 }
1527 
1529  return RPCHelpMan{
1530  "preciousblock",
1531  "Treats a block as if it were received before others with the same "
1532  "work.\n"
1533  "\nA later preciousblock call can override the effect of an earlier "
1534  "one.\n"
1535  "\nThe effects of preciousblock are not retained across restarts.\n",
1536  {
1538  "the hash of the block to mark as precious"},
1539  },
1541  RPCExamples{HelpExampleCli("preciousblock", "\"blockhash\"") +
1542  HelpExampleRpc("preciousblock", "\"blockhash\"")},
1543  [&](const RPCHelpMan &self, const Config &config,
1544  const JSONRPCRequest &request) -> UniValue {
1545  BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1546  CBlockIndex *pblockindex;
1547 
1548  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1549  {
1550  LOCK(cs_main);
1551  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1552  if (!pblockindex) {
1554  "Block not found");
1555  }
1556  }
1557 
1558  BlockValidationState state;
1559  chainman.ActiveChainstate().PreciousBlock(state, pblockindex);
1560 
1561  if (!state.IsValid()) {
1563  }
1564 
1565  // Block to make sure wallet/indexers sync before returning
1567 
1568  return NullUniValue;
1569  },
1570  };
1571 }
1572 
1574  return RPCHelpMan{
1575  "invalidateblock",
1576  "Permanently marks a block as invalid, as if it violated a consensus "
1577  "rule.\n",
1578  {
1580  "the hash of the block to mark as invalid"},
1581  },
1583  RPCExamples{HelpExampleCli("invalidateblock", "\"blockhash\"") +
1584  HelpExampleRpc("invalidateblock", "\"blockhash\"")},
1585  [&](const RPCHelpMan &self, const Config &config,
1586  const JSONRPCRequest &request) -> UniValue {
1587  const BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1588  BlockValidationState state;
1589 
1590  ChainstateManager &chainman = EnsureAnyChainman(request.context);
1591  CBlockIndex *pblockindex;
1592  {
1593  LOCK(cs_main);
1594  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1595  if (!pblockindex) {
1597  "Block not found");
1598  }
1599  }
1600  chainman.ActiveChainstate().InvalidateBlock(state, pblockindex);
1601 
1602  if (state.IsValid()) {
1603  chainman.ActiveChainstate().ActivateBestChain(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(state, pblockindex);
1654 
1655  if (state.IsValid()) {
1656  active_chainstate.ActivateBestChain(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(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(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 = GetBlockChecked(chainman.m_blockman, &pindex);
2023  const CBlockUndo &blockUndo =
2024  GetUndoChecked(chainman.m_blockman, &pindex);
2025 
2026  // Calculate everything if nothing selected (default)
2027  const bool do_all = stats.size() == 0;
2028  const bool do_mediantxsize =
2029  do_all || stats.count("mediantxsize") != 0;
2030  const bool do_medianfee = do_all || stats.count("medianfee") != 0;
2031  const bool do_medianfeerate =
2032  do_all || stats.count("medianfeerate") != 0;
2033  const bool loop_inputs =
2034  do_all || do_medianfee || do_medianfeerate ||
2035  SetHasKeys(stats, "utxo_size_inc", "totalfee", "avgfee",
2036  "avgfeerate", "minfee", "maxfee", "minfeerate",
2037  "maxfeerate");
2038  const bool loop_outputs =
2039  do_all || loop_inputs || stats.count("total_out");
2040  const bool do_calculate_size =
2041  do_mediantxsize || loop_inputs ||
2042  SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize",
2043  "maxtxsize");
2044 
2045  const int64_t blockMaxSize = config.GetMaxBlockSize();
2046  Amount maxfee = Amount::zero();
2047  Amount maxfeerate = Amount::zero();
2048  Amount minfee = MAX_MONEY;
2049  Amount minfeerate = MAX_MONEY;
2050  Amount total_out = Amount::zero();
2051  Amount totalfee = Amount::zero();
2052  int64_t inputs = 0;
2053  int64_t maxtxsize = 0;
2054  int64_t mintxsize = blockMaxSize;
2055  int64_t outputs = 0;
2056  int64_t total_size = 0;
2057  int64_t utxo_size_inc = 0;
2058  std::vector<Amount> fee_array;
2059  std::vector<Amount> feerate_array;
2060  std::vector<int64_t> txsize_array;
2061 
2062  for (size_t i = 0; i < block.vtx.size(); ++i) {
2063  const auto &tx = block.vtx.at(i);
2064  outputs += tx->vout.size();
2065  Amount tx_total_out = Amount::zero();
2066  if (loop_outputs) {
2067  for (const CTxOut &out : tx->vout) {
2068  tx_total_out += out.nValue;
2069  utxo_size_inc +=
2072  }
2073  }
2074 
2075  if (tx->IsCoinBase()) {
2076  continue;
2077  }
2078 
2079  // Don't count coinbase's fake input
2080  inputs += tx->vin.size();
2081  // Don't count coinbase reward
2082  total_out += tx_total_out;
2083 
2084  int64_t tx_size = 0;
2085  if (do_calculate_size) {
2086  tx_size = tx->GetTotalSize();
2087  if (do_mediantxsize) {
2088  txsize_array.push_back(tx_size);
2089  }
2090  maxtxsize = std::max(maxtxsize, tx_size);
2091  mintxsize = std::min(mintxsize, tx_size);
2092  total_size += tx_size;
2093  }
2094 
2095  if (loop_inputs) {
2096  Amount tx_total_in = Amount::zero();
2097  const auto &txundo = blockUndo.vtxundo.at(i - 1);
2098  for (const Coin &coin : txundo.vprevout) {
2099  const CTxOut &prevoutput = coin.GetTxOut();
2100 
2101  tx_total_in += prevoutput.nValue;
2102  utxo_size_inc -=
2103  GetSerializeSize(prevoutput, PROTOCOL_VERSION) +
2105  }
2106 
2107  Amount txfee = tx_total_in - tx_total_out;
2108  CHECK_NONFATAL(MoneyRange(txfee));
2109  if (do_medianfee) {
2110  fee_array.push_back(txfee);
2111  }
2112  maxfee = std::max(maxfee, txfee);
2113  minfee = std::min(minfee, txfee);
2114  totalfee += txfee;
2115 
2116  Amount feerate = txfee / tx_size;
2117  if (do_medianfeerate) {
2118  feerate_array.push_back(feerate);
2119  }
2120  maxfeerate = std::max(maxfeerate, feerate);
2121  minfeerate = std::min(minfeerate, feerate);
2122  }
2123  }
2124 
2125  UniValue ret_all(UniValue::VOBJ);
2126  ret_all.pushKV("avgfee",
2127  block.vtx.size() > 1
2128  ? (totalfee / int((block.vtx.size() - 1)))
2129  : Amount::zero());
2130  ret_all.pushKV("avgfeerate", total_size > 0
2131  ? (totalfee / total_size)
2132  : Amount::zero());
2133  ret_all.pushKV("avgtxsize",
2134  (block.vtx.size() > 1)
2135  ? total_size / (block.vtx.size() - 1)
2136  : 0);
2137  ret_all.pushKV("blockhash", pindex.GetBlockHash().GetHex());
2138  ret_all.pushKV("height", (int64_t)pindex.nHeight);
2139  ret_all.pushKV("ins", inputs);
2140  ret_all.pushKV("maxfee", maxfee);
2141  ret_all.pushKV("maxfeerate", maxfeerate);
2142  ret_all.pushKV("maxtxsize", maxtxsize);
2143  ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
2144  ret_all.pushKV("medianfeerate",
2145  CalculateTruncatedMedian(feerate_array));
2146  ret_all.pushKV("mediantime", pindex.GetMedianTimePast());
2147  ret_all.pushKV("mediantxsize",
2148  CalculateTruncatedMedian(txsize_array));
2149  ret_all.pushKV("minfee",
2150  minfee == MAX_MONEY ? Amount::zero() : minfee);
2151  ret_all.pushKV("minfeerate", minfeerate == MAX_MONEY
2152  ? Amount::zero()
2153  : minfeerate);
2154  ret_all.pushKV("mintxsize",
2155  mintxsize == blockMaxSize ? 0 : mintxsize);
2156  ret_all.pushKV("outs", outputs);
2157  ret_all.pushKV("subsidy", GetBlockSubsidy(pindex.nHeight,
2158  chainman.GetConsensus()));
2159  ret_all.pushKV("time", pindex.GetBlockTime());
2160  ret_all.pushKV("total_out", total_out);
2161  ret_all.pushKV("total_size", total_size);
2162  ret_all.pushKV("totalfee", totalfee);
2163  ret_all.pushKV("txs", (int64_t)block.vtx.size());
2164  ret_all.pushKV("utxo_increase", outputs - inputs);
2165  ret_all.pushKV("utxo_size_inc", utxo_size_inc);
2166 
2167  if (do_all) {
2168  return ret_all;
2169  }
2170 
2171  UniValue ret(UniValue::VOBJ);
2172  for (const std::string &stat : stats) {
2173  const UniValue &value = ret_all[stat];
2174  if (value.isNull()) {
2175  throw JSONRPCError(
2177  strprintf("Invalid selected statistic %s", stat));
2178  }
2179  ret.pushKV(stat, value);
2180  }
2181  return ret;
2182  },
2183  };
2184 }
2185 
2186 namespace {
2188 static bool FindScriptPubKey(std::atomic<int> &scan_progress,
2189  const std::atomic<bool> &should_abort,
2190  int64_t &count, CCoinsViewCursor *cursor,
2191  const std::set<CScript> &needles,
2192  std::map<COutPoint, Coin> &out_results,
2193  std::function<void()> &interruption_point) {
2194  scan_progress = 0;
2195  count = 0;
2196  while (cursor->Valid()) {
2197  COutPoint key;
2198  Coin coin;
2199  if (!cursor->GetKey(key) || !cursor->GetValue(coin)) {
2200  return false;
2201  }
2202  if (++count % 8192 == 0) {
2203  interruption_point();
2204  if (should_abort) {
2205  // allow to abort the scan via the abort reference
2206  return false;
2207  }
2208  }
2209  if (count % 256 == 0) {
2210  // update progress reference every 256 item
2211  const TxId &txid = key.GetTxId();
2212  uint32_t high = 0x100 * *txid.begin() + *(txid.begin() + 1);
2213  scan_progress = int(high * 100.0 / 65536.0 + 0.5);
2214  }
2215  if (needles.count(coin.GetTxOut().scriptPubKey)) {
2216  out_results.emplace(key, coin);
2217  }
2218  cursor->Next();
2219  }
2220  scan_progress = 100;
2221  return true;
2222 }
2223 } // namespace
2224 
2226 static std::atomic<int> g_scan_progress;
2227 static std::atomic<bool> g_scan_in_progress;
2228 static std::atomic<bool> g_should_abort_scan;
2230 private:
2232 
2233 public:
2235 
2236  bool reserve() {
2238  if (g_scan_in_progress.exchange(true)) {
2239  return false;
2240  }
2241  m_could_reserve = true;
2242  return true;
2243  }
2244 
2246  if (m_could_reserve) {
2247  g_scan_in_progress = false;
2248  }
2249  }
2250 };
2251 
2253  const auto &ticker = Currency::get().ticker;
2254  return RPCHelpMan{
2255  "scantxoutset",
2256  "Scans the unspent transaction output set for entries that match "
2257  "certain output descriptors.\n"
2258  "Examples of output descriptors are:\n"
2259  " addr(<address>) Outputs whose scriptPubKey "
2260  "corresponds to the specified address (does not include P2PK)\n"
2261  " raw(<hex script>) Outputs whose scriptPubKey "
2262  "equals the specified hex scripts\n"
2263  " combo(<pubkey>) P2PK and P2PKH outputs for "
2264  "the given pubkey\n"
2265  " pkh(<pubkey>) P2PKH outputs for the given "
2266  "pubkey\n"
2267  " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for "
2268  "the given threshold and pubkeys\n"
2269  "\nIn the above, <pubkey> either refers to a fixed public key in "
2270  "hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
2271  "or more path elements separated by \"/\", and optionally ending in "
2272  "\"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
2273  "unhardened or hardened child keys.\n"
2274  "In the latter case, a range needs to be specified by below if "
2275  "different from 1000.\n"
2276  "For more information on output descriptors, see the documentation in "
2277  "the doc/descriptors.md file.\n",
2278  {
2280  "The action to execute\n"
2281  " \"start\" for starting a "
2282  "scan\n"
2283  " \"abort\" for aborting the "
2284  "current scan (returns true when abort was successful)\n"
2285  " \"status\" for "
2286  "progress report (in %) of the current scan"},
2287  {"scanobjects",
2290  "Array of scan objects. Required for \"start\" action\n"
2291  " Every scan object is either a "
2292  "string descriptor or an object:",
2293  {
2295  "An output descriptor"},
2296  {
2297  "",
2300  "An object with output descriptor and metadata",
2301  {
2303  "An output descriptor"},
2304  {"range", RPCArg::Type::RANGE, RPCArg::Default{1000},
2305  "The range of HD chain indexes to explore (either "
2306  "end or [begin,end])"},
2307  },
2308  },
2309  },
2310  "[scanobjects,...]"},
2311  },
2312  {
2313  RPCResult{"When action=='abort'", RPCResult::Type::BOOL, "", ""},
2314  RPCResult{"When action=='status' and no scan is in progress",
2315  RPCResult::Type::NONE, "", ""},
2316  RPCResult{
2317  "When action=='status' and scan is in progress",
2319  "",
2320  "",
2321  {
2322  {RPCResult::Type::NUM, "progress", "The scan progress"},
2323  }},
2324  RPCResult{
2325  "When action=='start'",
2327  "",
2328  "",
2329  {
2330  {RPCResult::Type::BOOL, "success",
2331  "Whether the scan was completed"},
2332  {RPCResult::Type::NUM, "txouts",
2333  "The number of unspent transaction outputs scanned"},
2334  {RPCResult::Type::NUM, "height",
2335  "The current block height (index)"},
2336  {RPCResult::Type::STR_HEX, "bestblock",
2337  "The hash of the block at the tip of the chain"},
2339  "unspents",
2340  "",
2341  {
2343  "",
2344  "",
2345  {
2346  {RPCResult::Type::STR_HEX, "txid",
2347  "The transaction id"},
2348  {RPCResult::Type::NUM, "vout", "The vout value"},
2349  {RPCResult::Type::STR_HEX, "scriptPubKey",
2350  "The script key"},
2351  {RPCResult::Type::STR, "desc",
2352  "A specialized descriptor for the matched "
2353  "scriptPubKey"},
2354  {RPCResult::Type::STR_AMOUNT, "amount",
2355  "The total amount in " + ticker +
2356  " of the unspent output"},
2357  {RPCResult::Type::NUM, "height",
2358  "Height of the unspent transaction output"},
2359  }},
2360  }},
2361  {RPCResult::Type::STR_AMOUNT, "total_amount",
2362  "The total amount of all found unspent outputs in " +
2363  ticker},
2364  }},
2365  },
2366  RPCExamples{""},
2367  [&](const RPCHelpMan &self, const Config &config,
2368  const JSONRPCRequest &request) -> UniValue {
2369  RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR});
2370 
2371  UniValue result(UniValue::VOBJ);
2372  if (request.params[0].get_str() == "status") {
2373  CoinsViewScanReserver reserver;
2374  if (reserver.reserve()) {
2375  // no scan in progress
2376  return NullUniValue;
2377  }
2378  result.pushKV("progress", g_scan_progress.load());
2379  return result;
2380  } else if (request.params[0].get_str() == "abort") {
2381  CoinsViewScanReserver reserver;
2382  if (reserver.reserve()) {
2383  // reserve was possible which means no scan was running
2384  return false;
2385  }
2386  // set the abort flag
2387  g_should_abort_scan = true;
2388  return true;
2389  } else if (request.params[0].get_str() == "start") {
2390  CoinsViewScanReserver reserver;
2391  if (!reserver.reserve()) {
2393  "Scan already in progress, use action "
2394  "\"abort\" or \"status\"");
2395  }
2396 
2397  if (request.params.size() < 2) {
2399  "scanobjects argument is required for "
2400  "the start action");
2401  }
2402 
2403  std::set<CScript> needles;
2404  std::map<CScript, std::string> descriptors;
2405  Amount total_in = Amount::zero();
2406 
2407  // loop through the scan objects
2408  for (const UniValue &scanobject :
2409  request.params[1].get_array().getValues()) {
2410  FlatSigningProvider provider;
2411  auto scripts =
2412  EvalDescriptorStringOrObject(scanobject, provider);
2413  for (const auto &script : scripts) {
2414  std::string inferred =
2415  InferDescriptor(script, provider)->ToString();
2416  needles.emplace(script);
2417  descriptors.emplace(std::move(script),
2418  std::move(inferred));
2419  }
2420  }
2421 
2422  // Scan the unspent transaction output set for inputs
2423  UniValue unspents(UniValue::VARR);
2424  std::vector<CTxOut> input_txos;
2425  std::map<COutPoint, Coin> coins;
2426  g_should_abort_scan = false;
2427  g_scan_progress = 0;
2428  int64_t count = 0;
2429  std::unique_ptr<CCoinsViewCursor> pcursor;
2430  const CBlockIndex *tip;
2431  NodeContext &node = EnsureAnyNodeContext(request.context);
2432  {
2433  ChainstateManager &chainman = EnsureChainman(node);
2434  LOCK(cs_main);
2435  Chainstate &active_chainstate = chainman.ActiveChainstate();
2436  active_chainstate.ForceFlushStateToDisk();
2437  pcursor = CHECK_NONFATAL(std::unique_ptr<CCoinsViewCursor>(
2438  active_chainstate.CoinsDB().Cursor()));
2439  tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
2440  }
2441  bool res = FindScriptPubKey(
2442  g_scan_progress, g_should_abort_scan, count, pcursor.get(),
2443  needles, coins, node.rpc_interruption_point);
2444  result.pushKV("success", res);
2445  result.pushKV("txouts", count);
2446  result.pushKV("height", tip->nHeight);
2447  result.pushKV("bestblock", tip->GetBlockHash().GetHex());
2448 
2449  for (const auto &it : coins) {
2450  const COutPoint &outpoint = it.first;
2451  const Coin &coin = it.second;
2452  const CTxOut &txo = coin.GetTxOut();
2453  input_txos.push_back(txo);
2454  total_in += txo.nValue;
2455 
2456  UniValue unspent(UniValue::VOBJ);
2457  unspent.pushKV("txid", outpoint.GetTxId().GetHex());
2458  unspent.pushKV("vout", int32_t(outpoint.GetN()));
2459  unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
2460  unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
2461  unspent.pushKV("amount", txo.nValue);
2462  unspent.pushKV("height", int32_t(coin.GetHeight()));
2463 
2464  unspents.push_back(unspent);
2465  }
2466  result.pushKV("unspents", unspents);
2467  result.pushKV("total_amount", total_in);
2468  } else {
2469  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid command");
2470  }
2471  return result;
2472  },
2473  };
2474 }
2475 
2477  return RPCHelpMan{
2478  "getblockfilter",
2479  "Retrieve a BIP 157 content filter for a particular block.\n",
2480  {
2482  "The hash of the block"},
2483  {"filtertype", RPCArg::Type::STR, RPCArg::Default{"basic"},
2484  "The type name of the filter"},
2485  },
2487  "",
2488  "",
2489  {
2490  {RPCResult::Type::STR_HEX, "filter",
2491  "the hex-encoded filter data"},
2492  {RPCResult::Type::STR_HEX, "header",
2493  "the hex-encoded filter header"},
2494  }},
2495  RPCExamples{
2496  HelpExampleCli("getblockfilter",
2497  "\"00000000c937983704a73af28acdec37b049d214a"
2498  "dbda81d7e2a3dd146f6ed09\" \"basic\"") +
2499  HelpExampleRpc("getblockfilter",
2500  "\"00000000c937983704a73af28acdec37b049d214adbda81d7"
2501  "e2a3dd146f6ed09\", \"basic\"")},
2502  [&](const RPCHelpMan &self, const Config &config,
2503  const JSONRPCRequest &request) -> UniValue {
2504  const BlockHash block_hash(
2505  ParseHashV(request.params[0], "blockhash"));
2506  std::string filtertype_name = "basic";
2507  if (!request.params[1].isNull()) {
2508  filtertype_name = request.params[1].get_str();
2509  }
2510 
2511  BlockFilterType filtertype;
2512  if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2514  "Unknown filtertype");
2515  }
2516 
2517  BlockFilterIndex *index = GetBlockFilterIndex(filtertype);
2518  if (!index) {
2520  "Index is not enabled for filtertype " +
2521  filtertype_name);
2522  }
2523 
2524  const CBlockIndex *block_index;
2525  bool block_was_connected;
2526  {
2527  ChainstateManager &chainman =
2528  EnsureAnyChainman(request.context);
2529  LOCK(cs_main);
2530  block_index = chainman.m_blockman.LookupBlockIndex(block_hash);
2531  if (!block_index) {
2533  "Block not found");
2534  }
2535  block_was_connected =
2536  block_index->IsValid(BlockValidity::SCRIPTS);
2537  }
2538 
2539  bool index_ready = index->BlockUntilSyncedToCurrentChain();
2540 
2541  BlockFilter filter;
2542  uint256 filter_header;
2543  if (!index->LookupFilter(block_index, filter) ||
2544  !index->LookupFilterHeader(block_index, filter_header)) {
2545  int err_code;
2546  std::string errmsg = "Filter not found.";
2547 
2548  if (!block_was_connected) {
2549  err_code = RPC_INVALID_ADDRESS_OR_KEY;
2550  errmsg += " Block was not connected to active chain.";
2551  } else if (!index_ready) {
2552  err_code = RPC_MISC_ERROR;
2553  errmsg += " Block filters are still in the process of "
2554  "being indexed.";
2555  } else {
2556  err_code = RPC_INTERNAL_ERROR;
2557  errmsg += " This error is unexpected and indicates index "
2558  "corruption.";
2559  }
2560 
2561  throw JSONRPCError(err_code, errmsg);
2562  }
2563 
2564  UniValue ret(UniValue::VOBJ);
2565  ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
2566  ret.pushKV("header", filter_header.GetHex());
2567  return ret;
2568  },
2569  };
2570 }
2571 
2578  return RPCHelpMan{
2579  "dumptxoutset",
2580  "Write the serialized UTXO set to disk.\n",
2581  {
2583  "path to the output file. If relative, will be prefixed by "
2584  "datadir."},
2585  },
2587  "",
2588  "",
2589  {
2590  {RPCResult::Type::NUM, "coins_written",
2591  "the number of coins written in the snapshot"},
2592  {RPCResult::Type::STR_HEX, "base_hash",
2593  "the hash of the base of the snapshot"},
2594  {RPCResult::Type::NUM, "base_height",
2595  "the height of the base of the snapshot"},
2596  {RPCResult::Type::STR, "path",
2597  "the absolute path that the snapshot was written to"},
2598  {RPCResult::Type::STR_HEX, "txoutset_hash",
2599  "the hash of the UTXO set contents"},
2600  {RPCResult::Type::NUM, "nchaintx",
2601  "the number of transactions in the chain up to and "
2602  "including the base block"},
2603  }},
2604  RPCExamples{HelpExampleCli("dumptxoutset", "utxo.dat")},
2605  [&](const RPCHelpMan &self, const Config &config,
2606  const JSONRPCRequest &request) -> UniValue {
2607  const ArgsManager &args{EnsureAnyArgsman(request.context)};
2608  const fs::path path = fsbridge::AbsPathJoin(
2609  args.GetDataDirNet(), fs::u8path(request.params[0].get_str()));
2610  // Write to a temporary path and then move into `path` on completion
2611  // to avoid confusion due to an interruption.
2612  const fs::path temppath = fsbridge::AbsPathJoin(
2613  args.GetDataDirNet(),
2614  fs::u8path(request.params[0].get_str() + ".incomplete"));
2615 
2616  if (fs::exists(path)) {
2618  path.u8string() +
2619  " already exists. If you are sure this "
2620  "is what you want, "
2621  "move it out of the way first");
2622  }
2623 
2624  FILE *file{fsbridge::fopen(temppath, "wb")};
2625  AutoFile afile{file};
2626  NodeContext &node = EnsureAnyNodeContext(request.context);
2627  UniValue result = CreateUTXOSnapshot(
2628  node, node.chainman->ActiveChainstate(), afile, path, temppath);
2629  fs::rename(temppath, path);
2630 
2631  return result;
2632  },
2633  };
2634 }
2635 
2637  AutoFile &afile, const fs::path &path,
2638  const fs::path &temppath) {
2639  std::unique_ptr<CCoinsViewCursor> pcursor;
2640  std::optional<CCoinsStats> maybe_stats;
2641  const CBlockIndex *tip;
2642 
2643  {
2644  // We need to lock cs_main to ensure that the coinsdb isn't
2645  // written to between (i) flushing coins cache to disk
2646  // (coinsdb), (ii) getting stats based upon the coinsdb, and
2647  // (iii) constructing a cursor to the coinsdb for use below this
2648  // block.
2649  //
2650  // Cursors returned by leveldb iterate over snapshots, so the
2651  // contents of the pcursor will not be affected by simultaneous
2652  // writes during use below this block.
2653  //
2654  // See discussion here:
2655  // https://github.com/bitcoin/bitcoin/pull/15606#discussion_r274479369
2656  //
2657  LOCK(::cs_main);
2658 
2659  chainstate.ForceFlushStateToDisk();
2660 
2661  maybe_stats = GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman,
2662  CoinStatsHashType::HASH_SERIALIZED,
2663  node.rpc_interruption_point);
2664  if (!maybe_stats) {
2665  throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
2666  }
2667 
2668  pcursor =
2669  std::unique_ptr<CCoinsViewCursor>(chainstate.CoinsDB().Cursor());
2670  tip = CHECK_NONFATAL(
2671  chainstate.m_blockman.LookupBlockIndex(maybe_stats->hashBlock));
2672  }
2673 
2675  strprintf("writing UTXO snapshot at height %s (%s) to file %s (via %s)",
2676  tip->nHeight, tip->GetBlockHash().ToString(),
2677  fs::PathToString(path), fs::PathToString(temppath)));
2678 
2679  SnapshotMetadata metadata{tip->GetBlockHash(), maybe_stats->coins_count,
2680  uint64_t(tip->GetChainTxCount())};
2681 
2682  afile << metadata;
2683 
2684  COutPoint key;
2685  Coin coin;
2686  unsigned int iter{0};
2687 
2688  while (pcursor->Valid()) {
2689  if (iter % 5000 == 0) {
2690  node.rpc_interruption_point();
2691  }
2692  ++iter;
2693  if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
2694  afile << key;
2695  afile << coin;
2696  }
2697 
2698  pcursor->Next();
2699  }
2700 
2701  afile.fclose();
2702 
2703  UniValue result(UniValue::VOBJ);
2704  result.pushKV("coins_written", maybe_stats->coins_count);
2705  result.pushKV("base_hash", tip->GetBlockHash().ToString());
2706  result.pushKV("base_height", tip->nHeight);
2707  result.pushKV("path", path.u8string());
2708  result.pushKV("txoutset_hash", maybe_stats->hashSerialized.ToString());
2709  // Cast required because univalue doesn't have serialization specified for
2710  // `unsigned int`, nChainTx's type.
2711  result.pushKV("nchaintx", uint64_t{tip->nChainTx});
2712  return result;
2713 }
2714 
2716  // clang-format off
2717  static const CRPCCommand commands[] = {
2718  // category actor (function)
2719  // ------------------ ----------------------
2720  { "blockchain", getbestblockhash, },
2721  { "blockchain", getblock, },
2722  { "blockchain", getblockfrompeer, },
2723  { "blockchain", getblockchaininfo, },
2724  { "blockchain", getblockcount, },
2725  { "blockchain", getblockhash, },
2726  { "blockchain", getblockheader, },
2727  { "blockchain", getblockstats, },
2728  { "blockchain", getchaintips, },
2729  { "blockchain", getchaintxstats, },
2730  { "blockchain", getdifficulty, },
2731  { "blockchain", gettxout, },
2732  { "blockchain", gettxoutsetinfo, },
2733  { "blockchain", pruneblockchain, },
2734  { "blockchain", verifychain, },
2735  { "blockchain", preciousblock, },
2736  { "blockchain", scantxoutset, },
2737  { "blockchain", getblockfilter, },
2738 
2739  /* Not shown in help */
2740  { "hidden", invalidateblock, },
2741  { "hidden", parkblock, },
2742  { "hidden", reconsiderblock, },
2743  { "hidden", syncwithvalidationinterfacequeue, },
2744  { "hidden", dumptxoutset, },
2745  { "hidden", unparkblock, },
2746  { "hidden", waitfornewblock, },
2747  { "hidden", waitforblock, },
2748  { "hidden", waitforblockheight, },
2749  };
2750  // clang-format on
2751  for (const auto &c : commands) {
2752  t.appendCommand(c.name, &c);
2753  }
2754 }
bool MoneyRange(const Amount nValue)
Definition: amount.h:166
static constexpr Amount MAX_MONEY
No amount larger than this (in satoshi) is valid.
Definition: amount.h:165
RPCHelpMan gettxout()
static RPCHelpMan getblock()
Definition: blockchain.cpp:677
static int ComputeNextBlockAndDepth(const CBlockIndex *tip, const CBlockIndex *blockindex, const CBlockIndex *&next)
Definition: blockchain.cpp:88
static RPCHelpMan getdifficulty()
Definition: blockchain.cpp:439
static std::atomic< bool > g_scan_in_progress
static bool SetHasKeys(const std::set< T > &set)
static RPCHelpMan reconsiderblock()
static T CalculateTruncatedMedian(std::vector< T > &scores)
static RPCHelpMan invalidateblock()
static RPCHelpMan syncwithvalidationinterfacequeue()
Definition: blockchain.cpp:422
static RPCHelpMan getchaintips()
static RPCHelpMan gettxoutsetinfo()
Definition: blockchain.cpp: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:658
static RPCHelpMan getblockfilter()
static RPCHelpMan getbestblockhash()
Definition: blockchain.cpp:216
static CBlock GetBlockChecked(BlockManager &blockman, const CBlockIndex *pblockindex)
Definition: blockchain.cpp:636
RPCHelpMan getblockchaininfo()
UniValue blockToJSON(BlockManager &blockman, const CBlock &block, const CBlockIndex *tip, const CBlockIndex *blockindex, bool txDetails)
Block description to JSON.
Definition: blockchain.cpp:165
static RPCHelpMan getchaintxstats()
static RPCHelpMan waitforblock()
Definition: blockchain.cpp:300
static RPCHelpMan getblockfrompeer()
Definition: blockchain.cpp:459
static const CBlockIndex * ParseHashOrHeight(const UniValue &param, ChainstateManager &chainman)
Definition: blockchain.cpp:99
static RPCHelpMan getblockhash()
Definition: blockchain.cpp:511
void RegisterBlockchainRPCCommands(CRPCTable &t)
static RPCHelpMan verifychain()
static std::atomic< bool > g_should_abort_scan
RPCHelpMan unparkblock()
UniValue blockheaderToJSON(const CBlockIndex *tip, const CBlockIndex *blockindex)
Block header to JSON.
Definition: blockchain.cpp:131
static RPCHelpMan waitforblockheight()
Definition: blockchain.cpp:362
static RPCHelpMan pruneblockchain()
Definition: blockchain.cpp:815
static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange)
static RPCHelpMan getblockheader()
Definition: blockchain.cpp:540
RPCHelpMan parkblock()
UniValue CreateUTXOSnapshot(NodeContext &node, Chainstate &chainstate, AutoFile &afile, const fs::path &path, const fs::path &temppath)
Helper to create UTXO snapshots given a chainstate and a file handle.
static GlobalMutex cs_blockchange
Definition: blockchain.cpp:63
static RPCHelpMan dumptxoutset()
Serialize the UTXO set to a file for loading elsewhere.
static RPCHelpMan getblockcount()
Definition: blockchain.cpp:198
static RPCHelpMan waitfornewblock()
Definition: blockchain.cpp:243
void RPCNotifyBlockChange(const CBlockIndex *pindex)
Callback for when block tip changed.
Definition: blockchain.cpp:234
bool BlockFilterTypeByName(const std::string &name, BlockFilterType &filter_type)
Find a filter type by its human-readable name.
BlockFilterType
Definition: blockfilter.h:88
BlockFilterIndex * GetBlockFilterIndex(BlockFilterType filter_type)
Get a block filter index by type.
@ SCRIPTS
Scripts & signatures ok.
@ TREE
All parent headers found, difficulty matches, timestamp >= median previous, checkpoint.
const CBlockIndex * LastCommonAncestor(const CBlockIndex *pa, const CBlockIndex *pb)
Find the last common ancestor two blocks have.
Definition: chain.cpp:112
static constexpr int64_t TIMESTAMP_WINDOW
Timestamp window used as a grace period by code that compares external timestamps (such as timestamps...
Definition: chain.h:36
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:53
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:528
int fclose()
Definition: streams.h:541
Complete block filter struct as defined in BIP 157.
Definition: blockfilter.h:111
const std::vector< uint8_t > & GetEncodedFilter() const
Definition: blockfilter.h:134
BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of bloc...
bool LookupFilter(const CBlockIndex *block_index, BlockFilter &filter_out) const
Get a single filter by block.
bool LookupFilterHeader(const CBlockIndex *block_index, uint256 &header_out) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_headers_cache)
Get a single filter header by block.
Definition: block.h:60
std::vector< CTransactionRef > vtx
Definition: block.h:63
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: blockindex.h:25
bool IsValid(enum BlockValidity nUpTo=BlockValidity::TRANSACTIONS) const EXCLUSIVE_LOCKS_REQUIRED(
Check whether this block index entry is valid up to the passed validity level.
Definition: blockindex.h:211
uint256 hashMerkleRoot
Definition: blockindex.h:91
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: blockindex.h:32
CBlockHeader GetBlockHeader() const
Definition: blockindex.h:133
arith_uint256 nChainWork
(memory only) Total amount of work (expected number of hashes) in the chain up to and including this ...
Definition: blockindex.h:51
int64_t GetChainTxCount() const
Get the number of transaction in the chain so far.
Definition: blockindex.h:154
uint32_t nTime
Definition: blockindex.h:92
uint32_t nNonce
Definition: blockindex.h:94
int64_t GetBlockTime() const
Definition: blockindex.h:180
int64_t GetMedianTimePast() const
Definition: blockindex.h:192
uint32_t nBits
Definition: blockindex.h:93
unsigned int nTx
Number of transactions in this block.
Definition: blockindex.h:60
int32_t nVersion
block header
Definition: blockindex.h:90
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition: blockindex.cpp:78
BlockHash GetBlockHash() const
Definition: blockindex.h:146
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: blockindex.h:38
unsigned int nChainTx
(memory only) Number of transactions in the chain up to and including this block.
Definition: blockindex.h:77
Undo information for a CBlock.
Definition: undo.h:73
std::vector< CTxUndo > vtxundo
Definition: undo.h:76
An in-memory indexed chain of blocks.
Definition: chain.h:134
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:150
CBlockIndex * FindEarliestAtLeast(int64_t nTime, int height) const
Find the earliest block with timestamp equal or greater than the given time and height equal or great...
Definition: chain.cpp:62
int Height() const
Return the maximal height in the chain.
Definition: chain.h:186
const CBlockIndex * FindFork(const CBlockIndex *pindex) const
Find the last common block between this chain and a block index entry.
Definition: chain.cpp:49
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
Definition: chain.h:166
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
Definition: chainparams.h:80
std::string NetworkIDString() const
Return the BIP70 network string (main, test or regtest)
Definition: chainparams.h:127
const ChainTxData & TxData() const
Definition: chainparams.h:140
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:221
BlockHash GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:214
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: coins.cpp:95
Cursor for iterating over CoinsView state.
Definition: coins.h:143
virtual void Next()=0
virtual bool Valid() const =0
virtual bool GetKey(COutPoint &key) const =0
virtual bool GetValue(Coin &coin) const =0
CCoinsViewCursor * Cursor() const override
Get a cursor to iterate over the whole state.
Definition: txdb.cpp:208
Abstract view on the open txout dataset.
Definition: coins.h:163
virtual BlockHash GetBestBlock() const
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:16
CCoinsView that brings transactions from a mempool into view.
Definition: txmempool.h:591
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: txmempool.cpp:607
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:177
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:20
uint32_t GetN() const
Definition: transaction.h:36
const TxId & GetTxId() const
Definition: transaction.h:35
RPC command dispatcher.
Definition: server.h:184
void appendCommand(const std::string &name, const CRPCCommand *pcmd)
Appends a CRPCCommand to the dispatch table.
Definition: server.cpp:332
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:209
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:296
bool isSpent(const COutPoint &outpoint) const
Definition: txmempool.cpp:130
An output of a transaction.
Definition: transaction.h:128
CScript scriptPubKey
Definition: transaction.h:131
Amount nValue
Definition: transaction.h:130
Restore the UTXO in a Coin at a given COutPoint.
Definition: undo.h:62
RAII wrapper for VerifyDB: Verify consistency of the block and coin databases.
Definition: validation.h:552
VerifyDBResult VerifyDB(Chainstate &chainstate, CCoinsView &coinsview, int nCheckLevel, int nCheckDepth) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Definition: validation.h:631
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:740
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:773
void ForceFlushStateToDisk()
Unconditionally flush all changes to disk.
void UnparkBlockAndChildren(CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Remove parked status from a block and its descendants.
bool ActivateBestChain(BlockValidationState &state, std::shared_ptr< const CBlock > pblock=nullptr, bool skip_checkblockindex=false) EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex
Find the best known block, and make it the tip of the block chain.
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:766
node::BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all Chainstate instances.
Definition: validation.h:704
void ClearAvalancheFinalizedBlock() EXCLUSIVE_LOCKS_REQUIRED(!cs_avalancheFinalizedBlockIndex)
Clear avalanche finalization.
bool ParkBlock(BlockValidationState &state, CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex
Park a block.
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:1146
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1356
const CChainParams & GetParams() const
Definition: validation.h:1240
node::BlockMap & BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:1366
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1359
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1362
kernel::Notifications & GetNotifications() const
Definition: validation.h:1255
const Consensus::Params & GetConsensus() const
Definition: validation.h:1243
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1278
A UTXO entry.
Definition: coins.h:28
uint32_t GetHeight() const
Definition: coins.h:45
bool IsCoinBase() const
Definition: coins.h:46
CTxOut & GetTxOut()
Definition: coins.h:49
Definition: config.h:19
Different type to mark Mutex at global scope.
Definition: sync.h:144
virtual std::optional< std::string > FetchBlock(const Config &config, NodeId peer_id, const CBlockIndex &block_index)=0
Attempt to manually fetch block from a given peer.
const std::string & get_str() const
@ VOBJ
Definition: univalue.h:27
@ VARR
Definition: univalue.h:27
bool isNull() const
Definition: univalue.h:89
size_t size() const
Definition: univalue.h:80
const std::vector< UniValue > & getValues() const
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
const UniValue & get_array() const
bool pushKV(const std::string &key, const UniValue &val)
Definition: univalue.cpp:133
bool isNum() const
Definition: univalue.h:94
int get_int() const
bool IsValid() const
Definition: validation.h:112
std::string GetRejectReason() const
Definition: validation.h:116
std::string ToString() const
Definition: validation.h:118
uint8_t * begin()
Definition: uint256.h:85
std::string ToString() const
Definition: uint256.h:80
std::string GetHex() const
Definition: uint256.cpp:16
std::string GetHex() const
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
std::string u8string() const
Definition: fs.h:72
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
Definition: blockstorage.h:71
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos) const
Functions for disk access for blocks.
CBlockIndex * LookupBlockIndex(const BlockHash &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
bool UndoReadFromDisk(CBlockUndo &blockundo, const CBlockIndex &index) const
uint64_t GetPruneTarget() const
Attempt to stay below this number of bytes of block files.
Definition: blockstorage.h:235
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:232
Metadata describing a serialized version of a UTXO set from which an assumeutxo Chainstate can be con...
Definition: utxo_snapshot.h:21
256-bit opaque blob.
Definition: uint256.h:129
std::unique_ptr< CoinStatsIndex > g_coin_stats_index
The global UTXO set hash object.
void TxToUniv(const CTransaction &tx, const BlockHash &hashBlock, UniValue &entry, bool include_hex=true, int serialize_flags=0, const CTxUndo *txundo=nullptr)
Definition: core_write.cpp:217
void ScriptPubKeyToUniv(const CScript &scriptPubKey, UniValue &out, bool fIncludeHex)
Definition: core_write.cpp:190
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:7
std::unique_ptr< Descriptor > InferDescriptor(const CScript &script, const SigningProvider &provider)
Find a descriptor for the specified script, using information from provider where possible.
#define LogPrint(category,...)
Definition: logging.h:210
unsigned int nHeight
@ RPC
Definition: logging.h:47
@ NONE
Definition: logging.h:39
static path u8path(const std::string &utf8_str)
Definition: fs.h:90
static bool exists(const path &p)
Definition: fs.h:102
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition: fs.h:142
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:30
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:39
CoinStatsHashType
Definition: coinstats.h:23
Definition: init.h:28
std::optional< kernel::CCoinsStats > GetUTXOStats(CCoinsView *view, BlockManager &blockman, kernel::CoinStatsHashType hash_type, const std::function< void()> &interruption_point, const CBlockIndex *pindex, bool index_requested)
Calculate statistics about the unspent transaction output set.
Definition: coinstats.cpp:16
int64_t NodeId
Definition: nodeid.h:10
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:315
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:58
@ RPC_MISC_ERROR
General application defined errors std::exception thrown in command handling.
Definition: protocol.h:38
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:46
@ RPC_INTERNAL_ERROR
Definition: protocol.h:33
@ RPC_DATABASE_ERROR
Database error.
Definition: protocol.h:48
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:42
void RPCTypeCheck(const UniValue &params, const std::list< UniValueType > &typesExpected, bool fAllowNull)
Type-check arguments; throws JSONRPCError if wrong type given.
Definition: util.cpp:25
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:176
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:1061
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:193
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:21
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded values (throws error if not hex).
Definition: util.cpp:99
@ SER_NETWORK
Definition: serialize.h:152
size_t GetSerializeSize(const T &t, int nVersion=0)
Definition: serialize.h:1258
bool IsRPCRunning()
Query whether RPC is running.
Definition: server.cpp:383
int RPCSerializationFlags()
Retrieves any serialization flags requested in command line argument.
Definition: server.cpp:608
ArgsManager & EnsureAnyArgsman(const std::any &context)
Definition: server_util.cpp:47
ChainstateManager & EnsureAnyChainman(const std::any &context)
Definition: server_util.cpp:58
NodeContext & EnsureAnyNodeContext(const std::any &context)
Definition: server_util.cpp:20
PeerManager & EnsurePeerman(const NodeContext &node)
Definition: server_util.cpp:71
CTxMemPool & EnsureMemPool(const NodeContext &node)
Definition: server_util.cpp:28
ChainstateManager & EnsureChainman(const NodeContext &node)
Definition: server_util.cpp:51
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
uint64_t nDiskSize
Definition: coinstats.h:36
Amount total_unspendables_scripts
Total cumulative amount of outputs sent to unspendable scripts (OP_RETURN for example) up to and incl...
Definition: coinstats.h:67
Amount total_coinbase_amount
Total cumulative amount of coinbase outputs up to and including this block.
Definition: coinstats.h:60
Amount total_unspendables_genesis_block
The unspendable coinbase amount from the genesis block.
Definition: coinstats.h:62
uint64_t nTransactions
Definition: coinstats.h:32
uint64_t nTransactionOutputs
Definition: coinstats.h:33
uint64_t nBogoSize
Definition: coinstats.h:34
bool index_used
Signals if the coinstatsindex was used to retrieve the statistics.
Definition: coinstats.h:43
Amount total_unspendables_bip30
The two unspendable coinbase outputs total amount caused by BIP30.
Definition: coinstats.h:64
Amount total_prevout_spent_amount
Total cumulative amount of prevouts spent up to and including this block.
Definition: coinstats.h:54
BlockHash hashBlock
Definition: coinstats.h:31
Amount total_unspendables_unclaimed_rewards
Total cumulative amount of coins lost due to unclaimed miner rewards up to and including this block.
Definition: coinstats.h:70
uint256 hashSerialized
Definition: coinstats.h:35
Amount total_new_outputs_ex_coinbase_amount
Total cumulative amount of outputs created up to and including this block.
Definition: coinstats.h:57
Amount total_unspendable_amount
Total cumulative amount of unspendable coins up to and including this block.
Definition: coinstats.h:52
NodeContext struct containing references to chain state and connection state.
Definition: context.h:40
#define WAIT_LOCK(cs, name)
Definition: sync.h:317
#define AssertLockNotHeld(cs)
Definition: sync.h:163
#define LOCK(cs)
Definition: sync.h:306
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:357
static int count
Definition: tests.c:31
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:56
#define LOG_TIME_SECONDS(end_msg)
Definition: timer.h:103
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1202
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:68
static const uint32_t MEMPOOL_HEIGHT
Fake height value used in Coins to signify they are only in the memory pool(since 0....
Definition: txmempool.h:45
uint256 uint256S(const char *str)
uint256 from const char *.
Definition: uint256.h:143
const UniValue NullUniValue
Definition: univalue.cpp:13
Amount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams)
double GuessVerificationProgress(const ChainTxData &data, const CBlockIndex *pindex)
Guess how far we are in the verification process at the given block index require cs_main if pindex h...
const std::vector< std::string > CHECKLEVEL_DOC
Documentation for argument 'checklevel'.
Definition: validation.cpp:97
void PruneBlockFilesManual(Chainstate &active_chainstate, int nManualPruneHeight)
Prune block files up to a given height.
static constexpr int DEFAULT_CHECKLEVEL
Definition: validation.h:97
static const unsigned int MIN_BLOCKS_TO_KEEP
Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ActiveChain().Tip() will not be pr...
Definition: validation.h:95
static const signed int DEFAULT_CHECKBLOCKS
Definition: validation.h:96
void SyncWithValidationInterfaceQueue()
This is a synonym for the following, which asserts certain locks are not held: std::promise<void> pro...
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:11
bilingual_str GetWarnings(bool verbose)
Format a string that describes several potential problems detected by the core.
Definition: warnings.cpp:41