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