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#ifndef BITCOIN_CLUSTER_LINEARIZE_H6#define BITCOIN_CLUSTER_LINEARIZE_H8#include <algorithm>9#include <cstdint>10#include <numeric>11#include <optional>12#include <ranges>13#include <utility>14#include <vector>16#include <attributes.h>17#include <memusage.h>18#include <random.h>19#include <span.h>20#include <util/feefrac.h>21#include <util/vecdeque.h>23namespace cluster_linearize {25/** Data type to represent transaction indices in DepGraphs and the clusters they represent. */26using DepGraphIndex = uint32_t;28/** Data structure that holds a transaction graph's preprocessed data (fee, size, ancestors,29* descendants). */30template<typename SetType>31class DepGraph32{33/** Information about a single transaction. */34struct Entry35{36/** Fee and size of transaction itself. */37FeeFrac feerate;38/** All ancestors of the transaction (including itself). */39SetType ancestors;40/** All descendants of the transaction (including itself). */41SetType descendants;43/** Equality operator (primarily for testing purposes). */44friend bool operator==(const Entry&, const Entry&) noexcept = default;46/** Construct an empty entry. */47Entry() noexcept = default;48/** Construct an entry with a given feerate, ancestor set, descendant set. */49Entry(const FeeFrac& f, const SetType& a, const SetType& d) noexcept : feerate(f), ancestors(a), descendants(d) {}50};52/** Data for each transaction. */53std::vector<Entry> entries;55/** Which positions are used. */56SetType m_used;58public:59/** Equality operator (primarily for testing purposes). */60friend bool operator==(const DepGraph& a, const DepGraph& b) noexcept61{62if (a.m_used != b.m_used) return false;63// Only compare the used positions within the entries vector.64for (auto idx : a.m_used) {65if (a.entries[idx] != b.entries[idx]) return false;66}67return true;68}70// Default constructors.71DepGraph() noexcept = default;72DepGraph(const DepGraph&) noexcept = default;73DepGraph(DepGraph&&) noexcept = default;74DepGraph& operator=(const DepGraph&) noexcept = default;75DepGraph& operator=(DepGraph&&) noexcept = default;77/** Construct a DepGraph object given another DepGraph and a mapping from old to new.78*79* @param depgraph The original DepGraph that is being remapped.80*81* @param mapping A span such that mapping[i] gives the position in the new DepGraph82* for position i in the old depgraph. Its size must be equal to83* depgraph.PositionRange(). The value of mapping[i] is ignored if84* position i is a hole in depgraph (i.e., if !depgraph.Positions()[i]).85*86* @param pos_range The PositionRange() for the new DepGraph. It must equal the largest87* value in mapping for any used position in depgraph plus 1, or 0 if88* depgraph.TxCount() == 0.89*90* Complexity: O(N^2) where N=depgraph.TxCount().91*/92DepGraph(const DepGraph<SetType>& depgraph, std::span<const DepGraphIndex> mapping, DepGraphIndex pos_range) noexcept : entries(pos_range)93{94Assume(mapping.size() == depgraph.PositionRange());95Assume((pos_range == 0) == (depgraph.TxCount() == 0));96for (DepGraphIndex i : depgraph.Positions()) {97auto new_idx = mapping[i];98Assume(new_idx < pos_range);99// Add transaction.100entries[new_idx].ancestors = SetType::Singleton(new_idx);101entries[new_idx].descendants = SetType::Singleton(new_idx);102m_used.Set(new_idx);103// Fill in fee and size.104entries[new_idx].feerate = depgraph.entries[i].feerate;105}106for (DepGraphIndex i : depgraph.Positions()) {107// Fill in dependencies by mapping direct parents.108SetType parents;109for (auto j : depgraph.GetReducedParents(i)) parents.Set(mapping[j]);110AddDependencies(parents, mapping[i]);111}112// Verify that the provided pos_range was correct (no unused positions at the end).113Assume(m_used.None() ? (pos_range == 0) : (pos_range == m_used.Last() + 1));114}116/** Get the set of transactions positions in use. Complexity: O(1). */117const SetType& Positions() const noexcept { return m_used; }118/** Get the range of positions in this DepGraph. All entries in Positions() are in [0, PositionRange() - 1]. */119DepGraphIndex PositionRange() const noexcept { return entries.size(); }120/** Get the number of transactions in the graph. Complexity: O(1). */121auto TxCount() const noexcept { return m_used.Count(); }122/** Get the feerate of a given transaction i. Complexity: O(1). */123const FeeFrac& FeeRate(DepGraphIndex i) const noexcept { return entries[i].feerate; }124/** Get the mutable feerate of a given transaction i. Complexity: O(1). */125FeeFrac& FeeRate(DepGraphIndex i) noexcept { return entries[i].feerate; }126/** Get the ancestors of a given transaction i. Complexity: O(1). */127const SetType& Ancestors(DepGraphIndex i) const noexcept { return entries[i].ancestors; }128/** Get the descendants of a given transaction i. Complexity: O(1). */129const SetType& Descendants(DepGraphIndex i) const noexcept { return entries[i].descendants; }131/** Add a new unconnected transaction to this transaction graph (in the first available132* position), and return its DepGraphIndex.133*134* Complexity: O(1) (amortized, due to resizing of backing vector).135*/136DepGraphIndex AddTransaction(const FeeFrac& feefrac) noexcept137{138static constexpr auto ALL_POSITIONS = SetType::Fill(SetType::Size());139auto available = ALL_POSITIONS - m_used;140Assume(available.Any());141DepGraphIndex new_idx = available.First();142if (new_idx == entries.size()) {143entries.emplace_back(feefrac, SetType::Singleton(new_idx), SetType::Singleton(new_idx));144} else {145entries[new_idx] = Entry(feefrac, SetType::Singleton(new_idx), SetType::Singleton(new_idx));146}147m_used.Set(new_idx);148return new_idx;149}151/** Remove the specified positions from this DepGraph.152*153* The specified positions will no longer be part of Positions(), and dependencies with them are154* removed. Note that due to DepGraph only tracking ancestors/descendants (and not direct155* dependencies), if a parent is removed while a grandparent remains, the grandparent will156* remain an ancestor.157*158* Complexity: O(N) where N=TxCount().159*/160void RemoveTransactions(const SetType& del) noexcept161{162m_used -= del;163// Remove now-unused trailing entries.164while (!entries.empty() && !m_used[entries.size() - 1]) {165entries.pop_back();166}167// Remove the deleted transactions from ancestors/descendants of other transactions. Note168// that the deleted positions will retain old feerate and dependency information. This does169// not matter as they will be overwritten by AddTransaction if they get used again.170for (auto& entry : entries) {171entry.ancestors &= m_used;172entry.descendants &= m_used;173}174}176/** Modify this transaction graph, adding multiple parents to a specified child.177*178* Complexity: O(N) where N=TxCount().179*/180void AddDependencies(const SetType& parents, DepGraphIndex child) noexcept181{182Assume(m_used[child]);183Assume(parents.IsSubsetOf(m_used));184// Compute the ancestors of parents that are not already ancestors of child.185SetType par_anc;186for (auto par : parents - Ancestors(child)) {187par_anc |= Ancestors(par);188}189par_anc -= Ancestors(child);190// Bail out if there are no such ancestors.191if (par_anc.None()) return;192// To each such ancestor, add as descendants the descendants of the child.193const auto& chl_des = entries[child].descendants;194for (auto anc_of_par : par_anc) {195entries[anc_of_par].descendants |= chl_des;196}197// To each descendant of the child, add those ancestors.198for (auto dec_of_chl : Descendants(child)) {199entries[dec_of_chl].ancestors |= par_anc;200}201}203/** Compute the (reduced) set of parents of node i in this graph.204*205* This returns the minimal subset of the parents of i whose ancestors together equal all of206* i's ancestors (unless i is part of a cycle of dependencies). Note that DepGraph does not207* store the set of parents; this information is inferred from the ancestor sets.208*209* Complexity: O(N) where N=Ancestors(i).Count() (which is bounded by TxCount()).210*/211SetType GetReducedParents(DepGraphIndex i) const noexcept212{213SetType parents = Ancestors(i);214parents.Reset(i);215for (auto parent : parents) {216if (parents[parent]) {217parents -= Ancestors(parent);218parents.Set(parent);219}220}221return parents;222}224/** Compute the (reduced) set of children of node i in this graph.225*226* This returns the minimal subset of the children of i whose descendants together equal all of227* i's descendants (unless i is part of a cycle of dependencies). Note that DepGraph does not228* store the set of children; this information is inferred from the descendant sets.229*230* Complexity: O(N) where N=Descendants(i).Count() (which is bounded by TxCount()).231*/232SetType GetReducedChildren(DepGraphIndex i) const noexcept233{234SetType children = Descendants(i);235children.Reset(i);236for (auto child : children) {237if (children[child]) {238children -= Descendants(child);239children.Set(child);240}241}242return children;243}245/** Compute the aggregate feerate of a set of nodes in this graph.246*247* Complexity: O(N) where N=elems.Count().248**/249FeeFrac FeeRate(const SetType& elems) const noexcept250{
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.