Inside Bitcoin
Opening the selected file…
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.
3501{3502auto [cursor, stats, tip]{WITH_LOCK(::cs_main, return PrepareUTXOSnapshot(chainstate, node.rpc_interruption_point))};3503return WriteUTXOSnapshot(chainstate,3504cursor.get(),3505&stats,3506tip,3507std::move(afile),3508path,3509tmppath,3510node.rpc_interruption_point);3511}3513static RPCMethod loadtxoutset()3514{3515return RPCMethod{3516"loadtxoutset",3517"Load the serialized UTXO set from a file.\n"3518"Once this snapshot is loaded, its contents will be "3519"deserialized into a second chainstate data structure, which is then used to sync to "3520"the network's tip. "3521"Meanwhile, the original chainstate will complete the initial block download process in "3522"the background, eventually validating up to the block that the snapshot is based upon.\n\n"3524"The result is a usable bitcoind instance that is current with the network tip in a "3525"matter of minutes rather than hours. UTXO snapshot are typically obtained from "3526"third-party sources (HTTP, torrent, etc.) which is reasonable since their "3527"contents are always checked by hash.\n\n"3529"You can find more information on this process in the `assumeutxo` design "3530"document (<https://github.com/bitcoin/bitcoin/blob/master/doc/design/assumeutxo.md>).",3531{3532{"path",3533RPCArg::Type::STR,3534RPCArg::Optional::NO,3535"path to the snapshot file. If relative, will be prefixed by datadir."},3536},3537RPCResult{3538RPCResult::Type::OBJ, "", "",3539{3540{RPCResult::Type::NUM, "coins_loaded", "the number of coins loaded from the snapshot"},3541{RPCResult::Type::STR_HEX, "tip_hash", "the hash of the base of the snapshot"},3542{RPCResult::Type::NUM, "base_height", "the height of the base of the snapshot"},3543{RPCResult::Type::STR, "path", "the absolute path that the snapshot was loaded from"},3544}3545},3546RPCExamples{3547HelpExampleCli("-rpcclienttimeout=0 loadtxoutset", "utxo.dat")3548},3549[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue3550{3551NodeContext& node = EnsureAnyNodeContext(request.context);3552ChainstateManager& chainman = EnsureChainman(node);3553const fs::path path{AbsPathForConfigVal(EnsureArgsman(node), fs::u8path(self.Arg<std::string_view>("path")))};3555FILE* file{fsbridge::fopen(path, "rb")};3556AutoFile afile{file};3557if (afile.IsNull()) {3558throw JSONRPCError(3559RPC_INVALID_PARAMETER,3560"Couldn't open file " + path.utf8string() + " for reading.");3561}3563SnapshotMetadata metadata{chainman.GetParams().MessageStart()};3564try {3565afile >> metadata;3566} catch (const std::ios_base::failure& e) {3567throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("Unable to parse metadata: %s", e.what()));3568}3570auto activation_result{chainman.ActivateSnapshot(afile, metadata, false)};3571if (!activation_result) {3572throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to load UTXO snapshot: %s. (%s)", util::ErrorString(activation_result).original, path.utf8string()));3573}3575// Because we can't provide historical blocks during tip or background sync.3576// Update local services to reflect we are a limited peer until we are fully sync.3577node.connman->RemoveLocalServices(NODE_NETWORK);3578// Setting the limited state is usually redundant because the node can always3579// provide the last 288 blocks, but it doesn't hurt to set it.3580node.connman->AddLocalServices(NODE_NETWORK_LIMITED);3582CBlockIndex& snapshot_index{*CHECK_NONFATAL(*activation_result)};3584UniValue result(UniValue::VOBJ);3585result.pushKV("coins_loaded", metadata.m_coins_count);3586result.pushKV("tip_hash", snapshot_index.GetBlockHash().ToString());3587result.pushKV("base_height", snapshot_index.nHeight);3588result.pushKV("path", fs::PathToString(path));3589return result;3590},3591};3592}3594const std::vector<RPCResult> RPCHelpForChainstate{3595{RPCResult::Type::NUM, "blocks", "number of blocks in this chainstate"},3596{RPCResult::Type::STR_HEX, "bestblockhash", "blockhash of the tip"},3597{RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},3598{RPCResult::Type::STR_HEX, "target", "The difficulty target"},3599{RPCResult::Type::NUM, "difficulty", "difficulty of the tip"},3600{RPCResult::Type::NUM, "verificationprogress", "progress towards the network tip"},3601{RPCResult::Type::STR_HEX, "snapshot_blockhash", /*optional=*/true, "the base block of the snapshot this chainstate is based on, if any"},3602{RPCResult::Type::NUM, "coins_db_cache_bytes", "size of the coinsdb cache"},3603{RPCResult::Type::NUM, "coins_tip_cache_bytes", "size of the coinstip cache"},3604{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."},3605};3607static RPCMethod getchainstates()3608{3609return RPCMethod{3610"getchainstates",3611"Return information about chainstates.\n",3612{},3613RPCResult{3614RPCResult::Type::OBJ, "", "", {3615{RPCResult::Type::NUM, "headers", "the number of headers seen so far"},3616{RPCResult::Type::ARR, "chainstates", "list of the chainstates ordered by work, with the most-work (active) chainstate last", {{RPCResult::Type::OBJ, "", "", RPCHelpForChainstate},}},3617}3618},3619RPCExamples{3620HelpExampleCli("getchainstates", "")3621+ HelpExampleRpc("getchainstates", "")3622},3623[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue3624{3625LOCK(cs_main);3626UniValue obj(UniValue::VOBJ);3628ChainstateManager& chainman = EnsureAnyChainman(request.context);3630auto make_chain_data = [&](const Chainstate& cs) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {3631AssertLockHeld(::cs_main);3632UniValue data(UniValue::VOBJ);3633if (!cs.m_chain.Tip()) {3634return data;3635}3636const CChain& chain = cs.m_chain;3637const CBlockIndex* tip = chain.Tip();3639data.pushKV("blocks", chain.Height());3640data.pushKV("bestblockhash", tip->GetBlockHash().GetHex());3641data.pushKV("bits", strprintf("%08x", tip->nBits));3642data.pushKV("target", GetTarget(*tip, chainman.GetConsensus().powLimit).GetHex());3643data.pushKV("difficulty", GetDifficulty(*tip));3644data.pushKV("verificationprogress", chainman.GuessVerificationProgress(tip));3645data.pushKV("coins_db_cache_bytes", cs.m_coinsdb_cache_size_bytes);3646data.pushKV("coins_tip_cache_bytes", cs.m_coinstip_cache_size_bytes);3647if (cs.m_from_snapshot_blockhash) {3648data.pushKV("snapshot_blockhash", cs.m_from_snapshot_blockhash->ToString());3649}3650data.pushKV("validated", cs.m_assumeutxo == Assumeutxo::VALIDATED);3651return data;3652};3654obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);3655UniValue obj_chainstates{UniValue::VARR};3656if (const Chainstate * cs{chainman.HistoricalChainstate()}) {3657obj_chainstates.push_back(make_chain_data(*cs));3658}3659obj_chainstates.push_back(make_chain_data(chainman.CurrentChainstate()));3660obj.pushKV("chainstates", std::move(obj_chainstates));3661return obj;3662}3663};3664}3667void RegisterBlockchainRPCCommands(CRPCTable& t)3668{3669static const CRPCCommand commands[]{3670{"blockchain", &getblockchaininfo},3671{"blockchain", &getchaintxstats},3672{"blockchain", &getblockstats},3673{"blockchain", &getbestblockhash},3674{"blockchain", &getblockcount},3675{"blockchain", &getblock},3676{"blockchain", &getblockfrompeer},3677{"blockchain", &getblockhash},3678{"blockchain", &getblockheader},3679{"blockchain", &getchaintips},3680{"blockchain", &getdifficulty},3681{"blockchain", &getdeploymentinfo},3682{"blockchain", &gettxout},3683{"blockchain", &gettxoutsetinfo},3684{"blockchain", &pruneblockchain},3685{"blockchain", &verifychain},3686{"blockchain", &preciousblock},3687{"blockchain", &scantxoutset},3688{"blockchain", &scanblocks},3689{"blockchain", &getdescriptoractivity},3690{"blockchain", &getblockfilter},3691{"blockchain", &dumptxoutset},3692{"blockchain", &loadtxoutset},3693{"blockchain", &getchainstates},3694{"hidden", &invalidateblock},3695{"hidden", &reconsiderblock},3696{"blockchain", &waitfornewblock},3697{"blockchain", &waitforblock},3698{"blockchain", &waitforblockheight},3699{"hidden", &syncwithvalidationinterfacequeue},3700};3701for (const auto& c : commands) {3702t.appendCommand(c.name, &c);3703}3704}