LCOV - code coverage report
Current view: top level - src/rpc - blockchain.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 2089 2203 94.8 %
Date: 2021-06-29 14:35:33 Functions: 117 121 96.7 %
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: 490 598 81.9 %

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

Generated by: LCOV version 1.14