clusterlin: use 'cost' terminology instead of 'iters' (refactor)
What changed, and why it matters
This commit is a pure rename/refactor. It changes variable names, comments, and constant names from 'iterations'/'iters' to 'cost' throughout the cluster linearization and transaction graph code. No logic, behavior, or security properties are altered.
No security action required. This is a benign terminology refactor with no functional or security impact.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff renames identifiers and updates comments to use ‘cost’ terminology consistently instead of ‘iterations’/’iters’. Examples include: Linearize() parameter max_iterations -> max_cost, DoWork() parameter iters -> max_cost, ACCEPTABLE_ITERS -> ACCEPTABLE_COST, POST_CHANGE_WORK -> POST_CHANGE_COST, MaxOptimalLinearizationIters -> MaxOptimalLinearizationCost, and m_acceptable_iters -> m_acceptable_cost. The numeric values and control flow remain identical. This is a non-functional refactor.
Changed components
src/cluster_linearize.hsrc/txgraph.cppsrc/txgraph.hsrc/txmempool.cppsrc/txmempool.htest/bench/fuzz files (terminology only)Inspect captured patch +111 / −91
diff --git a/src/bench/cluster_linearize.cpp b/src/bench/cluster_linearize.cpp
index d345a7ca..0799cc2c 100644
--- a/src/bench/cluster_linearize.cpp
+++ b/src/bench/cluster_linearize.cpp
@@ -55,7 +55,7 @@ void BenchLinearizeOptimallyTotal(benchmark::Bench& bench, const std::string& na
// Benchmark the total time to optimal.
uint64_t rng_seed = 0;
bench.name(bench_name).run([&] {
- auto [_lin, optimal, _cost] = Linearize(depgraph, /*max_iterations=*/10000000, rng_seed++, IndexTxOrder{});
+ auto [_lin, optimal, _cost] = Linearize(depgraph, /*max_cost=*/10000000, rng_seed++, IndexTxOrder{});
assert(optimal);
});
}
@@ -72,7 +72,7 @@ void BenchLinearizeOptimallyPerCost(benchmark::Bench& bench, const std::string&
// Determine the cost of 100 rng_seeds.
uint64_t total_cost = 0;
for (uint64_t iter = 0; iter < 100; ++iter) {
- auto [_lin, optimal, cost] = Linearize(depgraph, /*max_iterations=*/10000000, /*rng_seed=*/iter, IndexTxOrder{});
+ auto [_lin, optimal, cost] = Linearize(depgraph, /*max_cost=*/10000000, /*rng_seed=*/iter, IndexTxOrder{});
total_cost += cost;
}
@@ -80,7 +80,7 @@ void BenchLinearizeOptimallyPerCost(benchmark::Bench& bench, const std::string&
bench.name(bench_name).unit("cost").batch(total_cost).run([&] {
uint64_t recompute_cost = 0;
for (uint64_t iter = 0; iter < 100; ++iter) {
- auto [_lin, optimal, cost] = Linearize(depgraph, /*max_iterations=*/10000000, /*rng_seed=*/iter, IndexTxOrder{});
+ auto [_lin, optimal, cost] = Linearize(depgraph, /*max_cost=*/10000000, /*rng_seed=*/iter, IndexTxOrder{});
assert(optimal);
recompute_cost += cost;
}
diff --git a/src/bench/txgraph.cpp b/src/bench/txgraph.cpp
index 00074db6..c56a284a 100644
--- a/src/bench/txgraph.cpp
+++ b/src/bench/txgraph.cpp
@@ -51,9 +51,9 @@ void BenchTxGraphTrim(benchmark::Bench& bench)
static constexpr int NUM_DEPS_PER_BOTTOM_TX = 100;
/** Set a very large cluster size limit so that only the count limit is triggered. */
static constexpr int32_t MAX_CLUSTER_SIZE = 100'000 * 100;
- /** Set a very high number for acceptable iterations, so that we certainly benchmark optimal
+ /** Set a very high number for acceptable cost, so that we certainly benchmark optimal
* linearization. */
- static constexpr uint64_t NUM_ACCEPTABLE_ITERS = 100'000'000;
+ static constexpr uint64_t HIGH_ACCEPTABLE_COST = 100'000'000;
/** Refs to all top transactions. */
std::vector<TxGraph::Ref> top_refs;
@@ -65,7 +65,7 @@ void BenchTxGraphTrim(benchmark::Bench& bench)
std::vector<size_t> top_components;
InsecureRandomContext rng(11);
- auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, NUM_ACCEPTABLE_ITERS, PointerComparator);
+ auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, HIGH_ACCEPTABLE_COST, PointerComparator);
// Construct the top chains.
for (int chain = 0; chain < NUM_TOP_CHAINS; ++chain) {
diff --git a/src/cluster_linearize.h b/src/cluster_linearize.h
index 8f2076ca..57df4512 100644
--- a/src/cluster_linearize.h
+++ b/src/cluster_linearize.h
@@ -1742,7 +1742,7 @@ public:
/** Find or improve a linearization for a cluster.
*
* @param[in] depgraph Dependency graph of the cluster to be linearized.
- * @param[in] max_iterations Upper bound on the amount of work that will be done.
+ * @param[in] max_cost Upper bound on the amount of work that will be done.
* @param[in] rng_seed A random number seed to control search order. This prevents peers
* from predicting exactly which clusters would be hard for us to
* linearize.
@@ -1762,7 +1762,7 @@ public:
template<typename SetType>
std::tuple<std::vector<DepGraphIndex>, bool, uint64_t> Linearize(
const DepGraph<SetType>& depgraph,
- uint64_t max_iterations,
+ uint64_t max_cost,
uint64_t rng_seed,
const StrongComparator<DepGraphIndex> auto& fallback_order,
std::span<const DepGraphIndex> old_linearization = {},
@@ -1778,23 +1778,23 @@ std::tuple<std::vector<DepGraphIndex>, bool, uint64_t> Linearize(
}
// Make improvement steps to it until we hit the max_iterations limit, or an optimal result
// is found.
- if (forest.GetCost() < max_iterations) {
+ if (forest.GetCost() < max_cost) {
forest.StartOptimizing();
do {
if (!forest.OptimizeStep()) break;
- } while (forest.GetCost() < max_iterations);
+ } while (forest.GetCost() < max_cost);
}
// Make chunk minimization steps until we hit the max_iterations limit, or all chunks are
// minimal.
bool optimal = false;
- if (forest.GetCost() < max_iterations) {
+ if (forest.GetCost() < max_cost) {
forest.StartMinimizing();
do {
if (!forest.MinimizeStep()) {
optimal = true;
break;
}
- } while (forest.GetCost() < max_iterations);
+ } while (forest.GetCost() < max_cost);
}
return {forest.GetLinearization(fallback_order), optimal, forest.GetCost()};
}
diff --git a/src/test/cluster_linearize_tests.cpp b/src/test/cluster_linearize_tests.cpp
index e14b5ebc..4f851c1d 100644
--- a/src/test/cluster_linearize_tests.cpp
+++ b/src/test/cluster_linearize_tests.cpp
@@ -88,9 +88,15 @@ void TestOptimalLinearization(std::span<const uint8_t> enc, std::initializer_lis
is_topological = false;
break;
}
- std::tie(lin, opt, cost) = Linearize(depgraph, 1000000000000, rng.rand64(), IndexTxOrder{}, lin, is_topological);
+ std::tie(lin, opt, cost) = Linearize(
+ /*depgraph=*/depgraph,
+ /*max_cost=*/1000000000000,
+ /*rng_seed=*/rng.rand64(),
+ /*fallback_order=*/IndexTxOrder{},
+ /*old_linearization=*/lin,
+ /*is_topological=*/is_topological);
BOOST_CHECK(opt);
- BOOST_CHECK(cost <= MaxOptimalLinearizationIters(depgraph.TxCount()));
+ BOOST_CHECK(cost <= MaxOptimalLinearizationCost(depgraph.TxCount()));
SanityCheck(depgraph, lin);
BOOST_CHECK(std::ranges::equal(lin, optimal_linearization));
}
diff --git a/src/test/fuzz/cluster_linearize.cpp b/src/test/fuzz/cluster_linearize.cpp
index 5dc7eb21..adee8f2e 100644
--- a/src/test/fuzz/cluster_linearize.cpp
+++ b/src/test/fuzz/cluster_linearize.cpp
@@ -984,7 +984,7 @@ FUZZ_TARGET(clusterlin_sfl)
// Verify that optimality is reached within an expected amount of work. This protects against
// hypothetical bugs that hugely increase the amount of work needed to reach optimality.
- assert(sfl.GetCost() <= MaxOptimalLinearizationIters(depgraph.TxCount()));
+ assert(sfl.GetCost() <= MaxOptimalLinearizationCost(depgraph.TxCount()));
// The result must be as good as SimpleLinearize.
auto [simple_linearization, simple_optimal] = SimpleLinearize(depgraph, MAX_SIMPLE_ITERATIONS / 10);
@@ -1011,15 +1011,15 @@ FUZZ_TARGET(clusterlin_linearize)
{
// Verify the behavior of Linearize().
- // Retrieve an RNG seed, an iteration count, a depgraph, and whether to make it connected from
- // the fuzz input.
+ // Retrieve an RNG seed, a maximum amount of work, a depgraph, and whether to make it connected
+ // from the fuzz input.
SpanReader reader(buffer);
DepGraph<TestBitSet> depgraph;
uint64_t rng_seed{0};
- uint64_t iter_count{0};
+ uint64_t max_cost{0};
uint8_t flags{7};
try {
- reader >> VARINT(iter_count) >> Using<DepGraphFormatter>(depgraph) >> rng_seed >> flags;
+ reader >> VARINT(max_cost) >> Using<DepGraphFormatter>(depgraph) >> rng_seed >> flags;
} catch (const std::ios_base::failure&) {}
bool make_connected = flags & 1;
// The following 3 booleans have 4 combinations:
@@ -1043,8 +1043,14 @@ FUZZ_TARGET(clusterlin_linearize)
}
// Invoke Linearize().
- iter_count &= 0x7ffff;
- auto [linearization, optimal, cost] = Linearize(depgraph, iter_count, rng_seed, IndexTxOrder{}, old_linearization, /*is_topological=*/claim_topological_input);
+ max_cost &= 0x7ffff;
+ auto [linearization, optimal, cost] = Linearize(
+ /*depgraph=*/depgraph,
+ /*max_cost=*/max_cost,
+ /*rng_seed=*/rng_seed,
+ /*fallback_order=*/IndexTxOrder{},
+ /*old_linearization=*/old_linearization,
+ /*is_topological=*/claim_topological_input);
SanityCheck(depgraph, linearization);
auto chunking = ChunkLinearization(depgraph, linearization);
@@ -1056,8 +1062,8 @@ FUZZ_TARGET(clusterlin_linearize)
assert(cmp >= 0);
}
- // If the iteration count is sufficiently high, an optimal linearization must be found.
- if (iter_count > MaxOptimalLinearizationIters(depgraph.TxCount())) {
+ // If the maximum amount of work is sufficiently high, an optimal linearization must be found.
+ if (max_cost > MaxOptimalLinearizationCost(depgraph.TxCount())) {
assert(optimal);
}
@@ -1145,7 +1151,7 @@ FUZZ_TARGET(clusterlin_linearize)
// Redo from scratch with a different rng_seed. The resulting linearization should be
// deterministic, if both are optimal.
- auto [linearization2, optimal2, cost2] = Linearize(depgraph, MaxOptimalLinearizationIters(depgraph.TxCount()) + 1, rng_seed ^ 0x1337, IndexTxOrder{});
+ auto [linearization2, optimal2, cost2] = Linearize(depgraph, MaxOptimalLinearizationCost(depgraph.TxCount()) + 1, rng_seed ^ 0x1337, IndexTxOrder{});
assert(optimal2);
assert(linearization2 == linearization);
}
diff --git a/src/test/fuzz/txgraph.cpp b/src/test/fuzz/txgraph.cpp
index 59c65bde..0fc4e047 100644
--- a/src/test/fuzz/txgraph.cpp
+++ b/src/test/fuzz/txgraph.cpp
@@ -325,8 +325,8 @@ FUZZ_TARGET(txgraph)
auto max_cluster_count = provider.ConsumeIntegralInRange<DepGraphIndex>(1, MAX_CLUSTER_COUNT_LIMIT);
/** The maximum total size of transactions in a (non-oversized) cluster. */
auto max_cluster_size = provider.ConsumeIntegralInRange<uint64_t>(1, 0x3fffff * MAX_CLUSTER_COUNT_LIMIT);
- /** The number of iterations to consider a cluster acceptably linearized. */
- auto acceptable_iters = provider.ConsumeIntegralInRange<uint64_t>(0, 10000);
+ /** The amount of work to consider a cluster acceptably linearized. */
+ auto acceptable_cost = provider.ConsumeIntegralInRange<uint64_t>(0, 10000);
/** The set of uint64_t "txid"s that have been assigned before. */
std::set<uint64_t> assigned_txids;
@@ -342,7 +342,7 @@ FUZZ_TARGET(txgraph)
auto real = MakeTxGraph(
/*max_cluster_count=*/max_cluster_count,
/*max_cluster_size=*/max_cluster_size,
- /*acceptable_iters=*/acceptable_iters,
+ /*acceptable_cost=*/acceptable_cost,
/*fallback_order=*/fallback_order);
std::vector<SimTxGraph> sims;
@@ -758,9 +758,9 @@ FUZZ_TARGET(txgraph)
break;
} else if (command-- == 0) {
// DoWork.
- uint64_t iters = provider.ConsumeIntegralInRange<uint64_t>(0, alt ? 10000 : 255);
- bool ret = real->DoWork(iters);
- uint64_t iters_for_optimal{0};
+ uint64_t max_cost = provider.ConsumeIntegralInRange<uint64_t>(0, alt ? 10000 : 255);
+ bool ret = real->DoWork(max_cost);
+ uint64_t cost_for_optimal{0};
for (unsigned level = 0; level < sims.size(); ++level) {
// DoWork() will not optimize oversized levels, or the main level if a builder
// is present. Note that this impacts the DoWork() return value, as true means
@@ -773,24 +773,24 @@ FUZZ_TARGET(txgraph)
if (ret) {
sims[level].real_is_optimal = true;
}
- // Compute how many iterations would be needed to make everything optimal.
+ // Compute how much work would be needed to make everything optimal.
for (auto component : sims[level].GetComponents()) {
- auto iters_opt_this_cluster = MaxOptimalLinearizationIters(component.Count());
- if (iters_opt_this_cluster > acceptable_iters) {
- // If the number of iterations required to linearize this cluster
- // optimally exceeds acceptable_iters, DoWork() may process it in two
+ auto cost_opt_this_cluster = MaxOptimalLinearizationCost(component.Count());
+ if (cost_opt_this_cluster > acceptable_cost) {
+ // If the amount of work required to linearize this cluster
+ // optimally exceeds acceptable_cost, DoWork() may process it in two
// stages: once to acceptable, and once to optimal.
- iters_for_optimal += iters_opt_this_cluster + acceptable_iters;
+ cost_for_optimal += cost_opt_this_cluster + acceptable_cost;
} else {
- iters_for_optimal += iters_opt_this_cluster;
+ cost_for_optimal += cost_opt_this_cluster;
}
}
}
if (!ret) {
- // DoWork can only have more work left if the requested number of iterations
+ // DoWork can only have more work left if the requested amount of work
// was insufficient to linearize everything optimally within the levels it is
// allowed to touch.
- assert(iters <= iters_for_optimal);
+ assert(max_cost <= cost_for_optimal);
}
break;
} else if (sims.size() == 2 && !sims[0].IsOversized() && !sims[1].IsOversized() && command-- == 0) {
@@ -1165,7 +1165,7 @@ FUZZ_TARGET(txgraph)
auto real_redo = MakeTxGraph(
/*max_cluster_count=*/max_cluster_count,
/*max_cluster_size=*/max_cluster_size,
- /*acceptable_iters=*/acceptable_iters,
+ /*acceptable_cost=*/acceptable_cost,
/*fallback_order=*/fallback_order);
/** Vector (indexed by SimTxGraph::Pos) of TxObjects in real_redo). */
std::vector<std::optional<SimTxObject>> txobjects_redo;
diff --git a/src/test/txgraph_tests.cpp b/src/test/txgraph_tests.cpp
index f069e5bd..444e2185 100644
--- a/src/test/txgraph_tests.cpp
+++ b/src/test/txgraph_tests.cpp
@@ -15,9 +15,9 @@ BOOST_AUTO_TEST_SUITE(txgraph_tests)
namespace {
-/** The number used as acceptable_iters argument in these tests. High enough that everything
+/** The number used as acceptable_cost argument in these tests. High enough that everything
* should be optimal, always. */
-constexpr uint64_t NUM_ACCEPTABLE_ITERS = 100'000'000;
+constexpr uint64_t HIGH_ACCEPTABLE_COST = 100'000'000;
std::strong_ordering PointerComparator(const TxGraph::Ref& a, const TxGraph::Ref& b) noexcept
{
@@ -48,7 +48,7 @@ BOOST_AUTO_TEST_CASE(txgraph_trim_zigzag)
static constexpr int32_t MAX_CLUSTER_SIZE = 100'000 * 100;
// Create a new graph for the test.
- auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, NUM_ACCEPTABLE_ITERS, PointerComparator);
+ auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, HIGH_ACCEPTABLE_COST, PointerComparator);
// Add all transactions and store their Refs.
std::vector<TxGraph::Ref> refs;
@@ -111,7 +111,7 @@ BOOST_AUTO_TEST_CASE(txgraph_trim_flower)
/** Set a very large cluster size limit so that only the count limit is triggered. */
static constexpr int32_t MAX_CLUSTER_SIZE = 100'000 * 100;
- auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, NUM_ACCEPTABLE_ITERS, PointerComparator);
+ auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, HIGH_ACCEPTABLE_COST, PointerComparator);
// Add all transactions and store their Refs.
std::vector<TxGraph::Ref> refs;
@@ -197,7 +197,7 @@ BOOST_AUTO_TEST_CASE(txgraph_trim_huge)
std::vector<size_t> top_components;
FastRandomContext rng;
- auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, NUM_ACCEPTABLE_ITERS, PointerComparator);
+ auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, HIGH_ACCEPTABLE_COST, PointerComparator);
// Construct the top chains.
for (int chain = 0; chain < NUM_TOP_CHAINS; ++chain) {
@@ -270,7 +270,7 @@ BOOST_AUTO_TEST_CASE(txgraph_trim_big_singletons)
static constexpr int NUM_TOTAL_TX = 100;
// Create a new graph for the test.
- auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, NUM_ACCEPTABLE_ITERS, PointerComparator);
+ auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, HIGH_ACCEPTABLE_COST, PointerComparator);
// Add all transactions and store their Refs.
std::vector<TxGraph::Ref> refs;
@@ -304,7 +304,7 @@ BOOST_AUTO_TEST_CASE(txgraph_trim_big_singletons)
BOOST_AUTO_TEST_CASE(txgraph_chunk_chain)
{
// Create a new graph for the test.
- auto graph = MakeTxGraph(50, 1000, NUM_ACCEPTABLE_ITERS, PointerComparator);
+ auto graph = MakeTxGraph(50, 1000, HIGH_ACCEPTABLE_COST, PointerComparator);
auto block_builder_checker = [&graph](std::vector<std::vector<TxGraph::Ref*>> expected_chunks) {
std::vector<std::vector<TxGraph::Ref*>> chunks;
@@ -383,7 +383,7 @@ BOOST_AUTO_TEST_CASE(txgraph_staging)
/* Create a new graph for the test.
* The parameters are max_cluster_count, max_cluster_size, acceptable_iters
*/
- auto graph = MakeTxGraph(10, 1000, NUM_ACCEPTABLE_ITERS, PointerComparator);
+ auto graph = MakeTxGraph(10, 1000, HIGH_ACCEPTABLE_COST, PointerComparator);
std::vector<TxGraph::Ref> refs;
refs.reserve(2);
diff --git a/src/test/util/cluster_linearize.h b/src/test/util/cluster_linearize.h
index 3814c3fc..f50a51bd 100644
--- a/src/test/util/cluster_linearize.h
+++ b/src/test/util/cluster_linearize.h
@@ -394,13 +394,13 @@ void SanityCheck(const DepGraph<SetType>& depgraph, std::span<const DepGraphInde
}
}
-inline uint64_t MaxOptimalLinearizationIters(DepGraphIndex cluster_count)
+inline uint64_t MaxOptimalLinearizationCost(DepGraphIndex cluster_count)
{
// These are the largest numbers seen returned as cost by Linearize(), in a large randomized
// trial. There exist almost certainly far worse cases, but they are unlikely to be
// encountered in randomized tests. The purpose of these numbers is guaranteeing that for
// *some* reasonable cost bound, optimal linearizations are always found.
- static constexpr uint64_t ITERS[65] = {
+ static constexpr uint64_t COSTS[65] = {
0,
0, 4, 10, 34, 76, 156, 229, 380,
441, 517, 678, 933, 1037, 1366, 1464, 1711,
@@ -411,9 +411,9 @@ inline uint64_t MaxOptimalLinearizationIters(DepGraphIndex cluster_count)
34046, 26227, 34662, 38019, 40814, 31113, 41448, 33968,
35024, 59207, 42872, 41277, 42365, 51833, 63410, 67035
};
- assert(cluster_count < std::size(ITERS));
+ assert(cluster_count < std::size(COSTS));
// Multiply the table number by two, to account for the fact that they are not absolutes.
- return ITERS[cluster_count] * 2;
+ return COSTS[cluster_count] * 2;
}
} // namespace
diff --git a/src/txgraph.cpp b/src/txgraph.cpp
index a9d502b4..ca12bca6 100644
--- a/src/txgraph.cpp
+++ b/src/txgraph.cpp
@@ -217,7 +217,7 @@ public:
virtual void ApplyDependencies(TxGraphImpl& graph, int level, std::span<std::pair<GraphIndex, GraphIndex>> to_apply) noexcept = 0;
/** Improve the linearization of this Cluster. Returns how much work was performed and whether
* the Cluster's QualityLevel improved as a result. */
- virtual std::pair<uint64_t, bool> Relinearize(TxGraphImpl& graph, int level, uint64_t max_iters) noexcept = 0;
+ virtual std::pair<uint64_t, bool> Relinearize(TxGraphImpl& graph, int level, uint64_t max_cost) noexcept = 0;
/** For every chunk in the cluster, append its FeeFrac to ret. */
virtual void AppendChunkFeerates(std::vector<FeeFrac>& ret) const noexcept = 0;
/** Add a TrimTxData entry (filling m_chunk_feerate, m_index, m_tx_size) for every
@@ -296,7 +296,7 @@ public:
[[nodiscard]] bool Split(TxGraphImpl& graph, int level) noexcept final;
void Merge(TxGraphImpl& graph, int level, Cluster& cluster) noexcept final;
void ApplyDependencies(TxGraphImpl& graph, int level, std::span<std::pair<GraphIndex, GraphIndex>> to_apply) noexcept final;
- std::pair<uint64_t, bool> Relinearize(TxGraphImpl& graph, int level, uint64_t max_iters) noexcept final;
+ std::pair<uint64_t, bool> Relinearize(TxGraphImpl& graph, int level, uint64_t max_cost) noexcept final;
void AppendChunkFeerates(std::vector<FeeFrac>& ret) const noexcept final;
uint64_t AppendTrimData(std::vector<TrimTxData>& ret, std::vector<std::pair<GraphIndex, GraphIndex>>& deps) const noexcept final;
void GetAncestorRefs(const TxGraphImpl& graph, std::span<std::pair<Cluster*, DepGraphIndex>>& args, std::vector<TxGraph::Ref*>& output) noexcept final;
@@ -353,7 +353,7 @@ public:
[[nodiscard]] bool Split(TxGraphImpl& graph, int level) noexcept final;
void Merge(TxGraphImpl& graph, int level, Cluster& cluster) noexcept final;
void ApplyDependencies(TxGraphImpl& graph, int level, std::span<std::pair<GraphIndex, GraphIndex>> to_apply) noexcept final;
- std::pair<uint64_t, bool> Relinearize(TxGraphImpl& graph, int level, uint64_t max_iters) noexcept final;
+ std::pair<uint64_t, bool> Relinearize(TxGraphImpl& graph, int level, uint64_t max_cost) noexcept final;
void AppendChunkFeerates(std::vector<FeeFrac>& ret) const noexcept final;
uint64_t AppendTrimData(std::vector<TrimTxData>& ret, std::vector<std::pair<GraphIndex, GraphIndex>>& deps) const noexcept final;
void GetAncestorRefs(const TxGraphImpl& graph, std::span<std::pair<Cluster*, DepGraphIndex>>& args, std::vector<TxGraph::Ref*>& output) noexcept final;
@@ -400,9 +400,8 @@ private:
const DepGraphIndex m_max_cluster_count;
/** This TxGraphImpl's maximum cluster size limit. */
const uint64_t m_max_cluster_size;
- /** The number of linearization improvement steps needed per cluster to be considered
- * acceptable. */
- const uint64_t m_acceptable_iters;
+ /** The amount of linearization work needed per cluster to be considered acceptable. */
+ const uint64_t m_acceptable_cost;
/** Fallback ordering for transactions. */
const std::function<std::strong_ordering(const TxGraph::Ref&, const TxGraph::Ref&)> m_fallback_order;
@@ -636,12 +635,12 @@ public:
explicit TxGraphImpl(
DepGraphIndex max_cluster_count,
uint64_t max_cluster_size,
- uint64_t acceptable_iters,
+ uint64_t acceptable_cost,
const std::function<std::strong_ordering(const TxGraph::Ref&, const TxGraph::Ref&)>& fallback_order
) noexcept :
m_max_cluster_count(max_cluster_count),
m_max_cluster_size(max_cluster_size),
- m_acceptable_iters(acceptable_iters),
+ m_acceptable_cost(acceptable_cost),
m_fallback_order(fallback_order),
m_main_chunkindex(ChunkOrder(this))
{
@@ -803,7 +802,7 @@ public:
void AddDependency(const Ref& parent, const Ref& child) noexcept final;
void SetTransactionFee(const Ref&, int64_t fee) noexcept final;
- bool DoWork(uint64_t iters) noexcept final;
+ bool DoWork(uint64_t max_cost) noexcept final;
void StartStaging() noexcept final;
void CommitStaging() noexcept final;
@@ -2155,7 +2154,7 @@ void TxGraphImpl::ApplyDependencies(int level) noexcept
clusterset.m_group_data = GroupData{};
}
-std::pair<uint64_t, bool> GenericClusterImpl::Relinearize(TxGraphImpl& graph, int level, uint64_t max_iters) noexcept
+std::pair<uint64_t, bool> GenericClusterImpl::Relinearize(TxGraphImpl& graph, int level, uint64_t max_cost) noexcept
{
// We can only relinearize Clusters that do not need splitting.
Assume(!NeedsSplitting());
@@ -2168,7 +2167,13 @@ std::pair<uint64_t, bool> GenericClusterImpl::Relinearize(TxGraphImpl& graph, in
const auto ref_b = graph.m_entries[m_mapping[b]].m_ref;
return graph.m_fallback_order(*ref_a, *ref_b);
};
- auto [linearization, optimal, cost] = Linearize(m_depgraph, max_iters, rng_seed, fallback_order, m_linearization, /*is_topological=*/IsTopological());
+ auto [linearization, optimal, cost] = Linearize(
+ /*depgraph=*/m_depgraph,
+ /*max_cost=*/max_cost,
+ /*rng_seed=*/rng_seed,
+ /*fallback_order=*/fallback_order,
+ /*old_linearization=*/m_linearization,
+ /*is_topological=*/IsTopological());
// Postlinearize to improve the linearization (if optimal, only the sub-chunk order).
// This also guarantees that all chunks are connected (even when non-optimal).
PostLinearize(m_depgraph, linearization);
@@ -2179,7 +2184,7 @@ std::pair<uint64_t, bool> GenericClusterImpl::Relinearize(TxGraphImpl& graph, in
if (optimal) {
graph.SetClusterQuality(level, m_quality, m_setindex, QualityLevel::OPTIMAL);
improved = true;
- } else if (max_iters >= graph.m_acceptable_iters && !IsAcceptable()) {
+ } else if (max_cost >= graph.m_acceptable_cost && !IsAcceptable()) {
graph.SetClusterQuality(level, m_quality, m_setindex, QualityLevel::ACCEPTABLE);
improved = true;
} else if (!IsTopological()) {
@@ -2191,7 +2196,7 @@ std::pair<uint64_t, bool> GenericClusterImpl::Relinearize(TxGraphImpl& graph, in
return {cost, improved};
}
-std::pair<uint64_t, bool> SingletonClusterImpl::Relinearize(TxGraphImpl& graph, int level, uint64_t max_iters) noexcept
+std::pair<uint64_t, bool> SingletonClusterImpl::Relinearize(TxGraphImpl& graph, int level, uint64_t max_cost) noexcept
{
// All singletons are optimal, oversized, or need splitting. Each of these precludes
// Relinearize from being called.
@@ -2203,7 +2208,7 @@ void TxGraphImpl::MakeAcceptable(Cluster& cluster, int level) noexcept
{
// Relinearize the Cluster if needed.
if (!cluster.NeedsSplitting() && !cluster.IsAcceptable() && !cluster.IsOversized()) {
- cluster.Relinearize(*this, level, m_acceptable_iters);
+ cluster.Relinearize(*this, level, m_acceptable_cost);
}
}
@@ -3105,9 +3110,9 @@ void TxGraphImpl::SanityCheck() const
assert(actual_chunkindex == expected_chunkindex);
}
-bool TxGraphImpl::DoWork(uint64_t iters) noexcept
+bool TxGraphImpl::DoWork(uint64_t max_cost) noexcept
{
- uint64_t iters_done{0};
+ uint64_t cost_done{0};
// First linearize everything in NEEDS_RELINEARIZE to an acceptable level. If more budget
// remains after that, try to make everything optimal.
for (QualityLevel quality : {QualityLevel::NEEDS_FIX, QualityLevel::NEEDS_RELINEARIZE, QualityLevel::ACCEPTABLE}) {
@@ -3121,23 +3126,23 @@ bool TxGraphImpl::DoWork(uint64_t iters) noexcept
if (clusterset.m_oversized == true) continue;
auto& queue = clusterset.m_clusters[int(quality)];
while (!queue.empty()) {
- if (iters_done >= iters) return false;
+ if (cost_done >= max_cost) return false;
// Randomize the order in which we process, so that if the first cluster somehow
- // needs more work than what iters allows, we don't keep spending it on the same
+ // needs more work than what max_cost allows, we don't keep spending it on the same
// one.
auto pos = m_rng.randrange<size_t>(queue.size());
- auto iters_now = iters - iters_done;
+ auto cost_now = max_cost - cost_done;
if (quality == QualityLevel::NEEDS_FIX || quality == QualityLevel::NEEDS_RELINEARIZE) {
// If we're working with clusters that need relinearization still, only perform
- // up to m_acceptable_iters iterations. If they become ACCEPTABLE, and we still
+ // up to m_acceptable_cost work. If they become ACCEPTABLE, and we still
// have budget after all other clusters are ACCEPTABLE too, we'll spend the
// remaining budget on trying to make them OPTIMAL.
- iters_now = std::min(iters_now, m_acceptable_iters);
+ cost_now = std::min(cost_now, m_acceptable_cost);
}
- auto [cost, improved] = queue[pos].get()->Relinearize(*this, level, iters_now);
- iters_done += cost;
+ auto [cost, improved] = queue[pos].get()->Relinearize(*this, level, cost_now);
+ cost_done += cost;
// If no improvement was made to the Cluster, it means we've essentially run out of
- // budget. Even though it may be the case that iters_done < iters still, the
+ // budget. Even though it may be the case that cost_done < max_cost still, the
// linearizer decided there wasn't enough budget left to attempt anything with.
// To avoid an infinite loop that keeps trying clusters with minuscule budgets,
// stop here too.
@@ -3565,8 +3570,12 @@ TxGraph::Ref::Ref(Ref&& other) noexcept
std::unique_ptr<TxGraph> MakeTxGraph(
unsigned max_cluster_count,
uint64_t max_cluster_size,
- uint64_t acceptable_iters,
+ uint64_t acceptable_cost,
const std::function<std::strong_ordering(const TxGraph::Ref&, const TxGraph::Ref&)>& fallback_order) noexcept
{
- return std::make_unique<TxGraphImpl>(max_cluster_count, max_cluster_size, acceptable_iters, fallback_order);
+ return std::make_unique<TxGraphImpl>(
+ /*max_cluster_count=*/max_cluster_count,
+ /*max_cluster_size=*/max_cluster_size,
+ /*acceptable_cost=*/acceptable_cost,
+ /*fallback_order=*/fallback_order);
}
diff --git a/src/txgraph.h b/src/txgraph.h
index 8c7a9174..f76915c8 100644
--- a/src/txgraph.h
+++ b/src/txgraph.h
@@ -102,10 +102,10 @@ public:
virtual void SetTransactionFee(const Ref& arg, int64_t fee) noexcept = 0;
/** TxGraph is internally lazy, and will not compute many things until they are needed.
- * Calling DoWork will perform some work now (controlled by iters) so that future operations
+ * Calling DoWork will perform some work now (controlled by max_cost) so that future operations
* are fast, if there is any. Returns whether all currently-available work is done. This can
* be invoked while oversized, but oversized graphs will be skipped by this call. */
- virtual bool DoWork(uint64_t iters) noexcept = 0;
+ virtual bool DoWork(uint64_t max_cost) noexcept = 0;
/** Create a staging graph (which cannot exist already). This acts as if a full copy of
* the transaction graph is made, upon which further modifications are made. This copy can
@@ -257,7 +257,7 @@ public:
* and on the sum of transaction sizes within a cluster.
*
* - max_cluster_count cannot exceed MAX_CLUSTER_COUNT_LIMIT.
- * - acceptable_iters controls how many linearization optimization steps will be performed per
+ * - acceptable_cost controls how much linearization optimization work will be performed per
* cluster before they are considered to be of acceptable quality.
* - fallback_order determines how to break tie-breaks between transactions:
* fallback_order(a, b) < 0 means a is "better" than b, and will (in case of ties) be placed
@@ -266,7 +266,7 @@ public:
std::unique_ptr<TxGraph> MakeTxGraph(
unsigned max_cluster_count,
uint64_t max_cluster_size,
- uint64_t acceptable_iters,
+ uint64_t acceptable_cost,
const std::function<std::strong_ordering(const TxGraph::Ref&, const TxGraph::Ref&)>& fallback_order
) noexcept;
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 27b4c886..bfff1816 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -179,7 +179,7 @@ CTxMemPool::CTxMemPool(Options opts, bilingual_str& error)
m_txgraph = MakeTxGraph(
/*max_cluster_count=*/m_opts.limits.cluster_count,
/*max_cluster_size=*/m_opts.limits.cluster_size_vbytes * WITNESS_SCALE_FACTOR,
- /*acceptable_iters=*/ACCEPTABLE_ITERS,
+ /*acceptable_cost=*/ACCEPTABLE_COST,
/*fallback_order=*/[&](const TxGraph::Ref& a, const TxGraph::Ref& b) noexcept {
const Txid& txid_a = static_cast<const CTxMemPoolEntry&>(a).GetTx().GetHash();
const Txid& txid_b = static_cast<const CTxMemPoolEntry&>(b).GetTx().GetHash();
@@ -221,7 +221,7 @@ void CTxMemPool::Apply(ChangeSet* changeset)
addNewTransaction(it);
}
- if (!m_txgraph->DoWork(POST_CHANGE_WORK)) {
+ if (!m_txgraph->DoWork(/*max_cost=*/POST_CHANGE_COST)) {
LogDebug(BCLog::MEMPOOL, "Mempool in non-optimal ordering after addition(s).");
}
}
@@ -380,7 +380,7 @@ void CTxMemPool::removeForReorg(CChain& chain, std::function<bool(txiter)> check
for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
assert(TestLockPointValidity(chain, it->GetLockPoints()));
}
- if (!m_txgraph->DoWork(POST_CHANGE_WORK)) {
+ if (!m_txgraph->DoWork(/*max_cost=*/POST_CHANGE_COST)) {
LogDebug(BCLog::MEMPOOL, "Mempool in non-optimal ordering after reorg.");
}
}
@@ -425,7 +425,7 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne
}
lastRollingFeeUpdate = GetTime();
blockSinceLastRollingFeeBump = true;
- if (!m_txgraph->DoWork(POST_CHANGE_WORK)) {
+ if (!m_txgraph->DoWork(/*max_cost=*/POST_CHANGE_COST)) {
LogDebug(BCLog::MEMPOOL, "Mempool in non-optimal ordering after block.");
}
}
diff --git a/src/txmempool.h b/src/txmempool.h
index 9feeee3e..5a870f4c 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -49,14 +49,13 @@ struct bilingual_str;
/** Fake height value used in Coin to signify they are only in the memory pool (since 0.8) */
static const uint32_t MEMPOOL_HEIGHT = 0x7FFFFFFF;
-/** How many linearization iterations required for TxGraph clusters to have
- * "acceptable" quality, if they cannot be optimally linearized with fewer
- * iterations. */
-static constexpr uint64_t ACCEPTABLE_ITERS = 1'700;
+/** How much linearization cost required for TxGraph clusters to have
+ * "acceptable" quality, if they cannot be optimally linearized with less cost. */
+static constexpr uint64_t ACCEPTABLE_COST = 1'700;
/** How much work we ask TxGraph to do after a mempool change occurs (either
* due to a changeset being applied, a new block being found, or a reorg). */
-static constexpr uint64_t POST_CHANGE_WORK = 5 * ACCEPTABLE_ITERS;
+static constexpr uint64_t POST_CHANGE_COST = 5 * ACCEPTABLE_COST;
/**
* Test whether the LockPoints height and time are still valid on the current chain
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.