mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-03 17:54:19 +02:00
Merge bitcoin/bitcoin#33354: txgraph: use enum Level instead of bool main_only
d45f3717d2txgraph: use enum Level instead of bool main_only (Pieter Wuille) Pull request description: Part of #30289. Inspired by https://github.com/bitcoin/bitcoin/pull/28676#discussion_r2331387778. Since there has been more than one case in the development of #28676 of calling a `TxGraph` function without correctly setting the `bool main_only` argument that many of its interface functions have, make these mandatory and explicit, using an `enum class Level`: ```c++ 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. }; ``` ACKs for top commit: instagibbs: ACKd45f3717d2vasild: ACKd45f3717d2glozow: code review ACKd45f3717d2Tree-SHA512: d1c4b37e8ab3ec91b414df8970cb47aa080803f68da5881c8e1cbdc6939dea7851e0f715192cf3edd44b7f328cd6b678474d41f9cd9da8cb68f6c5fd78cb71b1
This commit is contained in:
@@ -114,9 +114,9 @@ void BenchTxGraphTrim(benchmark::Bench& bench)
|
|||||||
graph->GetBlockBuilder();
|
graph->GetBlockBuilder();
|
||||||
});
|
});
|
||||||
|
|
||||||
assert(!graph->IsOversized());
|
assert(!graph->IsOversized(TxGraph::Level::TOP));
|
||||||
// At least 99% of chains must survive.
|
// 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
|
} // namespace
|
||||||
|
|||||||
@@ -383,14 +383,14 @@ FUZZ_TARGET(txgraph)
|
|||||||
|
|
||||||
/** Function to construct the correct fee-size diagram a real graph has based on its graph
|
/** 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). */
|
* order (as reported by GetCluster(), so it works for both main and staging). */
|
||||||
auto get_diagram_fn = [&](bool main_only) -> std::vector<FeeFrac> {
|
auto get_diagram_fn = [&](TxGraph::Level level_select) -> std::vector<FeeFrac> {
|
||||||
int level = main_only ? 0 : sims.size() - 1;
|
int level = level_select == TxGraph::Level::MAIN ? 0 : sims.size() - 1;
|
||||||
auto& sim = sims[level];
|
auto& sim = sims[level];
|
||||||
// For every transaction in the graph, request its cluster, and throw them into a set.
|
// For every transaction in the graph, request its cluster, and throw them into a set.
|
||||||
std::set<std::vector<TxGraph::Ref*>> clusters;
|
std::set<std::vector<TxGraph::Ref*>> clusters;
|
||||||
for (auto i : sim.graph.Positions()) {
|
for (auto i : sim.graph.Positions()) {
|
||||||
auto ref = sim.GetRef(i);
|
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.
|
// Compute the chunkings of each (deduplicated) cluster.
|
||||||
size_t num_tx{0};
|
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
|
// operations), and the second-lowest bit as a way of selecting main vs. staging, and leave
|
||||||
// the rest of the bits in command.
|
// the rest of the bits in command.
|
||||||
bool alt = command & 1;
|
bool alt = command & 1;
|
||||||
bool use_main = command & 2;
|
TxGraph::Level level_select = (command & 2) ? TxGraph::Level::MAIN : TxGraph::Level::TOP;
|
||||||
command >>= 2;
|
command >>= 2;
|
||||||
|
|
||||||
/** Use the bottom 2 bits of command to select an entry in the block_builders vector (if
|
/** 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. */
|
* where builder_idx is used as well. */
|
||||||
int builder_idx = block_builders.empty() ? -1 : int((orig_command & 3) % block_builders.size());
|
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),
|
// 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.
|
// on both graphs), and one that always refers to the main graph.
|
||||||
auto& top_sim = sims.back();
|
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];
|
auto& main_sim = sims[0];
|
||||||
|
|
||||||
// Keep decrementing command for each applicable operation, until one is hit. Multiple
|
// Keep decrementing command for each applicable operation, until one is hit. Multiple
|
||||||
@@ -546,18 +546,18 @@ FUZZ_TARGET(txgraph)
|
|||||||
break;
|
break;
|
||||||
} else if (command-- == 0) {
|
} else if (command-- == 0) {
|
||||||
// GetTransactionCount.
|
// GetTransactionCount.
|
||||||
assert(real->GetTransactionCount(use_main) == sel_sim.GetTransactionCount());
|
assert(real->GetTransactionCount(level_select) == sel_sim.GetTransactionCount());
|
||||||
break;
|
break;
|
||||||
} else if (command-- == 0) {
|
} else if (command-- == 0) {
|
||||||
// Exists.
|
// Exists.
|
||||||
auto ref = pick_fn();
|
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;
|
bool should_exist = sel_sim.Find(ref) != SimTxGraph::MISSING;
|
||||||
assert(exists == should_exist);
|
assert(exists == should_exist);
|
||||||
break;
|
break;
|
||||||
} else if (command-- == 0) {
|
} else if (command-- == 0) {
|
||||||
// IsOversized.
|
// IsOversized.
|
||||||
assert(sel_sim.IsOversized() == real->IsOversized(use_main));
|
assert(sel_sim.IsOversized() == real->IsOversized(level_select));
|
||||||
break;
|
break;
|
||||||
} else if (command-- == 0) {
|
} else if (command-- == 0) {
|
||||||
// GetIndividualFeerate.
|
// GetIndividualFeerate.
|
||||||
@@ -590,8 +590,8 @@ FUZZ_TARGET(txgraph)
|
|||||||
} else if (!sel_sim.IsOversized() && command-- == 0) {
|
} else if (!sel_sim.IsOversized() && command-- == 0) {
|
||||||
// GetAncestors/GetDescendants.
|
// GetAncestors/GetDescendants.
|
||||||
auto ref = pick_fn();
|
auto ref = pick_fn();
|
||||||
auto result = alt ? real->GetDescendants(*ref, use_main)
|
auto result = alt ? real->GetDescendants(*ref, level_select)
|
||||||
: real->GetAncestors(*ref, use_main);
|
: real->GetAncestors(*ref, level_select);
|
||||||
assert(result.size() <= max_cluster_count);
|
assert(result.size() <= max_cluster_count);
|
||||||
auto result_set = sel_sim.MakeSet(result);
|
auto result_set = sel_sim.MakeSet(result);
|
||||||
assert(result.size() == result_set.Count());
|
assert(result.size() == result_set.Count());
|
||||||
@@ -610,8 +610,8 @@ FUZZ_TARGET(txgraph)
|
|||||||
// Their order should not matter, shuffle them.
|
// Their order should not matter, shuffle them.
|
||||||
std::shuffle(refs.begin(), refs.end(), rng);
|
std::shuffle(refs.begin(), refs.end(), rng);
|
||||||
// Invoke the real function, and convert to SimPos set.
|
// Invoke the real function, and convert to SimPos set.
|
||||||
auto result = alt ? real->GetDescendantsUnion(refs, use_main)
|
auto result = alt ? real->GetDescendantsUnion(refs, level_select)
|
||||||
: real->GetAncestorsUnion(refs, use_main);
|
: real->GetAncestorsUnion(refs, level_select);
|
||||||
auto result_set = sel_sim.MakeSet(result);
|
auto result_set = sel_sim.MakeSet(result);
|
||||||
assert(result.size() == result_set.Count());
|
assert(result.size() == result_set.Count());
|
||||||
// Compute the expected result.
|
// Compute the expected result.
|
||||||
@@ -623,7 +623,7 @@ FUZZ_TARGET(txgraph)
|
|||||||
} else if (!sel_sim.IsOversized() && command-- == 0) {
|
} else if (!sel_sim.IsOversized() && command-- == 0) {
|
||||||
// GetCluster.
|
// GetCluster.
|
||||||
auto ref = pick_fn();
|
auto ref = pick_fn();
|
||||||
auto result = real->GetCluster(*ref, use_main);
|
auto result = real->GetCluster(*ref, level_select);
|
||||||
// Check cluster count limit.
|
// Check cluster count limit.
|
||||||
assert(result.size() <= max_cluster_count);
|
assert(result.size() <= max_cluster_count);
|
||||||
// Require the result to be topologically valid and not contain duplicates.
|
// 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.
|
// Their order should not matter, shuffle them.
|
||||||
std::shuffle(refs.begin(), refs.end(), rng);
|
std::shuffle(refs.begin(), refs.end(), rng);
|
||||||
// Invoke the real function.
|
// 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
|
// 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
|
// simulated graph. For each, remember the lowest-index transaction SimPos in the
|
||||||
// cluster.
|
// cluster.
|
||||||
@@ -905,7 +905,7 @@ FUZZ_TARGET(txgraph)
|
|||||||
|
|
||||||
// First, we need to have dependencies applied and linearizations fixed to avoid
|
// First, we need to have dependencies applied and linearizations fixed to avoid
|
||||||
// circular dependencies in implied graph; trigger it via whatever means.
|
// circular dependencies in implied graph; trigger it via whatever means.
|
||||||
real->CountDistinctClusters({}, false);
|
real->CountDistinctClusters({}, TxGraph::Level::TOP);
|
||||||
|
|
||||||
// Gather the current clusters.
|
// Gather the current clusters.
|
||||||
auto clusters = top_sim.GetComponents();
|
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
|
// Check that the implied ordering gives rise to a combined diagram that matches the
|
||||||
// diagram constructed from the individual cluster linearization chunkings.
|
// 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);
|
auto main_implied_diagram = ChunkLinearization(sims[0].graph, vec1);
|
||||||
assert(CompareChunks(main_real_diagram, main_implied_diagram) == 0);
|
assert(CompareChunks(main_real_diagram, main_implied_diagram) == 0);
|
||||||
|
|
||||||
@@ -1141,7 +1141,7 @@ FUZZ_TARGET(txgraph)
|
|||||||
std::greater{});
|
std::greater{});
|
||||||
assert(main_cmp_diagram.size() + missing_main_cmp.size() == main_real_diagram.size());
|
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.
|
// 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::vector<FeeFrac> missing_stage_cmp;
|
||||||
std::set_difference(stage_real_diagram.begin(), stage_real_diagram.end(),
|
std::set_difference(stage_real_diagram.begin(), stage_real_diagram.end(),
|
||||||
stage_cmp_diagram.begin(), stage_cmp_diagram.end(),
|
stage_cmp_diagram.begin(), stage_cmp_diagram.end(),
|
||||||
@@ -1167,13 +1167,13 @@ FUZZ_TARGET(txgraph)
|
|||||||
|
|
||||||
assert(real->HaveStaging() == (sims.size() > 1));
|
assert(real->HaveStaging() == (sims.size() > 1));
|
||||||
|
|
||||||
// Try to run a full comparison, for both main_only=false and main_only=true in TxGraph
|
// Try to run a full comparison, for both TxGraph::Level::MAIN and TxGraph::Level::TOP in
|
||||||
// inspector functions that support both.
|
// TxGraph inspector functions that support both.
|
||||||
for (int main_only = 0; main_only < 2; ++main_only) {
|
for (auto level : {TxGraph::Level::TOP, TxGraph::Level::MAIN}) {
|
||||||
auto& sim = main_only ? sims[0] : sims.back();
|
auto& sim = level == TxGraph::Level::TOP ? sims.back() : sims.front();
|
||||||
// Compare simple properties of the graph with the simulation.
|
// Compare simple properties of the graph with the simulation.
|
||||||
assert(real->IsOversized(main_only) == sim.IsOversized());
|
assert(real->IsOversized(level) == sim.IsOversized());
|
||||||
assert(real->GetTransactionCount(main_only) == sim.GetTransactionCount());
|
assert(real->GetTransactionCount(level) == sim.GetTransactionCount());
|
||||||
// If the graph (and the simulation) are not oversized, perform a full comparison.
|
// If the graph (and the simulation) are not oversized, perform a full comparison.
|
||||||
if (!sim.IsOversized()) {
|
if (!sim.IsOversized()) {
|
||||||
auto todo = sim.graph.Positions();
|
auto todo = sim.graph.Positions();
|
||||||
@@ -1188,16 +1188,16 @@ FUZZ_TARGET(txgraph)
|
|||||||
assert(sim.graph.FeeRate(i) == real->GetIndividualFeerate(*sim.GetRef(i)));
|
assert(sim.graph.FeeRate(i) == real->GetIndividualFeerate(*sim.GetRef(i)));
|
||||||
// Check its ancestors against simulation.
|
// Check its ancestors against simulation.
|
||||||
auto expect_anc = sim.graph.Ancestors(i);
|
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.Count() <= max_cluster_count);
|
||||||
assert(anc == expect_anc);
|
assert(anc == expect_anc);
|
||||||
// Check its descendants against simulation.
|
// Check its descendants against simulation.
|
||||||
auto expect_desc = sim.graph.Descendants(i);
|
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.Count() <= max_cluster_count);
|
||||||
assert(desc == expect_desc);
|
assert(desc == expect_desc);
|
||||||
// Check the cluster the transaction is part of.
|
// 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(cluster.size() <= max_cluster_count);
|
||||||
assert(sim.MakeSet(cluster) == component);
|
assert(sim.MakeSet(cluster) == component);
|
||||||
// Check that the cluster is reported in a valid topological order (its
|
// 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);
|
assert(total_size <= max_cluster_size);
|
||||||
// Construct a chunking object for the simulated graph, using the reported cluster
|
// Construct a chunking object for the simulated graph, using the reported cluster
|
||||||
// linearization as ordering, and compare it against the reported chunk feerates.
|
// 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);
|
cluster_linearize::LinearizationChunking simlinchunk(sim.graph, simlin);
|
||||||
DepGraphIndex idx{0};
|
DepGraphIndex idx{0};
|
||||||
for (unsigned chunknum = 0; chunknum < simlinchunk.NumChunksLeft(); ++chunknum) {
|
for (unsigned chunknum = 0; chunknum < simlinchunk.NumChunksLeft(); ++chunknum) {
|
||||||
|
|||||||
@@ -64,19 +64,19 @@ BOOST_AUTO_TEST_CASE(txgraph_trim_zigzag)
|
|||||||
// Check that the graph is now oversized. This also forces the graph to
|
// Check that the graph is now oversized. This also forces the graph to
|
||||||
// group clusters and compute the oversized status.
|
// group clusters and compute the oversized status.
|
||||||
graph->SanityCheck();
|
graph->SanityCheck();
|
||||||
BOOST_CHECK_EQUAL(graph->GetTransactionCount(), NUM_TOTAL_TX);
|
BOOST_CHECK_EQUAL(graph->GetTransactionCount(TxGraph::Level::TOP), NUM_TOTAL_TX);
|
||||||
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.
|
// Call Trim() to remove transactions and bring the cluster back within limits.
|
||||||
auto removed_refs = graph->Trim();
|
auto removed_refs = graph->Trim();
|
||||||
graph->SanityCheck();
|
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.
|
// 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(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) {
|
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
|
// Check that the graph is now oversized. This also forces the graph to
|
||||||
// group clusters and compute the oversized status.
|
// 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.
|
// Call Trim() to remove transactions and bring the cluster back within limits.
|
||||||
auto removed_refs = graph->Trim();
|
auto removed_refs = graph->Trim();
|
||||||
graph->SanityCheck();
|
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.
|
// Since only the bottom transaction connects these clusters, we only need to remove it.
|
||||||
BOOST_CHECK_EQUAL(removed_refs.size(), 1);
|
BOOST_CHECK_EQUAL(removed_refs.size(), 1);
|
||||||
BOOST_CHECK_EQUAL(graph->GetTransactionCount(false), MAX_CLUSTER_COUNT * 2);
|
BOOST_CHECK_EQUAL(graph->GetTransactionCount(TxGraph::Level::TOP), MAX_CLUSTER_COUNT * 2);
|
||||||
BOOST_CHECK(!graph->Exists(refs[0]));
|
BOOST_CHECK(!graph->Exists(refs[0], TxGraph::Level::TOP));
|
||||||
for (unsigned int i = 1; i < refs.size(); ++i) {
|
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();
|
graph->SanityCheck();
|
||||||
|
|
||||||
// Not oversized so far (just 1000 clusters of 64).
|
// 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.
|
// Construct the bottom transactions, and dependencies to the top chains.
|
||||||
while (top_components.size() > 1) {
|
while (top_components.size() > 1) {
|
||||||
@@ -237,19 +237,19 @@ BOOST_AUTO_TEST_CASE(txgraph_trim_huge)
|
|||||||
graph->SanityCheck();
|
graph->SanityCheck();
|
||||||
|
|
||||||
// Now we are oversized (one cluster of 64011).
|
// Now we are oversized (one cluster of 64011).
|
||||||
BOOST_CHECK(graph->IsOversized());
|
BOOST_CHECK(graph->IsOversized(TxGraph::Level::TOP));
|
||||||
const auto total_tx_count = graph->GetTransactionCount();
|
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 == top_refs.size() + bottom_refs.size());
|
||||||
BOOST_CHECK(total_tx_count == NUM_TOTAL_TX);
|
BOOST_CHECK(total_tx_count == NUM_TOTAL_TX);
|
||||||
|
|
||||||
// Call Trim() to remove transactions and bring the cluster back within limits.
|
// Call Trim() to remove transactions and bring the cluster back within limits.
|
||||||
auto removed_refs = graph->Trim();
|
auto removed_refs = graph->Trim();
|
||||||
BOOST_CHECK(!graph->IsOversized());
|
BOOST_CHECK(!graph->IsOversized(TxGraph::Level::TOP));
|
||||||
BOOST_CHECK(removed_refs.size() == total_tx_count - graph->GetTransactionCount());
|
BOOST_CHECK(removed_refs.size() == total_tx_count - graph->GetTransactionCount(TxGraph::Level::TOP));
|
||||||
graph->SanityCheck();
|
graph->SanityCheck();
|
||||||
|
|
||||||
// At least 99% of chains must survive.
|
// 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)
|
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
|
// Check that the graph is now oversized. This also forces the graph to
|
||||||
// group clusters and compute the oversized status.
|
// 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.
|
// Call Trim() to remove transactions and bring the cluster back within limits.
|
||||||
auto removed_refs = graph->Trim();
|
auto removed_refs = graph->Trim();
|
||||||
graph->SanityCheck();
|
graph->SanityCheck();
|
||||||
BOOST_CHECK_EQUAL(graph->GetTransactionCount(), NUM_TOTAL_TX - 6);
|
BOOST_CHECK_EQUAL(graph->GetTransactionCount(TxGraph::Level::TOP), NUM_TOTAL_TX - 6);
|
||||||
BOOST_CHECK(!graph->IsOversized(/*main_only=*/false));
|
BOOST_CHECK(!graph->IsOversized(TxGraph::Level::TOP));
|
||||||
|
|
||||||
// Check that all the oversized transactions were removed.
|
// Check that all the oversized transactions were removed.
|
||||||
for (unsigned int i = 0; i < refs.size(); ++i) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -496,8 +496,8 @@ public:
|
|||||||
void SetClusterQuality(int level, QualityLevel old_quality, ClusterSetIndex old_index, QualityLevel new_quality) noexcept;
|
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). */
|
/** Get the index of the top level ClusterSet (staging if it exists, main otherwise). */
|
||||||
int GetTopLevel() const noexcept { return m_staging_clusterset.has_value(); }
|
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). */
|
/** Get the specified level (staging if it exists and level is TOP, main otherwise). */
|
||||||
int GetSpecifiedLevel(bool main_only) const noexcept { return m_staging_clusterset.has_value() && !main_only; }
|
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). */
|
/** Get a reference to the ClusterSet at the specified level (which must exist). */
|
||||||
ClusterSet& GetClusterSet(int level) noexcept;
|
ClusterSet& GetClusterSet(int level) noexcept;
|
||||||
const ClusterSet& GetClusterSet(int level) const noexcept;
|
const ClusterSet& GetClusterSet(int level) const noexcept;
|
||||||
@@ -600,18 +600,18 @@ public:
|
|||||||
void AbortStaging() noexcept final;
|
void AbortStaging() noexcept final;
|
||||||
bool HaveStaging() const noexcept final { return m_staging_clusterset.has_value(); }
|
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 GetMainChunkFeerate(const Ref& arg) noexcept final;
|
||||||
FeePerWeight GetIndividualFeerate(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*> GetCluster(const Ref& arg, Level level) noexcept final;
|
||||||
std::vector<Ref*> GetAncestors(const Ref& arg, bool main_only = false) noexcept final;
|
std::vector<Ref*> GetAncestors(const Ref& arg, Level level) noexcept final;
|
||||||
std::vector<Ref*> GetDescendants(const Ref& arg, bool main_only = false) noexcept final;
|
std::vector<Ref*> GetDescendants(const Ref& arg, Level level) noexcept final;
|
||||||
std::vector<Ref*> GetAncestorsUnion(std::span<const Ref* const> args, bool main_only = false) 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, bool main_only = false) noexcept final;
|
std::vector<Ref*> GetDescendantsUnion(std::span<const Ref* const> args, Level level) noexcept final;
|
||||||
GraphIndex GetTransactionCount(bool main_only = false) noexcept final;
|
GraphIndex GetTransactionCount(Level level) noexcept final;
|
||||||
bool IsOversized(bool main_only = false) noexcept final;
|
bool IsOversized(Level level) noexcept final;
|
||||||
std::strong_ordering CompareMainOrder(const Ref& a, const Ref& b) 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::pair<std::vector<FeeFrac>, std::vector<FeeFrac>> GetMainStagingDiagrams() noexcept final;
|
||||||
std::vector<Ref*> Trim() 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;
|
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;
|
if (GetRefGraph(arg) == nullptr) return false;
|
||||||
Assume(GetRefGraph(arg) == this);
|
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.
|
// Make sure the transaction isn't scheduled for removal.
|
||||||
ApplyRemovals(level);
|
ApplyRemovals(level);
|
||||||
auto cluster = FindCluster(GetRefIndex(arg), 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.
|
// Return the empty vector if the Ref is empty.
|
||||||
if (GetRefGraph(arg) == nullptr) return {};
|
if (GetRefGraph(arg) == nullptr) return {};
|
||||||
Assume(GetRefGraph(arg) == this);
|
Assume(GetRefGraph(arg) == this);
|
||||||
// Apply all removals and dependencies, as the result might be incorrect otherwise.
|
// 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);
|
ApplyDependencies(level);
|
||||||
// Ancestry cannot be known if unapplied dependencies remain.
|
// Ancestry cannot be known if unapplied dependencies remain.
|
||||||
Assume(GetClusterSet(level).m_deps_to_add.empty());
|
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;
|
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.
|
// Return the empty vector if the Ref is empty.
|
||||||
if (GetRefGraph(arg) == nullptr) return {};
|
if (GetRefGraph(arg) == nullptr) return {};
|
||||||
Assume(GetRefGraph(arg) == this);
|
Assume(GetRefGraph(arg) == this);
|
||||||
// Apply all removals and dependencies, as the result might be incorrect otherwise.
|
// 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);
|
ApplyDependencies(level);
|
||||||
// Ancestry cannot be known if unapplied dependencies remain.
|
// Ancestry cannot be known if unapplied dependencies remain.
|
||||||
Assume(GetClusterSet(level).m_deps_to_add.empty());
|
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;
|
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.
|
// Apply all dependencies, as the result might be incorrect otherwise.
|
||||||
size_t level = GetSpecifiedLevel(main_only);
|
size_t level = GetSpecifiedLevel(level_select);
|
||||||
ApplyDependencies(level);
|
ApplyDependencies(level);
|
||||||
// Ancestry cannot be known if unapplied dependencies remain.
|
// Ancestry cannot be known if unapplied dependencies remain.
|
||||||
Assume(GetClusterSet(level).m_deps_to_add.empty());
|
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;
|
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.
|
// Apply all dependencies, as the result might be incorrect otherwise.
|
||||||
size_t level = GetSpecifiedLevel(main_only);
|
size_t level = GetSpecifiedLevel(level_select);
|
||||||
ApplyDependencies(level);
|
ApplyDependencies(level);
|
||||||
// Ancestry cannot be known if unapplied dependencies remain.
|
// Ancestry cannot be known if unapplied dependencies remain.
|
||||||
Assume(GetClusterSet(level).m_deps_to_add.empty());
|
Assume(GetClusterSet(level).m_deps_to_add.empty());
|
||||||
@@ -1978,14 +1978,14 @@ std::vector<TxGraph::Ref*> TxGraphImpl::GetDescendantsUnion(std::span<const Ref*
|
|||||||
return ret;
|
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
|
// Return the empty vector if the Ref is empty (which may be indicative of the transaction
|
||||||
// having been removed already.
|
// having been removed already.
|
||||||
if (GetRefGraph(arg) == nullptr) return {};
|
if (GetRefGraph(arg) == nullptr) return {};
|
||||||
Assume(GetRefGraph(arg) == this);
|
Assume(GetRefGraph(arg) == this);
|
||||||
// Apply all removals and dependencies, as the result might be incorrect otherwise.
|
// 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);
|
ApplyDependencies(level);
|
||||||
// Cluster linearization cannot be known if unapplied dependencies remain.
|
// Cluster linearization cannot be known if unapplied dependencies remain.
|
||||||
Assume(GetClusterSet(level).m_deps_to_add.empty());
|
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;
|
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);
|
ApplyRemovals(level);
|
||||||
return GetClusterSet(level).m_txcount;
|
return GetClusterSet(level).m_txcount;
|
||||||
}
|
}
|
||||||
@@ -2047,9 +2047,9 @@ FeePerWeight TxGraphImpl::GetMainChunkFeerate(const Ref& arg) noexcept
|
|||||||
return entry.m_main_chunk_feerate;
|
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);
|
auto& clusterset = GetClusterSet(level);
|
||||||
if (clusterset.m_oversized.has_value()) {
|
if (clusterset.m_oversized.has_value()) {
|
||||||
// Return cached value if known.
|
// 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));
|
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);
|
ApplyDependencies(level);
|
||||||
auto& clusterset = GetClusterSet(level);
|
auto& clusterset = GetClusterSet(level);
|
||||||
Assume(clusterset.m_deps_to_add.empty());
|
Assume(clusterset.m_deps_to_add.empty());
|
||||||
|
|||||||
@@ -60,6 +60,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
class Ref;
|
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 destructor, so inheriting is safe. */
|
||||||
virtual ~TxGraph() = default;
|
virtual ~TxGraph() = default;
|
||||||
/** Construct a new transaction with the specified feerate, and return a Ref to it.
|
/** 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;
|
virtual bool HaveStaging() const noexcept = 0;
|
||||||
|
|
||||||
/** Determine whether the graph is oversized (contains a connected component of more than the
|
/** 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
|
* configured maximum cluster count). Some of the functions below are not available
|
||||||
* queried; otherwise the main graph is queried. Some of the functions below are not available
|
|
||||||
* for oversized graphs. The mutators above are always available. Removing a transaction by
|
* 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
|
* destroying its Ref while staging exists will not clear main's oversizedness until staging
|
||||||
* is aborted or committed. */
|
* is aborted or committed. */
|
||||||
virtual bool IsOversized(bool main_only = false) noexcept = 0;
|
virtual bool IsOversized(Level level) noexcept = 0;
|
||||||
/** Determine whether arg exists in the graph (i.e., was not removed). If main_only is false
|
/** Determine whether arg exists in the graph (i.e., was not removed). This is
|
||||||
* and a staging graph exists, it is queried; otherwise the main graph is queried. This is
|
|
||||||
* available even for oversized graphs. */
|
* 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
|
/** 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
|
* if arg does not exist in either main or staging. This is available even for oversized
|
||||||
* graphs. */
|
* graphs. */
|
||||||
@@ -131,40 +134,35 @@ public:
|
|||||||
* oversized. */
|
* oversized. */
|
||||||
virtual FeePerWeight GetMainChunkFeerate(const Ref& arg) noexcept = 0;
|
virtual FeePerWeight GetMainChunkFeerate(const Ref& arg) noexcept = 0;
|
||||||
/** Get pointers to all transactions in the cluster which arg is in. The transactions are
|
/** 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;
|
* returned in graph order. The queried graph must not be oversized. Returns {} if
|
||||||
* otherwise the main graph is queried. The queried graph must not be oversized. Returns {} if
|
|
||||||
* arg does not exist in the queried graph. */
|
* 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
|
/** 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
|
* itself), in unspecified order. The queried graph must not be oversized.
|
||||||
* queried; otherwise the main graph is queried. The queried graph must not be oversized.
|
|
||||||
* Returns {} if arg does not exist in the graph. */
|
* 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
|
/** 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
|
* itself), in unspecified order. The queried graph must not be oversized.
|
||||||
* queried; otherwise the main graph is queried. The queried graph must not be oversized.
|
|
||||||
* Returns {} if arg does not exist in the graph. */
|
* 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
|
/** 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
|
* arguments' ancestors (each transaction is only reported once). Refs that do not exist in
|
||||||
* the queried graph are ignored. Null refs are not allowed. */
|
* 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
|
/** 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
|
* arguments' descendants (each transaction is only reported once). Refs that do not exist in
|
||||||
* the queried graph are ignored. Null refs are not allowed. */
|
* 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;
|
virtual std::vector<Ref*> GetDescendantsUnion(std::span<const Ref* const> args, Level level) noexcept = 0;
|
||||||
/** Get the total number of transactions in the graph. If main_only is false and a staging
|
/** Get the total number of transactions in the graph. This is available even
|
||||||
* graph exists, it is queried; otherwise the main graph is queried. This is available even
|
|
||||||
* for oversized graphs. */
|
* 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
|
/** 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. */
|
* 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;
|
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
|
/** Count the number of distinct clusters that the specified transactions belong to. Refs that
|
||||||
* main_only is false and a staging graph exists, staging clusters are counted. Otherwise,
|
* do not exist in the queried graph are ignored. Refs can not be null. The queried graph must
|
||||||
* main clusters are counted. Refs that do not exist in the queried graph are ignored. Refs
|
* not be oversized. */
|
||||||
* can not be null. The queried graph must not be oversized. */
|
virtual GraphIndex CountDistinctClusters(std::span<const Ref* const>, Level level) noexcept = 0;
|
||||||
virtual GraphIndex CountDistinctClusters(std::span<const Ref* const>, bool main_only = false) noexcept = 0;
|
|
||||||
/** For both main and staging (which must both exist and not be oversized), return the combined
|
/** 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
|
* respective feerate diagrams, including chunks from all clusters, but excluding clusters
|
||||||
* that appear identically in both. Use FeeFrac rather than FeePerWeight so CompareChunks is
|
* that appear identically in both. Use FeeFrac rather than FeePerWeight so CompareChunks is
|
||||||
|
|||||||
Reference in New Issue
Block a user