From e96b00d99ebe27eeadba88841db32b2b8e741433 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 13 Apr 2025 11:16:26 -0400 Subject: [PATCH] txgraph: make number of acceptable iterations configurable (feature) --- src/bench/txgraph.cpp | 5 ++++- src/test/fuzz/txgraph.cpp | 4 +++- src/test/txgraph_tests.cpp | 12 ++++++++---- src/txgraph.cpp | 12 ++++++++---- src/txgraph.h | 5 +++-- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/bench/txgraph.cpp b/src/bench/txgraph.cpp index 2504d02bc34..5303386baaa 100644 --- a/src/bench/txgraph.cpp +++ b/src/bench/txgraph.cpp @@ -46,6 +46,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 + * linearization. */ + static constexpr uint64_t NUM_ACCEPTABLE_ITERS = 100'000'000; /** Refs to all top transactions. */ std::vector top_refs; @@ -57,7 +60,7 @@ void BenchTxGraphTrim(benchmark::Bench& bench) std::vector top_components; InsecureRandomContext rng(11); - auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE); + auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, NUM_ACCEPTABLE_ITERS); // Construct the top chains. for (int chain = 0; chain < NUM_TOP_CHAINS; ++chain) { diff --git a/src/test/fuzz/txgraph.cpp b/src/test/fuzz/txgraph.cpp index 561bf0b420c..7e4409df6b8 100644 --- a/src/test/fuzz/txgraph.cpp +++ b/src/test/fuzz/txgraph.cpp @@ -309,9 +309,11 @@ FUZZ_TARGET(txgraph) auto max_cluster_count = provider.ConsumeIntegralInRange(1, MAX_CLUSTER_COUNT_LIMIT); /** The maximum total size of transactions in a (non-oversized) cluster. */ auto max_cluster_size = provider.ConsumeIntegralInRange(1, 0x3fffff * MAX_CLUSTER_COUNT_LIMIT); + /** The number of iterations to consider a cluster acceptably linearized. */ + auto acceptable_iters = provider.ConsumeIntegralInRange(0, 10000); // Construct a real graph, and a vector of simulated graphs (main, and possibly staging). - auto real = MakeTxGraph(max_cluster_count, max_cluster_size); + auto real = MakeTxGraph(max_cluster_count, max_cluster_size, acceptable_iters); std::vector sims; sims.reserve(2); sims.emplace_back(max_cluster_count, max_cluster_size); diff --git a/src/test/txgraph_tests.cpp b/src/test/txgraph_tests.cpp index 75abfba7dc5..63741e6cd7d 100644 --- a/src/test/txgraph_tests.cpp +++ b/src/test/txgraph_tests.cpp @@ -13,6 +13,10 @@ BOOST_AUTO_TEST_SUITE(txgraph_tests) +/** The number used as acceptable_iters argument in these tests. High enough that everything + * should be optimal, always. */ +static constexpr uint64_t NUM_ACCEPTABLE_ITERS = 100'000'000; + BOOST_AUTO_TEST_CASE(txgraph_trim_zigzag) { // T T T T T T T T T T T T T T (50 T's) @@ -35,7 +39,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); + auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, NUM_ACCEPTABLE_ITERS); // Add all transactions and store their Refs. std::vector refs; @@ -98,7 +102,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); + auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, NUM_ACCEPTABLE_ITERS); // Add all transactions and store their Refs. std::vector refs; @@ -184,7 +188,7 @@ BOOST_AUTO_TEST_CASE(txgraph_trim_huge) std::vector top_components; FastRandomContext rng; - auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE); + auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, NUM_ACCEPTABLE_ITERS); // Construct the top chains. for (int chain = 0; chain < NUM_TOP_CHAINS; ++chain) { @@ -256,7 +260,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); + auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, NUM_ACCEPTABLE_ITERS); // Add all transactions and store their Refs. std::vector refs; diff --git a/src/txgraph.cpp b/src/txgraph.cpp index 8decb5d0099..6615bca50d0 100644 --- a/src/txgraph.cpp +++ b/src/txgraph.cpp @@ -255,6 +255,9 @@ 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; /** Information about one group of Clusters to be merged. */ struct GroupEntry @@ -456,9 +459,10 @@ private: public: /** Construct a new TxGraphImpl with the specified limits. */ - explicit TxGraphImpl(DepGraphIndex max_cluster_count, uint64_t max_cluster_size) noexcept : + explicit TxGraphImpl(DepGraphIndex max_cluster_count, uint64_t max_cluster_size, uint64_t acceptable_iters) noexcept : m_max_cluster_count(max_cluster_count), m_max_cluster_size(max_cluster_size), + m_acceptable_iters(acceptable_iters), m_main_chunkindex(ChunkOrder(this)) { Assume(max_cluster_count >= 1); @@ -1677,7 +1681,7 @@ void TxGraphImpl::MakeAcceptable(Cluster& cluster) noexcept { // Relinearize the Cluster if needed. if (!cluster.NeedsSplitting() && !cluster.IsAcceptable() && !cluster.IsOversized()) { - cluster.Relinearize(*this, 10000); + cluster.Relinearize(*this, m_acceptable_iters); } } @@ -2892,7 +2896,7 @@ TxGraph::Ref::Ref(Ref&& other) noexcept std::swap(m_index, other.m_index); } -std::unique_ptr MakeTxGraph(unsigned max_cluster_count, uint64_t max_cluster_size) noexcept +std::unique_ptr MakeTxGraph(unsigned max_cluster_count, uint64_t max_cluster_size, uint64_t acceptable_iters) noexcept { - return std::make_unique(max_cluster_count, max_cluster_size); + return std::make_unique(max_cluster_count, max_cluster_size, acceptable_iters); } diff --git a/src/txgraph.h b/src/txgraph.h index 2c40cd28d2e..4bddf95b860 100644 --- a/src/txgraph.h +++ b/src/txgraph.h @@ -247,7 +247,8 @@ public: /** Construct a new TxGraph with the specified limit on the number of transactions within a cluster, * and on the sum of transaction sizes within a cluster. max_cluster_count cannot exceed - * MAX_CLUSTER_COUNT_LIMIT. */ -std::unique_ptr MakeTxGraph(unsigned max_cluster_count, uint64_t max_cluster_size) noexcept; + * MAX_CLUSTER_COUNT_LIMIT. acceptable_iters controls how many linearization optimization + * steps will be performed per cluster before they are considered to be of acceptable quality. */ +std::unique_ptr MakeTxGraph(unsigned max_cluster_count, uint64_t max_cluster_size, uint64_t acceptable_iters) noexcept; #endif // BITCOIN_TXGRAPH_H