Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
501if (!block) break;502current_block = *block;503}505UniValue ret(UniValue::VOBJ);506ret.pushKV("hash", current_block.hash.GetHex());507ret.pushKV("height", current_block.height);508return ret;509},510};511}513static RPCMethod syncwithvalidationinterfacequeue()514{515return RPCMethod{516"syncwithvalidationinterfacequeue",517"Waits for the validation interface queue to catch up on everything that was there when we entered this function.\n",518{},519RPCResult{RPCResult::Type::NONE, "", ""},520RPCExamples{521HelpExampleCli("syncwithvalidationinterfacequeue","")522+ HelpExampleRpc("syncwithvalidationinterfacequeue","")523},524[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue525{526NodeContext& node = EnsureAnyNodeContext(request.context);527CHECK_NONFATAL(node.validation_signals)->SyncWithValidationInterfaceQueue();528return UniValue::VNULL;529},530};531}533static RPCMethod getdifficulty()534{535return RPCMethod{536"getdifficulty",537"Returns the proof-of-work difficulty as a multiple of the minimum difficulty.\n",538{},539RPCResult{540RPCResult::Type::NUM, "", "the proof-of-work difficulty as a multiple of the minimum difficulty."},541RPCExamples{542HelpExampleCli("getdifficulty", "")543+ HelpExampleRpc("getdifficulty", "")544},545[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue546{547ChainstateManager& chainman = EnsureAnyChainman(request.context);548LOCK(cs_main);549return GetDifficulty(*CHECK_NONFATAL(chainman.ActiveChain().Tip()));550},551};552}554static RPCMethod getblockfrompeer()555{556return RPCMethod{557"getblockfrompeer",558"Attempt to fetch block from a given peer.\n\n"559"We must have the header for this block, e.g. using submitheader.\n"560"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"561"Subsequent calls for the same block may cause the response from the previous peer to be ignored.\n"562"Peers generally ignore requests for a stale block that they never fully verified, or one that is more than a month old.\n"563"When a peer does not respond with a block, we will disconnect.\n"564"Note: The block could be re-pruned as soon as it is received.\n\n"565"Returns an empty JSON object if the request was successfully scheduled.",566{567{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash to try to fetch"},568{"peer_id", RPCArg::Type::NUM, RPCArg::Optional::NO, "The peer to fetch it from (see getpeerinfo for peer IDs)"},569},570RPCResult{RPCResult::Type::OBJ, "", /*optional=*/false, "", {}},571RPCExamples{572HelpExampleCli("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0")573+ HelpExampleRpc("getblockfrompeer", R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", 0)")574},575[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue576{577const NodeContext& node = EnsureAnyNodeContext(request.context);578ChainstateManager& chainman = EnsureChainman(node);579PeerManager& peerman = EnsurePeerman(node);581const uint256& block_hash{ParseHashV(request.params[0], "blockhash")};582const NodeId peer_id{request.params[1].getInt<int64_t>()};584const CBlockIndex* const index = WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(block_hash););586if (!index) {587throw JSONRPCError(RPC_MISC_ERROR, "Block header missing");588}590// Fetching blocks before the node has syncing past their height can prevent block files from591// being pruned, so we avoid it if the node is in prune mode.592if (chainman.m_blockman.IsPruneMode() && index->nHeight > WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip()->nHeight)) {593throw JSONRPCError(RPC_MISC_ERROR, "In prune mode, only blocks that the node has already synced previously can be fetched from a peer");594}596const bool block_has_data = WITH_LOCK(::cs_main, return index->nStatus & BLOCK_HAVE_DATA);597if (block_has_data) {598throw JSONRPCError(RPC_MISC_ERROR, "Block already downloaded");599}601if (const auto res{peerman.FetchBlock(peer_id, *index)}; !res) {602throw JSONRPCError(RPC_MISC_ERROR, res.error());603}604return UniValue::VOBJ;605},606};607}609static RPCMethod getblockhash()610{611return RPCMethod{612"getblockhash",613"Returns hash of block in best-block-chain at height provided.\n",614{615{"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The height index"},616},617RPCResult{618RPCResult::Type::STR_HEX, "", "The block hash"},619RPCExamples{620HelpExampleCli("getblockhash", "1000")621+ HelpExampleRpc("getblockhash", "1000")622},623[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue624{625ChainstateManager& chainman = EnsureAnyChainman(request.context);626LOCK(cs_main);627const CChain& active_chain = chainman.ActiveChain();629int nHeight = request.params[0].getInt<int>();630if (nHeight < 0 || nHeight > active_chain.Height())631throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");633const CBlockIndex* pblockindex = active_chain[nHeight];634return pblockindex->GetBlockHash().GetHex();635},636};637}639static RPCMethod getblockheader()640{641return RPCMethod{642"getblockheader",643"If verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"644"If verbose is true, returns an Object with information about blockheader <hash>.\n",645{646{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},647{"verbose", RPCArg::Type::BOOL, RPCArg::Default{true}, "true for a json object, false for the hex-encoded data"},648},649{650RPCResult{"for verbose = true",651RPCResult::Type::OBJ, "", "",652{653{RPCResult::Type::STR_HEX, "hash", "the block hash (same as provided)"},654{RPCResult::Type::NUM, "confirmations", "The number of confirmations, or -1 if the block is not on the main chain"},655{RPCResult::Type::NUM, "height", "The block height or index"},656{RPCResult::Type::NUM, "version", "The block version"},657{RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},658{RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},659{RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},660{RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},661{RPCResult::Type::NUM, "nonce", "The nonce"},662{RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},663{RPCResult::Type::STR_HEX, "target", "The difficulty target"},664{RPCResult::Type::NUM, "difficulty", "The difficulty"},665{RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the current chain"},666{RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},667{RPCResult::Type::STR_HEX, "previousblockhash", /*optional=*/true, "The hash of the previous block (if available)"},668{RPCResult::Type::STR_HEX, "nextblockhash", /*optional=*/true, "The hash of the next block (if available)"},669}},670RPCResult{"for verbose=false",671RPCResult::Type::STR_HEX, "", "A string that is serialized, hex-encoded data for block 'hash'"},672},673RPCExamples{674HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")675+ HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")676},677[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue678{679uint256 hash(ParseHashV(request.params[0], "hash"));681bool fVerbose = true;682if (!request.params[1].isNull())683fVerbose = request.params[1].get_bool();685const CBlockIndex* pblockindex;686const CBlockIndex* tip;687ChainstateManager& chainman = EnsureAnyChainman(request.context);688{689LOCK(cs_main);690pblockindex = chainman.m_blockman.LookupBlockIndex(hash);691tip = chainman.ActiveChain().Tip();692}694if (!pblockindex) {695throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");696}698if (!fVerbose)699{700DataStream ssBlock{};701ssBlock << pblockindex->GetBlockHeader();702std::string strHex = HexStr(ssBlock);703return strHex;704}706return blockheaderToJSON(*tip, *pblockindex, chainman.GetConsensus().powLimit);707},708};709}711void CheckBlockDataAvailability(BlockManager& blockman, const CBlockIndex& blockindex, bool check_for_undo)712{713AssertLockHeld(cs_main);714uint32_t flag = check_for_undo ? BLOCK_HAVE_UNDO : BLOCK_HAVE_DATA;715if (!(blockindex.nStatus & flag)) {716if (blockman.IsBlockPruned(blockindex)) {717throw JSONRPCError(RPC_MISC_ERROR, strprintf("%s not available (pruned data)", check_for_undo ? "Undo data" : "Block"));718}719if (check_for_undo) {720throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available");721}722throw JSONRPCError(RPC_MISC_ERROR, "Block not available (not fully downloaded)");723}724}726static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex& blockindex)727{728CBlock block;729{730LOCK(cs_main);731CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/false);732}734if (!blockman.ReadBlock(block, blockindex)) {735// Block not found on disk. This shouldn't normally happen unless the block was736// pruned right after we released the lock above.737throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");738}740return block;741}743static std::vector<std::byte> GetRawBlockChecked(BlockManager& blockman, const CBlockIndex& blockindex)744{745FlatFilePos pos{};746{747LOCK(cs_main);748CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/false);749pos = blockindex.GetBlockPos();750}