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.
1// Copyright (c) 2022-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <kernel/coinstats.h>7#include <chain.h>8#include <coins.h>9#include <crypto/muhash.h>10#include <hash.h>11#include <node/blockstorage.h>12#include <primitives/transaction.h>13#include <script/script.h>14#include <span.h>15#include <streams.h>16#include <sync.h>17#include <txdb.h>18#include <uint256.h>19#include <util/check.h>20#include <util/log.h>21#include <util/overflow.h>22#include <validation.h>24#include <cstddef>25#include <map>26#include <memory>27#include <utility>29namespace kernel {31CCoinsStats::CCoinsStats(int block_height, const uint256& block_hash)32: nHeight(block_height),33hashBlock(block_hash) {}35// Database-independent metric indicating the UTXO set size36uint64_t GetBogoSize(const CScript& script_pub_key)37{38return 32 /* txid */ +394 /* vout index */ +404 /* height + coinbase */ +418 /* amount */ +422 /* scriptPubKey len */ +43script_pub_key.size() /* scriptPubKey */;44}46template <typename T>47static void TxOutSer(T& ss, const COutPoint& outpoint, const Coin& coin)48{49ss << outpoint;50ss << ((uint32_t{coin.nHeight} << 1) | uint32_t{coin.fCoinBase});51ss << coin.out;52}54static void ApplyCoinHash(HashWriter& ss, const COutPoint& outpoint, const Coin& coin)55{56TxOutSer(ss, outpoint, coin);57}59void ApplyCoinHash(MuHash3072& muhash, const COutPoint& outpoint, const Coin& coin)60{61DataStream ss{};62TxOutSer(ss, outpoint, coin);63muhash.Insert(MakeUCharSpan(ss));64}66void RemoveCoinHash(MuHash3072& muhash, const COutPoint& outpoint, const Coin& coin)67{68DataStream ss{};69TxOutSer(ss, outpoint, coin);70muhash.Remove(MakeUCharSpan(ss));71}73static void ApplyCoinHash(std::nullptr_t, const COutPoint& outpoint, const Coin& coin) {}75//! Warning: be very careful when changing this! assumeutxo and UTXO snapshot76//! validation commitments are reliant on the hash constructed by this77//! function.78//!79//! If the construction of this hash is changed, it will invalidate80//! existing UTXO snapshots. This will not result in any kind of consensus81//! failure, but it will force clients that were expecting to make use of82//! assumeutxo to do traditional IBD instead.83//!84//! It is also possible, though very unlikely, that a change in this85//! construction could cause a previously invalid (and potentially malicious)86//! UTXO snapshot to be considered valid.87template <typename T>88static void ApplyHash(T& hash_obj, const Txid& hash, const std::map<uint32_t, Coin>& outputs)89{90for (auto it = outputs.begin(); it != outputs.end(); ++it) {91COutPoint outpoint = COutPoint(hash, it->first);92Coin coin = it->second;93ApplyCoinHash(hash_obj, outpoint, coin);94}95}97static void ApplyStats(CCoinsStats& stats, const std::map<uint32_t, Coin>& outputs)98{99assert(!outputs.empty());100stats.nTransactions++;101for (auto it = outputs.begin(); it != outputs.end(); ++it) {102stats.nTransactionOutputs++;103if (stats.total_amount.has_value()) {104stats.total_amount = CheckedAdd(*stats.total_amount, it->second.out.nValue);105}106stats.nBogoSize += GetBogoSize(it->second.out.scriptPubKey);107}108}110//! Calculate statistics about the unspent transaction output set111template <typename T>112static std::optional<CCoinsStats> ComputeUTXOStats(T hash_obj, const CCoinsViewDB& view, node::BlockManager& blockman, const std::function<void()>& interruption_point)113{114std::unique_ptr<CCoinsViewCursor> pcursor;115CBlockIndex* pindex;116{117LOCK(::cs_main);118pcursor = view.Cursor();119pindex = blockman.LookupBlockIndex(pcursor->GetBestBlock());120}121CCoinsStats stats{Assert(pindex)->nHeight, pindex->GetBlockHash()};123Txid prevkey;124std::map<uint32_t, Coin> outputs;125while (pcursor->Valid()) {126if (interruption_point) interruption_point();127COutPoint key;128Coin coin;129if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {130if (!outputs.empty() && key.hash != prevkey) {131ApplyStats(stats, outputs);132ApplyHash(hash_obj, prevkey, outputs);133outputs.clear();134}135prevkey = key.hash;136outputs[key.n] = std::move(coin);137stats.coins_count++;138} else {139LogError("%s: unable to read value\n", __func__);140return std::nullopt;141}142pcursor->Next();143}144if (!outputs.empty()) {145ApplyStats(stats, outputs);146ApplyHash(hash_obj, prevkey, outputs);147}149FinalizeHash(hash_obj, stats);151stats.nDiskSize = view.EstimateSize();152return stats;153}155std::optional<CCoinsStats> ComputeUTXOStats(CoinStatsHashType hash_type, const CCoinsViewDB& view, node::BlockManager& blockman, const std::function<void()>& interruption_point)156{157return [&]() -> std::optional<CCoinsStats> {158switch (hash_type) {159case(CoinStatsHashType::HASH_SERIALIZED): {160HashWriter ss{};161return ComputeUTXOStats(ss, view, blockman, interruption_point);162}163case(CoinStatsHashType::MUHASH): {164MuHash3072 muhash;165return ComputeUTXOStats(muhash, view, blockman, interruption_point);166}167case(CoinStatsHashType::NONE): {168return ComputeUTXOStats(nullptr, view, blockman, interruption_point);169}170} // no default case, so the compiler can warn about missing cases171assert(false);172}();173}175static void FinalizeHash(HashWriter& ss, CCoinsStats& stats)176{177stats.hashSerialized = ss.GetHash();178}179static void FinalizeHash(MuHash3072& muhash, CCoinsStats& stats)180{181uint256 out;182muhash.Finalize(out);183stats.hashSerialized = out;184}185static void FinalizeHash(std::nullptr_t, CCoinsStats& stats) {}187} // namespace kernel