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.
751SetType active_children;752/** Which chunk this transaction belongs to. */753SetIdx chunk_idx;754};756/** The set of all TxIdx's of transactions in the cluster indexing into m_tx_data. */757SetType m_transaction_idxs;758/** The set of all chunk SetIdx's. This excludes the SetIdxs that refer to active759* dependencies' tops. */760SetType m_chunk_idxs;761/** The set of all SetIdx's that appear in m_suboptimal_chunks. Note that they do not need to762* be chunks: some of these sets may have been converted to a dependency's top set since being763* added to m_suboptimal_chunks. */764SetType m_suboptimal_idxs;765/** Information about each transaction (and chunks). Keeps the "holes" from DepGraph during766* construction. Indexed by TxIdx. */767std::vector<TxData> m_tx_data;768/** Information about each set (chunk, or active dependency top set). Indexed by SetIdx. */769std::vector<SetInfo<SetType>> m_set_info;770/** For each chunk, indexed by SetIdx, the set of out-of-chunk reachable transactions, in the771* upwards (.first) and downwards (.second) direction. */772std::vector<std::pair<SetType, SetType>> m_reachable;773/** A FIFO of chunk SetIdxs for chunks that may be improved still. */774VecDeque<SetIdx> m_suboptimal_chunks;775/** A FIFO of chunk indexes with a pivot transaction in them, and a flag to indicate their776* status:777* - bit 1: currently attempting to move the pivot down, rather than up.778* - bit 2: this is the second stage, so we have already tried moving the pivot in the other779* direction.780*/781VecDeque<std::tuple<SetIdx, TxIdx, unsigned>> m_nonminimal_chunks;783/** The DepGraph we are trying to linearize. */784const DepGraph<SetType>& m_depgraph;786/** Accounting for the cost of this computation. */787CostModel m_cost;789/** Pick a random transaction within a set (which must be non-empty). */790TxIdx PickRandomTx(const SetType& tx_idxs) noexcept791{792Assume(tx_idxs.Any());793unsigned pos = m_rng.randrange<unsigned>(tx_idxs.Count());794for (auto tx_idx : tx_idxs) {795if (pos == 0) return tx_idx;796--pos;797}798Assume(false);799return TxIdx(-1);800}802/** Find the set of out-of-chunk transactions reachable from tx_idxs, both in upwards and803* downwards direction. Only used by SanityCheck to verify the precomputed reachable sets in804* m_reachable that are maintained by Activate/Deactivate. */805std::pair<SetType, SetType> GetReachable(const SetType& tx_idxs) const noexcept806{807SetType parents, children;808for (auto tx_idx : tx_idxs) {809const auto& tx_data = m_tx_data[tx_idx];810parents |= tx_data.parents;811children |= tx_data.children;812}813return {parents - tx_idxs, children - tx_idxs};814}816/** Make the inactive dependency from child to parent, which must not be in the same chunk817* already, active. Returns the merged chunk idx. */818SetIdx Activate(TxIdx parent_idx, TxIdx child_idx) noexcept819{820m_cost.ActivateBegin();821// Gather and check information about the parent and child transactions.822auto& parent_data = m_tx_data[parent_idx];823auto& child_data = m_tx_data[child_idx];824Assume(parent_data.children[child_idx]);825Assume(!parent_data.active_children[child_idx]);826// Get the set index of the chunks the parent and child are currently in. The parent chunk827// will become the top set of the newly activated dependency, while the child chunk will be828// grown to become the merged chunk.829auto parent_chunk_idx = parent_data.chunk_idx;830auto child_chunk_idx = child_data.chunk_idx;831Assume(parent_chunk_idx != child_chunk_idx);832Assume(m_chunk_idxs[parent_chunk_idx]);833Assume(m_chunk_idxs[child_chunk_idx]);834auto& top_info = m_set_info[parent_chunk_idx];835auto& bottom_info = m_set_info[child_chunk_idx];837// Consider the following example:838//839// A A There are two chunks, ABC and DEF, and the inactive E->C dependency840// / \ / \ is activated, resulting in a single chunk ABCDEF.841// B C B C842// : ==> | Dependency | top set before | top set after | change843// D E D E B->A | AC | ACDEF | +DEF844// \ / \ / C->A | AB | AB |845// F F F->D | D | D |846// F->E | E | ABCE | +ABC847//848// The common pattern here is that any dependency which has the parent or child of the849// dependency being activated (E->C here) in its top set, will have the opposite part added850// to it. This is true for B->A and F->E, but not for C->A and F->D.851//852// Traverse the old parent chunk top_info (ABC in example), and add bottom_info (DEF) to853// every dependency's top set which has the parent (C) in it. At the same time, change the854// chunk_idx for each to be child_chunk_idx, which becomes the set for the merged chunk.855for (auto tx_idx : top_info.transactions) {856auto& tx_data = m_tx_data[tx_idx];857tx_data.chunk_idx = child_chunk_idx;858for (auto dep_child_idx : tx_data.active_children) {859auto& dep_top_info = m_set_info[tx_data.dep_top_idx[dep_child_idx]];860if (dep_top_info.transactions[parent_idx]) dep_top_info |= bottom_info;861}862}863// Traverse the old child chunk bottom_info (DEF in example), and add top_info (ABC) to864// every dependency's top set which has the child (E) in it.865for (auto tx_idx : bottom_info.transactions) {866auto& tx_data = m_tx_data[tx_idx];867for (auto dep_child_idx : tx_data.active_children) {868auto& dep_top_info = m_set_info[tx_data.dep_top_idx[dep_child_idx]];869if (dep_top_info.transactions[child_idx]) dep_top_info |= top_info;870}871}872// Merge top_info into bottom_info, which becomes the merged chunk.873bottom_info |= top_info;874// Compute merged sets of reachable transactions from the new chunk, based on the input875// chunks' reachable sets.876m_reachable[child_chunk_idx].first |= m_reachable[parent_chunk_idx].first;877m_reachable[child_chunk_idx].second |= m_reachable[parent_chunk_idx].second;878m_reachable[child_chunk_idx].first -= bottom_info.transactions;879m_reachable[child_chunk_idx].second -= bottom_info.transactions;880// Make parent chunk the set for the new active dependency.881parent_data.dep_top_idx[child_idx] = parent_chunk_idx;882parent_data.active_children.Set(child_idx);883m_chunk_idxs.Reset(parent_chunk_idx);884// Return the newly merged chunk.885m_cost.ActivateEnd(/*num_deps=*/bottom_info.transactions.Count() - 1);886return child_chunk_idx;887}889/** Make a specified active dependency inactive. Returns the created parent and child chunk890* indexes. */891std::pair<SetIdx, SetIdx> Deactivate(TxIdx parent_idx, TxIdx child_idx) noexcept892{893m_cost.DeactivateBegin();894// Gather and check information about the parent transactions.895auto& parent_data = m_tx_data[parent_idx];896Assume(parent_data.children[child_idx]);897Assume(parent_data.active_children[child_idx]);898// Get the top set of the active dependency (which will become the parent chunk) and the899// chunk set the transactions are currently in (which will become the bottom chunk).900auto parent_chunk_idx = parent_data.dep_top_idx[child_idx];901auto child_chunk_idx = parent_data.chunk_idx;902Assume(parent_chunk_idx != child_chunk_idx);903Assume(m_chunk_idxs[child_chunk_idx]);904Assume(!m_chunk_idxs[parent_chunk_idx]); // top set, not a chunk905auto& top_info = m_set_info[parent_chunk_idx];906auto& bottom_info = m_set_info[child_chunk_idx];908// Remove the active dependency.909parent_data.active_children.Reset(child_idx);910m_chunk_idxs.Set(parent_chunk_idx);911auto ntx = bottom_info.transactions.Count();912// Subtract the top_info from the bottom_info, as it will become the child chunk.913bottom_info -= top_info;914// See the comment above in Activate(). We perform the opposite operations here, removing915// instead of adding. Simultaneously, aggregate the top/bottom's union of parents/children.916SetType top_parents, top_children;917for (auto tx_idx : top_info.transactions) {918auto& tx_data = m_tx_data[tx_idx];919tx_data.chunk_idx = parent_chunk_idx;920top_parents |= tx_data.parents;921top_children |= tx_data.children;922for (auto dep_child_idx : tx_data.active_children) {923auto& dep_top_info = m_set_info[tx_data.dep_top_idx[dep_child_idx]];924if (dep_top_info.transactions[parent_idx]) dep_top_info -= bottom_info;925}926}927SetType bottom_parents, bottom_children;928for (auto tx_idx : bottom_info.transactions) {929auto& tx_data = m_tx_data[tx_idx];930bottom_parents |= tx_data.parents;931bottom_children |= tx_data.children;932for (auto dep_child_idx : tx_data.active_children) {933auto& dep_top_info = m_set_info[tx_data.dep_top_idx[dep_child_idx]];934if (dep_top_info.transactions[child_idx]) dep_top_info -= top_info;935}936}937// Compute the new sets of reachable transactions for each new chunk, based on the938// top/bottom parents and children computed above.939m_reachable[parent_chunk_idx].first = top_parents - top_info.transactions;940m_reachable[parent_chunk_idx].second = top_children - top_info.transactions;941m_reachable[child_chunk_idx].first = bottom_parents - bottom_info.transactions;942m_reachable[child_chunk_idx].second = bottom_children - bottom_info.transactions;943// Return the two new set idxs.944m_cost.DeactivateEnd(/*num_deps=*/ntx - 1);945return {parent_chunk_idx, child_chunk_idx};946}948/** Activate a dependency from the bottom set to the top set, which must exist. Return the949* index of the merged chunk. */950SetIdx MergeChunks(SetIdx top_idx, SetIdx bottom_idx) noexcept951{952m_cost.MergeChunksBegin();953Assume(m_chunk_idxs[top_idx]);954Assume(m_chunk_idxs[bottom_idx]);955auto& top_chunk_info = m_set_info[top_idx];956auto& bottom_chunk_info = m_set_info[bottom_idx];957// Count the number of dependencies between bottom_chunk and top_chunk, remembering the958// per-transaction counts so the picking loop below does not need to recompute the959// intersections.960unsigned num_deps{0};961std::array<SetIdx, SetType::Size()> counts;962for (auto tx_idx : top_chunk_info.transactions) {963auto& tx_data = m_tx_data[tx_idx];964auto count = (tx_data.children & bottom_chunk_info.transactions).Count();965counts[tx_idx] = count;966num_deps += count;967}968m_cost.MergeChunksMid(/*num_txns=*/top_chunk_info.transactions.Count());969Assume(num_deps > 0);970// Uniformly randomly pick one of them and activate it.971unsigned pick = m_rng.randrange(num_deps);972unsigned num_steps = 0;973for (auto tx_idx : top_chunk_info.transactions) {974++num_steps;975auto count = counts[tx_idx];976if (pick < count) {977auto& tx_data = m_tx_data[tx_idx];978auto intersect = tx_data.children & bottom_chunk_info.transactions;979for (auto child_idx : intersect) {980if (pick == 0) {981m_cost.MergeChunksEnd(/*num_steps=*/num_steps);982return Activate(tx_idx, child_idx);983}984--pick;985}986Assume(false);987break;988}989pick -= count;990}991Assume(false);992return INVALID_SET_IDX;993}995/** Activate a dependency from chunk_idx to merge_chunk_idx (if !DownWard), or a dependency996* from merge_chunk_idx to chunk_idx (if DownWard). Return the index of the merged chunk. */997template<bool DownWard>998SetIdx MergeChunksDirected(SetIdx chunk_idx, SetIdx merge_chunk_idx) noexcept999{1000if constexpr (DownWard) {
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.