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.
1251// The last chunk returned by the BlockBuilder must match GetWorstMainChunk, in reverse.1252std::reverse(last_chunk.begin(), last_chunk.end());1253auto [worst_chunk, worst_chunk_feerate] = real->GetWorstMainChunk();1254assert(last_chunk == worst_chunk);1255assert(last_chunk_feerate == worst_chunk_feerate);1257// Check that the implied ordering gives rise to a combined diagram that matches the1258// diagram constructed from the individual cluster linearization chunkings.1259auto main_real_diagram = get_diagram_fn(TxGraph::Level::MAIN);1260auto main_implied_diagram = ChunkLinearization(sims[0].graph, vec1);1261assert(CompareChunks(main_real_diagram, main_implied_diagram) == 0);1263if (sims.size() >= 2 && !sims[1].IsOversized()) {1264// When the staging graph is not oversized as well, call GetMainStagingDiagrams, and1265// fully verify the result.1266auto [main_cmp_diagram, stage_cmp_diagram] = real->GetMainStagingDiagrams();1267// Check that the feerates in each diagram are monotonically decreasing.1268for (size_t i = 1; i < main_cmp_diagram.size(); ++i) {1269assert(ByRatio{main_cmp_diagram[i]} <= ByRatio{main_cmp_diagram[i - 1]});1270}1271for (size_t i = 1; i < stage_cmp_diagram.size(); ++i) {1272assert(ByRatio{stage_cmp_diagram[i]} <= ByRatio{stage_cmp_diagram[i - 1]});1273}1274// Treat the diagrams as sets of chunk feerates, and sort them in the same way so that1275// std::set_difference can be used on them below. The exact ordering does not matter1276// here, but it has to be consistent with the one used in main_real_diagram and1277// stage_real_diagram).1278std::ranges::sort(main_cmp_diagram, std::greater<ByRatioNegSize<FeeFrac>>{});1279std::ranges::sort(stage_cmp_diagram, std::greater<ByRatioNegSize<FeeFrac>>{});1280// Find the chunks that appear in main_diagram but are missing from main_cmp_diagram.1281// This is allowed, because GetMainStagingDiagrams omits clusters in main unaffected1282// by staging.1283std::vector<FeeFrac> missing_main_cmp;1284std::set_difference(main_real_diagram.begin(), main_real_diagram.end(),1285main_cmp_diagram.begin(), main_cmp_diagram.end(),1286std::inserter(missing_main_cmp, missing_main_cmp.end()),1287std::greater<ByRatioNegSize<FeeFrac>>{});1288assert(main_cmp_diagram.size() + missing_main_cmp.size() == main_real_diagram.size());1289// Do the same for chunks in stage_diagram missing from stage_cmp_diagram.1290auto stage_real_diagram = get_diagram_fn(TxGraph::Level::TOP);1291std::vector<FeeFrac> missing_stage_cmp;1292std::set_difference(stage_real_diagram.begin(), stage_real_diagram.end(),1293stage_cmp_diagram.begin(), stage_cmp_diagram.end(),1294std::inserter(missing_stage_cmp, missing_stage_cmp.end()),1295std::greater<ByRatioNegSize<FeeFrac>>{});1296assert(stage_cmp_diagram.size() + missing_stage_cmp.size() == stage_real_diagram.size());1297// The missing chunks must be equal across main & staging (otherwise they couldn't have1298// been omitted).1299assert(missing_main_cmp == missing_stage_cmp);1301// The missing part must include at least all transactions in staging which have not been1302// modified, or been in a cluster together with modified transactions, since they were1303// copied from main. Note that due to the reordering of removals w.r.t. dependency1304// additions, it is possible that the real implementation found more unaffected things.1305FeeFrac missing_real;1306for (const auto& feerate : missing_main_cmp) missing_real += feerate;1307FeeFrac missing_expected = sims[1].graph.FeeRate(sims[1].graph.Positions() - sims[1].modified);1308// Note that missing_real.fee < missing_expected.fee is possible to due the presence of1309// negative-fee transactions.1310assert(missing_real.size >= missing_expected.size);1311}1312}1314assert(real->HaveStaging() == (sims.size() > 1));1316// Try to run a full comparison, for both TxGraph::Level::MAIN and TxGraph::Level::TOP in1317// TxGraph inspector functions that support both.1318for (auto level : {TxGraph::Level::TOP, TxGraph::Level::MAIN}) {1319auto& sim = level == TxGraph::Level::TOP ? sims.back() : sims.front();1320// Compare simple properties of the graph with the simulation.1321assert(real->IsOversized(level) == sim.IsOversized());1322assert(real->GetTransactionCount(level) == sim.GetTransactionCount());1323// If the graph (and the simulation) are not oversized, perform a full comparison.1324if (!sim.IsOversized()) {1325auto todo = sim.graph.Positions();1326// Iterate over all connected components of the resulting (simulated) graph, each of which1327// should correspond to a cluster in the real one.1328while (todo.Any()) {1329auto component = sim.graph.FindConnectedComponent(todo);1330todo -= component;1331// Iterate over the transactions in that component.1332for (auto i : component) {1333// Check its individual feerate against simulation.1334assert(sim.graph.FeeRate(i) == real->GetIndividualFeerate(*sim.GetRef(i)));1335// Check its ancestors against simulation.1336auto expect_anc = sim.graph.Ancestors(i);1337auto anc = sim.MakeSet(real->GetAncestors(*sim.GetRef(i), level));1338assert(anc.Count() <= max_cluster_count);1339assert(anc == expect_anc);1340// Check its descendants against simulation.1341auto expect_desc = sim.graph.Descendants(i);1342auto desc = sim.MakeSet(real->GetDescendants(*sim.GetRef(i), level));1343assert(desc.Count() <= max_cluster_count);1344assert(desc == expect_desc);1345// Check the cluster the transaction is part of.1346auto cluster = real->GetCluster(*sim.GetRef(i), level);1347assert(cluster.size() <= max_cluster_count);1348assert(sim.MakeSet(cluster) == component);1349// Check that the cluster is reported in a valid topological order (its1350// linearization).1351std::vector<DepGraphIndex> simlin;1352SimTxGraph::SetType done;1353uint64_t total_size{0};1354for (TxGraph::Ref* ptr : cluster) {1355auto simpos = sim.Find(ptr);1356assert(sim.graph.Descendants(simpos).IsSubsetOf(component - done));1357done.Set(simpos);1358assert(sim.graph.Ancestors(simpos).IsSubsetOf(done));1359simlin.push_back(simpos);1360total_size += sim.graph.FeeRate(simpos).size;1361}1362// Check cluster size.1363assert(total_size <= max_cluster_size);1364// Construct a chunking object for the simulated graph, using the reported cluster1365// linearization as ordering, and compare it against the reported chunk feerates.1366if (sims.size() == 1 || level == TxGraph::Level::MAIN) {1367auto simlinchunk = ChunkLinearizationInfo(sim.graph, simlin);1368DepGraphIndex idx{0};1369for (auto& chunk : simlinchunk) {1370// Require that the chunks of cluster linearizations are connected (this must1371// be the case as all linearizations inside are PostLinearized).1372assert(sim.graph.IsConnected(chunk.transactions));1373// Check the chunk feerates of all transactions in the cluster.1374while (chunk.transactions.Any()) {1375assert(chunk.transactions[simlin[idx]]);1376chunk.transactions.Reset(simlin[idx]);1377assert(chunk.feerate == real->GetMainChunkFeerate(*cluster[idx]));1378++idx;1379}1380}1381}1382}1383}1384}1385}1387// Sanity check again (because invoking inspectors may modify internal unobservable state).1388real->SanityCheck();1390// Kill the block builders.1391block_builders.clear();1392// Kill the TxGraph object.1393real.reset();1394// Kill the simulated graphs, with all remaining Refs in it. If any, this verifies that Refs1395// can outlive the TxGraph that created them.1396sims.clear();1397}
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.