Bitcoin Core  31.0.0
P2P Digital Currency
blockchain.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-present 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 <chainparamsbase.h>
12 #include <clientversion.h>
13 #include <coins.h>
14 #include <common/args.h>
15 #include <consensus/amount.h>
16 #include <consensus/params.h>
17 #include <consensus/validation.h>
18 #include <core_io.h>
19 #include <deploymentinfo.h>
20 #include <deploymentstatus.h>
21 #include <flatfile.h>
22 #include <hash.h>
23 #include <index/blockfilterindex.h>
24 #include <index/coinstatsindex.h>
25 #include <interfaces/mining.h>
26 #include <kernel/coinstats.h>
27 #include <logging/timer.h>
28 #include <net.h>
29 #include <net_processing.h>
30 #include <node/blockstorage.h>
31 #include <node/context.h>
32 #include <node/transaction.h>
33 #include <node/utxo_snapshot.h>
34 #include <node/warnings.h>
35 #include <primitives/transaction.h>
36 #include <rpc/server.h>
37 #include <rpc/server_util.h>
38 #include <rpc/util.h>
39 #include <script/descriptor.h>
40 #include <serialize.h>
41 #include <streams.h>
42 #include <sync.h>
43 #include <tinyformat.h>
44 #include <txdb.h>
45 #include <txmempool.h>
46 #include <undo.h>
47 #include <univalue.h>
48 #include <util/check.h>
49 #include <util/fs.h>
50 #include <util/strencodings.h>
51 #include <util/syserror.h>
52 #include <util/translation.h>
53 #include <validation.h>
54 #include <validationinterface.h>
55 #include <versionbits.h>
56 
57 #include <cstdint>
58 
59 #include <condition_variable>
60 #include <iterator>
61 #include <memory>
62 #include <mutex>
63 #include <optional>
64 #include <string>
65 #include <string_view>
66 #include <vector>
67 
70 
72 using interfaces::Mining;
73 using node::BlockManager;
74 using node::NodeContext;
77 
78 std::tuple<std::unique_ptr<CCoinsViewCursor>, CCoinsStats, const CBlockIndex*>
80  Chainstate& chainstate,
81  const std::function<void()>& interruption_point = {})
83 
85  Chainstate& chainstate,
86  CCoinsViewCursor* pcursor,
87  CCoinsStats* maybe_stats,
88  const CBlockIndex* tip,
89  AutoFile&& afile,
90  const fs::path& path,
91  const fs::path& temppath,
92  const std::function<void()>& interruption_point = {});
93 
94 /* Calculate the difficulty for a given block index.
95  */
96 double GetDifficulty(const CBlockIndex& blockindex)
97 {
98  int nShift = (blockindex.nBits >> 24) & 0xff;
99  double dDiff =
100  (double)0x0000ffff / (double)(blockindex.nBits & 0x00ffffff);
101 
102  while (nShift < 29)
103  {
104  dDiff *= 256.0;
105  nShift++;
106  }
107  while (nShift > 29)
108  {
109  dDiff /= 256.0;
110  nShift--;
111  }
112 
113  return dDiff;
114 }
115 
116 static int ComputeNextBlockAndDepth(const CBlockIndex& tip, const CBlockIndex& blockindex, const CBlockIndex*& next)
117 {
118  next = tip.GetAncestor(blockindex.nHeight + 1);
119  if (next && next->pprev == &blockindex) {
120  return tip.nHeight - blockindex.nHeight + 1;
121  }
122  next = nullptr;
123  return &blockindex == &tip ? 1 : -1;
124 }
125 
126 static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateManager& chainman)
127 {
128  LOCK(::cs_main);
129  CChain& active_chain = chainman.ActiveChain();
130 
131  if (param.isNum()) {
132  const int height{param.getInt<int>()};
133  if (height < 0) {
134  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d is negative", height));
135  }
136  const int current_tip{active_chain.Height()};
137  if (height > current_tip) {
138  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d after current tip %d", height, current_tip));
139  }
140 
141  return active_chain[height];
142  } else {
143  const uint256 hash{ParseHashV(param, "hash_or_height")};
144  const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
145 
146  if (!pindex) {
147  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
148  }
149 
150  return pindex;
151  }
152 }
153 
154 UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex, const uint256 pow_limit)
155 {
156  // Serialize passed information without accessing chain state of the active chain!
157  AssertLockNotHeld(cs_main); // For performance reasons
158 
160  result.pushKV("hash", blockindex.GetBlockHash().GetHex());
161  const CBlockIndex* pnext;
162  int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
163  result.pushKV("confirmations", confirmations);
164  result.pushKV("height", blockindex.nHeight);
165  result.pushKV("version", blockindex.nVersion);
166  result.pushKV("versionHex", strprintf("%08x", blockindex.nVersion));
167  result.pushKV("merkleroot", blockindex.hashMerkleRoot.GetHex());
168  result.pushKV("time", blockindex.nTime);
169  result.pushKV("mediantime", blockindex.GetMedianTimePast());
170  result.pushKV("nonce", blockindex.nNonce);
171  result.pushKV("bits", strprintf("%08x", blockindex.nBits));
172  result.pushKV("target", GetTarget(blockindex, pow_limit).GetHex());
173  result.pushKV("difficulty", GetDifficulty(blockindex));
174  result.pushKV("chainwork", blockindex.nChainWork.GetHex());
175  result.pushKV("nTx", blockindex.nTx);
176 
177  if (blockindex.pprev)
178  result.pushKV("previousblockhash", blockindex.pprev->GetBlockHash().GetHex());
179  if (pnext)
180  result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
181  return result;
182 }
183 
186 {
187  CHECK_NONFATAL(!coinbase_tx.vin.empty());
188  const CTxIn& vin_0{coinbase_tx.vin[0]};
189  UniValue coinbase_tx_obj(UniValue::VOBJ);
190  coinbase_tx_obj.pushKV("version", coinbase_tx.version);
191  coinbase_tx_obj.pushKV("locktime", coinbase_tx.nLockTime);
192  coinbase_tx_obj.pushKV("sequence", vin_0.nSequence);
193  coinbase_tx_obj.pushKV("coinbase", HexStr(vin_0.scriptSig));
194  const auto& witness_stack{vin_0.scriptWitness.stack};
195  if (!witness_stack.empty()) {
196  CHECK_NONFATAL(witness_stack.size() == 1);
197  coinbase_tx_obj.pushKV("witness", HexStr(witness_stack[0]));
198  }
199  return coinbase_tx_obj;
200 }
201 
202 UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity, const uint256 pow_limit)
203 {
204  UniValue result = blockheaderToJSON(tip, blockindex, pow_limit);
205 
206  result.pushKV("strippedsize", ::GetSerializeSize(TX_NO_WITNESS(block)));
207  result.pushKV("size", ::GetSerializeSize(TX_WITH_WITNESS(block)));
208  result.pushKV("weight", ::GetBlockWeight(block));
209 
210  CHECK_NONFATAL(!block.vtx.empty());
211  result.pushKV("coinbase_tx", coinbaseTxToJSON(*block.vtx[0]));
212 
214  txs.reserve(block.vtx.size());
215 
216  switch (verbosity) {
218  for (const CTransactionRef& tx : block.vtx) {
219  txs.push_back(tx->GetHash().GetHex());
220  }
221  break;
222 
225  CBlockUndo blockUndo;
226  const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))};
227  bool have_undo{is_not_pruned && WITH_LOCK(::cs_main, return blockindex.nStatus & BLOCK_HAVE_UNDO)};
228  if (have_undo && !blockman.ReadBlockUndo(blockUndo, blockindex)) {
229  throw JSONRPCError(RPC_INTERNAL_ERROR, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event.");
230  }
231  for (size_t i = 0; i < block.vtx.size(); ++i) {
232  const CTransactionRef& tx = block.vtx.at(i);
233  // coinbase transaction (i.e. i == 0) doesn't have undo data
234  const CTxUndo* txundo = (have_undo && i > 0) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
235  UniValue objTx(UniValue::VOBJ);
236  TxToUniv(*tx, /*block_hash=*/uint256(), /*entry=*/objTx, /*include_hex=*/true, txundo, verbosity);
237  txs.push_back(std::move(objTx));
238  }
239  break;
240  }
241 
242  result.pushKV("tx", std::move(txs));
243 
244  return result;
245 }
246 
248 {
249  return RPCHelpMan{
250  "getblockcount",
251  "Returns the height of the most-work fully-validated chain.\n"
252  "The genesis block has height 0.\n",
253  {},
254  RPCResult{
255  RPCResult::Type::NUM, "", "The current block count"},
256  RPCExamples{
257  HelpExampleCli("getblockcount", "")
258  + HelpExampleRpc("getblockcount", "")
259  },
260  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
261 {
262  ChainstateManager& chainman = EnsureAnyChainman(request.context);
263  LOCK(cs_main);
264  return chainman.ActiveChain().Height();
265 },
266  };
267 }
268 
270 {
271  return RPCHelpMan{
272  "getbestblockhash",
273  "Returns the hash of the best (tip) block in the most-work fully-validated chain.\n",
274  {},
275  RPCResult{
276  RPCResult::Type::STR_HEX, "", "the block hash, hex-encoded"},
277  RPCExamples{
278  HelpExampleCli("getbestblockhash", "")
279  + HelpExampleRpc("getbestblockhash", "")
280  },
281  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
282 {
283  ChainstateManager& chainman = EnsureAnyChainman(request.context);
284  LOCK(cs_main);
285  return chainman.ActiveChain().Tip()->GetBlockHash().GetHex();
286 },
287  };
288 }
289 
291 {
292  return RPCHelpMan{
293  "waitfornewblock",
294  "Waits for any new block and returns useful info about it.\n"
295  "\nReturns the current block on timeout or exit.\n"
296  "\nMake sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
297  {
298  {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
299  {"current_tip", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "Method waits for the chain tip to differ from this."},
300  },
301  RPCResult{
302  RPCResult::Type::OBJ, "", "",
303  {
304  {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
305  {RPCResult::Type::NUM, "height", "Block height"},
306  }},
307  RPCExamples{
308  HelpExampleCli("waitfornewblock", "1000")
309  + HelpExampleRpc("waitfornewblock", "1000")
310  },
311  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
312 {
313  int timeout = 0;
314  if (!request.params[0].isNull())
315  timeout = request.params[0].getInt<int>();
316  if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout");
317 
318  NodeContext& node = EnsureAnyNodeContext(request.context);
319  Mining& miner = EnsureMining(node);
320 
321  // If the caller provided a current_tip value, pass it to waitTipChanged().
322  //
323  // If the caller did not provide a current tip hash, call getTip() to get
324  // one and wait for the tip to be different from this value. This mode is
325  // less reliable because if the tip changed between waitfornewblock calls,
326  // it will need to change a second time before this call returns.
327  BlockRef current_block{CHECK_NONFATAL(miner.getTip()).value()};
328 
329  uint256 tip_hash{request.params[1].isNull()
330  ? current_block.hash
331  : ParseHashV(request.params[1], "current_tip")};
332 
333  // If the user provided an invalid current_tip then this call immediately
334  // returns the current tip.
335  std::optional<BlockRef> block = timeout ? miner.waitTipChanged(tip_hash, std::chrono::milliseconds(timeout)) :
336  miner.waitTipChanged(tip_hash);
337 
338  // Return current block upon shutdown
339  if (block) current_block = *block;
340 
342  ret.pushKV("hash", current_block.hash.GetHex());
343  ret.pushKV("height", current_block.height);
344  return ret;
345 },
346  };
347 }
348 
350 {
351  return RPCHelpMan{
352  "waitforblock",
353  "Waits for a specific new block and returns useful info about it.\n"
354  "\nReturns the current block on timeout or exit.\n"
355  "\nMake sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
356  {
357  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Block hash to wait for."},
358  {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
359  },
360  RPCResult{
361  RPCResult::Type::OBJ, "", "",
362  {
363  {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
364  {RPCResult::Type::NUM, "height", "Block height"},
365  }},
366  RPCExamples{
367  HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\" 1000")
368  + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
369  },
370  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
371 {
372  int timeout = 0;
373 
374  uint256 hash(ParseHashV(request.params[0], "blockhash"));
375 
376  if (!request.params[1].isNull())
377  timeout = request.params[1].getInt<int>();
378  if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout");
379 
380  NodeContext& node = EnsureAnyNodeContext(request.context);
381  Mining& miner = EnsureMining(node);
382 
383  // Abort if RPC came out of warmup too early
384  BlockRef current_block{CHECK_NONFATAL(miner.getTip()).value()};
385 
386  const auto deadline{std::chrono::steady_clock::now() + 1ms * timeout};
387  while (current_block.hash != hash) {
388  std::optional<BlockRef> block;
389  if (timeout) {
390  auto now{std::chrono::steady_clock::now()};
391  if (now >= deadline) break;
392  const MillisecondsDouble remaining{deadline - now};
393  block = miner.waitTipChanged(current_block.hash, remaining);
394  } else {
395  block = miner.waitTipChanged(current_block.hash);
396  }
397  // Return current block upon shutdown
398  if (!block) break;
399  current_block = *block;
400  }
401 
403  ret.pushKV("hash", current_block.hash.GetHex());
404  ret.pushKV("height", current_block.height);
405  return ret;
406 },
407  };
408 }
409 
411 {
412  return RPCHelpMan{
413  "waitforblockheight",
414  "Waits for (at least) block height and returns the height and hash\n"
415  "of the current tip.\n"
416  "\nReturns the current block on timeout or exit.\n"
417  "\nMake sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
418  {
419  {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "Block height to wait for."},
420  {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
421  },
422  RPCResult{
423  RPCResult::Type::OBJ, "", "",
424  {
425  {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
426  {RPCResult::Type::NUM, "height", "Block height"},
427  }},
428  RPCExamples{
429  HelpExampleCli("waitforblockheight", "100 1000")
430  + HelpExampleRpc("waitforblockheight", "100, 1000")
431  },
432  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
433 {
434  int timeout = 0;
435 
436  int height = request.params[0].getInt<int>();
437 
438  if (!request.params[1].isNull())
439  timeout = request.params[1].getInt<int>();
440  if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout");
441 
442  NodeContext& node = EnsureAnyNodeContext(request.context);
443  Mining& miner = EnsureMining(node);
444 
445  // Abort if RPC came out of warmup too early
446  BlockRef current_block{CHECK_NONFATAL(miner.getTip()).value()};
447 
448  const auto deadline{std::chrono::steady_clock::now() + 1ms * timeout};
449 
450  while (current_block.height < height) {
451  std::optional<BlockRef> block;
452  if (timeout) {
453  auto now{std::chrono::steady_clock::now()};
454  if (now >= deadline) break;
455  const MillisecondsDouble remaining{deadline - now};
456  block = miner.waitTipChanged(current_block.hash, remaining);
457  } else {
458  block = miner.waitTipChanged(current_block.hash);
459  }
460  // Return current block on shutdown
461  if (!block) break;
462  current_block = *block;
463  }
464 
466  ret.pushKV("hash", current_block.hash.GetHex());
467  ret.pushKV("height", current_block.height);
468  return ret;
469 },
470  };
471 }
472 
474 {
475  return RPCHelpMan{
476  "syncwithvalidationinterfacequeue",
477  "Waits for the validation interface queue to catch up on everything that was there when we entered this function.\n",
478  {},
480  RPCExamples{
481  HelpExampleCli("syncwithvalidationinterfacequeue","")
482  + HelpExampleRpc("syncwithvalidationinterfacequeue","")
483  },
484  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
485 {
486  NodeContext& node = EnsureAnyNodeContext(request.context);
487  CHECK_NONFATAL(node.validation_signals)->SyncWithValidationInterfaceQueue();
488  return UniValue::VNULL;
489 },
490  };
491 }
492 
494 {
495  return RPCHelpMan{
496  "getdifficulty",
497  "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.\n",
498  {},
499  RPCResult{
500  RPCResult::Type::NUM, "", "the proof-of-work difficulty as a multiple of the minimum difficulty."},
501  RPCExamples{
502  HelpExampleCli("getdifficulty", "")
503  + HelpExampleRpc("getdifficulty", "")
504  },
505  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
506 {
507  ChainstateManager& chainman = EnsureAnyChainman(request.context);
508  LOCK(cs_main);
509  return GetDifficulty(*CHECK_NONFATAL(chainman.ActiveChain().Tip()));
510 },
511  };
512 }
513 
515 {
516  return RPCHelpMan{
517  "getblockfrompeer",
518  "Attempt to fetch block from a given peer.\n\n"
519  "We must have the header for this block, e.g. using submitheader.\n"
520  "The block will not have any undo data which can limit the usage of the block data in a context where the undo data is needed.\n"
521  "Subsequent calls for the same block may cause the response from the previous peer to be ignored.\n"
522  "Peers generally ignore requests for a stale block that they never fully verified, or one that is more than a month old.\n"
523  "When a peer does not respond with a block, we will disconnect.\n"
524  "Note: The block could be re-pruned as soon as it is received.\n\n"
525  "Returns an empty JSON object if the request was successfully scheduled.",
526  {
527  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash to try to fetch"},
528  {"peer_id", RPCArg::Type::NUM, RPCArg::Optional::NO, "The peer to fetch it from (see getpeerinfo for peer IDs)"},
529  },
530  RPCResult{RPCResult::Type::OBJ, "", /*optional=*/false, "", {}},
531  RPCExamples{
532  HelpExampleCli("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0")
533  + HelpExampleRpc("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0")
534  },
535  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
536 {
537  const NodeContext& node = EnsureAnyNodeContext(request.context);
539  PeerManager& peerman = EnsurePeerman(node);
540 
541  const uint256& block_hash{ParseHashV(request.params[0], "blockhash")};
542  const NodeId peer_id{request.params[1].getInt<int64_t>()};
543 
544  const CBlockIndex* const index = WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(block_hash););
545 
546  if (!index) {
547  throw JSONRPCError(RPC_MISC_ERROR, "Block header missing");
548  }
549 
550  // Fetching blocks before the node has syncing past their height can prevent block files from
551  // being pruned, so we avoid it if the node is in prune mode.
552  if (chainman.m_blockman.IsPruneMode() && index->nHeight > WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip()->nHeight)) {
553  throw JSONRPCError(RPC_MISC_ERROR, "In prune mode, only blocks that the node has already synced previously can be fetched from a peer");
554  }
555 
556  const bool block_has_data = WITH_LOCK(::cs_main, return index->nStatus & BLOCK_HAVE_DATA);
557  if (block_has_data) {
558  throw JSONRPCError(RPC_MISC_ERROR, "Block already downloaded");
559  }
560 
561  if (const auto res{peerman.FetchBlock(peer_id, *index)}; !res) {
562  throw JSONRPCError(RPC_MISC_ERROR, res.error());
563  }
564  return UniValue::VOBJ;
565 },
566  };
567 }
568 
570 {
571  return RPCHelpMan{
572  "getblockhash",
573  "Returns hash of block in best-block-chain at height provided.\n",
574  {
575  {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The height index"},
576  },
577  RPCResult{
578  RPCResult::Type::STR_HEX, "", "The block hash"},
579  RPCExamples{
580  HelpExampleCli("getblockhash", "1000")
581  + HelpExampleRpc("getblockhash", "1000")
582  },
583  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
584 {
585  ChainstateManager& chainman = EnsureAnyChainman(request.context);
586  LOCK(cs_main);
587  const CChain& active_chain = chainman.ActiveChain();
588 
589  int nHeight = request.params[0].getInt<int>();
590  if (nHeight < 0 || nHeight > active_chain.Height())
591  throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
592 
593  const CBlockIndex* pblockindex = active_chain[nHeight];
594  return pblockindex->GetBlockHash().GetHex();
595 },
596  };
597 }
598 
600 {
601  return RPCHelpMan{
602  "getblockheader",
603  "If verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"
604  "If verbose is true, returns an Object with information about blockheader <hash>.\n",
605  {
606  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
607  {"verbose", RPCArg::Type::BOOL, RPCArg::Default{true}, "true for a json object, false for the hex-encoded data"},
608  },
609  {
610  RPCResult{"for verbose = true",
611  RPCResult::Type::OBJ, "", "",
612  {
613  {RPCResult::Type::STR_HEX, "hash", "the block hash (same as provided)"},
614  {RPCResult::Type::NUM, "confirmations", "The number of confirmations, or -1 if the block is not on the main chain"},
615  {RPCResult::Type::NUM, "height", "The block height or index"},
616  {RPCResult::Type::NUM, "version", "The block version"},
617  {RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},
618  {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
619  {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
620  {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
621  {RPCResult::Type::NUM, "nonce", "The nonce"},
622  {RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},
623  {RPCResult::Type::STR_HEX, "target", "The difficulty target"},
624  {RPCResult::Type::NUM, "difficulty", "The difficulty"},
625  {RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the current chain"},
626  {RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
627  {RPCResult::Type::STR_HEX, "previousblockhash", /*optional=*/true, "The hash of the previous block (if available)"},
628  {RPCResult::Type::STR_HEX, "nextblockhash", /*optional=*/true, "The hash of the next block (if available)"},
629  }},
630  RPCResult{"for verbose=false",
631  RPCResult::Type::STR_HEX, "", "A string that is serialized, hex-encoded data for block 'hash'"},
632  },
633  RPCExamples{
634  HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
635  + HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
636  },
637  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
638 {
639  uint256 hash(ParseHashV(request.params[0], "hash"));
640 
641  bool fVerbose = true;
642  if (!request.params[1].isNull())
643  fVerbose = request.params[1].get_bool();
644 
645  const CBlockIndex* pblockindex;
646  const CBlockIndex* tip;
647  ChainstateManager& chainman = EnsureAnyChainman(request.context);
648  {
649  LOCK(cs_main);
650  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
651  tip = chainman.ActiveChain().Tip();
652  }
653 
654  if (!pblockindex) {
655  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
656  }
657 
658  if (!fVerbose)
659  {
660  DataStream ssBlock{};
661  ssBlock << pblockindex->GetBlockHeader();
662  std::string strHex = HexStr(ssBlock);
663  return strHex;
664  }
665 
666  return blockheaderToJSON(*tip, *pblockindex, chainman.GetConsensus().powLimit);
667 },
668  };
669 }
670 
671 void CheckBlockDataAvailability(BlockManager& blockman, const CBlockIndex& blockindex, bool check_for_undo)
672 {
674  uint32_t flag = check_for_undo ? BLOCK_HAVE_UNDO : BLOCK_HAVE_DATA;
675  if (!(blockindex.nStatus & flag)) {
676  if (blockman.IsBlockPruned(blockindex)) {
677  throw JSONRPCError(RPC_MISC_ERROR, strprintf("%s not available (pruned data)", check_for_undo ? "Undo data" : "Block"));
678  }
679  if (check_for_undo) {
680  throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available");
681  }
682  throw JSONRPCError(RPC_MISC_ERROR, "Block not available (not fully downloaded)");
683  }
684 }
685 
686 static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex& blockindex)
687 {
688  CBlock block;
689  {
690  LOCK(cs_main);
691  CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/false);
692  }
693 
694  if (!blockman.ReadBlock(block, blockindex)) {
695  // Block not found on disk. This shouldn't normally happen unless the block was
696  // pruned right after we released the lock above.
697  throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
698  }
699 
700  return block;
701 }
702 
703 static std::vector<std::byte> GetRawBlockChecked(BlockManager& blockman, const CBlockIndex& blockindex)
704 {
705  FlatFilePos pos{};
706  {
707  LOCK(cs_main);
708  CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/false);
709  pos = blockindex.GetBlockPos();
710  }
711 
712  if (auto data{blockman.ReadRawBlock(pos)}) return std::move(*data);
713  // Block not found on disk. This shouldn't normally happen unless the block was
714  // pruned right after we released the lock above.
715  throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
716 }
717 
718 static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex& blockindex)
719 {
720  CBlockUndo blockUndo;
721 
722  // The Genesis block does not have undo data
723  if (blockindex.nHeight == 0) return blockUndo;
724 
725  {
726  LOCK(cs_main);
727  CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/true);
728  }
729 
730  if (!blockman.ReadBlockUndo(blockUndo, blockindex)) {
731  throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
732  }
733 
734  return blockUndo;
735 }
736 
738  RPCResult::Type::ARR, "vin", "",
739  {
740  {RPCResult::Type::OBJ, "", "",
741  {
742  {RPCResult::Type::ELISION, "", "The same output as verbosity = 2"},
743  {RPCResult::Type::OBJ, "prevout", "(Only if undo information is available)",
744  {
745  {RPCResult::Type::BOOL, "generated", "Coinbase or not"},
746  {RPCResult::Type::NUM, "height", "The height of the prevout"},
747  {RPCResult::Type::STR_AMOUNT, "value", "The value in " + CURRENCY_UNIT},
748  {RPCResult::Type::OBJ, "scriptPubKey", "",
749  {
750  {RPCResult::Type::STR, "asm", "Disassembly of the output script"},
751  {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
752  {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"},
753  {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
754  {RPCResult::Type::STR, "type", "The type (one of: " + GetAllOutputTypes() + ")"},
755  }},
756  }},
757  }},
758  }
759 };
760 
762 {
763  return RPCHelpMan{
764  "getblock",
765  "If verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
766  "If verbosity is 1, returns an Object with information about block <hash>.\n"
767  "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction.\n"
768  "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",
769  {
770  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
771  {"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",
772  RPCArgOptions{.skip_type_check = true}},
773  },
774  {
775  RPCResult{"for verbosity = 0",
776  RPCResult::Type::STR_HEX, "", "A string that is serialized, hex-encoded data for block 'hash'"},
777  RPCResult{"for verbosity = 1",
778  RPCResult::Type::OBJ, "", "",
779  {
780  {RPCResult::Type::STR_HEX, "hash", "the block hash (same as provided)"},
781  {RPCResult::Type::NUM, "confirmations", "The number of confirmations, or -1 if the block is not on the main chain"},
782  {RPCResult::Type::NUM, "size", "The block size"},
783  {RPCResult::Type::NUM, "strippedsize", "The block size excluding witness data"},
784  {RPCResult::Type::NUM, "weight", "The block weight as defined in BIP 141"},
785  {RPCResult::Type::OBJ, "coinbase_tx", "Coinbase transaction metadata",
786  {
787  {RPCResult::Type::NUM, "version", "The coinbase transaction version"},
788  {RPCResult::Type::NUM, "locktime", "The coinbase transaction's locktime (nLockTime)"},
789  {RPCResult::Type::NUM, "sequence", "The coinbase input's sequence number (nSequence)"},
790  {RPCResult::Type::STR_HEX, "coinbase", "The coinbase input's script"},
791  {RPCResult::Type::STR_HEX, "witness", /*optional=*/true, "The coinbase input's first (and only) witness stack element, if present"},
792  }},
793  {RPCResult::Type::NUM, "height", "The block height or index"},
794  {RPCResult::Type::NUM, "version", "The block version"},
795  {RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},
796  {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
797  {RPCResult::Type::ARR, "tx", "The transaction ids",
798  {{RPCResult::Type::STR_HEX, "", "The transaction id"}}},
799  {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
800  {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
801  {RPCResult::Type::NUM, "nonce", "The nonce"},
802  {RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},
803  {RPCResult::Type::STR_HEX, "target", "The difficulty target"},
804  {RPCResult::Type::NUM, "difficulty", "The difficulty"},
805  {RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the chain up to this block (in hex)"},
806  {RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
807  {RPCResult::Type::STR_HEX, "previousblockhash", /*optional=*/true, "The hash of the previous block (if available)"},
808  {RPCResult::Type::STR_HEX, "nextblockhash", /*optional=*/true, "The hash of the next block (if available)"},
809  }},
810  RPCResult{"for verbosity = 2",
811  RPCResult::Type::OBJ, "", "",
812  {
813  {RPCResult::Type::ELISION, "", "Same output as verbosity = 1"},
814  {RPCResult::Type::ARR, "tx", "",
815  {
816  {RPCResult::Type::OBJ, "", "",
817  {
818  {RPCResult::Type::ELISION, "", "The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result"},
819  {RPCResult::Type::NUM, "fee", /*optional=*/true, "The transaction fee in " + CURRENCY_UNIT + ", omitted if block undo data is not available"},
820  }},
821  }},
822  }},
823  RPCResult{"for verbosity = 3",
824  RPCResult::Type::OBJ, "", "",
825  {
826  {RPCResult::Type::ELISION, "", "Same output as verbosity = 2"},
827  {RPCResult::Type::ARR, "tx", "",
828  {
829  {RPCResult::Type::OBJ, "", "",
830  {
831  getblock_vin,
832  }},
833  }},
834  }},
835  },
836  RPCExamples{
837  HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
838  + HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
839  },
840  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
841 {
842  uint256 hash(ParseHashV(request.params[0], "blockhash"));
843 
844  int verbosity{ParseVerbosity(request.params[1], /*default_verbosity=*/1, /*allow_bool=*/true)};
845 
846  const CBlockIndex* pblockindex;
847  const CBlockIndex* tip;
848  ChainstateManager& chainman = EnsureAnyChainman(request.context);
849  {
850  LOCK(cs_main);
851  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
852  tip = chainman.ActiveChain().Tip();
853 
854  if (!pblockindex) {
855  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
856  }
857  }
858 
859  const std::vector<std::byte> block_data{GetRawBlockChecked(chainman.m_blockman, *pblockindex)};
860 
861  if (verbosity <= 0) {
862  return HexStr(block_data);
863  }
864 
865  CBlock block{};
866  SpanReader{block_data} >> TX_WITH_WITNESS(block);
867 
868  TxVerbosity tx_verbosity;
869  if (verbosity == 1) {
870  tx_verbosity = TxVerbosity::SHOW_TXID;
871  } else if (verbosity == 2) {
872  tx_verbosity = TxVerbosity::SHOW_DETAILS;
873  } else {
875  }
876 
877  return blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity, chainman.GetConsensus().powLimit);
878 },
879  };
880 }
881 
883 std::optional<int> GetPruneHeight(const BlockManager& blockman, const CChain& chain) {
885 
886  // Search for the last block missing block data or undo data. Don't let the
887  // search consider the genesis block, because the genesis block does not
888  // have undo data, but should not be considered pruned.
889  const CBlockIndex* first_block{chain[1]};
890  const CBlockIndex* chain_tip{chain.Tip()};
891 
892  // If there are no blocks after the genesis block, or no blocks at all, nothing is pruned.
893  if (!first_block || !chain_tip) return std::nullopt;
894 
895  // If the chain tip is pruned, everything is pruned.
896  if ((chain_tip->nStatus & BLOCK_HAVE_MASK) != BLOCK_HAVE_MASK) return chain_tip->nHeight;
897 
898  const auto& first_unpruned{blockman.GetFirstBlock(*chain_tip, /*status_mask=*/BLOCK_HAVE_MASK, first_block)};
899  if (&first_unpruned == first_block) {
900  // All blocks between first_block and chain_tip have data, so nothing is pruned.
901  return std::nullopt;
902  }
903 
904  // Block before the first unpruned block is the last pruned block.
905  return CHECK_NONFATAL(first_unpruned.pprev)->nHeight;
906 }
907 
909 {
910  return RPCHelpMan{"pruneblockchain",
911  "Attempts to delete block and undo data up to a specified height or timestamp, if eligible for pruning.\n"
912  "Requires `-prune` to be enabled at startup. While pruned data may be re-fetched in some cases (e.g., via `getblockfrompeer`), local deletion is irreversible.\n",
913  {
914  {"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"
915  " to prune blocks whose block time is at least 2 hours older than the provided timestamp."},
916  },
917  RPCResult{
918  RPCResult::Type::NUM, "", "Height of the last block pruned"},
919  RPCExamples{
920  HelpExampleCli("pruneblockchain", "1000")
921  + HelpExampleRpc("pruneblockchain", "1000")
922  },
923  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
924 {
925  ChainstateManager& chainman = EnsureAnyChainman(request.context);
926  if (!chainman.m_blockman.IsPruneMode()) {
927  throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
928  }
929 
930  LOCK(cs_main);
931  Chainstate& active_chainstate = chainman.ActiveChainstate();
932  CChain& active_chain = active_chainstate.m_chain;
933 
934  int heightParam = request.params[0].getInt<int>();
935  if (heightParam < 0) {
936  throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative block height.");
937  }
938 
939  // Height value more than a billion is too high to be a block height, and
940  // too low to be a block time (corresponds to timestamp from Sep 2001).
941  if (heightParam > 1000000000) {
942  // Add a 2 hour buffer to include blocks which might have had old timestamps
943  const CBlockIndex* pindex = active_chain.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0);
944  if (!pindex) {
945  throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp.");
946  }
947  heightParam = pindex->nHeight;
948  }
949 
950  unsigned int height = (unsigned int) heightParam;
951  unsigned int chainHeight = (unsigned int) active_chain.Height();
952  if (chainHeight < chainman.GetParams().PruneAfterHeight()) {
953  throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning.");
954  } else if (height > chainHeight) {
955  throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height.");
956  } else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
957  LogDebug(BCLog::RPC, "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks.\n");
958  height = chainHeight - MIN_BLOCKS_TO_KEEP;
959  }
960 
961  PruneBlockFilesManual(active_chainstate, height);
962  return GetPruneHeight(chainman.m_blockman, active_chain).value_or(-1);
963 },
964  };
965 }
966 
967 CoinStatsHashType ParseHashType(std::string_view hash_type_input)
968 {
969  if (hash_type_input == "hash_serialized_3") {
970  return CoinStatsHashType::HASH_SERIALIZED;
971  } else if (hash_type_input == "muhash") {
972  return CoinStatsHashType::MUHASH;
973  } else if (hash_type_input == "none") {
975  } else {
976  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("'%s' is not a valid hash_type", hash_type_input));
977  }
978 }
979 
985 static std::optional<kernel::CCoinsStats> GetUTXOStats(CCoinsView* view, node::BlockManager& blockman,
986  kernel::CoinStatsHashType hash_type,
987  const std::function<void()>& interruption_point = {},
988  const CBlockIndex* pindex = nullptr,
989  bool index_requested = true)
990 {
991  // Use CoinStatsIndex if it is requested and available and a hash_type of Muhash or None was requested
992  if ((hash_type == kernel::CoinStatsHashType::MUHASH || hash_type == kernel::CoinStatsHashType::NONE) && g_coin_stats_index && index_requested) {
993  if (pindex) {
994  return g_coin_stats_index->LookUpStats(*pindex);
995  } else {
996  CBlockIndex& block_index = *CHECK_NONFATAL(WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(view->GetBestBlock())));
997  return g_coin_stats_index->LookUpStats(block_index);
998  }
999  }
1000 
1001  // If the coinstats index isn't requested or is otherwise not usable, the
1002  // pindex should either be null or equal to the view's best block. This is
1003  // because without the coinstats index we can only get coinstats about the
1004  // best block.
1005  CHECK_NONFATAL(!pindex || pindex->GetBlockHash() == view->GetBestBlock());
1006 
1007  return kernel::ComputeUTXOStats(hash_type, view, blockman, interruption_point);
1008 }
1009 
1011 {
1012  return RPCHelpMan{
1013  "gettxoutsetinfo",
1014  "Returns statistics about the unspent transaction output set.\n"
1015  "Note this call may take some time if you are not using coinstatsindex.\n",
1016  {
1017  {"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'."},
1018  {"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).",
1019  RPCArgOptions{
1020  .skip_type_check = true,
1021  .type_str = {"", "string or numeric"},
1022  }},
1023  {"use_index", RPCArg::Type::BOOL, RPCArg::Default{true}, "Use coinstatsindex, if available."},
1024  },
1025  RPCResult{
1026  RPCResult::Type::OBJ, "", "",
1027  {
1028  {RPCResult::Type::NUM, "height", "The block height (index) of the returned statistics"},
1029  {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at which these statistics are calculated"},
1030  {RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs"},
1031  {RPCResult::Type::NUM, "bogosize", "Database-independent, meaningless metric indicating the UTXO set size"},
1032  {RPCResult::Type::STR_HEX, "hash_serialized_3", /*optional=*/true, "The serialized hash (only present if 'hash_serialized_3' hash_type is chosen)"},
1033  {RPCResult::Type::STR_HEX, "muhash", /*optional=*/true, "The serialized hash (only present if 'muhash' hash_type is chosen)"},
1034  {RPCResult::Type::NUM, "transactions", /*optional=*/true, "The number of transactions with unspent outputs (not available when coinstatsindex is used)"},
1035  {RPCResult::Type::NUM, "disk_size", /*optional=*/true, "The estimated size of the chainstate on disk (not available when coinstatsindex is used)"},
1036  {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of coins in the UTXO set"},
1037  {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)"},
1038  {RPCResult::Type::OBJ, "block_info", /*optional=*/true, "Info on amounts in the block at this block height (only available if coinstatsindex is used)",
1039  {
1040  {RPCResult::Type::STR_AMOUNT, "prevout_spent", "Total amount of all prevouts spent in this block"},
1041  {RPCResult::Type::STR_AMOUNT, "coinbase", "Coinbase subsidy amount of this block"},
1042  {RPCResult::Type::STR_AMOUNT, "new_outputs_ex_coinbase", "Total amount of new outputs created by this block"},
1043  {RPCResult::Type::STR_AMOUNT, "unspendable", "Total amount of unspendable outputs created in this block"},
1044  {RPCResult::Type::OBJ, "unspendables", "Detailed view of the unspendable categories",
1045  {
1046  {RPCResult::Type::STR_AMOUNT, "genesis_block", "The unspendable amount of the Genesis block subsidy"},
1047  {RPCResult::Type::STR_AMOUNT, "bip30", "Transactions overridden by duplicates (no longer possible with BIP30)"},
1048  {RPCResult::Type::STR_AMOUNT, "scripts", "Amounts sent to scripts that are unspendable (for example OP_RETURN outputs)"},
1049  {RPCResult::Type::STR_AMOUNT, "unclaimed_rewards", "Fee rewards that miners did not claim in their coinbase transaction"},
1050  }}
1051  }},
1052  }},
1053  RPCExamples{
1054  HelpExampleCli("gettxoutsetinfo", "") +
1055  HelpExampleCli("gettxoutsetinfo", R"("none")") +
1056  HelpExampleCli("gettxoutsetinfo", R"("none" 1000)") +
1057  HelpExampleCli("gettxoutsetinfo", R"("none" '"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"')") +
1058  HelpExampleCli("-named gettxoutsetinfo", R"(hash_type='muhash' use_index='false')") +
1059  HelpExampleRpc("gettxoutsetinfo", "") +
1060  HelpExampleRpc("gettxoutsetinfo", R"("none")") +
1061  HelpExampleRpc("gettxoutsetinfo", R"("none", 1000)") +
1062  HelpExampleRpc("gettxoutsetinfo", R"("none", "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09")")
1063  },
1064  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1065 {
1067 
1068  const CBlockIndex* pindex{nullptr};
1069  const CoinStatsHashType hash_type{ParseHashType(self.Arg<std::string_view>("hash_type"))};
1070  bool index_requested = request.params[2].isNull() || request.params[2].get_bool();
1071 
1072  NodeContext& node = EnsureAnyNodeContext(request.context);
1073  ChainstateManager& chainman = EnsureChainman(node);
1074  Chainstate& active_chainstate = chainman.ActiveChainstate();
1075  active_chainstate.ForceFlushStateToDisk(/*wipe_cache=*/false);
1076 
1077  CCoinsView* coins_view;
1078  BlockManager* blockman;
1079  {
1080  LOCK(::cs_main);
1081  coins_view = &active_chainstate.CoinsDB();
1082  blockman = &active_chainstate.m_blockman;
1083  }
1084 
1085  if (!request.params[1].isNull()) {
1086  if (!g_coin_stats_index) {
1087  throw JSONRPCError(RPC_INVALID_PARAMETER, "Querying specific block heights requires coinstatsindex");
1088  }
1089 
1090  if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1091  throw JSONRPCError(RPC_INVALID_PARAMETER, "hash_serialized_3 hash type cannot be queried for a specific block");
1092  }
1093 
1094  if (!index_requested) {
1095  throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot set use_index to false when querying for a specific block");
1096  }
1097  pindex = ParseHashOrHeight(request.params[1], chainman);
1098  }
1099 
1100  if (index_requested && g_coin_stats_index) {
1101  if (!g_coin_stats_index->BlockUntilSyncedToCurrentChain()) {
1102  const IndexSummary summary{g_coin_stats_index->GetSummary()};
1103 
1104  // If a specific block was requested and the index has already synced past that height, we can return the
1105  // data already even though the index is not fully synced yet.
1106  if (pindex && pindex->nHeight > summary.best_block_height) {
1107  throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to get data because coinstatsindex is still syncing. Current height: %d", summary.best_block_height));
1108  }
1109  }
1110  }
1111 
1112  const std::optional<CCoinsStats> maybe_stats = GetUTXOStats(coins_view, *blockman, hash_type, node.rpc_interruption_point, pindex, index_requested);
1113  if (maybe_stats.has_value()) {
1114  const CCoinsStats& stats = maybe_stats.value();
1115  ret.pushKV("height", stats.nHeight);
1116  ret.pushKV("bestblock", stats.hashBlock.GetHex());
1117  ret.pushKV("txouts", stats.nTransactionOutputs);
1118  ret.pushKV("bogosize", stats.nBogoSize);
1119  if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1120  ret.pushKV("hash_serialized_3", stats.hashSerialized.GetHex());
1121  }
1122  if (hash_type == CoinStatsHashType::MUHASH) {
1123  ret.pushKV("muhash", stats.hashSerialized.GetHex());
1124  }
1125  CHECK_NONFATAL(stats.total_amount.has_value());
1126  ret.pushKV("total_amount", ValueFromAmount(stats.total_amount.value()));
1127  if (!stats.index_used) {
1128  ret.pushKV("transactions", stats.nTransactions);
1129  ret.pushKV("disk_size", stats.nDiskSize);
1130  } else {
1131  CCoinsStats prev_stats{};
1132  if (stats.nHeight > 0) {
1133  const CBlockIndex& block_index = *CHECK_NONFATAL(WITH_LOCK(::cs_main, return blockman->LookupBlockIndex(stats.hashBlock)));
1134  const std::optional<CCoinsStats> maybe_prev_stats = GetUTXOStats(coins_view, *blockman, hash_type, node.rpc_interruption_point, block_index.pprev, index_requested);
1135  if (!maybe_prev_stats) {
1136  throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
1137  }
1138  prev_stats = maybe_prev_stats.value();
1139  }
1140 
1141  CAmount block_total_unspendable_amount = stats.total_unspendables_genesis_block +
1142  stats.total_unspendables_bip30 +
1145  CAmount prev_block_total_unspendable_amount = prev_stats.total_unspendables_genesis_block +
1146  prev_stats.total_unspendables_bip30 +
1147  prev_stats.total_unspendables_scripts +
1148  prev_stats.total_unspendables_unclaimed_rewards;
1149 
1150  ret.pushKV("total_unspendable_amount", ValueFromAmount(block_total_unspendable_amount));
1151 
1152  UniValue block_info(UniValue::VOBJ);
1153  // These per-block values should fit uint64 under normal circumstances
1154  arith_uint256 diff_prevout = stats.total_prevout_spent_amount - prev_stats.total_prevout_spent_amount;
1155  arith_uint256 diff_coinbase = stats.total_coinbase_amount - prev_stats.total_coinbase_amount;
1156  arith_uint256 diff_outputs = stats.total_new_outputs_ex_coinbase_amount - prev_stats.total_new_outputs_ex_coinbase_amount;
1157  CAmount prevout_amount = static_cast<CAmount>(diff_prevout.GetLow64());
1158  CAmount coinbase_amount = static_cast<CAmount>(diff_coinbase.GetLow64());
1159  CAmount outputs_amount = static_cast<CAmount>(diff_outputs.GetLow64());
1160  block_info.pushKV("prevout_spent", ValueFromAmount(prevout_amount));
1161  block_info.pushKV("coinbase", ValueFromAmount(coinbase_amount));
1162  block_info.pushKV("new_outputs_ex_coinbase", ValueFromAmount(outputs_amount));
1163  block_info.pushKV("unspendable", ValueFromAmount(block_total_unspendable_amount - prev_block_total_unspendable_amount));
1164 
1165  UniValue unspendables(UniValue::VOBJ);
1166  unspendables.pushKV("genesis_block", ValueFromAmount(stats.total_unspendables_genesis_block - prev_stats.total_unspendables_genesis_block));
1167  unspendables.pushKV("bip30", ValueFromAmount(stats.total_unspendables_bip30 - prev_stats.total_unspendables_bip30));
1168  unspendables.pushKV("scripts", ValueFromAmount(stats.total_unspendables_scripts - prev_stats.total_unspendables_scripts));
1169  unspendables.pushKV("unclaimed_rewards", ValueFromAmount(stats.total_unspendables_unclaimed_rewards - prev_stats.total_unspendables_unclaimed_rewards));
1170  block_info.pushKV("unspendables", std::move(unspendables));
1171 
1172  ret.pushKV("block_info", std::move(block_info));
1173  }
1174  } else {
1175  throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
1176  }
1177  return ret;
1178 },
1179  };
1180 }
1181 
1183 {
1184  return RPCHelpMan{
1185  "gettxout",
1186  "Returns details about an unspent transaction output.\n",
1187  {
1188  {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
1189  {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
1190  {"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."},
1191  },
1192  {
1193  RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "", ""},
1194  RPCResult{"Otherwise", RPCResult::Type::OBJ, "", "", {
1195  {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
1196  {RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
1197  {RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT},
1198  {RPCResult::Type::OBJ, "scriptPubKey", "", {
1199  {RPCResult::Type::STR, "asm", "Disassembly of the output script"},
1200  {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
1201  {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"},
1202  {RPCResult::Type::STR, "type", "The type, eg pubkeyhash"},
1203  {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
1204  }},
1205  {RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
1206  }},
1207  },
1208  RPCExamples{
1209  "\nGet unspent transactions\n"
1210  + HelpExampleCli("listunspent", "") +
1211  "\nView the details\n"
1212  + HelpExampleCli("gettxout", "\"txid\" 1") +
1213  "\nAs a JSON-RPC call\n"
1214  + HelpExampleRpc("gettxout", "\"txid\", 1")
1215  },
1216  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1217 {
1218  NodeContext& node = EnsureAnyNodeContext(request.context);
1219  ChainstateManager& chainman = EnsureChainman(node);
1220  LOCK(cs_main);
1221 
1223 
1224  auto hash{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
1225  COutPoint out{hash, request.params[1].getInt<uint32_t>()};
1226  bool fMempool = true;
1227  if (!request.params[2].isNull())
1228  fMempool = request.params[2].get_bool();
1229 
1230  Chainstate& active_chainstate = chainman.ActiveChainstate();
1231  CCoinsViewCache* coins_view = &active_chainstate.CoinsTip();
1232 
1233  std::optional<Coin> coin;
1234  if (fMempool) {
1235  const CTxMemPool& mempool = EnsureMemPool(node);
1236  LOCK(mempool.cs);
1237  CCoinsViewMemPool view(coins_view, mempool);
1238  if (!mempool.isSpent(out)) coin = view.GetCoin(out);
1239  } else {
1240  coin = coins_view->GetCoin(out);
1241  }
1242  if (!coin) return UniValue::VNULL;
1243 
1244  const CBlockIndex* pindex = active_chainstate.m_blockman.LookupBlockIndex(coins_view->GetBestBlock());
1245  ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
1246  if (coin->nHeight == MEMPOOL_HEIGHT) {
1247  ret.pushKV("confirmations", 0);
1248  } else {
1249  ret.pushKV("confirmations", pindex->nHeight - coin->nHeight + 1);
1250  }
1251  ret.pushKV("value", ValueFromAmount(coin->out.nValue));
1253  ScriptToUniv(coin->out.scriptPubKey, /*out=*/o, /*include_hex=*/true, /*include_address=*/true);
1254  ret.pushKV("scriptPubKey", std::move(o));
1255  ret.pushKV("coinbase", static_cast<bool>(coin->fCoinBase));
1256 
1257  return ret;
1258 },
1259  };
1260 }
1261 
1263 {
1264  return RPCHelpMan{
1265  "verifychain",
1266  "Verifies blockchain database.\n",
1267  {
1268  {"checklevel", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL)},
1269  strprintf("How thorough the block verification is:\n%s", MakeUnorderedList(CHECKLEVEL_DOC))},
1270  {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, 0=all", DEFAULT_CHECKBLOCKS)}, "The number of blocks to check."},
1271  },
1272  RPCResult{
1273  RPCResult::Type::BOOL, "", "Verification finished successfully. If false, check debug.log for reason."},
1274  RPCExamples{
1275  HelpExampleCli("verifychain", "")
1276  + HelpExampleRpc("verifychain", "")
1277  },
1278  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1279 {
1280  const int check_level{request.params[0].isNull() ? DEFAULT_CHECKLEVEL : request.params[0].getInt<int>()};
1281  const int check_depth{request.params[1].isNull() ? DEFAULT_CHECKBLOCKS : request.params[1].getInt<int>()};
1282 
1283  ChainstateManager& chainman = EnsureAnyChainman(request.context);
1284  LOCK(cs_main);
1285 
1286  Chainstate& active_chainstate = chainman.ActiveChainstate();
1287  return CVerifyDB(chainman.GetNotifications()).VerifyDB(
1288  active_chainstate, chainman.GetParams().GetConsensus(), active_chainstate.CoinsTip(), check_level, check_depth) == VerifyDBResult::SUCCESS;
1289 },
1290  };
1291 }
1292 
1293 static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const ChainstateManager& chainman, Consensus::BuriedDeployment dep)
1294 {
1295  // For buried deployments.
1296 
1297  if (!DeploymentEnabled(chainman, dep)) return;
1298 
1300  rv.pushKV("type", "buried");
1301  // getdeploymentinfo reports the softfork as active from when the chain height is
1302  // one below the activation height
1303  rv.pushKV("active", DeploymentActiveAfter(blockindex, chainman, dep));
1304  rv.pushKV("height", chainman.GetConsensus().DeploymentHeight(dep));
1305  softforks.pushKV(DeploymentName(dep), std::move(rv));
1306 }
1307 
1308 static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const ChainstateManager& chainman, Consensus::DeploymentPos id)
1309 {
1310  // For BIP9 deployments.
1311  if (!DeploymentEnabled(chainman, id)) return;
1312  if (blockindex == nullptr) return;
1313 
1314  UniValue bip9(UniValue::VOBJ);
1315  BIP9Info info{chainman.m_versionbitscache.Info(*blockindex, chainman.GetConsensus(), id)};
1316  const auto& depparams{chainman.GetConsensus().vDeployments[id]};
1317 
1318  // BIP9 parameters
1319  if (info.stats.has_value()) {
1320  bip9.pushKV("bit", depparams.bit);
1321  }
1322  bip9.pushKV("start_time", depparams.nStartTime);
1323  bip9.pushKV("timeout", depparams.nTimeout);
1324  bip9.pushKV("min_activation_height", depparams.min_activation_height);
1325 
1326  // BIP9 status
1327  bip9.pushKV("status", info.current_state);
1328  bip9.pushKV("since", info.since);
1329  bip9.pushKV("status_next", info.next_state);
1330 
1331  // BIP9 signalling status, if applicable
1332  if (info.stats.has_value()) {
1333  UniValue statsUV(UniValue::VOBJ);
1334  statsUV.pushKV("period", info.stats->period);
1335  statsUV.pushKV("elapsed", info.stats->elapsed);
1336  statsUV.pushKV("count", info.stats->count);
1337  if (info.stats->threshold > 0 || info.stats->possible) {
1338  statsUV.pushKV("threshold", info.stats->threshold);
1339  statsUV.pushKV("possible", info.stats->possible);
1340  }
1341  bip9.pushKV("statistics", std::move(statsUV));
1342 
1343  std::string sig;
1344  sig.reserve(info.signalling_blocks.size());
1345  for (const bool s : info.signalling_blocks) {
1346  sig.push_back(s ? '#' : '-');
1347  }
1348  bip9.pushKV("signalling", sig);
1349  }
1350 
1352  rv.pushKV("type", "bip9");
1353  bool is_active = false;
1354  if (info.active_since.has_value()) {
1355  rv.pushKV("height", *info.active_since);
1356  is_active = (*info.active_since <= blockindex->nHeight + 1);
1357  }
1358  rv.pushKV("active", is_active);
1359  rv.pushKV("bip9", bip9);
1360  softforks.pushKV(DeploymentName(id), std::move(rv));
1361 }
1362 
1363 // used by rest.cpp:rest_chaininfo, so cannot be static
1365 {
1366  return RPCHelpMan{"getblockchaininfo",
1367  "Returns an object containing various state info regarding blockchain processing.\n",
1368  {},
1369  RPCResult{
1370  RPCResult::Type::OBJ, "", "",
1371  {
1372  {RPCResult::Type::STR, "chain", "current network name (" LIST_CHAIN_NAMES ")"},
1373  {RPCResult::Type::NUM, "blocks", "the height of the most-work fully-validated chain. The genesis block has height 0"},
1374  {RPCResult::Type::NUM, "headers", "the current number of headers we have validated"},
1375  {RPCResult::Type::STR, "bestblockhash", "the hash of the currently best block"},
1376  {RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},
1377  {RPCResult::Type::STR_HEX, "target", "The difficulty target"},
1378  {RPCResult::Type::NUM, "difficulty", "the current difficulty"},
1379  {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
1380  {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
1381  {RPCResult::Type::NUM, "verificationprogress", "estimate of verification progress [0..1]"},
1382  {RPCResult::Type::BOOL, "initialblockdownload", "(debug information) estimate of whether this node is in Initial Block Download mode"},
1383  {RPCResult::Type::STR_HEX, "chainwork", "total amount of work in active chain, in hexadecimal"},
1384  {RPCResult::Type::NUM, "size_on_disk", "the estimated size of the block and undo files on disk"},
1385  {RPCResult::Type::BOOL, "pruned", "if the blocks are subject to pruning"},
1386  {RPCResult::Type::NUM, "pruneheight", /*optional=*/true, "the first block unpruned, all previous blocks were pruned (only present if pruning is enabled)"},
1387  {RPCResult::Type::BOOL, "automatic_pruning", /*optional=*/true, "whether automatic pruning is enabled (only present if pruning is enabled)"},
1388  {RPCResult::Type::NUM, "prune_target_size", /*optional=*/true, "the target size used by pruning (only present if automatic pruning is enabled)"},
1389  {RPCResult::Type::STR_HEX, "signet_challenge", /*optional=*/true, "the block challenge (aka. block script), in hexadecimal (only present if the current network is a signet)"},
1390  (IsDeprecatedRPCEnabled("warnings") ?
1391  RPCResult{RPCResult::Type::STR, "warnings", "any network and blockchain warnings (DEPRECATED)"} :
1392  RPCResult{RPCResult::Type::ARR, "warnings", "any network and blockchain warnings (run with `-deprecatedrpc=warnings` to return the latest warning as a single string)",
1393  {
1394  {RPCResult::Type::STR, "", "warning"},
1395  }
1396  }
1397  ),
1398  }},
1399  RPCExamples{
1400  HelpExampleCli("getblockchaininfo", "")
1401  + HelpExampleRpc("getblockchaininfo", "")
1402  },
1403  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1404 {
1405  ChainstateManager& chainman = EnsureAnyChainman(request.context);
1406  LOCK(cs_main);
1407  Chainstate& active_chainstate = chainman.ActiveChainstate();
1408 
1409  const CBlockIndex& tip{*CHECK_NONFATAL(active_chainstate.m_chain.Tip())};
1410  const int height{tip.nHeight};
1411  UniValue obj(UniValue::VOBJ);
1412  obj.pushKV("chain", chainman.GetParams().GetChainTypeString());
1413  obj.pushKV("blocks", height);
1414  obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
1415  obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex());
1416  obj.pushKV("bits", strprintf("%08x", tip.nBits));
1417  obj.pushKV("target", GetTarget(tip, chainman.GetConsensus().powLimit).GetHex());
1418  obj.pushKV("difficulty", GetDifficulty(tip));
1419  obj.pushKV("time", tip.GetBlockTime());
1420  obj.pushKV("mediantime", tip.GetMedianTimePast());
1421  obj.pushKV("verificationprogress", chainman.GuessVerificationProgress(&tip));
1422  obj.pushKV("initialblockdownload", chainman.IsInitialBlockDownload());
1423  obj.pushKV("chainwork", tip.nChainWork.GetHex());
1424  obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage());
1425  obj.pushKV("pruned", chainman.m_blockman.IsPruneMode());
1426  if (chainman.m_blockman.IsPruneMode()) {
1427  const auto prune_height{GetPruneHeight(chainman.m_blockman, active_chainstate.m_chain)};
1428  obj.pushKV("pruneheight", prune_height ? prune_height.value() + 1 : 0);
1429 
1430  const bool automatic_pruning{chainman.m_blockman.GetPruneTarget() != BlockManager::PRUNE_TARGET_MANUAL};
1431  obj.pushKV("automatic_pruning", automatic_pruning);
1432  if (automatic_pruning) {
1433  obj.pushKV("prune_target_size", chainman.m_blockman.GetPruneTarget());
1434  }
1435  }
1436  if (chainman.GetParams().GetChainType() == ChainType::SIGNET) {
1437  const std::vector<uint8_t>& signet_challenge =
1439  obj.pushKV("signet_challenge", HexStr(signet_challenge));
1440  }
1441 
1442  NodeContext& node = EnsureAnyNodeContext(request.context);
1443  obj.pushKV("warnings", node::GetWarningsForRpc(*CHECK_NONFATAL(node.warnings), IsDeprecatedRPCEnabled("warnings")));
1444  return obj;
1445 },
1446  };
1447 }
1448 
1449 namespace {
1450 const std::vector<RPCResult> RPCHelpForDeployment{
1451  {RPCResult::Type::STR, "type", "one of \"buried\", \"bip9\""},
1452  {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)"},
1453  {RPCResult::Type::BOOL, "active", "true if the rules are enforced for the mempool and the next block"},
1454  {RPCResult::Type::OBJ, "bip9", /*optional=*/true, "status of bip9 softforks (only for \"bip9\" type)",
1455  {
1456  {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)"},
1457  {RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"},
1458  {RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"},
1459  {RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"},
1460  {RPCResult::Type::STR, "status", "status of deployment at specified block (one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\")"},
1461  {RPCResult::Type::NUM, "since", "height of the first block to which the status applies"},
1462  {RPCResult::Type::STR, "status_next", "status of deployment at the next block"},
1463  {RPCResult::Type::OBJ, "statistics", /*optional=*/true, "numeric statistics about signalling for a softfork (only for \"started\" and \"locked_in\" status)",
1464  {
1465  {RPCResult::Type::NUM, "period", "the length in blocks of the signalling period"},
1466  {RPCResult::Type::NUM, "threshold", /*optional=*/true, "the number of blocks with the version bit set required to activate the feature (only for \"started\" status)"},
1467  {RPCResult::Type::NUM, "elapsed", "the number of blocks elapsed since the beginning of the current period"},
1468  {RPCResult::Type::NUM, "count", "the number of blocks with the version bit set in the current period"},
1469  {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)"},
1470  }},
1471  {RPCResult::Type::STR, "signalling", /*optional=*/true, "indicates blocks that signalled with a # and blocks that did not with a -"},
1472  }},
1473 };
1474 
1475 UniValue DeploymentInfo(const CBlockIndex* blockindex, const ChainstateManager& chainman)
1476 {
1477  UniValue softforks(UniValue::VOBJ);
1478  SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_HEIGHTINCB);
1479  SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_DERSIG);
1480  SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_CLTV);
1481  SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_CSV);
1482  SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_SEGWIT);
1483  SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TESTDUMMY);
1484  SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TAPROOT);
1485  return softforks;
1486 }
1487 } // anon namespace
1488 
1490 {
1491  return RPCHelpMan{"getdeploymentinfo",
1492  "Returns an object containing various state info regarding deployments of consensus changes.",
1493  {
1494  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Default{"hash of current chain tip"}, "The block hash at which to query deployment state"},
1495  },
1496  RPCResult{
1497  RPCResult::Type::OBJ, "", "", {
1498  {RPCResult::Type::STR, "hash", "requested block hash (or tip)"},
1499  {RPCResult::Type::NUM, "height", "requested block height (or tip)"},
1500  {RPCResult::Type::ARR, "script_flags", "script verify flags for the block", {
1501  {RPCResult::Type::STR, "flag", "a script verify flag"},
1502  }},
1503  {RPCResult::Type::OBJ_DYN, "deployments", "", {
1504  {RPCResult::Type::OBJ, "xxxx", "name of the deployment", RPCHelpForDeployment}
1505  }},
1506  }
1507  },
1508  RPCExamples{ HelpExampleCli("getdeploymentinfo", "") + HelpExampleRpc("getdeploymentinfo", "") },
1509  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1510  {
1511  const ChainstateManager& chainman = EnsureAnyChainman(request.context);
1512  LOCK(cs_main);
1513  const Chainstate& active_chainstate = chainman.ActiveChainstate();
1514 
1515  const CBlockIndex* blockindex;
1516  if (request.params[0].isNull()) {
1517  blockindex = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
1518  } else {
1519  const uint256 hash(ParseHashV(request.params[0], "blockhash"));
1520  blockindex = chainman.m_blockman.LookupBlockIndex(hash);
1521  if (!blockindex) {
1522  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1523  }
1524  }
1525 
1526  UniValue deploymentinfo(UniValue::VOBJ);
1527  deploymentinfo.pushKV("hash", blockindex->GetBlockHash().ToString());
1528  deploymentinfo.pushKV("height", blockindex->nHeight);
1529  {
1530  const auto flagnames = GetScriptFlagNames(GetBlockScriptFlags(*blockindex, chainman));
1531  UniValue uv_flagnames(UniValue::VARR);
1532  uv_flagnames.push_backV(flagnames.begin(), flagnames.end());
1533  deploymentinfo.pushKV("script_flags", uv_flagnames);
1534  }
1535  deploymentinfo.pushKV("deployments", DeploymentInfo(blockindex, chainman));
1536  return deploymentinfo;
1537  },
1538  };
1539 }
1540 
1543 {
1544  bool operator()(const CBlockIndex* a, const CBlockIndex* b) const
1545  {
1546  /* Make sure that unequal blocks with the same height do not compare
1547  equal. Use the pointers themselves to make a distinction. */
1548 
1549  if (a->nHeight != b->nHeight)
1550  return (a->nHeight > b->nHeight);
1551 
1552  return a < b;
1553  }
1554 };
1555 
1557 {
1558  return RPCHelpMan{"getchaintips",
1559  "Return information about all known tips in the block tree,"
1560  " including the main chain as well as orphaned branches.\n",
1561  {},
1562  RPCResult{
1563  RPCResult::Type::ARR, "", "",
1564  {{RPCResult::Type::OBJ, "", "",
1565  {
1566  {RPCResult::Type::NUM, "height", "height of the chain tip"},
1567  {RPCResult::Type::STR_HEX, "hash", "block hash of the tip"},
1568  {RPCResult::Type::NUM, "branchlen", "zero for main chain, otherwise length of branch connecting the tip to the main chain"},
1569  {RPCResult::Type::STR, "status", "status of the chain, \"active\" for the main chain\n"
1570  "Possible values for status:\n"
1571  "1. \"invalid\" This branch contains at least one invalid block\n"
1572  "2. \"headers-only\" Not all blocks for this branch are available, but the headers are valid\n"
1573  "3. \"valid-headers\" All blocks are available for this branch, but they were never fully validated\n"
1574  "4. \"valid-fork\" This branch is not part of the active chain, but is fully validated\n"
1575  "5. \"active\" This is the tip of the active main chain, which is certainly valid"},
1576  }}}},
1577  RPCExamples{
1578  HelpExampleCli("getchaintips", "")
1579  + HelpExampleRpc("getchaintips", "")
1580  },
1581  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1582 {
1583  ChainstateManager& chainman = EnsureAnyChainman(request.context);
1584  LOCK(cs_main);
1585  CChain& active_chain = chainman.ActiveChain();
1586 
1587  /*
1588  * Idea: The set of chain tips is the active chain tip, plus orphan blocks which do not have another orphan building off of them.
1589  * Algorithm:
1590  * - Make one pass through BlockIndex(), picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers.
1591  * - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip.
1592  * - Add the active chain tip
1593  */
1594  std::set<const CBlockIndex*, CompareBlocksByHeight> setTips;
1595  std::set<const CBlockIndex*> setOrphans;
1596  std::set<const CBlockIndex*> setPrevs;
1597 
1598  for (const auto& [_, block_index] : chainman.BlockIndex()) {
1599  if (!active_chain.Contains(&block_index)) {
1600  setOrphans.insert(&block_index);
1601  setPrevs.insert(block_index.pprev);
1602  }
1603  }
1604 
1605  for (std::set<const CBlockIndex*>::iterator it = setOrphans.begin(); it != setOrphans.end(); ++it) {
1606  if (setPrevs.erase(*it) == 0) {
1607  setTips.insert(*it);
1608  }
1609  }
1610 
1611  // Always report the currently active tip.
1612  setTips.insert(active_chain.Tip());
1613 
1614  /* Construct the output array. */
1615  UniValue res(UniValue::VARR);
1616  for (const CBlockIndex* block : setTips) {
1617  UniValue obj(UniValue::VOBJ);
1618  obj.pushKV("height", block->nHeight);
1619  obj.pushKV("hash", block->phashBlock->GetHex());
1620 
1621  const int branchLen = block->nHeight - active_chain.FindFork(block)->nHeight;
1622  obj.pushKV("branchlen", branchLen);
1623 
1624  std::string status;
1625  if (active_chain.Contains(block)) {
1626  // This block is part of the currently active chain.
1627  status = "active";
1628  } else if (block->nStatus & BLOCK_FAILED_VALID) {
1629  // This block or one of its ancestors is invalid.
1630  status = "invalid";
1631  } else if (!block->HaveNumChainTxs()) {
1632  // This block cannot be connected because full block data for it or one of its parents is missing.
1633  status = "headers-only";
1634  } else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {
1635  // This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.
1636  status = "valid-fork";
1637  } else if (block->IsValid(BLOCK_VALID_TREE)) {
1638  // The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.
1639  status = "valid-headers";
1640  } else {
1641  // No clue.
1642  status = "unknown";
1643  }
1644  obj.pushKV("status", status);
1645 
1646  res.push_back(std::move(obj));
1647  }
1648 
1649  return res;
1650 },
1651  };
1652 }
1653 
1655 {
1656  return RPCHelpMan{
1657  "preciousblock",
1658  "Treats a block as if it were received before others with the same work.\n"
1659  "\nA later preciousblock call can override the effect of an earlier one.\n"
1660  "\nThe effects of preciousblock are not retained across restarts.\n",
1661  {
1662  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as precious"},
1663  },
1665  RPCExamples{
1666  HelpExampleCli("preciousblock", "\"blockhash\"")
1667  + HelpExampleRpc("preciousblock", "\"blockhash\"")
1668  },
1669  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1670 {
1671  uint256 hash(ParseHashV(request.params[0], "blockhash"));
1672  CBlockIndex* pblockindex;
1673 
1674  ChainstateManager& chainman = EnsureAnyChainman(request.context);
1675  {
1676  LOCK(cs_main);
1677  pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1678  if (!pblockindex) {
1679  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1680  }
1681  }
1682 
1683  BlockValidationState state;
1684  chainman.ActiveChainstate().PreciousBlock(state, pblockindex);
1685 
1686  if (!state.IsValid()) {
1687  throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
1688  }
1689 
1690  return UniValue::VNULL;
1691 },
1692  };
1693 }
1694 
1695 void InvalidateBlock(ChainstateManager& chainman, const uint256 block_hash) {
1696  BlockValidationState state;
1697  CBlockIndex* pblockindex;
1698  {
1699  LOCK(chainman.GetMutex());
1700  pblockindex = chainman.m_blockman.LookupBlockIndex(block_hash);
1701  if (!pblockindex) {
1702  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1703  }
1704  }
1705  chainman.ActiveChainstate().InvalidateBlock(state, pblockindex);
1706 
1707  if (state.IsValid()) {
1708  chainman.ActiveChainstate().ActivateBestChain(state);
1709  }
1710 
1711  if (!state.IsValid()) {
1712  throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
1713  }
1714 }
1715 
1717 {
1718  return RPCHelpMan{
1719  "invalidateblock",
1720  "Permanently marks a block as invalid, as if it violated a consensus rule.\n",
1721  {
1722  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as invalid"},
1723  },
1725  RPCExamples{
1726  HelpExampleCli("invalidateblock", "\"blockhash\"")
1727  + HelpExampleRpc("invalidateblock", "\"blockhash\"")
1728  },
1729  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1730 {
1731  ChainstateManager& chainman = EnsureAnyChainman(request.context);
1732  uint256 hash(ParseHashV(request.params[0], "blockhash"));
1733 
1734  InvalidateBlock(chainman, hash);
1735 
1736  return UniValue::VNULL;
1737 },
1738  };
1739 }
1740 
1741 void ReconsiderBlock(ChainstateManager& chainman, uint256 block_hash) {
1742  {
1743  LOCK(chainman.GetMutex());
1744  CBlockIndex* pblockindex = chainman.m_blockman.LookupBlockIndex(block_hash);
1745  if (!pblockindex) {
1746  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1747  }
1748 
1749  chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex);
1750  chainman.RecalculateBestHeader();
1751  }
1752 
1753  BlockValidationState state;
1754  chainman.ActiveChainstate().ActivateBestChain(state);
1755 
1756  if (!state.IsValid()) {
1757  throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
1758  }
1759 }
1760 
1762 {
1763  return RPCHelpMan{
1764  "reconsiderblock",
1765  "Removes invalidity status of a block, its ancestors and its descendants, reconsider them for activation.\n"
1766  "This can be used to undo the effects of invalidateblock.\n",
1767  {
1768  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to reconsider"},
1769  },
1771  RPCExamples{
1772  HelpExampleCli("reconsiderblock", "\"blockhash\"")
1773  + HelpExampleRpc("reconsiderblock", "\"blockhash\"")
1774  },
1775  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1776 {
1777  ChainstateManager& chainman = EnsureAnyChainman(request.context);
1778  uint256 hash(ParseHashV(request.params[0], "blockhash"));
1779 
1780  ReconsiderBlock(chainman, hash);
1781 
1782  return UniValue::VNULL;
1783 },
1784  };
1785 }
1786 
1788 {
1789  return RPCHelpMan{
1790  "getchaintxstats",
1791  "Compute statistics about the total number and rate of transactions in the chain.\n",
1792  {
1793  {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{"one month"}, "Size of the window in number of blocks"},
1794  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"chain tip"}, "The hash of the block that ends the window."},
1795  },
1796  RPCResult{
1797  RPCResult::Type::OBJ, "", "",
1798  {
1799  {RPCResult::Type::NUM_TIME, "time", "The timestamp for the final block in the window, expressed in " + UNIX_EPOCH_TIME},
1800  {RPCResult::Type::NUM, "txcount", /*optional=*/true,
1801  "The total number of transactions in the chain up to that point, if known. "
1802  "It may be unknown when using assumeutxo."},
1803  {RPCResult::Type::STR_HEX, "window_final_block_hash", "The hash of the final block in the window"},
1804  {RPCResult::Type::NUM, "window_final_block_height", "The height of the final block in the window."},
1805  {RPCResult::Type::NUM, "window_block_count", "Size of the window in number of blocks"},
1806  {RPCResult::Type::NUM, "window_interval", /*optional=*/true, "The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0"},
1807  {RPCResult::Type::NUM, "window_tx_count", /*optional=*/true,
1808  "The number of transactions in the window. "
1809  "Only returned if \"window_block_count\" is > 0 and if txcount exists for the start and end of the window."},
1810  {RPCResult::Type::NUM, "txrate", /*optional=*/true,
1811  "The average rate of transactions per second in the window. "
1812  "Only returned if \"window_interval\" is > 0 and if window_tx_count exists."},
1813  }},
1814  RPCExamples{
1815  HelpExampleCli("getchaintxstats", "")
1816  + HelpExampleRpc("getchaintxstats", "2016")
1817  },
1818  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1819 {
1820  ChainstateManager& chainman = EnsureAnyChainman(request.context);
1821  const CBlockIndex* pindex;
1822  int blockcount = 30 * 24 * 60 * 60 / chainman.GetParams().GetConsensus().nPowTargetSpacing; // By default: 1 month
1823 
1824  if (request.params[1].isNull()) {
1825  LOCK(cs_main);
1826  pindex = chainman.ActiveChain().Tip();
1827  } else {
1828  uint256 hash(ParseHashV(request.params[1], "blockhash"));
1829  LOCK(cs_main);
1830  pindex = chainman.m_blockman.LookupBlockIndex(hash);
1831  if (!pindex) {
1832  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1833  }
1834  if (!chainman.ActiveChain().Contains(pindex)) {
1835  throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain");
1836  }
1837  }
1838 
1839  CHECK_NONFATAL(pindex != nullptr);
1840 
1841  if (request.params[0].isNull()) {
1842  blockcount = std::max(0, std::min(blockcount, pindex->nHeight - 1));
1843  } else {
1844  blockcount = request.params[0].getInt<int>();
1845 
1846  if (blockcount < 0 || (blockcount > 0 && blockcount >= pindex->nHeight)) {
1847  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 0 and the block's height - 1");
1848  }
1849  }
1850 
1851  const CBlockIndex& past_block{*CHECK_NONFATAL(pindex->GetAncestor(pindex->nHeight - blockcount))};
1852  const int64_t nTimeDiff{pindex->GetMedianTimePast() - past_block.GetMedianTimePast()};
1853 
1855  ret.pushKV("time", pindex->nTime);
1856  if (pindex->m_chain_tx_count) {
1857  ret.pushKV("txcount", pindex->m_chain_tx_count);
1858  }
1859  ret.pushKV("window_final_block_hash", pindex->GetBlockHash().GetHex());
1860  ret.pushKV("window_final_block_height", pindex->nHeight);
1861  ret.pushKV("window_block_count", blockcount);
1862  if (blockcount > 0) {
1863  ret.pushKV("window_interval", nTimeDiff);
1864  if (pindex->m_chain_tx_count != 0 && past_block.m_chain_tx_count != 0) {
1865  const auto window_tx_count = pindex->m_chain_tx_count - past_block.m_chain_tx_count;
1866  ret.pushKV("window_tx_count", window_tx_count);
1867  if (nTimeDiff > 0) {
1868  ret.pushKV("txrate", double(window_tx_count) / nTimeDiff);
1869  }
1870  }
1871  }
1872 
1873  return ret;
1874 },
1875  };
1876 }
1877 
1878 template<typename T>
1879 static T CalculateTruncatedMedian(std::vector<T>& scores)
1880 {
1881  size_t size = scores.size();
1882  if (size == 0) {
1883  return 0;
1884  }
1885 
1886  std::sort(scores.begin(), scores.end());
1887  if (size % 2 == 0) {
1888  return (scores[size / 2 - 1] + scores[size / 2]) / 2;
1889  } else {
1890  return scores[size / 2];
1891  }
1892 }
1893 
1894 void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight)
1895 {
1896  if (scores.empty()) {
1897  return;
1898  }
1899 
1900  std::sort(scores.begin(), scores.end());
1901 
1902  // 10th, 25th, 50th, 75th, and 90th percentile weight units.
1903  const double weights[NUM_GETBLOCKSTATS_PERCENTILES] = {
1904  total_weight / 10.0, total_weight / 4.0, total_weight / 2.0, (total_weight * 3.0) / 4.0, (total_weight * 9.0) / 10.0
1905  };
1906 
1907  int64_t next_percentile_index = 0;
1908  int64_t cumulative_weight = 0;
1909  for (const auto& element : scores) {
1910  cumulative_weight += element.second;
1911  while (next_percentile_index < NUM_GETBLOCKSTATS_PERCENTILES && cumulative_weight >= weights[next_percentile_index]) {
1912  result[next_percentile_index] = element.first;
1913  ++next_percentile_index;
1914  }
1915  }
1916 
1917  // Fill any remaining percentiles with the last value.
1918  for (int64_t i = next_percentile_index; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {
1919  result[i] = scores.back().first;
1920  }
1921 }
1922 
1923 template<typename T>
1924 static inline bool SetHasKeys(const std::set<T>& set) {return false;}
1925 template<typename T, typename Tk, typename... Args>
1926 static inline bool SetHasKeys(const std::set<T>& set, const Tk& key, const Args&... args)
1927 {
1928  return (set.contains(key)) || SetHasKeys(set, args...);
1929 }
1930 
1931 // outpoint (needed for the utxo index) + nHeight + fCoinBase
1932 static constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);
1933 
1935 {
1936  return RPCHelpMan{
1937  "getblockstats",
1938  "Compute per block statistics for a given window. All amounts are in satoshis.\n"
1939  "It won't work for some heights with pruning.\n",
1940  {
1941  {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block",
1942  RPCArgOptions{
1943  .skip_type_check = true,
1944  .type_str = {"", "string or numeric"},
1945  }},
1946  {"stats", RPCArg::Type::ARR, RPCArg::DefaultHint{"all values"}, "Values to plot (see result below)",
1947  {
1948  {"height", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
1949  {"time", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
1950  },
1952  },
1953  RPCResult{
1954  RPCResult::Type::OBJ, "", "",
1955  {
1956  {RPCResult::Type::NUM, "avgfee", /*optional=*/true, "Average fee in the block"},
1957  {RPCResult::Type::NUM, "avgfeerate", /*optional=*/true, "Average feerate (in satoshis per virtual byte)"},
1958  {RPCResult::Type::NUM, "avgtxsize", /*optional=*/true, "Average transaction size"},
1959  {RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "The block hash (to check for potential reorgs)"},
1960  {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)",
1961  {
1962  {RPCResult::Type::NUM, "10th_percentile_feerate", "The 10th percentile feerate"},
1963  {RPCResult::Type::NUM, "25th_percentile_feerate", "The 25th percentile feerate"},
1964  {RPCResult::Type::NUM, "50th_percentile_feerate", "The 50th percentile feerate"},
1965  {RPCResult::Type::NUM, "75th_percentile_feerate", "The 75th percentile feerate"},
1966  {RPCResult::Type::NUM, "90th_percentile_feerate", "The 90th percentile feerate"},
1967  }},
1968  {RPCResult::Type::NUM, "height", /*optional=*/true, "The height of the block"},
1969  {RPCResult::Type::NUM, "ins", /*optional=*/true, "The number of inputs (excluding coinbase)"},
1970  {RPCResult::Type::NUM, "maxfee", /*optional=*/true, "Maximum fee in the block"},
1971  {RPCResult::Type::NUM, "maxfeerate", /*optional=*/true, "Maximum feerate (in satoshis per virtual byte)"},
1972  {RPCResult::Type::NUM, "maxtxsize", /*optional=*/true, "Maximum transaction size"},
1973  {RPCResult::Type::NUM, "medianfee", /*optional=*/true, "Truncated median fee in the block"},
1974  {RPCResult::Type::NUM, "mediantime", /*optional=*/true, "The block median time past"},
1975  {RPCResult::Type::NUM, "mediantxsize", /*optional=*/true, "Truncated median transaction size"},
1976  {RPCResult::Type::NUM, "minfee", /*optional=*/true, "Minimum fee in the block"},
1977  {RPCResult::Type::NUM, "minfeerate", /*optional=*/true, "Minimum feerate (in satoshis per virtual byte)"},
1978  {RPCResult::Type::NUM, "mintxsize", /*optional=*/true, "Minimum transaction size"},
1979  {RPCResult::Type::NUM, "outs", /*optional=*/true, "The number of outputs"},
1980  {RPCResult::Type::NUM, "subsidy", /*optional=*/true, "The block subsidy"},
1981  {RPCResult::Type::NUM, "swtotal_size", /*optional=*/true, "Total size of all segwit transactions"},
1982  {RPCResult::Type::NUM, "swtotal_weight", /*optional=*/true, "Total weight of all segwit transactions"},
1983  {RPCResult::Type::NUM, "swtxs", /*optional=*/true, "The number of segwit transactions"},
1984  {RPCResult::Type::NUM, "time", /*optional=*/true, "The block time"},
1985  {RPCResult::Type::NUM, "total_out", /*optional=*/true, "Total amount in all outputs (excluding coinbase and thus reward [ie subsidy + totalfee])"},
1986  {RPCResult::Type::NUM, "total_size", /*optional=*/true, "Total size of all non-coinbase transactions"},
1987  {RPCResult::Type::NUM, "total_weight", /*optional=*/true, "Total weight of all non-coinbase transactions"},
1988  {RPCResult::Type::NUM, "totalfee", /*optional=*/true, "The fee total"},
1989  {RPCResult::Type::NUM, "txs", /*optional=*/true, "The number of transactions (including coinbase)"},
1990  {RPCResult::Type::NUM, "utxo_increase", /*optional=*/true, "The increase/decrease in the number of unspent outputs (not discounting op_return and similar)"},
1991  {RPCResult::Type::NUM, "utxo_size_inc", /*optional=*/true, "The increase/decrease in size for the utxo index (not discounting op_return and similar)"},
1992  {RPCResult::Type::NUM, "utxo_increase_actual", /*optional=*/true, "The increase/decrease in the number of unspent outputs, not counting unspendables"},
1993  {RPCResult::Type::NUM, "utxo_size_inc_actual", /*optional=*/true, "The increase/decrease in size for the utxo index, not counting unspendables"},
1994  }},
1995  RPCExamples{
1996  HelpExampleCli("getblockstats", R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
1997  HelpExampleCli("getblockstats", R"(1000 '["minfeerate","avgfeerate"]')") +
1998  HelpExampleRpc("getblockstats", R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") +
1999  HelpExampleRpc("getblockstats", R"(1000, ["minfeerate","avgfeerate"])")
2000  },
2001  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2002 {
2003  ChainstateManager& chainman = EnsureAnyChainman(request.context);
2004  const CBlockIndex& pindex{*CHECK_NONFATAL(ParseHashOrHeight(request.params[0], chainman))};
2005 
2006  std::set<std::string> stats;
2007  if (!request.params[1].isNull()) {
2008  const UniValue stats_univalue = request.params[1].get_array();
2009  for (unsigned int i = 0; i < stats_univalue.size(); i++) {
2010  const std::string stat = stats_univalue[i].get_str();
2011  stats.insert(stat);
2012  }
2013  }
2014 
2015  const CBlock& block = GetBlockChecked(chainman.m_blockman, pindex);
2016  const CBlockUndo& blockUndo = GetUndoChecked(chainman.m_blockman, pindex);
2017 
2018  const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default)
2019  const bool do_mediantxsize = do_all || stats.contains("mediantxsize");
2020  const bool do_medianfee = do_all || stats.contains("medianfee");
2021  const bool do_feerate_percentiles = do_all || stats.contains("feerate_percentiles");
2022  const bool loop_inputs = do_all || do_medianfee || do_feerate_percentiles ||
2023  SetHasKeys(stats, "utxo_increase", "utxo_increase_actual", "utxo_size_inc", "utxo_size_inc_actual", "totalfee", "avgfee", "avgfeerate", "minfee", "maxfee", "minfeerate", "maxfeerate");
2024  const bool loop_outputs = do_all || loop_inputs || stats.contains("total_out");
2025  const bool do_calculate_size = do_mediantxsize ||
2026  SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize", "maxtxsize", "swtotal_size");
2027  const bool do_calculate_weight = do_all || SetHasKeys(stats, "total_weight", "avgfeerate", "swtotal_weight", "avgfeerate", "feerate_percentiles", "minfeerate", "maxfeerate");
2028  const bool do_calculate_sw = do_all || SetHasKeys(stats, "swtxs", "swtotal_size", "swtotal_weight");
2029 
2030  CAmount maxfee = 0;
2031  CAmount maxfeerate = 0;
2032  CAmount minfee = MAX_MONEY;
2033  CAmount minfeerate = MAX_MONEY;
2034  CAmount total_out = 0;
2035  CAmount totalfee = 0;
2036  int64_t inputs = 0;
2037  int64_t maxtxsize = 0;
2038  int64_t mintxsize = MAX_BLOCK_SERIALIZED_SIZE;
2039  int64_t outputs = 0;
2040  int64_t swtotal_size = 0;
2041  int64_t swtotal_weight = 0;
2042  int64_t swtxs = 0;
2043  int64_t total_size = 0;
2044  int64_t total_weight = 0;
2045  int64_t utxos = 0;
2046  int64_t utxo_size_inc = 0;
2047  int64_t utxo_size_inc_actual = 0;
2048  std::vector<CAmount> fee_array;
2049  std::vector<std::pair<CAmount, int64_t>> feerate_array;
2050  std::vector<int64_t> txsize_array;
2051 
2052  for (size_t i = 0; i < block.vtx.size(); ++i) {
2053  const auto& tx = block.vtx.at(i);
2054  outputs += tx->vout.size();
2055 
2056  CAmount tx_total_out = 0;
2057  if (loop_outputs) {
2058  for (const CTxOut& out : tx->vout) {
2059  tx_total_out += out.nValue;
2060 
2061  uint64_t out_size{GetSerializeSize(out) + PER_UTXO_OVERHEAD};
2062  utxo_size_inc += out_size;
2063 
2064  // The Genesis block and the repeated BIP30 block coinbases don't change the UTXO
2065  // set counts, so they have to be excluded from the statistics
2066  if (pindex.nHeight == 0 || (IsBIP30Repeat(pindex) && tx->IsCoinBase())) continue;
2067  // Skip unspendable outputs since they are not included in the UTXO set
2068  if (out.scriptPubKey.IsUnspendable()) continue;
2069 
2070  ++utxos;
2071  utxo_size_inc_actual += out_size;
2072  }
2073  }
2074 
2075  if (tx->IsCoinBase()) {
2076  continue;
2077  }
2078 
2079  inputs += tx->vin.size(); // Don't count coinbase's fake input
2080  total_out += tx_total_out; // Don't count coinbase reward
2081 
2082  int64_t tx_size = 0;
2083  if (do_calculate_size) {
2084 
2085  tx_size = tx->ComputeTotalSize();
2086  if (do_mediantxsize) {
2087  txsize_array.push_back(tx_size);
2088  }
2089  maxtxsize = std::max(maxtxsize, tx_size);
2090  mintxsize = std::min(mintxsize, tx_size);
2091  total_size += tx_size;
2092  }
2093 
2094  int64_t weight = 0;
2095  if (do_calculate_weight) {
2096  weight = GetTransactionWeight(*tx);
2097  total_weight += weight;
2098  }
2099 
2100  if (do_calculate_sw && tx->HasWitness()) {
2101  ++swtxs;
2102  swtotal_size += tx_size;
2103  swtotal_weight += weight;
2104  }
2105 
2106  if (loop_inputs) {
2107  CAmount tx_total_in = 0;
2108  const auto& txundo = blockUndo.vtxundo.at(i - 1);
2109  for (const Coin& coin: txundo.vprevout) {
2110  const CTxOut& prevoutput = coin.out;
2111 
2112  tx_total_in += prevoutput.nValue;
2113  uint64_t prevout_size{GetSerializeSize(prevoutput) + PER_UTXO_OVERHEAD};
2114  utxo_size_inc -= prevout_size;
2115  utxo_size_inc_actual -= prevout_size;
2116  }
2117 
2118  CAmount txfee = tx_total_in - tx_total_out;
2119  CHECK_NONFATAL(MoneyRange(txfee));
2120  if (do_medianfee) {
2121  fee_array.push_back(txfee);
2122  }
2123  maxfee = std::max(maxfee, txfee);
2124  minfee = std::min(minfee, txfee);
2125  totalfee += txfee;
2126 
2127  // New feerate uses satoshis per virtual byte instead of per serialized byte
2128  CAmount feerate = weight ? (txfee * WITNESS_SCALE_FACTOR) / weight : 0;
2129  if (do_feerate_percentiles) {
2130  feerate_array.emplace_back(feerate, weight);
2131  }
2132  maxfeerate = std::max(maxfeerate, feerate);
2133  minfeerate = std::min(minfeerate, feerate);
2134  }
2135  }
2136 
2137  CAmount feerate_percentiles[NUM_GETBLOCKSTATS_PERCENTILES] = { 0 };
2138  CalculatePercentilesByWeight(feerate_percentiles, feerate_array, total_weight);
2139 
2140  UniValue feerates_res(UniValue::VARR);
2141  for (int64_t i = 0; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {
2142  feerates_res.push_back(feerate_percentiles[i]);
2143  }
2144 
2145  UniValue ret_all(UniValue::VOBJ);
2146  ret_all.pushKV("avgfee", (block.vtx.size() > 1) ? totalfee / (block.vtx.size() - 1) : 0);
2147  ret_all.pushKV("avgfeerate", total_weight ? (totalfee * WITNESS_SCALE_FACTOR) / total_weight : 0); // Unit: sat/vbyte
2148  ret_all.pushKV("avgtxsize", (block.vtx.size() > 1) ? total_size / (block.vtx.size() - 1) : 0);
2149  ret_all.pushKV("blockhash", pindex.GetBlockHash().GetHex());
2150  ret_all.pushKV("feerate_percentiles", std::move(feerates_res));
2151  ret_all.pushKV("height", pindex.nHeight);
2152  ret_all.pushKV("ins", inputs);
2153  ret_all.pushKV("maxfee", maxfee);
2154  ret_all.pushKV("maxfeerate", maxfeerate);
2155  ret_all.pushKV("maxtxsize", maxtxsize);
2156  ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
2157  ret_all.pushKV("mediantime", pindex.GetMedianTimePast());
2158  ret_all.pushKV("mediantxsize", CalculateTruncatedMedian(txsize_array));
2159  ret_all.pushKV("minfee", (minfee == MAX_MONEY) ? 0 : minfee);
2160  ret_all.pushKV("minfeerate", (minfeerate == MAX_MONEY) ? 0 : minfeerate);
2161  ret_all.pushKV("mintxsize", mintxsize == MAX_BLOCK_SERIALIZED_SIZE ? 0 : mintxsize);
2162  ret_all.pushKV("outs", outputs);
2163  ret_all.pushKV("subsidy", GetBlockSubsidy(pindex.nHeight, chainman.GetParams().GetConsensus()));
2164  ret_all.pushKV("swtotal_size", swtotal_size);
2165  ret_all.pushKV("swtotal_weight", swtotal_weight);
2166  ret_all.pushKV("swtxs", swtxs);
2167  ret_all.pushKV("time", pindex.GetBlockTime());
2168  ret_all.pushKV("total_out", total_out);
2169  ret_all.pushKV("total_size", total_size);
2170  ret_all.pushKV("total_weight", total_weight);
2171  ret_all.pushKV("totalfee", totalfee);
2172  ret_all.pushKV("txs", block.vtx.size());
2173  ret_all.pushKV("utxo_increase", outputs - inputs);
2174  ret_all.pushKV("utxo_size_inc", utxo_size_inc);
2175  ret_all.pushKV("utxo_increase_actual", utxos - inputs);
2176  ret_all.pushKV("utxo_size_inc_actual", utxo_size_inc_actual);
2177 
2178  if (do_all) {
2179  return ret_all;
2180  }
2181 
2183  for (const std::string& stat : stats) {
2184  const UniValue& value = ret_all[stat];
2185  if (value.isNull()) {
2186  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid selected statistic '%s'", stat));
2187  }
2188  ret.pushKV(stat, value);
2189  }
2190  return ret;
2191 },
2192  };
2193 }
2194 
2195 namespace {
2197 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)
2198 {
2199  scan_progress = 0;
2200  count = 0;
2201  while (cursor->Valid()) {
2202  COutPoint key;
2203  Coin coin;
2204  if (!cursor->GetKey(key) || !cursor->GetValue(coin)) return false;
2205  if (++count % 8192 == 0) {
2206  interruption_point();
2207  if (should_abort) {
2208  // allow to abort the scan via the abort reference
2209  return false;
2210  }
2211  }
2212  if (count % 256 == 0) {
2213  // update progress reference every 256 item
2214  uint32_t high = 0x100 * *UCharCast(key.hash.begin()) + *(UCharCast(key.hash.begin()) + 1);
2215  scan_progress = (int)(high * 100.0 / 65536.0 + 0.5);
2216  }
2217  if (needles.contains(coin.out.scriptPubKey)) {
2218  out_results.emplace(key, coin);
2219  }
2220  cursor->Next();
2221  }
2222  scan_progress = 100;
2223  return true;
2224 }
2225 } // namespace
2226 
2228 static std::atomic<int> g_scan_progress;
2229 static std::atomic<bool> g_scan_in_progress;
2230 static std::atomic<bool> g_should_abort_scan;
2232 {
2233 private:
2234  bool m_could_reserve{false};
2235 public:
2236  explicit CoinsViewScanReserver() = default;
2237 
2238  bool reserve() {
2240  if (g_scan_in_progress.exchange(true)) {
2241  return false;
2242  }
2244  m_could_reserve = true;
2245  return true;
2246  }
2247 
2249  if (m_could_reserve) {
2250  g_scan_in_progress = false;
2251  g_scan_progress = 0;
2252  }
2253  }
2254 };
2255 
2256 static const auto scan_action_arg_desc = RPCArg{
2257  "action", RPCArg::Type::STR, RPCArg::Optional::NO, "The action to execute\n"
2258  "\"start\" for starting a scan\n"
2259  "\"abort\" for aborting the current scan (returns true when abort was successful)\n"
2260  "\"status\" for progress report (in %) of the current scan"
2261 };
2262 
2263 static const auto output_descriptor_obj = RPCArg{
2264  "", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with output descriptor and metadata",
2265  {
2266  {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
2267  {"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "The range of HD chain indexes to explore (either end or [begin,end])"},
2268  }
2269 };
2270 
2271 static const auto scan_objects_arg_desc = RPCArg{
2272  "scanobjects", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "Array of scan objects. Required for \"start\" action\n"
2273  "Every scan object is either a string descriptor or an object:",
2274  {
2275  {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
2277  },
2278  RPCArgOptions{.oneline_description="[scanobjects,...]"},
2279 };
2280 
2281 static const auto scan_result_abort = RPCResult{
2282  "when action=='abort'", RPCResult::Type::BOOL, "success",
2283  "True if scan will be aborted (not necessarily before this RPC returns), or false if there is no scan to abort"
2284 };
2286  "when action=='status' and no scan is in progress - possibly already completed", RPCResult::Type::NONE, "", ""
2287 };
2289  "when action=='status' and a scan is currently in progress", RPCResult::Type::OBJ, "", "",
2290  {{RPCResult::Type::NUM, "progress", "Approximate percent complete"},}
2291 };
2292 
2293 
2295 {
2296  // raw() descriptor corresponding to mainnet address 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S
2297  const std::string EXAMPLE_DESCRIPTOR_RAW = "raw(76a91411b366edfc0a8b66feebae5c2e25a7b6a5d1cf3188ac)#fm24fxxy";
2298 
2299  return RPCHelpMan{
2300  "scantxoutset",
2301  "Scans the unspent transaction output set for entries that match certain output descriptors.\n"
2302  "Examples of output descriptors are:\n"
2303  " addr(<address>) Outputs whose output script corresponds to the specified address (does not include P2PK)\n"
2304  " raw(<hex script>) Outputs whose output script equals the specified hex-encoded bytes\n"
2305  " combo(<pubkey>) P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH outputs for the given pubkey\n"
2306  " pkh(<pubkey>) P2PKH outputs for the given pubkey\n"
2307  " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n"
2308  " tr(<pubkey>) P2TR\n"
2309  " tr(<pubkey>,{pk(<pubkey>)}) P2TR with single fallback pubkey in tapscript\n"
2310  " rawtr(<pubkey>) P2TR with the specified key as output key rather than inner\n"
2311  " wsh(and_v(v:pk(<pubkey>),after(2))) P2WSH miniscript with mandatory pubkey and a timelock\n"
2312  "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
2313  "or more path elements separated by \"/\", and optionally ending in \"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
2314  "unhardened or hardened child keys.\n"
2315  "In the latter case, a range needs to be specified by below if different from 1000.\n"
2316  "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n",
2317  {
2320  },
2321  {
2322  RPCResult{"when action=='start'; only returns after scan completes", RPCResult::Type::OBJ, "", "", {
2323  {RPCResult::Type::BOOL, "success", "Whether the scan was completed"},
2324  {RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs scanned"},
2325  {RPCResult::Type::NUM, "height", "The block height at which the scan was done"},
2326  {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
2327  {RPCResult::Type::ARR, "unspents", "",
2328  {
2329  {RPCResult::Type::OBJ, "", "",
2330  {
2331  {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
2332  {RPCResult::Type::NUM, "vout", "The vout value"},
2333  {RPCResult::Type::STR_HEX, "scriptPubKey", "The output script"},
2334  {RPCResult::Type::STR, "desc", "A specialized descriptor for the matched output script"},
2335  {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the unspent output"},
2336  {RPCResult::Type::BOOL, "coinbase", "Whether this is a coinbase output"},
2337  {RPCResult::Type::NUM, "height", "Height of the unspent transaction output"},
2338  {RPCResult::Type::STR_HEX, "blockhash", "Blockhash of the unspent transaction output"},
2339  {RPCResult::Type::NUM, "confirmations", "Number of confirmations of the unspent transaction output when the scan was done"},
2340  }},
2341  }},
2342  {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of all found unspent outputs in " + CURRENCY_UNIT},
2343  }},
2347  },
2348  RPCExamples{
2349  HelpExampleCli("scantxoutset", "start \'[\"" + EXAMPLE_DESCRIPTOR_RAW + "\"]\'") +
2350  HelpExampleCli("scantxoutset", "status") +
2351  HelpExampleCli("scantxoutset", "abort") +
2352  HelpExampleRpc("scantxoutset", "\"start\", [\"" + EXAMPLE_DESCRIPTOR_RAW + "\"]") +
2353  HelpExampleRpc("scantxoutset", "\"status\"") +
2354  HelpExampleRpc("scantxoutset", "\"abort\"")
2355  },
2356  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2357 {
2359  const auto action{self.Arg<std::string_view>("action")};
2360  if (action == "status") {
2361  CoinsViewScanReserver reserver;
2362  if (reserver.reserve()) {
2363  // no scan in progress
2364  return UniValue::VNULL;
2365  }
2366  result.pushKV("progress", g_scan_progress.load());
2367  return result;
2368  } else if (action == "abort") {
2369  CoinsViewScanReserver reserver;
2370  if (reserver.reserve()) {
2371  // reserve was possible which means no scan was running
2372  return false;
2373  }
2374  // set the abort flag
2375  g_should_abort_scan = true;
2376  return true;
2377  } else if (action == "start") {
2378  CoinsViewScanReserver reserver;
2379  if (!reserver.reserve()) {
2380  throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
2381  }
2382 
2383  if (request.params.size() < 2) {
2384  throw JSONRPCError(RPC_MISC_ERROR, "scanobjects argument is required for the start action");
2385  }
2386 
2387  std::set<CScript> needles;
2388  std::map<CScript, std::string> descriptors;
2389  CAmount total_in = 0;
2390 
2391  // loop through the scan objects
2392  for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
2393  FlatSigningProvider provider;
2394  auto scripts = EvalDescriptorStringOrObject(scanobject, provider);
2395  for (CScript& script : scripts) {
2396  std::string inferred = InferDescriptor(script, provider)->ToString();
2397  needles.emplace(script);
2398  descriptors.emplace(std::move(script), std::move(inferred));
2399  }
2400  }
2401 
2402  // Scan the unspent transaction output set for inputs
2403  UniValue unspents(UniValue::VARR);
2404  std::vector<CTxOut> input_txos;
2405  std::map<COutPoint, Coin> coins;
2406  g_should_abort_scan = false;
2407  int64_t count = 0;
2408  std::unique_ptr<CCoinsViewCursor> pcursor;
2409  const CBlockIndex* tip;
2410  NodeContext& node = EnsureAnyNodeContext(request.context);
2411  {
2412  ChainstateManager& chainman = EnsureChainman(node);
2413  LOCK(cs_main);
2414  Chainstate& active_chainstate = chainman.ActiveChainstate();
2415  active_chainstate.ForceFlushStateToDisk(/*wipe_cache=*/false);
2416  pcursor = CHECK_NONFATAL(active_chainstate.CoinsDB().Cursor());
2417  tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
2418  }
2419  bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins, node.rpc_interruption_point);
2420  result.pushKV("success", res);
2421  result.pushKV("txouts", count);
2422  result.pushKV("height", tip->nHeight);
2423  result.pushKV("bestblock", tip->GetBlockHash().GetHex());
2424 
2425  for (const auto& it : coins) {
2426  const COutPoint& outpoint = it.first;
2427  const Coin& coin = it.second;
2428  const CTxOut& txo = coin.out;
2429  const CBlockIndex& coinb_block{*CHECK_NONFATAL(tip->GetAncestor(coin.nHeight))};
2430  input_txos.push_back(txo);
2431  total_in += txo.nValue;
2432 
2433  UniValue unspent(UniValue::VOBJ);
2434  unspent.pushKV("txid", outpoint.hash.GetHex());
2435  unspent.pushKV("vout", outpoint.n);
2436  unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
2437  unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
2438  unspent.pushKV("amount", ValueFromAmount(txo.nValue));
2439  unspent.pushKV("coinbase", coin.IsCoinBase());
2440  unspent.pushKV("height", coin.nHeight);
2441  unspent.pushKV("blockhash", coinb_block.GetBlockHash().GetHex());
2442  unspent.pushKV("confirmations", tip->nHeight - coin.nHeight + 1);
2443 
2444  unspents.push_back(std::move(unspent));
2445  }
2446  result.pushKV("unspents", std::move(unspents));
2447  result.pushKV("total_amount", ValueFromAmount(total_in));
2448  } else {
2449  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid action '%s'", action));
2450  }
2451  return result;
2452 },
2453  };
2454 }
2455 
2457 static std::atomic<int> g_scanfilter_progress;
2458 static std::atomic<int> g_scanfilter_progress_height;
2459 static std::atomic<bool> g_scanfilter_in_progress;
2460 static std::atomic<bool> g_scanfilter_should_abort_scan;
2462 {
2463 private:
2464  bool m_could_reserve{false};
2465 public:
2466  explicit BlockFiltersScanReserver() = default;
2467 
2468  bool reserve() {
2470  if (g_scanfilter_in_progress.exchange(true)) {
2471  return false;
2472  }
2473  m_could_reserve = true;
2474  return true;
2475  }
2476 
2478  if (m_could_reserve) {
2479  g_scanfilter_in_progress = false;
2480  }
2481  }
2482 };
2483 
2484 static bool CheckBlockFilterMatches(BlockManager& blockman, const CBlockIndex& blockindex, const GCSFilter::ElementSet& needles)
2485 {
2486  const CBlock block{GetBlockChecked(blockman, blockindex)};
2487  const CBlockUndo block_undo{GetUndoChecked(blockman, blockindex)};
2488 
2489  // Check if any of the outputs match the scriptPubKey
2490  for (const auto& tx : block.vtx) {
2491  if (std::any_of(tx->vout.cbegin(), tx->vout.cend(), [&](const auto& txout) {
2492  return needles.contains(std::vector<unsigned char>(txout.scriptPubKey.begin(), txout.scriptPubKey.end()));
2493  })) {
2494  return true;
2495  }
2496  }
2497  // Check if any of the inputs match the scriptPubKey
2498  for (const auto& txundo : block_undo.vtxundo) {
2499  if (std::any_of(txundo.vprevout.cbegin(), txundo.vprevout.cend(), [&](const auto& coin) {
2500  return needles.contains(std::vector<unsigned char>(coin.out.scriptPubKey.begin(), coin.out.scriptPubKey.end()));
2501  })) {
2502  return true;
2503  }
2504  }
2505 
2506  return false;
2507 }
2508 
2510 {
2511  return RPCHelpMan{
2512  "scanblocks",
2513  "Return relevant blockhashes for given descriptors (requires blockfilterindex).\n"
2514  "This call may take several minutes. Make sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
2515  {
2518  RPCArg{"start_height", RPCArg::Type::NUM, RPCArg::Default{0}, "Height to start to scan from"},
2519  RPCArg{"stop_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"chain tip"}, "Height to stop to scan"},
2520  RPCArg{"filtertype", RPCArg::Type::STR, RPCArg::Default{BlockFilterTypeName(BlockFilterType::BASIC)}, "The type name of the filter"},
2522  {
2523  {"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"},
2524  },
2525  RPCArgOptions{.oneline_description="options"}},
2526  },
2527  {
2529  RPCResult{"When action=='start'; only returns after scan completes", RPCResult::Type::OBJ, "", "", {
2530  {RPCResult::Type::NUM, "from_height", "The height we started the scan from"},
2531  {RPCResult::Type::NUM, "to_height", "The height we ended the scan at"},
2532  {RPCResult::Type::ARR, "relevant_blocks", "Blocks that may have matched a scanobject.", {
2533  {RPCResult::Type::STR_HEX, "blockhash", "A relevant blockhash"},
2534  }},
2535  {RPCResult::Type::BOOL, "completed", "true if the scan process was not aborted"}
2536  }},
2537  RPCResult{"when action=='status' and a scan is currently in progress", RPCResult::Type::OBJ, "", "", {
2538  {RPCResult::Type::NUM, "progress", "Approximate percent complete"},
2539  {RPCResult::Type::NUM, "current_height", "Height of the block currently being scanned"},
2540  },
2541  },
2543  },
2544  RPCExamples{
2545  HelpExampleCli("scanblocks", "start '[\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"]' 300000") +
2546  HelpExampleCli("scanblocks", "start '[\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"]' 100 150 basic") +
2547  HelpExampleCli("scanblocks", "status") +
2548  HelpExampleRpc("scanblocks", "\"start\", [\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"], 300000") +
2549  HelpExampleRpc("scanblocks", "\"start\", [\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"], 100, 150, \"basic\"") +
2550  HelpExampleRpc("scanblocks", "\"status\"")
2551  },
2552  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2553 {
2555  auto action{self.Arg<std::string_view>("action")};
2556  if (action == "status") {
2557  BlockFiltersScanReserver reserver;
2558  if (reserver.reserve()) {
2559  // no scan in progress
2560  return NullUniValue;
2561  }
2562  ret.pushKV("progress", g_scanfilter_progress.load());
2563  ret.pushKV("current_height", g_scanfilter_progress_height.load());
2564  return ret;
2565  } else if (action == "abort") {
2566  BlockFiltersScanReserver reserver;
2567  if (reserver.reserve()) {
2568  // reserve was possible which means no scan was running
2569  return false;
2570  }
2571  // set the abort flag
2573  return true;
2574  } else if (action == "start") {
2575  BlockFiltersScanReserver reserver;
2576  if (!reserver.reserve()) {
2577  throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
2578  }
2579  auto filtertype_name{self.Arg<std::string_view>("filtertype")};
2580 
2581  BlockFilterType filtertype;
2582  if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2583  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown filtertype");
2584  }
2585 
2586  UniValue options{request.params[5].isNull() ? UniValue::VOBJ : request.params[5]};
2587  bool filter_false_positives{options.exists("filter_false_positives") ? options["filter_false_positives"].get_bool() : false};
2588 
2589  BlockFilterIndex* index = GetBlockFilterIndex(filtertype);
2590  if (!index) {
2591  throw JSONRPCError(RPC_MISC_ERROR, tfm::format("Index is not enabled for filtertype %s", filtertype_name));
2592  }
2593 
2594  NodeContext& node = EnsureAnyNodeContext(request.context);
2595  ChainstateManager& chainman = EnsureChainman(node);
2596 
2597  // set the start-height
2598  const CBlockIndex* start_index = nullptr;
2599  const CBlockIndex* stop_block = nullptr;
2600  {
2601  LOCK(cs_main);
2602  CChain& active_chain = chainman.ActiveChain();
2603  start_index = active_chain.Genesis();
2604  stop_block = active_chain.Tip(); // If no stop block is provided, stop at the chain tip.
2605  if (!request.params[2].isNull()) {
2606  start_index = active_chain[request.params[2].getInt<int>()];
2607  if (!start_index) {
2608  throw JSONRPCError(RPC_MISC_ERROR, "Invalid start_height");
2609  }
2610  }
2611  if (!request.params[3].isNull()) {
2612  stop_block = active_chain[request.params[3].getInt<int>()];
2613  if (!stop_block || stop_block->nHeight < start_index->nHeight) {
2614  throw JSONRPCError(RPC_MISC_ERROR, "Invalid stop_height");
2615  }
2616  }
2617  }
2618  CHECK_NONFATAL(start_index);
2619  CHECK_NONFATAL(stop_block);
2620 
2621  // loop through the scan objects, add scripts to the needle_set
2622  GCSFilter::ElementSet needle_set;
2623  for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
2624  FlatSigningProvider provider;
2625  std::vector<CScript> scripts = EvalDescriptorStringOrObject(scanobject, provider);
2626  for (const CScript& script : scripts) {
2627  needle_set.emplace(script.begin(), script.end());
2628  }
2629  }
2630  UniValue blocks(UniValue::VARR);
2631  const int amount_per_chunk = 10000;
2632  std::vector<BlockFilter> filters;
2633  int start_block_height = start_index->nHeight; // for progress reporting
2634  const int total_blocks_to_process = stop_block->nHeight - start_block_height;
2635 
2638  g_scanfilter_progress_height = start_block_height;
2639  bool completed = true;
2640 
2641  const CBlockIndex* end_range = nullptr;
2642  do {
2643  node.rpc_interruption_point(); // allow a clean shutdown
2645  completed = false;
2646  break;
2647  }
2648 
2649  // split the lookup range in chunks if we are deeper than 'amount_per_chunk' blocks from the stopping block
2650  int start_block = !end_range ? start_index->nHeight : start_index->nHeight + 1; // to not include the previous round 'end_range' block
2651  end_range = (start_block + amount_per_chunk < stop_block->nHeight) ?
2652  WITH_LOCK(::cs_main, return chainman.ActiveChain()[start_block + amount_per_chunk]) :
2653  stop_block;
2654 
2655  if (index->LookupFilterRange(start_block, end_range, filters)) {
2656  for (const BlockFilter& filter : filters) {
2657  // compare the elements-set with each filter
2658  if (filter.GetFilter().MatchAny(needle_set)) {
2659  if (filter_false_positives) {
2660  // Double check the filter matches by scanning the block
2661  const CBlockIndex& blockindex = *CHECK_NONFATAL(WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(filter.GetBlockHash())));
2662 
2663  if (!CheckBlockFilterMatches(chainman.m_blockman, blockindex, needle_set)) {
2664  continue;
2665  }
2666  }
2667 
2668  blocks.push_back(filter.GetBlockHash().GetHex());
2669  }
2670  }
2671  }
2672  start_index = end_range;
2673 
2674  // update progress
2675  int blocks_processed = end_range->nHeight - start_block_height;
2676  if (total_blocks_to_process > 0) { // avoid division by zero
2677  g_scanfilter_progress = (int)(100.0 / total_blocks_to_process * blocks_processed);
2678  } else {
2679  g_scanfilter_progress = 100;
2680  }
2682 
2683  // Finish if we reached the stop block
2684  } while (start_index != stop_block);
2685 
2686  ret.pushKV("from_height", start_block_height);
2687  ret.pushKV("to_height", start_index->nHeight); // start_index is always the last scanned block here
2688  ret.pushKV("relevant_blocks", std::move(blocks));
2689  ret.pushKV("completed", completed);
2690  } else {
2691  throw JSONRPCError(RPC_INVALID_PARAMETER, tfm::format("Invalid action '%s'", action));
2692  }
2693  return ret;
2694 },
2695  };
2696 }
2697 
2699 {
2700  return RPCHelpMan{
2701  "getdescriptoractivity",
2702  "Get spend and receive activity associated with a set of descriptors for a set of blocks. "
2703  "This command pairs well with the `relevant_blocks` output of `scanblocks()`.\n"
2704  "This call may take several minutes. If you encounter timeouts, try specifying no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
2705  {
2706  RPCArg{"blockhashes", RPCArg::Type::ARR, RPCArg::Optional::NO, "The list of blockhashes to examine for activity. Order doesn't matter. Must be along main chain or an error is thrown.\n", {
2707  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A valid blockhash"},
2708  }},
2709  RPCArg{"scanobjects", RPCArg::Type::ARR, RPCArg::Optional::NO, "The list of descriptors (scan objects) to examine for activity. Every scan object is either a string descriptor or an object:",
2710  {
2711  {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
2713  },
2714  RPCArgOptions{.oneline_description="[scanobjects,...]"},
2715  },
2716  {"include_mempool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to include unconfirmed activity"},
2717  },
2718  RPCResult{
2719  RPCResult::Type::OBJ, "", "", {
2720  {RPCResult::Type::ARR, "activity", "events", {
2721  {RPCResult::Type::OBJ, "", "", {
2722  {RPCResult::Type::STR, "type", "always 'spend'"},
2723  {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the spent output"},
2724  {RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "The blockhash this spend appears in (omitted if unconfirmed)"},
2725  {RPCResult::Type::NUM, "height", /*optional=*/true, "Height of the spend (omitted if unconfirmed)"},
2726  {RPCResult::Type::STR_HEX, "spend_txid", "The txid of the spending transaction"},
2727  {RPCResult::Type::NUM, "spend_vin", "The input index of the spend"},
2728  {RPCResult::Type::STR_HEX, "prevout_txid", "The txid of the prevout"},
2729  {RPCResult::Type::NUM, "prevout_vout", "The vout of the prevout"},
2730  {RPCResult::Type::OBJ, "prevout_spk", "", ScriptPubKeyDoc()},
2731  }},
2732  {RPCResult::Type::OBJ, "", "", {
2733  {RPCResult::Type::STR, "type", "always 'receive'"},
2734  {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the new output"},
2735  {RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "The block that this receive is in (omitted if unconfirmed)"},
2736  {RPCResult::Type::NUM, "height", /*optional=*/true, "The height of the receive (omitted if unconfirmed)"},
2737  {RPCResult::Type::STR_HEX, "txid", "The txid of the receiving transaction"},
2738  {RPCResult::Type::NUM, "vout", "The vout of the receiving output"},
2739  {RPCResult::Type::OBJ, "output_spk", "", ScriptPubKeyDoc()},
2740  }},
2741  // TODO is the skip_type_check avoidable with a heterogeneous ARR?
2742  }, /*skip_type_check=*/true},
2743  },
2744  },
2745  RPCExamples{
2746  HelpExampleCli("getdescriptoractivity", "'[\"000000000000000000001347062c12fded7c528943c8ce133987e2e2f5a840ee\"]' '[\"addr(bc1qzl6nsgqzu89a66l50cvwapnkw5shh23zarqkw9)\"]'")
2747  },
2748  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2749 {
2751  UniValue activity(UniValue::VARR);
2752  NodeContext& node = EnsureAnyNodeContext(request.context);
2753  ChainstateManager& chainman = EnsureChainman(node);
2754 
2755  struct CompareByHeightAscending {
2756  bool operator()(const CBlockIndex* a, const CBlockIndex* b) const {
2757  return a->nHeight < b->nHeight;
2758  }
2759  };
2760 
2761  std::set<const CBlockIndex*, CompareByHeightAscending> blockindexes_sorted;
2762 
2763  {
2764  // Validate all given blockhashes, and ensure blocks are along a single chain.
2765  LOCK(::cs_main);
2766  for (const UniValue& blockhash : request.params[0].get_array().getValues()) {
2767  uint256 bhash = ParseHashV(blockhash, "blockhash");
2768  CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(bhash);
2769  if (!pindex) {
2770  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
2771  }
2772  if (!chainman.ActiveChain().Contains(pindex)) {
2773  throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain");
2774  }
2775  blockindexes_sorted.insert(pindex);
2776  }
2777  }
2778 
2779  std::set<CScript> scripts_to_watch;
2780 
2781  // Determine scripts to watch.
2782  for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
2783  FlatSigningProvider provider;
2784  std::vector<CScript> scripts = EvalDescriptorStringOrObject(scanobject, provider);
2785 
2786  for (const CScript& script : scripts) {
2787  scripts_to_watch.insert(script);
2788  }
2789  }
2790 
2791  const auto AddSpend = [&](
2792  const CScript& spk,
2793  const CAmount val,
2794  const CTransactionRef& tx,
2795  int vin,
2796  const CTxIn& txin,
2797  const CBlockIndex* index
2798  ) {
2799  UniValue event(UniValue::VOBJ);
2800  UniValue spkUv(UniValue::VOBJ);
2801  ScriptToUniv(spk, /*out=*/spkUv, /*include_hex=*/true, /*include_address=*/true);
2802 
2803  event.pushKV("type", "spend");
2804  event.pushKV("amount", ValueFromAmount(val));
2805  if (index) {
2806  event.pushKV("blockhash", index->GetBlockHash().ToString());
2807  event.pushKV("height", index->nHeight);
2808  }
2809  event.pushKV("spend_txid", tx->GetHash().ToString());
2810  event.pushKV("spend_vin", vin);
2811  event.pushKV("prevout_txid", txin.prevout.hash.ToString());
2812  event.pushKV("prevout_vout", txin.prevout.n);
2813  event.pushKV("prevout_spk", spkUv);
2814 
2815  return event;
2816  };
2817 
2818  const auto AddReceive = [&](const CTxOut& txout, const CBlockIndex* index, int vout, const CTransactionRef& tx) {
2819  UniValue event(UniValue::VOBJ);
2820  UniValue spkUv(UniValue::VOBJ);
2821  ScriptToUniv(txout.scriptPubKey, /*out=*/spkUv, /*include_hex=*/true, /*include_address=*/true);
2822 
2823  event.pushKV("type", "receive");
2824  event.pushKV("amount", ValueFromAmount(txout.nValue));
2825  if (index) {
2826  event.pushKV("blockhash", index->GetBlockHash().ToString());
2827  event.pushKV("height", index->nHeight);
2828  }
2829  event.pushKV("txid", tx->GetHash().ToString());
2830  event.pushKV("vout", vout);
2831  event.pushKV("output_spk", spkUv);
2832 
2833  return event;
2834  };
2835 
2836  BlockManager* blockman;
2837  Chainstate& active_chainstate = chainman.ActiveChainstate();
2838  {
2839  LOCK(::cs_main);
2840  blockman = CHECK_NONFATAL(&active_chainstate.m_blockman);
2841  }
2842 
2843  for (const CBlockIndex* blockindex : blockindexes_sorted) {
2844  const CBlock block{GetBlockChecked(chainman.m_blockman, *blockindex)};
2845  const CBlockUndo block_undo{GetUndoChecked(*blockman, *blockindex)};
2846 
2847  for (size_t i = 0; i < block.vtx.size(); ++i) {
2848  const auto& tx = block.vtx.at(i);
2849 
2850  if (!tx->IsCoinBase()) {
2851  // skip coinbase; spends can't happen there.
2852  const auto& txundo = block_undo.vtxundo.at(i - 1);
2853 
2854  for (size_t vin_idx = 0; vin_idx < tx->vin.size(); ++vin_idx) {
2855  const auto& coin = txundo.vprevout.at(vin_idx);
2856  const auto& txin = tx->vin.at(vin_idx);
2857  if (scripts_to_watch.contains(coin.out.scriptPubKey)) {
2858  activity.push_back(AddSpend(
2859  coin.out.scriptPubKey, coin.out.nValue, tx, vin_idx, txin, blockindex));
2860  }
2861  }
2862  }
2863 
2864  for (size_t vout_idx = 0; vout_idx < tx->vout.size(); ++vout_idx) {
2865  const auto& vout = tx->vout.at(vout_idx);
2866  if (scripts_to_watch.contains(vout.scriptPubKey)) {
2867  activity.push_back(AddReceive(vout, blockindex, vout_idx, tx));
2868  }
2869  }
2870  }
2871  }
2872 
2873  bool search_mempool = true;
2874  if (!request.params[2].isNull()) {
2875  search_mempool = request.params[2].get_bool();
2876  }
2877 
2878  if (search_mempool) {
2879  const CTxMemPool& mempool = EnsureMemPool(node);
2880  LOCK(::cs_main);
2881  LOCK(mempool.cs);
2882  const CCoinsViewCache& coins_view = &active_chainstate.CoinsTip();
2883 
2884  for (const CTxMemPoolEntry& e : mempool.entryAll()) {
2885  const auto& tx = e.GetSharedTx();
2886 
2887  for (size_t vin_idx = 0; vin_idx < tx->vin.size(); ++vin_idx) {
2888  CScript scriptPubKey;
2889  CAmount value;
2890  const auto& txin = tx->vin.at(vin_idx);
2891  std::optional<Coin> coin = coins_view.GetCoin(txin.prevout);
2892 
2893  // Check if the previous output is in the chain
2894  if (!coin) {
2895  // If not found in the chain, check the mempool. Likely, this is a
2896  // child transaction of another transaction in the mempool.
2897  CTransactionRef prev_tx = CHECK_NONFATAL(mempool.get(txin.prevout.hash));
2898 
2899  if (txin.prevout.n >= prev_tx->vout.size()) {
2900  throw std::runtime_error("Invalid output index");
2901  }
2902  const CTxOut& out = prev_tx->vout[txin.prevout.n];
2903  scriptPubKey = out.scriptPubKey;
2904  value = out.nValue;
2905  } else {
2906  // Coin found in the chain
2907  const CTxOut& out = coin->out;
2908  scriptPubKey = out.scriptPubKey;
2909  value = out.nValue;
2910  }
2911 
2912  if (scripts_to_watch.contains(scriptPubKey)) {
2913  UniValue event(UniValue::VOBJ);
2914  activity.push_back(AddSpend(
2915  scriptPubKey, value, tx, vin_idx, txin, nullptr));
2916  }
2917  }
2918 
2919  for (size_t vout_idx = 0; vout_idx < tx->vout.size(); ++vout_idx) {
2920  const auto& vout = tx->vout.at(vout_idx);
2921  if (scripts_to_watch.contains(vout.scriptPubKey)) {
2922  activity.push_back(AddReceive(vout, nullptr, vout_idx, tx));
2923  }
2924  }
2925  }
2926  }
2927 
2928  ret.pushKV("activity", activity);
2929  return ret;
2930 },
2931  };
2932 }
2933 
2935 {
2936  return RPCHelpMan{
2937  "getblockfilter",
2938  "Retrieve a BIP 157 content filter for a particular block.\n",
2939  {
2940  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hash of the block"},
2941  {"filtertype", RPCArg::Type::STR, RPCArg::Default{BlockFilterTypeName(BlockFilterType::BASIC)}, "The type name of the filter"},
2942  },
2943  RPCResult{
2944  RPCResult::Type::OBJ, "", "",
2945  {
2946  {RPCResult::Type::STR_HEX, "filter", "the hex-encoded filter data"},
2947  {RPCResult::Type::STR_HEX, "header", "the hex-encoded filter header"},
2948  }},
2949  RPCExamples{
2950  HelpExampleCli("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" \"basic\"") +
2951  HelpExampleRpc("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\", \"basic\"")
2952  },
2953  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2954 {
2955  uint256 block_hash = ParseHashV(request.params[0], "blockhash");
2956  auto filtertype_name{self.Arg<std::string_view>("filtertype")};
2957 
2958  BlockFilterType filtertype;
2959  if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2960  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown filtertype");
2961  }
2962 
2963  BlockFilterIndex* index = GetBlockFilterIndex(filtertype);
2964  if (!index) {
2965  throw JSONRPCError(RPC_MISC_ERROR, tfm::format("Index is not enabled for filtertype %s", filtertype_name));
2966  }
2967 
2968  const CBlockIndex* block_index;
2969  bool block_was_connected;
2970  {
2971  ChainstateManager& chainman = EnsureAnyChainman(request.context);
2972  LOCK(cs_main);
2973  block_index = chainman.m_blockman.LookupBlockIndex(block_hash);
2974  if (!block_index) {
2975  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
2976  }
2977  block_was_connected = block_index->IsValid(BLOCK_VALID_SCRIPTS);
2978  }
2979 
2980  bool index_ready = index->BlockUntilSyncedToCurrentChain();
2981 
2982  BlockFilter filter;
2983  uint256 filter_header;
2984  if (!index->LookupFilter(block_index, filter) ||
2985  !index->LookupFilterHeader(block_index, filter_header)) {
2986  int err_code;
2987  std::string errmsg = "Filter not found.";
2988 
2989  if (!block_was_connected) {
2990  err_code = RPC_INVALID_ADDRESS_OR_KEY;
2991  errmsg += " Block was not connected to active chain.";
2992  } else if (!index_ready) {
2993  err_code = RPC_MISC_ERROR;
2994  errmsg += " Block filters are still in the process of being indexed.";
2995  } else {
2996  err_code = RPC_INTERNAL_ERROR;
2997  errmsg += " This error is unexpected and indicates index corruption.";
2998  }
2999 
3000  throw JSONRPCError(err_code, errmsg);
3001  }
3002 
3004  ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
3005  ret.pushKV("header", filter_header.GetHex());
3006  return ret;
3007 },
3008  };
3009 }
3010 
3016 {
3018 public:
3019  NetworkDisable(CConnman& connman) : m_connman(connman) {
3020  m_connman.SetNetworkActive(false);
3021  if (m_connman.GetNetworkActive()) {
3022  throw JSONRPCError(RPC_MISC_ERROR, "Network activity could not be suspended.");
3023  }
3024  };
3027  };
3028 };
3029 
3035 {
3038 public:
3039  TemporaryRollback(ChainstateManager& chainman, const CBlockIndex& index) : m_chainman(chainman), m_invalidate_index(index) {
3041  };
3044  };
3045 };
3046 
3053 {
3054  return RPCHelpMan{
3055  "dumptxoutset",
3056  "Write the serialized UTXO set to a file. This can be used in loadtxoutset afterwards if this snapshot height is supported in the chainparams as well.\n\n"
3057  "Unless the \"latest\" type is requested, the node will roll back to the requested height and network activity will be suspended during this process. "
3058  "Because of this it is discouraged to interact with the node in any other way during the execution of this call to avoid inconsistent results and race conditions, particularly RPCs that interact with blockstorage.\n\n"
3059  "This call may take several minutes. Make sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
3060  {
3061  {"path", RPCArg::Type::STR, RPCArg::Optional::NO, "Path to the output file. If relative, will be prefixed by datadir."},
3062  {"type", RPCArg::Type::STR, RPCArg::Default(""), "The type of snapshot to create. Can be \"latest\" to create a snapshot of the current UTXO set or \"rollback\" to temporarily roll back the state of the node to a historical block before creating the snapshot of a historical UTXO set. This parameter can be omitted if a separate \"rollback\" named parameter is specified indicating the height or hash of a specific historical block. If \"rollback\" is specified and separate \"rollback\" named parameter is not specified, this will roll back to the latest valid snapshot block that can currently be loaded with loadtxoutset."},
3064  {
3066  "Height or hash of the block to roll back to before creating the snapshot. Note: The further this number is from the tip, the longer this process will take. Consider setting a higher -rpcclienttimeout value in this case.",
3067  RPCArgOptions{.skip_type_check = true, .type_str = {"", "string or numeric"}}},
3068  },
3069  },
3070  },
3071  RPCResult{
3072  RPCResult::Type::OBJ, "", "",
3073  {
3074  {RPCResult::Type::NUM, "coins_written", "the number of coins written in the snapshot"},
3075  {RPCResult::Type::STR_HEX, "base_hash", "the hash of the base of the snapshot"},
3076  {RPCResult::Type::NUM, "base_height", "the height of the base of the snapshot"},
3077  {RPCResult::Type::STR, "path", "the absolute path that the snapshot was written to"},
3078  {RPCResult::Type::STR_HEX, "txoutset_hash", "the hash of the UTXO set contents"},
3079  {RPCResult::Type::NUM, "nchaintx", "the number of transactions in the chain up to and including the base block"},
3080  }
3081  },
3082  RPCExamples{
3083  HelpExampleCli("-rpcclienttimeout=0 dumptxoutset", "utxo.dat latest") +
3084  HelpExampleCli("-rpcclienttimeout=0 dumptxoutset", "utxo.dat rollback") +
3085  HelpExampleCli("-rpcclienttimeout=0 -named dumptxoutset", R"(utxo.dat rollback=853456)")
3086  },
3087  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
3088 {
3089  NodeContext& node = EnsureAnyNodeContext(request.context);
3090  const CBlockIndex* tip{WITH_LOCK(::cs_main, return node.chainman->ActiveChain().Tip())};
3091  const CBlockIndex* target_index{nullptr};
3092  const auto snapshot_type{self.Arg<std::string_view>("type")};
3093  const UniValue options{request.params[2].isNull() ? UniValue::VOBJ : request.params[2]};
3094  if (options.exists("rollback")) {
3095  if (!snapshot_type.empty() && snapshot_type != "rollback") {
3096  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid snapshot type \"%s\" specified with rollback option", snapshot_type));
3097  }
3098  target_index = ParseHashOrHeight(options["rollback"], *node.chainman);
3099  } else if (snapshot_type == "rollback") {
3100  auto snapshot_heights = node.chainman->GetParams().GetAvailableSnapshotHeights();
3101  CHECK_NONFATAL(snapshot_heights.size() > 0);
3102  auto max_height = std::max_element(snapshot_heights.begin(), snapshot_heights.end());
3103  target_index = ParseHashOrHeight(*max_height, *node.chainman);
3104  } else if (snapshot_type == "latest") {
3105  target_index = tip;
3106  } else {
3107  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid snapshot type \"%s\" specified. Please specify \"rollback\" or \"latest\"", snapshot_type));
3108  }
3109 
3110  const ArgsManager& args{EnsureAnyArgsman(request.context)};
3111  const fs::path path = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(self.Arg<std::string_view>("path")));
3112  // Write to a temporary path and then move into `path` on completion
3113  // to avoid confusion due to an interruption.
3114  const fs::path temppath = path + ".incomplete";
3115 
3116  if (fs::exists(path)) {
3117  throw JSONRPCError(
3119  path.utf8string() + " already exists. If you are sure this is what you want, "
3120  "move it out of the way first");
3121  }
3122 
3123  FILE* file{fsbridge::fopen(temppath, "wb")};
3124  AutoFile afile{file};
3125  if (afile.IsNull()) {
3126  throw JSONRPCError(
3128  "Couldn't open file " + temppath.utf8string() + " for writing.");
3129  }
3130 
3131  CConnman& connman = EnsureConnman(node);
3132  const CBlockIndex* invalidate_index{nullptr};
3133  std::optional<NetworkDisable> disable_network;
3134  std::optional<TemporaryRollback> temporary_rollback;
3135 
3136  // If the user wants to dump the txoutset of the current tip, we don't have
3137  // to roll back at all
3138  if (target_index != tip) {
3139  // If the node is running in pruned mode we ensure all necessary block
3140  // data is available before starting to roll back.
3141  if (node.chainman->m_blockman.IsPruneMode()) {
3142  LOCK(node.chainman->GetMutex());
3143  const CBlockIndex* current_tip{node.chainman->ActiveChain().Tip()};
3144  const CBlockIndex& first_block{node.chainman->m_blockman.GetFirstBlock(*current_tip, /*status_mask=*/BLOCK_HAVE_MASK)};
3145  if (first_block.nHeight > target_index->nHeight) {
3146  throw JSONRPCError(RPC_MISC_ERROR, "Could not roll back to requested height since necessary block data is already pruned.");
3147  }
3148  }
3149 
3150  // Suspend network activity for the duration of the process when we are
3151  // rolling back the chain to get a utxo set from a past height. We do
3152  // this so we don't punish peers that send us that send us data that
3153  // seems wrong in this temporary state. For example a normal new block
3154  // would be classified as a block connecting an invalid block.
3155  // Skip if the network is already disabled because this
3156  // automatically re-enables the network activity at the end of the
3157  // process which may not be what the user wants.
3158  if (connman.GetNetworkActive()) {
3159  disable_network.emplace(connman);
3160  }
3161 
3162  invalidate_index = WITH_LOCK(::cs_main, return node.chainman->ActiveChain().Next(target_index));
3163  temporary_rollback.emplace(*node.chainman, *invalidate_index);
3164  }
3165 
3166  Chainstate* chainstate;
3167  std::unique_ptr<CCoinsViewCursor> cursor;
3168  CCoinsStats stats;
3169  {
3170  // Lock the chainstate before calling PrepareUtxoSnapshot, to be able
3171  // to get a UTXO database cursor while the chain is pointing at the
3172  // target block. After that, release the lock while calling
3173  // WriteUTXOSnapshot. The cursor will remain valid and be used by
3174  // WriteUTXOSnapshot to write a consistent snapshot even if the
3175  // chainstate changes.
3176  LOCK(node.chainman->GetMutex());
3177  chainstate = &node.chainman->ActiveChainstate();
3178  // In case there is any issue with a block being read from disk we need
3179  // to stop here, otherwise the dump could still be created for the wrong
3180  // height.
3181  // The new tip could also not be the target block if we have a stale
3182  // sister block of invalidate_index. This block (or a descendant) would
3183  // be activated as the new tip and we would not get to new_tip_index.
3184  if (target_index != chainstate->m_chain.Tip()) {
3185  LogWarning("dumptxoutset failed to roll back to requested height, reverting to tip.\n");
3186  throw JSONRPCError(RPC_MISC_ERROR, "Could not roll back to requested height.");
3187  } else {
3188  std::tie(cursor, stats, tip) = PrepareUTXOSnapshot(*chainstate, node.rpc_interruption_point);
3189  }
3190  }
3191 
3192  UniValue result = WriteUTXOSnapshot(*chainstate,
3193  cursor.get(),
3194  &stats,
3195  tip,
3196  std::move(afile),
3197  path,
3198  temppath,
3199  node.rpc_interruption_point);
3200  fs::rename(temppath, path);
3201 
3202  result.pushKV("path", path.utf8string());
3203  return result;
3204 },
3205  };
3206 }
3207 
3208 std::tuple<std::unique_ptr<CCoinsViewCursor>, CCoinsStats, const CBlockIndex*>
3210  Chainstate& chainstate,
3211  const std::function<void()>& interruption_point)
3212 {
3213  std::unique_ptr<CCoinsViewCursor> pcursor;
3214  std::optional<CCoinsStats> maybe_stats;
3215  const CBlockIndex* tip;
3216 
3217  {
3218  // We need to lock cs_main to ensure that the coinsdb isn't written to
3219  // between (i) flushing coins cache to disk (coinsdb), (ii) getting stats
3220  // based upon the coinsdb, and (iii) constructing a cursor to the
3221  // coinsdb for use in WriteUTXOSnapshot.
3222  //
3223  // Cursors returned by leveldb iterate over snapshots, so the contents
3224  // of the pcursor will not be affected by simultaneous writes during
3225  // use below this block.
3226  //
3227  // See discussion here:
3228  // https://github.com/bitcoin/bitcoin/pull/15606#discussion_r274479369
3229  //
3231 
3232  chainstate.ForceFlushStateToDisk(/*wipe_cache=*/false);
3233 
3234  maybe_stats = GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman, CoinStatsHashType::HASH_SERIALIZED, interruption_point);
3235  if (!maybe_stats) {
3236  throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
3237  }
3238 
3239  pcursor = chainstate.CoinsDB().Cursor();
3240  tip = CHECK_NONFATAL(chainstate.m_blockman.LookupBlockIndex(maybe_stats->hashBlock));
3241  }
3242 
3243  return {std::move(pcursor), *CHECK_NONFATAL(maybe_stats), tip};
3244 }
3245 
3247  Chainstate& chainstate,
3248  CCoinsViewCursor* pcursor,
3249  CCoinsStats* maybe_stats,
3250  const CBlockIndex* tip,
3251  AutoFile&& afile,
3252  const fs::path& path,
3253  const fs::path& temppath,
3254  const std::function<void()>& interruption_point)
3255 {
3256  LOG_TIME_SECONDS(strprintf("writing UTXO snapshot at height %s (%s) to file %s (via %s)",
3257  tip->nHeight, tip->GetBlockHash().ToString(),
3258  fs::PathToString(path), fs::PathToString(temppath)));
3259 
3260  SnapshotMetadata metadata{chainstate.m_chainman.GetParams().MessageStart(), tip->GetBlockHash(), maybe_stats->coins_count};
3261 
3262  afile << metadata;
3263 
3264  COutPoint key;
3265  Txid last_hash;
3266  Coin coin;
3267  unsigned int iter{0};
3268  size_t written_coins_count{0};
3269  std::vector<std::pair<uint32_t, Coin>> coins;
3270 
3271  // To reduce space the serialization format of the snapshot avoids
3272  // duplication of tx hashes. The code takes advantage of the guarantee by
3273  // leveldb that keys are lexicographically sorted.
3274  // In the coins vector we collect all coins that belong to a certain tx hash
3275  // (key.hash) and when we have them all (key.hash != last_hash) we write
3276  // them to file using the below lambda function.
3277  // See also https://github.com/bitcoin/bitcoin/issues/25675
3278  auto write_coins_to_file = [&](AutoFile& afile, const Txid& last_hash, const std::vector<std::pair<uint32_t, Coin>>& coins, size_t& written_coins_count) {
3279  afile << last_hash;
3280  WriteCompactSize(afile, coins.size());
3281  for (const auto& [n, coin] : coins) {
3282  WriteCompactSize(afile, n);
3283  afile << coin;
3284  ++written_coins_count;
3285  }
3286  };
3287 
3288  pcursor->GetKey(key);
3289  last_hash = key.hash;
3290  while (pcursor->Valid()) {
3291  if (iter % 5000 == 0) interruption_point();
3292  ++iter;
3293  if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
3294  if (key.hash != last_hash) {
3295  write_coins_to_file(afile, last_hash, coins, written_coins_count);
3296  last_hash = key.hash;
3297  coins.clear();
3298  }
3299  coins.emplace_back(key.n, coin);
3300  }
3301  pcursor->Next();
3302  }
3303 
3304  if (!coins.empty()) {
3305  write_coins_to_file(afile, last_hash, coins, written_coins_count);
3306  }
3307 
3308  CHECK_NONFATAL(written_coins_count == maybe_stats->coins_count);
3309 
3310  if (afile.fclose() != 0) {
3311  throw std::ios_base::failure(
3312  strprintf("Error closing %s: %s", fs::PathToString(temppath), SysErrorString(errno)));
3313  }
3314 
3316  result.pushKV("coins_written", written_coins_count);
3317  result.pushKV("base_hash", tip->GetBlockHash().ToString());
3318  result.pushKV("base_height", tip->nHeight);
3319  result.pushKV("path", path.utf8string());
3320  result.pushKV("txoutset_hash", maybe_stats->hashSerialized.ToString());
3321  result.pushKV("nchaintx", tip->m_chain_tx_count);
3322  return result;
3323 }
3324 
3327  Chainstate& chainstate,
3328  AutoFile&& afile,
3329  const fs::path& path,
3330  const fs::path& tmppath)
3331 {
3332  auto [cursor, stats, tip]{WITH_LOCK(::cs_main, return PrepareUTXOSnapshot(chainstate, node.rpc_interruption_point))};
3333  return WriteUTXOSnapshot(chainstate,
3334  cursor.get(),
3335  &stats,
3336  tip,
3337  std::move(afile),
3338  path,
3339  tmppath,
3340  node.rpc_interruption_point);
3341 }
3342 
3344 {
3345  return RPCHelpMan{
3346  "loadtxoutset",
3347  "Load the serialized UTXO set from a file.\n"
3348  "Once this snapshot is loaded, its contents will be "
3349  "deserialized into a second chainstate data structure, which is then used to sync to "
3350  "the network's tip. "
3351  "Meanwhile, the original chainstate will complete the initial block download process in "
3352  "the background, eventually validating up to the block that the snapshot is based upon.\n\n"
3353 
3354  "The result is a usable bitcoind instance that is current with the network tip in a "
3355  "matter of minutes rather than hours. UTXO snapshot are typically obtained from "
3356  "third-party sources (HTTP, torrent, etc.) which is reasonable since their "
3357  "contents are always checked by hash.\n\n"
3358 
3359  "You can find more information on this process in the `assumeutxo` design "
3360  "document (<https://github.com/bitcoin/bitcoin/blob/master/doc/design/assumeutxo.md>).",
3361  {
3362  {"path",
3365  "path to the snapshot file. If relative, will be prefixed by datadir."},
3366  },
3367  RPCResult{
3368  RPCResult::Type::OBJ, "", "",
3369  {
3370  {RPCResult::Type::NUM, "coins_loaded", "the number of coins loaded from the snapshot"},
3371  {RPCResult::Type::STR_HEX, "tip_hash", "the hash of the base of the snapshot"},
3372  {RPCResult::Type::NUM, "base_height", "the height of the base of the snapshot"},
3373  {RPCResult::Type::STR, "path", "the absolute path that the snapshot was loaded from"},
3374  }
3375  },
3376  RPCExamples{
3377  HelpExampleCli("-rpcclienttimeout=0 loadtxoutset", "utxo.dat")
3378  },
3379  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
3380 {
3381  NodeContext& node = EnsureAnyNodeContext(request.context);
3382  ChainstateManager& chainman = EnsureChainman(node);
3383  const fs::path path{AbsPathForConfigVal(EnsureArgsman(node), fs::u8path(self.Arg<std::string_view>("path")))};
3384 
3385  FILE* file{fsbridge::fopen(path, "rb")};
3386  AutoFile afile{file};
3387  if (afile.IsNull()) {
3388  throw JSONRPCError(
3390  "Couldn't open file " + path.utf8string() + " for reading.");
3391  }
3392 
3393  SnapshotMetadata metadata{chainman.GetParams().MessageStart()};
3394  try {
3395  afile >> metadata;
3396  } catch (const std::ios_base::failure& e) {
3397  throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("Unable to parse metadata: %s", e.what()));
3398  }
3399 
3400  auto activation_result{chainman.ActivateSnapshot(afile, metadata, false)};
3401  if (!activation_result) {
3402  throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to load UTXO snapshot: %s. (%s)", util::ErrorString(activation_result).original, path.utf8string()));
3403  }
3404 
3405  // Because we can't provide historical blocks during tip or background sync.
3406  // Update local services to reflect we are a limited peer until we are fully sync.
3407  node.connman->RemoveLocalServices(NODE_NETWORK);
3408  // Setting the limited state is usually redundant because the node can always
3409  // provide the last 288 blocks, but it doesn't hurt to set it.
3410  node.connman->AddLocalServices(NODE_NETWORK_LIMITED);
3411 
3412  CBlockIndex& snapshot_index{*CHECK_NONFATAL(*activation_result)};
3413 
3415  result.pushKV("coins_loaded", metadata.m_coins_count);
3416  result.pushKV("tip_hash", snapshot_index.GetBlockHash().ToString());
3417  result.pushKV("base_height", snapshot_index.nHeight);
3418  result.pushKV("path", fs::PathToString(path));
3419  return result;
3420 },
3421  };
3422 }
3423 
3424 const std::vector<RPCResult> RPCHelpForChainstate{
3425  {RPCResult::Type::NUM, "blocks", "number of blocks in this chainstate"},
3426  {RPCResult::Type::STR_HEX, "bestblockhash", "blockhash of the tip"},
3427  {RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},
3428  {RPCResult::Type::STR_HEX, "target", "The difficulty target"},
3429  {RPCResult::Type::NUM, "difficulty", "difficulty of the tip"},
3430  {RPCResult::Type::NUM, "verificationprogress", "progress towards the network tip"},
3431  {RPCResult::Type::STR_HEX, "snapshot_blockhash", /*optional=*/true, "the base block of the snapshot this chainstate is based on, if any"},
3432  {RPCResult::Type::NUM, "coins_db_cache_bytes", "size of the coinsdb cache"},
3433  {RPCResult::Type::NUM, "coins_tip_cache_bytes", "size of the coinstip cache"},
3434  {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."},
3435 };
3436 
3438 {
3439 return RPCHelpMan{
3440  "getchainstates",
3441  "Return information about chainstates.\n",
3442  {},
3443  RPCResult{
3444  RPCResult::Type::OBJ, "", "", {
3445  {RPCResult::Type::NUM, "headers", "the number of headers seen so far"},
3446  {RPCResult::Type::ARR, "chainstates", "list of the chainstates ordered by work, with the most-work (active) chainstate last", {{RPCResult::Type::OBJ, "", "", RPCHelpForChainstate},}},
3447  }
3448  },
3449  RPCExamples{
3450  HelpExampleCli("getchainstates", "")
3451  + HelpExampleRpc("getchainstates", "")
3452  },
3453  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
3454 {
3455  LOCK(cs_main);
3456  UniValue obj(UniValue::VOBJ);
3457 
3458  ChainstateManager& chainman = EnsureAnyChainman(request.context);
3459 
3460  auto make_chain_data = [&](const Chainstate& cs) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
3463  if (!cs.m_chain.Tip()) {
3464  return data;
3465  }
3466  const CChain& chain = cs.m_chain;
3467  const CBlockIndex* tip = chain.Tip();
3468 
3469  data.pushKV("blocks", chain.Height());
3470  data.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
3471  data.pushKV("bits", strprintf("%08x", tip->nBits));
3472  data.pushKV("target", GetTarget(*tip, chainman.GetConsensus().powLimit).GetHex());
3473  data.pushKV("difficulty", GetDifficulty(*tip));
3474  data.pushKV("verificationprogress", chainman.GuessVerificationProgress(tip));
3475  data.pushKV("coins_db_cache_bytes", cs.m_coinsdb_cache_size_bytes);
3476  data.pushKV("coins_tip_cache_bytes", cs.m_coinstip_cache_size_bytes);
3477  if (cs.m_from_snapshot_blockhash) {
3478  data.pushKV("snapshot_blockhash", cs.m_from_snapshot_blockhash->ToString());
3479  }
3480  data.pushKV("validated", cs.m_assumeutxo == Assumeutxo::VALIDATED);
3481  return data;
3482  };
3483 
3484  obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
3485  UniValue obj_chainstates{UniValue::VARR};
3486  if (const Chainstate * cs{chainman.HistoricalChainstate()}) {
3487  obj_chainstates.push_back(make_chain_data(*cs));
3488  }
3489  obj_chainstates.push_back(make_chain_data(chainman.CurrentChainstate()));
3490  obj.pushKV("chainstates", std::move(obj_chainstates));
3491  return obj;
3492 }
3493  };
3494 }
3495 
3496 
3498 {
3499  static const CRPCCommand commands[]{
3500  {"blockchain", &getblockchaininfo},
3501  {"blockchain", &getchaintxstats},
3502  {"blockchain", &getblockstats},
3503  {"blockchain", &getbestblockhash},
3504  {"blockchain", &getblockcount},
3505  {"blockchain", &getblock},
3506  {"blockchain", &getblockfrompeer},
3507  {"blockchain", &getblockhash},
3508  {"blockchain", &getblockheader},
3509  {"blockchain", &getchaintips},
3510  {"blockchain", &getdifficulty},
3511  {"blockchain", &getdeploymentinfo},
3512  {"blockchain", &gettxout},
3513  {"blockchain", &gettxoutsetinfo},
3514  {"blockchain", &pruneblockchain},
3515  {"blockchain", &verifychain},
3516  {"blockchain", &preciousblock},
3517  {"blockchain", &scantxoutset},
3518  {"blockchain", &scanblocks},
3519  {"blockchain", &getdescriptoractivity},
3520  {"blockchain", &getblockfilter},
3521  {"blockchain", &dumptxoutset},
3522  {"blockchain", &loadtxoutset},
3523  {"blockchain", &getchainstates},
3524  {"hidden", &invalidateblock},
3525  {"hidden", &reconsiderblock},
3526  {"blockchain", &waitfornewblock},
3527  {"blockchain", &waitforblock},
3528  {"blockchain", &waitforblockheight},
3529  {"hidden", &syncwithvalidationinterfacequeue},
3530  };
3531  for (const auto& c : commands) {
3532  t.appendCommand(c.name, &c);
3533  }
3534 }
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:403
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:686
arith_uint256 nChainWork
(memory only) Total amount of work (expected number of hashes) in the chain up to and including this ...
Definition: chain.h:118
CAmount nValue
Definition: transaction.h:142
const std::vector< RPCResult > RPCHelpForChainstate
std::vector< RPCResult > ScriptPubKeyDoc()
Definition: util.cpp:1390
std::string GetHex() const
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:226
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1038
bool LookupFilter(const CBlockIndex *block_index, BlockFilter &filter_out) const
Get a single filter by block.
static RPCHelpMan syncwithvalidationinterfacequeue()
Definition: blockchain.cpp:473
static const auto scan_result_abort
Interval between compact filter checkpoints.
void push_back(UniValue val)
Definition: univalue.cpp:103
const std::vector< std::string > CHECKLEVEL_DOC
Documentation for argument &#39;checklevel&#39;.
Definition: validation.cpp:100
int ret
static constexpr int NUM_GETBLOCKSTATS_PERCENTILES
Definition: blockchain.h:31
bool IsCoinBase() const
Definition: coins.h:59
CConnman & m_connman
static RPCHelpMan getblock()
Definition: blockchain.cpp:761
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:34
The same as previous option with information about prevouts if available.
arith_uint256 total_new_outputs_ex_coinbase_amount
Total cumulative amount of outputs created up to and including this block.
Definition: coinstats.h:67
AssertLockHeld(pool.cs)
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams)
std::array< BIP9Deployment, MAX_VERSION_BITS_DEPLOYMENTS > vDeployments
Definition: params.h:110
const std::vector< UniValue > & getValues() const
bool BlockFilterTypeByName(std::string_view name, BlockFilterType &filter_type)
Find a filter type by its human-readable name.
std::unique_ptr< CCoinsViewCursor > Cursor() const override
Get a cursor to iterate over the whole state.
Definition: txdb.cpp:194
static const int WITNESS_SCALE_FACTOR
Definition: consensus.h:21
bool IsPruneMode() const
Whether running in -prune mode.
Definition: blockstorage.h:404
RPC command dispatcher.
Definition: server.h:86
int64_t GetBlockTime() const
Definition: chain.h:221
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:25
CScript scriptPubKey
Definition: transaction.h:143
UniValue ValueFromAmount(const CAmount amount)
Definition: core_io.cpp:285
static std::vector< std::byte > GetRawBlockChecked(BlockManager &blockman, const CBlockIndex &blockindex)
Definition: blockchain.cpp:703
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: chain.h:100
uint64_t CalculateCurrentUsage()
Calculate the amount of disk space the block & undo files currently use.
static RPCHelpMan getblockfrompeer()
Definition: blockchain.cpp:514
Required arg.
uint256 GetTarget(const CBlockIndex &blockindex, const uint256 pow_limit)
Definition: util.cpp:1401
std::string GetChainTypeString() const
Return the chain type string.
Definition: chainparams.h:109
node::BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all Chainstate instances...
Definition: validation.h:573
A UTXO entry.
Definition: coins.h:34
CTxMemPool & EnsureMemPool(const NodeContext &node)
Definition: server_util.cpp:34
Definition: block.h:73
#define LogWarning(...)
Definition: log.h:96
TxVerbosity
Verbose level for block&#39;s transaction.
Definition: core_io.h:28
UniValue blockToJSON(BlockManager &blockman, const CBlock &block, const CBlockIndex &tip, const CBlockIndex &blockindex, TxVerbosity verbosity, const uint256 pow_limit)
Block description to JSON.
Definition: blockchain.cpp:202
Interface for managing multiple Chainstate objects, where each chainstate is associated with chainsta...
Definition: validation.h:939
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
DeploymentPos
Definition: params.h:34
An in-memory indexed chain of blocks.
Definition: chain.h:379
static std::atomic< bool > g_scanfilter_should_abort_scan
BlockFiltersScanReserver()=default
virtual util::Expected< void, std::string > FetchBlock(NodeId peer_id, const CBlockIndex &block_index)=0
Attempt to manually fetch block from a given peer.
NetworkDisable(CConnman &connman)
BlockFilterIndex * GetBlockFilterIndex(BlockFilterType filter_type)
Get a block filter index by type.
virtual void Next()=0
bool index_used
Signals if the coinstatsindex was used to retrieve the statistics.
Definition: coinstats.h:47
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:76
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1165
Chainstate &InitializeChainstate(CTxMemPool *mempool) EXCLUSIVE_LOCKS_REQUIRED(util::Result< CBlockIndex * ActivateSnapshot)(AutoFile &coins_file, const node::SnapshotMetadata &metadata, bool in_memory)
Instantiate a new chainstate.
Definition: validation.h:1105
All parent headers found, difficulty matches, timestamp >= median previous.
Definition: chain.h:51
static constexpr int DEFAULT_CHECKLEVEL
Definition: validation.h:78
bool MoneyRange(const CAmount &nValue)
Definition: amount.h:27
CBlockHeader GetBlockHeader() const
Definition: chain.h:185
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:109
int Height() const
Return the maximal height in the chain.
Definition: chain.h:425
Special type that behaves almost exactly like OBJ, defining an options object with a list of pre-defi...
CTxOut out
unspent transaction output
Definition: coins.h:38
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.
stage after last reached validness failed
Definition: chain.h:79
std::optional< CAmount > total_amount
The total amount, or nullopt if an overflow occurred calculating it.
Definition: coinstats.h:41
constexpr const std::byte * begin() const
Hash/height pair to help track and identify blocks.
Definition: types.h:13
#define LOG_TIME_SECONDS(end_msg)
Definition: timer.h:107
static const auto scan_result_status_some
const std::string & get_str() const
CTransactionRef get(const Txid &hash) const
Definition: txmempool.cpp:621
CBlockIndex * Genesis() const
Returns the index entry for the genesis block of this chain, or nullptr if none.
Definition: chain.h:390
bool isNum() const
Definition: univalue.h:86
const UniValue & get_array() const
uint64_t coins_count
The number of coins contained.
Definition: coinstats.h:44
uint32_t nTime
Definition: chain.h:142
undo data available in rev*.dat
Definition: chain.h:76
#define LIST_CHAIN_NAMES
List of possible chain / network names.
static RPCHelpMan scantxoutset()
bool skip_type_check
Definition: util.h:170
Int getInt() const
Definition: univalue.h:140
bool IsInitialBlockDownload() const noexcept
Check whether we are doing an initial block download (synchronizing from disk or network) ...
CChain m_chain
The current chain of blockheaders we consult and build on.
Definition: validation.h:625
void format(std::ostream &out, FormatStringCheck< sizeof...(Args)> fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:1079
consteval auto _(util::TranslatedLiteral str)
Definition: translation.h:79
uint64_t nDiskSize
Definition: coinstats.h:39
void TxToUniv(const CTransaction &tx, const uint256 &block_hash, UniValue &entry, bool include_hex, const CTxUndo *txundo, TxVerbosity verbosity, std::function< bool(const CTxOut &)> is_change_func)
Definition: core_io.cpp:430
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: coins.cpp:83
static int ComputeNextBlockAndDepth(const CBlockIndex &tip, const CBlockIndex &blockindex, const CBlockIndex *&next)
Definition: blockchain.cpp:116
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
GetCoin, returning whether it exists and is not spent.
Definition: txmempool.cpp:742
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:372
static int32_t GetTransactionWeight(const CTransaction &tx)
Definition: validation.h:132
static constexpr int64_t TIMESTAMP_WINDOW
Timestamp window used as a grace period by code that compares external timestamps (such as timestamps...
Definition: chain.h:37
static RPCHelpMan loadtxoutset()
void ForceFlushStateToDisk(bool wipe_cache=true)
Flush all changes to disk.
arith_uint256 total_coinbase_amount
Total cumulative amount of coinbase outputs up to and including this block.
Definition: coinstats.h:69
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:58
std::unique_ptr< Descriptor > InferDescriptor(const CScript &script, const SigningProvider &provider)
Find a descriptor for the specified script, using information from provider where possible...
bool isSpent(const COutPoint &outpoint) const
Definition: txmempool.cpp:190
void reserve(size_t new_cap)
Definition: univalue.cpp:242
const std::vector< CTxIn > vin
Definition: transaction.h:291
Invalid, missing or duplicate parameter.
Definition: protocol.h:44
static RPCHelpMan getdescriptoractivity()
RAII class that temporarily rolls back the local chain in it&#39;s constructor and rolls it forward again...
RPCHelpMan getblockchaininfo()
VersionBitsCache m_versionbitscache
Track versionbit status.
Definition: validation.h:1192
CTxMemPoolEntry stores data about the corresponding transaction, as well as data about all in-mempool...
Definition: mempool_entry.h:65
Minimal stream for reading from an existing byte array by std::span.
Definition: streams.h:82
bool DeploymentEnabled(const Consensus::Params &params, Consensus::BuriedDeployment dep)
Determine if a deployment is enabled (can ever be active)
std::string SysErrorString(int err)
Return system error string from errno value.
Definition: syserror.cpp:17
CoinsViewScanReserver()=default
static RPCHelpMan getchaintxstats()
const RPCResult getblock_vin
Definition: blockchain.cpp:737
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:60
CAmount total_unspendables_bip30
The two unspendable coinbase outputs total amount caused by BIP30.
Definition: coinstats.h:56
static T CalculateTruncatedMedian(std::vector< T > &scores)
std::string GetAllOutputTypes()
Gets all existing output types formatted for RPC help sections.
Definition: util.cpp:46
virtual bool GetValue(Coin &coin) const =0
uint256 GetBlockHash() const
Definition: chain.h:198
std::tuple< std::unique_ptr< CCoinsViewCursor >, CCoinsStats, const CBlockIndex * > PrepareUTXOSnapshot(Chainstate &chainstate, const std::function< void()> &interruption_point={}) EXCLUSIVE_LOCKS_REQUIRED(UniValue WriteUTXOSnapshot(Chainstate &chainstate, CCoinsViewCursor *pcursor, CCoinsStats *maybe_stats, const CBlockIndex *tip, AutoFile &&afile, const fs::path &path, const fs::path &temppath, const std::function< void()> &interruption_point={})
Definition: blockchain.cpp:84
arith_uint256 total_prevout_spent_amount
Total cumulative amount of prevouts spent up to and including this block.
Definition: coinstats.h:65
UniValue CreateUTXOSnapshot(node::NodeContext &node, Chainstate &chainstate, AutoFile &&afile, const fs::path &path, const fs::path &tmppath)
Test-only helper to create UTXO snapshots given a chainstate and a file handle.
std::string oneline_description
Should be empty unless it is supposed to override the auto-generated summary line.
Definition: util.h:171
uint32_t nHeight
at which height this containing transaction was included in the active block chain ...
Definition: coins.h:44
bool IsValid() const
Definition: validation.h:105
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:61
iterator end()
Definition: prevector.h:257
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:50
BlockFilterType
Definition: blockfilter.h:93
static RPCHelpMan getblockfilter()
uint64_t PruneAfterHeight() const
Definition: chainparams.h:101
std::string MakeUnorderedList(const std::vector< std::string > &items)
Create an unordered multi-line list of items.
Definition: string.h:226
Special type that is a STR with only hex chars.
NodeContext struct containing references to chain state and connection state.
Definition: context.h:56
bool IsBIP30Repeat(const CBlockIndex &block_index)
Identifies blocks that overwrote an existing coinbase output in the UTXO set (see BIP30) ...
static bool exists(const path &p)
Definition: fs.h:95
uint256 powLimit
Proof of work parameters.
Definition: params.h:112
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:201
ChainstateManager & m_chainman
The chainstate manager that owns this chainstate.
Definition: validation.h:583
Interface giving clients (RPC, Stratum v2 Template Provider in the future) ability to create block te...
Definition: mining.h:96
static std::atomic< bool > g_scan_in_progress
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:70
void ReconsiderBlock(ChainstateManager &chainman, uint256 block_hash)
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: args.h:239
bool operator()(const CBlockIndex *a, const CBlockIndex *b) const
Special string with only hex chars.
Definition: util.h:186
ArgsManager & args
Definition: bitcoind.cpp:277
virtual bool Valid() const =0
Chainstate stores and provides an API to update our local knowledge of the current best chain...
Definition: validation.h:550
static RPCHelpMan waitfornewblock()
Definition: blockchain.cpp:290
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)
Scripts & signatures ok.
Definition: chain.h:69
static const CBlockIndex * ParseHashOrHeight(const UniValue &param, ChainstateManager &chainman)
Definition: blockchain.cpp:126
void RegisterBlockchainRPCCommands(CRPCTable &t)
uint32_t nNonce
Definition: chain.h:144
Abstract view on the open txout dataset.
Definition: coins.h:307
UniValue blockheaderToJSON(const CBlockIndex &tip, const CBlockIndex &blockindex, const uint256 pow_limit)
Block header to JSON.
Definition: blockchain.cpp:154
An input of a transaction.
Definition: transaction.h:61
uint64_t m_chain_tx_count
(memory only) Number of transactions in the chain up to and including this block. ...
Definition: chain.h:129
#define LOCK(cs)
Definition: sync.h:258
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:132
int DeploymentHeight(BuriedDeployment dep) const
Definition: params.h:139
std::string ToString() const
Definition: validation.h:111
static RPCHelpMan dumptxoutset()
Serialize the UTXO set to a file for loading elsewhere.
void WriteCompactSize(SizeComputer &os, uint64_t nSize)
Definition: serialize.h:1089
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:599
Complete block filter struct as defined in BIP 157.
Definition: blockfilter.h:115
double GuessVerificationProgress(const CBlockIndex *pindex) const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Guess verification progress (as a fraction between 0.0=genesis and 1.0=current tip).
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:410
kernel::Notifications & GetNotifications() const
Definition: validation.h:1012
Txid hash
Definition: transaction.h:31
int64_t size()
Return the size of the file.
Definition: streams.cpp:60
int64_t nPowTargetSpacing
Definition: params.h:120
RAII wrapper for VerifyDB: Verify consistency of the block and coin databases.
Definition: validation.h:435
static const auto output_descriptor_obj
uint32_t n
Definition: transaction.h:32
uint64_t GetSerializeSize(const T &t)
Definition: serialize.h:1095
interfaces::Mining & EnsureMining(const NodeContext &node)
uint256 hashSerialized
Definition: coinstats.h:38
static RPCHelpMan getblockstats()
const Consensus::Params & GetConsensus() const
Definition: validation.h:1008
const std::string CURRENCY_UNIT
Definition: feerate.h:19
ReadRawBlockResult ReadRawBlock(const FlatFilePos &pos, std::optional< std::pair< size_t, size_t >> block_part=std::nullopt) const
SnapshotCompletionResult MaybeValidateSnapshot(Chainstate &validated_cs, Chainstate &unvalidated_cs) EXCLUSIVE_LOCKS_REQUIRED(Chainstate & CurrentChainstate() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Try to validate an assumeutxo snapshot by using a validated historical chainstate targeted at the sna...
Definition: validation.h:1119
uint256 hashMerkleRoot
Definition: chain.h:141
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1167
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
Definition: blockstorage.h:191
CCoinsViewDB & CoinsDB() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:694
std::optional< int > GetPruneHeight(const BlockManager &blockman, const CChain &chain)
Return height of highest block that has been pruned, or std::nullopt if no blocks have been pruned...
Definition: blockchain.cpp:883
General application defined errors.
Definition: protocol.h:40
std::string DefaultHint
Hint for default value.
Definition: util.h:220
int64_t NodeId
Definition: net.h:103
void push_backV(const std::vector< UniValue > &vec)
Definition: univalue.cpp:110
Every block in the chain has been validated.
Definition: net.h:1071
void SetNetworkActive(bool active)
Definition: net.cpp:3354
bool GetNetworkActive() const
Definition: net.h:1167
An output of a transaction.
Definition: transaction.h:139
std::string ToString() const
Definition: uint256.cpp:21
CoinStatsHashType ParseHashType(std::string_view hash_type_input)
Definition: blockchain.cpp:967
Invalid address or key.
Definition: protocol.h:42
RAII class that disables the network in its constructor and enables it in its destructor.
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
Definition: validation.h:1032
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:28
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:183
bool IsDeprecatedRPCEnabled(const std::string &method)
Definition: server.cpp:339
unsigned int nHeight
bool isNull() const
Definition: univalue.h:81
Special numeric to denote unix epoch time.
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:289
UniValue Default
Default constant value.
Definition: util.h:222
256-bit unsigned big integer.
int64_t GetMedianTimePast() const
Definition: chain.h:233
static RPCHelpMan getdifficulty()
Definition: blockchain.cpp:493
static RPCHelpMan invalidateblock()
std::unordered_set< Element, ByteVectorHash > ElementSet
Definition: blockfilter.h:33
virtual bool GetKey(COutPoint &key) const =0
UniValue GetWarningsForRpc(const Warnings &warnings, bool use_deprecated)
RPC helper function that wraps warnings.GetMessages().
Definition: warnings.cpp:54
node::BlockMap & BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:1183
static RPCHelpMan getblockcount()
Definition: blockchain.cpp:247
Definition: messages.h:21
script_verify_flags GetBlockScriptFlags(const CBlockIndex &block_index, const ChainstateManager &chainman)
void ScriptToUniv(const CScript &script, UniValue &out, bool include_hex, bool include_address, const SigningProvider *provider)
Definition: core_io.cpp:409
void InvalidateBlock(ChainstateManager &chainman, const uint256 block_hash)
uint256 GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:198
Database error.
Definition: protocol.h:45
Special type that is a NUM or [NUM,NUM].
int32_t nVersion
block header
Definition: chain.h:140
const CChainParams & GetParams() const
Definition: validation.h:1007
#define LogDebug(category,...)
Definition: log.h:115
256-bit opaque blob.
Definition: uint256.h:195
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
ChainType GetChainType() const
Return the chain type.
Definition: chainparams.h:111
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:51
static RPCHelpMan waitforblock()
Definition: blockchain.cpp:349
std::vector< CTransactionRef > vtx
Definition: block.h:77
std::string utf8string() const
Return a UTF-8 representation of the path as a std::string, for compatibility with code using std::st...
Definition: fs.h:74
static const auto scan_objects_arg_desc
static CBlock GetBlockChecked(BlockManager &blockman, const CBlockIndex &blockindex)
Definition: blockchain.cpp:686
Detailed status of an enabled BIP9 deployment.
Definition: versionbits.h:50
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:186
auto result
Definition: common-types.h:74
static bool SetHasKeys(const std::set< T > &set)
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:985
int ParseVerbosity(const UniValue &arg, int default_verbosity, bool allow_bool)
Parses verbosity from provided UniValue.
Definition: util.cpp:83
Only TXID for each block&#39;s transaction.
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:93
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:125
Undo information for a CBlock.
Definition: undo.h:62
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:404
static transaction_identifier FromUint256(const uint256 &id)
uint256 ParseHashV(const UniValue &v, std::string_view name)
Utilities: convert hex-encoded Values (throws error if not hex).
Definition: util.cpp:117
static const signed int DEFAULT_CHECKBLOCKS
Definition: validation.h:77
Undo information for a CTransaction.
Definition: undo.h:52
uint64_t GetLow64() const
ChainstateManager & EnsureChainman(const NodeContext &node)
Definition: server_util.cpp:74
static bool ComputeUTXOStats(CCoinsView *view, CCoinsStats &stats, T hash_obj, const std::function< void()> &interruption_point, std::unique_ptr< CCoinsViewCursor > pcursor)
Calculate statistics about the unspent transaction output set.
Definition: coinstats.cpp:112
const MessageStartChars & MessageStart() const
Definition: chainparams.h:90
virtual std::optional< BlockRef > getTip()=0
Returns the hash and height for the tip of this chain.
virtual uint256 GetBestBlock() const
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:19
BIP9Info Info(const CBlockIndex &block_index, const Consensus::Params &params, Consensus::DeploymentPos id) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
std::vector< uint8_t > signet_challenge
Definition: params.h:137
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:396
static RPCHelpMan preciousblock()
std::string GetHex() const
Definition: uint256.cpp:11
static constexpr size_t PER_UTXO_OVERHEAD
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:157
static RPCHelpMan waitforblockheight()
Definition: blockchain.cpp:410
static RPCHelpMan gettxoutsetinfo()
int fclose()
Definition: streams.h:407
ArgsManager & EnsureAnyArgsman(const std::any &context)
Definition: server_util.cpp:69
const UniValue NullUniValue
Definition: univalue.cpp:15
static constexpr CAmount MAX_MONEY
No amount larger than this (in satoshi) is valid.
Definition: amount.h:26
static RPCHelpMan pruneblockchain()
Definition: blockchain.cpp:908
#define AssertLockNotHeld(cs)
Definition: sync.h:141
static void pool cs
bool ReadBlock(CBlock &block, const FlatFilePos &pos, const std::optional< uint256 > &expected_hash) const
Functions for disk access for blocks.
static int count
bilingual_str ErrorString(const Result< T > &result)
Definition: result.h:93
iterator begin()
Definition: prevector.h:255
TemporaryRollback(ChainstateManager &chainman, const CBlockIndex &index)
static CBlockUndo GetUndoChecked(BlockManager &blockman, const CBlockIndex &blockindex)
Definition: blockchain.cpp:718
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:1324
static RPCHelpMan reconsiderblock()
PeerManager & EnsurePeerman(const NodeContext &node)
const CBlockIndex & m_invalidate_index
unsigned char * UCharCast(char *c)
Definition: span.h:95
ChainstateManager & m_chainman
static RPCHelpMan getchaintips()
bool IsValid(enum BlockStatus nUpTo) const EXCLUSIVE_LOCKS_REQUIRED(
Check whether this block index entry is valid up to the passed validity level.
Definition: chain.h:250
std::unique_ptr< CoinStatsIndex > g_coin_stats_index
The global UTXO set hash object.
double GetDifficulty(const CBlockIndex &blockindex)
Get the difficulty of the net wrt to the given block index.
Definition: blockchain.cpp:96
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
UniValue coinbaseTxToJSON(const CTransaction &coinbase_tx)
Serialize coinbase transaction metadata.
Definition: blockchain.cpp:185
static path u8path(std::string_view utf8_str)
Definition: fs.h:81
std::string GetHex() const
Hex encoding of the number (with the most significant digits first).
size_t size() const
Definition: univalue.h:71
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:54
The basic transaction that is broadcasted on the network and contained in blocks. ...
Definition: transaction.h:280
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:106
FlatFilePos GetBlockPos() const EXCLUSIVE_LOCKS_REQUIRED(
Definition: chain.h:163
const std::vector< unsigned char > & GetEncodedFilter() const LIFETIMEBOUND
Definition: blockfilter.h:139
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:89
void CheckBlockDataAvailability(BlockManager &blockman, const CBlockIndex &blockindex, bool check_for_undo)
Definition: blockchain.cpp:671
Chainstate & ActiveChainstate() const
Alternatives to CurrentChainstate() used by older code to query latest chainstate information without...
Special dictionary with keys that are not literals.
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:367
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition: chain.cpp:110
full block available in blk*.dat
Definition: chain.h:75
std::vector< std::string > GetScriptFlagNames(script_verify_flags flags)
virtual std::optional< BlockRef > waitTipChanged(uint256 current_tip, MillisecondsDouble timeout=MillisecondsDouble::max())=0
Waits for the connected tip to change.
ChainstateManager & EnsureAnyChainman(const std::any &context)
Definition: server_util.cpp:82
Chainstate * HistoricalChainstate() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Return historical chainstate targeting a specific block, if any.
Definition: validation.h:1128
std::vector< CTxUndo > vtxundo
Definition: undo.h:65
static int64_t GetBlockWeight(const CBlock &block)
Definition: validation.h:136
static RPCHelpMan scanblocks()
uint64_t nBogoSize
Definition: coinstats.h:37
uint64_t nTransactionOutputs
Definition: coinstats.h:36
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:33
uint64_t GetPruneTarget() const
Attempt to stay below this number of bytes of block files.
Definition: blockstorage.h:407
bool PreciousBlock(BlockValidationState &state, CBlockIndex *pindex) LOCKS_EXCLUDED(bool InvalidateBlock(BlockValidationState &state, CBlockIndex *pindex) LOCKS_EXCLUDED(void SetBlockFailureFlags(CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(voi ResetBlockFailureFlags)(CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Mark a block as precious and reorganize.
Definition: validation.h:805
std::tuple< std::unique_ptr< CCoinsViewCursor >, CCoinsStats, const CBlockIndex * > PrepareUTXOSnapshot(Chainstate &chainstate, const std::function< void()> &interruption_point)
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:50
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:752
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.
std::string HexStr(const std::span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition: hex_base.cpp:30
#define T(expected, seed, data)
uint32_t nBits
Definition: chain.h:143
std::chrono::duration< double, std::chrono::milliseconds::period > MillisecondsDouble
Definition: time.h:94
BuriedDeployment
A buried deployment is one where the height of the activation has been hardcoded into the client impl...
Definition: params.h:24
unsigned int nTx
Number of transactions in this block.
Definition: chain.h:123
std::vector< CTxMemPoolEntryRef > entryAll() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: txmempool.cpp:588
NodeContext & EnsureAnyNodeContext(const std::any &context)
Definition: server_util.cpp:25
static RPCHelpMan getblockhash()
Definition: blockchain.cpp:569
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it...
Definition: txmempool.h:260
ArgsManager & EnsureArgsman(const NodeContext &node)
Definition: server_util.cpp:61
Error parsing or validating structure in raw format.
Definition: protocol.h:46
CConnman & EnsureConnman(const NodeContext &node)
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:43
const uint32_t nLockTime
Definition: transaction.h:294
static constexpr TransactionSerParams TX_WITH_WITNESS
Definition: transaction.h:180
static constexpr TransactionSerParams TX_NO_WITNESS
Definition: transaction.h:181
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)
bool ReadBlockUndo(CBlockUndo &blockundo, const CBlockIndex &index) const
Metadata describing a serialized version of a UTXO set from which an assumeutxo Chainstate can be con...
Definition: utxo_snapshot.h:37
const uint32_t version
Definition: transaction.h:293
Cursor for iterating over CoinsView state.
Definition: coins.h:229
static RPCHelpMan getbestblockhash()
Definition: blockchain.cpp:269