LCOV - code coverage report
Current view: top level - src/rpc - blockchain.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 1830 1936 94.5 %
Date: 2022-04-21 14:51:19 Functions: 98 102 96.1 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 470 578 81.3 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2010 Satoshi Nakamoto
#       2                 :            : // Copyright (c) 2009-2022 The Bitcoin Core developers
#       3                 :            : // Distributed under the MIT software license, see the accompanying
#       4                 :            : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#       5                 :            : 
#       6                 :            : #include <rpc/blockchain.h>
#       7                 :            : 
#       8                 :            : #include <blockfilter.h>
#       9                 :            : #include <chain.h>
#      10                 :            : #include <chainparams.h>
#      11                 :            : #include <coins.h>
#      12                 :            : #include <consensus/amount.h>
#      13                 :            : #include <consensus/params.h>
#      14                 :            : #include <consensus/validation.h>
#      15                 :            : #include <core_io.h>
#      16                 :            : #include <deploymentinfo.h>
#      17                 :            : #include <deploymentstatus.h>
#      18                 :            : #include <fs.h>
#      19                 :            : #include <hash.h>
#      20                 :            : #include <index/blockfilterindex.h>
#      21                 :            : #include <index/coinstatsindex.h>
#      22                 :            : #include <logging/timer.h>
#      23                 :            : #include <net.h>
#      24                 :            : #include <net_processing.h>
#      25                 :            : #include <node/blockstorage.h>
#      26                 :            : #include <node/coinstats.h>
#      27                 :            : #include <node/context.h>
#      28                 :            : #include <node/utxo_snapshot.h>
#      29                 :            : #include <primitives/transaction.h>
#      30                 :            : #include <rpc/server.h>
#      31                 :            : #include <rpc/server_util.h>
#      32                 :            : #include <rpc/util.h>
#      33                 :            : #include <script/descriptor.h>
#      34                 :            : #include <streams.h>
#      35                 :            : #include <sync.h>
#      36                 :            : #include <txdb.h>
#      37                 :            : #include <txmempool.h>
#      38                 :            : #include <undo.h>
#      39                 :            : #include <univalue.h>
#      40                 :            : #include <util/strencodings.h>
#      41                 :            : #include <util/translation.h>
#      42                 :            : #include <validation.h>
#      43                 :            : #include <validationinterface.h>
#      44                 :            : #include <versionbits.h>
#      45                 :            : #include <warnings.h>
#      46                 :            : 
#      47                 :            : #include <stdint.h>
#      48                 :            : 
#      49                 :            : #include <condition_variable>
#      50                 :            : #include <memory>
#      51                 :            : #include <mutex>
#      52                 :            : 
#      53                 :            : using node::BlockManager;
#      54                 :            : using node::CCoinsStats;
#      55                 :            : using node::CoinStatsHashType;
#      56                 :            : using node::GetUTXOStats;
#      57                 :            : using node::IsBlockPruned;
#      58                 :            : using node::NodeContext;
#      59                 :            : using node::ReadBlockFromDisk;
#      60                 :            : using node::SnapshotMetadata;
#      61                 :            : using node::UndoReadFromDisk;
#      62                 :            : 
#      63                 :            : struct CUpdatedBlock
#      64                 :            : {
#      65                 :            :     uint256 hash;
#      66                 :            :     int height;
#      67                 :            : };
#      68                 :            : 
#      69                 :            : static Mutex cs_blockchange;
#      70                 :            : static std::condition_variable cond_blockchange;
#      71                 :            : static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange);
#      72                 :            : 
#      73                 :            : /* Calculate the difficulty for a given block index.
#      74                 :            :  */
#      75                 :            : double GetDifficulty(const CBlockIndex* blockindex)
#      76                 :       5093 : {
#      77         [ -  + ]:       5093 :     CHECK_NONFATAL(blockindex);
#      78                 :            : 
#      79                 :       5093 :     int nShift = (blockindex->nBits >> 24) & 0xff;
#      80                 :       5093 :     double dDiff =
#      81                 :       5093 :         (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
#      82                 :            : 
#      83         [ +  + ]:       5117 :     while (nShift < 29)
#      84                 :         24 :     {
#      85                 :         24 :         dDiff *= 256.0;
#      86                 :         24 :         nShift++;
#      87                 :         24 :     }
#      88         [ +  + ]:      20290 :     while (nShift > 29)
#      89                 :      15197 :     {
#      90                 :      15197 :         dDiff /= 256.0;
#      91                 :      15197 :         nShift--;
#      92                 :      15197 :     }
#      93                 :            : 
#      94                 :       5093 :     return dDiff;
#      95                 :       5093 : }
#      96                 :            : 
#      97                 :            : static int ComputeNextBlockAndDepth(const CBlockIndex* tip, const CBlockIndex* blockindex, const CBlockIndex*& next)
#      98                 :       4636 : {
#      99                 :       4636 :     next = tip->GetAncestor(blockindex->nHeight + 1);
#     100 [ +  + ][ +  + ]:       4636 :     if (next && next->pprev == blockindex) {
#     101                 :       2454 :         return tip->nHeight - blockindex->nHeight + 1;
#     102                 :       2454 :     }
#     103                 :       2182 :     next = nullptr;
#     104         [ +  + ]:       2182 :     return blockindex == tip ? 1 : -1;
#     105                 :       4636 : }
#     106                 :            : 
#     107                 :            : static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateManager& chainman)
#     108                 :        117 : {
#     109                 :        117 :     LOCK(::cs_main);
#     110                 :        117 :     CChain& active_chain = chainman.ActiveChain();
#     111                 :            : 
#     112         [ +  + ]:        117 :     if (param.isNum()) {
#     113                 :        110 :         const int height{param.get_int()};
#     114         [ +  + ]:        110 :         if (height < 0) {
#     115                 :          1 :             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d is negative", height));
#     116                 :          1 :         }
#     117                 :        109 :         const int current_tip{active_chain.Height()};
#     118         [ +  + ]:        109 :         if (height > current_tip) {
#     119                 :          1 :             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d after current tip %d", height, current_tip));
#     120                 :          1 :         }
#     121                 :            : 
#     122                 :        108 :         return active_chain[height];
#     123                 :        109 :     } else {
#     124                 :          7 :         const uint256 hash{ParseHashV(param, "hash_or_height")};
#     125                 :          7 :         const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
#     126                 :            : 
#     127         [ +  + ]:          7 :         if (!pindex) {
#     128                 :          1 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
#     129                 :          1 :         }
#     130                 :            : 
#     131                 :          6 :         return pindex;
#     132                 :          7 :     }
#     133                 :        117 : }
#     134                 :            : 
#     135                 :            : UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex)
#     136                 :       4636 : {
#     137                 :            :     // Serialize passed information without accessing chain state of the active chain!
#     138                 :       4636 :     AssertLockNotHeld(cs_main); // For performance reasons
#     139                 :            : 
#     140                 :       4636 :     UniValue result(UniValue::VOBJ);
#     141                 :       4636 :     result.pushKV("hash", blockindex->GetBlockHash().GetHex());
#     142                 :       4636 :     const CBlockIndex* pnext;
#     143                 :       4636 :     int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
#     144                 :       4636 :     result.pushKV("confirmations", confirmations);
#     145                 :       4636 :     result.pushKV("height", blockindex->nHeight);
#     146                 :       4636 :     result.pushKV("version", blockindex->nVersion);
#     147                 :       4636 :     result.pushKV("versionHex", strprintf("%08x", blockindex->nVersion));
#     148                 :       4636 :     result.pushKV("merkleroot", blockindex->hashMerkleRoot.GetHex());
#     149                 :       4636 :     result.pushKV("time", (int64_t)blockindex->nTime);
#     150                 :       4636 :     result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
#     151                 :       4636 :     result.pushKV("nonce", (uint64_t)blockindex->nNonce);
#     152                 :       4636 :     result.pushKV("bits", strprintf("%08x", blockindex->nBits));
#     153                 :       4636 :     result.pushKV("difficulty", GetDifficulty(blockindex));
#     154                 :       4636 :     result.pushKV("chainwork", blockindex->nChainWork.GetHex());
#     155                 :       4636 :     result.pushKV("nTx", (uint64_t)blockindex->nTx);
#     156                 :            : 
#     157         [ +  + ]:       4636 :     if (blockindex->pprev)
#     158                 :       4608 :         result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
#     159         [ +  + ]:       4636 :     if (pnext)
#     160                 :       2454 :         result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
#     161                 :       4636 :     return result;
#     162                 :       4636 : }
#     163                 :            : 
#     164                 :            : UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity)
#     165                 :       2198 : {
#     166                 :       2198 :     UniValue result = blockheaderToJSON(tip, blockindex);
#     167                 :            : 
#     168                 :       2198 :     result.pushKV("strippedsize", (int)::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS));
#     169                 :       2198 :     result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION));
#     170                 :       2198 :     result.pushKV("weight", (int)::GetBlockWeight(block));
#     171                 :       2198 :     UniValue txs(UniValue::VARR);
#     172                 :            : 
#     173         [ -  + ]:       2198 :     switch (verbosity) {
#     174         [ +  + ]:        532 :         case TxVerbosity::SHOW_TXID:
#     175         [ +  + ]:       3517 :             for (const CTransactionRef& tx : block.vtx) {
#     176                 :       3517 :                 txs.push_back(tx->GetHash().GetHex());
#     177                 :       3517 :             }
#     178                 :        532 :             break;
#     179                 :            : 
#     180         [ +  + ]:       1659 :         case TxVerbosity::SHOW_DETAILS:
#     181         [ +  + ]:       1666 :         case TxVerbosity::SHOW_DETAILS_AND_PREVOUT:
#     182                 :       1666 :             CBlockUndo blockUndo;
#     183                 :       1666 :             const bool have_undo{WITH_LOCK(::cs_main, return !IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex))};
#     184                 :            : 
#     185         [ +  + ]:       3347 :             for (size_t i = 0; i < block.vtx.size(); ++i) {
#     186                 :       1681 :                 const CTransactionRef& tx = block.vtx.at(i);
#     187                 :            :                 // coinbase transaction (i.e. i == 0) doesn't have undo data
#     188 [ +  + ][ +  + ]:       1681 :                 const CTxUndo* txundo = (have_undo && i > 0) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
#     189                 :       1681 :                 UniValue objTx(UniValue::VOBJ);
#     190                 :       1681 :                 TxToUniv(*tx, /*block_hash=*/uint256(), /*entry=*/objTx, /*include_hex=*/true, RPCSerializationFlags(), txundo, verbosity);
#     191                 :       1681 :                 txs.push_back(objTx);
#     192                 :       1681 :             }
#     193                 :       1666 :             break;
#     194                 :       2198 :     }
#     195                 :            : 
#     196                 :       2198 :     result.pushKV("tx", txs);
#     197                 :            : 
#     198                 :       2198 :     return result;
#     199                 :       2198 : }
#     200                 :            : 
#     201                 :            : static RPCHelpMan getblockcount()
#     202                 :       5396 : {
#     203                 :       5396 :     return RPCHelpMan{"getblockcount",
#     204                 :       5396 :                 "\nReturns the height of the most-work fully-validated chain.\n"
#     205                 :       5396 :                 "The genesis block has height 0.\n",
#     206                 :       5396 :                 {},
#     207                 :       5396 :                 RPCResult{
#     208                 :       5396 :                     RPCResult::Type::NUM, "", "The current block count"},
#     209                 :       5396 :                 RPCExamples{
#     210                 :       5396 :                     HelpExampleCli("getblockcount", "")
#     211                 :       5396 :             + HelpExampleRpc("getblockcount", "")
#     212                 :       5396 :                 },
#     213                 :       5396 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     214                 :       5396 : {
#     215                 :       3802 :     ChainstateManager& chainman = EnsureAnyChainman(request.context);
#     216                 :       3802 :     LOCK(cs_main);
#     217                 :       3802 :     return chainman.ActiveChain().Height();
#     218                 :       3802 : },
#     219                 :       5396 :     };
#     220                 :       5396 : }
#     221                 :            : 
#     222                 :            : static RPCHelpMan getbestblockhash()
#     223                 :      15028 : {
#     224                 :      15028 :     return RPCHelpMan{"getbestblockhash",
#     225                 :      15028 :                 "\nReturns the hash of the best (tip) block in the most-work fully-validated chain.\n",
#     226                 :      15028 :                 {},
#     227                 :      15028 :                 RPCResult{
#     228                 :      15028 :                     RPCResult::Type::STR_HEX, "", "the block hash, hex-encoded"},
#     229                 :      15028 :                 RPCExamples{
#     230                 :      15028 :                     HelpExampleCli("getbestblockhash", "")
#     231                 :      15028 :             + HelpExampleRpc("getbestblockhash", "")
#     232                 :      15028 :                 },
#     233                 :      15028 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     234                 :      15028 : {
#     235                 :      13434 :     ChainstateManager& chainman = EnsureAnyChainman(request.context);
#     236                 :      13434 :     LOCK(cs_main);
#     237                 :      13434 :     return chainman.ActiveChain().Tip()->GetBlockHash().GetHex();
#     238                 :      13434 : },
#     239                 :      15028 :     };
#     240                 :      15028 : }
#     241                 :            : 
#     242                 :            : void RPCNotifyBlockChange(const CBlockIndex* pindex)
#     243                 :      54005 : {
#     244         [ +  + ]:      54005 :     if(pindex) {
#     245                 :      53216 :         LOCK(cs_blockchange);
#     246                 :      53216 :         latestblock.hash = pindex->GetBlockHash();
#     247                 :      53216 :         latestblock.height = pindex->nHeight;
#     248                 :      53216 :     }
#     249                 :      54005 :     cond_blockchange.notify_all();
#     250                 :      54005 : }
#     251                 :            : 
#     252                 :            : static RPCHelpMan waitfornewblock()
#     253                 :       1590 : {
#     254                 :       1590 :     return RPCHelpMan{"waitfornewblock",
#     255                 :       1590 :                 "\nWaits for a specific new block and returns useful info about it.\n"
#     256                 :       1590 :                 "\nReturns the current block on timeout or exit.\n",
#     257                 :       1590 :                 {
#     258                 :       1590 :                     {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
#     259                 :       1590 :                 },
#     260                 :       1590 :                 RPCResult{
#     261                 :       1590 :                     RPCResult::Type::OBJ, "", "",
#     262                 :       1590 :                     {
#     263                 :       1590 :                         {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
#     264                 :       1590 :                         {RPCResult::Type::NUM, "height", "Block height"},
#     265                 :       1590 :                     }},
#     266                 :       1590 :                 RPCExamples{
#     267                 :       1590 :                     HelpExampleCli("waitfornewblock", "1000")
#     268                 :       1590 :             + HelpExampleRpc("waitfornewblock", "1000")
#     269                 :       1590 :                 },
#     270                 :       1590 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     271                 :       1590 : {
#     272                 :          1 :     int timeout = 0;
#     273         [ -  + ]:          1 :     if (!request.params[0].isNull())
#     274                 :          0 :         timeout = request.params[0].get_int();
#     275                 :            : 
#     276                 :          1 :     CUpdatedBlock block;
#     277                 :          1 :     {
#     278                 :          1 :         WAIT_LOCK(cs_blockchange, lock);
#     279                 :          1 :         block = latestblock;
#     280         [ -  + ]:          1 :         if(timeout)
#     281 [ #  # ][ #  # ]:          0 :             cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
#                 [ #  # ]
#     282                 :          1 :         else
#     283 [ -  + ][ -  + ]:          2 :             cond_blockchange.wait(lock, [&block]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
#                 [ +  + ]
#     284                 :          1 :         block = latestblock;
#     285                 :          1 :     }
#     286                 :          1 :     UniValue ret(UniValue::VOBJ);
#     287                 :          1 :     ret.pushKV("hash", block.hash.GetHex());
#     288                 :          1 :     ret.pushKV("height", block.height);
#     289                 :          1 :     return ret;
#     290                 :          1 : },
#     291                 :       1590 :     };
#     292                 :       1590 : }
#     293                 :            : 
#     294                 :            : static RPCHelpMan waitforblock()
#     295                 :       1589 : {
#     296                 :       1589 :     return RPCHelpMan{"waitforblock",
#     297                 :       1589 :                 "\nWaits for a specific new block and returns useful info about it.\n"
#     298                 :       1589 :                 "\nReturns the current block on timeout or exit.\n",
#     299                 :       1589 :                 {
#     300                 :       1589 :                     {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Block hash to wait for."},
#     301                 :       1589 :                     {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
#     302                 :       1589 :                 },
#     303                 :       1589 :                 RPCResult{
#     304                 :       1589 :                     RPCResult::Type::OBJ, "", "",
#     305                 :       1589 :                     {
#     306                 :       1589 :                         {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
#     307                 :       1589 :                         {RPCResult::Type::NUM, "height", "Block height"},
#     308                 :       1589 :                     }},
#     309                 :       1589 :                 RPCExamples{
#     310                 :       1589 :                     HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\" 1000")
#     311                 :       1589 :             + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
#     312                 :       1589 :                 },
#     313                 :       1589 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     314                 :       1589 : {
#     315                 :          0 :     int timeout = 0;
#     316                 :            : 
#     317                 :          0 :     uint256 hash(ParseHashV(request.params[0], "blockhash"));
#     318                 :            : 
#     319         [ #  # ]:          0 :     if (!request.params[1].isNull())
#     320                 :          0 :         timeout = request.params[1].get_int();
#     321                 :            : 
#     322                 :          0 :     CUpdatedBlock block;
#     323                 :          0 :     {
#     324                 :          0 :         WAIT_LOCK(cs_blockchange, lock);
#     325         [ #  # ]:          0 :         if(timeout)
#     326 [ #  # ][ #  # ]:          0 :             cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.hash == hash || !IsRPCRunning();});
#     327                 :          0 :         else
#     328 [ #  # ][ #  # ]:          0 :             cond_blockchange.wait(lock, [&hash]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.hash == hash || !IsRPCRunning(); });
#     329                 :          0 :         block = latestblock;
#     330                 :          0 :     }
#     331                 :            : 
#     332                 :          0 :     UniValue ret(UniValue::VOBJ);
#     333                 :          0 :     ret.pushKV("hash", block.hash.GetHex());
#     334                 :          0 :     ret.pushKV("height", block.height);
#     335                 :          0 :     return ret;
#     336                 :          0 : },
#     337                 :       1589 :     };
#     338                 :       1589 : }
#     339                 :            : 
#     340                 :            : static RPCHelpMan waitforblockheight()
#     341                 :       1595 : {
#     342                 :       1595 :     return RPCHelpMan{"waitforblockheight",
#     343                 :       1595 :                 "\nWaits for (at least) block height and returns the height and hash\n"
#     344                 :       1595 :                 "of the current tip.\n"
#     345                 :       1595 :                 "\nReturns the current block on timeout or exit.\n",
#     346                 :       1595 :                 {
#     347                 :       1595 :                     {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "Block height to wait for."},
#     348                 :       1595 :                     {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
#     349                 :       1595 :                 },
#     350                 :       1595 :                 RPCResult{
#     351                 :       1595 :                     RPCResult::Type::OBJ, "", "",
#     352                 :       1595 :                     {
#     353                 :       1595 :                         {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
#     354                 :       1595 :                         {RPCResult::Type::NUM, "height", "Block height"},
#     355                 :       1595 :                     }},
#     356                 :       1595 :                 RPCExamples{
#     357                 :       1595 :                     HelpExampleCli("waitforblockheight", "100 1000")
#     358                 :       1595 :             + HelpExampleRpc("waitforblockheight", "100, 1000")
#     359                 :       1595 :                 },
#     360                 :       1595 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     361                 :       1595 : {
#     362                 :          6 :     int timeout = 0;
#     363                 :            : 
#     364                 :          6 :     int height = request.params[0].get_int();
#     365                 :            : 
#     366         [ +  + ]:          6 :     if (!request.params[1].isNull())
#     367                 :          4 :         timeout = request.params[1].get_int();
#     368                 :            : 
#     369                 :          6 :     CUpdatedBlock block;
#     370                 :          6 :     {
#     371                 :          6 :         WAIT_LOCK(cs_blockchange, lock);
#     372         [ +  + ]:          6 :         if(timeout)
#     373 [ +  + ][ -  + ]:          5 :             cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height >= height || !IsRPCRunning();});
#     374                 :          2 :         else
#     375 [ +  + ][ -  + ]:         12 :             cond_blockchange.wait(lock, [&height]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height >= height || !IsRPCRunning(); });
#     376                 :          6 :         block = latestblock;
#     377                 :          6 :     }
#     378                 :          6 :     UniValue ret(UniValue::VOBJ);
#     379                 :          6 :     ret.pushKV("hash", block.hash.GetHex());
#     380                 :          6 :     ret.pushKV("height", block.height);
#     381                 :          6 :     return ret;
#     382                 :          6 : },
#     383                 :       1595 :     };
#     384                 :       1595 : }
#     385                 :            : 
#     386                 :            : static RPCHelpMan syncwithvalidationinterfacequeue()
#     387                 :       7361 : {
#     388                 :       7361 :     return RPCHelpMan{"syncwithvalidationinterfacequeue",
#     389                 :       7361 :                 "\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n",
#     390                 :       7361 :                 {},
#     391                 :       7361 :                 RPCResult{RPCResult::Type::NONE, "", ""},
#     392                 :       7361 :                 RPCExamples{
#     393                 :       7361 :                     HelpExampleCli("syncwithvalidationinterfacequeue","")
#     394                 :       7361 :             + HelpExampleRpc("syncwithvalidationinterfacequeue","")
#     395                 :       7361 :                 },
#     396                 :       7361 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     397                 :       7361 : {
#     398                 :       5772 :     SyncWithValidationInterfaceQueue();
#     399                 :       5772 :     return NullUniValue;
#     400                 :       5772 : },
#     401                 :       7361 :     };
#     402                 :       7361 : }
#     403                 :            : 
#     404                 :            : static RPCHelpMan getdifficulty()
#     405                 :       1595 : {
#     406                 :       1595 :     return RPCHelpMan{"getdifficulty",
#     407                 :       1595 :                 "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n",
#     408                 :       1595 :                 {},
#     409                 :       1595 :                 RPCResult{
#     410                 :       1595 :                     RPCResult::Type::NUM, "", "the proof-of-work difficulty as a multiple of the minimum difficulty."},
#     411                 :       1595 :                 RPCExamples{
#     412                 :       1595 :                     HelpExampleCli("getdifficulty", "")
#     413                 :       1595 :             + HelpExampleRpc("getdifficulty", "")
#     414                 :       1595 :                 },
#     415                 :       1595 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     416                 :       1595 : {
#     417                 :          1 :     ChainstateManager& chainman = EnsureAnyChainman(request.context);
#     418                 :          1 :     LOCK(cs_main);
#     419                 :          1 :     return GetDifficulty(chainman.ActiveChain().Tip());
#     420                 :          1 : },
#     421                 :       1595 :     };
#     422                 :       1595 : }
#     423                 :            : 
#     424                 :            : static RPCHelpMan getblockfrompeer()
#     425                 :       1599 : {
#     426                 :       1599 :     return RPCHelpMan{
#     427                 :       1599 :         "getblockfrompeer",
#     428                 :       1599 :         "Attempt to fetch block from a given peer.\n\n"
#     429                 :       1599 :         "We must have the header for this block, e.g. using submitheader.\n"
#     430                 :       1599 :         "Subsequent calls for the same block and a new peer will cause the response from the previous peer to be ignored.\n\n"
#     431                 :       1599 :         "Returns an empty JSON object if the request was successfully scheduled.",
#     432                 :       1599 :         {
#     433                 :       1599 :             {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash to try to fetch"},
#     434                 :       1599 :             {"peer_id", RPCArg::Type::NUM, RPCArg::Optional::NO, "The peer to fetch it from (see getpeerinfo for peer IDs)"},
#     435                 :       1599 :         },
#     436                 :       1599 :         RPCResult{RPCResult::Type::OBJ, "", /*optional=*/false, "", {}},
#     437                 :       1599 :         RPCExamples{
#     438                 :       1599 :             HelpExampleCli("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0")
#     439                 :       1599 :             + HelpExampleRpc("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0")
#     440                 :       1599 :         },
#     441                 :       1599 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     442                 :       1599 : {
#     443                 :          5 :     const NodeContext& node = EnsureAnyNodeContext(request.context);
#     444                 :          5 :     ChainstateManager& chainman = EnsureChainman(node);
#     445                 :          5 :     PeerManager& peerman = EnsurePeerman(node);
#     446                 :            : 
#     447                 :          5 :     const uint256& block_hash{ParseHashV(request.params[0], "blockhash")};
#     448                 :          5 :     const NodeId peer_id{request.params[1].get_int64()};
#     449                 :            : 
#     450                 :          5 :     const CBlockIndex* const index = WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(block_hash););
#     451                 :            : 
#     452         [ +  + ]:          5 :     if (!index) {
#     453                 :          1 :         throw JSONRPCError(RPC_MISC_ERROR, "Block header missing");
#     454                 :          1 :     }
#     455                 :            : 
#     456                 :          4 :     const bool block_has_data = WITH_LOCK(::cs_main, return index->nStatus & BLOCK_HAVE_DATA);
#     457         [ +  + ]:          4 :     if (block_has_data) {
#     458                 :          1 :         throw JSONRPCError(RPC_MISC_ERROR, "Block already downloaded");
#     459                 :          1 :     }
#     460                 :            : 
#     461         [ +  + ]:          3 :     if (const auto err{peerman.FetchBlock(peer_id, *index)}) {
#     462                 :          1 :         throw JSONRPCError(RPC_MISC_ERROR, err.value());
#     463                 :          1 :     }
#     464                 :          2 :     return UniValue::VOBJ;
#     465                 :          3 : },
#     466                 :       1599 :     };
#     467                 :       1599 : }
#     468                 :            : 
#     469                 :            : static RPCHelpMan getblockhash()
#     470                 :       4373 : {
#     471                 :       4373 :     return RPCHelpMan{"getblockhash",
#     472                 :       4373 :                 "\nReturns hash of block in best-block-chain at height provided.\n",
#     473                 :       4373 :                 {
#     474                 :       4373 :                     {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The height index"},
#     475                 :       4373 :                 },
#     476                 :       4373 :                 RPCResult{
#     477                 :       4373 :                     RPCResult::Type::STR_HEX, "", "The block hash"},
#     478                 :       4373 :                 RPCExamples{
#     479                 :       4373 :                     HelpExampleCli("getblockhash", "1000")
#     480                 :       4373 :             + HelpExampleRpc("getblockhash", "1000")
#     481                 :       4373 :                 },
#     482                 :       4373 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     483                 :       4373 : {
#     484                 :       2779 :     ChainstateManager& chainman = EnsureAnyChainman(request.context);
#     485                 :       2779 :     LOCK(cs_main);
#     486                 :       2779 :     const CChain& active_chain = chainman.ActiveChain();
#     487                 :            : 
#     488                 :       2779 :     int nHeight = request.params[0].get_int();
#     489 [ -  + ][ +  + ]:       2779 :     if (nHeight < 0 || nHeight > active_chain.Height())
#     490                 :          1 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
#     491                 :            : 
#     492                 :       2778 :     const CBlockIndex* pblockindex = active_chain[nHeight];
#     493                 :       2778 :     return pblockindex->GetBlockHash().GetHex();
#     494                 :       2779 : },
#     495                 :       4373 :     };
#     496                 :       4373 : }
#     497                 :            : 
#     498                 :            : static RPCHelpMan getblockheader()
#     499                 :       4029 : {
#     500                 :       4029 :     return RPCHelpMan{"getblockheader",
#     501                 :       4029 :                 "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"
#     502                 :       4029 :                 "If verbose is true, returns an Object with information about blockheader <hash>.\n",
#     503                 :       4029 :                 {
#     504                 :       4029 :                     {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
#     505                 :       4029 :                     {"verbose", RPCArg::Type::BOOL, RPCArg::Default{true}, "true for a json object, false for the hex-encoded data"},
#     506                 :       4029 :                 },
#     507                 :       4029 :                 {
#     508                 :       4029 :                     RPCResult{"for verbose = true",
#     509                 :       4029 :                         RPCResult::Type::OBJ, "", "",
#     510                 :       4029 :                         {
#     511                 :       4029 :                             {RPCResult::Type::STR_HEX, "hash", "the block hash (same as provided)"},
#     512                 :       4029 :                             {RPCResult::Type::NUM, "confirmations", "The number of confirmations, or -1 if the block is not on the main chain"},
#     513                 :       4029 :                             {RPCResult::Type::NUM, "height", "The block height or index"},
#     514                 :       4029 :                             {RPCResult::Type::NUM, "version", "The block version"},
#     515                 :       4029 :                             {RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},
#     516                 :       4029 :                             {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
#     517                 :       4029 :                             {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
#     518                 :       4029 :                             {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
#     519                 :       4029 :                             {RPCResult::Type::NUM, "nonce", "The nonce"},
#     520                 :       4029 :                             {RPCResult::Type::STR_HEX, "bits", "The bits"},
#     521                 :       4029 :                             {RPCResult::Type::NUM, "difficulty", "The difficulty"},
#     522                 :       4029 :                             {RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the current chain"},
#     523                 :       4029 :                             {RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
#     524                 :       4029 :                             {RPCResult::Type::STR_HEX, "previousblockhash", /*optional=*/true, "The hash of the previous block (if available)"},
#     525                 :       4029 :                             {RPCResult::Type::STR_HEX, "nextblockhash", /*optional=*/true, "The hash of the next block (if available)"},
#     526                 :       4029 :                         }},
#     527                 :       4029 :                     RPCResult{"for verbose=false",
#     528                 :       4029 :                         RPCResult::Type::STR_HEX, "", "A string that is serialized, hex-encoded data for block 'hash'"},
#     529                 :       4029 :                 },
#     530                 :       4029 :                 RPCExamples{
#     531                 :       4029 :                     HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
#     532                 :       4029 :             + HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
#     533                 :       4029 :                 },
#     534                 :       4029 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     535                 :       4029 : {
#     536                 :       2435 :     uint256 hash(ParseHashV(request.params[0], "hash"));
#     537                 :            : 
#     538                 :       2435 :     bool fVerbose = true;
#     539         [ +  + ]:       2435 :     if (!request.params[1].isNull())
#     540                 :         21 :         fVerbose = request.params[1].get_bool();
#     541                 :            : 
#     542                 :       2435 :     const CBlockIndex* pblockindex;
#     543                 :       2435 :     const CBlockIndex* tip;
#     544                 :       2435 :     {
#     545                 :       2435 :         ChainstateManager& chainman = EnsureAnyChainman(request.context);
#     546                 :       2435 :         LOCK(cs_main);
#     547                 :       2435 :         pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
#     548                 :       2435 :         tip = chainman.ActiveChain().Tip();
#     549                 :       2435 :     }
#     550                 :            : 
#     551         [ +  + ]:       2435 :     if (!pblockindex) {
#     552                 :          2 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
#     553                 :          2 :     }
#     554                 :            : 
#     555         [ +  + ]:       2433 :     if (!fVerbose)
#     556                 :          1 :     {
#     557                 :          1 :         CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
#     558                 :          1 :         ssBlock << pblockindex->GetBlockHeader();
#     559                 :          1 :         std::string strHex = HexStr(ssBlock);
#     560                 :          1 :         return strHex;
#     561                 :          1 :     }
#     562                 :            : 
#     563                 :       2432 :     return blockheaderToJSON(tip, pblockindex);
#     564                 :       2433 : },
#     565                 :       4029 :     };
#     566                 :       4029 : }
#     567                 :            : 
#     568                 :            : static CBlock GetBlockChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
#     569                 :       2564 : {
#     570                 :       2564 :     AssertLockHeld(::cs_main);
#     571                 :       2564 :     CBlock block;
#     572         [ -  + ]:       2564 :     if (IsBlockPruned(pblockindex)) {
#     573                 :          0 :         throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
#     574                 :          0 :     }
#     575                 :            : 
#     576         [ +  + ]:       2564 :     if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) {
#     577                 :            :         // Block not found on disk. This could be because we have the block
#     578                 :            :         // header in our index but not yet have the block or did not accept the
#     579                 :            :         // block.
#     580                 :          5 :         throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
#     581                 :          5 :     }
#     582                 :            : 
#     583                 :       2559 :     return block;
#     584                 :       2564 : }
#     585                 :            : 
#     586                 :            : static CBlockUndo GetUndoChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
#     587                 :         99 : {
#     588                 :         99 :     AssertLockHeld(::cs_main);
#     589                 :         99 :     CBlockUndo blockUndo;
#     590         [ -  + ]:         99 :     if (IsBlockPruned(pblockindex)) {
#     591                 :          0 :         throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)");
#     592                 :          0 :     }
#     593                 :            : 
#     594         [ -  + ]:         99 :     if (!UndoReadFromDisk(blockUndo, pblockindex)) {
#     595                 :          0 :         throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
#     596                 :          0 :     }
#     597                 :            : 
#     598                 :         99 :     return blockUndo;
#     599                 :         99 : }
#     600                 :            : 
#     601                 :            : static RPCHelpMan getblock()
#     602                 :       4081 : {
#     603                 :       4081 :     return RPCHelpMan{"getblock",
#     604                 :       4081 :                 "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
#     605                 :       4081 :                 "If verbosity is 1, returns an Object with information about block <hash>.\n"
#     606                 :       4081 :                 "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction.\n"
#     607                 :       4081 :                 "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",
#     608                 :       4081 :                 {
#     609                 :       4081 :                     {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
#     610                 :       4081 :                     {"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"},
#     611                 :       4081 :                 },
#     612                 :       4081 :                 {
#     613                 :       4081 :                     RPCResult{"for verbosity = 0",
#     614                 :       4081 :                 RPCResult::Type::STR_HEX, "", "A string that is serialized, hex-encoded data for block 'hash'"},
#     615                 :       4081 :                     RPCResult{"for verbosity = 1",
#     616                 :       4081 :                 RPCResult::Type::OBJ, "", "",
#     617                 :       4081 :                 {
#     618                 :       4081 :                     {RPCResult::Type::STR_HEX, "hash", "the block hash (same as provided)"},
#     619                 :       4081 :                     {RPCResult::Type::NUM, "confirmations", "The number of confirmations, or -1 if the block is not on the main chain"},
#     620                 :       4081 :                     {RPCResult::Type::NUM, "size", "The block size"},
#     621                 :       4081 :                     {RPCResult::Type::NUM, "strippedsize", "The block size excluding witness data"},
#     622                 :       4081 :                     {RPCResult::Type::NUM, "weight", "The block weight as defined in BIP 141"},
#     623                 :       4081 :                     {RPCResult::Type::NUM, "height", "The block height or index"},
#     624                 :       4081 :                     {RPCResult::Type::NUM, "version", "The block version"},
#     625                 :       4081 :                     {RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},
#     626                 :       4081 :                     {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
#     627                 :       4081 :                     {RPCResult::Type::ARR, "tx", "The transaction ids",
#     628                 :       4081 :                         {{RPCResult::Type::STR_HEX, "", "The transaction id"}}},
#     629                 :       4081 :                     {RPCResult::Type::NUM_TIME, "time",       "The block time expressed in " + UNIX_EPOCH_TIME},
#     630                 :       4081 :                     {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
#     631                 :       4081 :                     {RPCResult::Type::NUM, "nonce", "The nonce"},
#     632                 :       4081 :                     {RPCResult::Type::STR_HEX, "bits", "The bits"},
#     633                 :       4081 :                     {RPCResult::Type::NUM, "difficulty", "The difficulty"},
#     634                 :       4081 :                     {RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the chain up to this block (in hex)"},
#     635                 :       4081 :                     {RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
#     636                 :       4081 :                     {RPCResult::Type::STR_HEX, "previousblockhash", /*optional=*/true, "The hash of the previous block (if available)"},
#     637                 :       4081 :                     {RPCResult::Type::STR_HEX, "nextblockhash", /*optional=*/true, "The hash of the next block (if available)"},
#     638                 :       4081 :                 }},
#     639                 :       4081 :                     RPCResult{"for verbosity = 2",
#     640                 :       4081 :                 RPCResult::Type::OBJ, "", "",
#     641                 :       4081 :                 {
#     642                 :       4081 :                     {RPCResult::Type::ELISION, "", "Same output as verbosity = 1"},
#     643                 :       4081 :                     {RPCResult::Type::ARR, "tx", "",
#     644                 :       4081 :                     {
#     645                 :       4081 :                         {RPCResult::Type::OBJ, "", "",
#     646                 :       4081 :                         {
#     647                 :       4081 :                             {RPCResult::Type::ELISION, "", "The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result"},
#     648                 :       4081 :                             {RPCResult::Type::NUM, "fee", "The transaction fee in " + CURRENCY_UNIT + ", omitted if block undo data is not available"},
#     649                 :       4081 :                         }},
#     650                 :       4081 :                     }},
#     651                 :       4081 :                 }},
#     652                 :       4081 :                     RPCResult{"for verbosity = 3",
#     653                 :       4081 :                 RPCResult::Type::OBJ, "", "",
#     654                 :       4081 :                 {
#     655                 :       4081 :                     {RPCResult::Type::ELISION, "", "Same output as verbosity = 2"},
#     656                 :       4081 :                     {RPCResult::Type::ARR, "tx", "",
#     657                 :       4081 :                     {
#     658                 :       4081 :                         {RPCResult::Type::OBJ, "", "",
#     659                 :       4081 :                         {
#     660                 :       4081 :                             {RPCResult::Type::ARR, "vin", "",
#     661                 :       4081 :                             {
#     662                 :       4081 :                                 {RPCResult::Type::OBJ, "", "",
#     663                 :       4081 :                                 {
#     664                 :       4081 :                                     {RPCResult::Type::ELISION, "", "The same output as verbosity = 2"},
#     665                 :       4081 :                                     {RPCResult::Type::OBJ, "prevout", "(Only if undo information is available)",
#     666                 :       4081 :                                     {
#     667                 :       4081 :                                         {RPCResult::Type::BOOL, "generated", "Coinbase or not"},
#     668                 :       4081 :                                         {RPCResult::Type::NUM, "height", "The height of the prevout"},
#     669                 :       4081 :                                         {RPCResult::Type::NUM, "value", "The value in " + CURRENCY_UNIT},
#     670                 :       4081 :                                         {RPCResult::Type::OBJ, "scriptPubKey", "",
#     671                 :       4081 :                                         {
#     672                 :       4081 :                                             {RPCResult::Type::STR, "asm", "The asm"},
#     673                 :       4081 :                                             {RPCResult::Type::STR, "hex", "The hex"},
#     674                 :       4081 :                                             {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
#     675                 :       4081 :                                             {RPCResult::Type::STR, "type", "The type (one of: " + GetAllOutputTypes() + ")"},
#     676                 :       4081 :                                         }},
#     677                 :       4081 :                                     }},
#     678                 :       4081 :                                 }},
#     679                 :       4081 :                             }},
#     680                 :       4081 :                         }},
#     681                 :       4081 :                     }},
#     682                 :       4081 :                 }},
#     683                 :       4081 :         },
#     684                 :       4081 :                 RPCExamples{
#     685                 :       4081 :                     HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
#     686                 :       4081 :             + HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
#     687                 :       4081 :                 },
#     688                 :       4081 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     689                 :       4081 : {
#     690                 :       2487 :     uint256 hash(ParseHashV(request.params[0], "blockhash"));
#     691                 :            : 
#     692                 :       2487 :     int verbosity = 1;
#     693         [ +  + ]:       2487 :     if (!request.params[1].isNull()) {
#     694         [ +  + ]:       2000 :         if (request.params[1].isBool()) {
#     695         [ +  + ]:        240 :             verbosity = request.params[1].get_bool() ? 1 : 0;
#     696                 :       1760 :         } else {
#     697                 :       1760 :             verbosity = request.params[1].get_int();
#     698                 :       1760 :         }
#     699                 :       2000 :     }
#     700                 :            : 
#     701                 :       2487 :     CBlock block;
#     702                 :       2487 :     const CBlockIndex* pblockindex;
#     703                 :       2487 :     const CBlockIndex* tip;
#     704                 :       2487 :     {
#     705                 :       2487 :         ChainstateManager& chainman = EnsureAnyChainman(request.context);
#     706                 :       2487 :         LOCK(cs_main);
#     707                 :       2487 :         pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
#     708                 :       2487 :         tip = chainman.ActiveChain().Tip();
#     709                 :            : 
#     710         [ +  + ]:       2487 :         if (!pblockindex) {
#     711                 :         21 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
#     712                 :         21 :         }
#     713                 :            : 
#     714                 :       2466 :         block = GetBlockChecked(pblockindex);
#     715                 :       2466 :     }
#     716                 :            : 
#     717         [ +  + ]:       2466 :     if (verbosity <= 0)
#     718                 :        266 :     {
#     719                 :        266 :         CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
#     720                 :        266 :         ssBlock << block;
#     721                 :        266 :         std::string strHex = HexStr(ssBlock);
#     722                 :        266 :         return strHex;
#     723                 :        266 :     }
#     724                 :            : 
#     725                 :       2200 :     TxVerbosity tx_verbosity;
#     726         [ +  + ]:       2200 :     if (verbosity == 1) {
#     727                 :        531 :         tx_verbosity = TxVerbosity::SHOW_TXID;
#     728         [ +  + ]:       1669 :     } else if (verbosity == 2) {
#     729                 :       1659 :         tx_verbosity = TxVerbosity::SHOW_DETAILS;
#     730                 :       1659 :     } else {
#     731                 :         10 :         tx_verbosity = TxVerbosity::SHOW_DETAILS_AND_PREVOUT;
#     732                 :         10 :     }
#     733                 :            : 
#     734                 :       2200 :     return blockToJSON(block, tip, pblockindex, tx_verbosity);
#     735                 :       2466 : },
#     736                 :       4081 :     };
#     737                 :       4081 : }
#     738                 :            : 
#     739                 :            : static RPCHelpMan pruneblockchain()
#     740                 :       1597 : {
#     741                 :       1597 :     return RPCHelpMan{"pruneblockchain", "",
#     742                 :       1597 :                 {
#     743                 :       1597 :                     {"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"
#     744                 :       1597 :             "                  to prune blocks whose block time is at least 2 hours older than the provided timestamp."},
#     745                 :       1597 :                 },
#     746                 :       1597 :                 RPCResult{
#     747                 :       1597 :                     RPCResult::Type::NUM, "", "Height of the last block pruned"},
#     748                 :       1597 :                 RPCExamples{
#     749                 :       1597 :                     HelpExampleCli("pruneblockchain", "1000")
#     750                 :       1597 :             + HelpExampleRpc("pruneblockchain", "1000")
#     751                 :       1597 :                 },
#     752                 :       1597 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     753                 :       1597 : {
#     754         [ -  + ]:          3 :     if (!node::fPruneMode)
#     755                 :          0 :         throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
#     756                 :            : 
#     757                 :          3 :     ChainstateManager& chainman = EnsureAnyChainman(request.context);
#     758                 :          3 :     LOCK(cs_main);
#     759                 :          3 :     CChainState& active_chainstate = chainman.ActiveChainstate();
#     760                 :          3 :     CChain& active_chain = active_chainstate.m_chain;
#     761                 :            : 
#     762                 :          3 :     int heightParam = request.params[0].get_int();
#     763         [ -  + ]:          3 :     if (heightParam < 0)
#     764                 :          0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative block height.");
#     765                 :            : 
#     766                 :            :     // Height value more than a billion is too high to be a block height, and
#     767                 :            :     // too low to be a block time (corresponds to timestamp from Sep 2001).
#     768         [ -  + ]:          3 :     if (heightParam > 1000000000) {
#     769                 :            :         // Add a 2 hour buffer to include blocks which might have had old timestamps
#     770                 :          0 :         const CBlockIndex* pindex = active_chain.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0);
#     771         [ #  # ]:          0 :         if (!pindex) {
#     772                 :          0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp.");
#     773                 :          0 :         }
#     774                 :          0 :         heightParam = pindex->nHeight;
#     775                 :          0 :     }
#     776                 :            : 
#     777                 :          3 :     unsigned int height = (unsigned int) heightParam;
#     778                 :          3 :     unsigned int chainHeight = (unsigned int) active_chain.Height();
#     779         [ -  + ]:          3 :     if (chainHeight < Params().PruneAfterHeight())
#     780                 :          0 :         throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning.");
#     781         [ -  + ]:          3 :     else if (height > chainHeight)
#     782                 :          0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height.");
#     783         [ -  + ]:          3 :     else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
#     784         [ #  # ]:          0 :         LogPrint(BCLog::RPC, "Attempt to prune blocks close to the tip.  Retaining the minimum number of blocks.\n");
#     785                 :          0 :         height = chainHeight - MIN_BLOCKS_TO_KEEP;
#     786                 :          0 :     }
#     787                 :            : 
#     788                 :          3 :     PruneBlockFilesManual(active_chainstate, height);
#     789                 :          3 :     const CBlockIndex* block = active_chain.Tip();
#     790         [ -  + ]:          3 :     CHECK_NONFATAL(block);
#     791 [ +  - ][ +  + ]:       1948 :     while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
#     792                 :       1945 :         block = block->pprev;
#     793                 :       1945 :     }
#     794                 :          3 :     return uint64_t(block->nHeight);
#     795                 :          3 : },
#     796                 :       1597 :     };
#     797                 :       1597 : }
#     798                 :            : 
#     799                 :            : CoinStatsHashType ParseHashType(const std::string& hash_type_input)
#     800                 :         38 : {
#     801         [ +  + ]:         38 :     if (hash_type_input == "hash_serialized_2") {
#     802                 :          5 :         return CoinStatsHashType::HASH_SERIALIZED;
#     803         [ +  + ]:         33 :     } else if (hash_type_input == "muhash") {
#     804                 :         22 :         return CoinStatsHashType::MUHASH;
#     805         [ +  + ]:         22 :     } else if (hash_type_input == "none") {
#     806                 :         10 :         return CoinStatsHashType::NONE;
#     807                 :         10 :     } else {
#     808                 :          1 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("'%s' is not a valid hash_type", hash_type_input));
#     809                 :          1 :     }
#     810                 :         38 : }
#     811                 :            : 
#     812                 :            : static RPCHelpMan gettxoutsetinfo()
#     813                 :       1637 : {
#     814                 :       1637 :     return RPCHelpMan{"gettxoutsetinfo",
#     815                 :       1637 :                 "\nReturns statistics about the unspent transaction output set.\n"
#     816                 :       1637 :                 "Note this call may take some time if you are not using coinstatsindex.\n",
#     817                 :       1637 :                 {
#     818                 :       1637 :                     {"hash_type", RPCArg::Type::STR, RPCArg::Default{"hash_serialized_2"}, "Which UTXO set hash should be calculated. Options: 'hash_serialized_2' (the legacy algorithm), 'muhash', 'none'."},
#     819                 :       1637 :                     {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "The block hash or height of the target height (only available with coinstatsindex).", "", {"", "string or numeric"}},
#     820                 :       1637 :                     {"use_index", RPCArg::Type::BOOL, RPCArg::Default{true}, "Use coinstatsindex, if available."},
#     821                 :       1637 :                 },
#     822                 :       1637 :                 RPCResult{
#     823                 :       1637 :                     RPCResult::Type::OBJ, "", "",
#     824                 :       1637 :                     {
#     825                 :       1637 :                         {RPCResult::Type::NUM, "height", "The block height (index) of the returned statistics"},
#     826                 :       1637 :                         {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at which these statistics are calculated"},
#     827                 :       1637 :                         {RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs"},
#     828                 :       1637 :                         {RPCResult::Type::NUM, "bogosize", "Database-independent, meaningless metric indicating the UTXO set size"},
#     829                 :       1637 :                         {RPCResult::Type::STR_HEX, "hash_serialized_2", /*optional=*/true, "The serialized hash (only present if 'hash_serialized_2' hash_type is chosen)"},
#     830                 :       1637 :                         {RPCResult::Type::STR_HEX, "muhash", /*optional=*/true, "The serialized hash (only present if 'muhash' hash_type is chosen)"},
#     831                 :       1637 :                         {RPCResult::Type::NUM, "transactions", /*optional=*/true, "The number of transactions with unspent outputs (not available when coinstatsindex is used)"},
#     832                 :       1637 :                         {RPCResult::Type::NUM, "disk_size", /*optional=*/true, "The estimated size of the chainstate on disk (not available when coinstatsindex is used)"},
#     833                 :       1637 :                         {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of coins in the UTXO set"},
#     834                 :       1637 :                         {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)"},
#     835                 :       1637 :                         {RPCResult::Type::OBJ, "block_info", /*optional=*/true, "Info on amounts in the block at this block height (only available if coinstatsindex is used)",
#     836                 :       1637 :                         {
#     837                 :       1637 :                             {RPCResult::Type::STR_AMOUNT, "prevout_spent", "Total amount of all prevouts spent in this block"},
#     838                 :       1637 :                             {RPCResult::Type::STR_AMOUNT, "coinbase", "Coinbase subsidy amount of this block"},
#     839                 :       1637 :                             {RPCResult::Type::STR_AMOUNT, "new_outputs_ex_coinbase", "Total amount of new outputs created by this block"},
#     840                 :       1637 :                             {RPCResult::Type::STR_AMOUNT, "unspendable", "Total amount of unspendable outputs created in this block"},
#     841                 :       1637 :                             {RPCResult::Type::OBJ, "unspendables", "Detailed view of the unspendable categories",
#     842                 :       1637 :                             {
#     843                 :       1637 :                                 {RPCResult::Type::STR_AMOUNT, "genesis_block", "The unspendable amount of the Genesis block subsidy"},
#     844                 :       1637 :                                 {RPCResult::Type::STR_AMOUNT, "bip30", "Transactions overridden by duplicates (no longer possible with BIP30)"},
#     845                 :       1637 :                                 {RPCResult::Type::STR_AMOUNT, "scripts", "Amounts sent to scripts that are unspendable (for example OP_RETURN outputs)"},
#     846                 :       1637 :                                 {RPCResult::Type::STR_AMOUNT, "unclaimed_rewards", "Fee rewards that miners did not claim in their coinbase transaction"},
#     847                 :       1637 :                             }}
#     848                 :       1637 :                         }},
#     849                 :       1637 :                     }},
#     850                 :       1637 :                 RPCExamples{
#     851                 :       1637 :                     HelpExampleCli("gettxoutsetinfo", "") +
#     852                 :       1637 :                     HelpExampleCli("gettxoutsetinfo", R"("none")") +
#     853                 :       1637 :                     HelpExampleCli("gettxoutsetinfo", R"("none" 1000)") +
#     854                 :       1637 :                     HelpExampleCli("gettxoutsetinfo", R"("none" '"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"')") +
#     855                 :       1637 :                     HelpExampleRpc("gettxoutsetinfo", "") +
#     856                 :       1637 :                     HelpExampleRpc("gettxoutsetinfo", R"("none")") +
#     857                 :       1637 :                     HelpExampleRpc("gettxoutsetinfo", R"("none", 1000)") +
#     858                 :       1637 :                     HelpExampleRpc("gettxoutsetinfo", R"("none", "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09")")
#     859                 :       1637 :                 },
#     860                 :       1637 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     861                 :       1637 : {
#     862                 :         43 :     UniValue ret(UniValue::VOBJ);
#     863                 :            : 
#     864                 :         43 :     const CBlockIndex* pindex{nullptr};
#     865         [ +  + ]:         43 :     const CoinStatsHashType hash_type{request.params[0].isNull() ? CoinStatsHashType::HASH_SERIALIZED : ParseHashType(request.params[0].get_str())};
#     866                 :         43 :     CCoinsStats stats{hash_type};
#     867 [ +  + ][ +  + ]:         43 :     stats.index_requested = request.params[2].isNull() || request.params[2].get_bool();
#     868                 :            : 
#     869                 :         43 :     NodeContext& node = EnsureAnyNodeContext(request.context);
#     870                 :         43 :     ChainstateManager& chainman = EnsureChainman(node);
#     871                 :         43 :     CChainState& active_chainstate = chainman.ActiveChainstate();
#     872                 :         43 :     active_chainstate.ForceFlushStateToDisk();
#     873                 :            : 
#     874                 :         43 :     CCoinsView* coins_view;
#     875                 :         43 :     BlockManager* blockman;
#     876                 :         43 :     {
#     877                 :         43 :         LOCK(::cs_main);
#     878                 :         43 :         coins_view = &active_chainstate.CoinsDB();
#     879                 :         43 :         blockman = &active_chainstate.m_blockman;
#     880                 :         43 :         pindex = blockman->LookupBlockIndex(coins_view->GetBestBlock());
#     881                 :         43 :     }
#     882                 :            : 
#     883         [ +  + ]:         43 :     if (!request.params[1].isNull()) {
#     884         [ +  + ]:         21 :         if (!g_coin_stats_index) {
#     885                 :          2 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Querying specific block heights requires coinstatsindex");
#     886                 :          2 :         }
#     887                 :            : 
#     888         [ +  + ]:         19 :         if (stats.m_hash_type == CoinStatsHashType::HASH_SERIALIZED) {
#     889                 :          4 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "hash_serialized_2 hash type cannot be queried for a specific block");
#     890                 :          4 :         }
#     891                 :            : 
#     892                 :         15 :         pindex = ParseHashOrHeight(request.params[1], chainman);
#     893                 :         15 :     }
#     894                 :            : 
#     895 [ +  + ][ +  + ]:         37 :     if (stats.index_requested && g_coin_stats_index) {
#     896         [ -  + ]:         22 :         if (!g_coin_stats_index->BlockUntilSyncedToCurrentChain()) {
#     897                 :          0 :             const IndexSummary summary{g_coin_stats_index->GetSummary()};
#     898                 :            : 
#     899                 :            :             // If a specific block was requested and the index has already synced past that height, we can return the
#     900                 :            :             // data already even though the index is not fully synced yet.
#     901         [ #  # ]:          0 :             if (pindex->nHeight > summary.best_block_height) {
#     902                 :          0 :                 throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to get data because coinstatsindex is still syncing. Current height: %d", summary.best_block_height));
#     903                 :          0 :             }
#     904                 :          0 :         }
#     905                 :         22 :     }
#     906                 :            : 
#     907         [ +  + ]:         37 :     if (GetUTXOStats(coins_view, *blockman, stats, node.rpc_interruption_point, pindex)) {
#     908                 :         36 :         ret.pushKV("height", (int64_t)stats.nHeight);
#     909                 :         36 :         ret.pushKV("bestblock", stats.hashBlock.GetHex());
#     910                 :         36 :         ret.pushKV("txouts", (int64_t)stats.nTransactionOutputs);
#     911                 :         36 :         ret.pushKV("bogosize", (int64_t)stats.nBogoSize);
#     912         [ +  + ]:         36 :         if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
#     913                 :          6 :             ret.pushKV("hash_serialized_2", stats.hashSerialized.GetHex());
#     914                 :          6 :         }
#     915         [ +  + ]:         36 :         if (hash_type == CoinStatsHashType::MUHASH) {
#     916                 :         21 :             ret.pushKV("muhash", stats.hashSerialized.GetHex());
#     917                 :         21 :         }
#     918         [ -  + ]:         36 :         CHECK_NONFATAL(stats.total_amount.has_value());
#     919                 :         36 :         ret.pushKV("total_amount", ValueFromAmount(stats.total_amount.value()));
#     920         [ +  + ]:         36 :         if (!stats.index_used) {
#     921                 :         14 :             ret.pushKV("transactions", static_cast<int64_t>(stats.nTransactions));
#     922                 :         14 :             ret.pushKV("disk_size", stats.nDiskSize);
#     923                 :         22 :         } else {
#     924                 :         22 :             ret.pushKV("total_unspendable_amount", ValueFromAmount(stats.total_unspendable_amount));
#     925                 :            : 
#     926                 :         22 :             CCoinsStats prev_stats{hash_type};
#     927                 :            : 
#     928         [ +  + ]:         22 :             if (pindex->nHeight > 0) {
#     929                 :         20 :                 GetUTXOStats(coins_view, *blockman, prev_stats, node.rpc_interruption_point, pindex->pprev);
#     930                 :         20 :             }
#     931                 :            : 
#     932                 :         22 :             UniValue block_info(UniValue::VOBJ);
#     933                 :         22 :             block_info.pushKV("prevout_spent", ValueFromAmount(stats.total_prevout_spent_amount - prev_stats.total_prevout_spent_amount));
#     934                 :         22 :             block_info.pushKV("coinbase", ValueFromAmount(stats.total_coinbase_amount - prev_stats.total_coinbase_amount));
#     935                 :         22 :             block_info.pushKV("new_outputs_ex_coinbase", ValueFromAmount(stats.total_new_outputs_ex_coinbase_amount - prev_stats.total_new_outputs_ex_coinbase_amount));
#     936                 :         22 :             block_info.pushKV("unspendable", ValueFromAmount(stats.total_unspendable_amount - prev_stats.total_unspendable_amount));
#     937                 :            : 
#     938                 :         22 :             UniValue unspendables(UniValue::VOBJ);
#     939                 :         22 :             unspendables.pushKV("genesis_block", ValueFromAmount(stats.total_unspendables_genesis_block - prev_stats.total_unspendables_genesis_block));
#     940                 :         22 :             unspendables.pushKV("bip30", ValueFromAmount(stats.total_unspendables_bip30 - prev_stats.total_unspendables_bip30));
#     941                 :         22 :             unspendables.pushKV("scripts", ValueFromAmount(stats.total_unspendables_scripts - prev_stats.total_unspendables_scripts));
#     942                 :         22 :             unspendables.pushKV("unclaimed_rewards", ValueFromAmount(stats.total_unspendables_unclaimed_rewards - prev_stats.total_unspendables_unclaimed_rewards));
#     943                 :         22 :             block_info.pushKV("unspendables", unspendables);
#     944                 :            : 
#     945                 :         22 :             ret.pushKV("block_info", block_info);
#     946                 :         22 :         }
#     947                 :         36 :     } else {
#     948                 :          1 :         throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
#     949                 :          1 :     }
#     950                 :         36 :     return ret;
#     951                 :         37 : },
#     952                 :       1637 :     };
#     953                 :       1637 : }
#     954                 :            : 
#     955                 :            : static RPCHelpMan gettxout()
#     956                 :       6563 : {
#     957                 :       6563 :     return RPCHelpMan{"gettxout",
#     958                 :       6563 :         "\nReturns details about an unspent transaction output.\n",
#     959                 :       6563 :         {
#     960                 :       6563 :             {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
#     961                 :       6563 :             {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
#     962                 :       6563 :             {"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."},
#     963                 :       6563 :         },
#     964                 :       6563 :         {
#     965                 :       6563 :             RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "", ""},
#     966                 :       6563 :             RPCResult{"Otherwise", RPCResult::Type::OBJ, "", "", {
#     967                 :       6563 :                 {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
#     968                 :       6563 :                 {RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
#     969                 :       6563 :                 {RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT},
#     970                 :       6563 :                 {RPCResult::Type::OBJ, "scriptPubKey", "", {
#     971                 :       6563 :                     {RPCResult::Type::STR, "asm", ""},
#     972                 :       6563 :                     {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
#     973                 :       6563 :                     {RPCResult::Type::STR_HEX, "hex", ""},
#     974                 :       6563 :                     {RPCResult::Type::STR, "type", "The type, eg pubkeyhash"},
#     975                 :       6563 :                     {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
#     976                 :       6563 :                 }},
#     977                 :       6563 :                 {RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
#     978                 :       6563 :             }},
#     979                 :       6563 :         },
#     980                 :       6563 :         RPCExamples{
#     981                 :       6563 :             "\nGet unspent transactions\n"
#     982                 :       6563 :             + HelpExampleCli("listunspent", "") +
#     983                 :       6563 :             "\nView the details\n"
#     984                 :       6563 :             + HelpExampleCli("gettxout", "\"txid\" 1") +
#     985                 :       6563 :             "\nAs a JSON-RPC call\n"
#     986                 :       6563 :             + HelpExampleRpc("gettxout", "\"txid\", 1")
#     987                 :       6563 :                 },
#     988                 :       6563 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     989                 :       6563 : {
#     990                 :       4969 :     NodeContext& node = EnsureAnyNodeContext(request.context);
#     991                 :       4969 :     ChainstateManager& chainman = EnsureChainman(node);
#     992                 :       4969 :     LOCK(cs_main);
#     993                 :            : 
#     994                 :       4969 :     UniValue ret(UniValue::VOBJ);
#     995                 :            : 
#     996                 :       4969 :     uint256 hash(ParseHashV(request.params[0], "txid"));
#     997                 :       4969 :     int n = request.params[1].get_int();
#     998                 :       4969 :     COutPoint out(hash, n);
#     999                 :       4969 :     bool fMempool = true;
#    1000         [ +  + ]:       4969 :     if (!request.params[2].isNull())
#    1001                 :         14 :         fMempool = request.params[2].get_bool();
#    1002                 :            : 
#    1003                 :       4969 :     Coin coin;
#    1004                 :       4969 :     CChainState& active_chainstate = chainman.ActiveChainstate();
#    1005                 :       4969 :     CCoinsViewCache* coins_view = &active_chainstate.CoinsTip();
#    1006                 :            : 
#    1007         [ +  + ]:       4969 :     if (fMempool) {
#    1008                 :       4963 :         const CTxMemPool& mempool = EnsureMemPool(node);
#    1009                 :       4963 :         LOCK(mempool.cs);
#    1010                 :       4963 :         CCoinsViewMemPool view(coins_view, mempool);
#    1011 [ -  + ][ +  + ]:       4963 :         if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
#    1012                 :          4 :             return NullUniValue;
#    1013                 :          4 :         }
#    1014                 :       4963 :     } else {
#    1015         [ +  + ]:          6 :         if (!coins_view->GetCoin(out, coin)) {
#    1016                 :          2 :             return NullUniValue;
#    1017                 :          2 :         }
#    1018                 :          6 :     }
#    1019                 :            : 
#    1020                 :       4963 :     const CBlockIndex* pindex = active_chainstate.m_blockman.LookupBlockIndex(coins_view->GetBestBlock());
#    1021                 :       4963 :     ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
#    1022         [ +  + ]:       4963 :     if (coin.nHeight == MEMPOOL_HEIGHT) {
#    1023                 :       1204 :         ret.pushKV("confirmations", 0);
#    1024                 :       3759 :     } else {
#    1025                 :       3759 :         ret.pushKV("confirmations", (int64_t)(pindex->nHeight - coin.nHeight + 1));
#    1026                 :       3759 :     }
#    1027                 :       4963 :     ret.pushKV("value", ValueFromAmount(coin.out.nValue));
#    1028                 :       4963 :     UniValue o(UniValue::VOBJ);
#    1029                 :       4963 :     ScriptToUniv(coin.out.scriptPubKey, /*out=*/o, /*include_hex=*/true, /*include_address=*/true);
#    1030                 :       4963 :     ret.pushKV("scriptPubKey", o);
#    1031                 :       4963 :     ret.pushKV("coinbase", (bool)coin.fCoinBase);
#    1032                 :            : 
#    1033                 :       4963 :     return ret;
#    1034                 :       4969 : },
#    1035                 :       6563 :     };
#    1036                 :       6563 : }
#    1037                 :            : 
#    1038                 :            : static RPCHelpMan verifychain()
#    1039                 :       1595 : {
#    1040                 :       1595 :     return RPCHelpMan{"verifychain",
#    1041                 :       1595 :                 "\nVerifies blockchain database.\n",
#    1042                 :       1595 :                 {
#    1043                 :       1595 :                     {"checklevel", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL)},
#    1044                 :       1595 :                         strprintf("How thorough the block verification is:\n%s", MakeUnorderedList(CHECKLEVEL_DOC))},
#    1045                 :       1595 :                     {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, 0=all", DEFAULT_CHECKBLOCKS)}, "The number of blocks to check."},
#    1046                 :       1595 :                 },
#    1047                 :       1595 :                 RPCResult{
#    1048                 :       1595 :                     RPCResult::Type::BOOL, "", "Verified or not"},
#    1049                 :       1595 :                 RPCExamples{
#    1050                 :       1595 :                     HelpExampleCli("verifychain", "")
#    1051                 :       1595 :             + HelpExampleRpc("verifychain", "")
#    1052                 :       1595 :                 },
#    1053                 :       1595 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#    1054                 :       1595 : {
#    1055         [ -  + ]:          1 :     const int check_level{request.params[0].isNull() ? DEFAULT_CHECKLEVEL : request.params[0].get_int()};
#    1056         [ -  + ]:          1 :     const int check_depth{request.params[1].isNull() ? DEFAULT_CHECKBLOCKS : request.params[1].get_int()};
#    1057                 :            : 
#    1058                 :          1 :     ChainstateManager& chainman = EnsureAnyChainman(request.context);
#    1059                 :          1 :     LOCK(cs_main);
#    1060                 :            : 
#    1061                 :          1 :     CChainState& active_chainstate = chainman.ActiveChainstate();
#    1062                 :          1 :     return CVerifyDB().VerifyDB(
#    1063                 :          1 :         active_chainstate, Params().GetConsensus(), active_chainstate.CoinsTip(), check_level, check_depth);
#    1064                 :          1 : },
#    1065                 :       1595 :     };
#    1066                 :       1595 : }
#    1067                 :            : 
#    1068                 :            : static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const Consensus::Params& params, Consensus::BuriedDeployment dep)
#    1069                 :        430 : {
#    1070                 :            :     // For buried deployments.
#    1071                 :            : 
#    1072         [ -  + ]:        430 :     if (!DeploymentEnabled(params, dep)) return;
#    1073                 :            : 
#    1074                 :        430 :     UniValue rv(UniValue::VOBJ);
#    1075                 :        430 :     rv.pushKV("type", "buried");
#    1076                 :            :     // getdeploymentinfo reports the softfork as active from when the chain height is
#    1077                 :            :     // one below the activation height
#    1078                 :        430 :     rv.pushKV("active", DeploymentActiveAfter(blockindex, params, dep));
#    1079                 :        430 :     rv.pushKV("height", params.DeploymentHeight(dep));
#    1080                 :        430 :     softforks.pushKV(DeploymentName(dep), rv);
#    1081                 :        430 : }
#    1082                 :            : 
#    1083                 :            : static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
#    1084                 :        172 : {
#    1085                 :            :     // For BIP9 deployments.
#    1086                 :            : 
#    1087         [ -  + ]:        172 :     if (!DeploymentEnabled(consensusParams, id)) return;
#    1088         [ -  + ]:        172 :     if (blockindex == nullptr) return;
#    1089                 :            : 
#    1090                 :        344 :     auto get_state_name = [](const ThresholdState state) -> std::string {
#    1091         [ -  + ]:        344 :         switch (state) {
#    1092         [ +  + ]:        110 :         case ThresholdState::DEFINED: return "defined";
#    1093         [ +  + ]:         55 :         case ThresholdState::STARTED: return "started";
#    1094         [ +  + ]:          6 :         case ThresholdState::LOCKED_IN: return "locked_in";
#    1095         [ +  + ]:        173 :         case ThresholdState::ACTIVE: return "active";
#    1096         [ -  + ]:          0 :         case ThresholdState::FAILED: return "failed";
#    1097                 :        344 :         }
#    1098                 :          0 :         return "invalid";
#    1099                 :        344 :     };
#    1100                 :            : 
#    1101                 :        172 :     UniValue bip9(UniValue::VOBJ);
#    1102                 :            : 
#    1103                 :        172 :     const ThresholdState next_state = g_versionbitscache.State(blockindex, consensusParams, id);
#    1104                 :        172 :     const ThresholdState current_state = g_versionbitscache.State(blockindex->pprev, consensusParams, id);
#    1105                 :            : 
#    1106 [ +  + ][ +  + ]:        172 :     const bool has_signal = (ThresholdState::STARTED == current_state || ThresholdState::LOCKED_IN == current_state);
#    1107                 :            : 
#    1108                 :            :     // BIP9 parameters
#    1109         [ +  + ]:        172 :     if (has_signal) {
#    1110                 :         31 :         bip9.pushKV("bit", consensusParams.vDeployments[id].bit);
#    1111                 :         31 :     }
#    1112                 :        172 :     bip9.pushKV("start_time", consensusParams.vDeployments[id].nStartTime);
#    1113                 :        172 :     bip9.pushKV("timeout", consensusParams.vDeployments[id].nTimeout);
#    1114                 :        172 :     bip9.pushKV("min_activation_height", consensusParams.vDeployments[id].min_activation_height);
#    1115                 :            : 
#    1116                 :            :     // BIP9 status
#    1117                 :        172 :     bip9.pushKV("status", get_state_name(current_state));
#    1118                 :        172 :     bip9.pushKV("since", g_versionbitscache.StateSinceHeight(blockindex->pprev, consensusParams, id));
#    1119                 :        172 :     bip9.pushKV("status_next", get_state_name(next_state));
#    1120                 :            : 
#    1121                 :            :     // BIP9 signalling status, if applicable
#    1122         [ +  + ]:        172 :     if (has_signal) {
#    1123                 :         31 :         UniValue statsUV(UniValue::VOBJ);
#    1124                 :         31 :         std::vector<bool> signals;
#    1125                 :         31 :         BIP9Stats statsStruct = g_versionbitscache.Statistics(blockindex, consensusParams, id, &signals);
#    1126                 :         31 :         statsUV.pushKV("period", statsStruct.period);
#    1127                 :         31 :         statsUV.pushKV("elapsed", statsStruct.elapsed);
#    1128                 :         31 :         statsUV.pushKV("count", statsStruct.count);
#    1129         [ +  + ]:         31 :         if (ThresholdState::LOCKED_IN != current_state) {
#    1130                 :         28 :             statsUV.pushKV("threshold", statsStruct.threshold);
#    1131                 :         28 :             statsUV.pushKV("possible", statsStruct.possible);
#    1132                 :         28 :         }
#    1133                 :         31 :         bip9.pushKV("statistics", statsUV);
#    1134                 :            : 
#    1135                 :         31 :         std::string sig;
#    1136                 :         31 :         sig.reserve(signals.size());
#    1137         [ +  + ]:       3184 :         for (const bool s : signals) {
#    1138         [ +  + ]:       3184 :             sig.push_back(s ? '#' : '-');
#    1139                 :       3184 :         }
#    1140                 :         31 :         bip9.pushKV("signalling", sig);
#    1141                 :         31 :     }
#    1142                 :            : 
#    1143                 :        172 :     UniValue rv(UniValue::VOBJ);
#    1144                 :        172 :     rv.pushKV("type", "bip9");
#    1145         [ +  + ]:        172 :     if (ThresholdState::ACTIVE == next_state) {
#    1146                 :         87 :         rv.pushKV("height", g_versionbitscache.StateSinceHeight(blockindex, consensusParams, id));
#    1147                 :         87 :     }
#    1148                 :        172 :     rv.pushKV("active", ThresholdState::ACTIVE == next_state);
#    1149                 :        172 :     rv.pushKV("bip9", bip9);
#    1150                 :            : 
#    1151                 :        172 :     softforks.pushKV(DeploymentName(id), rv);
#    1152                 :        172 : }
#    1153                 :            : 
#    1154                 :            : namespace {
#    1155                 :            : /* TODO: when -deprecatedrpc=softforks is removed, drop these */
#    1156                 :            : UniValue DeploymentInfo(const CBlockIndex* tip, const Consensus::Params& consensusParams);
#    1157                 :            : extern const std::vector<RPCResult> RPCHelpForDeployment;
#    1158                 :            : }
#    1159                 :            : 
#    1160                 :            : // used by rest.cpp:rest_chaininfo, so cannot be static
#    1161                 :            : RPCHelpMan getblockchaininfo()
#    1162                 :       2038 : {
#    1163                 :            :     /* TODO: from v24, remove -deprecatedrpc=softforks */
#    1164                 :       2038 :     return RPCHelpMan{"getblockchaininfo",
#    1165                 :       2038 :         "Returns an object containing various state info regarding blockchain processing.\n",
#    1166                 :       2038 :         {},
#    1167                 :       2038 :         RPCResult{
#    1168                 :       2038 :             RPCResult::Type::OBJ, "", "",
#    1169                 :       2038 :             {
#    1170                 :       2038 :                 {RPCResult::Type::STR, "chain", "current network name (main, test, signet, regtest)"},
#    1171                 :       2038 :                 {RPCResult::Type::NUM, "blocks", "the height of the most-work fully-validated chain. The genesis block has height 0"},
#    1172                 :       2038 :                 {RPCResult::Type::NUM, "headers", "the current number of headers we have validated"},
#    1173                 :       2038 :                 {RPCResult::Type::STR, "bestblockhash", "the hash of the currently best block"},
#    1174                 :       2038 :                 {RPCResult::Type::NUM, "difficulty", "the current difficulty"},
#    1175                 :       2038 :                 {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
#    1176                 :       2038 :                 {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
#    1177                 :       2038 :                 {RPCResult::Type::NUM, "verificationprogress", "estimate of verification progress [0..1]"},
#    1178                 :       2038 :                 {RPCResult::Type::BOOL, "initialblockdownload", "(debug information) estimate of whether this node is in Initial Block Download mode"},
#    1179                 :       2038 :                 {RPCResult::Type::STR_HEX, "chainwork", "total amount of work in active chain, in hexadecimal"},
#    1180                 :       2038 :                 {RPCResult::Type::NUM, "size_on_disk", "the estimated size of the block and undo files on disk"},
#    1181                 :       2038 :                 {RPCResult::Type::BOOL, "pruned", "if the blocks are subject to pruning"},
#    1182                 :       2038 :                 {RPCResult::Type::NUM, "pruneheight", /*optional=*/true, "lowest-height complete block stored (only present if pruning is enabled)"},
#    1183                 :       2038 :                 {RPCResult::Type::BOOL, "automatic_pruning", /*optional=*/true, "whether automatic pruning is enabled (only present if pruning is enabled)"},
#    1184                 :       2038 :                 {RPCResult::Type::NUM, "prune_target_size", /*optional=*/true, "the target size used by pruning (only present if automatic pruning is enabled)"},
#    1185                 :       2038 :                 {RPCResult::Type::OBJ_DYN, "softforks", /*optional=*/true, "(DEPRECATED, returned only if config option -deprecatedrpc=softforks is passed) status of softforks",
#    1186                 :       2038 :                 {
#    1187                 :       2038 :                     {RPCResult::Type::OBJ, "xxxx", "name of the softfork",
#    1188                 :       2038 :                         RPCHelpForDeployment
#    1189                 :       2038 :                     },
#    1190                 :       2038 :                 }},
#    1191                 :       2038 :                 {RPCResult::Type::STR, "warnings", "any network and blockchain warnings"},
#    1192                 :       2038 :             }},
#    1193                 :       2038 :         RPCExamples{
#    1194                 :       2038 :             HelpExampleCli("getblockchaininfo", "")
#    1195                 :       2038 :             + HelpExampleRpc("getblockchaininfo", "")
#    1196                 :       2038 :         },
#    1197                 :       2038 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#    1198                 :       2038 : {
#    1199                 :        441 :     const ArgsManager& args{EnsureAnyArgsman(request.context)};
#    1200                 :        441 :     ChainstateManager& chainman = EnsureAnyChainman(request.context);
#    1201                 :        441 :     LOCK(cs_main);
#    1202                 :        441 :     CChainState& active_chainstate = chainman.ActiveChainstate();
#    1203                 :            : 
#    1204                 :        441 :     const CBlockIndex* tip = active_chainstate.m_chain.Tip();
#    1205         [ -  + ]:        441 :     CHECK_NONFATAL(tip);
#    1206                 :        441 :     const int height = tip->nHeight;
#    1207                 :        441 :     UniValue obj(UniValue::VOBJ);
#    1208                 :        441 :     obj.pushKV("chain",                 Params().NetworkIDString());
#    1209                 :        441 :     obj.pushKV("blocks",                height);
#    1210         [ +  - ]:        441 :     obj.pushKV("headers",               pindexBestHeader ? pindexBestHeader->nHeight : -1);
#    1211                 :        441 :     obj.pushKV("bestblockhash",         tip->GetBlockHash().GetHex());
#    1212                 :        441 :     obj.pushKV("difficulty",            (double)GetDifficulty(tip));
#    1213                 :        441 :     obj.pushKV("time",                  (int64_t)tip->nTime);
#    1214                 :        441 :     obj.pushKV("mediantime",            (int64_t)tip->GetMedianTimePast());
#    1215                 :        441 :     obj.pushKV("verificationprogress",  GuessVerificationProgress(Params().TxData(), tip));
#    1216                 :        441 :     obj.pushKV("initialblockdownload",  active_chainstate.IsInitialBlockDownload());
#    1217                 :        441 :     obj.pushKV("chainwork",             tip->nChainWork.GetHex());
#    1218                 :        441 :     obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage());
#    1219                 :        441 :     obj.pushKV("pruned",                node::fPruneMode);
#    1220         [ +  + ]:        441 :     if (node::fPruneMode) {
#    1221                 :          4 :         const CBlockIndex* block = tip;
#    1222         [ -  + ]:          4 :         CHECK_NONFATAL(block);
#    1223 [ +  + ][ +  - ]:        803 :         while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
#    1224                 :        799 :             block = block->pprev;
#    1225                 :        799 :         }
#    1226                 :            : 
#    1227                 :          4 :         obj.pushKV("pruneheight",        block->nHeight);
#    1228                 :            : 
#    1229                 :            :         // if 0, execution bypasses the whole if block.
#    1230                 :          4 :         bool automatic_pruning{args.GetIntArg("-prune", 0) != 1};
#    1231                 :          4 :         obj.pushKV("automatic_pruning",  automatic_pruning);
#    1232         [ +  + ]:          4 :         if (automatic_pruning) {
#    1233                 :          1 :             obj.pushKV("prune_target_size",  node::nPruneTarget);
#    1234                 :          1 :         }
#    1235                 :          4 :     }
#    1236                 :            : 
#    1237         [ -  + ]:        441 :     if (IsDeprecatedRPCEnabled("softforks")) {
#    1238                 :          0 :         const Consensus::Params& consensusParams = Params().GetConsensus();
#    1239                 :          0 :         obj.pushKV("softforks", DeploymentInfo(tip, consensusParams));
#    1240                 :          0 :     }
#    1241                 :            : 
#    1242                 :        441 :     obj.pushKV("warnings", GetWarnings(false).original);
#    1243                 :        441 :     return obj;
#    1244                 :        441 : },
#    1245                 :       2038 :     };
#    1246                 :       2038 : }
#    1247                 :            : 
#    1248                 :            : namespace {
#    1249                 :            : const std::vector<RPCResult> RPCHelpForDeployment{
#    1250                 :            :     {RPCResult::Type::STR, "type", "one of \"buried\", \"bip9\""},
#    1251                 :            :     {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)"},
#    1252                 :            :     {RPCResult::Type::BOOL, "active", "true if the rules are enforced for the mempool and the next block"},
#    1253                 :            :     {RPCResult::Type::OBJ, "bip9", /*optional=*/true, "status of bip9 softforks (only for \"bip9\" type)",
#    1254                 :            :     {
#    1255                 :            :         {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)"},
#    1256                 :            :         {RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"},
#    1257                 :            :         {RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"},
#    1258                 :            :         {RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"},
#    1259                 :            :         {RPCResult::Type::STR, "status", "status of deployment at specified block (one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\")"},
#    1260                 :            :         {RPCResult::Type::NUM, "since", "height of the first block to which the status applies"},
#    1261                 :            :         {RPCResult::Type::STR, "status_next", "status of deployment at the next block"},
#    1262                 :            :         {RPCResult::Type::OBJ, "statistics", /*optional=*/true, "numeric statistics about signalling for a softfork (only for \"started\" and \"locked_in\" status)",
#    1263                 :            :         {
#    1264                 :            :             {RPCResult::Type::NUM, "period", "the length in blocks of the signalling period"},
#    1265                 :            :             {RPCResult::Type::NUM, "threshold", /*optional=*/true, "the number of blocks with the version bit set required to activate the feature (only for \"started\" status)"},
#    1266                 :            :             {RPCResult::Type::NUM, "elapsed", "the number of blocks elapsed since the beginning of the current period"},
#    1267                 :            :             {RPCResult::Type::NUM, "count", "the number of blocks with the version bit set in the current period"},
#    1268                 :            :             {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)"},
#    1269                 :            :         }},
#    1270                 :            :         {RPCResult::Type::STR, "signalling", /*optional=*/true, "indicates blocks that signalled with a # and blocks that did not with a -"},
#    1271                 :            :     }},
#    1272                 :            : };
#    1273                 :            : 
#    1274                 :            : UniValue DeploymentInfo(const CBlockIndex* blockindex, const Consensus::Params& consensusParams)
#    1275                 :         86 : {
#    1276                 :         86 :     UniValue softforks(UniValue::VOBJ);
#    1277                 :         86 :     SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_HEIGHTINCB);
#    1278                 :         86 :     SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_DERSIG);
#    1279                 :         86 :     SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_CLTV);
#    1280                 :         86 :     SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_CSV);
#    1281                 :         86 :     SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_SEGWIT);
#    1282                 :         86 :     SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_TESTDUMMY);
#    1283                 :         86 :     SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_TAPROOT);
#    1284                 :         86 :     return softforks;
#    1285                 :         86 : }
#    1286                 :            : } // anon namespace
#    1287                 :            : 
#    1288                 :            : static RPCHelpMan getdeploymentinfo()
#    1289                 :       1680 : {
#    1290                 :       1680 :     return RPCHelpMan{"getdeploymentinfo",
#    1291                 :       1680 :         "Returns an object containing various state info regarding deployments of consensus changes.",
#    1292                 :       1680 :         {
#    1293                 :       1680 :             {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Default{"hash of current chain tip"}, "The block hash at which to query deployment state"},
#    1294                 :       1680 :         },
#    1295                 :       1680 :         RPCResult{
#    1296                 :       1680 :             RPCResult::Type::OBJ, "", "", {
#    1297                 :       1680 :                 {RPCResult::Type::STR, "hash", "requested block hash (or tip)"},
#    1298                 :       1680 :                 {RPCResult::Type::NUM, "height", "requested block height (or tip)"},
#    1299                 :       1680 :                 {RPCResult::Type::OBJ_DYN, "deployments", "", {
#    1300                 :       1680 :                     {RPCResult::Type::OBJ, "xxxx", "name of the deployment", RPCHelpForDeployment}
#    1301                 :       1680 :                 }},
#    1302                 :       1680 :             }
#    1303                 :       1680 :         },
#    1304                 :       1680 :         RPCExamples{ HelpExampleCli("getdeploymentinfo", "") + HelpExampleRpc("getdeploymentinfo", "") },
#    1305                 :       1680 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#    1306                 :       1680 :         {
#    1307                 :         86 :             const ChainstateManager& chainman = EnsureAnyChainman(request.context);
#    1308                 :         86 :             LOCK(cs_main);
#    1309                 :         86 :             const CChainState& active_chainstate = chainman.ActiveChainstate();
#    1310                 :            : 
#    1311                 :         86 :             const CBlockIndex* blockindex;
#    1312         [ +  + ]:         86 :             if (request.params[0].isNull()) {
#    1313                 :         85 :                 blockindex = active_chainstate.m_chain.Tip();
#    1314         [ -  + ]:         85 :                 CHECK_NONFATAL(blockindex);
#    1315                 :         85 :             } else {
#    1316                 :          1 :                 const uint256 hash(ParseHashV(request.params[0], "blockhash"));
#    1317                 :          1 :                 blockindex = chainman.m_blockman.LookupBlockIndex(hash);
#    1318         [ -  + ]:          1 :                 if (!blockindex) {
#    1319                 :          0 :                     throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
#    1320                 :          0 :                 }
#    1321                 :          1 :             }
#    1322                 :            : 
#    1323                 :         86 :             const Consensus::Params& consensusParams = Params().GetConsensus();
#    1324                 :            : 
#    1325                 :         86 :             UniValue deploymentinfo(UniValue::VOBJ);
#    1326                 :         86 :             deploymentinfo.pushKV("hash", blockindex->GetBlockHash().ToString());
#    1327                 :         86 :             deploymentinfo.pushKV("height", blockindex->nHeight);
#    1328                 :         86 :             deploymentinfo.pushKV("deployments", DeploymentInfo(blockindex, consensusParams));
#    1329                 :         86 :             return deploymentinfo;
#    1330                 :         86 :         },
#    1331                 :       1680 :     };
#    1332                 :       1680 : }
#    1333                 :            : 
#    1334                 :            : /** Comparison function for sorting the getchaintips heads.  */
#    1335                 :            : struct CompareBlocksByHeight
#    1336                 :            : {
#    1337                 :            :     bool operator()(const CBlockIndex* a, const CBlockIndex* b) const
#    1338                 :        126 :     {
#    1339                 :            :         /* Make sure that unequal blocks with the same height do not compare
#    1340                 :            :            equal. Use the pointers themselves to make a distinction. */
#    1341                 :            : 
#    1342         [ +  + ]:        126 :         if (a->nHeight != b->nHeight)
#    1343                 :         59 :           return (a->nHeight > b->nHeight);
#    1344                 :            : 
#    1345                 :         67 :         return a < b;
#    1346                 :        126 :     }
#    1347                 :            : };
#    1348                 :            : 
#    1349                 :            : static RPCHelpMan getchaintips()
#    1350                 :       1620 : {
#    1351                 :       1620 :     return RPCHelpMan{"getchaintips",
#    1352                 :       1620 :                 "Return information about all known tips in the block tree,"
#    1353                 :       1620 :                 " including the main chain as well as orphaned branches.\n",
#    1354                 :       1620 :                 {},
#    1355                 :       1620 :                 RPCResult{
#    1356                 :       1620 :                     RPCResult::Type::ARR, "", "",
#    1357                 :       1620 :                     {{RPCResult::Type::OBJ, "", "",
#    1358                 :       1620 :                         {
#    1359                 :       1620 :                             {RPCResult::Type::NUM, "height", "height of the chain tip"},
#    1360                 :       1620 :                             {RPCResult::Type::STR_HEX, "hash", "block hash of the tip"},
#    1361                 :       1620 :                             {RPCResult::Type::NUM, "branchlen", "zero for main chain, otherwise length of branch connecting the tip to the main chain"},
#    1362                 :       1620 :                             {RPCResult::Type::STR, "status", "status of the chain, \"active\" for the main chain\n"
#    1363                 :       1620 :             "Possible values for status:\n"
#    1364                 :       1620 :             "1.  \"invalid\"               This branch contains at least one invalid block\n"
#    1365                 :       1620 :             "2.  \"headers-only\"          Not all blocks for this branch are available, but the headers are valid\n"
#    1366                 :       1620 :             "3.  \"valid-headers\"         All blocks are available for this branch, but they were never fully validated\n"
#    1367                 :       1620 :             "4.  \"valid-fork\"            This branch is not part of the active chain, but is fully validated\n"
#    1368                 :       1620 :             "5.  \"active\"                This is the tip of the active main chain, which is certainly valid"},
#    1369                 :       1620 :                         }}}},
#    1370                 :       1620 :                 RPCExamples{
#    1371                 :       1620 :                     HelpExampleCli("getchaintips", "")
#    1372                 :       1620 :             + HelpExampleRpc("getchaintips", "")
#    1373                 :       1620 :                 },
#    1374                 :       1620 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#    1375                 :       1620 : {
#    1376                 :         26 :     ChainstateManager& chainman = EnsureAnyChainman(request.context);
#    1377                 :         26 :     LOCK(cs_main);
#    1378                 :         26 :     CChain& active_chain = chainman.ActiveChain();
#    1379                 :            : 
#    1380                 :            :     /*
#    1381                 :            :      * Idea: The set of chain tips is the active chain tip, plus orphan blocks which do not have another orphan building off of them.
#    1382                 :            :      * Algorithm:
#    1383                 :            :      *  - Make one pass through BlockIndex(), picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers.
#    1384                 :            :      *  - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip.
#    1385                 :            :      *  - Add the active chain tip
#    1386                 :            :      */
#    1387                 :         26 :     std::set<const CBlockIndex*, CompareBlocksByHeight> setTips;
#    1388                 :         26 :     std::set<const CBlockIndex*> setOrphans;
#    1389                 :         26 :     std::set<const CBlockIndex*> setPrevs;
#    1390                 :            : 
#    1391         [ +  + ]:       5218 :     for (const auto& [_, block_index] : chainman.BlockIndex()) {
#    1392         [ +  + ]:       5218 :         if (!active_chain.Contains(&block_index)) {
#    1393                 :       1150 :             setOrphans.insert(&block_index);
#    1394                 :       1150 :             setPrevs.insert(block_index.pprev);
#    1395                 :       1150 :         }
#    1396                 :       5218 :     }
#    1397                 :            : 
#    1398         [ +  + ]:       1176 :     for (std::set<const CBlockIndex*>::iterator it = setOrphans.begin(); it != setOrphans.end(); ++it) {
#    1399         [ +  + ]:       1150 :         if (setPrevs.erase(*it) == 0) {
#    1400                 :         42 :             setTips.insert(*it);
#    1401                 :         42 :         }
#    1402                 :       1150 :     }
#    1403                 :            : 
#    1404                 :            :     // Always report the currently active tip.
#    1405                 :         26 :     setTips.insert(active_chain.Tip());
#    1406                 :            : 
#    1407                 :            :     /* Construct the output array.  */
#    1408                 :         26 :     UniValue res(UniValue::VARR);
#    1409         [ +  + ]:         68 :     for (const CBlockIndex* block : setTips) {
#    1410                 :         68 :         UniValue obj(UniValue::VOBJ);
#    1411                 :         68 :         obj.pushKV("height", block->nHeight);
#    1412                 :         68 :         obj.pushKV("hash", block->phashBlock->GetHex());
#    1413                 :            : 
#    1414                 :         68 :         const int branchLen = block->nHeight - active_chain.FindFork(block)->nHeight;
#    1415                 :         68 :         obj.pushKV("branchlen", branchLen);
#    1416                 :            : 
#    1417                 :         68 :         std::string status;
#    1418         [ +  + ]:         68 :         if (active_chain.Contains(block)) {
#    1419                 :            :             // This block is part of the currently active chain.
#    1420                 :         26 :             status = "active";
#    1421         [ +  + ]:         42 :         } else if (block->nStatus & BLOCK_FAILED_MASK) {
#    1422                 :            :             // This block or one of its ancestors is invalid.
#    1423                 :         17 :             status = "invalid";
#    1424         [ +  + ]:         25 :         } else if (!block->HaveTxsDownloaded()) {
#    1425                 :            :             // This block cannot be connected because full block data for it or one of its parents is missing.
#    1426                 :         23 :             status = "headers-only";
#    1427         [ +  - ]:         23 :         } else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {
#    1428                 :            :             // This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.
#    1429                 :          2 :             status = "valid-fork";
#    1430         [ #  # ]:          2 :         } else if (block->IsValid(BLOCK_VALID_TREE)) {
#    1431                 :            :             // The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.
#    1432                 :          0 :             status = "valid-headers";
#    1433                 :          0 :         } else {
#    1434                 :            :             // No clue.
#    1435                 :          0 :             status = "unknown";
#    1436                 :          0 :         }
#    1437                 :         68 :         obj.pushKV("status", status);
#    1438                 :            : 
#    1439                 :         68 :         res.push_back(obj);
#    1440                 :         68 :     }
#    1441                 :            : 
#    1442                 :         26 :     return res;
#    1443                 :         26 : },
#    1444                 :       1620 :     };
#    1445                 :       1620 : }
#    1446                 :            : 
#    1447                 :            : static RPCHelpMan preciousblock()
#    1448                 :       1603 : {
#    1449                 :       1603 :     return RPCHelpMan{"preciousblock",
#    1450                 :       1603 :                 "\nTreats a block as if it were received before others with the same work.\n"
#    1451                 :       1603 :                 "\nA later preciousblock call can override the effect of an earlier one.\n"
#    1452                 :       1603 :                 "\nThe effects of preciousblock are not retained across restarts.\n",
#    1453                 :       1603 :                 {
#    1454                 :       1603 :                     {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as precious"},
#    1455                 :       1603 :                 },
#    1456                 :       1603 :                 RPCResult{RPCResult::Type::NONE, "", ""},
#    1457                 :       1603 :                 RPCExamples{
#    1458                 :       1603 :                     HelpExampleCli("preciousblock", "\"blockhash\"")
#    1459                 :       1603 :             + HelpExampleRpc("preciousblock", "\"blockhash\"")
#    1460                 :       1603 :                 },
#    1461                 :       1603 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#    1462                 :       1603 : {
#    1463                 :          9 :     uint256 hash(ParseHashV(request.params[0], "blockhash"));
#    1464                 :          9 :     CBlockIndex* pblockindex;
#    1465                 :            : 
#    1466                 :          9 :     ChainstateManager& chainman = EnsureAnyChainman(request.context);
#    1467                 :          9 :     {
#    1468                 :          9 :         LOCK(cs_main);
#    1469                 :          9 :         pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
#    1470         [ -  + ]:          9 :         if (!pblockindex) {
#    1471                 :          0 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
#    1472                 :          0 :         }
#    1473                 :          9 :     }
#    1474                 :            : 
#    1475                 :          9 :     BlockValidationState state;
#    1476                 :          9 :     chainman.ActiveChainstate().PreciousBlock(state, pblockindex);
#    1477                 :            : 
#    1478         [ -  + ]:          9 :     if (!state.IsValid()) {
#    1479                 :          0 :         throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
#    1480                 :          0 :     }
#    1481                 :            : 
#    1482                 :          9 :     return NullUniValue;
#    1483                 :          9 : },
#    1484                 :       1603 :     };
#    1485                 :       1603 : }
#    1486                 :            : 
#    1487                 :            : static RPCHelpMan invalidateblock()
#    1488                 :       1653 : {
#    1489                 :       1653 :     return RPCHelpMan{"invalidateblock",
#    1490                 :       1653 :                 "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n",
#    1491                 :       1653 :                 {
#    1492                 :       1653 :                     {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as invalid"},
#    1493                 :       1653 :                 },
#    1494                 :       1653 :                 RPCResult{RPCResult::Type::NONE, "", ""},
#    1495                 :       1653 :                 RPCExamples{
#    1496                 :       1653 :                     HelpExampleCli("invalidateblock", "\"blockhash\"")
#    1497                 :       1653 :             + HelpExampleRpc("invalidateblock", "\"blockhash\"")
#    1498                 :       1653 :                 },
#    1499                 :       1653 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#    1500                 :       1653 : {
#    1501                 :         64 :     uint256 hash(ParseHashV(request.params[0], "blockhash"));
#    1502                 :         64 :     BlockValidationState state;
#    1503                 :            : 
#    1504                 :         64 :     ChainstateManager& chainman = EnsureAnyChainman(request.context);
#    1505                 :         64 :     CBlockIndex* pblockindex;
#    1506                 :         64 :     {
#    1507                 :         64 :         LOCK(cs_main);
#    1508                 :         64 :         pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
#    1509         [ -  + ]:         64 :         if (!pblockindex) {
#    1510                 :          0 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
#    1511                 :          0 :         }
#    1512                 :         64 :     }
#    1513                 :         64 :     chainman.ActiveChainstate().InvalidateBlock(state, pblockindex);
#    1514                 :            : 
#    1515         [ +  - ]:         64 :     if (state.IsValid()) {
#    1516                 :         64 :         chainman.ActiveChainstate().ActivateBestChain(state);
#    1517                 :         64 :     }
#    1518                 :            : 
#    1519         [ -  + ]:         64 :     if (!state.IsValid()) {
#    1520                 :          0 :         throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
#    1521                 :          0 :     }
#    1522                 :            : 
#    1523                 :         64 :     return NullUniValue;
#    1524                 :         64 : },
#    1525                 :       1653 :     };
#    1526                 :       1653 : }
#    1527                 :            : 
#    1528                 :            : static RPCHelpMan reconsiderblock()
#    1529                 :       1600 : {
#    1530                 :       1600 :     return RPCHelpMan{"reconsiderblock",
#    1531                 :       1600 :                 "\nRemoves invalidity status of a block, its ancestors and its descendants, reconsider them for activation.\n"
#    1532                 :       1600 :                 "This can be used to undo the effects of invalidateblock.\n",
#    1533                 :       1600 :                 {
#    1534                 :       1600 :                     {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to reconsider"},
#    1535                 :       1600 :                 },
#    1536                 :       1600 :                 RPCResult{RPCResult::Type::NONE, "", ""},
#    1537                 :       1600 :                 RPCExamples{
#    1538                 :       1600 :                     HelpExampleCli("reconsiderblock", "\"blockhash\"")
#    1539                 :       1600 :             + HelpExampleRpc("reconsiderblock", "\"blockhash\"")
#    1540                 :       1600 :                 },
#    1541                 :       1600 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#    1542                 :       1600 : {
#    1543                 :         11 :     ChainstateManager& chainman = EnsureAnyChainman(request.context);
#    1544                 :         11 :     uint256 hash(ParseHashV(request.params[0], "blockhash"));
#    1545                 :            : 
#    1546                 :         11 :     {
#    1547                 :         11 :         LOCK(cs_main);
#    1548                 :         11 :         CBlockIndex* pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
#    1549         [ -  + ]:         11 :         if (!pblockindex) {
#    1550                 :          0 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
#    1551                 :          0 :         }
#    1552                 :            : 
#    1553                 :         11 :         chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex);
#    1554                 :         11 :     }
#    1555                 :            : 
#    1556                 :          0 :     BlockValidationState state;
#    1557                 :         11 :     chainman.ActiveChainstate().ActivateBestChain(state);
#    1558                 :            : 
#    1559         [ -  + ]:         11 :     if (!state.IsValid()) {
#    1560                 :          0 :         throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
#    1561                 :          0 :     }
#    1562                 :            : 
#    1563                 :         11 :     return NullUniValue;
#    1564                 :         11 : },
#    1565                 :       1600 :     };
#    1566                 :       1600 : }
#    1567                 :            : 
#    1568                 :            : static RPCHelpMan getchaintxstats()
#    1569                 :       1606 : {
#    1570                 :       1606 :     return RPCHelpMan{"getchaintxstats",
#    1571                 :       1606 :                 "\nCompute statistics about the total number and rate of transactions in the chain.\n",
#    1572                 :       1606 :                 {
#    1573                 :       1606 :                     {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{"one month"}, "Size of the window in number of blocks"},
#    1574                 :       1606 :                     {"blockhash", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"chain tip"}, "The hash of the block that ends the window."},
#    1575                 :       1606 :                 },
#    1576                 :       1606 :                 RPCResult{
#    1577                 :       1606 :                     RPCResult::Type::OBJ, "", "",
#    1578                 :       1606 :                     {
#    1579                 :       1606 :                         {RPCResult::Type::NUM_TIME, "time", "The timestamp for the final block in the window, expressed in " + UNIX_EPOCH_TIME},
#    1580                 :       1606 :                         {RPCResult::Type::NUM, "txcount", "The total number of transactions in the chain up to that point"},
#    1581                 :       1606 :                         {RPCResult::Type::STR_HEX, "window_final_block_hash", "The hash of the final block in the window"},
#    1582                 :       1606 :                         {RPCResult::Type::NUM, "window_final_block_height", "The height of the final block in the window."},
#    1583                 :       1606 :                         {RPCResult::Type::NUM, "window_block_count", "Size of the window in number of blocks"},
#    1584                 :       1606 :                         {RPCResult::Type::NUM, "window_tx_count", /*optional=*/true, "The number of transactions in the window. Only returned if \"window_block_count\" is > 0"},
#    1585                 :       1606 :                         {RPCResult::Type::NUM, "window_interval", /*optional=*/true, "The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0"},
#    1586                 :       1606 :                         {RPCResult::Type::NUM, "txrate", /*optional=*/true, "The average rate of transactions per second in the window. Only returned if \"window_interval\" is > 0"},
#    1587                 :       1606 :                     }},
#    1588                 :       1606 :                 RPCExamples{
#    1589                 :       1606 :                     HelpExampleCli("getchaintxstats", "")
#    1590                 :       1606 :             + HelpExampleRpc("getchaintxstats", "2016")
#    1591                 :       1606 :                 },
#    1592                 :       1606 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#    1593                 :       1606 : {
#    1594                 :         11 :     ChainstateManager& chainman = EnsureAnyChainman(request.context);
#    1595                 :         11 :     const CBlockIndex* pindex;
#    1596                 :         11 :     int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month
#    1597                 :            : 
#    1598         [ +  + ]:         11 :     if (request.params[1].isNull()) {
#    1599                 :          5 :         LOCK(cs_main);
#    1600                 :          5 :         pindex = chainman.ActiveChain().Tip();
#    1601                 :          6 :     } else {
#    1602                 :          6 :         uint256 hash(ParseHashV(request.params[1], "blockhash"));
#    1603                 :          6 :         LOCK(cs_main);
#    1604                 :          6 :         pindex = chainman.m_blockman.LookupBlockIndex(hash);
#    1605         [ +  + ]:          6 :         if (!pindex) {
#    1606                 :          1 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
#    1607                 :          1 :         }
#    1608         [ +  + ]:          5 :         if (!chainman.ActiveChain().Contains(pindex)) {
#    1609                 :          1 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain");
#    1610                 :          1 :         }
#    1611                 :          5 :     }
#    1612                 :            : 
#    1613         [ -  + ]:          9 :     CHECK_NONFATAL(pindex != nullptr);
#    1614                 :            : 
#    1615         [ +  + ]:          9 :     if (request.params[0].isNull()) {
#    1616                 :          2 :         blockcount = std::max(0, std::min(blockcount, pindex->nHeight - 1));
#    1617                 :          7 :     } else {
#    1618                 :          7 :         blockcount = request.params[0].get_int();
#    1619                 :            : 
#    1620 [ +  + ][ +  - ]:          7 :         if (blockcount < 0 || (blockcount > 0 && blockcount >= pindex->nHeight)) {
#                 [ +  + ]
#    1621                 :          2 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 0 and the block's height - 1");
#    1622                 :          2 :         }
#    1623                 :          7 :     }
#    1624                 :            : 
#    1625                 :          7 :     const CBlockIndex* pindexPast = pindex->GetAncestor(pindex->nHeight - blockcount);
#    1626                 :          7 :     int nTimeDiff = pindex->GetMedianTimePast() - pindexPast->GetMedianTimePast();
#    1627                 :          7 :     int nTxDiff = pindex->nChainTx - pindexPast->nChainTx;
#    1628                 :            : 
#    1629                 :          7 :     UniValue ret(UniValue::VOBJ);
#    1630                 :          7 :     ret.pushKV("time", (int64_t)pindex->nTime);
#    1631                 :          7 :     ret.pushKV("txcount", (int64_t)pindex->nChainTx);
#    1632                 :          7 :     ret.pushKV("window_final_block_hash", pindex->GetBlockHash().GetHex());
#    1633                 :          7 :     ret.pushKV("window_final_block_height", pindex->nHeight);
#    1634                 :          7 :     ret.pushKV("window_block_count", blockcount);
#    1635         [ +  + ]:          7 :     if (blockcount > 0) {
#    1636                 :          2 :         ret.pushKV("window_tx_count", nTxDiff);
#    1637                 :          2 :         ret.pushKV("window_interval", nTimeDiff);
#    1638         [ +  - ]:          2 :         if (nTimeDiff > 0) {
#    1639                 :          2 :             ret.pushKV("txrate", ((double)nTxDiff) / nTimeDiff);
#    1640                 :          2 :         }
#    1641                 :          2 :     }
#    1642                 :            : 
#    1643                 :          7 :     return ret;
#    1644                 :          9 : },
#    1645                 :       1606 :     };
#    1646                 :       1606 : }
#    1647                 :            : 
#    1648                 :            : template<typename T>
#    1649                 :            : static T CalculateTruncatedMedian(std::vector<T>& scores)
#    1650                 :        198 : {
#    1651                 :        198 :     size_t size = scores.size();
#    1652         [ +  + ]:        198 :     if (size == 0) {
#    1653                 :        186 :         return 0;
#    1654                 :        186 :     }
#    1655                 :            : 
#    1656                 :         12 :     std::sort(scores.begin(), scores.end());
#    1657         [ -  + ]:         12 :     if (size % 2 == 0) {
#    1658                 :          0 :         return (scores[size / 2 - 1] + scores[size / 2]) / 2;
#    1659                 :         12 :     } else {
#    1660                 :         12 :         return scores[size / 2];
#    1661                 :         12 :     }
#    1662                 :         12 : }
#    1663                 :            : 
#    1664                 :            : void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight)
#    1665                 :        107 : {
#    1666         [ +  + ]:        107 :     if (scores.empty()) {
#    1667                 :         93 :         return;
#    1668                 :         93 :     }
#    1669                 :            : 
#    1670                 :         14 :     std::sort(scores.begin(), scores.end());
#    1671                 :            : 
#    1672                 :            :     // 10th, 25th, 50th, 75th, and 90th percentile weight units.
#    1673                 :         14 :     const double weights[NUM_GETBLOCKSTATS_PERCENTILES] = {
#    1674                 :         14 :         total_weight / 10.0, total_weight / 4.0, total_weight / 2.0, (total_weight * 3.0) / 4.0, (total_weight * 9.0) / 10.0
#    1675                 :         14 :     };
#    1676                 :            : 
#    1677                 :         14 :     int64_t next_percentile_index = 0;
#    1678                 :         14 :     int64_t cumulative_weight = 0;
#    1679         [ +  + ]:        444 :     for (const auto& element : scores) {
#    1680                 :        444 :         cumulative_weight += element.second;
#    1681 [ +  + ][ +  + ]:        514 :         while (next_percentile_index < NUM_GETBLOCKSTATS_PERCENTILES && cumulative_weight >= weights[next_percentile_index]) {
#    1682                 :         70 :             result[next_percentile_index] = element.first;
#    1683                 :         70 :             ++next_percentile_index;
#    1684                 :         70 :         }
#    1685                 :        444 :     }
#    1686                 :            : 
#    1687                 :            :     // Fill any remaining percentiles with the last value.
#    1688         [ -  + ]:         14 :     for (int64_t i = next_percentile_index; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {
#    1689                 :          0 :         result[i] = scores.back().first;
#    1690                 :          0 :     }
#    1691                 :         14 : }
#    1692                 :            : 
#    1693                 :            : template<typename T>
#    1694                 :        292 : static inline bool SetHasKeys(const std::set<T>& set) {return false;}
#    1695                 :            : template<typename T, typename Tk, typename... Args>
#    1696                 :            : static inline bool SetHasKeys(const std::set<T>& set, const Tk& key, const Args&... args)
#    1697                 :       1884 : {
#    1698 [ +  + ][ +  + ]:       1884 :     return (set.count(key) != 0) || SetHasKeys(set, args...);
#         [ +  + ][ +  + ]
#         [ +  + ][ +  + ]
#         [ +  + ][ +  + ]
#         [ +  + ][ +  + ]
#         [ +  + ][ +  + ]
#         [ +  + ][ +  + ]
#         [ +  + ][ +  + ]
#         [ -  + ][ +  + ]
#         [ +  + ][ +  + ]
#         [ +  + ][ +  + ]
#         [ +  + ][ +  + ]
#         [ -  + ][ +  + ]
#         [ +  + ][ -  + ]
#         [ +  + ][ +  + ]
#         [ +  + ][ +  + ]
#         [ +  + ][ -  + ]
#         [ +  + ][ +  + ]
#         [ +  + ][ +  + ]
#         [ +  + ][ +  + ]
#         [ +  + ][ +  + ]
#    1699                 :       1884 : }
#    1700                 :            : 
#    1701                 :            : // outpoint (needed for the utxo index) + nHeight + fCoinBase
#    1702                 :            : static constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);
#    1703                 :            : 
#    1704                 :            : static RPCHelpMan getblockstats()
#    1705                 :       1698 : {
#    1706                 :       1698 :     return RPCHelpMan{"getblockstats",
#    1707                 :       1698 :                 "\nCompute per block statistics for a given window. All amounts are in satoshis.\n"
#    1708                 :       1698 :                 "It won't work for some heights with pruning.\n",
#    1709                 :       1698 :                 {
#    1710                 :       1698 :                     {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block", "", {"", "string or numeric"}},
#    1711                 :       1698 :                     {"stats", RPCArg::Type::ARR, RPCArg::DefaultHint{"all values"}, "Values to plot (see result below)",
#    1712                 :       1698 :                         {
#    1713                 :       1698 :                             {"height", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
#    1714                 :       1698 :                             {"time", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
#    1715                 :       1698 :                         },
#    1716                 :       1698 :                         "stats"},
#    1717                 :       1698 :                 },
#    1718                 :       1698 :                 RPCResult{
#    1719                 :       1698 :             RPCResult::Type::OBJ, "", "",
#    1720                 :       1698 :             {
#    1721                 :       1698 :                 {RPCResult::Type::NUM, "avgfee", /*optional=*/true, "Average fee in the block"},
#    1722                 :       1698 :                 {RPCResult::Type::NUM, "avgfeerate", /*optional=*/true, "Average feerate (in satoshis per virtual byte)"},
#    1723                 :       1698 :                 {RPCResult::Type::NUM, "avgtxsize", /*optional=*/true, "Average transaction size"},
#    1724                 :       1698 :                 {RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "The block hash (to check for potential reorgs)"},
#    1725                 :       1698 :                 {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)",
#    1726                 :       1698 :                 {
#    1727                 :       1698 :                     {RPCResult::Type::NUM, "10th_percentile_feerate", "The 10th percentile feerate"},
#    1728                 :       1698 :                     {RPCResult::Type::NUM, "25th_percentile_feerate", "The 25th percentile feerate"},
#    1729                 :       1698 :                     {RPCResult::Type::NUM, "50th_percentile_feerate", "The 50th percentile feerate"},
#    1730                 :       1698 :                     {RPCResult::Type::NUM, "75th_percentile_feerate", "The 75th percentile feerate"},
#    1731                 :       1698 :                     {RPCResult::Type::NUM, "90th_percentile_feerate", "The 90th percentile feerate"},
#    1732                 :       1698 :                 }},
#    1733                 :       1698 :                 {RPCResult::Type::NUM, "height", /*optional=*/true, "The height of the block"},
#    1734                 :       1698 :                 {RPCResult::Type::NUM, "ins", /*optional=*/true, "The number of inputs (excluding coinbase)"},
#    1735                 :       1698 :                 {RPCResult::Type::NUM, "maxfee", /*optional=*/true, "Maximum fee in the block"},
#    1736                 :       1698 :                 {RPCResult::Type::NUM, "maxfeerate", /*optional=*/true, "Maximum feerate (in satoshis per virtual byte)"},
#    1737                 :       1698 :                 {RPCResult::Type::NUM, "maxtxsize", /*optional=*/true, "Maximum transaction size"},
#    1738                 :       1698 :                 {RPCResult::Type::NUM, "medianfee", /*optional=*/true, "Truncated median fee in the block"},
#    1739                 :       1698 :                 {RPCResult::Type::NUM, "mediantime", /*optional=*/true, "The block median time past"},
#    1740                 :       1698 :                 {RPCResult::Type::NUM, "mediantxsize", /*optional=*/true, "Truncated median transaction size"},
#    1741                 :       1698 :                 {RPCResult::Type::NUM, "minfee", /*optional=*/true, "Minimum fee in the block"},
#    1742                 :       1698 :                 {RPCResult::Type::NUM, "minfeerate", /*optional=*/true, "Minimum feerate (in satoshis per virtual byte)"},
#    1743                 :       1698 :                 {RPCResult::Type::NUM, "mintxsize", /*optional=*/true, "Minimum transaction size"},
#    1744                 :       1698 :                 {RPCResult::Type::NUM, "outs", /*optional=*/true, "The number of outputs"},
#    1745                 :       1698 :                 {RPCResult::Type::NUM, "subsidy", /*optional=*/true, "The block subsidy"},
#    1746                 :       1698 :                 {RPCResult::Type::NUM, "swtotal_size", /*optional=*/true, "Total size of all segwit transactions"},
#    1747                 :       1698 :                 {RPCResult::Type::NUM, "swtotal_weight", /*optional=*/true, "Total weight of all segwit transactions"},
#    1748                 :       1698 :                 {RPCResult::Type::NUM, "swtxs", /*optional=*/true, "The number of segwit transactions"},
#    1749                 :       1698 :                 {RPCResult::Type::NUM, "time", /*optional=*/true, "The block time"},
#    1750                 :       1698 :                 {RPCResult::Type::NUM, "total_out", /*optional=*/true, "Total amount in all outputs (excluding coinbase and thus reward [ie subsidy + totalfee])"},
#    1751                 :       1698 :                 {RPCResult::Type::NUM, "total_size", /*optional=*/true, "Total size of all non-coinbase transactions"},
#    1752                 :       1698 :                 {RPCResult::Type::NUM, "total_weight", /*optional=*/true, "Total weight of all non-coinbase transactions"},
#    1753                 :       1698 :                 {RPCResult::Type::NUM, "totalfee", /*optional=*/true, "The fee total"},
#    1754                 :       1698 :                 {RPCResult::Type::NUM, "txs", /*optional=*/true, "The number of transactions (including coinbase)"},
#    1755                 :       1698 :                 {RPCResult::Type::NUM, "utxo_increase", /*optional=*/true, "The increase/decrease in the number of unspent outputs"},
#    1756                 :       1698 :                 {RPCResult::Type::NUM, "utxo_size_inc", /*optional=*/true, "The increase/decrease in size for the utxo index (not discounting op_return and similar)"},
#    1757                 :       1698 :             }},
#    1758                 :       1698 :                 RPCExamples{
#    1759                 :       1698 :                     HelpExampleCli("getblockstats", R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
#    1760                 :       1698 :                     HelpExampleCli("getblockstats", R"(1000 '["minfeerate","avgfeerate"]')") +
#    1761                 :       1698 :                     HelpExampleRpc("getblockstats", R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") +
#    1762                 :       1698 :                     HelpExampleRpc("getblockstats", R"(1000, ["minfeerate","avgfeerate"])")
#    1763                 :       1698 :                 },
#    1764                 :       1698 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#    1765                 :       1698 : {
#    1766                 :        102 :     ChainstateManager& chainman = EnsureAnyChainman(request.context);
#    1767                 :        102 :     LOCK(cs_main);
#    1768                 :        102 :     const CBlockIndex* pindex{ParseHashOrHeight(request.params[0], chainman)};
#    1769         [ -  + ]:        102 :     CHECK_NONFATAL(pindex != nullptr);
#    1770                 :            : 
#    1771                 :        102 :     std::set<std::string> stats;
#    1772         [ +  + ]:        102 :     if (!request.params[1].isNull()) {
#    1773                 :         93 :         const UniValue stats_univalue = request.params[1].get_array();
#    1774         [ +  + ]:        192 :         for (unsigned int i = 0; i < stats_univalue.size(); i++) {
#    1775                 :         99 :             const std::string stat = stats_univalue[i].get_str();
#    1776                 :         99 :             stats.insert(stat);
#    1777                 :         99 :         }
#    1778                 :         93 :     }
#    1779                 :            : 
#    1780                 :        102 :     const CBlock block = GetBlockChecked(pindex);
#    1781                 :        102 :     const CBlockUndo blockUndo = GetUndoChecked(pindex);
#    1782                 :            : 
#    1783                 :        102 :     const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default)
#    1784 [ +  + ][ +  + ]:        102 :     const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0;
#    1785 [ +  + ][ +  + ]:        102 :     const bool do_medianfee = do_all || stats.count("medianfee") != 0;
#    1786 [ +  + ][ +  + ]:        102 :     const bool do_feerate_percentiles = do_all || stats.count("feerate_percentiles") != 0;
#    1787 [ +  + ][ +  + ]:        102 :     const bool loop_inputs = do_all || do_medianfee || do_feerate_percentiles ||
#                 [ +  + ]
#    1788         [ +  + ]:        102 :         SetHasKeys(stats, "utxo_size_inc", "totalfee", "avgfee", "avgfeerate", "minfee", "maxfee", "minfeerate", "maxfeerate");
#    1789 [ +  + ][ +  + ]:        102 :     const bool loop_outputs = do_all || loop_inputs || stats.count("total_out");
#                 [ +  + ]
#    1790         [ +  + ]:        102 :     const bool do_calculate_size = do_mediantxsize ||
#    1791         [ +  + ]:        102 :         SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize", "maxtxsize", "swtotal_size");
#    1792 [ +  + ][ +  + ]:        102 :     const bool do_calculate_weight = do_all || SetHasKeys(stats, "total_weight", "avgfeerate", "swtotal_weight", "avgfeerate", "feerate_percentiles", "minfeerate", "maxfeerate");
#    1793 [ +  + ][ +  + ]:        102 :     const bool do_calculate_sw = do_all || SetHasKeys(stats, "swtxs", "swtotal_size", "swtotal_weight");
#    1794                 :            : 
#    1795                 :        102 :     CAmount maxfee = 0;
#    1796                 :        102 :     CAmount maxfeerate = 0;
#    1797                 :        102 :     CAmount minfee = MAX_MONEY;
#    1798                 :        102 :     CAmount minfeerate = MAX_MONEY;
#    1799                 :        102 :     CAmount total_out = 0;
#    1800                 :        102 :     CAmount totalfee = 0;
#    1801                 :        102 :     int64_t inputs = 0;
#    1802                 :        102 :     int64_t maxtxsize = 0;
#    1803                 :        102 :     int64_t mintxsize = MAX_BLOCK_SERIALIZED_SIZE;
#    1804                 :        102 :     int64_t outputs = 0;
#    1805                 :        102 :     int64_t swtotal_size = 0;
#    1806                 :        102 :     int64_t swtotal_weight = 0;
#    1807                 :        102 :     int64_t swtxs = 0;
#    1808                 :        102 :     int64_t total_size = 0;
#    1809                 :        102 :     int64_t total_weight = 0;
#    1810                 :        102 :     int64_t utxo_size_inc = 0;
#    1811                 :        102 :     std::vector<CAmount> fee_array;
#    1812                 :        102 :     std::vector<std::pair<CAmount, int64_t>> feerate_array;
#    1813                 :        102 :     std::vector<int64_t> txsize_array;
#    1814                 :            : 
#    1815         [ +  + ]:        325 :     for (size_t i = 0; i < block.vtx.size(); ++i) {
#    1816                 :        223 :         const auto& tx = block.vtx.at(i);
#    1817                 :        223 :         outputs += tx->vout.size();
#    1818                 :            : 
#    1819                 :        223 :         CAmount tx_total_out = 0;
#    1820         [ +  + ]:        223 :         if (loop_outputs) {
#    1821         [ +  + ]:        192 :             for (const CTxOut& out : tx->vout) {
#    1822                 :        192 :                 tx_total_out += out.nValue;
#    1823                 :        192 :                 utxo_size_inc += GetSerializeSize(out, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD;
#    1824                 :        192 :             }
#    1825                 :         96 :         }
#    1826                 :            : 
#    1827         [ +  + ]:        223 :         if (tx->IsCoinBase()) {
#    1828                 :         99 :             continue;
#    1829                 :         99 :         }
#    1830                 :            : 
#    1831                 :        124 :         inputs += tx->vin.size(); // Don't count coinbase's fake input
#    1832                 :        124 :         total_out += tx_total_out; // Don't count coinbase reward
#    1833                 :            : 
#    1834                 :        124 :         int64_t tx_size = 0;
#    1835         [ +  + ]:        124 :         if (do_calculate_size) {
#    1836                 :            : 
#    1837                 :         32 :             tx_size = tx->GetTotalSize();
#    1838         [ +  + ]:         32 :             if (do_mediantxsize) {
#    1839                 :         12 :                 txsize_array.push_back(tx_size);
#    1840                 :         12 :             }
#    1841                 :         32 :             maxtxsize = std::max(maxtxsize, tx_size);
#    1842                 :         32 :             mintxsize = std::min(mintxsize, tx_size);
#    1843                 :         32 :             total_size += tx_size;
#    1844                 :         32 :         }
#    1845                 :            : 
#    1846                 :        124 :         int64_t weight = 0;
#    1847         [ +  + ]:        124 :         if (do_calculate_weight) {
#    1848                 :         32 :             weight = GetTransactionWeight(*tx);
#    1849                 :         32 :             total_weight += weight;
#    1850                 :         32 :         }
#    1851                 :            : 
#    1852 [ +  + ][ +  + ]:        124 :         if (do_calculate_sw && tx->HasWitness()) {
#    1853                 :          5 :             ++swtxs;
#    1854                 :          5 :             swtotal_size += tx_size;
#    1855                 :          5 :             swtotal_weight += weight;
#    1856                 :          5 :         }
#    1857                 :            : 
#    1858         [ +  + ]:        124 :         if (loop_inputs) {
#    1859                 :         48 :             CAmount tx_total_in = 0;
#    1860                 :         48 :             const auto& txundo = blockUndo.vtxundo.at(i - 1);
#    1861         [ +  + ]:         48 :             for (const Coin& coin: txundo.vprevout) {
#    1862                 :         48 :                 const CTxOut& prevoutput = coin.out;
#    1863                 :            : 
#    1864                 :         48 :                 tx_total_in += prevoutput.nValue;
#    1865                 :         48 :                 utxo_size_inc -= GetSerializeSize(prevoutput, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD;
#    1866                 :         48 :             }
#    1867                 :            : 
#    1868                 :         48 :             CAmount txfee = tx_total_in - tx_total_out;
#    1869         [ -  + ]:         48 :             CHECK_NONFATAL(MoneyRange(txfee));
#    1870         [ +  + ]:         48 :             if (do_medianfee) {
#    1871                 :         12 :                 fee_array.push_back(txfee);
#    1872                 :         12 :             }
#    1873                 :         48 :             maxfee = std::max(maxfee, txfee);
#    1874                 :         48 :             minfee = std::min(minfee, txfee);
#    1875                 :         48 :             totalfee += txfee;
#    1876                 :            : 
#    1877                 :            :             // New feerate uses satoshis per virtual byte instead of per serialized byte
#    1878         [ +  + ]:         48 :             CAmount feerate = weight ? (txfee * WITNESS_SCALE_FACTOR) / weight : 0;
#    1879         [ +  + ]:         48 :             if (do_feerate_percentiles) {
#    1880                 :         12 :                 feerate_array.emplace_back(std::make_pair(feerate, weight));
#    1881                 :         12 :             }
#    1882                 :         48 :             maxfeerate = std::max(maxfeerate, feerate);
#    1883                 :         48 :             minfeerate = std::min(minfeerate, feerate);
#    1884                 :         48 :         }
#    1885                 :        124 :     }
#    1886                 :            : 
#    1887                 :        102 :     CAmount feerate_percentiles[NUM_GETBLOCKSTATS_PERCENTILES] = { 0 };
#    1888                 :        102 :     CalculatePercentilesByWeight(feerate_percentiles, feerate_array, total_weight);
#    1889                 :            : 
#    1890                 :        102 :     UniValue feerates_res(UniValue::VARR);
#    1891         [ +  + ]:        597 :     for (int64_t i = 0; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {
#    1892                 :        495 :         feerates_res.push_back(feerate_percentiles[i]);
#    1893                 :        495 :     }
#    1894                 :            : 
#    1895                 :        102 :     UniValue ret_all(UniValue::VOBJ);
#    1896         [ +  + ]:        102 :     ret_all.pushKV("avgfee", (block.vtx.size() > 1) ? totalfee / (block.vtx.size() - 1) : 0);
#    1897         [ +  + ]:        102 :     ret_all.pushKV("avgfeerate", total_weight ? (totalfee * WITNESS_SCALE_FACTOR) / total_weight : 0); // Unit: sat/vbyte
#    1898         [ +  + ]:        102 :     ret_all.pushKV("avgtxsize", (block.vtx.size() > 1) ? total_size / (block.vtx.size() - 1) : 0);
#    1899                 :        102 :     ret_all.pushKV("blockhash", pindex->GetBlockHash().GetHex());
#    1900                 :        102 :     ret_all.pushKV("feerate_percentiles", feerates_res);
#    1901                 :        102 :     ret_all.pushKV("height", (int64_t)pindex->nHeight);
#    1902                 :        102 :     ret_all.pushKV("ins", inputs);
#    1903                 :        102 :     ret_all.pushKV("maxfee", maxfee);
#    1904                 :        102 :     ret_all.pushKV("maxfeerate", maxfeerate);
#    1905                 :        102 :     ret_all.pushKV("maxtxsize", maxtxsize);
#    1906                 :        102 :     ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
#    1907                 :        102 :     ret_all.pushKV("mediantime", pindex->GetMedianTimePast());
#    1908                 :        102 :     ret_all.pushKV("mediantxsize", CalculateTruncatedMedian(txsize_array));
#    1909         [ +  + ]:        102 :     ret_all.pushKV("minfee", (minfee == MAX_MONEY) ? 0 : minfee);
#    1910         [ +  + ]:        102 :     ret_all.pushKV("minfeerate", (minfeerate == MAX_MONEY) ? 0 : minfeerate);
#    1911         [ +  + ]:        102 :     ret_all.pushKV("mintxsize", mintxsize == MAX_BLOCK_SERIALIZED_SIZE ? 0 : mintxsize);
#    1912                 :        102 :     ret_all.pushKV("outs", outputs);
#    1913                 :        102 :     ret_all.pushKV("subsidy", GetBlockSubsidy(pindex->nHeight, Params().GetConsensus()));
#    1914                 :        102 :     ret_all.pushKV("swtotal_size", swtotal_size);
#    1915                 :        102 :     ret_all.pushKV("swtotal_weight", swtotal_weight);
#    1916                 :        102 :     ret_all.pushKV("swtxs", swtxs);
#    1917                 :        102 :     ret_all.pushKV("time", pindex->GetBlockTime());
#    1918                 :        102 :     ret_all.pushKV("total_out", total_out);
#    1919                 :        102 :     ret_all.pushKV("total_size", total_size);
#    1920                 :        102 :     ret_all.pushKV("total_weight", total_weight);
#    1921                 :        102 :     ret_all.pushKV("totalfee", totalfee);
#    1922                 :        102 :     ret_all.pushKV("txs", (int64_t)block.vtx.size());
#    1923                 :        102 :     ret_all.pushKV("utxo_increase", outputs - inputs);
#    1924                 :        102 :     ret_all.pushKV("utxo_size_inc", utxo_size_inc);
#    1925                 :            : 
#    1926         [ +  + ]:        102 :     if (do_all) {
#    1927                 :          6 :         return ret_all;
#    1928                 :          6 :     }
#    1929                 :            : 
#    1930                 :         96 :     UniValue ret(UniValue::VOBJ);
#    1931         [ +  + ]:         96 :     for (const std::string& stat : stats) {
#    1932                 :         94 :         const UniValue& value = ret_all[stat];
#    1933         [ +  + ]:         94 :         if (value.isNull()) {
#    1934                 :          5 :             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid selected statistic '%s'", stat));
#    1935                 :          5 :         }
#    1936                 :         89 :         ret.pushKV(stat, value);
#    1937                 :         89 :     }
#    1938                 :         91 :     return ret;
#    1939                 :         96 : },
#    1940                 :       1698 :     };
#    1941                 :       1698 : }
#    1942                 :            : 
#    1943                 :            : namespace {
#    1944                 :            : //! Search for a given set of pubkey scripts
#    1945                 :            : 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)
#    1946                 :         53 : {
#    1947                 :         53 :     scan_progress = 0;
#    1948                 :         53 :     count = 0;
#    1949         [ +  + ]:      11033 :     while (cursor->Valid()) {
#    1950                 :      10980 :         COutPoint key;
#    1951                 :      10980 :         Coin coin;
#    1952 [ -  + ][ -  + ]:      10980 :         if (!cursor->GetKey(key) || !cursor->GetValue(coin)) return false;
#    1953         [ -  + ]:      10980 :         if (++count % 8192 == 0) {
#    1954                 :          0 :             interruption_point();
#    1955         [ #  # ]:          0 :             if (should_abort) {
#    1956                 :            :                 // allow to abort the scan via the abort reference
#    1957                 :          0 :                 return false;
#    1958                 :          0 :             }
#    1959                 :          0 :         }
#    1960         [ -  + ]:      10980 :         if (count % 256 == 0) {
#    1961                 :            :             // update progress reference every 256 item
#    1962                 :          0 :             uint32_t high = 0x100 * *key.hash.begin() + *(key.hash.begin() + 1);
#    1963                 :          0 :             scan_progress = (int)(high * 100.0 / 65536.0 + 0.5);
#    1964                 :          0 :         }
#    1965         [ +  + ]:      10980 :         if (needles.count(coin.out.scriptPubKey)) {
#    1966                 :        795 :             out_results.emplace(key, coin);
#    1967                 :        795 :         }
#    1968                 :      10980 :         cursor->Next();
#    1969                 :      10980 :     }
#    1970                 :         53 :     scan_progress = 100;
#    1971                 :         53 :     return true;
#    1972                 :         53 : }
#    1973                 :            : } // namespace
#    1974                 :            : 
#    1975                 :            : /** RAII object to prevent concurrency issue when scanning the txout set */
#    1976                 :            : static std::atomic<int> g_scan_progress;
#    1977                 :            : static std::atomic<bool> g_scan_in_progress;
#    1978                 :            : static std::atomic<bool> g_should_abort_scan;
#    1979                 :            : class CoinsViewScanReserver
#    1980                 :            : {
#    1981                 :            : private:
#    1982                 :            :     bool m_could_reserve;
#    1983                 :            : public:
#    1984                 :         61 :     explicit CoinsViewScanReserver() : m_could_reserve(false) {}
#    1985                 :            : 
#    1986                 :         61 :     bool reserve() {
#    1987         [ -  + ]:         61 :         CHECK_NONFATAL(!m_could_reserve);
#    1988         [ -  + ]:         61 :         if (g_scan_in_progress.exchange(true)) {
#    1989                 :          0 :             return false;
#    1990                 :          0 :         }
#    1991         [ -  + ]:         61 :         CHECK_NONFATAL(g_scan_progress == 0);
#    1992                 :         61 :         m_could_reserve = true;
#    1993                 :         61 :         return true;
#    1994                 :         61 :     }
#    1995                 :            : 
#    1996                 :         61 :     ~CoinsViewScanReserver() {
#    1997         [ +  - ]:         61 :         if (m_could_reserve) {
#    1998                 :         61 :             g_scan_in_progress = false;
#    1999                 :         61 :             g_scan_progress = 0;
#    2000                 :         61 :         }
#    2001                 :         61 :     }
#    2002                 :            : };
#    2003                 :            : 
#    2004                 :            : static RPCHelpMan scantxoutset()
#    2005                 :       1655 : {
#    2006                 :            :     // scriptPubKey corresponding to mainnet address 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S
#    2007                 :       1655 :     const std::string EXAMPLE_DESCRIPTOR_RAW = "raw(76a91411b366edfc0a8b66feebae5c2e25a7b6a5d1cf3188ac)#fm24fxxy";
#    2008                 :            : 
#    2009                 :       1655 :     return RPCHelpMan{"scantxoutset",
#    2010                 :       1655 :         "\nScans the unspent transaction output set for entries that match certain output descriptors.\n"
#    2011                 :       1655 :         "Examples of output descriptors are:\n"
#    2012                 :       1655 :         "    addr(<address>)                      Outputs whose scriptPubKey corresponds to the specified address (does not include P2PK)\n"
#    2013                 :       1655 :         "    raw(<hex script>)                    Outputs whose scriptPubKey equals the specified hex scripts\n"
#    2014                 :       1655 :         "    combo(<pubkey>)                      P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH outputs for the given pubkey\n"
#    2015                 :       1655 :         "    pkh(<pubkey>)                        P2PKH outputs for the given pubkey\n"
#    2016                 :       1655 :         "    sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n"
#    2017                 :       1655 :         "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
#    2018                 :       1655 :         "or more path elements separated by \"/\", and optionally ending in \"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
#    2019                 :       1655 :         "unhardened or hardened child keys.\n"
#    2020                 :       1655 :         "In the latter case, a range needs to be specified by below if different from 1000.\n"
#    2021                 :       1655 :         "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n",
#    2022                 :       1655 :         {
#    2023                 :       1655 :             {"action", RPCArg::Type::STR, RPCArg::Optional::NO, "The action to execute\n"
#    2024                 :       1655 :                 "\"start\" for starting a scan\n"
#    2025                 :       1655 :                 "\"abort\" for aborting the current scan (returns true when abort was successful)\n"
#    2026                 :       1655 :                 "\"status\" for progress report (in %) of the current scan"},
#    2027                 :       1655 :             {"scanobjects", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "Array of scan objects. Required for \"start\" action\n"
#    2028                 :       1655 :                 "Every scan object is either a string descriptor or an object:",
#    2029                 :       1655 :             {
#    2030                 :       1655 :                 {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
#    2031                 :       1655 :                 {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with output descriptor and metadata",
#    2032                 :       1655 :                 {
#    2033                 :       1655 :                     {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
#    2034                 :       1655 :                     {"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "The range of HD chain indexes to explore (either end or [begin,end])"},
#    2035                 :       1655 :                 }},
#    2036                 :       1655 :             },
#    2037                 :       1655 :                         "[scanobjects,...]"},
#    2038                 :       1655 :         },
#    2039                 :       1655 :         {
#    2040                 :       1655 :             RPCResult{"When action=='abort'", RPCResult::Type::BOOL, "", ""},
#    2041                 :       1655 :             RPCResult{"When action=='status' and no scan is in progress", RPCResult::Type::NONE, "", ""},
#    2042                 :       1655 :             RPCResult{"When action=='status' and scan is in progress", RPCResult::Type::OBJ, "", "",
#    2043                 :       1655 :             {
#    2044                 :       1655 :                 {RPCResult::Type::NUM, "progress", "The scan progress"},
#    2045                 :       1655 :             }},
#    2046                 :       1655 :             RPCResult{"When action=='start'", RPCResult::Type::OBJ, "", "", {
#    2047                 :       1655 :                 {RPCResult::Type::BOOL, "success", "Whether the scan was completed"},
#    2048                 :       1655 :                 {RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs scanned"},
#    2049                 :       1655 :                 {RPCResult::Type::NUM, "height", "The current block height (index)"},
#    2050                 :       1655 :                 {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
#    2051                 :       1655 :                 {RPCResult::Type::ARR, "unspents", "",
#    2052                 :       1655 :                 {
#    2053                 :       1655 :                     {RPCResult::Type::OBJ, "", "",
#    2054                 :       1655 :                     {
#    2055                 :       1655 :                         {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
#    2056                 :       1655 :                         {RPCResult::Type::NUM, "vout", "The vout value"},
#    2057                 :       1655 :                         {RPCResult::Type::STR_HEX, "scriptPubKey", "The script key"},
#    2058                 :       1655 :                         {RPCResult::Type::STR, "desc", "A specialized descriptor for the matched scriptPubKey"},
#    2059                 :       1655 :                         {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the unspent output"},
#    2060                 :       1655 :                         {RPCResult::Type::NUM, "height", "Height of the unspent transaction output"},
#    2061                 :       1655 :                     }},
#    2062                 :       1655 :                 }},
#    2063                 :       1655 :                 {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of all found unspent outputs in " + CURRENCY_UNIT},
#    2064                 :       1655 :             }},
#    2065                 :       1655 :         },
#    2066                 :       1655 :         RPCExamples{
#    2067                 :       1655 :             HelpExampleCli("scantxoutset", "start \'[\"" + EXAMPLE_DESCRIPTOR_RAW + "\"]\'") +
#    2068                 :       1655 :             HelpExampleCli("scantxoutset", "status") +
#    2069                 :       1655 :             HelpExampleCli("scantxoutset", "abort") +
#    2070                 :       1655 :             HelpExampleRpc("scantxoutset", "\"start\", [\"" + EXAMPLE_DESCRIPTOR_RAW + "\"]") +
#    2071                 :       1655 :             HelpExampleRpc("scantxoutset", "\"status\"") +
#    2072                 :       1655 :             HelpExampleRpc("scantxoutset", "\"abort\"")
#    2073                 :       1655 :         },
#    2074                 :       1655 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#    2075                 :       1655 : {
#    2076                 :         61 :     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR});
#    2077                 :            : 
#    2078                 :         61 :     UniValue result(UniValue::VOBJ);
#    2079         [ +  + ]:         61 :     if (request.params[0].get_str() == "status") {
#    2080                 :          1 :         CoinsViewScanReserver reserver;
#    2081         [ +  - ]:          1 :         if (reserver.reserve()) {
#    2082                 :            :             // no scan in progress
#    2083                 :          1 :             return NullUniValue;
#    2084                 :          1 :         }
#    2085                 :          0 :         result.pushKV("progress", g_scan_progress);
#    2086                 :          0 :         return result;
#    2087         [ +  + ]:         60 :     } else if (request.params[0].get_str() == "abort") {
#    2088                 :          1 :         CoinsViewScanReserver reserver;
#    2089         [ +  - ]:          1 :         if (reserver.reserve()) {
#    2090                 :            :             // reserve was possible which means no scan was running
#    2091                 :          1 :             return false;
#    2092                 :          1 :         }
#    2093                 :            :         // set the abort flag
#    2094                 :          0 :         g_should_abort_scan = true;
#    2095                 :          0 :         return true;
#    2096         [ +  - ]:         59 :     } else if (request.params[0].get_str() == "start") {
#    2097                 :         59 :         CoinsViewScanReserver reserver;
#    2098         [ -  + ]:         59 :         if (!reserver.reserve()) {
#    2099                 :          0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
#    2100                 :          0 :         }
#    2101                 :            : 
#    2102         [ +  + ]:         59 :         if (request.params.size() < 2) {
#    2103                 :          1 :             throw JSONRPCError(RPC_MISC_ERROR, "scanobjects argument is required for the start action");
#    2104                 :          1 :         }
#    2105                 :            : 
#    2106                 :         58 :         std::set<CScript> needles;
#    2107                 :         58 :         std::map<CScript, std::string> descriptors;
#    2108                 :         58 :         CAmount total_in = 0;
#    2109                 :            : 
#    2110                 :            :         // loop through the scan objects
#    2111         [ +  + ]:         69 :         for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
#    2112                 :         69 :             FlatSigningProvider provider;
#    2113                 :         69 :             auto scripts = EvalDescriptorStringOrObject(scanobject, provider);
#    2114         [ +  + ]:      72139 :             for (const auto& script : scripts) {
#    2115                 :      72139 :                 std::string inferred = InferDescriptor(script, provider)->ToString();
#    2116                 :      72139 :                 needles.emplace(script);
#    2117                 :      72139 :                 descriptors.emplace(std::move(script), std::move(inferred));
#    2118                 :      72139 :             }
#    2119                 :         69 :         }
#    2120                 :            : 
#    2121                 :            :         // Scan the unspent transaction output set for inputs
#    2122                 :         58 :         UniValue unspents(UniValue::VARR);
#    2123                 :         58 :         std::vector<CTxOut> input_txos;
#    2124                 :         58 :         std::map<COutPoint, Coin> coins;
#    2125                 :         58 :         g_should_abort_scan = false;
#    2126                 :         58 :         int64_t count = 0;
#    2127                 :         58 :         std::unique_ptr<CCoinsViewCursor> pcursor;
#    2128                 :         58 :         const CBlockIndex* tip;
#    2129                 :         58 :         NodeContext& node = EnsureAnyNodeContext(request.context);
#    2130                 :         58 :         {
#    2131                 :         58 :             ChainstateManager& chainman = EnsureChainman(node);
#    2132                 :         58 :             LOCK(cs_main);
#    2133                 :         58 :             CChainState& active_chainstate = chainman.ActiveChainstate();
#    2134                 :         58 :             active_chainstate.ForceFlushStateToDisk();
#    2135                 :         58 :             pcursor = active_chainstate.CoinsDB().Cursor();
#    2136         [ -  + ]:         58 :             CHECK_NONFATAL(pcursor);
#    2137                 :         58 :             tip = active_chainstate.m_chain.Tip();
#    2138         [ -  + ]:         58 :             CHECK_NONFATAL(tip);
#    2139                 :         58 :         }
#    2140                 :         58 :         bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins, node.rpc_interruption_point);
#    2141                 :         58 :         result.pushKV("success", res);
#    2142                 :         58 :         result.pushKV("txouts", count);
#    2143                 :         58 :         result.pushKV("height", tip->nHeight);
#    2144                 :         58 :         result.pushKV("bestblock", tip->GetBlockHash().GetHex());
#    2145                 :            : 
#    2146         [ +  + ]:        795 :         for (const auto& it : coins) {
#    2147                 :        795 :             const COutPoint& outpoint = it.first;
#    2148                 :        795 :             const Coin& coin = it.second;
#    2149                 :        795 :             const CTxOut& txo = coin.out;
#    2150                 :        795 :             input_txos.push_back(txo);
#    2151                 :        795 :             total_in += txo.nValue;
#    2152                 :            : 
#    2153                 :        795 :             UniValue unspent(UniValue::VOBJ);
#    2154                 :        795 :             unspent.pushKV("txid", outpoint.hash.GetHex());
#    2155                 :        795 :             unspent.pushKV("vout", (int32_t)outpoint.n);
#    2156                 :        795 :             unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
#    2157                 :        795 :             unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
#    2158                 :        795 :             unspent.pushKV("amount", ValueFromAmount(txo.nValue));
#    2159                 :        795 :             unspent.pushKV("height", (int32_t)coin.nHeight);
#    2160                 :            : 
#    2161                 :        795 :             unspents.push_back(unspent);
#    2162                 :        795 :         }
#    2163                 :         58 :         result.pushKV("unspents", unspents);
#    2164                 :         58 :         result.pushKV("total_amount", ValueFromAmount(total_in));
#    2165                 :         58 :     } else {
#    2166                 :          0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid command");
#    2167                 :          0 :     }
#    2168                 :         58 :     return result;
#    2169                 :         61 : },
#    2170                 :       1655 :     };
#    2171                 :       1655 : }
#    2172                 :            : 
#    2173                 :            : static RPCHelpMan getblockfilter()
#    2174                 :       1613 : {
#    2175                 :       1613 :     return RPCHelpMan{"getblockfilter",
#    2176                 :       1613 :                 "\nRetrieve a BIP 157 content filter for a particular block.\n",
#    2177                 :       1613 :                 {
#    2178                 :       1613 :                     {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hash of the block"},
#    2179                 :       1613 :                     {"filtertype", RPCArg::Type::STR, RPCArg::Default{"basic"}, "The type name of the filter"},
#    2180                 :       1613 :                 },
#    2181                 :       1613 :                 RPCResult{
#    2182                 :       1613 :                     RPCResult::Type::OBJ, "", "",
#    2183                 :       1613 :                     {
#    2184                 :       1613 :                         {RPCResult::Type::STR_HEX, "filter", "the hex-encoded filter data"},
#    2185                 :       1613 :                         {RPCResult::Type::STR_HEX, "header", "the hex-encoded filter header"},
#    2186                 :       1613 :                     }},
#    2187                 :       1613 :                 RPCExamples{
#    2188                 :       1613 :                     HelpExampleCli("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" \"basic\"") +
#    2189                 :       1613 :                     HelpExampleRpc("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\", \"basic\"")
#    2190                 :       1613 :                 },
#    2191                 :       1613 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#    2192                 :       1613 : {
#    2193                 :         19 :     uint256 block_hash = ParseHashV(request.params[0], "blockhash");
#    2194                 :         19 :     std::string filtertype_name = "basic";
#    2195         [ +  + ]:         19 :     if (!request.params[1].isNull()) {
#    2196                 :         14 :         filtertype_name = request.params[1].get_str();
#    2197                 :         14 :     }
#    2198                 :            : 
#    2199                 :         19 :     BlockFilterType filtertype;
#    2200         [ +  + ]:         19 :     if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
#    2201                 :          1 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown filtertype");
#    2202                 :          1 :     }
#    2203                 :            : 
#    2204                 :         18 :     BlockFilterIndex* index = GetBlockFilterIndex(filtertype);
#    2205         [ +  + ]:         18 :     if (!index) {
#    2206                 :          2 :         throw JSONRPCError(RPC_MISC_ERROR, "Index is not enabled for filtertype " + filtertype_name);
#    2207                 :          2 :     }
#    2208                 :            : 
#    2209                 :         16 :     const CBlockIndex* block_index;
#    2210                 :         16 :     bool block_was_connected;
#    2211                 :         16 :     {
#    2212                 :         16 :         ChainstateManager& chainman = EnsureAnyChainman(request.context);
#    2213                 :         16 :         LOCK(cs_main);
#    2214                 :         16 :         block_index = chainman.m_blockman.LookupBlockIndex(block_hash);
#    2215         [ +  + ]:         16 :         if (!block_index) {
#    2216                 :          1 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
#    2217                 :          1 :         }
#    2218                 :         15 :         block_was_connected = block_index->IsValid(BLOCK_VALID_SCRIPTS);
#    2219                 :         15 :     }
#    2220                 :            : 
#    2221                 :          0 :     bool index_ready = index->BlockUntilSyncedToCurrentChain();
#    2222                 :            : 
#    2223                 :         15 :     BlockFilter filter;
#    2224                 :         15 :     uint256 filter_header;
#    2225         [ -  + ]:         15 :     if (!index->LookupFilter(block_index, filter) ||
#    2226         [ -  + ]:         15 :         !index->LookupFilterHeader(block_index, filter_header)) {
#    2227                 :          0 :         int err_code;
#    2228                 :          0 :         std::string errmsg = "Filter not found.";
#    2229                 :            : 
#    2230         [ #  # ]:          0 :         if (!block_was_connected) {
#    2231                 :          0 :             err_code = RPC_INVALID_ADDRESS_OR_KEY;
#    2232                 :          0 :             errmsg += " Block was not connected to active chain.";
#    2233         [ #  # ]:          0 :         } else if (!index_ready) {
#    2234                 :          0 :             err_code = RPC_MISC_ERROR;
#    2235                 :          0 :             errmsg += " Block filters are still in the process of being indexed.";
#    2236                 :          0 :         } else {
#    2237                 :          0 :             err_code = RPC_INTERNAL_ERROR;
#    2238                 :          0 :             errmsg += " This error is unexpected and indicates index corruption.";
#    2239                 :          0 :         }
#    2240                 :            : 
#    2241                 :          0 :         throw JSONRPCError(err_code, errmsg);
#    2242                 :          0 :     }
#    2243                 :            : 
#    2244                 :         15 :     UniValue ret(UniValue::VOBJ);
#    2245                 :         15 :     ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
#    2246                 :         15 :     ret.pushKV("header", filter_header.GetHex());
#    2247                 :         15 :     return ret;
#    2248                 :         15 : },
#    2249                 :       1613 :     };
#    2250                 :       1613 : }
#    2251                 :            : 
#    2252                 :            : /**
#    2253                 :            :  * Serialize the UTXO set to a file for loading elsewhere.
#    2254                 :            :  *
#    2255                 :            :  * @see SnapshotMetadata
#    2256                 :            :  */
#    2257                 :            : static RPCHelpMan dumptxoutset()
#    2258                 :       1591 : {
#    2259                 :       1591 :     return RPCHelpMan{
#    2260                 :       1591 :         "dumptxoutset",
#    2261                 :       1591 :         "Write the serialized UTXO set to disk.",
#    2262                 :       1591 :         {
#    2263                 :       1591 :             {"path", RPCArg::Type::STR, RPCArg::Optional::NO, "Path to the output file. If relative, will be prefixed by datadir."},
#    2264                 :       1591 :         },
#    2265                 :       1591 :         RPCResult{
#    2266                 :       1591 :             RPCResult::Type::OBJ, "", "",
#    2267                 :       1591 :                 {
#    2268                 :       1591 :                     {RPCResult::Type::NUM, "coins_written", "the number of coins written in the snapshot"},
#    2269                 :       1591 :                     {RPCResult::Type::STR_HEX, "base_hash", "the hash of the base of the snapshot"},
#    2270                 :       1591 :                     {RPCResult::Type::NUM, "base_height", "the height of the base of the snapshot"},
#    2271                 :       1591 :                     {RPCResult::Type::STR, "path", "the absolute path that the snapshot was written to"},
#    2272                 :       1591 :                     {RPCResult::Type::STR_HEX, "txoutset_hash", "the hash of the UTXO set contents"},
#    2273                 :       1591 :                     {RPCResult::Type::NUM, "nchaintx", "the number of transactions in the chain up to and including the base block"},
#    2274                 :       1591 :                 }
#    2275                 :       1591 :         },
#    2276                 :       1591 :         RPCExamples{
#    2277                 :       1591 :             HelpExampleCli("dumptxoutset", "utxo.dat")
#    2278                 :       1591 :         },
#    2279                 :       1591 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#    2280                 :       1591 : {
#    2281                 :          2 :     const ArgsManager& args{EnsureAnyArgsman(request.context)};
#    2282                 :          2 :     const fs::path path = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(request.params[0].get_str()));
#    2283                 :            :     // Write to a temporary path and then move into `path` on completion
#    2284                 :            :     // to avoid confusion due to an interruption.
#    2285                 :          2 :     const fs::path temppath = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(request.params[0].get_str() + ".incomplete"));
#    2286                 :            : 
#    2287         [ +  + ]:          2 :     if (fs::exists(path)) {
#    2288                 :          1 :         throw JSONRPCError(
#    2289                 :          1 :             RPC_INVALID_PARAMETER,
#    2290                 :          1 :             path.u8string() + " already exists. If you are sure this is what you want, "
#    2291                 :          1 :             "move it out of the way first");
#    2292                 :          1 :     }
#    2293                 :            : 
#    2294                 :          1 :     FILE* file{fsbridge::fopen(temppath, "wb")};
#    2295                 :          1 :     CAutoFile afile{file, SER_DISK, CLIENT_VERSION};
#    2296                 :          1 :     NodeContext& node = EnsureAnyNodeContext(request.context);
#    2297                 :          1 :     UniValue result = CreateUTXOSnapshot(
#    2298                 :          1 :         node, node.chainman->ActiveChainstate(), afile, path, temppath);
#    2299                 :          1 :     fs::rename(temppath, path);
#    2300                 :            : 
#    2301                 :          1 :     result.pushKV("path", path.u8string());
#    2302                 :          1 :     return result;
#    2303                 :          2 : },
#    2304                 :       1591 :     };
#    2305                 :       1591 : }
#    2306                 :            : 
#    2307                 :            : UniValue CreateUTXOSnapshot(
#    2308                 :            :     NodeContext& node,
#    2309                 :            :     CChainState& chainstate,
#    2310                 :            :     CAutoFile& afile,
#    2311                 :            :     const fs::path& path,
#    2312                 :            :     const fs::path& temppath)
#    2313                 :         10 : {
#    2314                 :         10 :     std::unique_ptr<CCoinsViewCursor> pcursor;
#    2315                 :         10 :     CCoinsStats stats{CoinStatsHashType::HASH_SERIALIZED};
#    2316                 :         10 :     const CBlockIndex* tip;
#    2317                 :            : 
#    2318                 :         10 :     {
#    2319                 :            :         // We need to lock cs_main to ensure that the coinsdb isn't written to
#    2320                 :            :         // between (i) flushing coins cache to disk (coinsdb), (ii) getting stats
#    2321                 :            :         // based upon the coinsdb, and (iii) constructing a cursor to the
#    2322                 :            :         // coinsdb for use below this block.
#    2323                 :            :         //
#    2324                 :            :         // Cursors returned by leveldb iterate over snapshots, so the contents
#    2325                 :            :         // of the pcursor will not be affected by simultaneous writes during
#    2326                 :            :         // use below this block.
#    2327                 :            :         //
#    2328                 :            :         // See discussion here:
#    2329                 :            :         //   https://github.com/bitcoin/bitcoin/pull/15606#discussion_r274479369
#    2330                 :            :         //
#    2331                 :         10 :         LOCK(::cs_main);
#    2332                 :            : 
#    2333                 :         10 :         chainstate.ForceFlushStateToDisk();
#    2334                 :            : 
#    2335         [ -  + ]:         10 :         if (!GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman, stats, node.rpc_interruption_point)) {
#    2336                 :          0 :             throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
#    2337                 :          0 :         }
#    2338                 :            : 
#    2339                 :         10 :         pcursor = chainstate.CoinsDB().Cursor();
#    2340                 :         10 :         tip = chainstate.m_blockman.LookupBlockIndex(stats.hashBlock);
#    2341         [ -  + ]:         10 :         CHECK_NONFATAL(tip);
#    2342                 :         10 :     }
#    2343                 :            : 
#    2344                 :         10 :     LOG_TIME_SECONDS(strprintf("writing UTXO snapshot at height %s (%s) to file %s (via %s)",
#    2345                 :         10 :         tip->nHeight, tip->GetBlockHash().ToString(),
#    2346                 :         10 :         fs::PathToString(path), fs::PathToString(temppath)));
#    2347                 :            : 
#    2348                 :         10 :     SnapshotMetadata metadata{tip->GetBlockHash(), stats.coins_count, tip->nChainTx};
#    2349                 :            : 
#    2350                 :         10 :     afile << metadata;
#    2351                 :            : 
#    2352                 :         10 :     COutPoint key;
#    2353                 :         10 :     Coin coin;
#    2354                 :         10 :     unsigned int iter{0};
#    2355                 :            : 
#    2356         [ +  + ]:       1190 :     while (pcursor->Valid()) {
#    2357         [ +  + ]:       1180 :         if (iter % 5000 == 0) node.rpc_interruption_point();
#    2358                 :       1180 :         ++iter;
#    2359 [ +  - ][ +  - ]:       1180 :         if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
#    2360                 :       1180 :             afile << key;
#    2361                 :       1180 :             afile << coin;
#    2362                 :       1180 :         }
#    2363                 :            : 
#    2364                 :       1180 :         pcursor->Next();
#    2365                 :       1180 :     }
#    2366                 :            : 
#    2367                 :         10 :     afile.fclose();
#    2368                 :            : 
#    2369                 :         10 :     UniValue result(UniValue::VOBJ);
#    2370                 :         10 :     result.pushKV("coins_written", stats.coins_count);
#    2371                 :         10 :     result.pushKV("base_hash", tip->GetBlockHash().ToString());
#    2372                 :         10 :     result.pushKV("base_height", tip->nHeight);
#    2373                 :         10 :     result.pushKV("path", path.u8string());
#    2374                 :         10 :     result.pushKV("txoutset_hash", stats.hashSerialized.ToString());
#    2375                 :            :     // Cast required because univalue doesn't have serialization specified for
#    2376                 :            :     // `unsigned int`, nChainTx's type.
#    2377                 :         10 :     result.pushKV("nchaintx", uint64_t{tip->nChainTx});
#    2378                 :         10 :     return result;
#    2379                 :         10 : }
#    2380                 :            : 
#    2381                 :            : 
#    2382                 :            : void RegisterBlockchainRPCCommands(CRPCTable &t)
#    2383                 :        993 : {
#    2384                 :            : // clang-format off
#    2385                 :        993 : static const CRPCCommand commands[] =
#    2386                 :        993 : { //  category              actor (function)
#    2387                 :            :   //  --------------------- ------------------------
#    2388                 :        993 :     { "blockchain",         &getblockchaininfo,                  },
#    2389                 :        993 :     { "blockchain",         &getchaintxstats,                    },
#    2390                 :        993 :     { "blockchain",         &getblockstats,                      },
#    2391                 :        993 :     { "blockchain",         &getbestblockhash,                   },
#    2392                 :        993 :     { "blockchain",         &getblockcount,                      },
#    2393                 :        993 :     { "blockchain",         &getblock,                           },
#    2394                 :        993 :     { "blockchain",         &getblockfrompeer,                   },
#    2395                 :        993 :     { "blockchain",         &getblockhash,                       },
#    2396                 :        993 :     { "blockchain",         &getblockheader,                     },
#    2397                 :        993 :     { "blockchain",         &getchaintips,                       },
#    2398                 :        993 :     { "blockchain",         &getdifficulty,                      },
#    2399                 :        993 :     { "blockchain",         &getdeploymentinfo,                  },
#    2400                 :        993 :     { "blockchain",         &gettxout,                           },
#    2401                 :        993 :     { "blockchain",         &gettxoutsetinfo,                    },
#    2402                 :        993 :     { "blockchain",         &pruneblockchain,                    },
#    2403                 :        993 :     { "blockchain",         &verifychain,                        },
#    2404                 :            : 
#    2405                 :        993 :     { "blockchain",         &preciousblock,                      },
#    2406                 :        993 :     { "blockchain",         &scantxoutset,                       },
#    2407                 :        993 :     { "blockchain",         &getblockfilter,                     },
#    2408                 :            : 
#    2409                 :            :     /* Not shown in help */
#    2410                 :        993 :     { "hidden",              &invalidateblock,                   },
#    2411                 :        993 :     { "hidden",              &reconsiderblock,                   },
#    2412                 :        993 :     { "hidden",              &waitfornewblock,                   },
#    2413                 :        993 :     { "hidden",              &waitforblock,                      },
#    2414                 :        993 :     { "hidden",              &waitforblockheight,                },
#    2415                 :        993 :     { "hidden",              &syncwithvalidationinterfacequeue,  },
#    2416                 :        993 :     { "hidden",              &dumptxoutset,                      },
#    2417                 :        993 : };
#    2418                 :            : // clang-format on
#    2419         [ +  + ]:      25818 :     for (const auto& c : commands) {
#    2420                 :      25818 :         t.appendCommand(c.name, &c);
#    2421                 :      25818 :     }
#    2422                 :        993 : }

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a