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.
252/** Hash an outpoint as its txid jumbo block followed by the zero-extended index as one normal block. */253size_t operator()(const COutPoint& id) const noexcept254{255return m_hasher.Hash(id.hash.ToUint256(), uint64_t{id.n});256}257};259/**260* PoolAllocator's MAX_BLOCK_SIZE_BYTES parameter here uses sizeof the data, and adds the size261* of 4 pointers. We do not know the exact node size used in the std::unordered_node implementation262* because it is implementation defined. Most implementations have an overhead of 1 or 2 pointers,263* so nodes can be connected in a linked list, and in some cases the hash value is stored as well.264* Using an additional sizeof(void*)*4 for MAX_BLOCK_SIZE_BYTES should thus be sufficient so that265* all implementations can allocate the nodes from the PoolAllocator.266*/267using CCoinsMap = std::unordered_map<COutPoint,268CCoinsCacheEntry,269SaltedCoinsCacheHasher,270std::equal_to<COutPoint>,271PoolAllocator<CoinsCachePair,272sizeof(CoinsCachePair) + sizeof(void*) * 4>>;274using CCoinsMapMemoryResource = CCoinsMap::allocator_type::ResourceType;276/** Cursor for iterating over CoinsView state */277class CCoinsViewCursor278{279public:280CCoinsViewCursor(const uint256& in_block_hash) : block_hash(in_block_hash) {}281virtual ~CCoinsViewCursor() = default;283virtual bool GetKey(COutPoint &key) const = 0;284virtual bool GetValue(Coin &coin) const = 0;286virtual bool Valid() const = 0;287virtual void Next() = 0;289//! Get best block at the time this cursor was created290const uint256& GetBestBlock() const { return block_hash; }291private:292uint256 block_hash;293};295/**296* Cursor for iterating over the linked list of flagged entries in CCoinsViewCache.297*298* This is a helper struct to encapsulate the diverging logic between a non-erasing299* CCoinsViewCache::Sync and an erasing CCoinsViewCache::Flush. This allows the receiver300* of CCoinsView::BatchWrite to iterate through the flagged entries without knowing301* the caller's intent.302*303* However, the receiver can still call CoinsViewCacheCursor::WillErase to see if the304* caller will erase the entry after BatchWrite returns. If so, the receiver can305* perform optimizations such as moving the coin out of the CCoinsCachEntry instead306* of copying it.307*/308struct CoinsViewCacheCursor309{310//! If will_erase is not set, iterating through the cursor will erase spent coins from the map,311//! and other coins will be unflagged (removing them from the linked list).312//! If will_erase is set, the underlying map and linked list will not be modified,313//! as the caller is expected to wipe the entire map anyway.314//! This is an optimization compared to erasing all entries as the cursor iterates them when will_erase is set.315//! Calling CCoinsMap::clear() afterwards is faster because a CoinsCachePair cannot be coerced back into a316//! CCoinsMap::iterator to be erased, and must therefore be looked up again by key in the CCoinsMap before being erased.317CoinsViewCacheCursor(size_t& dirty_count LIFETIMEBOUND,318CoinsCachePair& sentinel LIFETIMEBOUND,319CCoinsMap& map LIFETIMEBOUND,320bool will_erase) noexcept321: m_dirty_count(dirty_count), m_sentinel(sentinel), m_map(map), m_will_erase(will_erase) {}323inline CoinsCachePair* Begin() const noexcept { return m_sentinel.second.Next(); }324inline CoinsCachePair* End() const noexcept { return &m_sentinel; }326//! Return the next entry after current, possibly erasing current327inline CoinsCachePair* NextAndMaybeErase(CoinsCachePair& current) noexcept328{329const auto next_entry{current.second.Next()};330Assume(TrySub(m_dirty_count, current.second.IsDirty()));331// If we are not going to erase the cache, we must still erase spent entries.332// Otherwise, clear the state of the entry.333if (!m_will_erase) {334if (current.second.coin.IsSpent()) {335assert(current.second.coin.DynamicMemoryUsage() == 0); // scriptPubKey was already cleared in SpendCoin336m_map.erase(current.first);337} else {338current.second.SetClean();339}340}341return next_entry;342}344inline bool WillErase(CoinsCachePair& current) const noexcept { return m_will_erase || current.second.coin.IsSpent(); }345size_t GetDirtyCount() const noexcept { return m_dirty_count; }346size_t GetTotalCount() const noexcept { return m_map.size(); }347private:348size_t& m_dirty_count;349CoinsCachePair& m_sentinel;350CCoinsMap& m_map;351bool m_will_erase;352};354/** Pure abstract view on the open txout dataset. */355class CCoinsView356{357public:358//! As we use CCoinsViews polymorphically, have a virtual destructor359virtual ~CCoinsView() = default;361//! Retrieve the Coin (unspent transaction output) for a given outpoint.362//! May populate the cache. Use PeekCoin() to perform a non-caching lookup.363virtual std::optional<Coin> GetCoin(const COutPoint& outpoint) const = 0;365//! Retrieve the Coin (unspent transaction output) for a given outpoint, without caching results.366//! Does not populate the cache. Use GetCoin() to cache the result.367virtual std::optional<Coin> PeekCoin(const COutPoint& outpoint) const = 0;369//! Just check whether a given outpoint is unspent.370//! May populate the cache. Use PeekCoin() to perform a non-caching lookup.371virtual bool HaveCoin(const COutPoint& outpoint) const = 0;373//! Retrieve the block hash whose state this CCoinsView currently represents374virtual uint256 GetBestBlock() const = 0;376//! Retrieve the range of blocks that may have been only partially written.377//! If the database is in a consistent state, the result is the empty vector.378//! Otherwise, a two-element vector is returned consisting of the new and379//! the old block hash, in that order.380virtual std::vector<uint256> GetHeadBlocks() const = 0;382//! Do a bulk modification (multiple Coin changes + BestBlock change).383//! The passed cursor is used to iterate through the coins.384virtual void BatchWrite(CoinsViewCacheCursor& cursor, const uint256& block_hash) = 0;386//! Estimate database size387virtual size_t EstimateSize() const = 0;388};390/** Noop coins view. */391class CoinsViewEmpty : public CCoinsView392{393protected:394CoinsViewEmpty() = default;396public:397static CoinsViewEmpty& Get();399CoinsViewEmpty(const CoinsViewEmpty&) = delete;400CoinsViewEmpty& operator=(const CoinsViewEmpty&) = delete;402std::optional<Coin> GetCoin(const COutPoint&) const override { return {}; }403std::optional<Coin> PeekCoin(const COutPoint& outpoint) const override { return GetCoin(outpoint); }404bool HaveCoin(const COutPoint& outpoint) const override { return !!GetCoin(outpoint); }405uint256 GetBestBlock() const override { return {}; }406std::vector<uint256> GetHeadBlocks() const override { return {}; }407void BatchWrite(CoinsViewCacheCursor& cursor, const uint256&) override408{409for (auto it{cursor.Begin()}; it != cursor.End(); it = cursor.NextAndMaybeErase(*it)) { }410}411size_t EstimateSize() const override { return 0; }412};414/** CCoinsView backed by another CCoinsView */415class CCoinsViewBacked : public CCoinsView416{417protected:418CCoinsView* base;420public:421explicit CCoinsViewBacked(CCoinsView* in_view) : base{Assert(in_view)} {}423void SetBackend(CCoinsView& in_view) { base = &in_view; }425std::optional<Coin> GetCoin(const COutPoint& outpoint) const override { return base->GetCoin(outpoint); }426std::optional<Coin> PeekCoin(const COutPoint& outpoint) const override { return base->PeekCoin(outpoint); }427bool HaveCoin(const COutPoint& outpoint) const override { return base->HaveCoin(outpoint); }428uint256 GetBestBlock() const override { return base->GetBestBlock(); }429std::vector<uint256> GetHeadBlocks() const override { return base->GetHeadBlocks(); }430void BatchWrite(CoinsViewCacheCursor& cursor, const uint256& block_hash) override { base->BatchWrite(cursor, block_hash); }431size_t EstimateSize() const override { return base->EstimateSize(); }432};435/** CCoinsView that adds a memory cache for transactions to another CCoinsView */436class CCoinsViewCache : public CCoinsViewBacked437{438private:439const bool m_deterministic;441//! Force a reallocation of the cache map. This is required when downsizing442//! the cache because the map's allocator may be hanging onto a lot of443//! memory despite having called .clear().444//!445//! See: https://stackoverflow.com/questions/42114044/how-to-release-unordered-map-memory446void ReallocateCache();448/**449* @note this is marked const, but may actually append to `cacheCoins`, increasing450* memory usage.451*/452CCoinsMap::iterator FetchCoin(const COutPoint &outpoint) const;454protected:455/**456* Make mutable so that we can "fill the cache" even from Get-methods457* declared as "const".458*/459mutable uint256 m_block_hash;460mutable CCoinsMapMemoryResource m_cache_coins_memory_resource{};461/* The starting sentinel of the flagged entry circular doubly linked list. */462mutable CoinsCachePair m_sentinel;463mutable CCoinsMap cacheCoins;465/* Cached dynamic memory usage for the inner Coin objects. */466mutable size_t cachedCoinsUsage{0};467/* Running count of dirty Coin cache entries. */468mutable size_t m_dirty_count{0};470/**471* Discard all modifications made to this cache without flushing to the base view.472* This can be used to efficiently reuse a cache instance across multiple operations.473*/474virtual void Reset() noexcept;476/* Fetch the coin from base. Used for cache misses in FetchCoin. */477virtual std::optional<Coin> FetchCoinFromBase(const COutPoint& outpoint) const;479public:480CCoinsViewCache(CCoinsView* in_base, bool deterministic = false);482/**483* By deleting the copy constructor, we prevent accidentally using it when one intends to create a cache on top of a base cache.484*/485CCoinsViewCache(const CCoinsViewCache &) = delete;487// Standard CCoinsView methods488std::optional<Coin> GetCoin(const COutPoint& outpoint) const override;489std::optional<Coin> PeekCoin(const COutPoint& outpoint) const override;490bool HaveCoin(const COutPoint& outpoint) const override;491uint256 GetBestBlock() const override;492void SetBestBlock(const uint256& block_hash);493void BatchWrite(CoinsViewCacheCursor& cursor, const uint256& block_hash) override;495/**496* Check if we have the given utxo already loaded in this cache.497* The semantics are the same as HaveCoin(), but no calls to498* the backing CCoinsView are made.499*/500bool HaveCoinInCache(const COutPoint &outpoint) const;