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