LCOV - code coverage report
Current view: top level - src/rpc - blockchain.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 1538 1653 93.0 %
Date: 2020-09-26 01:30:44 Functions: 87 91 95.6 %

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

Generated by: LCOV version 1.15