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.
1// Copyright (c) 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 <txgraph.h>7#include <cluster_linearize.h>8#include <random.h>9#include <util/bitset.h>10#include <util/check.h>11#include <util/feefrac.h>12#include <util/vector.h>14#include <compare>15#include <functional>16#include <memory>17#include <ranges>18#include <set>19#include <span>20#include <unordered_set>21#include <utility>23namespace {25using namespace cluster_linearize;27/** The maximum number of levels a TxGraph can have (0 = main, 1 = staging). */28static constexpr int MAX_LEVELS{2};30// Forward declare the TxGraph implementation class.31class TxGraphImpl;33/** Position of a DepGraphIndex within a Cluster::m_linearization. */34using LinearizationIndex = uint32_t;35/** Position of a Cluster within TxGraphImpl::ClusterSet::m_clusters. */36using ClusterSetIndex = uint32_t;38/** Quality levels for cached cluster linearizations. */39enum class QualityLevel40{41/** This is a singleton cluster consisting of a transaction that individually exceeds the42* cluster size limit. It cannot be merged with anything. */43OVERSIZED_SINGLETON,44/** This cluster may have multiple disconnected components, which are all NEEDS_FIX. */45NEEDS_SPLIT_FIX,46/** This cluster may have multiple disconnected components, which are all NEEDS_RELINEARIZE. */47NEEDS_SPLIT,48/** This cluster may be non-topological. */49NEEDS_FIX,50/** This cluster has undergone changes that warrant re-linearization. */51NEEDS_RELINEARIZE,52/** The minimal level of linearization has been performed, but it is not known to be optimal. */53ACCEPTABLE,54/** The linearization is known to be optimal. */55OPTIMAL,56/** This cluster is not registered in any ClusterSet::m_clusters.57* This must be the last entry in QualityLevel as ClusterSet::m_clusters is sized using it. */58NONE,59};61/** Information about a transaction inside TxGraphImpl::Trim. */62struct TrimTxData63{64// Fields populated by Cluster::AppendTrimData(). These are immutable after TrimTxData65// construction.66/** Chunk feerate for this transaction. */67FeePerWeight m_chunk_feerate;68/** GraphIndex of the transaction. */69TxGraph::GraphIndex m_index;70/** Size of the transaction. */71uint32_t m_tx_size;73// Fields only used internally by TxGraphImpl::Trim():74/** Number of unmet dependencies this transaction has. -1 if the transaction is included. */75uint32_t m_deps_left;76/** Number of dependencies that apply to this transaction as child. */77uint32_t m_parent_count;78/** Where in deps_by_child those dependencies begin. */79uint32_t m_parent_offset;80/** Number of dependencies that apply to this transaction as parent. */81uint32_t m_children_count;82/** Where in deps_by_parent those dependencies begin. */83uint32_t m_children_offset;85// Fields only used internally by TxGraphImpl::Trim()'s union-find implementation, and only for86// transactions that are definitely included or definitely rejected.87//88// As transactions get processed, they get organized into trees which form partitions89// representing the would-be clusters up to that point. The root of each tree is a90// representative for that partition. See91// https://en.wikipedia.org/wiki/Disjoint-set_data_structure.92//93/** Pointer to another TrimTxData, towards the root of the tree. If this is a root, m_uf_parent94* is equal to this itself. */95TrimTxData* m_uf_parent;96/** If this is a root, the total number of transactions in the partition. */97uint32_t m_uf_count;98/** If this is a root, the total size of transactions in the partition. */99uint64_t m_uf_size;100};102/** A grouping of connected transactions inside a TxGraphImpl::ClusterSet. */103class Cluster104{105friend class TxGraphImpl;106friend class BlockBuilderImpl;108protected:109using GraphIndex = TxGraph::GraphIndex;110using SetType = BitSet<MAX_CLUSTER_COUNT_LIMIT>;111/** The quality level of m_linearization. */112QualityLevel m_quality{QualityLevel::NONE};113/** Which position this Cluster has in TxGraphImpl::ClusterSet::m_clusters[m_quality]. */114ClusterSetIndex m_setindex{ClusterSetIndex(-1)};115/** Sequence number for this Cluster (for tie-breaking comparison between equal-chunk-feerate116transactions in distinct clusters). */117uint64_t m_sequence;119explicit Cluster(uint64_t sequence) noexcept : m_sequence(sequence) {}121public:122// Provide virtual destructor, for safe polymorphic usage inside std::unique_ptr.123virtual ~Cluster() = default;125// Cannot move or copy (would invalidate Cluster* in Locator and ClusterSet). */126Cluster(const Cluster&) = delete;127Cluster& operator=(const Cluster&) = delete;128Cluster(Cluster&&) = delete;129Cluster& operator=(Cluster&&) = delete;131// Generic helper functions.133/** Whether the linearization of this Cluster can be exposed. */134bool IsAcceptable() const noexcept135{136return m_quality == QualityLevel::ACCEPTABLE || m_quality == QualityLevel::OPTIMAL;137}138/** Whether the linearization of this Cluster is topological. */139bool IsTopological() const noexcept140{141return m_quality != QualityLevel::NEEDS_FIX && m_quality != QualityLevel::NEEDS_SPLIT_FIX;142}143/** Whether the linearization of this Cluster is optimal. */144bool IsOptimal() const noexcept145{146return m_quality == QualityLevel::OPTIMAL;147}148/** Whether this cluster is oversized. Note that no changes that can cause oversizedness are149* ever applied, so the only way a materialized Cluster object can be oversized is by being150* an individually oversized transaction singleton. */151bool IsOversized() const noexcept { return m_quality == QualityLevel::OVERSIZED_SINGLETON; }152/** Whether this cluster requires splitting. */153bool NeedsSplitting() const noexcept154{155return m_quality == QualityLevel::NEEDS_SPLIT || m_quality == QualityLevel::NEEDS_SPLIT_FIX;156}158/** Get the smallest number of transactions this Cluster is intended for. */159virtual DepGraphIndex GetMinIntendedTxCount() const noexcept = 0;160/** Get the maximum number of transactions this Cluster supports. */161virtual DepGraphIndex GetMaxTxCount() const noexcept = 0;162/** Total memory usage currently for this Cluster, including all its dynamic memory, plus Cluster163* structure itself, and ClusterSet::m_clusters entry. */164virtual size_t TotalMemoryUsage() const noexcept = 0;165/** Determine the range of DepGraphIndexes used by this Cluster. */166virtual DepGraphIndex GetDepGraphIndexRange() const noexcept = 0;167/** Get the number of transactions in this Cluster. */168virtual LinearizationIndex GetTxCount() const noexcept = 0;169/** Get the total size of the transactions in this Cluster. */170virtual uint64_t GetTotalTxSize() const noexcept = 0;171/** Given a DepGraphIndex into this Cluster, find the corresponding GraphIndex. */172virtual GraphIndex GetClusterEntry(DepGraphIndex index) const noexcept = 0;173/** Append a transaction with given GraphIndex at the end of this Cluster and its174* linearization. Return the DepGraphIndex it was placed at. */175virtual DepGraphIndex AppendTransaction(GraphIndex graph_idx, FeePerWeight feerate) noexcept = 0;176/** Add dependencies to a given child in this cluster. */177virtual void AddDependencies(SetType parents, DepGraphIndex child) noexcept = 0;178/** Invoke visit1_fn for each transaction in the cluster, in linearization order, then179* visit2_fn in the same order, then wipe this Cluster. */180virtual void ExtractTransactions(const std::function<void (DepGraphIndex, GraphIndex, FeePerWeight)>& visit1_fn, const std::function<void (DepGraphIndex, GraphIndex, SetType)>& visit2_fn) noexcept = 0;181/** Figure out what level this Cluster exists at in the graph. In most cases this is known by182* the caller already (see all "int level" arguments below), but not always. */183virtual int GetLevel(const TxGraphImpl& graph) const noexcept = 0;184/** Only called by TxGraphImpl::SwapIndexes. */185virtual void UpdateMapping(DepGraphIndex cluster_idx, GraphIndex graph_idx) noexcept = 0;186/** Push changes to Cluster and its linearization to the TxGraphImpl Entry objects. Main chunk187* information is computed if the cluster is acceptable, or when rename is set. Rename is used188* when called from Compact, to recompute after GraphIndexes may have changed; in this case,189* no chunk index objects are removed or created either. */190virtual void Updated(TxGraphImpl& graph, int level, bool rename) noexcept = 0;191/** Remove all chunk index entries for this cluster (level=0 only). */192virtual void RemoveChunkData(TxGraphImpl& graph) noexcept = 0;193/** Create a copy of this Cluster in staging, returning a pointer to it (used by PullIn). */194virtual Cluster* CopyToStaging(TxGraphImpl& graph) const noexcept = 0;195/** Get the list of Clusters in main that conflict with this one (which is assumed to be in staging). */196virtual void GetConflicts(const TxGraphImpl& graph, std::vector<Cluster*>& out) const noexcept = 0;197/** Mark all the Entry objects belonging to this staging Cluster as missing. The Cluster must be198* deleted immediately after. */199virtual void MakeStagingTransactionsMissing(TxGraphImpl& graph) noexcept = 0;200/** Remove all transactions from a (non-empty) Cluster. */201virtual void Clear(TxGraphImpl& graph, int level) noexcept = 0;202/** Change a Cluster's level from 1 (staging) to 0 (main). */203virtual void MoveToMain(TxGraphImpl& graph) noexcept = 0;204/** Minimize this Cluster's memory usage. */205virtual void Compact() noexcept = 0;207// Functions that implement the Cluster-specific side of internal TxGraphImpl mutations.209/** Apply all removals from the front of to_remove that apply to this Cluster, popping them210* off. There must be at least one such entry. */211virtual void ApplyRemovals(TxGraphImpl& graph, int level, std::span<GraphIndex>& to_remove) noexcept = 0;212/** Split this cluster (must have a NEEDS_SPLIT* quality). Returns whether to delete this213* Cluster afterwards. */214[[nodiscard]] virtual bool Split(TxGraphImpl& graph, int level) noexcept = 0;215/** Move all transactions from cluster to *this (as separate components). */216virtual void Merge(TxGraphImpl& graph, int level, Cluster& cluster) noexcept = 0;217/** Given a span of (parent, child) pairs that all belong to this Cluster, apply them. */218virtual void ApplyDependencies(TxGraphImpl& graph, int level, std::span<std::pair<GraphIndex, GraphIndex>> to_apply) noexcept = 0;219/** Improve the linearization of this Cluster. Returns how much work was performed and whether220* the Cluster's QualityLevel improved as a result. */221virtual std::pair<uint64_t, bool> Relinearize(TxGraphImpl& graph, int level, uint64_t max_cost) noexcept = 0;222/** For every chunk in the cluster, append its FeeFrac to ret. */223virtual void AppendChunkFeerates(std::vector<FeeFrac>& ret) const noexcept = 0;224/** Add a TrimTxData entry (filling m_chunk_feerate, m_index, m_tx_size) for every225* transaction in the Cluster to ret. Implicit dependencies between consecutive transactions226* in the linearization are added to deps. Return the Cluster's total transaction size. */227virtual uint64_t AppendTrimData(std::vector<TrimTxData>& ret, std::vector<std::pair<GraphIndex, GraphIndex>>& deps) const noexcept = 0;229// Functions that implement the Cluster-specific side of public TxGraph functions.231/** Process elements from the front of args that apply to this cluster, and append Refs for the232* union of their ancestors to output. */233virtual void GetAncestorRefs(const TxGraphImpl& graph, std::span<std::pair<Cluster*, DepGraphIndex>>& args, std::vector<TxGraph::Ref*>& output) noexcept = 0;234/** Process elements from the front of args that apply to this cluster, and append Refs for the235* union of their descendants to output. */236virtual void GetDescendantRefs(const TxGraphImpl& graph, std::span<std::pair<Cluster*, DepGraphIndex>>& args, std::vector<TxGraph::Ref*>& output) noexcept = 0;237/** Populate range with refs for the transactions in this Cluster's linearization, from238* position start_pos until start_pos+range.size()-1, inclusive. Returns whether that239* range includes the last transaction in the linearization. */240virtual bool GetClusterRefs(TxGraphImpl& graph, std::span<TxGraph::Ref*> range, LinearizationIndex start_pos) noexcept = 0;241/** Get the individual transaction feerate of a Cluster element. */242virtual FeePerWeight GetIndividualFeerate(DepGraphIndex idx) noexcept = 0;243/** Modify the fee of a Cluster element. */244virtual void SetFee(TxGraphImpl& graph, int level, DepGraphIndex idx, int64_t fee) noexcept = 0;246// Debugging functions.248virtual void SanityCheck(const TxGraphImpl& graph, int level) const = 0;249};
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.