From d45f3717d2c65d1a6012a4bc2f47ff75004fd171 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 9 Sep 2025 15:54:33 -0400 Subject: [PATCH] txgraph: use enum Level instead of bool main_only --- src/bench/txgraph.cpp | 4 +-- src/test/fuzz/txgraph.cpp | 58 +++++++++++++++++++------------------- src/test/txgraph_tests.cpp | 40 +++++++++++++------------- src/txgraph.cpp | 58 +++++++++++++++++++------------------- src/txgraph.h | 48 +++++++++++++++---------------- 5 files changed, 103 insertions(+), 105 deletions(-) diff --git a/src/bench/txgraph.cpp b/src/bench/txgraph.cpp index 5303386baaa..70824c2a51e 100644 --- a/src/bench/txgraph.cpp +++ b/src/bench/txgraph.cpp @@ -114,9 +114,9 @@ void BenchTxGraphTrim(benchmark::Bench& bench) graph->GetBlockBuilder(); }); - assert(!graph->IsOversized()); + assert(!graph->IsOversized(TxGraph::Level::TOP)); // At least 99% of chains must survive. - assert(graph->GetTransactionCount() >= (NUM_TOP_CHAINS * NUM_TX_PER_TOP_CHAIN * 99) / 100); + assert(graph->GetTransactionCount(TxGraph::Level::TOP) >= (NUM_TOP_CHAINS * NUM_TX_PER_TOP_CHAIN * 99) / 100); } } // namespace diff --git a/src/test/fuzz/txgraph.cpp b/src/test/fuzz/txgraph.cpp index 50af38db57b..00001034718 100644 --- a/src/test/fuzz/txgraph.cpp +++ b/src/test/fuzz/txgraph.cpp @@ -383,14 +383,14 @@ FUZZ_TARGET(txgraph) /** Function to construct the correct fee-size diagram a real graph has based on its graph * order (as reported by GetCluster(), so it works for both main and staging). */ - auto get_diagram_fn = [&](bool main_only) -> std::vector { - int level = main_only ? 0 : sims.size() - 1; + auto get_diagram_fn = [&](TxGraph::Level level_select) -> std::vector { + int level = level_select == TxGraph::Level::MAIN ? 0 : sims.size() - 1; auto& sim = sims[level]; // For every transaction in the graph, request its cluster, and throw them into a set. std::set> clusters; for (auto i : sim.graph.Positions()) { auto ref = sim.GetRef(i); - clusters.insert(real->GetCluster(*ref, main_only)); + clusters.insert(real->GetCluster(*ref, level_select)); } // Compute the chunkings of each (deduplicated) cluster. size_t num_tx{0}; @@ -423,19 +423,19 @@ FUZZ_TARGET(txgraph) // operations), and the second-lowest bit as a way of selecting main vs. staging, and leave // the rest of the bits in command. bool alt = command & 1; - bool use_main = command & 2; + TxGraph::Level level_select = (command & 2) ? TxGraph::Level::MAIN : TxGraph::Level::TOP; command >>= 2; /** Use the bottom 2 bits of command to select an entry in the block_builders vector (if - * any). These use the same bits as alt/use_main, so don't use those in actions below + * any). These use the same bits as alt/level_select, so don't use those in actions below * where builder_idx is used as well. */ int builder_idx = block_builders.empty() ? -1 : int((orig_command & 3) % block_builders.size()); // Provide convenient aliases for the top simulated graph (main, or staging if it exists), - // one for the simulated graph selected based on use_main (for operations that can operate + // one for the simulated graph selected based on level_select (for operations that can operate // on both graphs), and one that always refers to the main graph. auto& top_sim = sims.back(); - auto& sel_sim = use_main ? sims[0] : top_sim; + auto& sel_sim = level_select == TxGraph::Level::MAIN ? sims[0] : top_sim; auto& main_sim = sims[0]; // Keep decrementing command for each applicable operation, until one is hit. Multiple @@ -546,18 +546,18 @@ FUZZ_TARGET(txgraph) break; } else if (command-- == 0) { // GetTransactionCount. - assert(real->GetTransactionCount(use_main) == sel_sim.GetTransactionCount()); + assert(real->GetTransactionCount(level_select) == sel_sim.GetTransactionCount()); break; } else if (command-- == 0) { // Exists. auto ref = pick_fn(); - bool exists = real->Exists(*ref, use_main); + bool exists = real->Exists(*ref, level_select); bool should_exist = sel_sim.Find(ref) != SimTxGraph::MISSING; assert(exists == should_exist); break; } else if (command-- == 0) { // IsOversized. - assert(sel_sim.IsOversized() == real->IsOversized(use_main)); + assert(sel_sim.IsOversized() == real->IsOversized(level_select)); break; } else if (command-- == 0) { // GetIndividualFeerate. @@ -590,8 +590,8 @@ FUZZ_TARGET(txgraph) } else if (!sel_sim.IsOversized() && command-- == 0) { // GetAncestors/GetDescendants. auto ref = pick_fn(); - auto result = alt ? real->GetDescendants(*ref, use_main) - : real->GetAncestors(*ref, use_main); + auto result = alt ? real->GetDescendants(*ref, level_select) + : real->GetAncestors(*ref, level_select); assert(result.size() <= max_cluster_count); auto result_set = sel_sim.MakeSet(result); assert(result.size() == result_set.Count()); @@ -610,8 +610,8 @@ FUZZ_TARGET(txgraph) // Their order should not matter, shuffle them. std::shuffle(refs.begin(), refs.end(), rng); // Invoke the real function, and convert to SimPos set. - auto result = alt ? real->GetDescendantsUnion(refs, use_main) - : real->GetAncestorsUnion(refs, use_main); + auto result = alt ? real->GetDescendantsUnion(refs, level_select) + : real->GetAncestorsUnion(refs, level_select); auto result_set = sel_sim.MakeSet(result); assert(result.size() == result_set.Count()); // Compute the expected result. @@ -623,7 +623,7 @@ FUZZ_TARGET(txgraph) } else if (!sel_sim.IsOversized() && command-- == 0) { // GetCluster. auto ref = pick_fn(); - auto result = real->GetCluster(*ref, use_main); + auto result = real->GetCluster(*ref, level_select); // Check cluster count limit. assert(result.size() <= max_cluster_count); // Require the result to be topologically valid and not contain duplicates. @@ -712,7 +712,7 @@ FUZZ_TARGET(txgraph) // Their order should not matter, shuffle them. std::shuffle(refs.begin(), refs.end(), rng); // Invoke the real function. - auto result = real->CountDistinctClusters(refs, use_main); + auto result = real->CountDistinctClusters(refs, level_select); // Build a set with representatives of the clusters the Refs occur in in the // simulated graph. For each, remember the lowest-index transaction SimPos in the // cluster. @@ -905,7 +905,7 @@ FUZZ_TARGET(txgraph) // First, we need to have dependencies applied and linearizations fixed to avoid // circular dependencies in implied graph; trigger it via whatever means. - real->CountDistinctClusters({}, false); + real->CountDistinctClusters({}, TxGraph::Level::TOP); // Gather the current clusters. auto clusters = top_sim.GetComponents(); @@ -1110,7 +1110,7 @@ FUZZ_TARGET(txgraph) // Check that the implied ordering gives rise to a combined diagram that matches the // diagram constructed from the individual cluster linearization chunkings. - auto main_real_diagram = get_diagram_fn(/*main_only=*/true); + auto main_real_diagram = get_diagram_fn(TxGraph::Level::MAIN); auto main_implied_diagram = ChunkLinearization(sims[0].graph, vec1); assert(CompareChunks(main_real_diagram, main_implied_diagram) == 0); @@ -1141,7 +1141,7 @@ FUZZ_TARGET(txgraph) std::greater{}); assert(main_cmp_diagram.size() + missing_main_cmp.size() == main_real_diagram.size()); // Do the same for chunks in stage_diagram missing from stage_cmp_diagram. - auto stage_real_diagram = get_diagram_fn(/*main_only=*/false); + auto stage_real_diagram = get_diagram_fn(TxGraph::Level::TOP); std::vector missing_stage_cmp; std::set_difference(stage_real_diagram.begin(), stage_real_diagram.end(), stage_cmp_diagram.begin(), stage_cmp_diagram.end(), @@ -1167,13 +1167,13 @@ FUZZ_TARGET(txgraph) assert(real->HaveStaging() == (sims.size() > 1)); - // Try to run a full comparison, for both main_only=false and main_only=true in TxGraph - // inspector functions that support both. - for (int main_only = 0; main_only < 2; ++main_only) { - auto& sim = main_only ? sims[0] : sims.back(); + // Try to run a full comparison, for both TxGraph::Level::MAIN and TxGraph::Level::TOP in + // TxGraph inspector functions that support both. + for (auto level : {TxGraph::Level::TOP, TxGraph::Level::MAIN}) { + auto& sim = level == TxGraph::Level::TOP ? sims.back() : sims.front(); // Compare simple properties of the graph with the simulation. - assert(real->IsOversized(main_only) == sim.IsOversized()); - assert(real->GetTransactionCount(main_only) == sim.GetTransactionCount()); + assert(real->IsOversized(level) == sim.IsOversized()); + assert(real->GetTransactionCount(level) == sim.GetTransactionCount()); // If the graph (and the simulation) are not oversized, perform a full comparison. if (!sim.IsOversized()) { auto todo = sim.graph.Positions(); @@ -1188,16 +1188,16 @@ FUZZ_TARGET(txgraph) assert(sim.graph.FeeRate(i) == real->GetIndividualFeerate(*sim.GetRef(i))); // Check its ancestors against simulation. auto expect_anc = sim.graph.Ancestors(i); - auto anc = sim.MakeSet(real->GetAncestors(*sim.GetRef(i), main_only)); + auto anc = sim.MakeSet(real->GetAncestors(*sim.GetRef(i), level)); assert(anc.Count() <= max_cluster_count); assert(anc == expect_anc); // Check its descendants against simulation. auto expect_desc = sim.graph.Descendants(i); - auto desc = sim.MakeSet(real->GetDescendants(*sim.GetRef(i), main_only)); + auto desc = sim.MakeSet(real->GetDescendants(*sim.GetRef(i), level)); assert(desc.Count() <= max_cluster_count); assert(desc == expect_desc); // Check the cluster the transaction is part of. - auto cluster = real->GetCluster(*sim.GetRef(i), main_only); + auto cluster = real->GetCluster(*sim.GetRef(i), level); assert(cluster.size() <= max_cluster_count); assert(sim.MakeSet(cluster) == component); // Check that the cluster is reported in a valid topological order (its @@ -1217,7 +1217,7 @@ FUZZ_TARGET(txgraph) assert(total_size <= max_cluster_size); // Construct a chunking object for the simulated graph, using the reported cluster // linearization as ordering, and compare it against the reported chunk feerates. - if (sims.size() == 1 || main_only) { + if (sims.size() == 1 || level == TxGraph::Level::MAIN) { cluster_linearize::LinearizationChunking simlinchunk(sim.graph, simlin); DepGraphIndex idx{0}; for (unsigned chunknum = 0; chunknum < simlinchunk.NumChunksLeft(); ++chunknum) { diff --git a/src/test/txgraph_tests.cpp b/src/test/txgraph_tests.cpp index 63741e6cd7d..3fb20d8dcca 100644 --- a/src/test/txgraph_tests.cpp +++ b/src/test/txgraph_tests.cpp @@ -64,19 +64,19 @@ BOOST_AUTO_TEST_CASE(txgraph_trim_zigzag) // Check that the graph is now oversized. This also forces the graph to // group clusters and compute the oversized status. graph->SanityCheck(); - BOOST_CHECK_EQUAL(graph->GetTransactionCount(), NUM_TOTAL_TX); - BOOST_CHECK(graph->IsOversized(/*main_only=*/false)); + BOOST_CHECK_EQUAL(graph->GetTransactionCount(TxGraph::Level::TOP), NUM_TOTAL_TX); + BOOST_CHECK(graph->IsOversized(TxGraph::Level::TOP)); // Call Trim() to remove transactions and bring the cluster back within limits. auto removed_refs = graph->Trim(); graph->SanityCheck(); - BOOST_CHECK(!graph->IsOversized(/*main_only=*/false)); + BOOST_CHECK(!graph->IsOversized(TxGraph::Level::TOP)); // We only need to trim the middle bottom transaction to end up with 2 clusters each within cluster limits. BOOST_CHECK_EQUAL(removed_refs.size(), 1); - BOOST_CHECK_EQUAL(graph->GetTransactionCount(), MAX_CLUSTER_COUNT * 2 - 2); + BOOST_CHECK_EQUAL(graph->GetTransactionCount(TxGraph::Level::TOP), MAX_CLUSTER_COUNT * 2 - 2); for (unsigned int i = 0; i < refs.size(); ++i) { - BOOST_CHECK_EQUAL(graph->Exists(refs[i]), i != (NUM_BOTTOM_TX / 2)); + BOOST_CHECK_EQUAL(graph->Exists(refs[i], TxGraph::Level::TOP), i != (NUM_BOTTOM_TX / 2)); } } @@ -123,19 +123,19 @@ BOOST_AUTO_TEST_CASE(txgraph_trim_flower) // Check that the graph is now oversized. This also forces the graph to // group clusters and compute the oversized status. - BOOST_CHECK(graph->IsOversized(/*main_only=*/false)); + BOOST_CHECK(graph->IsOversized(TxGraph::Level::TOP)); // Call Trim() to remove transactions and bring the cluster back within limits. auto removed_refs = graph->Trim(); graph->SanityCheck(); - BOOST_CHECK(!graph->IsOversized(/*main_only=*/false)); + BOOST_CHECK(!graph->IsOversized(TxGraph::Level::TOP)); // Since only the bottom transaction connects these clusters, we only need to remove it. BOOST_CHECK_EQUAL(removed_refs.size(), 1); - BOOST_CHECK_EQUAL(graph->GetTransactionCount(false), MAX_CLUSTER_COUNT * 2); - BOOST_CHECK(!graph->Exists(refs[0])); + BOOST_CHECK_EQUAL(graph->GetTransactionCount(TxGraph::Level::TOP), MAX_CLUSTER_COUNT * 2); + BOOST_CHECK(!graph->Exists(refs[0], TxGraph::Level::TOP)); for (unsigned int i = 1; i < refs.size(); ++i) { - BOOST_CHECK(graph->Exists(refs[i])); + BOOST_CHECK(graph->Exists(refs[i], TxGraph::Level::TOP)); } } @@ -208,7 +208,7 @@ BOOST_AUTO_TEST_CASE(txgraph_trim_huge) graph->SanityCheck(); // Not oversized so far (just 1000 clusters of 64). - BOOST_CHECK(!graph->IsOversized()); + BOOST_CHECK(!graph->IsOversized(TxGraph::Level::TOP)); // Construct the bottom transactions, and dependencies to the top chains. while (top_components.size() > 1) { @@ -237,19 +237,19 @@ BOOST_AUTO_TEST_CASE(txgraph_trim_huge) graph->SanityCheck(); // Now we are oversized (one cluster of 64011). - BOOST_CHECK(graph->IsOversized()); - const auto total_tx_count = graph->GetTransactionCount(); + BOOST_CHECK(graph->IsOversized(TxGraph::Level::TOP)); + const auto total_tx_count = graph->GetTransactionCount(TxGraph::Level::TOP); BOOST_CHECK(total_tx_count == top_refs.size() + bottom_refs.size()); BOOST_CHECK(total_tx_count == NUM_TOTAL_TX); // Call Trim() to remove transactions and bring the cluster back within limits. auto removed_refs = graph->Trim(); - BOOST_CHECK(!graph->IsOversized()); - BOOST_CHECK(removed_refs.size() == total_tx_count - graph->GetTransactionCount()); + BOOST_CHECK(!graph->IsOversized(TxGraph::Level::TOP)); + BOOST_CHECK(removed_refs.size() == total_tx_count - graph->GetTransactionCount(TxGraph::Level::TOP)); graph->SanityCheck(); // At least 99% of chains must survive. - BOOST_CHECK(graph->GetTransactionCount() >= (NUM_TOP_CHAINS * NUM_TX_PER_TOP_CHAIN * 99) / 100); + BOOST_CHECK(graph->GetTransactionCount(TxGraph::Level::TOP) >= (NUM_TOP_CHAINS * NUM_TX_PER_TOP_CHAIN * 99) / 100); } BOOST_AUTO_TEST_CASE(txgraph_trim_big_singletons) @@ -277,17 +277,17 @@ BOOST_AUTO_TEST_CASE(txgraph_trim_big_singletons) // Check that the graph is now oversized. This also forces the graph to // group clusters and compute the oversized status. - BOOST_CHECK(graph->IsOversized(/*main_only=*/false)); + BOOST_CHECK(graph->IsOversized(TxGraph::Level::TOP)); // Call Trim() to remove transactions and bring the cluster back within limits. auto removed_refs = graph->Trim(); graph->SanityCheck(); - BOOST_CHECK_EQUAL(graph->GetTransactionCount(), NUM_TOTAL_TX - 6); - BOOST_CHECK(!graph->IsOversized(/*main_only=*/false)); + BOOST_CHECK_EQUAL(graph->GetTransactionCount(TxGraph::Level::TOP), NUM_TOTAL_TX - 6); + BOOST_CHECK(!graph->IsOversized(TxGraph::Level::TOP)); // Check that all the oversized transactions were removed. for (unsigned int i = 0; i < refs.size(); ++i) { - BOOST_CHECK_EQUAL(graph->Exists(refs[i]), i != 88 && i % 20 != 0); + BOOST_CHECK_EQUAL(graph->Exists(refs[i], TxGraph::Level::TOP), i != 88 && i % 20 != 0); } } diff --git a/src/txgraph.cpp b/src/txgraph.cpp index 345be02f0f1..c8ff7537fe1 100644 --- a/src/txgraph.cpp +++ b/src/txgraph.cpp @@ -496,8 +496,8 @@ public: void SetClusterQuality(int level, QualityLevel old_quality, ClusterSetIndex old_index, QualityLevel new_quality) noexcept; /** Get the index of the top level ClusterSet (staging if it exists, main otherwise). */ int GetTopLevel() const noexcept { return m_staging_clusterset.has_value(); } - /** Get the specified level (staging if it exists and main_only is not specified, main otherwise). */ - int GetSpecifiedLevel(bool main_only) const noexcept { return m_staging_clusterset.has_value() && !main_only; } + /** Get the specified level (staging if it exists and level is TOP, main otherwise). */ + int GetSpecifiedLevel(Level level) const noexcept { return level == Level::TOP && m_staging_clusterset.has_value(); } /** Get a reference to the ClusterSet at the specified level (which must exist). */ ClusterSet& GetClusterSet(int level) noexcept; const ClusterSet& GetClusterSet(int level) const noexcept; @@ -600,18 +600,18 @@ public: void AbortStaging() noexcept final; bool HaveStaging() const noexcept final { return m_staging_clusterset.has_value(); } - bool Exists(const Ref& arg, bool main_only = false) noexcept final; + bool Exists(const Ref& arg, Level level) noexcept final; FeePerWeight GetMainChunkFeerate(const Ref& arg) noexcept final; FeePerWeight GetIndividualFeerate(const Ref& arg) noexcept final; - std::vector GetCluster(const Ref& arg, bool main_only = false) noexcept final; - std::vector GetAncestors(const Ref& arg, bool main_only = false) noexcept final; - std::vector GetDescendants(const Ref& arg, bool main_only = false) noexcept final; - std::vector GetAncestorsUnion(std::span args, bool main_only = false) noexcept final; - std::vector GetDescendantsUnion(std::span args, bool main_only = false) noexcept final; - GraphIndex GetTransactionCount(bool main_only = false) noexcept final; - bool IsOversized(bool main_only = false) noexcept final; + std::vector GetCluster(const Ref& arg, Level level) noexcept final; + std::vector GetAncestors(const Ref& arg, Level level) noexcept final; + std::vector GetDescendants(const Ref& arg, Level level) noexcept final; + std::vector GetAncestorsUnion(std::span args, Level level) noexcept final; + std::vector GetDescendantsUnion(std::span args, Level level) noexcept final; + GraphIndex GetTransactionCount(Level level) noexcept final; + bool IsOversized(Level level) noexcept final; std::strong_ordering CompareMainOrder(const Ref& a, const Ref& b) noexcept final; - GraphIndex CountDistinctClusters(std::span refs, bool main_only = false) noexcept final; + GraphIndex CountDistinctClusters(std::span refs, Level level) noexcept final; std::pair, std::vector> GetMainStagingDiagrams() noexcept final; std::vector Trim() noexcept final; @@ -1790,11 +1790,11 @@ void TxGraphImpl::AddDependency(const Ref& parent, const Ref& child) noexcept if (clusterset.m_oversized == false) clusterset.m_oversized = std::nullopt; } -bool TxGraphImpl::Exists(const Ref& arg, bool main_only) noexcept +bool TxGraphImpl::Exists(const Ref& arg, Level level_select) noexcept { if (GetRefGraph(arg) == nullptr) return false; Assume(GetRefGraph(arg) == this); - size_t level = GetSpecifiedLevel(main_only); + size_t level = GetSpecifiedLevel(level_select); // Make sure the transaction isn't scheduled for removal. ApplyRemovals(level); auto cluster = FindCluster(GetRefIndex(arg), level); @@ -1870,13 +1870,13 @@ void Cluster::MakeStagingTransactionsMissing(TxGraphImpl& graph) noexcept } } -std::vector TxGraphImpl::GetAncestors(const Ref& arg, bool main_only) noexcept +std::vector TxGraphImpl::GetAncestors(const Ref& arg, Level level_select) noexcept { // Return the empty vector if the Ref is empty. if (GetRefGraph(arg) == nullptr) return {}; Assume(GetRefGraph(arg) == this); // Apply all removals and dependencies, as the result might be incorrect otherwise. - size_t level = GetSpecifiedLevel(main_only); + size_t level = GetSpecifiedLevel(level_select); ApplyDependencies(level); // Ancestry cannot be known if unapplied dependencies remain. Assume(GetClusterSet(level).m_deps_to_add.empty()); @@ -1891,13 +1891,13 @@ std::vector TxGraphImpl::GetAncestors(const Ref& arg, bool main_o return ret; } -std::vector TxGraphImpl::GetDescendants(const Ref& arg, bool main_only) noexcept +std::vector TxGraphImpl::GetDescendants(const Ref& arg, Level level_select) noexcept { // Return the empty vector if the Ref is empty. if (GetRefGraph(arg) == nullptr) return {}; Assume(GetRefGraph(arg) == this); // Apply all removals and dependencies, as the result might be incorrect otherwise. - size_t level = GetSpecifiedLevel(main_only); + size_t level = GetSpecifiedLevel(level_select); ApplyDependencies(level); // Ancestry cannot be known if unapplied dependencies remain. Assume(GetClusterSet(level).m_deps_to_add.empty()); @@ -1912,10 +1912,10 @@ std::vector TxGraphImpl::GetDescendants(const Ref& arg, bool main return ret; } -std::vector TxGraphImpl::GetAncestorsUnion(std::span args, bool main_only) noexcept +std::vector TxGraphImpl::GetAncestorsUnion(std::span args, Level level_select) noexcept { // Apply all dependencies, as the result might be incorrect otherwise. - size_t level = GetSpecifiedLevel(main_only); + size_t level = GetSpecifiedLevel(level_select); ApplyDependencies(level); // Ancestry cannot be known if unapplied dependencies remain. Assume(GetClusterSet(level).m_deps_to_add.empty()); @@ -1945,10 +1945,10 @@ std::vector TxGraphImpl::GetAncestorsUnion(std::span TxGraphImpl::GetDescendantsUnion(std::span args, bool main_only) noexcept +std::vector TxGraphImpl::GetDescendantsUnion(std::span args, Level level_select) noexcept { // Apply all dependencies, as the result might be incorrect otherwise. - size_t level = GetSpecifiedLevel(main_only); + size_t level = GetSpecifiedLevel(level_select); ApplyDependencies(level); // Ancestry cannot be known if unapplied dependencies remain. Assume(GetClusterSet(level).m_deps_to_add.empty()); @@ -1978,14 +1978,14 @@ std::vector TxGraphImpl::GetDescendantsUnion(std::span TxGraphImpl::GetCluster(const Ref& arg, bool main_only) noexcept +std::vector TxGraphImpl::GetCluster(const Ref& arg, Level level_select) noexcept { // Return the empty vector if the Ref is empty (which may be indicative of the transaction // having been removed already. if (GetRefGraph(arg) == nullptr) return {}; Assume(GetRefGraph(arg) == this); // Apply all removals and dependencies, as the result might be incorrect otherwise. - size_t level = GetSpecifiedLevel(main_only); + size_t level = GetSpecifiedLevel(level_select); ApplyDependencies(level); // Cluster linearization cannot be known if unapplied dependencies remain. Assume(GetClusterSet(level).m_deps_to_add.empty()); @@ -1999,9 +1999,9 @@ std::vector TxGraphImpl::GetCluster(const Ref& arg, bool main_onl return ret; } -TxGraph::GraphIndex TxGraphImpl::GetTransactionCount(bool main_only) noexcept +TxGraph::GraphIndex TxGraphImpl::GetTransactionCount(Level level_select) noexcept { - size_t level = GetSpecifiedLevel(main_only); + size_t level = GetSpecifiedLevel(level_select); ApplyRemovals(level); return GetClusterSet(level).m_txcount; } @@ -2047,9 +2047,9 @@ FeePerWeight TxGraphImpl::GetMainChunkFeerate(const Ref& arg) noexcept return entry.m_main_chunk_feerate; } -bool TxGraphImpl::IsOversized(bool main_only) noexcept +bool TxGraphImpl::IsOversized(Level level_select) noexcept { - size_t level = GetSpecifiedLevel(main_only); + size_t level = GetSpecifiedLevel(level_select); auto& clusterset = GetClusterSet(level); if (clusterset.m_oversized.has_value()) { // Return cached value if known. @@ -2213,9 +2213,9 @@ std::strong_ordering TxGraphImpl::CompareMainOrder(const Ref& a, const Ref& b) n return CompareMainTransactions(GetRefIndex(a), GetRefIndex(b)); } -TxGraph::GraphIndex TxGraphImpl::CountDistinctClusters(std::span refs, bool main_only) noexcept +TxGraph::GraphIndex TxGraphImpl::CountDistinctClusters(std::span refs, Level level_select) noexcept { - size_t level = GetSpecifiedLevel(main_only); + size_t level = GetSpecifiedLevel(level_select); ApplyDependencies(level); auto& clusterset = GetClusterSet(level); Assume(clusterset.m_deps_to_add.empty()); diff --git a/src/txgraph.h b/src/txgraph.h index ef2a7bd3c06..20ea97ac5e4 100644 --- a/src/txgraph.h +++ b/src/txgraph.h @@ -60,6 +60,11 @@ public: */ class Ref; + enum class Level { + TOP, //!< Refers to staging if it exists, main otherwise. + MAIN //!< Always refers to the main graph, whether staging is present or not. + }; + /** Virtual destructor, so inheriting is safe. */ virtual ~TxGraph() = default; /** Construct a new transaction with the specified feerate, and return a Ref to it. @@ -112,16 +117,14 @@ public: virtual bool HaveStaging() const noexcept = 0; /** Determine whether the graph is oversized (contains a connected component of more than the - * configured maximum cluster count). If main_only is false and a staging graph exists, it is - * queried; otherwise the main graph is queried. Some of the functions below are not available + * configured maximum cluster count). Some of the functions below are not available * for oversized graphs. The mutators above are always available. Removing a transaction by * destroying its Ref while staging exists will not clear main's oversizedness until staging * is aborted or committed. */ - virtual bool IsOversized(bool main_only = false) noexcept = 0; - /** Determine whether arg exists in the graph (i.e., was not removed). If main_only is false - * and a staging graph exists, it is queried; otherwise the main graph is queried. This is + virtual bool IsOversized(Level level) noexcept = 0; + /** Determine whether arg exists in the graph (i.e., was not removed). This is * available even for oversized graphs. */ - virtual bool Exists(const Ref& arg, bool main_only = false) noexcept = 0; + virtual bool Exists(const Ref& arg, Level level) noexcept = 0; /** Get the individual transaction feerate of transaction arg. Returns the empty FeePerWeight * if arg does not exist in either main or staging. This is available even for oversized * graphs. */ @@ -131,40 +134,35 @@ public: * oversized. */ virtual FeePerWeight GetMainChunkFeerate(const Ref& arg) noexcept = 0; /** Get pointers to all transactions in the cluster which arg is in. The transactions are - * returned in graph order. If main_only is false and a staging graph exists, it is queried; - * otherwise the main graph is queried. The queried graph must not be oversized. Returns {} if + * returned in graph order. The queried graph must not be oversized. Returns {} if * arg does not exist in the queried graph. */ - virtual std::vector GetCluster(const Ref& arg, bool main_only = false) noexcept = 0; + virtual std::vector GetCluster(const Ref& arg, Level level) noexcept = 0; /** Get pointers to all ancestors of the specified transaction (including the transaction - * itself), in unspecified order. If main_only is false and a staging graph exists, it is - * queried; otherwise the main graph is queried. The queried graph must not be oversized. + * itself), in unspecified order. The queried graph must not be oversized. * Returns {} if arg does not exist in the graph. */ - virtual std::vector GetAncestors(const Ref& arg, bool main_only = false) noexcept = 0; + virtual std::vector GetAncestors(const Ref& arg, Level level) noexcept = 0; /** Get pointers to all descendants of the specified transaction (including the transaction - * itself), in unspecified order. If main_only is false and a staging graph exists, it is - * queried; otherwise the main graph is queried. The queried graph must not be oversized. + * itself), in unspecified order. The queried graph must not be oversized. * Returns {} if arg does not exist in the graph. */ - virtual std::vector GetDescendants(const Ref& arg, bool main_only = false) noexcept = 0; + virtual std::vector GetDescendants(const Ref& arg, Level level) noexcept = 0; /** Like GetAncestors, but return the Refs for all transactions in the union of the provided * arguments' ancestors (each transaction is only reported once). Refs that do not exist in * the queried graph are ignored. Null refs are not allowed. */ - virtual std::vector GetAncestorsUnion(std::span args, bool main_only = false) noexcept = 0; + virtual std::vector GetAncestorsUnion(std::span args, Level level) noexcept = 0; /** Like GetDescendants, but return the Refs for all transactions in the union of the provided * arguments' descendants (each transaction is only reported once). Refs that do not exist in * the queried graph are ignored. Null refs are not allowed. */ - virtual std::vector GetDescendantsUnion(std::span args, bool main_only = false) noexcept = 0; - /** Get the total number of transactions in the graph. If main_only is false and a staging - * graph exists, it is queried; otherwise the main graph is queried. This is available even + virtual std::vector GetDescendantsUnion(std::span args, Level level) noexcept = 0; + /** Get the total number of transactions in the graph. This is available even * for oversized graphs. */ - virtual GraphIndex GetTransactionCount(bool main_only = false) noexcept = 0; + virtual GraphIndex GetTransactionCount(Level level) noexcept = 0; /** Compare two transactions according to their order in the main graph. Both transactions must * be in the main graph. The main graph must not be oversized. */ virtual std::strong_ordering CompareMainOrder(const Ref& a, const Ref& b) noexcept = 0; - /** Count the number of distinct clusters that the specified transactions belong to. If - * main_only is false and a staging graph exists, staging clusters are counted. Otherwise, - * main clusters are counted. Refs that do not exist in the queried graph are ignored. Refs - * can not be null. The queried graph must not be oversized. */ - virtual GraphIndex CountDistinctClusters(std::span, bool main_only = false) noexcept = 0; + /** Count the number of distinct clusters that the specified transactions belong to. Refs that + * do not exist in the queried graph are ignored. Refs can not be null. The queried graph must + * not be oversized. */ + virtual GraphIndex CountDistinctClusters(std::span, Level level) noexcept = 0; /** For both main and staging (which must both exist and not be oversized), return the combined * respective feerate diagrams, including chunks from all clusters, but excluding clusters * that appear identically in both. Use FeeFrac rather than FeePerWeight so CompareChunks is