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.
2251cluster_ptr->Updated(*this, /*level=*/level, /*rename=*/false);2252clusterset.m_cluster_usage += cluster_ptr->TotalMemoryUsage();2253++clusterset.m_txcount;2254// Deal with individually oversized transactions.2255if (oversized) {2256++clusterset.m_txcount_oversized;2257clusterset.m_oversized = true;2258clusterset.m_group_data = std::nullopt;2259}2260}2262void TxGraphImpl::RemoveTransaction(const Ref& arg) noexcept2263{2264// Don't do anything if the Ref is empty (which may be indicative of the transaction already2265// having been removed).2266if (GetRefGraph(arg) == nullptr) return;2267Assume(GetRefGraph(arg) == this);2268Assume(m_main_chunkindex_observers == 0 || GetTopLevel() != 0);2269// Find the Cluster the transaction is in, and stop if it isn't in any.2270int level = GetTopLevel();2271auto cluster = FindCluster(GetRefIndex(arg), level);2272if (cluster == nullptr) return;2273// Remember that the transaction is to be removed.2274auto& clusterset = GetClusterSet(level);2275clusterset.m_to_remove.push_back(GetRefIndex(arg));2276// Wipe m_group_data (as it will need to be recomputed).2277clusterset.m_group_data.reset();2278if (clusterset.m_oversized == true) clusterset.m_oversized = std::nullopt;2279}2281void TxGraphImpl::AddDependency(const Ref& parent, const Ref& child) noexcept2282{2283// Don't do anything if either Ref is empty (which may be indicative of it having already been2284// removed).2285if (GetRefGraph(parent) == nullptr || GetRefGraph(child) == nullptr) return;2286Assume(GetRefGraph(parent) == this && GetRefGraph(child) == this);2287Assume(m_main_chunkindex_observers == 0 || GetTopLevel() != 0);2288// Don't do anything if this is a dependency on self.2289if (GetRefIndex(parent) == GetRefIndex(child)) return;2290// Find the Cluster the parent and child transaction are in, and stop if either appears to be2291// already removed.2292int level = GetTopLevel();2293auto par_cluster = FindCluster(GetRefIndex(parent), level);2294if (par_cluster == nullptr) return;2295auto chl_cluster = FindCluster(GetRefIndex(child), level);2296if (chl_cluster == nullptr) return;2297// Remember that this dependency is to be applied.2298auto& clusterset = GetClusterSet(level);2299clusterset.m_deps_to_add.emplace_back(GetRefIndex(parent), GetRefIndex(child));2300// Wipe m_group_data (as it will need to be recomputed).2301clusterset.m_group_data.reset();2302if (clusterset.m_oversized == false) clusterset.m_oversized = std::nullopt;2303}2305bool TxGraphImpl::Exists(const Ref& arg, Level level_select) noexcept2306{2307if (GetRefGraph(arg) == nullptr) return false;2308Assume(GetRefGraph(arg) == this);2309size_t level = GetSpecifiedLevel(level_select);2310// Make sure the transaction isn't scheduled for removal.2311ApplyRemovals(level);2312auto cluster = FindCluster(GetRefIndex(arg), level);2313return cluster != nullptr;2314}2316void GenericClusterImpl::GetAncestorRefs(const TxGraphImpl& graph, std::span<std::pair<Cluster*, DepGraphIndex>>& args, std::vector<TxGraph::Ref*>& output) noexcept2317{2318/** The union of all ancestors to be returned. */2319SetType ancestors_union;2320// Process elements from the front of args, as long as they apply.2321while (!args.empty()) {2322if (args.front().first != this) break;2323ancestors_union |= m_depgraph.Ancestors(args.front().second);2324args = args.subspan(1);2325}2326Assume(ancestors_union.Any());2327// Translate all ancestors (in arbitrary order) to Refs (if they have any), and return them.2328for (auto idx : ancestors_union) {2329const auto& entry = graph.m_entries[m_mapping[idx]];2330Assume(entry.m_ref != nullptr);2331output.push_back(entry.m_ref);2332}2333}2335void SingletonClusterImpl::GetAncestorRefs(const TxGraphImpl& graph, std::span<std::pair<Cluster*, DepGraphIndex>>& args, std::vector<TxGraph::Ref*>& output) noexcept2336{2337Assume(GetTxCount());2338while (!args.empty()) {2339if (args.front().first != this) break;2340args = args.subspan(1);2341}2342const auto& entry = graph.m_entries[m_graph_index];2343Assume(entry.m_ref != nullptr);2344output.push_back(entry.m_ref);2345}2347void GenericClusterImpl::GetDescendantRefs(const TxGraphImpl& graph, std::span<std::pair<Cluster*, DepGraphIndex>>& args, std::vector<TxGraph::Ref*>& output) noexcept2348{2349/** The union of all descendants to be returned. */2350SetType descendants_union;2351// Process elements from the front of args, as long as they apply.2352while (!args.empty()) {2353if (args.front().first != this) break;2354descendants_union |= m_depgraph.Descendants(args.front().second);2355args = args.subspan(1);2356}2357Assume(descendants_union.Any());2358// Translate all descendants (in arbitrary order) to Refs (if they have any), and return them.2359for (auto idx : descendants_union) {2360const auto& entry = graph.m_entries[m_mapping[idx]];2361Assume(entry.m_ref != nullptr);2362output.push_back(entry.m_ref);2363}2364}2366void SingletonClusterImpl::GetDescendantRefs(const TxGraphImpl& graph, std::span<std::pair<Cluster*, DepGraphIndex>>& args, std::vector<TxGraph::Ref*>& output) noexcept2367{2368// In a singleton cluster, the ancestors or descendants are always just the entire cluster.2369GetAncestorRefs(graph, args, output);2370}2372bool GenericClusterImpl::GetClusterRefs(TxGraphImpl& graph, std::span<TxGraph::Ref*> range, LinearizationIndex start_pos) noexcept2373{2374// Translate the transactions in the Cluster (in linearization order, starting at start_pos in2375// the linearization) to Refs, and fill them in range.2376for (auto& ref : range) {2377Assume(start_pos < m_linearization.size());2378const auto& entry = graph.m_entries[m_mapping[m_linearization[start_pos++]]];2379Assume(entry.m_ref != nullptr);2380ref = entry.m_ref;2381}2382// Return whether start_pos has advanced to the end of the Cluster.2383return start_pos == m_linearization.size();2384}2386bool SingletonClusterImpl::GetClusterRefs(TxGraphImpl& graph, std::span<TxGraph::Ref*> range, LinearizationIndex start_pos) noexcept2387{2388Assume(!range.empty());2389Assume(GetTxCount());2390Assume(start_pos == 0);2391const auto& entry = graph.m_entries[m_graph_index];2392Assume(entry.m_ref != nullptr);2393range[0] = entry.m_ref;2394return true;2395}2397FeePerWeight GenericClusterImpl::GetIndividualFeerate(DepGraphIndex idx) noexcept2398{2399return FeePerWeight::FromFeeFrac(m_depgraph.FeeRate(idx));2400}2402FeePerWeight SingletonClusterImpl::GetIndividualFeerate(DepGraphIndex idx) noexcept2403{2404Assume(GetTxCount());2405Assume(idx == 0);2406return m_feerate;2407}2409void GenericClusterImpl::MakeStagingTransactionsMissing(TxGraphImpl& graph) noexcept2410{2411// Mark all transactions of a Cluster missing, needed when aborting staging, so that the2412// corresponding Locators don't retain references into aborted Clusters.2413for (auto ci : m_linearization) {2414GraphIndex idx = m_mapping[ci];2415auto& entry = graph.m_entries[idx];2416entry.m_locator[1].SetMissing();2417}2418}2420void SingletonClusterImpl::MakeStagingTransactionsMissing(TxGraphImpl& graph) noexcept2421{2422if (GetTxCount()) {2423auto& entry = graph.m_entries[m_graph_index];2424entry.m_locator[1].SetMissing();2425}2426}2428std::vector<TxGraph::Ref*> TxGraphImpl::GetAncestors(const Ref& arg, Level level_select) noexcept2429{2430// Return the empty vector if the Ref is empty.2431if (GetRefGraph(arg) == nullptr) return {};2432Assume(GetRefGraph(arg) == this);2433// Apply all removals and dependencies, as the result might be incorrect otherwise.2434size_t level = GetSpecifiedLevel(level_select);2435ApplyDependencies(level);2436// Ancestry cannot be known if unapplied dependencies remain.2437Assume(GetClusterSet(level).m_deps_to_add.empty());2438// Find the Cluster the argument is in, and return the empty vector if it isn't in any.2439auto [cluster, cluster_level] = FindClusterAndLevel(GetRefIndex(arg), level);2440if (cluster == nullptr) return {};2441// Dispatch to the Cluster.2442std::pair<Cluster*, DepGraphIndex> match = {cluster, m_entries[GetRefIndex(arg)].m_locator[cluster_level].index};2443auto matches = std::span(&match, 1);2444std::vector<TxGraph::Ref*> ret;2445cluster->GetAncestorRefs(*this, matches, ret);2446return ret;2447}2449std::vector<TxGraph::Ref*> TxGraphImpl::GetDescendants(const Ref& arg, Level level_select) noexcept2450{2451// Return the empty vector if the Ref is empty.2452if (GetRefGraph(arg) == nullptr) return {};2453Assume(GetRefGraph(arg) == this);2454// Apply all removals and dependencies, as the result might be incorrect otherwise.2455size_t level = GetSpecifiedLevel(level_select);2456ApplyDependencies(level);2457// Ancestry cannot be known if unapplied dependencies remain.2458Assume(GetClusterSet(level).m_deps_to_add.empty());2459// Find the Cluster the argument is in, and return the empty vector if it isn't in any.2460auto [cluster, cluster_level] = FindClusterAndLevel(GetRefIndex(arg), level);2461if (cluster == nullptr) return {};2462// Dispatch to the Cluster.2463std::pair<Cluster*, DepGraphIndex> match = {cluster, m_entries[GetRefIndex(arg)].m_locator[cluster_level].index};2464auto matches = std::span(&match, 1);2465std::vector<TxGraph::Ref*> ret;2466cluster->GetDescendantRefs(*this, matches, ret);2467return ret;2468}2470std::vector<TxGraph::Ref*> TxGraphImpl::GetAncestorsUnion(std::span<const Ref* const> args, Level level_select) noexcept2471{2472// Apply all dependencies, as the result might be incorrect otherwise.2473size_t level = GetSpecifiedLevel(level_select);2474ApplyDependencies(level);2475// Ancestry cannot be known if unapplied dependencies remain.2476Assume(GetClusterSet(level).m_deps_to_add.empty());2478// Translate args to matches.2479std::vector<std::pair<Cluster*, DepGraphIndex>> matches;2480matches.reserve(args.size());2481for (auto arg : args) {2482Assume(arg);2483// Skip empty Refs.2484if (GetRefGraph(*arg) == nullptr) continue;2485Assume(GetRefGraph(*arg) == this);2486// Find the Cluster the argument is in, and skip if none is found.2487auto [cluster, cluster_level] = FindClusterAndLevel(GetRefIndex(*arg), level);2488if (cluster == nullptr) continue;2489// Append to matches.2490matches.emplace_back(cluster, m_entries[GetRefIndex(*arg)].m_locator[cluster_level].index);2491}2492// Group by Cluster.2493std::ranges::sort(matches, [](auto& a, auto& b) noexcept { return CompareClusters(a.first, b.first) < 0; });2494// Dispatch to the Clusters.2495std::span match_span(matches);2496std::vector<TxGraph::Ref*> ret;2497while (!match_span.empty()) {2498match_span.front().first->GetAncestorRefs(*this, match_span, ret);2499}2500return ret;
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.