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.
751}752if (exists) {753auto& clusterset = GetClusterSet(level);754clusterset.m_to_remove.push_back(idx);755// Force recomputation of grouping data.756clusterset.m_group_data = std::nullopt;757// Do not wipe the oversized state of main if staging exists. The reason for this758// is that the alternative would mean that cluster merges may need to be applied to759// a formerly-oversized main graph while staging exists (to satisfy chunk feerate760// queries into main, for example), and such merges could conflict with pulls of761// some of their constituents into staging.762if (level == GetTopLevel() && clusterset.m_oversized == true) {763clusterset.m_oversized = std::nullopt;764}765}766}767m_unlinked.push_back(idx);768if (!exists_anywhere) Compact();769}771// Functions related to various normalization/application steps.772/** Get rid of unlinked Entry objects in m_entries, if possible (this changes the GraphIndex773* values for remaining Entry objects, so this only does something when no to-be-applied774* operations or staged removals referring to GraphIndexes remain). */775void Compact() noexcept;776/** If cluster is not in staging, copy it there, and return a pointer to it.777* Staging must exist, and this modifies the locators of its778* transactions from inherited (P,M) to explicit (P,P). */779Cluster* PullIn(Cluster* cluster, int level) noexcept;780/** Apply all removals queued up in m_to_remove to the relevant Clusters (which get a781* NEEDS_SPLIT* QualityLevel) up to the specified level. */782void ApplyRemovals(int up_to_level) noexcept;783/** Split an individual cluster. */784void Split(Cluster& cluster, int level) noexcept;785/** Split all clusters that need splitting up to the specified level. */786void SplitAll(int up_to_level) noexcept;787/** Populate m_group_data based on m_deps_to_add in the specified level. */788void GroupClusters(int level) noexcept;789/** Merge the specified clusters. */790void Merge(std::span<Cluster*> to_merge, int level) noexcept;791/** Apply all m_deps_to_add to the relevant Clusters in the specified level. */792void ApplyDependencies(int level) noexcept;793/** Make a specified Cluster have quality ACCEPTABLE or OPTIMAL. */794void MakeAcceptable(Cluster& cluster, int level) noexcept;795/** Make all Clusters at the specified level have quality ACCEPTABLE or OPTIMAL. */796void MakeAllAcceptable(int level) noexcept;798// Implementations for the public TxGraph interface.800void AddTransaction(Ref& arg, const FeePerWeight& feerate) noexcept final;801void RemoveTransaction(const Ref& arg) noexcept final;802void AddDependency(const Ref& parent, const Ref& child) noexcept final;803void SetTransactionFee(const Ref&, int64_t fee) noexcept final;805bool DoWork(uint64_t max_cost) noexcept final;807void StartStaging() noexcept final;808void CommitStaging() noexcept final;809void AbortStaging() noexcept final;810bool HaveStaging() const noexcept final { return m_staging_clusterset.has_value(); }812bool Exists(const Ref& arg, Level level) noexcept final;813FeePerWeight GetMainChunkFeerate(const Ref& arg) noexcept final;814FeePerWeight GetIndividualFeerate(const Ref& arg) noexcept final;815std::vector<Ref*> GetCluster(const Ref& arg, Level level) noexcept final;816std::vector<Ref*> GetAncestors(const Ref& arg, Level level) noexcept final;817std::vector<Ref*> GetDescendants(const Ref& arg, Level level) noexcept final;818std::vector<Ref*> GetAncestorsUnion(std::span<const Ref* const> args, Level level) noexcept final;819std::vector<Ref*> GetDescendantsUnion(std::span<const Ref* const> args, Level level) noexcept final;820GraphIndex GetTransactionCount(Level level) noexcept final;821bool IsOversized(Level level) noexcept final;822std::strong_ordering CompareMainOrder(const Ref& a, const Ref& b) noexcept final;823GraphIndex CountDistinctClusters(std::span<const Ref* const> refs, Level level) noexcept final;824std::pair<std::vector<FeeFrac>, std::vector<FeeFrac>> GetMainStagingDiagrams() noexcept final;825std::vector<Ref*> Trim() noexcept final;827std::unique_ptr<BlockBuilder> GetBlockBuilder() noexcept final;828std::pair<std::vector<Ref*>, FeePerWeight> GetWorstMainChunk() noexcept final;830size_t GetMainMemoryUsage() noexcept final;832void SanityCheck() const final;833};835TxGraphImpl::ClusterSet& TxGraphImpl::GetClusterSet(int level) noexcept836{837if (level == 0) return m_main_clusterset;838Assume(level == 1);839Assume(m_staging_clusterset.has_value());840return *m_staging_clusterset;841}843const TxGraphImpl::ClusterSet& TxGraphImpl::GetClusterSet(int level) const noexcept844{845if (level == 0) return m_main_clusterset;846Assume(level == 1);847Assume(m_staging_clusterset.has_value());848return *m_staging_clusterset;849}851/** Implementation of the TxGraph::BlockBuilder interface. */852class BlockBuilderImpl final : public TxGraph::BlockBuilder853{854/** Which TxGraphImpl this object is doing block building for. It will have its855* m_main_chunkindex_observers incremented as long as this BlockBuilderImpl exists. */856TxGraphImpl* const m_graph;857/** Cluster sequence numbers which we're not including further transactions from. */858std::unordered_set<uint64_t> m_excluded_clusters;859/** Iterator to the current chunk in the chunk index. end() if nothing further remains. */860TxGraphImpl::ChunkIndex::const_iterator m_cur_iter;861/** Which cluster the current chunk belongs to, so we can exclude further transactions from it862* when that chunk is skipped. */863Cluster* m_cur_cluster;864/** Whether we know that m_cur_iter points to the last chunk of m_cur_cluster. */865bool m_known_end_of_cluster;867// Move m_cur_iter / m_cur_cluster to the next acceptable chunk.868void Next() noexcept;870public:871/** Construct a new BlockBuilderImpl to build blocks for the provided graph. */872BlockBuilderImpl(TxGraphImpl& graph) noexcept;874// Implement the public interface.875~BlockBuilderImpl() final;876std::optional<std::pair<std::vector<TxGraph::Ref*>, FeePerWeight>> GetCurrentChunk() noexcept final;877void Include() noexcept final;878void Skip() noexcept final;879};881void TxGraphImpl::ClearChunkData(Entry& entry) noexcept882{883if (entry.m_main_chunkindex_iterator != m_main_chunkindex.end()) {884Assume(m_main_chunkindex_observers == 0);885// If the Entry has a non-empty m_main_chunkindex_iterator, extract it, and move the handle886// to the cache of discarded chunkindex entries.887m_main_chunkindex_discarded.emplace_back(m_main_chunkindex.extract(entry.m_main_chunkindex_iterator));888entry.m_main_chunkindex_iterator = m_main_chunkindex.end();889}890}892void TxGraphImpl::CreateChunkData(GraphIndex idx, LinearizationIndex chunk_count) noexcept893{894auto& entry = m_entries[idx];895// Make sure to not create chunk data for unlinked entries, which would make invoking896// m_fallback_order on them impossible.897Assume(entry.m_ref != nullptr);898if (!m_main_chunkindex_discarded.empty()) {899// Reuse an discarded node handle.900auto& node = m_main_chunkindex_discarded.back().value();901node.m_graph_index = idx;902node.m_chunk_count = chunk_count;903auto insert_result = m_main_chunkindex.insert(std::move(m_main_chunkindex_discarded.back()));904Assume(insert_result.inserted);905entry.m_main_chunkindex_iterator = insert_result.position;906m_main_chunkindex_discarded.pop_back();907} else {908// Construct a new entry.909auto emplace_result = m_main_chunkindex.emplace(idx, chunk_count);910Assume(emplace_result.second);911entry.m_main_chunkindex_iterator = emplace_result.first;912}913}915size_t GenericClusterImpl::TotalMemoryUsage() const noexcept916{917return // Dynamic memory allocated in this Cluster.918memusage::DynamicUsage(m_mapping) + memusage::DynamicUsage(m_linearization) +919// Dynamic memory usage inside m_depgraph.920m_depgraph.DynamicMemoryUsage() +921// Memory usage of the allocated Cluster itself.922memusage::MallocUsage(sizeof(GenericClusterImpl)) +923// Memory usage of the ClusterSet::m_clusters entry.924sizeof(std::unique_ptr<Cluster>);925}927size_t SingletonClusterImpl::TotalMemoryUsage() const noexcept928{929return // Memory usage of the allocated SingletonClusterImpl itself.930memusage::MallocUsage(sizeof(SingletonClusterImpl)) +931// Memory usage of the ClusterSet::m_clusters entry.932sizeof(std::unique_ptr<Cluster>);933}935uint64_t GenericClusterImpl::GetTotalTxSize() const noexcept936{937uint64_t ret{0};938for (auto i : m_linearization) {939ret += m_depgraph.FeeRate(i).size;940}941return ret;942}944DepGraphIndex GenericClusterImpl::AppendTransaction(GraphIndex graph_idx, FeePerWeight feerate) noexcept945{946Assume(graph_idx != GraphIndex(-1));947auto ret = m_depgraph.AddTransaction(feerate);948m_mapping.push_back(graph_idx);949m_linearization.push_back(ret);950return ret;951}953DepGraphIndex SingletonClusterImpl::AppendTransaction(GraphIndex graph_idx, FeePerWeight feerate) noexcept954{955Assume(!GetTxCount());956m_graph_index = graph_idx;957m_feerate = feerate;958return 0;959}961void GenericClusterImpl::AddDependencies(SetType parents, DepGraphIndex child) noexcept962{963m_depgraph.AddDependencies(parents, child);964}966void SingletonClusterImpl::AddDependencies(SetType parents, DepGraphIndex child) noexcept967{968// Singletons cannot have any dependencies.969Assume(child == 0);970Assume(parents == SetType{} || parents == SetType::Fill(0));971}973void GenericClusterImpl::ExtractTransactions(const std::function<void (DepGraphIndex, GraphIndex, FeePerWeight)>& visit1_fn, const std::function<void (DepGraphIndex, GraphIndex, SetType)>& visit2_fn) noexcept974{975for (auto pos : m_linearization) {976visit1_fn(pos, m_mapping[pos], FeePerWeight::FromFeeFrac(m_depgraph.FeeRate(pos)));977}978for (auto pos : m_linearization) {979visit2_fn(pos, m_mapping[pos], m_depgraph.GetReducedParents(pos));980}981// Purge this Cluster, now that everything has been moved.982m_depgraph = DepGraph<SetType>{};983m_linearization.clear();984m_mapping.clear();985}987void SingletonClusterImpl::ExtractTransactions(const std::function<void (DepGraphIndex, GraphIndex, FeePerWeight)>& visit1_fn, const std::function<void (DepGraphIndex, GraphIndex, SetType)>& visit2_fn) noexcept988{989if (GetTxCount()) {990visit1_fn(0, m_graph_index, m_feerate);991visit2_fn(0, m_graph_index, SetType{});992m_graph_index = NO_GRAPH_INDEX;993}994}996int GenericClusterImpl::GetLevel(const TxGraphImpl& graph) const noexcept997{998// GetLevel() does not work for empty Clusters.999if (!Assume(!m_linearization.empty())) return -1;
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.