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.
251chunking = perm_chunking;252}253} else {254// Otherwise, fast forward to the last permutation with the same non-topological255// prefix.256auto first_non_topo = perm_linearization.begin() + topo_length;257assert(std::is_sorted(first_non_topo + 1, perm_linearization.end()));258std::reverse(first_non_topo + 1, perm_linearization.end());259}260} while(std::next_permutation(perm_linearization.begin(), perm_linearization.end()));262return linearization;263}266/** Stitch connected components together in a DepGraph, guaranteeing its corresponding cluster is connected. */267template<typename BS>268void MakeConnected(DepGraph<BS>& depgraph)269{270auto todo = depgraph.Positions();271auto comp = depgraph.FindConnectedComponent(todo);272Assume(depgraph.IsConnected(comp));273todo -= comp;274while (todo.Any()) {275auto nextcomp = depgraph.FindConnectedComponent(todo);276Assume(depgraph.IsConnected(nextcomp));277depgraph.AddDependencies(BS::Singleton(comp.Last()), nextcomp.First());278todo -= nextcomp;279comp = nextcomp;280}281}283/** Given a dependency graph, and a todo set, read a topological subset of todo from reader. */284template<typename SetType>285SetType ReadTopologicalSet(const DepGraph<SetType>& depgraph, const SetType& todo, SpanReader& reader, bool non_empty)286{287// Read a bitmask from the fuzzing input. Add 1 if non_empty, so the mask is definitely not288// zero in that case.289uint64_t mask{0};290try {291reader >> VARINT(mask);292} catch(const std::ios_base::failure&) {}293if (mask != uint64_t(-1)) mask += non_empty;295SetType ret;296for (auto i : todo) {297if (!ret[i]) {298if (mask & 1) ret |= depgraph.Ancestors(i);299mask >>= 1;300}301}302ret &= todo;304// While mask starts off non-zero if non_empty is true, it is still possible that all its low305// bits are 0, and ret ends up being empty. As a last resort, use the in-todo ancestry of the306// first todo position.307if (non_empty && ret.None()) {308Assume(todo.Any());309ret = depgraph.Ancestors(todo.First()) & todo;310Assume(ret.Any());311}312return ret;313}315/** Given a dependency graph, construct any valid linearization for it, reading from a SpanReader. */316template<typename BS>317std::vector<DepGraphIndex> ReadLinearization(const DepGraph<BS>& depgraph, SpanReader& reader, bool topological=true)318{319std::vector<DepGraphIndex> linearization;320TestBitSet todo = depgraph.Positions();321// In every iteration one transaction is appended to linearization.322while (todo.Any()) {323// Compute the set of transactions to select from.324TestBitSet potential_next;325if (topological) {326// Find all transactions with no not-yet-included ancestors.327for (auto j : todo) {328if ((depgraph.Ancestors(j) & todo) == TestBitSet::Singleton(j)) {329potential_next.Set(j);330}331}332} else {333// Allow any element to be selected next, regardless of topology.334potential_next = todo;335}336// There must always be one (otherwise there is a cycle in the graph).337assert(potential_next.Any());338// Read a number from reader, and interpret it as index into potential_next.339uint64_t idx{0};340try {341reader >> VARINT(idx);342} catch (const std::ios_base::failure&) {}343idx %= potential_next.Count();344// Find out which transaction that corresponds to.345for (auto j : potential_next) {346if (idx == 0) {347// When found, add it to linearization and remove it from todo.348linearization.push_back(j);349assert(todo[j]);350todo.Reset(j);351break;352}353--idx;354}355}356return linearization;357}359/** Given a dependency graph, construct a tree-structured graph.360*361* Copies the nodes from the depgraph, but only keeps the first parent (even direction)362* or the first child (odd direction) for each transaction.363*/364template<typename BS>365DepGraph<BS> BuildTreeGraph(const DepGraph<BS>& depgraph, uint8_t direction)366{367DepGraph<BS> depgraph_tree;368for (DepGraphIndex i = 0; i < depgraph.PositionRange(); ++i) {369if (depgraph.Positions()[i]) {370depgraph_tree.AddTransaction(depgraph.FeeRate(i));371} else {372// For holes, add a dummy transaction which is deleted below, so that non-hole373// transactions retain their position.374depgraph_tree.AddTransaction(FeeFrac{});375}376}377depgraph_tree.RemoveTransactions(BS::Fill(depgraph.PositionRange()) - depgraph.Positions());379if (direction & 1) {380for (DepGraphIndex i : depgraph.Positions()) {381auto children = depgraph.GetReducedChildren(i);382if (children.Any()) {383depgraph_tree.AddDependencies(BS::Singleton(i), children.First());384}385}386} else {387for (DepGraphIndex i : depgraph.Positions()) {388auto parents = depgraph.GetReducedParents(i);389if (parents.Any()) {390depgraph_tree.AddDependencies(BS::Singleton(parents.First()), i);391}392}393}395return depgraph_tree;396}398} // namespace400FUZZ_TARGET(clusterlin_depgraph_sim)401{402// Simulation test to verify the full behavior of DepGraph.404FuzzedDataProvider provider(buffer.data(), buffer.size());406/** Real DepGraph being tested. */407DepGraph<TestBitSet> real;408/** Simulated DepGraph (sim[i] is std::nullopt if position i does not exist; otherwise,409* sim[i]->first is its individual feerate, and sim[i]->second is its set of ancestors. */410std::array<std::optional<std::pair<FeeFrac, TestBitSet>>, TestBitSet::Size()> sim;411/** The number of non-nullopt position in sim. */412DepGraphIndex num_tx_sim{0};414/** Read a valid index of a transaction from the provider. */415auto idx_fn = [&]() {416auto offset = provider.ConsumeIntegralInRange<DepGraphIndex>(0, num_tx_sim - 1);417for (DepGraphIndex i = 0; i < sim.size(); ++i) {418if (!sim[i].has_value()) continue;419if (offset == 0) return i;420--offset;421}422assert(false);423return DepGraphIndex(-1);424};426/** Read a valid subset of the transactions from the provider. */427auto subset_fn = [&]() {428auto range = (uint64_t{1} << num_tx_sim) - 1;429const auto mask = provider.ConsumeIntegralInRange<uint64_t>(0, range);430auto mask_shifted = mask;431TestBitSet subset;432for (DepGraphIndex i = 0; i < sim.size(); ++i) {433if (!sim[i].has_value()) continue;434if (mask_shifted & 1) {435subset.Set(i);436}437mask_shifted >>= 1;438}439assert(mask_shifted == 0);440return subset;441};443/** Read any set of transactions from the provider (including unused positions). */444auto set_fn = [&]() {445auto range = (uint64_t{1} << sim.size()) - 1;446const auto mask = provider.ConsumeIntegralInRange<uint64_t>(0, range);447TestBitSet set;448for (DepGraphIndex i = 0; i < sim.size(); ++i) {449if ((mask >> i) & 1) {450set.Set(i);451}452}453return set;454};456/** Propagate ancestor information in sim. */457auto anc_update_fn = [&]() {458while (true) {459bool updates{false};460for (DepGraphIndex chl = 0; chl < sim.size(); ++chl) {461if (!sim[chl].has_value()) continue;462for (auto par : sim[chl]->second) {463if (!sim[chl]->second.IsSupersetOf(sim[par]->second)) {464sim[chl]->second |= sim[par]->second;465updates = true;466}467}468}469if (!updates) break;470}471};473/** Compare the state of transaction i in the simulation with the real one. */474auto check_fn = [&](DepGraphIndex i) {475// Compare used positions.476assert(real.Positions()[i] == sim[i].has_value());477if (sim[i].has_value()) {478// Compare feerate.479assert(real.FeeRate(i) == sim[i]->first);480// Compare ancestors (note that SanityCheck verifies correspondence between ancestors481// and descendants, so we can restrict ourselves to ancestors here).482assert(real.Ancestors(i) == sim[i]->second);483}484};486auto last_compaction_pos{real.PositionRange()};488LIMITED_WHILE (provider.remaining_bytes() > 0, 1000) {489int command = provider.ConsumeIntegral<uint8_t>() % 4;490while (true) {491// Iterate decreasing command until an applicable branch is found.492if (num_tx_sim < TestBitSet::Size() && command-- == 0) {493// AddTransaction.494auto fee = provider.ConsumeIntegralInRange<int64_t>(-0x8000000000000, 0x7ffffffffffff);495auto size = provider.ConsumeIntegralInRange<int32_t>(1, 0x3fffff);496FeeFrac feerate{fee, size};497// Apply to DepGraph.498auto idx = real.AddTransaction(feerate);499// Verify that the returned index is correct.500assert(!sim[idx].has_value());
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.