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