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.
251FeeFrac ret;252for (auto pos : elems) ret += entries[pos].feerate;253return ret;254}256/** Get the connected component within the subset "todo" that contains tx (which must be in257* todo).258*259* Two transactions are considered connected if they are both in `todo`, and one is an ancestor260* of the other in the entire graph (so not just within `todo`), or transitively there is a261* path of transactions connecting them. This does mean that if `todo` contains a transaction262* and a grandparent, but misses the parent, they will still be part of the same component.263*264* Complexity: O(ret.Count()).265*/266SetType GetConnectedComponent(const SetType& todo, DepGraphIndex tx) const noexcept267{268Assume(todo[tx]);269Assume(todo.IsSubsetOf(m_used));270auto to_add = SetType::Singleton(tx);271SetType ret;272do {273SetType old = ret;274for (auto add : to_add) {275ret |= Descendants(add);276ret |= Ancestors(add);277}278ret &= todo;279to_add = ret - old;280} while (to_add.Any());281return ret;282}284/** Find some connected component within the subset "todo" of this graph.285*286* Specifically, this finds the connected component which contains the first transaction of287* todo (if any).288*289* Complexity: O(ret.Count()).290*/291SetType FindConnectedComponent(const SetType& todo) const noexcept292{293if (todo.None()) return todo;294return GetConnectedComponent(todo, todo.First());295}297/** Determine if a subset is connected.298*299* Complexity: O(subset.Count()).300*/301bool IsConnected(const SetType& subset) const noexcept302{303return FindConnectedComponent(subset) == subset;304}306/** Determine if this entire graph is connected.307*308* Complexity: O(TxCount()).309*/310bool IsConnected() const noexcept { return IsConnected(m_used); }312/** Append the entries of select to list in a topologically valid order.313*314* Complexity: O(select.Count() * log(select.Count())).315*/316void AppendTopo(std::vector<DepGraphIndex>& list, const SetType& select) const noexcept317{318DepGraphIndex old_len = list.size();319for (auto i : select) list.push_back(i);320std::ranges::sort(std::span{list}.subspan(old_len), [&](DepGraphIndex a, DepGraphIndex b) noexcept {321const auto a_anc_count = entries[a].ancestors.Count();322const auto b_anc_count = entries[b].ancestors.Count();323if (a_anc_count != b_anc_count) return a_anc_count < b_anc_count;324return a < b;325});326}328/** Check if this graph is acyclic. */329bool IsAcyclic() const noexcept330{331for (auto i : Positions()) {332if ((Ancestors(i) & Descendants(i)) != SetType::Singleton(i)) {333return false;334}335}336return true;337}339unsigned CountDependencies() const noexcept340{341unsigned ret = 0;342for (auto i : Positions()) {343ret += GetReducedParents(i).Count();344}345return ret;346}348/** Reduce memory usage if possible. No observable effect. */349void Compact() noexcept350{351entries.shrink_to_fit();352}354size_t DynamicMemoryUsage() const noexcept355{356return memusage::DynamicUsage(entries);357}358};360/** A set of transactions together with their aggregate feerate. */361template<typename SetType>362struct SetInfo363{364/** The transactions in the set. */365SetType transactions;366/** Their combined fee and size. */367FeeFrac feerate;369/** Construct a SetInfo for the empty set. */370SetInfo() noexcept = default;372/** Construct a SetInfo for a specified set and feerate. */373SetInfo(const SetType& txn, const FeeFrac& fr) noexcept : transactions(txn), feerate(fr) {}375/** Construct a SetInfo for a given transaction in a depgraph. */376explicit SetInfo(const DepGraph<SetType>& depgraph, DepGraphIndex pos) noexcept :377transactions(SetType::Singleton(pos)), feerate(depgraph.FeeRate(pos)) {}379/** Construct a SetInfo for a set of transactions in a depgraph. */380explicit SetInfo(const DepGraph<SetType>& depgraph, const SetType& txn) noexcept :381transactions(txn), feerate(depgraph.FeeRate(txn)) {}383/** Add a transaction to this SetInfo (which must not yet be in it). */384void Set(const DepGraph<SetType>& depgraph, DepGraphIndex pos) noexcept385{386Assume(!transactions[pos]);387transactions.Set(pos);388feerate += depgraph.FeeRate(pos);389}391/** Add the transactions of other to this SetInfo (no overlap allowed). */392SetInfo& operator|=(const SetInfo& other) noexcept393{394Assume(!transactions.Overlaps(other.transactions));395transactions |= other.transactions;396feerate += other.feerate;397return *this;398}400/** Remove the transactions of other from this SetInfo (which must be a subset). */401SetInfo& operator-=(const SetInfo& other) noexcept402{403Assume(other.transactions.IsSubsetOf(transactions));404transactions -= other.transactions;405feerate -= other.feerate;406return *this;407}409/** Compute the difference between this and other SetInfo (which must be a subset). */410SetInfo operator-(const SetInfo& other) const noexcept411{412Assume(other.transactions.IsSubsetOf(transactions));413return {transactions - other.transactions, feerate - other.feerate};414}416/** Swap two SetInfo objects. */417friend void swap(SetInfo& a, SetInfo& b) noexcept418{419swap(a.transactions, b.transactions);420swap(a.feerate, b.feerate);421}423/** Permit equality testing. */424friend bool operator==(const SetInfo&, const SetInfo&) noexcept = default;425};427/** Compute the chunks of linearization as SetInfos. */428template<typename SetType>429std::vector<SetInfo<SetType>> ChunkLinearizationInfo(const DepGraph<SetType>& depgraph, std::span<const DepGraphIndex> linearization) noexcept430{431std::vector<SetInfo<SetType>> ret;432for (DepGraphIndex i : linearization) {433/** The new chunk to be added, initially a singleton. */434SetInfo<SetType> new_chunk(depgraph, i);435// As long as the new chunk has a higher feerate than the last chunk so far, absorb it.436while (!ret.empty() && ByRatio{new_chunk.feerate} > ByRatio{ret.back().feerate}) {437new_chunk |= ret.back();438ret.pop_back();439}440// Actually move that new chunk into the chunking.441ret.emplace_back(std::move(new_chunk));442}443return ret;444}446/** Compute the feerates of the chunks of linearization. Identical to ChunkLinearizationInfo, but447* only returns the chunk feerates, not the corresponding transaction sets. */448template<typename SetType>449std::vector<FeeFrac> ChunkLinearization(const DepGraph<SetType>& depgraph, std::span<const DepGraphIndex> linearization) noexcept450{451std::vector<FeeFrac> ret;452for (DepGraphIndex i : linearization) {453/** The new chunk to be added, initially a singleton. */454auto new_chunk = depgraph.FeeRate(i);455// As long as the new chunk has a higher feerate than the last chunk so far, absorb it.456while (!ret.empty() && ByRatio{new_chunk} > ByRatio{ret.back()}) {457new_chunk += ret.back();458ret.pop_back();459}460// Actually move that new chunk into the chunking.461ret.push_back(std::move(new_chunk));462}463return ret;464}466/** Concept for function objects that return std::strong_ordering when invoked with two Args. */467template<typename F, typename Arg>468concept StrongComparator =469std::regular_invocable<F, Arg, Arg> &&470std::is_same_v<std::invoke_result_t<F, Arg, Arg>, std::strong_ordering>;472/** Simple default transaction ordering function for SpanningForestState::GetLinearization() and473* Linearize(), which just sorts by DepGraphIndex. */474using IndexTxOrder = std::compare_three_way;476/** A default cost model for SFL for SetType=BitSet<64>, based on benchmarks.477*478* The numbers here were obtained in February 2026 by:479* - For a variety of machines:480* - Running a fixed collection of ~385000 clusters found through random generation and fuzzing,481* optimizing for difficulty of linearization.482* - Linearize each ~3000 times, with different random seeds. Sometimes without input483* linearization, sometimes with a bad one.484* - Gather cycle counts for each of the operations included in this cost model,485* broken down by their parameters.486* - Correct the data by subtracting the runtime of obtaining the cycle count.487* - Drop the 5% top and bottom samples from each cycle count dataset, and compute the average488* of the remaining samples.489* - For each operation, fit a least-squares linear function approximation through the samples.490* - Rescale all machine expressions to make their total time match, as we only care about491* relative cost of each operation.492* - Take the per-operation average of operation expressions across all machines, to construct493* expressions for an average machine.494* - Approximate the result with integer coefficients. Each cost unit corresponds to somewhere495* between 0.5 ns and 2.5 ns, depending on the hardware.496*/497class SFLDefaultCostModel498{499uint64_t m_cost{0};
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.