Bitcoin Core  27.99.0
P2P Digital Currency
blockchain.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2022 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 <clientversion.h>
12 #include <coins.h>
13 #include <common/args.h>
14 #include <consensus/amount.h>
15 #include <consensus/params.h>
16 #include <consensus/validation.h>
17 #include <core_io.h>
18 #include <deploymentinfo.h>
19 #include <deploymentstatus.h>
20 #include <flatfile.h>
21 #include <hash.h>
22 #include <index/blockfilterindex.h>
23 #include <index/coinstatsindex.h>
24 #include <kernel/coinstats.h>
25 #include <logging/timer.h>
26 #include <net.h>
27 #include <net_processing.h>
28 #include <node/blockstorage.h>
29 #include <node/context.h>
30 #include <node/transaction.h>
31 #include <node/utxo_snapshot.h>
32 #include <primitives/transaction.h>
33 #include <rpc/server.h>
34 #include <rpc/server_util.h>
35 #include <rpc/util.h>
36 #include <script/descriptor.h>
37 #include <streams.h>
38 #include <sync.h>
39 #include <txdb.h>
40 #include <txmempool.h>
41 #include <undo.h>
42 #include <univalue.h>
43 #include <util/check.h>
44 #include <util/fs.h>
45 #include <util/strencodings.h>
46 #include <util/translation.h>
47 #include <validation.h>
48 #include <validationinterface.h>
49 #include <versionbits.h>
50 #include <warnings.h>
51 
52 #include <stdint.h>
53 
54 #include <condition_variable>
55 #include <memory>
56 #include <mutex>
57 
60 
61 using node::BlockManager;
62 using node::NodeContext;
64 
66 {
68  int height;
69 };
70 
72 static std::condition_variable cond_blockchange;
74 
75 /* Calculate the difficulty for a given block index.
76  */
77 double GetDifficulty(const CBlockIndex& blockindex)
78 {
79  int nShift = (blockindex.nBits >> 24) & 0xff;
80  double dDiff =
81  (double)0x0000ffff / (double)(blockindex.nBits & 0x00ffffff);
82 
83  while (nShift < 29)
84  {
85  dDiff *= 256.0;
86  nShift++;
87  }
88  while (nShift > 29)
89  {
90  dDiff /= 256.0;
91  nShift--;
92  }
93 
94  return dDiff;
95 }
96 
97 static int ComputeNextBlockAndDepth(const CBlockIndex& tip, const CBlockIndex& blockindex, const CBlockIndex*& next)
98 {
99  next = tip.GetAncestor(blockindex.nHeight + 1);
100  if (next && next->pprev == &blockindex) {
101  return tip.nHeight - blockindex.nHeight + 1;
102  }
103  next = nullptr;
104  return &blockindex == &tip ? 1 : -1;
105 }
106 
107 static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateManager& chainman)
108 {
109  LOCK(::cs_main);
110  CChain& active_chain = chainman.ActiveChain();
111 
112  if (param.isNum()) {
113  const int height{param.getInt<int>()};
114  if (height < 0) {
115  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d is negative", height));
116  }
117  const int current_tip{active_chain.Height()};
118  if (height > current_tip) {
119  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d after current tip %d", height, current_tip));
120  }
121 
122  return active_chain[height];
123  } else {
124  const uint256 hash{ParseHashV(param, "hash_or_height")};
125  const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
126 
127  if (!pindex) {
128  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
129  }
130 
131  return pindex;
132  }
133 }
134 
135 UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex)
136 {
137  // Serialize passed information without accessing chain state of the active chain!
138  AssertLockNotHeld(cs_main); // For performance reasons
139 
140  UniValue result(UniValue::VOBJ);
141  result.pushKV("hash", blockindex.GetBlockHash().GetHex());
142  const CBlockIndex* pnext;
143  int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
144  result.pushKV("confirmations", confirmations);
145  result.pushKV("height", blockindex.nHeight);
146  result.pushKV("version", blockindex.nVersion);
147  result.pushKV("versionHex", strprintf("%08x", blockindex.nVersion));
148  result.pushKV("merkleroot", blockindex.hashMerkleRoot.GetHex());
149  result.pushKV("time", blockindex.nTime);
150  result.pushKV("mediantime", blockindex.GetMedianTimePast());
151  result.pushKV("nonce", blockindex.nNonce);
152  result.pushKV("bits", strprintf("%08x", blockindex.nBits));
153  result.pushKV("difficulty", GetDifficulty(blockindex));
154  result.pushKV("chainwork", blockindex.nChainWork.GetHex());
155  result.pushKV("nTx", blockindex.nTx);
156 
157  if (blockindex.pprev)
158  result.pushKV("previousblockhash", blockindex.pprev->GetBlockHash().GetHex());
159  if (pnext)
160  result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
161  return result;
162 }
163 
164 UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity)
165 {
166  UniValue result = blockheaderToJSON(tip, blockindex);
167 
168  result.pushKV("strippedsize", (int)::GetSerializeSize(TX_NO_WITNESS(block)));
169  result.pushKV("size", (int)::GetSerializeSize(TX_WITH_WITNESS(block)));
170  result.pushKV("weight", (int)::GetBlockWeight(block));
172 
173  switch (verbosity) {
175  for (const CTransactionRef& tx : block.vtx) {
176  txs.push_back(tx->GetHash().GetHex());
177  }
178  break;
179 
182  CBlockUndo blockUndo;
183  const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))};
184  const bool have_undo{is_not_pruned && blockman.UndoReadFromDisk(blockUndo, blockindex)};
185 
186  for (size_t i = 0; i < block.vtx.size(); ++i) {
187  const CTransactionRef& tx = block.vtx.at(i);
188  // coinbase transaction (i.e. i == 0) doesn't have undo data
189  const CTxUndo* txundo = (have_undo && i > 0) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
190  UniValue objTx(UniValue::VOBJ);
191  TxToUniv(*tx, /*block_hash=*/uint256(), /*entry=*/objTx, /*include_hex=*/true, txundo, verbosity);
192  txs.push_back(objTx);
193  }
194  break;
195  }
196 
197  result.pushKV("tx", txs);
198 
199  return result;
200 }
201 
203 {
204  return RPCHelpMan{"getblockcount",
205  "\nReturns the height of the most-work fully-validated chain.\n"
206  "The genesis block has height 0.\n",
207  {},
208  RPCResult{
209  RPCResult::Type::NUM, "", "The current block count"},
210  RPCExamples{
211  HelpExampleCli("getblockcount", "")
212  + HelpExampleRpc("getblockcount", "")
213  },
214  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
215 {
216  ChainstateManager& chainman = EnsureAnyChainman(request.context);
217  LOCK(cs_main);
218  return chainman.ActiveChain().Height();
219 },
220  };
221 }
222 
224 {
225  return RPCHelpMan{"getbestblockhash",
226  "\nReturns the hash of the best (tip) block in the most-work fully-validated chain.\n",
227  {},
228  RPCResult{
229  RPCResult::Type::STR_HEX, "", "the block hash, hex-encoded"},
230  RPCExamples{
231  HelpExampleCli("getbestblockhash", "")
232  + HelpExampleRpc("getbestblockhash", "")
233  },
234  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
235 {
236  ChainstateManager& chainman = EnsureAnyChainman(request.context);
237  LOCK(cs_main);
238  return chainman.ActiveChain().Tip()->GetBlockHash().GetHex();
239 },
240  };
241 }
242 
244 {
245  if(pindex) {
247  latestblock.hash = pindex->GetBlockHash();
248  latestblock.height = pindex->nHeight;
249  }
250  cond_blockchange.notify_all();
251 }
252 
254 {
255  return RPCHelpMan{"waitfornewblock",
256  "\nWaits for a specific new block and returns useful info about it.\n"
257  "\nReturns the current block on timeout or exit.\n",
258  {
259  {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
260  },
261  RPCResult{
262  RPCResult::Type::OBJ, "", "",
263  {
264  {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
265  {RPCResult::Type::NUM, "height", "Block height"},
266  }},
267  RPCExamples{
268  HelpExampleCli("waitfornewblock", "1000")
269  + HelpExampleRpc("waitfornewblock", "1000")
270  },
271  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
272 {
273  int timeout = 0;
274  if (!request.params[0].isNull())
275  timeout = request.params[0].getInt<int>();
276 
277  CUpdatedBlock block;
278  {
279  WAIT_LOCK(cs_blockchange, lock);
280  block = latestblock;
281  if(timeout)
282  cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
283  else
284  cond_blockchange.wait(lock, [&block]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
285  block = latestblock;
286  }
288  ret.pushKV("hash", block.hash.GetHex());
289  ret.pushKV("height", block.height);
290  return ret;
291 },
292  };
293 }
294 
296 {
297  return RPCHelpMan{"waitforblock",
298  "\nWaits for a specific new block and returns useful info about it.\n"
299  "\nReturns the current block on timeout or exit.\n",
300  {
301  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Block hash to wait for."},
302  {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
303  },
304  RPCResult{
305  RPCResult::Type::OBJ, "", "",
306  {
307  {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
308  {RPCResult::Type::NUM, "height", "Block height"},
309  }},
310  RPCExamples{
311  HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\" 1000")
312  + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
313  },
314  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
315 {
316  int timeout = 0;
317 
318  uint256 hash(ParseHashV(request.params[0], "blockhash"));
319 
320  if (!request.params[1].isNull())
321  timeout = request.params[1].getInt<int>();
322 
323  CUpdatedBlock block;
324  {
325  WAIT_LOCK(cs_blockchange, lock);
326  if(timeout)
327  cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.hash == hash || !IsRPCRunning();});
328  else
329  cond_blockchange.wait(lock, [&hash]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.hash == hash || !IsRPCRunning(); });
330  block = latestblock;
331  }
332 
334  ret.pushKV("hash", block.hash.GetHex());
335  ret.pushKV("height", block.height);
336  return ret;
337 },
338  };
339 }
340 
342 {
343  return RPCHelpMan{"waitforblockheight",
344  "\nWaits for (at least) block height and returns the height and hash\n"
345  "of the current tip.\n"
346  "\nReturns the current block on timeout or exit.\n",
347  {
348  {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "Block height to wait for."},
349  {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
350  },
351  RPCResult{
352  RPCResult::Type::OBJ, "", "",
353  {
354  {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
355  {RPCResult::Type::NUM, "height", "Block height"},
356  }},
357  RPCExamples{
358  HelpExampleCli("waitforblockheight", "100 1000")
359  + HelpExampleRpc("waitforblockheight", "100, 1000")
360  },
361  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
362 {
363  int timeout = 0;
364 
365  int height = request.params[0].getInt<int>();
366 
367  if (!request.params[1].isNull())
368  timeout = request.params[1].getInt<int>();
369 
370  CUpdatedBlock block;
371  {
372  WAIT_LOCK(cs_blockchange, lock);
373  if(timeout)
374  cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height >= height || !IsRPCRunning();});
375  else
376  cond_blockchange.wait(lock, [&height]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height >= height || !IsRPCRunning(); });
377  block = latestblock;
378  }
380  ret.pushKV("hash", block.hash.GetHex());
381  ret.pushKV("height", block.height);
382  return ret;
383 },
384  };
385 }
386 
388 {
389  return RPCHelpMan{"syncwithvalidationinterfacequeue",
390  "\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n",
391  {},
393  RPCExamples{
394  HelpExampleCli("syncwithvalidationinterfacequeue","")
395  + HelpExampleRpc("syncwithvalidationinterfacequeue","")
396  },
397  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
398 {
399  NodeContext& node = EnsureAnyNodeContext(request.context);
400  CHECK_NONFATAL(node.validation_signals)->SyncWithValidationInterfaceQueue();
401  return UniValue::VNULL;
402 },
403  };
404 }
405 
407 {
408  return RPCHelpMan{"getdifficulty",
409  "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n",
410  {},
411  RPCResult{
412  RPCResult::Type::NUM, "", "the proof-of-work difficulty as a multiple of the minimum difficulty."},
413  RPCExamples{
414  HelpExampleCli("getdifficulty", "")
415  + HelpExampleRpc("getdifficulty", "")
416  },
417  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
418 {
419  ChainstateManager& chainman = EnsureAnyChainman(request.context);
420  LOCK(cs_main);
421  return GetDifficulty(*CHECK_NONFATAL(chainman.ActiveChain().Tip()));
422 },
423  };
424 }
425 
427 {
428  return RPCHelpMan{
429  "getblockfrompeer",
430  "Attempt to fetch block from a given peer.\n\n"
431  "We must have the header for this block, e.g. using submitheader.\n"
432  "Subsequent calls for the same block may cause the response from the previous peer to be ignored.\n"
433  "Peers generally ignore requests for a stale block that they never fully verified, or one that is more than a month old.\n"
434  "When a peer does not respond with a block, we will disconnect.\n"
435  "Note: The block could be re-pruned as soon as it is received.\n\n"
436  "Returns an empty JSON object if the request was successfully scheduled.",
437  {
438  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash to try to fetch"},
439  {"peer_id", RPCArg::Type::NUM, RPCArg::Optional::NO, "The peer to fetch it from (see getpeerinfo for peer IDs)"},
440  },
441  RPCResult{RPCResult::Type::OBJ, "", /*optional=*/false, "", {}},
442  RPCExamples{
443  HelpExampleCli("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0")
444  + HelpExampleRpc("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0")
445  },
446  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
447 {
448  const NodeContext& node = EnsureAnyNodeContext(request.context);
450  PeerManager& peerman = EnsurePeerman(node);
451 
452  const uint256& block_hash{ParseHashV(request.params[0], "blockhash")};
453  const NodeId peer_id{request.params[1].getInt<int64_t>()};
454 
455  const CBlockIndex* const index = WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(block_hash););
456 
457  if (!index) {
458  throw JSONRPCError(RPC_MISC_ERROR, "Block header missing");
459  }
460 
461  // Fetching blocks before the node has syncing past their height can prevent block files from
462  // being pruned, so we avoid it if the node is in prune mode.
463  if (chainman.m_blockman.IsPruneMode() && index->nHeight > WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip()->nHeight)) {
464  throw JSONRPCError(RPC_MISC_ERROR, "In prune mode, only blocks that the node has already synced previously can be fetched from a peer");
465  }
466 
467  const bool block_has_data = WITH_LOCK(::cs_main, return index->nStatus & BLOCK_HAVE_DATA);
468  if (block_has_data) {
469  throw JSONRPCError(RPC_MISC_ERROR, "Block already downloaded");
470  }
471 
472  if (const auto err{peerman.FetchBlock(peer_id, *index)}) {
473  throw JSONRPCError(RPC_MISC_ERROR, err.value());
474  }
475  return UniValue::VOBJ;
476 },
477  };
478 }
479 
481 {
482  return RPCHelpMan{"getblockhash",
483  "\nReturns hash of block in best-block-chain at height provided.\n",
484  {
485  {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The height index"},
486  },
487  RPCResult{
488  RPCResult::Type::STR_HEX, "", "The block hash"},
489  RPCExamples{
490  HelpExampleCli("getblockhash", "1000")
491  + HelpExampleRpc("getblockhash", "1000")
492  },
493  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
494 {
495  ChainstateManager& chainman = EnsureAnyChainman(request.context);
496  LOCK(cs_main);
497  const CChain& active_chain = chainman.ActiveChain();
498 
499  int nHeight = request.params[0].getInt<int>();
500  if (nHeight < 0 || nHeight > active_chain.Height())
501  throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
502 
503  const CBlockIndex* pblockindex = active_chain[nHeight];
504  return pblockindex->GetBlockHash().GetHex();
505 },
506  };
507 }
508 
510 {
511  return RPCHelpMan{"getblockheader",
512  "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"
513  "If verbose is true, returns an Object with information about blockheader <hash>.\n",
514  {
515  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
516  {"verbose", RPCArg::Type::BOOL, RPCArg::Default{true}, "true for a json object, false for the hex-encoded data"},
517  },
518  {
519  RPCResult{"for verbose = true",
520  RPCResult::Type::OBJ, "", "",
521  {
522  {RPCResult::Type::STR_HEX, "hash", "the block hash (same as provided)"},
523  {RPCResult::Type::NUM, "confirmations", "The number of confirmations, or -1 if the block is not on the main chain"},
524  {RPCResult::Type::NUM, "height", "The block height or index"},
525  {RPCResult::Type::NUM, "version", "The block version"},
526  {RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},
527  {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
528  {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
529  {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
530  {RPCResult::Type::NUM, "nonce", "The nonce"},
531  {RPCResult::Type::STR_HEX, "bits", "The bits"},
532  {RPCResult::Type::NUM, "difficulty", "The difficulty"},
533  {RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the current chain"},
534  {RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
535  {RPCResult::Type::STR_HEX, "previousblockhash", /*optional=*/true, "The hash of the previous block (if available)"},
536  {RPCResult::Type::STR_HEX, "nextblockhash", /*optional=*/true, "The hash of the next block (if available)"},
537  }},
538  RPCResult{"for verbose=false",
539  RPCResult::Type::STR_HEX, "", "A string that is serialized, hex-encoded data for block 'hash'"},
540  },
541  RPCExamples{
542  HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
543  + HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
544  },
545  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
546 {
547  uint256 hash(ParseHashV(request.params[0], "hash"));
548 
549  bool fVerbose = true;
550  if (!request.params[1].isNull())
551  fVerbose = request.params[1].get_bool();
552 
553  const CBlockIndex* pblockindex;
554  const CBlockIndex* tip;
555  {
556  ChainstateManager& chainman = EnsureAnyChainman(request.context);
557  LOCK(cs_main);
558  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
559  tip = chainman.ActiveChain().Tip();
560  }
561 
562  if (!pblockindex) {
563  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
564  }
565 
566  if (!fVerbose)
567  {
568  DataStream ssBlock{};
569  ssBlock << pblockindex->GetBlockHeader();
570  std::string strHex = HexStr(ssBlock);
571  return strHex;
572  }
573 
574  return blockheaderToJSON(*tip, *pblockindex);
575 },
576  };
577 }
578 
579 static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex& blockindex)
580 {
581  CBlock block;
582  {
583  LOCK(cs_main);
584  if (blockman.IsBlockPruned(blockindex)) {
585  throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
586  }
587  }
588 
589  if (!blockman.ReadBlockFromDisk(block, blockindex)) {
590  // Block not found on disk. This could be because we have the block
591  // header in our index but not yet have the block or did not accept the
592  // block. Or if the block was pruned right after we released the lock above.
593  throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
594  }
595 
596  return block;
597 }
598 
599 static std::vector<uint8_t> GetRawBlockChecked(BlockManager& blockman, const CBlockIndex& blockindex)
600 {
601  std::vector<uint8_t> data{};
602  FlatFilePos pos{};
603  {
604  LOCK(cs_main);
605  if (blockman.IsBlockPruned(blockindex)) {
606  throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
607  }
608  pos = blockindex.GetBlockPos();
609  }
610 
611  if (!blockman.ReadRawBlockFromDisk(data, pos)) {
612  // Block not found on disk. This could be because we have the block
613  // header in our index but not yet have the block or did not accept the
614  // block. Or if the block was pruned right after we released the lock above.
615  throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
616  }
617 
618  return data;
619 }
620 
621 static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex& blockindex)
622 {
623  CBlockUndo blockUndo;
624 
625  // The Genesis block does not have undo data
626  if (blockindex.nHeight == 0) return blockUndo;
627 
628  {
629  LOCK(cs_main);
630  if (blockman.IsBlockPruned(blockindex)) {
631  throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)");
632  }
633  }
634 
635  if (!blockman.UndoReadFromDisk(blockUndo, blockindex)) {
636  throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
637  }
638 
639  return blockUndo;
640 }
641 
643  RPCResult::Type::ARR, "vin", "",
644  {
645  {RPCResult::Type::OBJ, "", "",
646  {
647  {RPCResult::Type::ELISION, "", "The same output as verbosity = 2"},
648  {RPCResult::Type::OBJ, "prevout", "(Only if undo information is available)",
649  {
650  {RPCResult::Type::BOOL, "generated", "Coinbase or not"},
651  {RPCResult::Type::NUM, "height", "The height of the prevout"},
652  {RPCResult::Type::STR_AMOUNT, "value", "The value in " + CURRENCY_UNIT},
653  {RPCResult::Type::OBJ, "scriptPubKey", "",
654  {
655  {RPCResult::Type::STR, "asm", "Disassembly of the public key script"},
656  {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
657  {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"},
658  {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
659  {RPCResult::Type::STR, "type", "The type (one of: " + GetAllOutputTypes() + ")"},
660  }},
661  }},
662  }},
663  }
664 };
665 
667 {
668  return RPCHelpMan{"getblock",
669  "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
670  "If verbosity is 1, returns an Object with information about block <hash>.\n"
671  "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction.\n"
672  "If verbosity is 3, returns an Object with information about block <hash> and information about each transaction, including prevout information for inputs (only for unpruned blocks in the current best chain).\n",
673  {
674  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
675  {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1}, "0 for hex-encoded data, 1 for a JSON object, 2 for JSON object with transaction data, and 3 for JSON object with transaction data including prevout information for inputs",
676  RPCArgOptions{.skip_type_check = true}},
677  },
678  {
679  RPCResult{"for verbosity = 0",
680  RPCResult::Type::STR_HEX, "", "A string that is serialized, hex-encoded data for block 'hash'"},
681  RPCResult{"for verbosity = 1",
682  RPCResult::Type::OBJ, "", "",
683  {
684  {RPCResult::Type::STR_HEX, "hash", "the block hash (same as provided)"},
685  {RPCResult::Type::NUM, "confirmations", "The number of confirmations, or -1 if the block is not on the main chain"},
686  {RPCResult::Type::NUM, "size", "The block size"},
687  {RPCResult::Type::NUM, "strippedsize", "The block size excluding witness data"},
688  {RPCResult::Type::NUM, "weight", "The block weight as defined in BIP 141"},
689  {RPCResult::Type::NUM, "height", "The block height or index"},
690  {RPCResult::Type::NUM, "version", "The block version"},
691  {RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},
692  {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
693  {RPCResult::Type::ARR, "tx", "The transaction ids",
694  {{RPCResult::Type::STR_HEX, "", "The transaction id"}}},
695  {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
696  {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
697  {RPCResult::Type::NUM, "nonce", "The nonce"},
698  {RPCResult::Type::STR_HEX, "bits", "The bits"},
699  {RPCResult::Type::NUM, "difficulty", "The difficulty"},
700  {RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the chain up to this block (in hex)"},
701  {RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
702  {RPCResult::Type::STR_HEX, "previousblockhash", /*optional=*/true, "The hash of the previous block (if available)"},
703  {RPCResult::Type::STR_HEX, "nextblockhash", /*optional=*/true, "The hash of the next block (if available)"},
704  }},
705  RPCResult{"for verbosity = 2",
706  RPCResult::Type::OBJ, "", "",
707  {
708  {RPCResult::Type::ELISION, "", "Same output as verbosity = 1"},
709  {RPCResult::Type::ARR, "tx", "",
710  {
711  {RPCResult::Type::OBJ, "", "",
712  {
713  {RPCResult::Type::ELISION, "", "The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result"},
714  {RPCResult::Type::NUM, "fee", "The transaction fee in " + CURRENCY_UNIT + ", omitted if block undo data is not available"},
715  }},
716  }},
717  }},
718  RPCResult{"for verbosity = 3",
719  RPCResult::Type::OBJ, "", "",
720  {
721  {RPCResult::Type::ELISION, "", "Same output as verbosity = 2"},
722  {RPCResult::Type::ARR, "tx", "",
723  {
724  {RPCResult::Type::OBJ, "", "",
725  {
726  getblock_vin,
727  }},
728  }},
729  }},
730  },
731  RPCExamples{
732  HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
733  + HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
734  },
735  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
736 {
737  uint256 hash(ParseHashV(request.params[0], "blockhash"));
738 
739  int verbosity = 1;
740  if (!request.params[1].isNull()) {
741  if (request.params[1].isBool()) {
742  verbosity = request.params[1].get_bool() ? 1 : 0;
743  } else {
744  verbosity = request.params[1].getInt<int>();
745  }
746  }
747 
748  const CBlockIndex* pblockindex;
749  const CBlockIndex* tip;
750  ChainstateManager& chainman = EnsureAnyChainman(request.context);
751  {
752  LOCK(cs_main);
753  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
754  tip = chainman.ActiveChain().Tip();
755 
756  if (!pblockindex) {
757  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
758  }
759  }
760 
761  const std::vector<uint8_t> block_data{GetRawBlockChecked(chainman.m_blockman, *pblockindex)};
762 
763  if (verbosity <= 0) {
764  return HexStr(block_data);
765  }
766 
767  DataStream block_stream{block_data};
768  CBlock block{};
769  block_stream >> TX_WITH_WITNESS(block);
770 
771  TxVerbosity tx_verbosity;
772  if (verbosity == 1) {
773  tx_verbosity = TxVerbosity::SHOW_TXID;
774  } else if (verbosity == 2) {
775  tx_verbosity = TxVerbosity::SHOW_DETAILS;
776  } else {
778  }
779 
780  return blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity);
781 },
782  };
783 }
784 
786 {
787  return RPCHelpMan{"pruneblockchain", "",
788  {
789  {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block height to prune up to. May be set to a discrete height, or to a " + UNIX_EPOCH_TIME + "\n"
790  " to prune blocks whose block time is at least 2 hours older than the provided timestamp."},
791  },
792  RPCResult{
793  RPCResult::Type::NUM, "", "Height of the last block pruned"},
794  RPCExamples{
795  HelpExampleCli("pruneblockchain", "1000")
796  + HelpExampleRpc("pruneblockchain", "1000")
797  },
798  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
799 {
800  ChainstateManager& chainman = EnsureAnyChainman(request.context);
801  if (!chainman.m_blockman.IsPruneMode()) {
802  throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
803  }
804 
805  LOCK(cs_main);
806  Chainstate& active_chainstate = chainman.ActiveChainstate();
807  CChain& active_chain = active_chainstate.m_chain;
808 
809  int heightParam = request.params[0].getInt<int>();
810  if (heightParam < 0) {
811  throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative block height.");
812  }
813 
814  // Height value more than a billion is too high to be a block height, and
815  // too low to be a block time (corresponds to timestamp from Sep 2001).
816  if (heightParam > 1000000000) {
817  // Add a 2 hour buffer to include blocks which might have had old timestamps
818  const CBlockIndex* pindex = active_chain.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0);
819  if (!pindex) {
820  throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp.");
821  }
822  heightParam = pindex->nHeight;
823  }
824 
825  unsigned int height = (unsigned int) heightParam;
826  unsigned int chainHeight = (unsigned int) active_chain.Height();
827  if (chainHeight < chainman.GetParams().PruneAfterHeight()) {
828  throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning.");
829  } else if (height > chainHeight) {
830  throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height.");
831  } else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
832  LogPrint(BCLog::RPC, "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks.\n");
833  height = chainHeight - MIN_BLOCKS_TO_KEEP;
834  }
835 
836  PruneBlockFilesManual(active_chainstate, height);
837  const CBlockIndex& block{*CHECK_NONFATAL(active_chain.Tip())};
838  return block.nStatus & BLOCK_HAVE_DATA ? active_chainstate.m_blockman.GetFirstStoredBlock(block)->nHeight - 1 : block.nHeight;
839 },
840  };
841 }
842 
843 CoinStatsHashType ParseHashType(const std::string& hash_type_input)
844 {
845  if (hash_type_input == "hash_serialized_3") {
846  return CoinStatsHashType::HASH_SERIALIZED;
847  } else if (hash_type_input == "muhash") {
848  return CoinStatsHashType::MUHASH;
849  } else if (hash_type_input == "none") {
851  } else {
852  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("'%s' is not a valid hash_type", hash_type_input));
853  }
854 }
855 
861 static std::optional<kernel::CCoinsStats> GetUTXOStats(CCoinsView* view, node::BlockManager& blockman,
862  kernel::CoinStatsHashType hash_type,
863  const std::function<void()>& interruption_point = {},
864  const CBlockIndex* pindex = nullptr,
865  bool index_requested = true)
866 {
867  // Use CoinStatsIndex if it is requested and available and a hash_type of Muhash or None was requested
868  if ((hash_type == kernel::CoinStatsHashType::MUHASH || hash_type == kernel::CoinStatsHashType::NONE) && g_coin_stats_index && index_requested) {
869  if (pindex) {
870  return g_coin_stats_index->LookUpStats(*pindex);
871  } else {
872  CBlockIndex& block_index = *CHECK_NONFATAL(WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(view->GetBestBlock())));
873  return g_coin_stats_index->LookUpStats(block_index);
874  }
875  }
876 
877  // If the coinstats index isn't requested or is otherwise not usable, the
878  // pindex should either be null or equal to the view's best block. This is
879  // because without the coinstats index we can only get coinstats about the
880  // best block.
881  CHECK_NONFATAL(!pindex || pindex->GetBlockHash() == view->GetBestBlock());
882 
883  return kernel::ComputeUTXOStats(hash_type, view, blockman, interruption_point);
884 }
885 
887 {
888  return RPCHelpMan{"gettxoutsetinfo",
889  "\nReturns statistics about the unspent transaction output set.\n"
890  "Note this call may take some time if you are not using coinstatsindex.\n",
891  {
892  {"hash_type", RPCArg::Type::STR, RPCArg::Default{"hash_serialized_3"}, "Which UTXO set hash should be calculated. Options: 'hash_serialized_3' (the legacy algorithm), 'muhash', 'none'."},
893  {"hash_or_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"the current best block"}, "The block hash or height of the target height (only available with coinstatsindex).",
895  .skip_type_check = true,
896  .type_str = {"", "string or numeric"},
897  }},
898  {"use_index", RPCArg::Type::BOOL, RPCArg::Default{true}, "Use coinstatsindex, if available."},
899  },
900  RPCResult{
901  RPCResult::Type::OBJ, "", "",
902  {
903  {RPCResult::Type::NUM, "height", "The block height (index) of the returned statistics"},
904  {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at which these statistics are calculated"},
905  {RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs"},
906  {RPCResult::Type::NUM, "bogosize", "Database-independent, meaningless metric indicating the UTXO set size"},
907  {RPCResult::Type::STR_HEX, "hash_serialized_3", /*optional=*/true, "The serialized hash (only present if 'hash_serialized_3' hash_type is chosen)"},
908  {RPCResult::Type::STR_HEX, "muhash", /*optional=*/true, "The serialized hash (only present if 'muhash' hash_type is chosen)"},
909  {RPCResult::Type::NUM, "transactions", /*optional=*/true, "The number of transactions with unspent outputs (not available when coinstatsindex is used)"},
910  {RPCResult::Type::NUM, "disk_size", /*optional=*/true, "The estimated size of the chainstate on disk (not available when coinstatsindex is used)"},
911  {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of coins in the UTXO set"},
912  {RPCResult::Type::STR_AMOUNT, "total_unspendable_amount", /*optional=*/true, "The total amount of coins permanently excluded from the UTXO set (only available if coinstatsindex is used)"},
913  {RPCResult::Type::OBJ, "block_info", /*optional=*/true, "Info on amounts in the block at this block height (only available if coinstatsindex is used)",
914  {
915  {RPCResult::Type::STR_AMOUNT, "prevout_spent", "Total amount of all prevouts spent in this block"},
916  {RPCResult::Type::STR_AMOUNT, "coinbase", "Coinbase subsidy amount of this block"},
917  {RPCResult::Type::STR_AMOUNT, "new_outputs_ex_coinbase", "Total amount of new outputs created by this block"},
918  {RPCResult::Type::STR_AMOUNT, "unspendable", "Total amount of unspendable outputs created in this block"},
919  {RPCResult::Type::OBJ, "unspendables", "Detailed view of the unspendable categories",
920  {
921  {RPCResult::Type::STR_AMOUNT, "genesis_block", "The unspendable amount of the Genesis block subsidy"},
922  {RPCResult::Type::STR_AMOUNT, "bip30", "Transactions overridden by duplicates (no longer possible with BIP30)"},
923  {RPCResult::Type::STR_AMOUNT, "scripts", "Amounts sent to scripts that are unspendable (for example OP_RETURN outputs)"},
924  {RPCResult::Type::STR_AMOUNT, "unclaimed_rewards", "Fee rewards that miners did not claim in their coinbase transaction"},
925  }}
926  }},
927  }},
928  RPCExamples{
929  HelpExampleCli("gettxoutsetinfo", "") +
930  HelpExampleCli("gettxoutsetinfo", R"("none")") +
931  HelpExampleCli("gettxoutsetinfo", R"("none" 1000)") +
932  HelpExampleCli("gettxoutsetinfo", R"("none" '"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"')") +
933  HelpExampleCli("-named gettxoutsetinfo", R"(hash_type='muhash' use_index='false')") +
934  HelpExampleRpc("gettxoutsetinfo", "") +
935  HelpExampleRpc("gettxoutsetinfo", R"("none")") +
936  HelpExampleRpc("gettxoutsetinfo", R"("none", 1000)") +
937  HelpExampleRpc("gettxoutsetinfo", R"("none", "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09")")
938  },
939  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
940 {
942 
943  const CBlockIndex* pindex{nullptr};
944  const CoinStatsHashType hash_type{request.params[0].isNull() ? CoinStatsHashType::HASH_SERIALIZED : ParseHashType(request.params[0].get_str())};
945  bool index_requested = request.params[2].isNull() || request.params[2].get_bool();
946 
947  NodeContext& node = EnsureAnyNodeContext(request.context);
949  Chainstate& active_chainstate = chainman.ActiveChainstate();
950  active_chainstate.ForceFlushStateToDisk();
951 
952  CCoinsView* coins_view;
953  BlockManager* blockman;
954  {
955  LOCK(::cs_main);
956  coins_view = &active_chainstate.CoinsDB();
957  blockman = &active_chainstate.m_blockman;
958  pindex = blockman->LookupBlockIndex(coins_view->GetBestBlock());
959  }
960 
961  if (!request.params[1].isNull()) {
962  if (!g_coin_stats_index) {
963  throw JSONRPCError(RPC_INVALID_PARAMETER, "Querying specific block heights requires coinstatsindex");
964  }
965 
966  if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
967  throw JSONRPCError(RPC_INVALID_PARAMETER, "hash_serialized_3 hash type cannot be queried for a specific block");
968  }
969 
970  if (!index_requested) {
971  throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot set use_index to false when querying for a specific block");
972  }
973  pindex = ParseHashOrHeight(request.params[1], chainman);
974  }
975 
976  if (index_requested && g_coin_stats_index) {
977  if (!g_coin_stats_index->BlockUntilSyncedToCurrentChain()) {
978  const IndexSummary summary{g_coin_stats_index->GetSummary()};
979 
980  // If a specific block was requested and the index has already synced past that height, we can return the
981  // data already even though the index is not fully synced yet.
982  if (pindex->nHeight > summary.best_block_height) {
983  throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to get data because coinstatsindex is still syncing. Current height: %d", summary.best_block_height));
984  }
985  }
986  }
987 
988  const std::optional<CCoinsStats> maybe_stats = GetUTXOStats(coins_view, *blockman, hash_type, node.rpc_interruption_point, pindex, index_requested);
989  if (maybe_stats.has_value()) {
990  const CCoinsStats& stats = maybe_stats.value();
991  ret.pushKV("height", (int64_t)stats.nHeight);
992  ret.pushKV("bestblock", stats.hashBlock.GetHex());
993  ret.pushKV("txouts", (int64_t)stats.nTransactionOutputs);
994  ret.pushKV("bogosize", (int64_t)stats.nBogoSize);
995  if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
996  ret.pushKV("hash_serialized_3", stats.hashSerialized.GetHex());
997  }
998  if (hash_type == CoinStatsHashType::MUHASH) {
999  ret.pushKV("muhash", stats.hashSerialized.GetHex());
1000  }
1001  CHECK_NONFATAL(stats.total_amount.has_value());
1002  ret.pushKV("total_amount", ValueFromAmount(stats.total_amount.value()));
1003  if (!stats.index_used) {
1004  ret.pushKV("transactions", static_cast<int64_t>(stats.nTransactions));
1005  ret.pushKV("disk_size", stats.nDiskSize);
1006  } else {
1007  ret.pushKV("total_unspendable_amount", ValueFromAmount(stats.total_unspendable_amount));
1008 
1009  CCoinsStats prev_stats{};
1010  if (pindex->nHeight > 0) {
1011  const std::optional<CCoinsStats> maybe_prev_stats = GetUTXOStats(coins_view, *blockman, hash_type, node.rpc_interruption_point, pindex->pprev, index_requested);
1012  if (!maybe_prev_stats) {
1013  throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
1014  }
1015  prev_stats = maybe_prev_stats.value();
1016  }
1017 
1018  UniValue block_info(UniValue::VOBJ);
1019  block_info.pushKV("prevout_spent", ValueFromAmount(stats.total_prevout_spent_amount - prev_stats.total_prevout_spent_amount));
1020  block_info.pushKV("coinbase", ValueFromAmount(stats.total_coinbase_amount - prev_stats.total_coinbase_amount));
1021  block_info.pushKV("new_outputs_ex_coinbase", ValueFromAmount(stats.total_new_outputs_ex_coinbase_amount - prev_stats.total_new_outputs_ex_coinbase_amount));
1022  block_info.pushKV("unspendable", ValueFromAmount(stats.total_unspendable_amount - prev_stats.total_unspendable_amount));
1023 
1024  UniValue unspendables(UniValue::VOBJ);
1025  unspendables.pushKV("genesis_block", ValueFromAmount(stats.total_unspendables_genesis_block - prev_stats.total_unspendables_genesis_block));
1026  unspendables.pushKV("bip30", ValueFromAmount(stats.total_unspendables_bip30 - prev_stats.total_unspendables_bip30));
1027  unspendables.pushKV("scripts", ValueFromAmount(stats.total_unspendables_scripts - prev_stats.total_unspendables_scripts));
1028  unspendables.pushKV("unclaimed_rewards", ValueFromAmount(stats.total_unspendables_unclaimed_rewards - prev_stats.total_unspendables_unclaimed_rewards));
1029  block_info.pushKV("unspendables", unspendables);
1030 
1031  ret.pushKV("block_info", block_info);
1032  }
1033  } else {
1034  throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
1035  }
1036  return ret;
1037 },
1038  };
1039 }
1040 
1042 {
1043  return RPCHelpMan{"gettxout",
1044  "\nReturns details about an unspent transaction output.\n",
1045  {
1046  {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
1047  {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
1048  {"include_mempool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to include the mempool. Note that an unspent output that is spent in the mempool won't appear."},
1049  },
1050  {
1051  RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "", ""},
1052  RPCResult{"Otherwise", RPCResult::Type::OBJ, "", "", {
1053  {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
1054  {RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
1055  {RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT},
1056  {RPCResult::Type::OBJ, "scriptPubKey", "", {
1057  {RPCResult::Type::STR, "asm", "Disassembly of the public key script"},
1058  {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
1059  {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"},
1060  {RPCResult::Type::STR, "type", "The type, eg pubkeyhash"},
1061  {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
1062  }},
1063  {RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
1064  }},
1065  },
1066  RPCExamples{
1067  "\nGet unspent transactions\n"
1068  + HelpExampleCli("listunspent", "") +
1069  "\nView the details\n"
1070  + HelpExampleCli("gettxout", "\"txid\" 1") +
1071  "\nAs a JSON-RPC call\n"
1072  + HelpExampleRpc("gettxout", "\"txid\", 1")
1073  },
1074  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1075 {
1076  NodeContext& node = EnsureAnyNodeContext(request.context);
1077  ChainstateManager& chainman = EnsureChainman(node);
1078  LOCK(cs_main);
1079 
1081 
1082  auto hash{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
1083  COutPoint out{hash, request.params[1].getInt<uint32_t>()};
1084  bool fMempool = true;
1085  if (!request.params[2].isNull())
1086  fMempool = request.params[2].get_bool();
1087 
1088  Coin coin;
1089  Chainstate& active_chainstate = chainman.ActiveChainstate();
1090  CCoinsViewCache* coins_view = &active_chainstate.CoinsTip();
1091 
1092  if (fMempool) {
1093  const CTxMemPool& mempool = EnsureMemPool(node);
1094  LOCK(mempool.cs);
1095  CCoinsViewMemPool view(coins_view, mempool);
1096  if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
1097  return UniValue::VNULL;
1098  }
1099  } else {
1100  if (!coins_view->GetCoin(out, coin)) {
1101  return UniValue::VNULL;
1102  }
1103  }
1104 
1105  const CBlockIndex* pindex = active_chainstate.m_blockman.LookupBlockIndex(coins_view->GetBestBlock());
1106  ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
1107  if (coin.nHeight == MEMPOOL_HEIGHT) {
1108  ret.pushKV("confirmations", 0);
1109  } else {
1110  ret.pushKV("confirmations", (int64_t)(pindex->nHeight - coin.nHeight + 1));
1111  }
1112  ret.pushKV("value", ValueFromAmount(coin.out.nValue));
1114  ScriptToUniv(coin.out.scriptPubKey, /*out=*/o, /*include_hex=*/true, /*include_address=*/true);
1115  ret.pushKV("scriptPubKey", o);
1116  ret.pushKV("coinbase", (bool)coin.fCoinBase);
1117 
1118  return ret;
1119 },
1120  };
1121 }
1122 
1124 {
1125  return RPCHelpMan{"verifychain",
1126  "\nVerifies blockchain database.\n",
1127  {
1128  {"checklevel", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL)},
1129  strprintf("How thorough the block verification is:\n%s", MakeUnorderedList(CHECKLEVEL_DOC))},
1130  {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, 0=all", DEFAULT_CHECKBLOCKS)}, "The number of blocks to check."},
1131  },
1132  RPCResult{
1133  RPCResult::Type::BOOL, "", "Verification finished successfully. If false, check debug.log for reason."},
1134  RPCExamples{
1135  HelpExampleCli("verifychain", "")
1136  + HelpExampleRpc("verifychain", "")
1137  },
1138  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1139 {
1140  const int check_level{request.params[0].isNull() ? DEFAULT_CHECKLEVEL : request.params[0].getInt<int>()};
1141  const int check_depth{request.params[1].isNull() ? DEFAULT_CHECKBLOCKS : request.params[1].getInt<int>()};
1142 
1143  ChainstateManager& chainman = EnsureAnyChainman(request.context);
1144  LOCK(cs_main);
1145 
1146  Chainstate& active_chainstate = chainman.ActiveChainstate();
1147  return CVerifyDB(chainman.GetNotifications()).VerifyDB(
1148  active_chainstate, chainman.GetParams().GetConsensus(), active_chainstate.CoinsTip(), check_level, check_depth) == VerifyDBResult::SUCCESS;
1149 },
1150  };
1151 }
1152 
1153 static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const ChainstateManager& chainman, Consensus::BuriedDeployment dep)
1154 {
1155  // For buried deployments.
1156 
1157  if (!DeploymentEnabled(chainman, dep)) return;
1158 
1160  rv.pushKV("type", "buried");
1161  // getdeploymentinfo reports the softfork as active from when the chain height is
1162  // one below the activation height
1163  rv.pushKV("active", DeploymentActiveAfter(blockindex, chainman, dep));
1164  rv.pushKV("height", chainman.GetConsensus().DeploymentHeight(dep));
1165  softforks.pushKV(DeploymentName(dep), rv);
1166 }
1167 
1168 static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const ChainstateManager& chainman, Consensus::DeploymentPos id)
1169 {
1170  // For BIP9 deployments.
1171 
1172  if (!DeploymentEnabled(chainman, id)) return;
1173  if (blockindex == nullptr) return;
1174 
1175  auto get_state_name = [](const ThresholdState state) -> std::string {
1176  switch (state) {
1177  case ThresholdState::DEFINED: return "defined";
1178  case ThresholdState::STARTED: return "started";
1179  case ThresholdState::LOCKED_IN: return "locked_in";
1180  case ThresholdState::ACTIVE: return "active";
1181  case ThresholdState::FAILED: return "failed";
1182  }
1183  return "invalid";
1184  };
1185 
1186  UniValue bip9(UniValue::VOBJ);
1187 
1188  const ThresholdState next_state = chainman.m_versionbitscache.State(blockindex, chainman.GetConsensus(), id);
1189  const ThresholdState current_state = chainman.m_versionbitscache.State(blockindex->pprev, chainman.GetConsensus(), id);
1190 
1191  const bool has_signal = (ThresholdState::STARTED == current_state || ThresholdState::LOCKED_IN == current_state);
1192 
1193  // BIP9 parameters
1194  if (has_signal) {
1195  bip9.pushKV("bit", chainman.GetConsensus().vDeployments[id].bit);
1196  }
1197  bip9.pushKV("start_time", chainman.GetConsensus().vDeployments[id].nStartTime);
1198  bip9.pushKV("timeout", chainman.GetConsensus().vDeployments[id].nTimeout);
1199  bip9.pushKV("min_activation_height", chainman.GetConsensus().vDeployments[id].min_activation_height);
1200 
1201  // BIP9 status
1202  bip9.pushKV("status", get_state_name(current_state));
1203  bip9.pushKV("since", chainman.m_versionbitscache.StateSinceHeight(blockindex->pprev, chainman.GetConsensus(), id));
1204  bip9.pushKV("status_next", get_state_name(next_state));
1205 
1206  // BIP9 signalling status, if applicable
1207  if (has_signal) {
1208  UniValue statsUV(UniValue::VOBJ);
1209  std::vector<bool> signals;
1210  BIP9Stats statsStruct = chainman.m_versionbitscache.Statistics(blockindex, chainman.GetConsensus(), id, &signals);
1211  statsUV.pushKV("period", statsStruct.period);
1212  statsUV.pushKV("elapsed", statsStruct.elapsed);
1213  statsUV.pushKV("count", statsStruct.count);
1214  if (ThresholdState::LOCKED_IN != current_state) {
1215  statsUV.pushKV("threshold", statsStruct.threshold);
1216  statsUV.pushKV("possible", statsStruct.possible);
1217  }
1218  bip9.pushKV("statistics", statsUV);
1219 
1220  std::string sig;
1221  sig.reserve(signals.size());
1222  for (const bool s : signals) {
1223  sig.push_back(s ? '#' : '-');
1224  }
1225  bip9.pushKV("signalling", sig);
1226  }
1227 
1229  rv.pushKV("type", "bip9");
1230  if (ThresholdState::ACTIVE == next_state) {
1231  rv.pushKV("height", chainman.m_versionbitscache.StateSinceHeight(blockindex, chainman.GetConsensus(), id));
1232  }
1233  rv.pushKV("active", ThresholdState::ACTIVE == next_state);
1234  rv.pushKV("bip9", bip9);
1235 
1236  softforks.pushKV(DeploymentName(id), rv);
1237 }
1238 
1239 // used by rest.cpp:rest_chaininfo, so cannot be static
1241 {
1242  return RPCHelpMan{"getblockchaininfo",
1243  "Returns an object containing various state info regarding blockchain processing.\n",
1244  {},
1245  RPCResult{
1246  RPCResult::Type::OBJ, "", "",
1247  {
1248  {RPCResult::Type::STR, "chain", "current network name (main, test, signet, regtest)"},
1249  {RPCResult::Type::NUM, "blocks", "the height of the most-work fully-validated chain. The genesis block has height 0"},
1250  {RPCResult::Type::NUM, "headers", "the current number of headers we have validated"},
1251  {RPCResult::Type::STR, "bestblockhash", "the hash of the currently best block"},
1252  {RPCResult::Type::NUM, "difficulty", "the current difficulty"},
1253  {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
1254  {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
1255  {RPCResult::Type::NUM, "verificationprogress", "estimate of verification progress [0..1]"},
1256  {RPCResult::Type::BOOL, "initialblockdownload", "(debug information) estimate of whether this node is in Initial Block Download mode"},
1257  {RPCResult::Type::STR_HEX, "chainwork", "total amount of work in active chain, in hexadecimal"},
1258  {RPCResult::Type::NUM, "size_on_disk", "the estimated size of the block and undo files on disk"},
1259  {RPCResult::Type::BOOL, "pruned", "if the blocks are subject to pruning"},
1260  {RPCResult::Type::NUM, "pruneheight", /*optional=*/true, "height of the last block pruned, plus one (only present if pruning is enabled)"},
1261  {RPCResult::Type::BOOL, "automatic_pruning", /*optional=*/true, "whether automatic pruning is enabled (only present if pruning is enabled)"},
1262  {RPCResult::Type::NUM, "prune_target_size", /*optional=*/true, "the target size used by pruning (only present if automatic pruning is enabled)"},
1263  {RPCResult::Type::STR, "warnings", "any network and blockchain warnings"},
1264  }},
1265  RPCExamples{
1266  HelpExampleCli("getblockchaininfo", "")
1267  + HelpExampleRpc("getblockchaininfo", "")
1268  },
1269  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1270 {
1271  ChainstateManager& chainman = EnsureAnyChainman(request.context);
1272  LOCK(cs_main);
1273  Chainstate& active_chainstate = chainman.ActiveChainstate();
1274 
1275  const CBlockIndex& tip{*CHECK_NONFATAL(active_chainstate.m_chain.Tip())};
1276  const int height{tip.nHeight};
1277  UniValue obj(UniValue::VOBJ);
1278  obj.pushKV("chain", chainman.GetParams().GetChainTypeString());
1279  obj.pushKV("blocks", height);
1280  obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
1281  obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex());
1282  obj.pushKV("difficulty", GetDifficulty(tip));
1283  obj.pushKV("time", tip.GetBlockTime());
1284  obj.pushKV("mediantime", tip.GetMedianTimePast());
1285  obj.pushKV("verificationprogress", GuessVerificationProgress(chainman.GetParams().TxData(), &tip));
1286  obj.pushKV("initialblockdownload", chainman.IsInitialBlockDownload());
1287  obj.pushKV("chainwork", tip.nChainWork.GetHex());
1288  obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage());
1289  obj.pushKV("pruned", chainman.m_blockman.IsPruneMode());
1290  if (chainman.m_blockman.IsPruneMode()) {
1291  bool has_tip_data = tip.nStatus & BLOCK_HAVE_DATA;
1292  obj.pushKV("pruneheight", has_tip_data ? chainman.m_blockman.GetFirstStoredBlock(tip)->nHeight : tip.nHeight + 1);
1293 
1294  const bool automatic_pruning{chainman.m_blockman.GetPruneTarget() != BlockManager::PRUNE_TARGET_MANUAL};
1295  obj.pushKV("automatic_pruning", automatic_pruning);
1296  if (automatic_pruning) {
1297  obj.pushKV("prune_target_size", chainman.m_blockman.GetPruneTarget());
1298  }
1299  }
1300 
1301  obj.pushKV("warnings", GetWarnings(false).original);
1302  return obj;
1303 },
1304  };
1305 }
1306 
1307 namespace {
1308 const std::vector<RPCResult> RPCHelpForDeployment{
1309  {RPCResult::Type::STR, "type", "one of \"buried\", \"bip9\""},
1310  {RPCResult::Type::NUM, "height", /*optional=*/true, "height of the first block which the rules are or will be enforced (only for \"buried\" type, or \"bip9\" type with \"active\" status)"},
1311  {RPCResult::Type::BOOL, "active", "true if the rules are enforced for the mempool and the next block"},
1312  {RPCResult::Type::OBJ, "bip9", /*optional=*/true, "status of bip9 softforks (only for \"bip9\" type)",
1313  {
1314  {RPCResult::Type::NUM, "bit", /*optional=*/true, "the bit (0-28) in the block version field used to signal this softfork (only for \"started\" and \"locked_in\" status)"},
1315  {RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"},
1316  {RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"},
1317  {RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"},
1318  {RPCResult::Type::STR, "status", "status of deployment at specified block (one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\")"},
1319  {RPCResult::Type::NUM, "since", "height of the first block to which the status applies"},
1320  {RPCResult::Type::STR, "status_next", "status of deployment at the next block"},
1321  {RPCResult::Type::OBJ, "statistics", /*optional=*/true, "numeric statistics about signalling for a softfork (only for \"started\" and \"locked_in\" status)",
1322  {
1323  {RPCResult::Type::NUM, "period", "the length in blocks of the signalling period"},
1324  {RPCResult::Type::NUM, "threshold", /*optional=*/true, "the number of blocks with the version bit set required to activate the feature (only for \"started\" status)"},
1325  {RPCResult::Type::NUM, "elapsed", "the number of blocks elapsed since the beginning of the current period"},
1326  {RPCResult::Type::NUM, "count", "the number of blocks with the version bit set in the current period"},
1327  {RPCResult::Type::BOOL, "possible", /*optional=*/true, "returns false if there are not enough blocks left in this period to pass activation threshold (only for \"started\" status)"},
1328  }},
1329  {RPCResult::Type::STR, "signalling", /*optional=*/true, "indicates blocks that signalled with a # and blocks that did not with a -"},
1330  }},
1331 };
1332 
1333 UniValue DeploymentInfo(const CBlockIndex* blockindex, const ChainstateManager& chainman)
1334 {
1335  UniValue softforks(UniValue::VOBJ);
1336  SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_HEIGHTINCB);
1337  SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_DERSIG);
1338  SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_CLTV);
1339  SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_CSV);
1340  SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_SEGWIT);
1341  SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TESTDUMMY);
1342  SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TAPROOT);
1343  return softforks;
1344 }
1345 } // anon namespace
1346 
1348 {
1349  return RPCHelpMan{"getdeploymentinfo",
1350  "Returns an object containing various state info regarding deployments of consensus changes.",
1351  {
1352  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Default{"hash of current chain tip"}, "The block hash at which to query deployment state"},
1353  },
1354  RPCResult{
1355  RPCResult::Type::OBJ, "", "", {
1356  {RPCResult::Type::STR, "hash", "requested block hash (or tip)"},
1357  {RPCResult::Type::NUM, "height", "requested block height (or tip)"},
1358  {RPCResult::Type::OBJ_DYN, "deployments", "", {
1359  {RPCResult::Type::OBJ, "xxxx", "name of the deployment", RPCHelpForDeployment}
1360  }},
1361  }
1362  },
1363  RPCExamples{ HelpExampleCli("getdeploymentinfo", "") + HelpExampleRpc("getdeploymentinfo", "") },
1364  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1365  {
1366  const ChainstateManager& chainman = EnsureAnyChainman(request.context);
1367  LOCK(cs_main);
1368  const Chainstate& active_chainstate = chainman.ActiveChainstate();
1369 
1370  const CBlockIndex* blockindex;
1371  if (request.params[0].isNull()) {
1372  blockindex = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
1373  } else {
1374  const uint256 hash(ParseHashV(request.params[0], "blockhash"));
1375  blockindex = chainman.m_blockman.LookupBlockIndex(hash);
1376  if (!blockindex) {
1377  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1378  }
1379  }
1380 
1381  UniValue deploymentinfo(UniValue::VOBJ);
1382  deploymentinfo.pushKV("hash", blockindex->GetBlockHash().ToString());
1383  deploymentinfo.pushKV("height", blockindex->nHeight);
1384  deploymentinfo.pushKV("deployments", DeploymentInfo(blockindex, chainman));
1385  return deploymentinfo;
1386  },
1387  };
1388 }
1389 
1392 {
1393  bool operator()(const CBlockIndex* a, const CBlockIndex* b) const
1394  {
1395  /* Make sure that unequal blocks with the same height do not compare
1396  equal. Use the pointers themselves to make a distinction. */
1397 
1398  if (a->nHeight != b->nHeight)
1399  return (a->nHeight > b->nHeight);
1400 
1401  return a < b;
1402  }
1403 };
1404 
1406 {
1407  return RPCHelpMan{"getchaintips",
1408  "Return information about all known tips in the block tree,"
1409  " including the main chain as well as orphaned branches.\n",
1410  {},
1411  RPCResult{
1412  RPCResult::Type::ARR, "", "",
1413  {{RPCResult::Type::OBJ, "", "",
1414  {
1415  {RPCResult::Type::NUM, "height", "height of the chain tip"},
1416  {RPCResult::Type::STR_HEX, "hash", "block hash of the tip"},
1417  {RPCResult::Type::NUM, "branchlen", "zero for main chain, otherwise length of branch connecting the tip to the main chain"},
1418  {RPCResult::Type::STR, "status", "status of the chain, \"active\" for the main chain\n"
1419  "Possible values for status:\n"
1420  "1. \"invalid\" This branch contains at least one invalid block\n"
1421  "2. \"headers-only\" Not all blocks for this branch are available, but the headers are valid\n"
1422  "3. \"valid-headers\" All blocks are available for this branch, but they were never fully validated\n"
1423  "4. \"valid-fork\" This branch is not part of the active chain, but is fully validated\n"
1424  "5. \"active\" This is the tip of the active main chain, which is certainly valid"},
1425  }}}},
1426  RPCExamples{
1427  HelpExampleCli("getchaintips", "")
1428  + HelpExampleRpc("getchaintips", "")
1429  },
1430  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1431 {
1432  ChainstateManager& chainman = EnsureAnyChainman(request.context);
1433  LOCK(cs_main);
1434  CChain& active_chain = chainman.ActiveChain();
1435 
1436  /*
1437  * Idea: The set of chain tips is the active chain tip, plus orphan blocks which do not have another orphan building off of them.
1438  * Algorithm:
1439  * - Make one pass through BlockIndex(), picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers.
1440  * - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip.
1441  * - Add the active chain tip
1442  */
1443  std::set<const CBlockIndex*, CompareBlocksByHeight> setTips;
1444  std::set<const CBlockIndex*> setOrphans;
1445  std::set<const CBlockIndex*> setPrevs;
1446 
1447  for (const auto& [_, block_index] : chainman.BlockIndex()) {
1448  if (!active_chain.Contains(&block_index)) {
1449  setOrphans.insert(&block_index);
1450  setPrevs.insert(block_index.pprev);
1451  }
1452  }
1453 
1454  for (std::set<const CBlockIndex*>::iterator it = setOrphans.begin(); it != setOrphans.end(); ++it) {
1455  if (setPrevs.erase(*it) == 0) {
1456  setTips.insert(*it);
1457  }
1458  }
1459 
1460  // Always report the currently active tip.
1461  setTips.insert(active_chain.Tip());
1462 
1463  /* Construct the output array. */
1464  UniValue res(UniValue::VARR);
1465  for (const CBlockIndex* block : setTips) {
1466  UniValue obj(UniValue::VOBJ);
1467  obj.pushKV("height", block->nHeight);
1468  obj.pushKV("hash", block->phashBlock->GetHex());
1469 
1470  const int branchLen = block->nHeight - active_chain.FindFork(block)->nHeight;
1471  obj.pushKV("branchlen", branchLen);
1472 
1473  std::string status;
1474  if (active_chain.Contains(block)) {
1475  // This block is part of the currently active chain.
1476  status = "active";
1477  } else if (block->nStatus & BLOCK_FAILED_MASK) {
1478  // This block or one of its ancestors is invalid.
1479  status = "invalid";
1480  } else if (!block->HaveNumChainTxs()) {
1481  // This block cannot be connected because full block data for it or one of its parents is missing.
1482  status = "headers-only";
1483  } else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {
1484  // This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.
1485  status = "valid-fork";
1486  } else if (block->IsValid(BLOCK_VALID_TREE)) {
1487  // The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.
1488  status = "valid-headers";
1489  } else {
1490  // No clue.
1491  status = "unknown";
1492  }
1493  obj.pushKV("status", status);
1494 
1495  res.push_back(obj);
1496  }
1497 
1498  return res;
1499 },
1500  };
1501 }
1502 
1504 {
1505  return RPCHelpMan{"preciousblock",
1506  "\nTreats a block as if it were received before others with the same work.\n"
1507  "\nA later preciousblock call can override the effect of an earlier one.\n"
1508  "\nThe effects of preciousblock are not retained across restarts.\n",
1509  {
1510  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as precious"},
1511  },
1513  RPCExamples{
1514  HelpExampleCli("preciousblock", "\"blockhash\"")
1515  + HelpExampleRpc("preciousblock", "\"blockhash\"")
1516  },
1517  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1518 {
1519  uint256 hash(ParseHashV(request.params[0], "blockhash"));
1520  CBlockIndex* pblockindex;
1521 
1522  ChainstateManager& chainman = EnsureAnyChainman(request.context);
1523  {
1524  LOCK(cs_main);
1525  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1526  if (!pblockindex) {
1527  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1528  }
1529  }
1530 
1531  BlockValidationState state;
1532  chainman.ActiveChainstate().PreciousBlock(state, pblockindex);
1533 
1534  if (!state.IsValid()) {
1535  throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
1536  }
1537 
1538  return UniValue::VNULL;
1539 },
1540  };
1541 }
1542 
1544 {
1545  return RPCHelpMan{"invalidateblock",
1546  "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n",
1547  {
1548  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as invalid"},
1549  },
1551  RPCExamples{
1552  HelpExampleCli("invalidateblock", "\"blockhash\"")
1553  + HelpExampleRpc("invalidateblock", "\"blockhash\"")
1554  },
1555  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1556 {
1557  uint256 hash(ParseHashV(request.params[0], "blockhash"));
1558  BlockValidationState state;
1559 
1560  ChainstateManager& chainman = EnsureAnyChainman(request.context);
1561  CBlockIndex* pblockindex;
1562  {
1563  LOCK(cs_main);
1564  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1565  if (!pblockindex) {
1566  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1567  }
1568  }
1569  chainman.ActiveChainstate().InvalidateBlock(state, pblockindex);
1570 
1571  if (state.IsValid()) {
1572  chainman.ActiveChainstate().ActivateBestChain(state);
1573  }
1574 
1575  if (!state.IsValid()) {
1576  throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
1577  }
1578 
1579  return UniValue::VNULL;
1580 },
1581  };
1582 }
1583 
1585 {
1586  return RPCHelpMan{"reconsiderblock",
1587  "\nRemoves invalidity status of a block, its ancestors and its descendants, reconsider them for activation.\n"
1588  "This can be used to undo the effects of invalidateblock.\n",
1589  {
1590  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to reconsider"},
1591  },
1593  RPCExamples{
1594  HelpExampleCli("reconsiderblock", "\"blockhash\"")
1595  + HelpExampleRpc("reconsiderblock", "\"blockhash\"")
1596  },
1597  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1598 {
1599  ChainstateManager& chainman = EnsureAnyChainman(request.context);
1600  uint256 hash(ParseHashV(request.params[0], "blockhash"));
1601 
1602  {
1603  LOCK(cs_main);
1604  CBlockIndex* pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1605  if (!pblockindex) {
1606  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1607  }
1608 
1609  chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex);
1610  }
1611 
1612  BlockValidationState state;
1613  chainman.ActiveChainstate().ActivateBestChain(state);
1614 
1615  if (!state.IsValid()) {
1616  throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
1617  }
1618 
1619  return UniValue::VNULL;
1620 },
1621  };
1622 }
1623 
1625 {
1626  return RPCHelpMan{"getchaintxstats",
1627  "\nCompute statistics about the total number and rate of transactions in the chain.\n",
1628  {
1629  {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{"one month"}, "Size of the window in number of blocks"},
1630  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"chain tip"}, "The hash of the block that ends the window."},
1631  },
1632  RPCResult{
1633  RPCResult::Type::OBJ, "", "",
1634  {
1635  {RPCResult::Type::NUM_TIME, "time", "The timestamp for the final block in the window, expressed in " + UNIX_EPOCH_TIME},
1636  {RPCResult::Type::NUM, "txcount", "The total number of transactions in the chain up to that point"},
1637  {RPCResult::Type::STR_HEX, "window_final_block_hash", "The hash of the final block in the window"},
1638  {RPCResult::Type::NUM, "window_final_block_height", "The height of the final block in the window."},
1639  {RPCResult::Type::NUM, "window_block_count", "Size of the window in number of blocks"},
1640  {RPCResult::Type::NUM, "window_tx_count", /*optional=*/true, "The number of transactions in the window. Only returned if \"window_block_count\" is > 0"},
1641  {RPCResult::Type::NUM, "window_interval", /*optional=*/true, "The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0"},
1642  {RPCResult::Type::NUM, "txrate", /*optional=*/true, "The average rate of transactions per second in the window. Only returned if \"window_interval\" is > 0"},
1643  }},
1644  RPCExamples{
1645  HelpExampleCli("getchaintxstats", "")
1646  + HelpExampleRpc("getchaintxstats", "2016")
1647  },
1648  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1649 {
1650  ChainstateManager& chainman = EnsureAnyChainman(request.context);
1651  const CBlockIndex* pindex;
1652  int blockcount = 30 * 24 * 60 * 60 / chainman.GetParams().GetConsensus().nPowTargetSpacing; // By default: 1 month
1653 
1654  if (request.params[1].isNull()) {
1655  LOCK(cs_main);
1656  pindex = chainman.ActiveChain().Tip();
1657  } else {
1658  uint256 hash(ParseHashV(request.params[1], "blockhash"));
1659  LOCK(cs_main);
1660  pindex = chainman.m_blockman.LookupBlockIndex(hash);
1661  if (!pindex) {
1662  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1663  }
1664  if (!chainman.ActiveChain().Contains(pindex)) {
1665  throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain");
1666  }
1667  }
1668 
1669  CHECK_NONFATAL(pindex != nullptr);
1670 
1671  if (request.params[0].isNull()) {
1672  blockcount = std::max(0, std::min(blockcount, pindex->nHeight - 1));
1673  } else {
1674  blockcount = request.params[0].getInt<int>();
1675 
1676  if (blockcount < 0 || (blockcount > 0 && blockcount >= pindex->nHeight)) {
1677  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 0 and the block's height - 1");
1678  }
1679  }
1680 
1681  const CBlockIndex& past_block{*CHECK_NONFATAL(pindex->GetAncestor(pindex->nHeight - blockcount))};
1682  const int64_t nTimeDiff{pindex->GetMedianTimePast() - past_block.GetMedianTimePast()};
1683  const int nTxDiff = pindex->nChainTx - past_block.nChainTx;
1684 
1686  ret.pushKV("time", (int64_t)pindex->nTime);
1687  ret.pushKV("txcount", (int64_t)pindex->nChainTx);
1688  ret.pushKV("window_final_block_hash", pindex->GetBlockHash().GetHex());
1689  ret.pushKV("window_final_block_height", pindex->nHeight);
1690  ret.pushKV("window_block_count", blockcount);
1691  if (blockcount > 0) {
1692  ret.pushKV("window_tx_count", nTxDiff);
1693  ret.pushKV("window_interval", nTimeDiff);
1694  if (nTimeDiff > 0) {
1695  ret.pushKV("txrate", ((double)nTxDiff) / nTimeDiff);
1696  }
1697  }
1698 
1699  return ret;
1700 },
1701  };
1702 }
1703 
1704 template<typename T>
1705 static T CalculateTruncatedMedian(std::vector<T>& scores)
1706 {
1707  size_t size = scores.size();
1708  if (size == 0) {
1709  return 0;
1710  }
1711 
1712  std::sort(scores.begin(), scores.end());
1713  if (size % 2 == 0) {
1714  return (scores[size / 2 - 1] + scores[size / 2]) / 2;
1715  } else {
1716  return scores[size / 2];
1717  }
1718 }
1719 
1720 void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight)
1721 {
1722  if (scores.empty()) {
1723  return;
1724  }
1725 
1726  std::sort(scores.begin(), scores.end());
1727 
1728  // 10th, 25th, 50th, 75th, and 90th percentile weight units.
1729  const double weights[NUM_GETBLOCKSTATS_PERCENTILES] = {
1730  total_weight / 10.0, total_weight / 4.0, total_weight / 2.0, (total_weight * 3.0) / 4.0, (total_weight * 9.0) / 10.0
1731  };
1732 
1733  int64_t next_percentile_index = 0;
1734  int64_t cumulative_weight = 0;
1735  for (const auto& element : scores) {
1736  cumulative_weight += element.second;
1737  while (next_percentile_index < NUM_GETBLOCKSTATS_PERCENTILES && cumulative_weight >= weights[next_percentile_index]) {
1738  result[next_percentile_index] = element.first;
1739  ++next_percentile_index;
1740  }
1741  }
1742 
1743  // Fill any remaining percentiles with the last value.
1744  for (int64_t i = next_percentile_index; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {
1745  result[i] = scores.back().first;
1746  }
1747 }
1748 
1749 template<typename T>
1750 static inline bool SetHasKeys(const std::set<T>& set) {return false;}
1751 template<typename T, typename Tk, typename... Args>
1752 static inline bool SetHasKeys(const std::set<T>& set, const Tk& key, const Args&... args)
1753 {
1754  return (set.count(key) != 0) || SetHasKeys(set, args...);
1755 }
1756 
1757 // outpoint (needed for the utxo index) + nHeight + fCoinBase
1758 static constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);
1759 
1761 {
1762  return RPCHelpMan{"getblockstats",
1763  "\nCompute per block statistics for a given window. All amounts are in satoshis.\n"
1764  "It won't work for some heights with pruning.\n",
1765  {
1766  {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block",
1767  RPCArgOptions{
1768  .skip_type_check = true,
1769  .type_str = {"", "string or numeric"},
1770  }},
1771  {"stats", RPCArg::Type::ARR, RPCArg::DefaultHint{"all values"}, "Values to plot (see result below)",
1772  {
1773  {"height", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
1774  {"time", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
1775  },
1777  },
1778  RPCResult{
1779  RPCResult::Type::OBJ, "", "",
1780  {
1781  {RPCResult::Type::NUM, "avgfee", /*optional=*/true, "Average fee in the block"},
1782  {RPCResult::Type::NUM, "avgfeerate", /*optional=*/true, "Average feerate (in satoshis per virtual byte)"},
1783  {RPCResult::Type::NUM, "avgtxsize", /*optional=*/true, "Average transaction size"},
1784  {RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "The block hash (to check for potential reorgs)"},
1785  {RPCResult::Type::ARR_FIXED, "feerate_percentiles", /*optional=*/true, "Feerates at the 10th, 25th, 50th, 75th, and 90th percentile weight unit (in satoshis per virtual byte)",
1786  {
1787  {RPCResult::Type::NUM, "10th_percentile_feerate", "The 10th percentile feerate"},
1788  {RPCResult::Type::NUM, "25th_percentile_feerate", "The 25th percentile feerate"},
1789  {RPCResult::Type::NUM, "50th_percentile_feerate", "The 50th percentile feerate"},
1790  {RPCResult::Type::NUM, "75th_percentile_feerate", "The 75th percentile feerate"},
1791  {RPCResult::Type::NUM, "90th_percentile_feerate", "The 90th percentile feerate"},
1792  }},
1793  {RPCResult::Type::NUM, "height", /*optional=*/true, "The height of the block"},
1794  {RPCResult::Type::NUM, "ins", /*optional=*/true, "The number of inputs (excluding coinbase)"},
1795  {RPCResult::Type::NUM, "maxfee", /*optional=*/true, "Maximum fee in the block"},
1796  {RPCResult::Type::NUM, "maxfeerate", /*optional=*/true, "Maximum feerate (in satoshis per virtual byte)"},
1797  {RPCResult::Type::NUM, "maxtxsize", /*optional=*/true, "Maximum transaction size"},
1798  {RPCResult::Type::NUM, "medianfee", /*optional=*/true, "Truncated median fee in the block"},
1799  {RPCResult::Type::NUM, "mediantime", /*optional=*/true, "The block median time past"},
1800  {RPCResult::Type::NUM, "mediantxsize", /*optional=*/true, "Truncated median transaction size"},
1801  {RPCResult::Type::NUM, "minfee", /*optional=*/true, "Minimum fee in the block"},
1802  {RPCResult::Type::NUM, "minfeerate", /*optional=*/true, "Minimum feerate (in satoshis per virtual byte)"},
1803  {RPCResult::Type::NUM, "mintxsize", /*optional=*/true, "Minimum transaction size"},
1804  {RPCResult::Type::NUM, "outs", /*optional=*/true, "The number of outputs"},
1805  {RPCResult::Type::NUM, "subsidy", /*optional=*/true, "The block subsidy"},
1806  {RPCResult::Type::NUM, "swtotal_size", /*optional=*/true, "Total size of all segwit transactions"},
1807  {RPCResult::Type::NUM, "swtotal_weight", /*optional=*/true, "Total weight of all segwit transactions"},
1808  {RPCResult::Type::NUM, "swtxs", /*optional=*/true, "The number of segwit transactions"},
1809  {RPCResult::Type::NUM, "time", /*optional=*/true, "The block time"},
1810  {RPCResult::Type::NUM, "total_out", /*optional=*/true, "Total amount in all outputs (excluding coinbase and thus reward [ie subsidy + totalfee])"},
1811  {RPCResult::Type::NUM, "total_size", /*optional=*/true, "Total size of all non-coinbase transactions"},
1812  {RPCResult::Type::NUM, "total_weight", /*optional=*/true, "Total weight of all non-coinbase transactions"},
1813  {RPCResult::Type::NUM, "totalfee", /*optional=*/true, "The fee total"},
1814  {RPCResult::Type::NUM, "txs", /*optional=*/true, "The number of transactions (including coinbase)"},
1815  {RPCResult::Type::NUM, "utxo_increase", /*optional=*/true, "The increase/decrease in the number of unspent outputs (not discounting op_return and similar)"},
1816  {RPCResult::Type::NUM, "utxo_size_inc", /*optional=*/true, "The increase/decrease in size for the utxo index (not discounting op_return and similar)"},
1817  {RPCResult::Type::NUM, "utxo_increase_actual", /*optional=*/true, "The increase/decrease in the number of unspent outputs, not counting unspendables"},
1818  {RPCResult::Type::NUM, "utxo_size_inc_actual", /*optional=*/true, "The increase/decrease in size for the utxo index, not counting unspendables"},
1819  }},
1820  RPCExamples{
1821  HelpExampleCli("getblockstats", R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
1822  HelpExampleCli("getblockstats", R"(1000 '["minfeerate","avgfeerate"]')") +
1823  HelpExampleRpc("getblockstats", R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") +
1824  HelpExampleRpc("getblockstats", R"(1000, ["minfeerate","avgfeerate"])")
1825  },
1826  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1827 {
1828  ChainstateManager& chainman = EnsureAnyChainman(request.context);
1829  const CBlockIndex& pindex{*CHECK_NONFATAL(ParseHashOrHeight(request.params[0], chainman))};
1830 
1831  std::set<std::string> stats;
1832  if (!request.params[1].isNull()) {
1833  const UniValue stats_univalue = request.params[1].get_array();
1834  for (unsigned int i = 0; i < stats_univalue.size(); i++) {
1835  const std::string stat = stats_univalue[i].get_str();
1836  stats.insert(stat);
1837  }
1838  }
1839 
1840  const CBlock& block = GetBlockChecked(chainman.m_blockman, pindex);
1841  const CBlockUndo& blockUndo = GetUndoChecked(chainman.m_blockman, pindex);
1842 
1843  const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default)
1844  const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0;
1845  const bool do_medianfee = do_all || stats.count("medianfee") != 0;
1846  const bool do_feerate_percentiles = do_all || stats.count("feerate_percentiles") != 0;
1847  const bool loop_inputs = do_all || do_medianfee || do_feerate_percentiles ||
1848  SetHasKeys(stats, "utxo_increase", "utxo_increase_actual", "utxo_size_inc", "utxo_size_inc_actual", "totalfee", "avgfee", "avgfeerate", "minfee", "maxfee", "minfeerate", "maxfeerate");
1849  const bool loop_outputs = do_all || loop_inputs || stats.count("total_out");
1850  const bool do_calculate_size = do_mediantxsize ||
1851  SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize", "maxtxsize", "swtotal_size");
1852  const bool do_calculate_weight = do_all || SetHasKeys(stats, "total_weight", "avgfeerate", "swtotal_weight", "avgfeerate", "feerate_percentiles", "minfeerate", "maxfeerate");
1853  const bool do_calculate_sw = do_all || SetHasKeys(stats, "swtxs", "swtotal_size", "swtotal_weight");
1854 
1855  CAmount maxfee = 0;
1856  CAmount maxfeerate = 0;
1857  CAmount minfee = MAX_MONEY;
1858  CAmount minfeerate = MAX_MONEY;
1859  CAmount total_out = 0;
1860  CAmount totalfee = 0;
1861  int64_t inputs = 0;
1862  int64_t maxtxsize = 0;
1863  int64_t mintxsize = MAX_BLOCK_SERIALIZED_SIZE;
1864  int64_t outputs = 0;
1865  int64_t swtotal_size = 0;
1866  int64_t swtotal_weight = 0;
1867  int64_t swtxs = 0;
1868  int64_t total_size = 0;
1869  int64_t total_weight = 0;
1870  int64_t utxos = 0;
1871  int64_t utxo_size_inc = 0;
1872  int64_t utxo_size_inc_actual = 0;
1873  std::vector<CAmount> fee_array;
1874  std::vector<std::pair<CAmount, int64_t>> feerate_array;
1875  std::vector<int64_t> txsize_array;
1876 
1877  for (size_t i = 0; i < block.vtx.size(); ++i) {
1878  const auto& tx = block.vtx.at(i);
1879  outputs += tx->vout.size();
1880 
1881  CAmount tx_total_out = 0;
1882  if (loop_outputs) {
1883  for (const CTxOut& out : tx->vout) {
1884  tx_total_out += out.nValue;
1885 
1886  size_t out_size = GetSerializeSize(out) + PER_UTXO_OVERHEAD;
1887  utxo_size_inc += out_size;
1888 
1889  // The Genesis block and the repeated BIP30 block coinbases don't change the UTXO
1890  // set counts, so they have to be excluded from the statistics
1891  if (pindex.nHeight == 0 || (IsBIP30Repeat(pindex) && tx->IsCoinBase())) continue;
1892  // Skip unspendable outputs since they are not included in the UTXO set
1893  if (out.scriptPubKey.IsUnspendable()) continue;
1894 
1895  ++utxos;
1896  utxo_size_inc_actual += out_size;
1897  }
1898  }
1899 
1900  if (tx->IsCoinBase()) {
1901  continue;
1902  }
1903 
1904  inputs += tx->vin.size(); // Don't count coinbase's fake input
1905  total_out += tx_total_out; // Don't count coinbase reward
1906 
1907  int64_t tx_size = 0;
1908  if (do_calculate_size) {
1909 
1910  tx_size = tx->GetTotalSize();
1911  if (do_mediantxsize) {
1912  txsize_array.push_back(tx_size);
1913  }
1914  maxtxsize = std::max(maxtxsize, tx_size);
1915  mintxsize = std::min(mintxsize, tx_size);
1916  total_size += tx_size;
1917  }
1918 
1919  int64_t weight = 0;
1920  if (do_calculate_weight) {
1921  weight = GetTransactionWeight(*tx);
1922  total_weight += weight;
1923  }
1924 
1925  if (do_calculate_sw && tx->HasWitness()) {
1926  ++swtxs;
1927  swtotal_size += tx_size;
1928  swtotal_weight += weight;
1929  }
1930 
1931  if (loop_inputs) {
1932  CAmount tx_total_in = 0;
1933  const auto& txundo = blockUndo.vtxundo.at(i - 1);
1934  for (const Coin& coin: txundo.vprevout) {
1935  const CTxOut& prevoutput = coin.out;
1936 
1937  tx_total_in += prevoutput.nValue;
1938  size_t prevout_size = GetSerializeSize(prevoutput) + PER_UTXO_OVERHEAD;
1939  utxo_size_inc -= prevout_size;
1940  utxo_size_inc_actual -= prevout_size;
1941  }
1942 
1943  CAmount txfee = tx_total_in - tx_total_out;
1944  CHECK_NONFATAL(MoneyRange(txfee));
1945  if (do_medianfee) {
1946  fee_array.push_back(txfee);
1947  }
1948  maxfee = std::max(maxfee, txfee);
1949  minfee = std::min(minfee, txfee);
1950  totalfee += txfee;
1951 
1952  // New feerate uses satoshis per virtual byte instead of per serialized byte
1953  CAmount feerate = weight ? (txfee * WITNESS_SCALE_FACTOR) / weight : 0;
1954  if (do_feerate_percentiles) {
1955  feerate_array.emplace_back(feerate, weight);
1956  }
1957  maxfeerate = std::max(maxfeerate, feerate);
1958  minfeerate = std::min(minfeerate, feerate);
1959  }
1960  }
1961 
1962  CAmount feerate_percentiles[NUM_GETBLOCKSTATS_PERCENTILES] = { 0 };
1963  CalculatePercentilesByWeight(feerate_percentiles, feerate_array, total_weight);
1964 
1965  UniValue feerates_res(UniValue::VARR);
1966  for (int64_t i = 0; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {
1967  feerates_res.push_back(feerate_percentiles[i]);
1968  }
1969 
1970  UniValue ret_all(UniValue::VOBJ);
1971  ret_all.pushKV("avgfee", (block.vtx.size() > 1) ? totalfee / (block.vtx.size() - 1) : 0);
1972  ret_all.pushKV("avgfeerate", total_weight ? (totalfee * WITNESS_SCALE_FACTOR) / total_weight : 0); // Unit: sat/vbyte
1973  ret_all.pushKV("avgtxsize", (block.vtx.size() > 1) ? total_size / (block.vtx.size() - 1) : 0);
1974  ret_all.pushKV("blockhash", pindex.GetBlockHash().GetHex());
1975  ret_all.pushKV("feerate_percentiles", feerates_res);
1976  ret_all.pushKV("height", (int64_t)pindex.nHeight);
1977  ret_all.pushKV("ins", inputs);
1978  ret_all.pushKV("maxfee", maxfee);
1979  ret_all.pushKV("maxfeerate", maxfeerate);
1980  ret_all.pushKV("maxtxsize", maxtxsize);
1981  ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
1982  ret_all.pushKV("mediantime", pindex.GetMedianTimePast());
1983  ret_all.pushKV("mediantxsize", CalculateTruncatedMedian(txsize_array));
1984  ret_all.pushKV("minfee", (minfee == MAX_MONEY) ? 0 : minfee);
1985  ret_all.pushKV("minfeerate", (minfeerate == MAX_MONEY) ? 0 : minfeerate);
1986  ret_all.pushKV("mintxsize", mintxsize == MAX_BLOCK_SERIALIZED_SIZE ? 0 : mintxsize);
1987  ret_all.pushKV("outs", outputs);
1988  ret_all.pushKV("subsidy", GetBlockSubsidy(pindex.nHeight, chainman.GetParams().GetConsensus()));
1989  ret_all.pushKV("swtotal_size", swtotal_size);
1990  ret_all.pushKV("swtotal_weight", swtotal_weight);
1991  ret_all.pushKV("swtxs", swtxs);
1992  ret_all.pushKV("time", pindex.GetBlockTime());
1993  ret_all.pushKV("total_out", total_out);
1994  ret_all.pushKV("total_size", total_size);
1995  ret_all.pushKV("total_weight", total_weight);
1996  ret_all.pushKV("totalfee", totalfee);
1997  ret_all.pushKV("txs", (int64_t)block.vtx.size());
1998  ret_all.pushKV("utxo_increase", outputs - inputs);
1999  ret_all.pushKV("utxo_size_inc", utxo_size_inc);
2000  ret_all.pushKV("utxo_increase_actual", utxos - inputs);
2001  ret_all.pushKV("utxo_size_inc_actual", utxo_size_inc_actual);
2002 
2003  if (do_all) {
2004  return ret_all;
2005  }
2006 
2008  for (const std::string& stat : stats) {
2009  const UniValue& value = ret_all[stat];
2010  if (value.isNull()) {
2011  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid selected statistic '%s'", stat));
2012  }
2013  ret.pushKV(stat, value);
2014  }
2015  return ret;
2016 },
2017  };
2018 }
2019 
2020 namespace {
2022 bool FindScriptPubKey(std::atomic<int>& scan_progress, const std::atomic<bool>& should_abort, int64_t& count, CCoinsViewCursor* cursor, const std::set<CScript>& needles, std::map<COutPoint, Coin>& out_results, std::function<void()>& interruption_point)
2023 {
2024  scan_progress = 0;
2025  count = 0;
2026  while (cursor->Valid()) {
2027  COutPoint key;
2028  Coin coin;
2029  if (!cursor->GetKey(key) || !cursor->GetValue(coin)) return false;
2030  if (++count % 8192 == 0) {
2031  interruption_point();
2032  if (should_abort) {
2033  // allow to abort the scan via the abort reference
2034  return false;
2035  }
2036  }
2037  if (count % 256 == 0) {
2038  // update progress reference every 256 item
2039  uint32_t high = 0x100 * *UCharCast(key.hash.begin()) + *(UCharCast(key.hash.begin()) + 1);
2040  scan_progress = (int)(high * 100.0 / 65536.0 + 0.5);
2041  }
2042  if (needles.count(coin.out.scriptPubKey)) {
2043  out_results.emplace(key, coin);
2044  }
2045  cursor->Next();
2046  }
2047  scan_progress = 100;
2048  return true;
2049 }
2050 } // namespace
2051 
2053 static std::atomic<int> g_scan_progress;
2054 static std::atomic<bool> g_scan_in_progress;
2055 static std::atomic<bool> g_should_abort_scan;
2057 {
2058 private:
2059  bool m_could_reserve{false};
2060 public:
2061  explicit CoinsViewScanReserver() = default;
2062 
2063  bool reserve() {
2065  if (g_scan_in_progress.exchange(true)) {
2066  return false;
2067  }
2069  m_could_reserve = true;
2070  return true;
2071  }
2072 
2074  if (m_could_reserve) {
2075  g_scan_in_progress = false;
2076  g_scan_progress = 0;
2077  }
2078  }
2079 };
2080 
2081 static const auto scan_action_arg_desc = RPCArg{
2082  "action", RPCArg::Type::STR, RPCArg::Optional::NO, "The action to execute\n"
2083  "\"start\" for starting a scan\n"
2084  "\"abort\" for aborting the current scan (returns true when abort was successful)\n"
2085  "\"status\" for progress report (in %) of the current scan"
2086 };
2087 
2088 static const auto scan_objects_arg_desc = RPCArg{
2089  "scanobjects", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "Array of scan objects. Required for \"start\" action\n"
2090  "Every scan object is either a string descriptor or an object:",
2091  {
2092  {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
2093  {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with output descriptor and metadata",
2094  {
2095  {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
2096  {"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "The range of HD chain indexes to explore (either end or [begin,end])"},
2097  }},
2098  },
2099  RPCArgOptions{.oneline_description="[scanobjects,...]"},
2100 };
2101 
2102 static const auto scan_result_abort = RPCResult{
2103  "when action=='abort'", RPCResult::Type::BOOL, "success",
2104  "True if scan will be aborted (not necessarily before this RPC returns), or false if there is no scan to abort"
2105 };
2107  "when action=='status' and no scan is in progress - possibly already completed", RPCResult::Type::NONE, "", ""
2108 };
2110  "when action=='status' and a scan is currently in progress", RPCResult::Type::OBJ, "", "",
2111  {{RPCResult::Type::NUM, "progress", "Approximate percent complete"},}
2112 };
2113 
2114 
2116 {
2117  // scriptPubKey corresponding to mainnet address 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S
2118  const std::string EXAMPLE_DESCRIPTOR_RAW = "raw(76a91411b366edfc0a8b66feebae5c2e25a7b6a5d1cf3188ac)#fm24fxxy";
2119 
2120  return RPCHelpMan{"scantxoutset",
2121  "\nScans the unspent transaction output set for entries that match certain output descriptors.\n"
2122  "Examples of output descriptors are:\n"
2123  " addr(<address>) Outputs whose scriptPubKey corresponds to the specified address (does not include P2PK)\n"
2124  " raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts\n"
2125  " combo(<pubkey>) P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH outputs for the given pubkey\n"
2126  " pkh(<pubkey>) P2PKH outputs for the given pubkey\n"
2127  " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n"
2128  " tr(<pubkey>) P2TR\n"
2129  " tr(<pubkey>,{pk(<pubkey>)}) P2TR with single fallback pubkey in tapscript\n"
2130  " rawtr(<pubkey>) P2TR with the specified key as output key rather than inner\n"
2131  " wsh(and_v(v:pk(<pubkey>),after(2))) P2WSH miniscript with mandatory pubkey and a timelock\n"
2132  "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
2133  "or more path elements separated by \"/\", and optionally ending in \"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
2134  "unhardened or hardened child keys.\n"
2135  "In the latter case, a range needs to be specified by below if different from 1000.\n"
2136  "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n",
2137  {
2140  },
2141  {
2142  RPCResult{"when action=='start'; only returns after scan completes", RPCResult::Type::OBJ, "", "", {
2143  {RPCResult::Type::BOOL, "success", "Whether the scan was completed"},
2144  {RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs scanned"},
2145  {RPCResult::Type::NUM, "height", "The current block height (index)"},
2146  {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
2147  {RPCResult::Type::ARR, "unspents", "",
2148  {
2149  {RPCResult::Type::OBJ, "", "",
2150  {
2151  {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
2152  {RPCResult::Type::NUM, "vout", "The vout value"},
2153  {RPCResult::Type::STR_HEX, "scriptPubKey", "The script key"},
2154  {RPCResult::Type::STR, "desc", "A specialized descriptor for the matched scriptPubKey"},
2155  {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the unspent output"},
2156  {RPCResult::Type::BOOL, "coinbase", "Whether this is a coinbase output"},
2157  {RPCResult::Type::NUM, "height", "Height of the unspent transaction output"},
2158  }},
2159  }},
2160  {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of all found unspent outputs in " + CURRENCY_UNIT},
2161  }},
2165  },
2166  RPCExamples{
2167  HelpExampleCli("scantxoutset", "start \'[\"" + EXAMPLE_DESCRIPTOR_RAW + "\"]\'") +
2168  HelpExampleCli("scantxoutset", "status") +
2169  HelpExampleCli("scantxoutset", "abort") +
2170  HelpExampleRpc("scantxoutset", "\"start\", [\"" + EXAMPLE_DESCRIPTOR_RAW + "\"]") +
2171  HelpExampleRpc("scantxoutset", "\"status\"") +
2172  HelpExampleRpc("scantxoutset", "\"abort\"")
2173  },
2174  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2175 {
2176  UniValue result(UniValue::VOBJ);
2177  if (request.params[0].get_str() == "status") {
2178  CoinsViewScanReserver reserver;
2179  if (reserver.reserve()) {
2180  // no scan in progress
2181  return UniValue::VNULL;
2182  }
2183  result.pushKV("progress", g_scan_progress.load());
2184  return result;
2185  } else if (request.params[0].get_str() == "abort") {
2186  CoinsViewScanReserver reserver;
2187  if (reserver.reserve()) {
2188  // reserve was possible which means no scan was running
2189  return false;
2190  }
2191  // set the abort flag
2192  g_should_abort_scan = true;
2193  return true;
2194  } else if (request.params[0].get_str() == "start") {
2195  CoinsViewScanReserver reserver;
2196  if (!reserver.reserve()) {
2197  throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
2198  }
2199 
2200  if (request.params.size() < 2) {
2201  throw JSONRPCError(RPC_MISC_ERROR, "scanobjects argument is required for the start action");
2202  }
2203 
2204  std::set<CScript> needles;
2205  std::map<CScript, std::string> descriptors;
2206  CAmount total_in = 0;
2207 
2208  // loop through the scan objects
2209  for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
2210  FlatSigningProvider provider;
2211  auto scripts = EvalDescriptorStringOrObject(scanobject, provider);
2212  for (CScript& script : scripts) {
2213  std::string inferred = InferDescriptor(script, provider)->ToString();
2214  needles.emplace(script);
2215  descriptors.emplace(std::move(script), std::move(inferred));
2216  }
2217  }
2218 
2219  // Scan the unspent transaction output set for inputs
2220  UniValue unspents(UniValue::VARR);
2221  std::vector<CTxOut> input_txos;
2222  std::map<COutPoint, Coin> coins;
2223  g_should_abort_scan = false;
2224  int64_t count = 0;
2225  std::unique_ptr<CCoinsViewCursor> pcursor;
2226  const CBlockIndex* tip;
2227  NodeContext& node = EnsureAnyNodeContext(request.context);
2228  {
2229  ChainstateManager& chainman = EnsureChainman(node);
2230  LOCK(cs_main);
2231  Chainstate& active_chainstate = chainman.ActiveChainstate();
2232  active_chainstate.ForceFlushStateToDisk();
2233  pcursor = CHECK_NONFATAL(active_chainstate.CoinsDB().Cursor());
2234  tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
2235  }
2236  bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins, node.rpc_interruption_point);
2237  result.pushKV("success", res);
2238  result.pushKV("txouts", count);
2239  result.pushKV("height", tip->nHeight);
2240  result.pushKV("bestblock", tip->GetBlockHash().GetHex());
2241 
2242  for (const auto& it : coins) {
2243  const COutPoint& outpoint = it.first;
2244  const Coin& coin = it.second;
2245  const CTxOut& txo = coin.out;
2246  input_txos.push_back(txo);
2247  total_in += txo.nValue;
2248 
2249  UniValue unspent(UniValue::VOBJ);
2250  unspent.pushKV("txid", outpoint.hash.GetHex());
2251  unspent.pushKV("vout", (int32_t)outpoint.n);
2252  unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
2253  unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
2254  unspent.pushKV("amount", ValueFromAmount(txo.nValue));
2255  unspent.pushKV("coinbase", coin.IsCoinBase());
2256  unspent.pushKV("height", (int32_t)coin.nHeight);
2257 
2258  unspents.push_back(unspent);
2259  }
2260  result.pushKV("unspents", unspents);
2261  result.pushKV("total_amount", ValueFromAmount(total_in));
2262  } else {
2263  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid action '%s'", request.params[0].get_str()));
2264  }
2265  return result;
2266 },
2267  };
2268 }
2269 
2271 static std::atomic<int> g_scanfilter_progress;
2272 static std::atomic<int> g_scanfilter_progress_height;
2273 static std::atomic<bool> g_scanfilter_in_progress;
2274 static std::atomic<bool> g_scanfilter_should_abort_scan;
2276 {
2277 private:
2278  bool m_could_reserve{false};
2279 public:
2280  explicit BlockFiltersScanReserver() = default;
2281 
2282  bool reserve() {
2284  if (g_scanfilter_in_progress.exchange(true)) {
2285  return false;
2286  }
2287  m_could_reserve = true;
2288  return true;
2289  }
2290 
2292  if (m_could_reserve) {
2293  g_scanfilter_in_progress = false;
2294  }
2295  }
2296 };
2297 
2298 static bool CheckBlockFilterMatches(BlockManager& blockman, const CBlockIndex& blockindex, const GCSFilter::ElementSet& needles)
2299 {
2300  const CBlock block{GetBlockChecked(blockman, blockindex)};
2301  const CBlockUndo block_undo{GetUndoChecked(blockman, blockindex)};
2302 
2303  // Check if any of the outputs match the scriptPubKey
2304  for (const auto& tx : block.vtx) {
2305  if (std::any_of(tx->vout.cbegin(), tx->vout.cend(), [&](const auto& txout) {
2306  return needles.count(std::vector<unsigned char>(txout.scriptPubKey.begin(), txout.scriptPubKey.end())) != 0;
2307  })) {
2308  return true;
2309  }
2310  }
2311  // Check if any of the inputs match the scriptPubKey
2312  for (const auto& txundo : block_undo.vtxundo) {
2313  if (std::any_of(txundo.vprevout.cbegin(), txundo.vprevout.cend(), [&](const auto& coin) {
2314  return needles.count(std::vector<unsigned char>(coin.out.scriptPubKey.begin(), coin.out.scriptPubKey.end())) != 0;
2315  })) {
2316  return true;
2317  }
2318  }
2319 
2320  return false;
2321 }
2322 
2324 {
2325  return RPCHelpMan{"scanblocks",
2326  "\nReturn relevant blockhashes for given descriptors (requires blockfilterindex).\n"
2327  "This call may take several minutes. Make sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
2328  {
2331  RPCArg{"start_height", RPCArg::Type::NUM, RPCArg::Default{0}, "Height to start to scan from"},
2332  RPCArg{"stop_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"chain tip"}, "Height to stop to scan"},
2333  RPCArg{"filtertype", RPCArg::Type::STR, RPCArg::Default{BlockFilterTypeName(BlockFilterType::BASIC)}, "The type name of the filter"},
2335  {
2336  {"filter_false_positives", RPCArg::Type::BOOL, RPCArg::Default{false}, "Filter false positives (slower and may fail on pruned nodes). Otherwise they may occur at a rate of 1/M"},
2337  },
2338  RPCArgOptions{.oneline_description="options"}},
2339  },
2340  {
2342  RPCResult{"When action=='start'; only returns after scan completes", RPCResult::Type::OBJ, "", "", {
2343  {RPCResult::Type::NUM, "from_height", "The height we started the scan from"},
2344  {RPCResult::Type::NUM, "to_height", "The height we ended the scan at"},
2345  {RPCResult::Type::ARR, "relevant_blocks", "Blocks that may have matched a scanobject.", {
2346  {RPCResult::Type::STR_HEX, "blockhash", "A relevant blockhash"},
2347  }},
2348  {RPCResult::Type::BOOL, "completed", "true if the scan process was not aborted"}
2349  }},
2350  RPCResult{"when action=='status' and a scan is currently in progress", RPCResult::Type::OBJ, "", "", {
2351  {RPCResult::Type::NUM, "progress", "Approximate percent complete"},
2352  {RPCResult::Type::NUM, "current_height", "Height of the block currently being scanned"},
2353  },
2354  },
2356  },
2357  RPCExamples{
2358  HelpExampleCli("scanblocks", "start '[\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"]' 300000") +
2359  HelpExampleCli("scanblocks", "start '[\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"]' 100 150 basic") +
2360  HelpExampleCli("scanblocks", "status") +
2361  HelpExampleRpc("scanblocks", "\"start\", [\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"], 300000") +
2362  HelpExampleRpc("scanblocks", "\"start\", [\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"], 100, 150, \"basic\"") +
2363  HelpExampleRpc("scanblocks", "\"status\"")
2364  },
2365  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2366 {
2368  if (request.params[0].get_str() == "status") {
2369  BlockFiltersScanReserver reserver;
2370  if (reserver.reserve()) {
2371  // no scan in progress
2372  return NullUniValue;
2373  }
2374  ret.pushKV("progress", g_scanfilter_progress.load());
2375  ret.pushKV("current_height", g_scanfilter_progress_height.load());
2376  return ret;
2377  } else if (request.params[0].get_str() == "abort") {
2378  BlockFiltersScanReserver reserver;
2379  if (reserver.reserve()) {
2380  // reserve was possible which means no scan was running
2381  return false;
2382  }
2383  // set the abort flag
2385  return true;
2386  } else if (request.params[0].get_str() == "start") {
2387  BlockFiltersScanReserver reserver;
2388  if (!reserver.reserve()) {
2389  throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
2390  }
2391  const std::string filtertype_name{request.params[4].isNull() ? "basic" : request.params[4].get_str()};
2392 
2393  BlockFilterType filtertype;
2394  if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2395  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown filtertype");
2396  }
2397 
2398  UniValue options{request.params[5].isNull() ? UniValue::VOBJ : request.params[5]};
2399  bool filter_false_positives{options.exists("filter_false_positives") ? options["filter_false_positives"].get_bool() : false};
2400 
2401  BlockFilterIndex* index = GetBlockFilterIndex(filtertype);
2402  if (!index) {
2403  throw JSONRPCError(RPC_MISC_ERROR, "Index is not enabled for filtertype " + filtertype_name);
2404  }
2405 
2406  NodeContext& node = EnsureAnyNodeContext(request.context);
2407  ChainstateManager& chainman = EnsureChainman(node);
2408 
2409  // set the start-height
2410  const CBlockIndex* start_index = nullptr;
2411  const CBlockIndex* stop_block = nullptr;
2412  {
2413  LOCK(cs_main);
2414  CChain& active_chain = chainman.ActiveChain();
2415  start_index = active_chain.Genesis();
2416  stop_block = active_chain.Tip(); // If no stop block is provided, stop at the chain tip.
2417  if (!request.params[2].isNull()) {
2418  start_index = active_chain[request.params[2].getInt<int>()];
2419  if (!start_index) {
2420  throw JSONRPCError(RPC_MISC_ERROR, "Invalid start_height");
2421  }
2422  }
2423  if (!request.params[3].isNull()) {
2424  stop_block = active_chain[request.params[3].getInt<int>()];
2425  if (!stop_block || stop_block->nHeight < start_index->nHeight) {
2426  throw JSONRPCError(RPC_MISC_ERROR, "Invalid stop_height");
2427  }
2428  }
2429  }
2430  CHECK_NONFATAL(start_index);
2431  CHECK_NONFATAL(stop_block);
2432 
2433  // loop through the scan objects, add scripts to the needle_set
2434  GCSFilter::ElementSet needle_set;
2435  for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
2436  FlatSigningProvider provider;
2437  std::vector<CScript> scripts = EvalDescriptorStringOrObject(scanobject, provider);
2438  for (const CScript& script : scripts) {
2439  needle_set.emplace(script.begin(), script.end());
2440  }
2441  }
2442  UniValue blocks(UniValue::VARR);
2443  const int amount_per_chunk = 10000;
2444  std::vector<BlockFilter> filters;
2445  int start_block_height = start_index->nHeight; // for progress reporting
2446  const int total_blocks_to_process = stop_block->nHeight - start_block_height;
2447 
2450  g_scanfilter_progress_height = start_block_height;
2451  bool completed = true;
2452 
2453  const CBlockIndex* end_range = nullptr;
2454  do {
2455  node.rpc_interruption_point(); // allow a clean shutdown
2457  completed = false;
2458  break;
2459  }
2460 
2461  // split the lookup range in chunks if we are deeper than 'amount_per_chunk' blocks from the stopping block
2462  int start_block = !end_range ? start_index->nHeight : start_index->nHeight + 1; // to not include the previous round 'end_range' block
2463  end_range = (start_block + amount_per_chunk < stop_block->nHeight) ?
2464  WITH_LOCK(::cs_main, return chainman.ActiveChain()[start_block + amount_per_chunk]) :
2465  stop_block;
2466 
2467  if (index->LookupFilterRange(start_block, end_range, filters)) {
2468  for (const BlockFilter& filter : filters) {
2469  // compare the elements-set with each filter
2470  if (filter.GetFilter().MatchAny(needle_set)) {
2471  if (filter_false_positives) {
2472  // Double check the filter matches by scanning the block
2473  const CBlockIndex& blockindex = *CHECK_NONFATAL(WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(filter.GetBlockHash())));
2474 
2475  if (!CheckBlockFilterMatches(chainman.m_blockman, blockindex, needle_set)) {
2476  continue;
2477  }
2478  }
2479 
2480  blocks.push_back(filter.GetBlockHash().GetHex());
2481  }
2482  }
2483  }
2484  start_index = end_range;
2485 
2486  // update progress
2487  int blocks_processed = end_range->nHeight - start_block_height;
2488  if (total_blocks_to_process > 0) { // avoid division by zero
2489  g_scanfilter_progress = (int)(100.0 / total_blocks_to_process * blocks_processed);
2490  } else {
2491  g_scanfilter_progress = 100;
2492  }
2494 
2495  // Finish if we reached the stop block
2496  } while (start_index != stop_block);
2497 
2498  ret.pushKV("from_height", start_block_height);
2499  ret.pushKV("to_height", start_index->nHeight); // start_index is always the last scanned block here
2500  ret.pushKV("relevant_blocks", blocks);
2501  ret.pushKV("completed", completed);
2502  }
2503  else {
2504  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid action '%s'", request.params[0].get_str()));
2505  }
2506  return ret;
2507 },
2508  };
2509 }
2510 
2512 {
2513  return RPCHelpMan{"getblockfilter",
2514  "\nRetrieve a BIP 157 content filter for a particular block.\n",
2515  {
2516  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hash of the block"},
2517  {"filtertype", RPCArg::Type::STR, RPCArg::Default{BlockFilterTypeName(BlockFilterType::BASIC)}, "The type name of the filter"},
2518  },
2519  RPCResult{
2520  RPCResult::Type::OBJ, "", "",
2521  {
2522  {RPCResult::Type::STR_HEX, "filter", "the hex-encoded filter data"},
2523  {RPCResult::Type::STR_HEX, "header", "the hex-encoded filter header"},
2524  }},
2525  RPCExamples{
2526  HelpExampleCli("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" \"basic\"") +
2527  HelpExampleRpc("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\", \"basic\"")
2528  },
2529  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2530 {
2531  uint256 block_hash = ParseHashV(request.params[0], "blockhash");
2532  std::string filtertype_name = BlockFilterTypeName(BlockFilterType::BASIC);
2533  if (!request.params[1].isNull()) {
2534  filtertype_name = request.params[1].get_str();
2535  }
2536 
2537  BlockFilterType filtertype;
2538  if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2539  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown filtertype");
2540  }
2541 
2542  BlockFilterIndex* index = GetBlockFilterIndex(filtertype);
2543  if (!index) {
2544  throw JSONRPCError(RPC_MISC_ERROR, "Index is not enabled for filtertype " + filtertype_name);
2545  }
2546 
2547  const CBlockIndex* block_index;
2548  bool block_was_connected;
2549  {
2550  ChainstateManager& chainman = EnsureAnyChainman(request.context);
2551  LOCK(cs_main);
2552  block_index = chainman.m_blockman.LookupBlockIndex(block_hash);
2553  if (!block_index) {
2554  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
2555  }
2556  block_was_connected = block_index->IsValid(BLOCK_VALID_SCRIPTS);
2557  }
2558 
2559  bool index_ready = index->BlockUntilSyncedToCurrentChain();
2560 
2561  BlockFilter filter;
2562  uint256 filter_header;
2563  if (!index->LookupFilter(block_index, filter) ||
2564  !index->LookupFilterHeader(block_index, filter_header)) {
2565  int err_code;
2566  std::string errmsg = "Filter not found.";
2567 
2568  if (!block_was_connected) {
2569  err_code = RPC_INVALID_ADDRESS_OR_KEY;
2570  errmsg += " Block was not connected to active chain.";
2571  } else if (!index_ready) {
2572  err_code = RPC_MISC_ERROR;
2573  errmsg += " Block filters are still in the process of being indexed.";
2574  } else {
2575  err_code = RPC_INTERNAL_ERROR;
2576  errmsg += " This error is unexpected and indicates index corruption.";
2577  }
2578 
2579  throw JSONRPCError(err_code, errmsg);
2580  }
2581 
2583  ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
2584  ret.pushKV("header", filter_header.GetHex());
2585  return ret;
2586 },
2587  };
2588 }
2589 
2596 {
2597  return RPCHelpMan{
2598  "dumptxoutset",
2599  "Write the serialized UTXO set to a file.",
2600  {
2601  {"path", RPCArg::Type::STR, RPCArg::Optional::NO, "Path to the output file. If relative, will be prefixed by datadir."},
2602  },
2603  RPCResult{
2604  RPCResult::Type::OBJ, "", "",
2605  {
2606  {RPCResult::Type::NUM, "coins_written", "the number of coins written in the snapshot"},
2607  {RPCResult::Type::STR_HEX, "base_hash", "the hash of the base of the snapshot"},
2608  {RPCResult::Type::NUM, "base_height", "the height of the base of the snapshot"},
2609  {RPCResult::Type::STR, "path", "the absolute path that the snapshot was written to"},
2610  {RPCResult::Type::STR_HEX, "txoutset_hash", "the hash of the UTXO set contents"},
2611  {RPCResult::Type::NUM, "nchaintx", "the number of transactions in the chain up to and including the base block"},
2612  }
2613  },
2614  RPCExamples{
2615  HelpExampleCli("dumptxoutset", "utxo.dat")
2616  },
2617  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2618 {
2619  const ArgsManager& args{EnsureAnyArgsman(request.context)};
2620  const fs::path path = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(request.params[0].get_str()));
2621  // Write to a temporary path and then move into `path` on completion
2622  // to avoid confusion due to an interruption.
2623  const fs::path temppath = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(request.params[0].get_str() + ".incomplete"));
2624 
2625  if (fs::exists(path)) {
2626  throw JSONRPCError(
2628  path.utf8string() + " already exists. If you are sure this is what you want, "
2629  "move it out of the way first");
2630  }
2631 
2632  FILE* file{fsbridge::fopen(temppath, "wb")};
2633  AutoFile afile{file};
2634  if (afile.IsNull()) {
2635  throw JSONRPCError(
2637  "Couldn't open file " + temppath.utf8string() + " for writing.");
2638  }
2639 
2640  NodeContext& node = EnsureAnyNodeContext(request.context);
2641  UniValue result = CreateUTXOSnapshot(
2642  node, node.chainman->ActiveChainstate(), afile, path, temppath);
2643  fs::rename(temppath, path);
2644 
2645  result.pushKV("path", path.utf8string());
2646  return result;
2647 },
2648  };
2649 }
2650 
2652  NodeContext& node,
2653  Chainstate& chainstate,
2654  AutoFile& afile,
2655  const fs::path& path,
2656  const fs::path& temppath)
2657 {
2658  std::unique_ptr<CCoinsViewCursor> pcursor;
2659  std::optional<CCoinsStats> maybe_stats;
2660  const CBlockIndex* tip;
2661 
2662  {
2663  // We need to lock cs_main to ensure that the coinsdb isn't written to
2664  // between (i) flushing coins cache to disk (coinsdb), (ii) getting stats
2665  // based upon the coinsdb, and (iii) constructing a cursor to the
2666  // coinsdb for use below this block.
2667  //
2668  // Cursors returned by leveldb iterate over snapshots, so the contents
2669  // of the pcursor will not be affected by simultaneous writes during
2670  // use below this block.
2671  //
2672  // See discussion here:
2673  // https://github.com/bitcoin/bitcoin/pull/15606#discussion_r274479369
2674  //
2675  LOCK(::cs_main);
2676 
2677  chainstate.ForceFlushStateToDisk();
2678 
2679  maybe_stats = GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman, CoinStatsHashType::HASH_SERIALIZED, node.rpc_interruption_point);
2680  if (!maybe_stats) {
2681  throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
2682  }
2683 
2684  pcursor = chainstate.CoinsDB().Cursor();
2685  tip = CHECK_NONFATAL(chainstate.m_blockman.LookupBlockIndex(maybe_stats->hashBlock));
2686  }
2687 
2688  LOG_TIME_SECONDS(strprintf("writing UTXO snapshot at height %s (%s) to file %s (via %s)",
2689  tip->nHeight, tip->GetBlockHash().ToString(),
2690  fs::PathToString(path), fs::PathToString(temppath)));
2691 
2692  SnapshotMetadata metadata{tip->GetBlockHash(), maybe_stats->coins_count};
2693 
2694  afile << metadata;
2695 
2696  COutPoint key;
2697  Coin coin;
2698  unsigned int iter{0};
2699 
2700  while (pcursor->Valid()) {
2701  if (iter % 5000 == 0) node.rpc_interruption_point();
2702  ++iter;
2703  if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
2704  afile << key;
2705  afile << coin;
2706  }
2707 
2708  pcursor->Next();
2709  }
2710 
2711  afile.fclose();
2712 
2713  UniValue result(UniValue::VOBJ);
2714  result.pushKV("coins_written", maybe_stats->coins_count);
2715  result.pushKV("base_hash", tip->GetBlockHash().ToString());
2716  result.pushKV("base_height", tip->nHeight);
2717  result.pushKV("path", path.utf8string());
2718  result.pushKV("txoutset_hash", maybe_stats->hashSerialized.ToString());
2719  result.pushKV("nchaintx", tip->nChainTx);
2720  return result;
2721 }
2722 
2724 {
2725  return RPCHelpMan{
2726  "loadtxoutset",
2727  "Load the serialized UTXO set from a file.\n"
2728  "Once this snapshot is loaded, its contents will be "
2729  "deserialized into a second chainstate data structure, which is then used to sync to "
2730  "the network's tip. "
2731  "Meanwhile, the original chainstate will complete the initial block download process in "
2732  "the background, eventually validating up to the block that the snapshot is based upon.\n\n"
2733 
2734  "The result is a usable bitcoind instance that is current with the network tip in a "
2735  "matter of minutes rather than hours. UTXO snapshot are typically obtained from "
2736  "third-party sources (HTTP, torrent, etc.) which is reasonable since their "
2737  "contents are always checked by hash.\n\n"
2738 
2739  "You can find more information on this process in the `assumeutxo` design "
2740  "document (<https://github.com/bitcoin/bitcoin/blob/master/doc/design/assumeutxo.md>).",
2741  {
2742  {"path",
2745  "path to the snapshot file. If relative, will be prefixed by datadir."},
2746  },
2747  RPCResult{
2748  RPCResult::Type::OBJ, "", "",
2749  {
2750  {RPCResult::Type::NUM, "coins_loaded", "the number of coins loaded from the snapshot"},
2751  {RPCResult::Type::STR_HEX, "tip_hash", "the hash of the base of the snapshot"},
2752  {RPCResult::Type::NUM, "base_height", "the height of the base of the snapshot"},
2753  {RPCResult::Type::STR, "path", "the absolute path that the snapshot was loaded from"},
2754  }
2755  },
2756  RPCExamples{
2757  HelpExampleCli("loadtxoutset", "utxo.dat")
2758  },
2759  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2760 {
2761  NodeContext& node = EnsureAnyNodeContext(request.context);
2762  ChainstateManager& chainman = EnsureChainman(node);
2763  fs::path path{AbsPathForConfigVal(EnsureArgsman(node), fs::u8path(request.params[0].get_str()))};
2764 
2765  FILE* file{fsbridge::fopen(path, "rb")};
2766  AutoFile afile{file};
2767  if (afile.IsNull()) {
2768  throw JSONRPCError(
2770  "Couldn't open file " + path.utf8string() + " for reading.");
2771  }
2772 
2773  SnapshotMetadata metadata;
2774  afile >> metadata;
2775 
2776  uint256 base_blockhash = metadata.m_base_blockhash;
2777  if (!chainman.GetParams().AssumeutxoForBlockhash(base_blockhash).has_value()) {
2778  throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to load UTXO snapshot, "
2779  "assumeutxo block hash in snapshot metadata not recognized (%s)", base_blockhash.ToString()));
2780  }
2781  CBlockIndex* snapshot_start_block = WITH_LOCK(::cs_main,
2782  return chainman.m_blockman.LookupBlockIndex(base_blockhash));
2783 
2784  if (!snapshot_start_block) {
2785  throw JSONRPCError(
2787  strprintf("The base block header (%s) must appear in the headers chain. Make sure all headers are syncing, and call this RPC again.",
2788  base_blockhash.ToString()));
2789  }
2790  if (!chainman.ActivateSnapshot(afile, metadata, false)) {
2791  throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to load UTXO snapshot " + fs::PathToString(path));
2792  }
2793 
2794  UniValue result(UniValue::VOBJ);
2795  result.pushKV("coins_loaded", metadata.m_coins_count);
2796  result.pushKV("tip_hash", snapshot_start_block->GetBlockHash().ToString());
2797  result.pushKV("base_height", snapshot_start_block->nHeight);
2798  result.pushKV("path", fs::PathToString(path));
2799  return result;
2800 },
2801  };
2802 }
2803 
2804 const std::vector<RPCResult> RPCHelpForChainstate{
2805  {RPCResult::Type::NUM, "blocks", "number of blocks in this chainstate"},
2806  {RPCResult::Type::STR_HEX, "bestblockhash", "blockhash of the tip"},
2807  {RPCResult::Type::NUM, "difficulty", "difficulty of the tip"},
2808  {RPCResult::Type::NUM, "verificationprogress", "progress towards the network tip"},
2809  {RPCResult::Type::STR_HEX, "snapshot_blockhash", /*optional=*/true, "the base block of the snapshot this chainstate is based on, if any"},
2810  {RPCResult::Type::NUM, "coins_db_cache_bytes", "size of the coinsdb cache"},
2811  {RPCResult::Type::NUM, "coins_tip_cache_bytes", "size of the coinstip cache"},
2812  {RPCResult::Type::BOOL, "validated", "whether the chainstate is fully validated. True if all blocks in the chainstate were validated, false if the chain is based on a snapshot and the snapshot has not yet been validated."},
2813 };
2814 
2816 {
2817 return RPCHelpMan{
2818  "getchainstates",
2819  "\nReturn information about chainstates.\n",
2820  {},
2821  RPCResult{
2822  RPCResult::Type::OBJ, "", "", {
2823  {RPCResult::Type::NUM, "headers", "the number of headers seen so far"},
2824  {RPCResult::Type::ARR, "chainstates", "list of the chainstates ordered by work, with the most-work (active) chainstate last", {{RPCResult::Type::OBJ, "", "", RPCHelpForChainstate},}},
2825  }
2826  },
2827  RPCExamples{
2828  HelpExampleCli("getchainstates", "")
2829  + HelpExampleRpc("getchainstates", "")
2830  },
2831  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2832 {
2833  LOCK(cs_main);
2834  UniValue obj(UniValue::VOBJ);
2835 
2836  ChainstateManager& chainman = EnsureAnyChainman(request.context);
2837 
2838  auto make_chain_data = [&](const Chainstate& cs, bool validated) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
2840  UniValue data(UniValue::VOBJ);
2841  if (!cs.m_chain.Tip()) {
2842  return data;
2843  }
2844  const CChain& chain = cs.m_chain;
2845  const CBlockIndex* tip = chain.Tip();
2846 
2847  data.pushKV("blocks", (int)chain.Height());
2848  data.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
2849  data.pushKV("difficulty", GetDifficulty(*tip));
2850  data.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
2851  data.pushKV("coins_db_cache_bytes", cs.m_coinsdb_cache_size_bytes);
2852  data.pushKV("coins_tip_cache_bytes", cs.m_coinstip_cache_size_bytes);
2853  if (cs.m_from_snapshot_blockhash) {
2854  data.pushKV("snapshot_blockhash", cs.m_from_snapshot_blockhash->ToString());
2855  }
2856  data.pushKV("validated", validated);
2857  return data;
2858  };
2859 
2860  obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
2861 
2862  const auto& chainstates = chainman.GetAll();
2863  UniValue obj_chainstates{UniValue::VARR};
2864  for (Chainstate* cs : chainstates) {
2865  obj_chainstates.push_back(make_chain_data(*cs, !cs->m_from_snapshot_blockhash || chainstates.size() == 1));
2866  }
2867  obj.pushKV("chainstates", std::move(obj_chainstates));
2868  return obj;
2869 }
2870  };
2871 }
2872 
2873 
2875 {
2876  static const CRPCCommand commands[]{
2877  {"blockchain", &getblockchaininfo},
2878  {"blockchain", &getchaintxstats},
2879  {"blockchain", &getblockstats},
2880  {"blockchain", &getbestblockhash},
2881  {"blockchain", &getblockcount},
2882  {"blockchain", &getblock},
2883  {"blockchain", &getblockfrompeer},
2884  {"blockchain", &getblockhash},
2885  {"blockchain", &getblockheader},
2886  {"blockchain", &getchaintips},
2887  {"blockchain", &getdifficulty},
2888  {"blockchain", &getdeploymentinfo},
2889  {"blockchain", &gettxout},
2890  {"blockchain", &gettxoutsetinfo},
2891  {"blockchain", &pruneblockchain},
2892  {"blockchain", &verifychain},
2893  {"blockchain", &preciousblock},
2894  {"blockchain", &scantxoutset},
2895  {"blockchain", &scanblocks},
2896  {"blockchain", &getblockfilter},
2897  {"blockchain", &dumptxoutset},
2898  {"blockchain", &loadtxoutset},
2899  {"blockchain", &getchainstates},
2900  {"hidden", &invalidateblock},
2901  {"hidden", &reconsiderblock},
2902  {"hidden", &waitfornewblock},
2903  {"hidden", &waitforblock},
2904  {"hidden", &waitforblockheight},
2905  {"hidden", &syncwithvalidationinterfacequeue},
2906  };
2907  for (const auto& c : commands) {
2908  t.appendCommand(c.name, &c);
2909  }
2910 }
static constexpr CAmount MAX_MONEY
No amount larger than this (in satoshi) is valid.
Definition: amount.h:26
bool MoneyRange(const CAmount &nValue)
Definition: amount.h:27
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
fs::path AbsPathForConfigVal(const ArgsManager &args, const fs::path &path, bool net_specific=true)
Most paths passed as configuration arguments are treated as relative to the datadir if they are not a...
Definition: config.cpp:211
int ret
ArgsManager & args
Definition: bitcoind.cpp:268
static RPCHelpMan getblock()
Definition: blockchain.cpp:666
static RPCHelpMan getdifficulty()
Definition: blockchain.cpp:406
static const auto scan_result_abort
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 int ComputeNextBlockAndDepth(const CBlockIndex &tip, const CBlockIndex &blockindex, const CBlockIndex *&next)
Definition: blockchain.cpp:97
const RPCResult getblock_vin
Definition: blockchain.cpp:642
static RPCHelpMan syncwithvalidationinterfacequeue()
Definition: blockchain.cpp:387
static CBlockUndo GetUndoChecked(BlockManager &blockman, const CBlockIndex &blockindex)
Definition: blockchain.cpp:621
static RPCHelpMan getchaintips()
static RPCHelpMan loadtxoutset()
static RPCHelpMan gettxoutsetinfo()
Definition: blockchain.cpp:886
static RPCHelpMan getchainstates()
static std::optional< kernel::CCoinsStats > GetUTXOStats(CCoinsView *view, node::BlockManager &blockman, kernel::CoinStatsHashType hash_type, const std::function< void()> &interruption_point={}, const CBlockIndex *pindex=nullptr, bool index_requested=true)
Calculate statistics about the unspent transaction output set.
Definition: blockchain.cpp:861
static std::atomic< int > g_scanfilter_progress_height
static RPCHelpMan getblockstats()
static std::atomic< bool > g_scanfilter_should_abort_scan
static std::atomic< int > g_scanfilter_progress
RAII object to prevent concurrency issue when scanning blockfilters.
static void SoftForkDescPushBack(const CBlockIndex *blockindex, UniValue &softforks, const ChainstateManager &chainman, Consensus::BuriedDeployment dep)
static RPCHelpMan preciousblock()
static constexpr size_t PER_UTXO_OVERHEAD
double GetDifficulty(const CBlockIndex &blockindex)
Get the difficulty of the net wrt to the given block index.
Definition: blockchain.cpp:77
static const auto scan_objects_arg_desc
static RPCHelpMan scantxoutset()
CoinStatsHashType ParseHashType(const std::string &hash_type_input)
Definition: blockchain.cpp:843
static bool CheckBlockFilterMatches(BlockManager &blockman, const CBlockIndex &blockindex, const GCSFilter::ElementSet &needles)
static std::condition_variable cond_blockchange
Definition: blockchain.cpp:72
void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector< std::pair< CAmount, int64_t >> &scores, int64_t total_weight)
Used by getblockstats to get feerates at different percentiles by weight
static std::atomic< int > g_scan_progress
RAII object to prevent concurrency issue when scanning the txout set.
static CBlock GetBlockChecked(BlockManager &blockman, const CBlockIndex &blockindex)
Definition: blockchain.cpp:579
RPCHelpMan getdeploymentinfo()
static RPCHelpMan getblockfilter()
static RPCHelpMan getbestblockhash()
Definition: blockchain.cpp:223
RPCHelpMan getblockchaininfo()
static RPCHelpMan getchaintxstats()
static RPCHelpMan waitforblock()
Definition: blockchain.cpp:295
static RPCHelpMan getblockfrompeer()
Definition: blockchain.cpp:426
static const auto scan_result_status_some
static const CBlockIndex * ParseHashOrHeight(const UniValue &param, ChainstateManager &chainman)
Definition: blockchain.cpp:107
static RPCHelpMan getblockhash()
Definition: blockchain.cpp:480
void RegisterBlockchainRPCCommands(CRPCTable &t)
static std::vector< uint8_t > GetRawBlockChecked(BlockManager &blockman, const CBlockIndex &blockindex)
Definition: blockchain.cpp:599
static RPCHelpMan gettxout()
static RPCHelpMan verifychain()
static std::atomic< bool > g_should_abort_scan
const std::vector< RPCResult > RPCHelpForChainstate
UniValue blockheaderToJSON(const CBlockIndex &tip, const CBlockIndex &blockindex)
Block header to JSON.
Definition: blockchain.cpp:135
static const auto scan_action_arg_desc
static RPCHelpMan waitforblockheight()
Definition: blockchain.cpp:341
UniValue blockToJSON(BlockManager &blockman, const CBlock &block, const CBlockIndex &tip, const CBlockIndex &blockindex, TxVerbosity verbosity)
Block description to JSON.
Definition: blockchain.cpp:164
static RPCHelpMan pruneblockchain()
Definition: blockchain.cpp:785
static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange)
static RPCHelpMan getblockheader()
Definition: blockchain.cpp:509
static RPCHelpMan scanblocks()
static std::atomic< bool > g_scanfilter_in_progress
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:71
static RPCHelpMan dumptxoutset()
Serialize the UTXO set to a file for loading elsewhere.
static RPCHelpMan getblockcount()
Definition: blockchain.cpp:202
static RPCHelpMan waitfornewblock()
Definition: blockchain.cpp:253
static const auto scan_result_status_none
void RPCNotifyBlockChange(const CBlockIndex *pindex)
Callback for when block tip changed.
Definition: blockchain.cpp:243
static constexpr int NUM_GETBLOCKSTATS_PERCENTILES
Definition: blockchain.h:27
const std::string & BlockFilterTypeName(BlockFilterType filter_type)
Get the human-readable name for a filter type.
bool BlockFilterTypeByName(const std::string &name, BlockFilterType &filter_type)
Find a filter type by its human-readable name.
BlockFilterType
Definition: blockfilter.h:93
BlockFilterIndex * GetBlockFilterIndex(BlockFilterType filter_type)
Get a block filter index by type.
@ BLOCK_VALID_SCRIPTS
Scripts & signatures ok.
Definition: chain.h:115
@ BLOCK_VALID_TREE
All parent headers found, difficulty matches, timestamp >= median previous, checkpoint.
Definition: chain.h:97
@ BLOCK_HAVE_DATA
full block available in blk*.dat
Definition: chain.h:121
@ BLOCK_FAILED_MASK
Definition: chain.h:127
static constexpr int64_t TIMESTAMP_WINDOW
Timestamp window used as a grace period by code that compares external timestamps (such as timestamps...
Definition: chain.h:37
const CChainParams & Params()
Return the currently selected parameters.
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:73
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: args.h:232
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:389
int fclose()
Definition: streams.h:405
Complete block filter struct as defined in BIP 157.
Definition: blockfilter.h:115
const std::vector< unsigned char > & GetEncodedFilter() const LIFETIMEBOUND
Definition: blockfilter.h:138
BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of bloc...
bool LookupFilterRange(int start_height, const CBlockIndex *stop_index, std::vector< BlockFilter > &filters_out) const
Get a range of filters between two heights on a chain.
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.
BlockFiltersScanReserver()=default
Definition: block.h:69
std::vector< CTransactionRef > vtx
Definition: block.h:72
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:141
uint256 hashMerkleRoot
Definition: chain.h:189
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: chain.h:147
CBlockHeader GetBlockHeader() const
Definition: chain.h:231
arith_uint256 nChainWork
(memory only) Total amount of work (expected number of hashes) in the chain up to and including this ...
Definition: chain.h:165
uint32_t nTime
Definition: chain.h:190
uint32_t nNonce
Definition: chain.h:192
uint256 GetBlockHash() const
Definition: chain.h:244
int64_t GetBlockTime() const
Definition: chain.h:267
int64_t GetMedianTimePast() const
Definition: chain.h:279
uint32_t nBits
Definition: chain.h:191
unsigned int nTx
Number of transactions in this block.
Definition: chain.h:170
bool IsValid(enum BlockStatus nUpTo=BLOCK_VALID_TRANSACTIONS) const EXCLUSIVE_LOCKS_REQUIRED(
Check whether this block index entry is valid up to the passed validity level.
Definition: chain.h:296
int32_t nVersion
block header
Definition: chain.h:188
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition: chain.cpp:120
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:153
FlatFilePos GetBlockPos() const EXCLUSIVE_LOCKS_REQUIRED(
Definition: chain.h:209
unsigned int nChainTx
(memory only) Number of transactions in the chain up to and including this block.
Definition: chain.h:177
Undo information for a CBlock.
Definition: undo.h:63
std::vector< CTxUndo > vtxundo
Definition: undo.h:65
An in-memory indexed chain of blocks.
Definition: chain.h:418
CBlockIndex * Genesis() const
Returns the index entry for the genesis block of this chain, or nullptr if none.
Definition: chain.h:428
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:434
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:71
int Height() const
Return the maximal height in the chain.
Definition: chain.h:463
const CBlockIndex * FindFork(const CBlockIndex *pindex) const
Find the last common block between this chain and a block index entry.
Definition: chain.cpp:60
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
Definition: chain.h:448
std::string GetChainTypeString() const
Return the chain type string.
Definition: chainparams.h:112
const ChainTxData & TxData() const
Definition: chainparams.h:131
std::optional< AssumeutxoData > AssumeutxoForBlockhash(const uint256 &blockhash) const
Definition: chainparams.h:126
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:93
uint64_t PruneAfterHeight() const
Definition: chainparams.h:104
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:229
uint256 GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:171
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: coins.cpp:60
Cursor for iterating over CoinsView state.
Definition: coins.h:154
virtual void Next()=0
virtual bool Valid() const =0
virtual bool GetKey(COutPoint &key) const =0
virtual bool GetValue(Coin &coin) const =0
std::unique_ptr< CCoinsViewCursor > Cursor() const override
Get a cursor to iterate over the whole state.
Definition: txdb.cpp:180
Abstract view on the open txout dataset.
Definition: coins.h:173
virtual uint256 GetBestBlock() const
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:13
CCoinsView that brings transactions from a mempool into view.
Definition: txmempool.h:848
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
GetCoin, returning whether it exists and is not spent.
Definition: txmempool.cpp:990
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:29
uint32_t n
Definition: transaction.h:32
Txid hash
Definition: transaction.h:31
RPC command dispatcher.
Definition: server.h:133
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:414
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:302
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:390
bool isSpent(const COutPoint &outpoint) const
Definition: txmempool.cpp:415
An output of a transaction.
Definition: transaction.h:150
CScript scriptPubKey
Definition: transaction.h:153
CAmount nValue
Definition: transaction.h:152
Undo information for a CTransaction.
Definition: undo.h:53
RAII wrapper for VerifyDB: Verify consistency of the block and coin databases.
Definition: validation.h:400
VerifyDBResult VerifyDB(Chainstate &chainstate, const Consensus::Params &consensus_params, 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:491
CChain m_chain
The current chain of blockheaders we consult and build on.
Definition: validation.h:571
CCoinsViewDB & CoinsDB() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:605
void ForceFlushStateToDisk()
Unconditionally flush all changes to disk.
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:597
node::BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all Chainstate instances.
Definition: validation.h:521
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:850
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1069
SnapshotCompletionResult MaybeCompleteSnapshotValidation() EXCLUSIVE_LOCKS_REQUIRED(const CBlockIndex *GetSnapshotBaseBlock() const EXCLUSIVE_LOCKS_REQUIRED(Chainstate ActiveChainstate)() const
Once the background validation chainstate has reached the height which is the base of the UTXO snapsh...
Definition: validation.h:1068
const CChainParams & GetParams() const
Definition: validation.h:934
bool IsInitialBlockDownload() const
Check whether we are doing an initial block download (synchronizing from disk or network)
node::BlockMap & BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:1083
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
Definition: validation.h:959
bool ActivateSnapshot(AutoFile &coins_file, const node::SnapshotMetadata &metadata, bool in_memory)
Construct and activate a Chainstate on the basis of UTXO snapshot data.
VersionBitsCache m_versionbitscache
Track versionbit status.
Definition: validation.h:1092
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1071
Chainstate &InitializeChainstate(CTxMemPool *mempool) EXCLUSIVE_LOCKS_REQUIRED(std::vector< Chainstate * GetAll)()
Instantiate a new chainstate.
Definition: validation.h:1037
kernel::Notifications & GetNotifications() const
Definition: validation.h:939
const Consensus::Params & GetConsensus() const
Definition: validation.h:935
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:966
A UTXO entry.
Definition: coins.h:32
bool IsCoinBase() const
Definition: coins.h:56
CTxOut out
unspent transaction output
Definition: coins.h:35
uint32_t nHeight
at which height this containing transaction was included in the active block chain
Definition: coins.h:41
unsigned int fCoinBase
whether containing transaction was a coinbase
Definition: coins.h:38
CoinsViewScanReserver()=default
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:147
std::unordered_set< Element, ByteVectorHash > ElementSet
Definition: blockfilter.h:32
Different type to mark Mutex at global scope.
Definition: sync.h:140
virtual std::optional< std::string > FetchBlock(NodeId peer_id, const CBlockIndex &block_index)=0
Attempt to manually fetch block from a given peer.
void push_back(UniValue val)
Definition: univalue.cpp:104
const std::string & get_str() const
@ VNULL
Definition: univalue.h:24
@ VOBJ
Definition: univalue.h:24
@ VARR
Definition: univalue.h:24
bool isNull() const
Definition: univalue.h:79
size_t size() const
Definition: univalue.h:71
const std::vector< UniValue > & getValues() const
Int getInt() const
Definition: univalue.h:138
const UniValue & get_array() const
bool isNum() const
Definition: univalue.h:84
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:126
bool IsValid() const
Definition: validation.h:122
std::string ToString() const
Definition: validation.h:128
int StateSinceHeight(const CBlockIndex *pindexPrev, const Consensus::Params &params, Consensus::DeploymentPos pos) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get the block height at which the BIP9 deployment switched into the state for the block after pindexP...
static BIP9Stats Statistics(const CBlockIndex *pindex, const Consensus::Params &params, Consensus::DeploymentPos pos, std::vector< bool > *signalling_blocks=nullptr)
Get the numerical statistics for a given deployment for the signalling period that includes pindex.
ThresholdState State(const CBlockIndex *pindexPrev, const Consensus::Params &params, Consensus::DeploymentPos pos) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get the BIP9 state for a given deployment for the block after pindexPrev.
std::string ToString() const
Definition: uint256.cpp:55
std::string GetHex() const
Definition: uint256.cpp:11
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:33
std::string utf8string() const
Return a UTF-8 representation of the path as a std::string, for compatibility with code using std::st...
Definition: fs.h:63
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
Definition: blockstorage.h:137
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos) const
Functions for disk access for blocks.
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
bool ReadRawBlockFromDisk(std::vector< uint8_t > &block, const FlatFilePos &pos) const
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:322
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:319
Metadata describing a serialized version of a UTXO set from which an assumeutxo Chainstate can be con...
Definition: utxo_snapshot.h:25
uint256 m_base_blockhash
The hash of the block that reflects the tip of the chain for the UTXO set contained in this snapshot.
Definition: utxo_snapshot.h:29
uint64_t m_coins_count
The number of coins in the UTXO set contained in this snapshot.
Definition: utxo_snapshot.h:33
constexpr const std::byte * begin() const
std::string GetHex() const
static transaction_identifier FromUint256(const uint256 &id)
256-bit opaque blob.
Definition: uint256.h:106
std::unique_ptr< CoinStatsIndex > g_coin_stats_index
The global UTXO set hash object.
static int64_t GetBlockWeight(const CBlock &block)
Definition: validation.h:153
static int32_t GetTransactionWeight(const CTransaction &tx)
Definition: validation.h:149
static const unsigned int MAX_BLOCK_SERIALIZED_SIZE
The maximum allowed size for a serialized block, in bytes (only for buffer size limits)
Definition: consensus.h:13
static const int WITNESS_SCALE_FACTOR
Definition: consensus.h:21
void TxToUniv(const CTransaction &tx, const uint256 &block_hash, UniValue &entry, bool include_hex=true, const CTxUndo *txundo=nullptr, TxVerbosity verbosity=TxVerbosity::SHOW_DETAILS)
Definition: core_write.cpp:171
TxVerbosity
Verbose level for block's transaction.
Definition: core_io.h:27
@ SHOW_DETAILS_AND_PREVOUT
The same as previous option with information about prevouts if available.
@ SHOW_TXID
Only TXID for each block's transaction.
@ SHOW_DETAILS
Include TXID, inputs, outputs, and other common block's transaction information.
void ScriptToUniv(const CScript &script, UniValue &out, bool include_hex=true, bool include_address=false, const SigningProvider *provider=nullptr)
Definition: core_write.cpp:150
UniValue ValueFromAmount(const CAmount amount)
Definition: core_write.cpp:26
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:8
std::string DeploymentName(Consensus::BuriedDeployment dep)
bool DeploymentActiveAfter(const CBlockIndex *pindexPrev, const Consensus::Params &params, Consensus::BuriedDeployment dep, [[maybe_unused]] VersionBitsCache &versionbitscache)
Determine if a deployment is active for the next block.
bool DeploymentEnabled(const Consensus::Params &params, Consensus::BuriedDeployment dep)
Determine if a deployment is enabled (can ever be active)
const std::string CURRENCY_UNIT
Definition: feerate.h:17
#define T(expected, seed, data)
#define LogPrint(category,...)
Definition: logging.h:263
unsigned int nHeight
static void pool cs
@ RPC
Definition: logging.h:48
@ NONE
Definition: logging.h:40
DeploymentPos
Definition: params.h:32
@ DEPLOYMENT_TAPROOT
Definition: params.h:34
@ DEPLOYMENT_TESTDUMMY
Definition: params.h:33
BuriedDeployment
A buried deployment is one where the height of the activation has been hardcoded into the client impl...
Definition: params.h:22
@ DEPLOYMENT_DERSIG
Definition: params.h:26
@ DEPLOYMENT_CSV
Definition: params.h:27
@ DEPLOYMENT_SEGWIT
Definition: params.h:28
@ DEPLOYMENT_HEIGHTINCB
Definition: params.h:24
@ DEPLOYMENT_CLTV
Definition: params.h:25
static path u8path(const std::string &utf8_str)
Definition: fs.h:75
static bool exists(const path &p)
Definition: fs.h:89
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:151
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:26
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:36
static bool ComputeUTXOStats(CCoinsView *view, CCoinsStats &stats, T hash_obj, const std::function< void()> &interruption_point)
Calculate statistics about the unspent transaction output set.
Definition: coinstats.cpp:116
CoinStatsHashType
Definition: coinstats.h:26
Definition: init.h:25
int64_t NodeId
Definition: net.h:97
static constexpr TransactionSerParams TX_NO_WITNESS
Definition: transaction.h:196
static constexpr TransactionSerParams TX_WITH_WITNESS
Definition: transaction.h:195
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:423
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:58
@ RPC_MISC_ERROR
General application defined errors.
Definition: protocol.h:39
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:43
@ RPC_INTERNAL_ERROR
Definition: protocol.h:35
@ RPC_DATABASE_ERROR
Database error.
Definition: protocol.h:44
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:41
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:155
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:173
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:30
std::string GetAllOutputTypes()
Gets all existing output types formatted for RPC help sections.
Definition: util.cpp:33
std::vector< CScript > EvalDescriptorStringOrObject(const UniValue &scanobject, FlatSigningProvider &provider, const bool expand_priv)
Evaluate a descriptor given as a string, or as a {"desc":...,"range":...} object, with default range ...
Definition: util.cpp:1285
uint256 ParseHashV(const UniValue &v, std::string_view name)
Utilities: convert hex-encoded Values (throws error if not hex).
Definition: util.cpp:89
std::unique_ptr< Descriptor > InferDescriptor(const CScript &script, const SigningProvider &provider)
Find a descriptor for the specified script, using information from provider where possible.
size_t GetSerializeSize(const T &t)
Definition: serialize.h:1116
bool IsRPCRunning()
Query whether RPC is running.
Definition: server.cpp:327
ArgsManager & EnsureArgsman(const NodeContext &node)
Definition: server_util.cpp:57
ArgsManager & EnsureAnyArgsman(const std::any &context)
Definition: server_util.cpp:65
ChainstateManager & EnsureAnyChainman(const std::any &context)
Definition: server_util.cpp:78
NodeContext & EnsureAnyNodeContext(const std::any &context)
Definition: server_util.cpp:21
PeerManager & EnsurePeerman(const NodeContext &node)
CTxMemPool & EnsureMemPool(const NodeContext &node)
Definition: server_util.cpp:30
ChainstateManager & EnsureChainman(const NodeContext &node)
Definition: server_util.cpp:70
unsigned char * UCharCast(char *c)
Definition: span.h:288
std::string MakeUnorderedList(const std::vector< std::string > &items)
Create an unordered multi-line list of items.
Definition: string.h:90
Display status of an in-progress BIP9 softfork.
Definition: versionbits.h:41
int count
Number of blocks with the version bit set since the beginning of the current period.
Definition: versionbits.h:49
int elapsed
Number of blocks elapsed since the beginning of the current period.
Definition: versionbits.h:47
int threshold
Number of blocks with the version bit set required to activate the softfork.
Definition: versionbits.h:45
bool possible
False if there are not enough blocks left in this period to pass activation threshold.
Definition: versionbits.h:51
int period
Length of blocks of the BIP9 signalling period.
Definition: versionbits.h:43
uint256 hash
Definition: blockchain.cpp:67
Comparison function for sorting the getchaintips heads.
bool operator()(const CBlockIndex *a, const CBlockIndex *b) const
int min_activation_height
If lock in occurs, delay activation until at least this block height.
Definition: params.h:54
int bit
Bit position to select the particular bit in nVersion.
Definition: params.h:45
int64_t nTimeout
Timeout/expiry MedianTime for the deployment attempt.
Definition: params.h:49
int64_t nStartTime
Start MedianTime for version bits miner confirmation.
Definition: params.h:47
BIP9Deployment vDeployments[MAX_VERSION_BITS_DEPLOYMENTS]
Definition: params.h:107
int DeploymentHeight(BuriedDeployment dep) const
Definition: params.h:131
int64_t nPowTargetSpacing
Definition: params.h:112
Definition: util.h:166
@ RANGE
Special type that is a NUM or [NUM,NUM].
@ STR_HEX
Special type that is a STR with only hex chars.
@ OBJ_NAMED_PARAMS
Special type that behaves almost exactly like OBJ, defining an options object with a list of pre-defi...
std::string DefaultHint
Hint for default value.
Definition: util.h:200
@ OMITTED
Optional argument for which the default value is omitted from help text for one of two reasons:
@ NO
Required arg.
std::string oneline_description
Should be empty unless it is supposed to override the auto-generated summary line.
Definition: util.h:151
bool skip_type_check
Definition: util.h:150
@ ELISION
Special type to denote elision (...)
@ NUM_TIME
Special numeric to denote unix epoch time.
@ ARR_FIXED
Special array that has a fixed number of entries.
@ OBJ_DYN
Special dictionary with keys that are not literals.
@ STR_HEX
Special string with only hex chars.
@ STR_AMOUNT
Special string to represent a floating point amount.
std::optional< CAmount > total_amount
The total amount, or nullopt if an overflow occurred calculating it.
Definition: coinstats.h:41
uint64_t nDiskSize
Definition: coinstats.h:39
CAmount total_unspendable_amount
Total cumulative amount of unspendable coins up to and including this block.
Definition: coinstats.h:54
CAmount total_unspendables_scripts
Total cumulative amount of outputs sent to unspendable scripts (OP_RETURN for example) up to and incl...
Definition: coinstats.h:66
CAmount total_new_outputs_ex_coinbase_amount
Total cumulative amount of outputs created up to and including this block.
Definition: coinstats.h:58
uint64_t nTransactions
Definition: coinstats.h:35
uint64_t nTransactionOutputs
Definition: coinstats.h:36
CAmount total_coinbase_amount
Total cumulative amount of coinbase outputs up to and including this block.
Definition: coinstats.h:60
uint64_t nBogoSize
Definition: coinstats.h:37
bool index_used
Signals if the coinstatsindex was used to retrieve the statistics.
Definition: coinstats.h:47
CAmount total_unspendables_bip30
The two unspendable coinbase outputs total amount caused by BIP30.
Definition: coinstats.h:64
CAmount total_unspendables_genesis_block
The unspendable coinbase amount from the genesis block.
Definition: coinstats.h:62
CAmount total_prevout_spent_amount
Total cumulative amount of prevouts spent up to and including this block.
Definition: coinstats.h:56
uint256 hashSerialized
Definition: coinstats.h:38
CAmount total_unspendables_unclaimed_rewards
Total cumulative amount of coins lost due to unclaimed miner rewards up to and including this block.
Definition: coinstats.h:68
NodeContext struct containing references to chain state and connection state.
Definition: context.h:49
#define WAIT_LOCK(cs, name)
Definition: sync.h:262
#define AssertLockNotHeld(cs)
Definition: sync.h:147
#define LOCK(cs)
Definition: sync.h:257
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:301
static int count
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:49
#define LOG_TIME_SECONDS(end_msg)
Definition: timer.h:107
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1162
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:74
static const uint32_t MEMPOOL_HEIGHT
Fake height value used in Coin to signify they are only in the memory pool (since 0....
Definition: txmempool.h:47
const UniValue NullUniValue
Definition: univalue.cpp:16
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
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...
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams)
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.
AssertLockHeld(pool.cs)
bool IsBIP30Repeat(const CBlockIndex &block_index)
Identifies blocks that overwrote an existing coinbase output in the UTXO set (see BIP30)
static constexpr int DEFAULT_CHECKLEVEL
Definition: validation.h:68
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:66
static const signed int DEFAULT_CHECKBLOCKS
Definition: validation.h:67
ThresholdState
BIP 9 defines a finite-state-machine to deploy a softfork in multiple stages.
Definition: versionbits.h:27
bilingual_str GetWarnings(bool verbose)
Format a string that describes several potential problems detected by the core.
Definition: warnings.cpp:35