blockchain.cpp raw

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