txgraph: use enum Level instead of bool main_only
What changed, and why it matters
This commit is a straightforward code cleanup: it replaces a confusing boolean parameter called main_only with a clearer enum named Level (with values TOP and MAIN) throughout the transaction-graph code. The behavior of the program is unchanged; only the names and call sites are updated to make the code easier to read and maintain.
No security action required. Treat as a normal maintainability refactor.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch refactors the TxGraph API by introducing an enum class TxGraph::Level { TOP, MAIN } and replacing every bool main_only parameter and default argument with an explicit Level argument. GetSpecifiedLevel(bool) becomes GetSpecifiedLevel(Level). All call sites in benchmarks, fuzz tests, unit tests, and the implementation are updated accordingly. The semantics remain identical: Level::TOP selects staging when present and main otherwise; Level::MAIN always selects main. No logic changes are introduced.
Changed components
src/txgraph.hsrc/txgraph.cppsrc/test/txgraph_tests.cppsrc/test/fuzz/txgraph.cppsrc/bench/txgraph.cppInspect captured patch +103 / −105
diff --git a/src/bench/txgraph.cpp b/src/bench/txgraph.cpp
index 5303386b..70824c2a 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 50af38db..00001034 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<FeeFrac> {
- int level = main_only ? 0 : sims.size() - 1;
+ auto get_diagram_fn = [&](TxGraph::Level level_select) -> std::vector<FeeFrac> {
+ 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<std::vector<TxGraph::Ref*>> 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<FeeFrac> 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 63741e6c..3fb20d8d 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 345be02f..c8ff7537 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<Ref*> GetCluster(const Ref& arg, bool main_only = false) noexcept final;
- std::vector<Ref*> GetAncestors(const Ref& arg, bool main_only = false) noexcept final;
- std::vector<Ref*> GetDescendants(const Ref& arg, bool main_only = false) noexcept final;
- std::vector<Ref*> GetAncestorsUnion(std::span<const Ref* const> args, bool main_only = false) noexcept final;
- std::vector<Ref*> GetDescendantsUnion(std::span<const Ref* const> 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<Ref*> GetCluster(const Ref& arg, Level level) noexcept final;
+ std::vector<Ref*> GetAncestors(const Ref& arg, Level level) noexcept final;
+ std::vector<Ref*> GetDescendants(const Ref& arg, Level level) noexcept final;
+ std::vector<Ref*> GetAncestorsUnion(std::span<const Ref* const> args, Level level) noexcept final;
+ std::vector<Ref*> GetDescendantsUnion(std::span<const Ref* const> 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<const Ref* const> refs, bool main_only = false) noexcept final;
+ GraphIndex CountDistinctClusters(std::span<const Ref* const> refs, Level level) noexcept final;
std::pair<std::vector<FeeFrac>, std::vector<FeeFrac>> GetMainStagingDiagrams() noexcept final;
std::vector<Ref*> 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<TxGraph::Ref*> TxGraphImpl::GetAncestors(const Ref& arg, bool main_only) noexcept
+std::vector<TxGraph::Ref*> 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<TxGraph::Ref*> TxGraphImpl::GetAncestors(const Ref& arg, bool main_o
return ret;
}
-std::vector<TxGraph::Ref*> TxGraphImpl::GetDescendants(const Ref& arg, bool main_only) noexcept
+std::vector<TxGraph::Ref*> 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<TxGraph::Ref*> TxGraphImpl::GetDescendants(const Ref& arg, bool main
return ret;
}
-std::vector<TxGraph::Ref*> TxGraphImpl::GetAncestorsUnion(std::span<const Ref* const> args, bool main_only) noexcept
+std::vector<TxGraph::Ref*> TxGraphImpl::GetAncestorsUnion(std::span<const Ref* const> 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<TxGraph::Ref*> TxGraphImpl::GetAncestorsUnion(std::span<const Ref* c
return ret;
}
-std::vector<TxGraph::Ref*> TxGraphImpl::GetDescendantsUnion(std::span<const Ref* const> args, bool main_only) noexcept
+std::vector<TxGraph::Ref*> TxGraphImpl::GetDescendantsUnion(std::span<const Ref* const> 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<TxGraph::Ref*> TxGraphImpl::GetDescendantsUnion(std::span<const Ref*
return ret;
}
-std::vector<TxGraph::Ref*> TxGraphImpl::GetCluster(const Ref& arg, bool main_only) noexcept
+std::vector<TxGraph::Ref*> 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<TxGraph::Ref*> 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<const Ref* const> refs, bool main_only) noexcept
+TxGraph::GraphIndex TxGraphImpl::CountDistinctClusters(std::span<const Ref* const> 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 ef2a7bd3..20ea97ac 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<Ref*> GetCluster(const Ref& arg, bool main_only = false) noexcept = 0;
+ virtual std::vector<Ref*> 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<Ref*> GetAncestors(const Ref& arg, bool main_only = false) noexcept = 0;
+ virtual std::vector<Ref*> 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<Ref*> GetDescendants(const Ref& arg, bool main_only = false) noexcept = 0;
+ virtual std::vector<Ref*> 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<Ref*> GetAncestorsUnion(std::span<const Ref* const> args, bool main_only = false) noexcept = 0;
+ virtual std::vector<Ref*> GetAncestorsUnion(std::span<const Ref* const> 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<Ref*> GetDescendantsUnion(std::span<const Ref* const> 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<Ref*> GetDescendantsUnion(std::span<const Ref* const> 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<const Ref* const>, 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<const Ref* const>, 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
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.