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.
501if (top_sim.graph.Ancestors(pos_par)[pos_chl]) break;502}503top_sim.AddDependency(par, chl);504top_sim.real_is_optimal = false;505real->AddDependency(*par, *chl);506break;507} else if ((block_builders.empty() || sims.size() > 1) && top_sim.removed.size() < 100 && command-- == 0) {508// RemoveTransaction. Either all its ancestors or all its descendants are also509// removed (if any), to make sure TxGraph's reordering of removals and dependencies510// has no effect.511std::vector<TxGraph::Ref*> to_remove;512to_remove.push_back(pick_fn());513top_sim.IncludeAncDesc(to_remove, alt);514// The order in which these ancestors/descendants are removed should not matter;515// randomly shuffle them.516std::shuffle(to_remove.begin(), to_remove.end(), rng);517for (TxGraph::Ref* ptr : to_remove) {518real->RemoveTransaction(*ptr);519top_sim.RemoveTransaction(ptr);520}521break;522} else if (sel_sim.removed.size() > 0 && command-- == 0) {523// ~Ref (of an already-removed transaction). Destroying a TxGraph::Ref has an524// observable effect on the TxGraph it refers to, so this simulation permits doing525// so separately from other actions on TxGraph.527// Pick a Ref of sel_sim.removed to destroy. Note that the same Ref may still occur528// in the other graph, and thus not actually trigger ~Ref yet (which is exactly529// what we want, as destroying Refs is only allowed when it does not refer to an530// existing transaction in either graph).531auto removed_pos = provider.ConsumeIntegralInRange<size_t>(0, sel_sim.removed.size() - 1);532if (removed_pos != sel_sim.removed.size() - 1) {533std::swap(sel_sim.removed[removed_pos], sel_sim.removed.back());534}535sel_sim.removed.pop_back();536break;537} else if (block_builders.empty() && command-- == 0) {538// ~Ref (of any transaction).539std::vector<TxGraph::Ref*> to_destroy;540to_destroy.push_back(pick_fn());541while (true) {542// Keep adding either the ancestors or descendants the already picked543// transactions have in both graphs (main and staging) combined. Destroying544// will trigger deletions in both, so to have consistent TxGraph behavior, the545// set must be closed under ancestors, or descendants, in both graphs.546auto old_size = to_destroy.size();547for (auto& sim : sims) sim.IncludeAncDesc(to_destroy, alt);548if (to_destroy.size() == old_size) break;549}550// The order in which these ancestors/descendants are destroyed should not matter;551// randomly shuffle them.552std::shuffle(to_destroy.begin(), to_destroy.end(), rng);553for (TxGraph::Ref* ptr : to_destroy) {554for (size_t level = 0; level < sims.size(); ++level) {555sims[level].DestroyTransaction(ptr, level == sims.size() - 1);556}557}558break;559} else if (block_builders.empty() && command-- == 0) {560// SetTransactionFee.561int64_t fee;562if (alt) {563fee = provider.ConsumeIntegralInRange<int64_t>(-0x8000000000000, 0x7ffffffffffff);564} else {565fee = provider.ConsumeIntegral<uint8_t>();566}567auto ref = pick_fn();568real->SetTransactionFee(*ref, fee);569for (auto& sim : sims) {570sim.SetTransactionFee(ref, fee);571}572break;573} else if (command-- == 0) {574// GetTransactionCount.575assert(real->GetTransactionCount(level_select) == sel_sim.GetTransactionCount());576break;577} else if (command-- == 0) {578// Exists.579auto ref = pick_fn();580bool exists = real->Exists(*ref, level_select);581bool should_exist = sel_sim.Find(ref) != SimTxGraph::MISSING;582assert(exists == should_exist);583break;584} else if (command-- == 0) {585// IsOversized.586assert(sel_sim.IsOversized() == real->IsOversized(level_select));587break;588} else if (command-- == 0) {589// GetIndividualFeerate.590auto ref = pick_fn();591auto feerate = real->GetIndividualFeerate(*ref);592bool found{false};593for (auto& sim : sims) {594auto simpos = sim.Find(ref);595if (simpos != SimTxGraph::MISSING) {596found = true;597assert(feerate == sim.graph.FeeRate(simpos));598}599}600if (!found) assert(feerate.IsEmpty());601break;602} else if (!main_sim.IsOversized() && command-- == 0) {603// GetMainChunkFeerate.604auto ref = pick_fn();605auto feerate = real->GetMainChunkFeerate(*ref);606auto simpos = main_sim.Find(ref);607if (simpos == SimTxGraph::MISSING) {608assert(feerate.IsEmpty());609} else {610// Just do some quick checks that the reported value is in range. A full611// recomputation of expected chunk feerates is done at the end.612assert(feerate.size >= main_sim.graph.FeeRate(simpos).size);613assert(feerate.size <= main_sim.SumAll().size);614}615break;616} else if (!sel_sim.IsOversized() && command-- == 0) {617// GetAncestors/GetDescendants.618auto ref = pick_fn();619auto result = alt ? real->GetDescendants(*ref, level_select)620: real->GetAncestors(*ref, level_select);621assert(result.size() <= max_cluster_count);622auto result_set = sel_sim.MakeSet(result);623assert(result.size() == result_set.Count());624auto expect_set = sel_sim.GetAncDesc(ref, alt);625assert(result_set == expect_set);626break;627} else if (!sel_sim.IsOversized() && command-- == 0) {628// GetAncestorsUnion/GetDescendantsUnion.629std::vector<TxGraph::Ref*> refs;630// Gather a list of up to 15 Ref pointers.631auto count = provider.ConsumeIntegralInRange<size_t>(0, 15);632refs.resize(count);633for (size_t i = 0; i < count; ++i) {634refs[i] = pick_fn();635}636// Their order should not matter, shuffle them.637std::shuffle(refs.begin(), refs.end(), rng);638// Invoke the real function, and convert to SimPos set.639auto result = alt ? real->GetDescendantsUnion(refs, level_select)640: real->GetAncestorsUnion(refs, level_select);641auto result_set = sel_sim.MakeSet(result);642assert(result.size() == result_set.Count());643// Compute the expected result.644SimTxGraph::SetType expect_set;645for (TxGraph::Ref* ref : refs) expect_set |= sel_sim.GetAncDesc(ref, alt);646// Compare.647assert(result_set == expect_set);648break;649} else if (!sel_sim.IsOversized() && command-- == 0) {650// GetCluster.651auto ref = pick_fn();652auto result = real->GetCluster(*ref, level_select);653// Check cluster count limit.654assert(result.size() <= max_cluster_count);655// Require the result to be topologically valid and not contain duplicates.656auto left = sel_sim.graph.Positions();657uint64_t total_size{0};658for (auto refptr : result) {659auto simpos = sel_sim.Find(refptr);660total_size += sel_sim.graph.FeeRate(simpos).size;661assert(simpos != SimTxGraph::MISSING);662assert(left[simpos]);663left.Reset(simpos);664assert(!sel_sim.graph.Ancestors(simpos).Overlaps(left));665}666// Check cluster size limit.667assert(total_size <= max_cluster_size);668// Require the set to be connected.669auto result_set = sel_sim.MakeSet(result);670assert(sel_sim.graph.IsConnected(result_set));671// If ref exists, the result must contain it. If not, it must be empty.672auto simpos = sel_sim.Find(ref);673if (simpos != SimTxGraph::MISSING) {674assert(result_set[simpos]);675} else {676assert(result_set.None());677}678// Require the set not to have ancestors or descendants outside of it.679for (auto i : result_set) {680assert(sel_sim.graph.Ancestors(i).IsSubsetOf(result_set));681assert(sel_sim.graph.Descendants(i).IsSubsetOf(result_set));682}683break;684} else if (command-- == 0) {685// HaveStaging.686assert((sims.size() == 2) == real->HaveStaging());687break;688} else if (sims.size() < 2 && command-- == 0) {689// StartStaging.690sims.emplace_back(sims.back());691sims.back().modified = SimTxGraph::SetType{};692real->StartStaging();693break;694} else if (block_builders.empty() && sims.size() > 1 && command-- == 0) {695// CommitStaging.696real->CommitStaging();697// Resulting main level is only guaranteed to be optimal if all levels are698const bool main_optimal = std::all_of(sims.cbegin(), sims.cend(), [](const auto &sim) { return sim.real_is_optimal; });699sims.erase(sims.begin());700sims.front().real_is_optimal = main_optimal;701break;702} else if (sims.size() > 1 && command-- == 0) {703// AbortStaging.704real->AbortStaging();705sims.pop_back();706// Reset the cached oversized value (if TxGraph::Ref destructions triggered707// removals of main transactions while staging was active, then aborting will708// cause it to be re-evaluated in TxGraph).709sims.back().oversized = std::nullopt;710break;711} else if (!main_sim.IsOversized() && command-- == 0) {712// CompareMainOrder.713auto ref_a = pick_fn();714auto ref_b = pick_fn();715auto sim_a = main_sim.Find(ref_a);716auto sim_b = main_sim.Find(ref_b);717// Both transactions must exist in the main graph.718if (sim_a == SimTxGraph::MISSING || sim_b == SimTxGraph::MISSING) break;719auto cmp = real->CompareMainOrder(*ref_a, *ref_b);720// Distinct transactions have distinct places.721if (sim_a != sim_b) assert(cmp != 0);722// Ancestors go before descendants.723if (main_sim.graph.Ancestors(sim_a)[sim_b]) assert(cmp >= 0);724if (main_sim.graph.Descendants(sim_a)[sim_b]) assert(cmp <= 0);725// Do not verify consistency with chunk feerates, as we cannot easily determine726// these here without making more calls to real, which could affect its internal727// state. A full comparison is done at the end.728break;729} else if (!sel_sim.IsOversized() && command-- == 0) {730// CountDistinctClusters.731std::vector<TxGraph::Ref*> refs;732// Gather a list of up to 15 (or up to 255) Ref pointers.733auto count = provider.ConsumeIntegralInRange<size_t>(0, alt ? 255 : 15);734refs.resize(count);735for (size_t i = 0; i < count; ++i) {736refs[i] = pick_fn();737}738// Their order should not matter, shuffle them.739std::shuffle(refs.begin(), refs.end(), rng);740// Invoke the real function.741auto result = real->CountDistinctClusters(refs, level_select);742// Build a set with representatives of the clusters the Refs occur in the743// simulated graph. For each, remember the lowest-index transaction SimPos in the744// cluster.745SimTxGraph::SetType sim_reps;746for (auto ref : refs) {747// Skip Refs that do not occur in the simulated graph.748auto simpos = sel_sim.Find(ref);749if (simpos == SimTxGraph::MISSING) continue;750// Find the component that includes ref.
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.