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.
1001PruneBlockFilesManual(active_chainstate, height);1002return GetPruneHeight(chainman.m_blockman, active_chain).value_or(-1);1003},1004};1005}1007CoinStatsHashType ParseHashType(std::string_view hash_type_input)1008{1009if (hash_type_input == "hash_serialized_3") {1010return CoinStatsHashType::HASH_SERIALIZED;1011} else if (hash_type_input == "muhash") {1012return CoinStatsHashType::MUHASH;1013} else if (hash_type_input == "none") {1014return CoinStatsHashType::NONE;1015} else {1016throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("'%s' is not a valid hash_type", hash_type_input));1017}1018}1020/**1021* Calculate statistics about the unspent transaction output set1022*1023* @param[in] index_requested Signals if the coinstatsindex should be used (when available).1024*/1025static std::optional<kernel::CCoinsStats> GetUTXOStats(const CCoinsViewDB& view, node::BlockManager& blockman,1026kernel::CoinStatsHashType hash_type,1027const std::function<void()>& interruption_point = {},1028const CBlockIndex* pindex = nullptr,1029bool index_requested = true)1030{1031// Use CoinStatsIndex if it is requested and available and a hash_type of Muhash or None was requested1032if ((hash_type == kernel::CoinStatsHashType::MUHASH || hash_type == kernel::CoinStatsHashType::NONE) && g_coin_stats_index && index_requested) {1033if (pindex) {1034return g_coin_stats_index->LookUpStats(*pindex);1035} else {1036CBlockIndex& block_index = *CHECK_NONFATAL(WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(view.GetBestBlock())));1037return g_coin_stats_index->LookUpStats(block_index);1038}1039}1041// If the coinstats index isn't requested or is otherwise not usable, the1042// pindex should either be null or equal to the view's best block. This is1043// because without the coinstats index we can only get coinstats about the1044// best block.1045CHECK_NONFATAL(!pindex || pindex->GetBlockHash() == view.GetBestBlock());1047return kernel::ComputeUTXOStats(hash_type, view, blockman, interruption_point);1048}1050static RPCMethod gettxoutsetinfo()1051{1052return RPCMethod{1053"gettxoutsetinfo",1054"Returns statistics about the unspent transaction output set.\n"1055"Note this call may take some time if you are not using coinstatsindex.\n",1056{1057{"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'."},1058{"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).",1059RPCArgOptions{1060.skip_type_check = true,1061.type_str = {"", "string or numeric"},1062}},1063{"use_index", RPCArg::Type::BOOL, RPCArg::Default{true}, "Use coinstatsindex, if available."},1064},1065RPCResult{1066RPCResult::Type::OBJ, "", "",1067{1068{RPCResult::Type::NUM, "height", "The block height (index) of the returned statistics"},1069{RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at which these statistics are calculated"},1070{RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs"},1071{RPCResult::Type::NUM, "bogosize", "Database-independent, meaningless metric indicating the UTXO set size"},1072{RPCResult::Type::STR_HEX, "hash_serialized_3", /*optional=*/true, "The serialized hash (only present if 'hash_serialized_3' hash_type is chosen)"},1073{RPCResult::Type::STR_HEX, "muhash", /*optional=*/true, "The serialized hash (only present if 'muhash' hash_type is chosen)"},1074{RPCResult::Type::NUM, "transactions", /*optional=*/true, "The number of transactions with unspent outputs (not available when coinstatsindex is used)"},1075{RPCResult::Type::NUM, "disk_size", /*optional=*/true, "The estimated size of the chainstate on disk (not available when coinstatsindex is used)"},1076{RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of coins in the UTXO set"},1077{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)"},1078{RPCResult::Type::OBJ, "block_info", /*optional=*/true, "Info on amounts in the block at this block height (only available if coinstatsindex is used)",1079{1080{RPCResult::Type::STR_AMOUNT, "prevout_spent", "Total amount of all prevouts spent in this block"},1081{RPCResult::Type::STR_AMOUNT, "coinbase", "Coinbase subsidy amount of this block"},1082{RPCResult::Type::STR_AMOUNT, "new_outputs_ex_coinbase", "Total amount of new outputs created by this block"},1083{RPCResult::Type::STR_AMOUNT, "unspendable", "Total amount of unspendable outputs created in this block"},1084{RPCResult::Type::OBJ, "unspendables", "Detailed view of the unspendable categories",1085{1086{RPCResult::Type::STR_AMOUNT, "genesis_block", "The unspendable amount of the Genesis block subsidy"},1087{RPCResult::Type::STR_AMOUNT, "bip30", "Transactions overridden by duplicates (no longer possible with BIP30)"},1088{RPCResult::Type::STR_AMOUNT, "scripts", "Amounts sent to scripts that are unspendable (for example OP_RETURN outputs)"},1089{RPCResult::Type::STR_AMOUNT, "unclaimed_rewards", "Fee rewards that miners did not claim in their coinbase transaction"},1090}}1091}},1092}},1093RPCExamples{1094HelpExampleCli("gettxoutsetinfo", "") +1095HelpExampleCli("gettxoutsetinfo", R"("none")") +1096HelpExampleCli("gettxoutsetinfo", R"("none" 1000)") +1097HelpExampleCli("gettxoutsetinfo", R"("none" '"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"')") +1098HelpExampleCli("-named gettxoutsetinfo", R"(hash_type='muhash' use_index='false')") +1099HelpExampleRpc("gettxoutsetinfo", "") +1100HelpExampleRpc("gettxoutsetinfo", R"("none")") +1101HelpExampleRpc("gettxoutsetinfo", R"("none", 1000)") +1102HelpExampleRpc("gettxoutsetinfo", R"("none", "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09")")1103},1104[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue1105{1106UniValue ret(UniValue::VOBJ);1108const CoinStatsHashType hash_type{ParseHashType(self.Arg<std::string_view>("hash_type"))};1109bool index_requested = request.params[2].isNull() || request.params[2].get_bool();1111NodeContext& node = EnsureAnyNodeContext(request.context);1112ChainstateManager& chainman = EnsureChainman(node);1113Chainstate& active_chainstate = chainman.ActiveChainstate();1114active_chainstate.ForceFlushStateToDisk(/*wipe_cache=*/false);1116const CCoinsViewDB& coins_view{WITH_LOCK(::cs_main, return active_chainstate.CoinsDB())};1117BlockManager& blockman{active_chainstate.m_blockman};1119const CBlockIndex* pindex{nullptr};1120if (!request.params[1].isNull()) {1121if (!g_coin_stats_index) {1122throw JSONRPCError(RPC_INVALID_PARAMETER, "Querying specific block heights requires coinstatsindex");1123}1125if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {1126throw JSONRPCError(RPC_INVALID_PARAMETER, "hash_serialized_3 hash type cannot be queried for a specific block");1127}1129if (!index_requested) {1130throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot set use_index to false when querying for a specific block");1131}1132pindex = ParseHashOrHeight(request.params[1], chainman);1133}1135if (index_requested && g_coin_stats_index) {1136if (!g_coin_stats_index->BlockUntilSyncedToCurrentChain()) {1137const IndexSummary summary{g_coin_stats_index->GetSummary()};1139// If a specific block was requested and the index has already synced past that height, we can return the1140// data already even though the index is not fully synced yet.1141if (pindex && pindex->nHeight > summary.best_block_height) {1142throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to get data because coinstatsindex is still syncing. Current height: %d", summary.best_block_height));1143}1144}1145}1147const std::optional<CCoinsStats> maybe_stats = GetUTXOStats(coins_view, blockman, hash_type, node.rpc_interruption_point, pindex, index_requested);1148if (maybe_stats.has_value()) {1149const CCoinsStats& stats = maybe_stats.value();1150ret.pushKV("height", stats.nHeight);1151ret.pushKV("bestblock", stats.hashBlock.GetHex());1152ret.pushKV("txouts", stats.nTransactionOutputs);1153ret.pushKV("bogosize", stats.nBogoSize);1154if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {1155ret.pushKV("hash_serialized_3", stats.hashSerialized.GetHex());1156}1157if (hash_type == CoinStatsHashType::MUHASH) {1158ret.pushKV("muhash", stats.hashSerialized.GetHex());1159}1160CHECK_NONFATAL(stats.total_amount.has_value());1161ret.pushKV("total_amount", ValueFromAmount(stats.total_amount.value()));1162if (!stats.index_used) {1163ret.pushKV("transactions", stats.nTransactions);1164ret.pushKV("disk_size", stats.nDiskSize);1165} else {1166CCoinsStats prev_stats{};1167if (stats.nHeight > 0) {1168const CBlockIndex& block_index = *CHECK_NONFATAL(WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(stats.hashBlock)));1169const std::optional<CCoinsStats> maybe_prev_stats = GetUTXOStats(coins_view, blockman, hash_type, node.rpc_interruption_point, block_index.pprev, index_requested);1170if (!maybe_prev_stats) {1171throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");1172}1173prev_stats = maybe_prev_stats.value();1174}1176CAmount block_total_unspendable_amount = stats.total_unspendables_genesis_block +1177stats.total_unspendables_bip30 +1178stats.total_unspendables_scripts +1179stats.total_unspendables_unclaimed_rewards;1180CAmount prev_block_total_unspendable_amount = prev_stats.total_unspendables_genesis_block +1181prev_stats.total_unspendables_bip30 +1182prev_stats.total_unspendables_scripts +1183prev_stats.total_unspendables_unclaimed_rewards;1185ret.pushKV("total_unspendable_amount", ValueFromAmount(block_total_unspendable_amount));1187UniValue block_info(UniValue::VOBJ);1188// These per-block values should fit uint64 under normal circumstances1189arith_uint256 diff_prevout = stats.total_prevout_spent_amount - prev_stats.total_prevout_spent_amount;1190arith_uint256 diff_coinbase = stats.total_coinbase_amount - prev_stats.total_coinbase_amount;1191arith_uint256 diff_outputs = stats.total_new_outputs_ex_coinbase_amount - prev_stats.total_new_outputs_ex_coinbase_amount;1192CAmount prevout_amount = static_cast<CAmount>(diff_prevout.GetLow64());1193CAmount coinbase_amount = static_cast<CAmount>(diff_coinbase.GetLow64());1194CAmount outputs_amount = static_cast<CAmount>(diff_outputs.GetLow64());1195block_info.pushKV("prevout_spent", ValueFromAmount(prevout_amount));1196block_info.pushKV("coinbase", ValueFromAmount(coinbase_amount));1197block_info.pushKV("new_outputs_ex_coinbase", ValueFromAmount(outputs_amount));1198block_info.pushKV("unspendable", ValueFromAmount(block_total_unspendable_amount - prev_block_total_unspendable_amount));1200UniValue unspendables(UniValue::VOBJ);1201unspendables.pushKV("genesis_block", ValueFromAmount(stats.total_unspendables_genesis_block - prev_stats.total_unspendables_genesis_block));1202unspendables.pushKV("bip30", ValueFromAmount(stats.total_unspendables_bip30 - prev_stats.total_unspendables_bip30));1203unspendables.pushKV("scripts", ValueFromAmount(stats.total_unspendables_scripts - prev_stats.total_unspendables_scripts));1204unspendables.pushKV("unclaimed_rewards", ValueFromAmount(stats.total_unspendables_unclaimed_rewards - prev_stats.total_unspendables_unclaimed_rewards));1205block_info.pushKV("unspendables", std::move(unspendables));1207ret.pushKV("block_info", std::move(block_info));1208}1209} else {1210throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");1211}1212return ret;1213},1214};1215}1217static RPCMethod gettxout()1218{1219return RPCMethod{1220"gettxout",1221"Returns details about an unspent transaction output.\n",1222{1223{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},1224{"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},1225{"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."},1226},1227{1228RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "", ""},1229RPCResult{"Otherwise", RPCResult::Type::OBJ, "", "", {1230{RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},1231{RPCResult::Type::NUM, "confirmations", "The number of confirmations"},1232{RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT},1233{RPCResult::Type::OBJ, "scriptPubKey", "", {1234{RPCResult::Type::STR, "asm", "Disassembly of the output script"},1235{RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},1236{RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"},1237{RPCResult::Type::STR, "type", "The type, eg pubkeyhash"},1238{RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},1239}},1240{RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},1241}},1242},1243RPCExamples{1244"\nGet unspent transactions\n"1245+ HelpExampleCli("listunspent", "") +1246"\nView the details\n"1247+ HelpExampleCli("gettxout", "\"txid\" 1") +1248"\nAs a JSON-RPC call\n"1249+ HelpExampleRpc("gettxout", "\"txid\", 1")1250},