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.
501if (feerate_cmp != 0) return feerate_cmp;502// Compare equal-feerate chunk prefix size for comparing equal chunk feerates. This does two503// things: it distinguishes equal-feerate chunks within the same cluster (because later504// ones will always have a higher prefix size), and it may distinguish equal-feerate chunks505// from distinct clusters.506if (entry_a.m_main_equal_feerate_chunk_prefix_size != entry_b.m_main_equal_feerate_chunk_prefix_size) {507return entry_a.m_main_equal_feerate_chunk_prefix_size <=> entry_b.m_main_equal_feerate_chunk_prefix_size;508}509// Compare by maximum m_fallback_order element to order equal-feerate chunks in distinct510// clusters, when the equal-feerate-prefix size is also the same.511const auto& locator_a = entry_a.m_locator[0];512const auto& locator_b = entry_b.m_locator[0];513Assume(locator_a.IsPresent() && locator_b.IsPresent());514if (locator_a.cluster != locator_b.cluster) {515auto fallback_cmp = m_fallback_order(*m_entries[entry_a.m_main_max_chunk_fallback].m_ref,516*m_entries[entry_b.m_main_max_chunk_fallback].m_ref);517if (fallback_cmp != 0) return fallback_cmp;518// This shouldn't be reachable as m_fallback_order defines a strong ordering.519Assume(false);520return CompareClusters(locator_a.cluster, locator_b.cluster);521}522// Within a single chunk, sort by position within cluster linearization.523return entry_a.m_main_lin_index <=> entry_b.m_main_lin_index;524}526/** Comparator for ChunkData objects in mining order. */527class ChunkOrder528{529const TxGraphImpl* const m_graph;530public:531explicit ChunkOrder(const TxGraphImpl* graph) : m_graph(graph) {}533bool operator()(const ChunkData& a, const ChunkData& b) const noexcept534{535return m_graph->CompareMainTransactions(a.m_graph_index, b.m_graph_index) < 0;536}537};539/** Definition for the mining index type. */540using ChunkIndex = std::set<ChunkData, ChunkOrder>;542/** Index of ChunkData objects, indexing the last transaction in each chunk in the main543* graph. */544ChunkIndex m_main_chunkindex;545/** Number of index-observing objects in existence (BlockBuilderImpls). */546size_t m_main_chunkindex_observers{0};547/** Cache of discarded ChunkIndex node handles to reuse, avoiding additional allocation. */548std::vector<ChunkIndex::node_type> m_main_chunkindex_discarded;550/** A Locator that describes whether, where, and in which Cluster an Entry appears.551* Every Entry has MAX_LEVELS locators, as it may appear in one Cluster per level.552*553* Each level of a Locator is in one of three states:554*555* - (P)resent: actually occurs in a Cluster at that level.556*557* - (M)issing:558* - In the main graph: the transaction does not exist in main.559* - In the staging graph: the transaction's existence is the same as in main. If it doesn't560* exist in main, (M) in staging means it does not exist there561* either. If it does exist in main, (M) in staging means the562* cluster it is in has not been modified in staging, and thus the563* transaction implicitly exists in staging too (without explicit564* Cluster object; see PullIn() to create it in staging too).565*566* - (R)emoved: only possible in staging; it means the transaction exists in main, but is567* removed in staging.568*569* The following combinations are possible:570* - (M,M): the transaction doesn't exist in either graph.571* - (P,M): the transaction exists in both, but only exists explicitly in a Cluster object in572* main. Its existence in staging is inherited from main.573* - (P,P): the transaction exists in both, and is materialized in both. Thus, the clusters574* and/or their linearizations may be different in main and staging.575* - (M,P): the transaction is added in staging, and does not exist in main.576* - (P,R): the transaction exists in main, but is removed in staging.577*578* When staging does not exist, only (M,M) and (P,M) are possible.579*/580struct Locator581{582/** Which Cluster the Entry appears in (nullptr = missing). */583Cluster* cluster{nullptr};584/** Where in the Cluster it appears (if cluster == nullptr: 0 = missing, -1 = removed). */585DepGraphIndex index{0};587/** Mark this Locator as missing (= same as lower level, or non-existing if level 0). */588void SetMissing() noexcept { cluster = nullptr; index = 0; }589/** Mark this Locator as removed (not allowed in level 0). */590void SetRemoved() noexcept { cluster = nullptr; index = DepGraphIndex(-1); }591/** Mark this Locator as present, in the specified Cluster. */592void SetPresent(Cluster* c, DepGraphIndex i) noexcept { cluster = c; index = i; }593/** Check if this Locator is missing. */594bool IsMissing() const noexcept { return cluster == nullptr && index == 0; }595/** Check if this Locator is removed. */596bool IsRemoved() const noexcept { return cluster == nullptr && index == DepGraphIndex(-1); }597/** Check if this Locator is present (in some Cluster). */598bool IsPresent() const noexcept { return cluster != nullptr; }599};601/** Internal information about each transaction in a TxGraphImpl. */602struct Entry603{604/** Pointer to the corresponding Ref object if any, or nullptr if unlinked. */605Ref* m_ref{nullptr};606/** Iterator to the corresponding ChunkData, if any, and m_main_chunkindex.end() otherwise.607* This is initialized on construction of the Entry, in AddTransaction. */608ChunkIndex::iterator m_main_chunkindex_iterator;609/** Which Cluster and position therein this Entry appears in. ([0] = main, [1] = staged). */610Locator m_locator[MAX_LEVELS];611/** The chunk feerate of this transaction in main (if present in m_locator[0]). */612FeePerWeight m_main_chunk_feerate;613/** The equal-feerate chunk prefix size of this transaction in main. If the transaction is614* part of chunk C in main, then this gives the sum of the sizes of all chunks in C's615* cluster, whose feerate is equal to that of C, which do not appear after C itself in616* the cluster's linearization.617* This provides a way to sort equal-feerate chunks across clusters, in a way that agrees618* with the within-cluster chunk ordering. */619int32_t m_main_equal_feerate_chunk_prefix_size;620/** The position this transaction has in the main linearization (if present). */621LinearizationIndex m_main_lin_index;622/** Of all transactions within this transaction's chunk in main (if present there), the623* maximal one according to m_fallback_order. */624GraphIndex m_main_max_chunk_fallback = GraphIndex(-1);625};627/** The set of all transactions (in all levels combined). GraphIndex values index into this. */628std::vector<Entry> m_entries;630/** Set of Entries which have no linked Ref anymore. */631std::vector<GraphIndex> m_unlinked;633public:634/** Construct a new TxGraphImpl with the specified limits and fallback order. */635explicit TxGraphImpl(636DepGraphIndex max_cluster_count,637uint64_t max_cluster_size,638uint64_t acceptable_cost,639const std::function<std::strong_ordering(const TxGraph::Ref&, const TxGraph::Ref&)>& fallback_order640) noexcept :641m_max_cluster_count(max_cluster_count),642m_max_cluster_size(max_cluster_size),643m_acceptable_cost(acceptable_cost),644m_fallback_order(fallback_order),645m_main_chunkindex(ChunkOrder(this))646{647Assume(max_cluster_count >= 1);648Assume(max_cluster_count <= MAX_CLUSTER_COUNT_LIMIT);649}651/** Destructor. */652~TxGraphImpl() noexcept;654// Cannot move or copy (would invalidate TxGraphImpl* in Ref, MiningOrder, EvictionOrder).655TxGraphImpl(const TxGraphImpl&) = delete;656TxGraphImpl& operator=(const TxGraphImpl&) = delete;657TxGraphImpl(TxGraphImpl&&) = delete;658TxGraphImpl& operator=(TxGraphImpl&&) = delete;660// Simple helper functions.662/** Swap the Entry referred to by a and the one referred to by b. Gather main clusters to663* update afterwards. */664void SwapIndexes(GraphIndex a, GraphIndex b, std::vector<Cluster*>& affected_main) noexcept;665/** If idx exists in the specified level ClusterSet (explicitly, or in the level below and not666* removed), return the Cluster it is in. Otherwise, return nullptr. */667Cluster* FindCluster(GraphIndex idx, int level) const noexcept { return FindClusterAndLevel(idx, level).first; }668/** Like FindCluster, but also return what level the match was found in (-1 if not found). */669std::pair<Cluster*, int> FindClusterAndLevel(GraphIndex idx, int level) const noexcept;670/** Extract a Cluster from its ClusterSet, and set its quality to QualityLevel::NONE. */671std::unique_ptr<Cluster> ExtractCluster(int level, QualityLevel quality, ClusterSetIndex setindex) noexcept;672/** Delete a Cluster. */673void DeleteCluster(Cluster& cluster, int level) noexcept;674/** Insert a Cluster into its ClusterSet. */675ClusterSetIndex InsertCluster(int level, std::unique_ptr<Cluster>&& cluster, QualityLevel quality) noexcept;676/** Change the QualityLevel of a Cluster (identified by old_quality and old_index). */677void SetClusterQuality(int level, QualityLevel old_quality, ClusterSetIndex old_index, QualityLevel new_quality) noexcept;678/** Get the index of the top level ClusterSet (staging if it exists, main otherwise). */679int GetTopLevel() const noexcept { return m_staging_clusterset.has_value(); }680/** Get the specified level (staging if it exists and level is TOP, main otherwise). */681int GetSpecifiedLevel(Level level) const noexcept { return level == Level::TOP && m_staging_clusterset.has_value(); }682/** Get a reference to the ClusterSet at the specified level (which must exist). */683ClusterSet& GetClusterSet(int level) noexcept;684const ClusterSet& GetClusterSet(int level) const noexcept;685/** Make a transaction not exist at a specified level. It must currently exist there.686* oversized_tx indicates whether the transaction is an individually-oversized one687* (OVERSIZED_SINGLETON). */688void ClearLocator(int level, GraphIndex index, bool oversized_tx) noexcept;689/** Find which Clusters in main conflict with ones in staging. */690std::vector<Cluster*> GetConflicts() const noexcept;691/** Clear an Entry's ChunkData. */692void ClearChunkData(Entry& entry) noexcept;693/** Give an Entry a ChunkData object. */694void CreateChunkData(GraphIndex idx, LinearizationIndex chunk_count) noexcept;695/** Create an empty GenericClusterImpl object. */696std::unique_ptr<GenericClusterImpl> CreateEmptyGenericCluster() noexcept697{698return std::make_unique<GenericClusterImpl>(m_next_sequence_counter++);699}700/** Create an empty SingletonClusterImpl object. */701std::unique_ptr<SingletonClusterImpl> CreateEmptySingletonCluster() noexcept702{703return std::make_unique<SingletonClusterImpl>(m_next_sequence_counter++);704}705/** Create an empty Cluster of the appropriate implementation for the specified (maximum) tx706* count. */707std::unique_ptr<Cluster> CreateEmptyCluster(DepGraphIndex tx_count) noexcept708{709if (tx_count >= SingletonClusterImpl::MIN_INTENDED_TX_COUNT && tx_count <= SingletonClusterImpl::MAX_TX_COUNT) {710return CreateEmptySingletonCluster();711}712if (tx_count >= GenericClusterImpl::MIN_INTENDED_TX_COUNT && tx_count <= GenericClusterImpl::MAX_TX_COUNT) {713return CreateEmptyGenericCluster();714}715assert(false);716return {};717}719// Functions for handling Refs.721/** Only called by Ref's move constructor/assignment to update Ref locations. */722void UpdateRef(GraphIndex idx, Ref& new_location) noexcept final723{724auto& entry = m_entries[idx];725Assume(entry.m_ref != nullptr);726entry.m_ref = &new_location;727}729/** Only called by Ref::~Ref to unlink Refs, and Ref's move assignment. */730void UnlinkRef(GraphIndex idx) noexcept final731{732auto& entry = m_entries[idx];733Assume(entry.m_ref != nullptr);734Assume(m_main_chunkindex_observers == 0 || !entry.m_locator[0].IsPresent());735// Remove all chunk index entries for the affected cluster, to avoid any chunk indexes736// referencing unlinked/destroyed Refs.737if (entry.m_locator[0].IsPresent()) {738entry.m_locator[0].cluster->RemoveChunkData(*this);739}740entry.m_ref = nullptr;741// Mark the transaction as to be removed in all levels where it explicitly or implicitly742// exists.743bool exists_anywhere{false};744bool exists{false};745for (int level = 0; level <= GetTopLevel(); ++level) {746if (entry.m_locator[level].IsPresent()) {747exists_anywhere = true;748exists = true;749} else if (entry.m_locator[level].IsRemoved()) {750exists = false;
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.