Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Cluster mempool implementation #28676

Draft
wants to merge 90 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
ab98ce5
util: add BitSet
sipa Jan 22, 2024
14ad38f
tests: add fuzz tests for BitSet
sipa May 23, 2024
ddd5514
clusterlin: introduce cluster_linearize.h with Cluster and DepGraph t…
sipa Jan 30, 2024
648856f
tests: Fuzzing framework for DepGraph class
sipa May 9, 2024
4bf08c0
clusterlin: add AncestorCandidateFinder class
sipa May 8, 2024
5f747f3
clusterlin: add SearchCandidateFinder class
sipa May 8, 2024
2af60f8
clusterlin: add Linearize function
sipa May 8, 2024
02d4284
bench: Candidate finding and linearization benchmarks
sipa May 16, 2024
0229297
clusterlin: add algorithms for connectedness/connected components
sipa May 15, 2024
db13f8e
clusterlin: separate initial search entries per component (optimization)
sipa May 13, 2024
1618822
clusterlin: use bounded BFS exploration (optimization)
sipa May 9, 2024
e0e7a67
clusterlin: randomize the SearchCandidateFinder search order
sipa May 10, 2024
f25eef9
clusterlin: permit passing in existing linearization to Linearize
sipa May 9, 2024
4ee9156
clusterlin: use feerate-sorted depgraph in SearchCandidateFinder
sipa May 15, 2024
02c3bd9
clusterlin: track upper bound potential set for work items (optimizat…
sipa May 9, 2024
829355d
clusterlin: reduce computation of unnecessary pot sets (optimization)
sipa May 9, 2024
c411a7a
clusterlin: include topological pot subsets automatically (optimization)
sipa May 9, 2024
f74ba48
clusterlin: improve heuristic to decide split transaction (optimization)
sipa May 9, 2024
cd84a26
clusterlin: avoid recomputing potential set on every split (optimizat…
sipa May 9, 2024
694a103
clusterlin: add PostLinearize + benchmarks + fuzz tests
sipa May 19, 2024
0676101
clusterlin: add MergeLinearizations function + fuzz test + benchmark
sipa May 29, 2024
a7829ba
Add is_visited helper to epochguard
sdaftuar Apr 8, 2024
3bffb34
Add txgraph module
sdaftuar Apr 8, 2024
91c0b68
add fuzz test for txgraph
sdaftuar Apr 13, 2024
071d131
Make CTxMemPoolEntry derive from TxEntry
sdaftuar Apr 8, 2024
1896afb
Track clusters in mempool with TxGraph
sdaftuar Apr 8, 2024
2e07a66
Limit mempool size based on chunk feerate
sdaftuar Sep 21, 2023
a74a05f
Select transactions for blocks based on chunk feerate
sdaftuar Sep 21, 2023
a56472a
Add new (unused) limits for cluster size/count
sdaftuar Sep 21, 2023
195fa4b
Do not allow mempool clusters to exceed configured limits
sdaftuar Sep 21, 2023
a862b0b
policy: Remove CPFP carveout rule
sdaftuar Oct 3, 2023
9e0938c
Implement new RBF logic for cluster mempool
sdaftuar Sep 21, 2023
a20f38a
==== END CLUSTER IMPLEMENTATION ====
sdaftuar Oct 17, 2023
0811c9a
==== BEGIN MEMPOOL CLEANUP ====
sdaftuar Oct 17, 2023
6e8058a
Remove the ancestor and descendant indices from the mempool
sdaftuar Sep 21, 2023
15ec906
Use cluster linearization for transaction relay sort order
sdaftuar Sep 27, 2023
8e047b1
Remove CTxMemPool::GetSortedDepthAndScore
sdaftuar Sep 28, 2023
82af314
Reimplement GetTransactionAncestry() to not rely on cached data
sdaftuar Sep 28, 2023
986406b
rpc: Calculate ancestor data from scratch for mempool rpc calls
sdaftuar Sep 28, 2023
657534f
Remove dependency on cached ancestor data in mini-miner
sdaftuar Sep 28, 2023
513dc9b
Stop enforcing ancestor size/count limits
sdaftuar Sep 28, 2023
0c9120d
Add test case for cluster size limits to v3 logic
sdaftuar Apr 14, 2024
aae45f4
Use mempool/txgraph to determine if a tx has descendants
sdaftuar Oct 3, 2023
21bfbb0
Calculate descendant information for mempool RPC output on-the-fly
sdaftuar Oct 3, 2023
308dec4
test: fix rbf carveout test in mempool_limit.py
sdaftuar Oct 18, 2023
67586ce
Stop enforcing descendant size/count limits
sdaftuar Oct 3, 2023
e311049
wallet: Replace max descendantsize with clustersize
sdaftuar Oct 3, 2023
751c373
mempool: Remove unused function CalculateDescendantMaximum
sdaftuar Oct 4, 2023
e6c76d2
Eliminate RBF workaround for CPFP carveout transactions
sdaftuar Oct 4, 2023
be678ac
Eliminate use of cached ancestor data in miniminer_tests and v3_policy
sdaftuar Apr 14, 2024
3d4ce41
mempool: eliminate accessors to mempool entry ancestor/descendant cac…
sdaftuar Oct 4, 2023
98e9b89
Remove unused members from CTxMemPoolEntry
sdaftuar Oct 4, 2023
9e2ea2f
Remove mempool logic designed to maintain ancestor/descendant state
sdaftuar Oct 4, 2023
93c7d01
mempool: addUnchecked no longer needs ancestors
sdaftuar Oct 5, 2023
7a1249f
Remove unused limits from CalculateMemPoolAncestors
sdaftuar Oct 15, 2023
26bc551
Make removeConflicts private
sdaftuar Oct 15, 2023
eb72abd
==== END MEMPOOL CLEANUP ====
sdaftuar Oct 17, 2023
1525d0d
==== BEGIN OPTIMIZATIONS ====
sdaftuar Oct 17, 2023
5c68be9
Rework removeForBlock so that clusters are only touched once
sdaftuar Oct 10, 2023
9eda1ea
Simplify ancestor calculation functions
sdaftuar Oct 15, 2023
d743d9c
Use txgraph to calculate ancestors
sdaftuar Apr 14, 2024
2472b4d
Use txgraph to calculate descendants
sdaftuar Apr 14, 2024
96e3cc0
Move GetNumChildren() to be a mempool function
sdaftuar Apr 16, 2024
9a99439
Make getting parents/children a function of the mempool, not a mempoo…
sdaftuar Apr 16, 2024
2a4c468
Rewrite GatherClusters to use the txgraph implementation
sdaftuar Apr 16, 2024
9aea970
Switch to using txgraph parents/children in public accessors
sdaftuar Apr 16, 2024
42a46bc
Stop tracking parents/children outside of txgraph
sdaftuar Apr 16, 2024
afe8f8f
Remove unused argument to RemoveStaged
sdaftuar Apr 16, 2024
91d0758
Switch to using the faster CalculateDescendants
sdaftuar Oct 16, 2023
df2a8b8
Rewrite removeRecursive to use vectors instead of sets
sdaftuar Apr 16, 2024
f2fdd37
Rewrite Expire to only invoke CalculateDescendants once
sdaftuar Apr 16, 2024
2a443bb
Rewrite removeForReorg to use a vector instead of a set
sdaftuar Apr 16, 2024
6a430b7
Drop unnecessary set in TrimToSize
sdaftuar Apr 16, 2024
57c69b3
RemoveStaged takes a vector, not a set
sdaftuar Apr 16, 2024
9b23cc8
Only use CalculateDescendants() with vectors, not sets
sdaftuar Apr 16, 2024
3daeb9c
Use faster CalculateMemPoolAncestors in rbf
sdaftuar Apr 16, 2024
76e4b33
Use faster CMPA in rpc/mempool
sdaftuar Apr 16, 2024
a8619b4
Eliminate need for ancestors in SingleV3Checks
sdaftuar Apr 16, 2024
cc463e9
Eliminate need for ancestors in PackageV3Checks
sdaftuar Apr 16, 2024
6cb8d4a
Don't calculate ancestors except for RBF transactions
sdaftuar Apr 16, 2024
1e9f23c
==== END OPTIMIZATIONS ====
sdaftuar Oct 17, 2023
654ae93
==== BEGIN TESTS ====
sdaftuar Oct 17, 2023
0edc5f4
bench: add more mempool benchmarks
sdaftuar Oct 11, 2023
610945c
fuzz: try to add more code coverage for mempool fuzzing
sdaftuar Oct 12, 2023
bebcd5c
Pass through cluster size limits to TxGraph::check()
sdaftuar Jan 29, 2024
f258137
Expose cluster information via rpc
sdaftuar Apr 19, 2023
de4b948
doc: Update mempool_replacements.md to reflect feerate diagram checks
sdaftuar Apr 24, 2024
435e2ec
test: add functional test for new cluster mempool RPCs
sdaftuar Apr 27, 2024
5de8783
fuzz: remove comparison between mini_miner block construction and miner
sdaftuar Apr 28, 2024
be7fb2a
fixup! Add txgraph module
sdaftuar Jun 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 9 additions & 19 deletions doc/policy/mempool-replacements.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,7 @@ other consensus and policy rules, each of the following conditions are met:
Use the (`-mempoolfullrbf`) configuration option to allow transaction replacement without enforcement of the
opt-in signaling rule.

2. The replacement transaction only include an unconfirmed input if that input was included in
one of the directly conflicting transactions. An unconfirmed input spends an output from a
currently-unconfirmed transaction.

*Rationale*: When RBF was originally implemented, the mempool did not keep track of
ancestor feerates yet. This rule was suggested as a temporary restriction.
2. [REDACTED]

3. The replacement transaction pays an absolute fee of at least the sum paid by the original
sdaftuar marked this conversation as resolved.
Show resolved Hide resolved
transactions.
Expand All @@ -45,23 +40,16 @@ other consensus and policy rules, each of the following conditions are met:
*Rationale*: Try to prevent DoS attacks where an attacker causes the network to repeatedly relay
transactions each paying a tiny additional amount in fees, e.g. just 1 satoshi.

5. The number of original transactions does not exceed 100. More precisely, the sum of all
directly conflicting transactions' descendant counts (number of transactions inclusive of itself
and its descendants) must not exceed 100; it is possible that this overestimates the true number
of original transactions.
5. The number of directly conflicting transactions does not exceed 100.

*Rationale*: Try to prevent DoS attacks where an attacker is able to easily occupy and flush out
significant portions of the node's mempool using replacements with multiple directly conflicting
transactions, each with large descendant sets.
*Rationale*: Limit CPU usage required to update the mempool for so many transactions being
removed at once.

6. The replacement transaction's feerate is greater than the feerates of all directly conflicting
transactions.
6. The feerate diagram of the mempool must be strictly improved by the replacement transaction.

*Rationale*: This rule was originally intended to ensure that the replacement transaction is
preferable for block-inclusion, compared to what would be removed from the mempool. This rule
predates ancestor feerate-based transaction selection.
*Rationale*: This ensures that block fees in all future blocks will go up
after the replacement (ignoring tail effects at the end of a block).

This set of rules is similar but distinct from BIP125.

Copy link
Member

@Sjors Sjors Nov 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bf467f8: history can be expanded:

  * Cluster mempool introduced, dropping rule 2 and introducing rule 7.
    As of **v27.0** ([PR 28676](https://github.com/bitcoin/bitcoin/pull/28676)).

## History

Expand All @@ -80,3 +68,5 @@ This set of rules is similar but distinct from BIP125.

* Full replace-by-fee enabled as a configurable mempool policy as of **v24.0** ([PR
#25353](https://github.com/bitcoin/bitcoin/pull/25353)).

* Feerate diagram policy enabled in conjunction with switch to cluster mempool as of **v??.0**.
5 changes: 5 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ BITCOIN_CORE_H = \
chainparamsseeds.h \
checkqueue.h \
clientversion.h \
cluster_linearize.h \
coins.h \
common/args.h \
common/bloom.h \
Expand Down Expand Up @@ -192,6 +193,7 @@ BITCOIN_CORE_H = \
kernel/mempool_removal_reason.h \
kernel/messagestartchars.h \
kernel/notifications_interface.h \
kernel/txgraph.h \
kernel/validation_cache_sizes.h \
key.h \
key_io.h \
Expand Down Expand Up @@ -292,6 +294,7 @@ BITCOIN_CORE_H = \
util/batchpriority.h \
util/bip32.h \
util/bitdeque.h \
util/bitset.h \
util/bytevectorhash.h \
util/chaintype.h \
util/check.h \
Expand Down Expand Up @@ -410,6 +413,7 @@ libbitcoin_node_a_SOURCES = \
kernel/disconnected_transactions.cpp \
kernel/mempool_persist.cpp \
kernel/mempool_removal_reason.cpp \
kernel/txgraph.cpp \
mapport.cpp \
net.cpp \
net_processing.cpp \
Expand Down Expand Up @@ -948,6 +952,7 @@ libbitcoinkernel_la_SOURCES = \
kernel/disconnected_transactions.cpp \
kernel/mempool_persist.cpp \
kernel/mempool_removal_reason.cpp \
kernel/txgraph.cpp \
logging.cpp \
node/blockstorage.cpp \
node/chainstate.cpp \
Expand Down
1 change: 1 addition & 0 deletions src/Makefile.bench.include
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ bench_bench_bitcoin_SOURCES = \
bench/chacha20.cpp \
bench/checkblock.cpp \
bench/checkqueue.cpp \
bench/clusterlin.cpp \
bench/crypto_hash.cpp \
bench/data.cpp \
bench/data.h \
Expand Down
4 changes: 4 additions & 0 deletions src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ BITCOIN_TESTS =\
test/torcontrol_tests.cpp \
test/transaction_tests.cpp \
test/translation_tests.cpp \
test/txgraph_tests.cpp \
test/txindex_tests.cpp \
test/txpackage_tests.cpp \
test/txreconciliation_tests.cpp \
Expand Down Expand Up @@ -294,13 +295,15 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/bech32.cpp \
test/fuzz/bip324.cpp \
test/fuzz/bitdeque.cpp \
test/fuzz/bitset.cpp \
test/fuzz/block.cpp \
test/fuzz/block_header.cpp \
test/fuzz/blockfilter.cpp \
test/fuzz/bloom_filter.cpp \
test/fuzz/buffered_file.cpp \
test/fuzz/chain.cpp \
test/fuzz/checkqueue.cpp \
test/fuzz/cluster_linearize.cpp \
test/fuzz/coins_view.cpp \
test/fuzz/coinscache_sim.cpp \
test/fuzz/connman.cpp \
Expand Down Expand Up @@ -392,6 +395,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/tx_in.cpp \
test/fuzz/tx_out.cpp \
test/fuzz/tx_pool.cpp \
test/fuzz/txgraph.cpp \
test/fuzz/txorphan.cpp \
test/fuzz/txrequest.cpp \
test/fuzz/utxo_snapshot.cpp \
Expand Down
197 changes: 197 additions & 0 deletions src/bench/clusterlin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
// Copyright (c) The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <bench/bench.h>

#include <util/bitset.h>
#include <cluster_linearize.h>

using namespace cluster_linearize;

namespace {

/** Construct a linear graph. These are pessimal for AncestorCandidateFinder, as they maximize
* the number of ancestor set feerate updates. */
template<typename SetType>
DepGraph<SetType> MakeLinearGraph(ClusterIndex ntx)
{
DepGraph<SetType> depgraph;
for (ClusterIndex i = 0; i < ntx; ++i) {
depgraph.AddTransaction({-int32_t(i), 1});
if (i > 0) depgraph.AddDependency(i - 1, i);
}
return depgraph;
}

// Construct a difficult graph. These need at least sqrt(2^(n-1)) iterations in the best
// implemented algorithms.
template<typename SetType>
DepGraph<SetType> MakeHardGraph(ClusterIndex ntx)
{
DepGraph<SetType> depgraph;
for (ClusterIndex i = 0; i < ntx; ++i) {
if (ntx & 1) {
if (i == 0) {
depgraph.AddTransaction({1, 2});
} else if (i == 1) {
depgraph.AddTransaction({14, 2});
depgraph.AddDependency(0, 1);
} else if (i == 2) {
depgraph.AddTransaction({6, 1});
depgraph.AddDependency(2, 1);
} else if (i == 3) {
depgraph.AddTransaction({5, 1});
depgraph.AddDependency(2, 3);
} else if ((i & 1) == 0) {
depgraph.AddTransaction({7, 1});
depgraph.AddDependency(i - 1, i);
} else {
depgraph.AddTransaction({5, 1});
depgraph.AddDependency(i, 4);
}
} else {
if (i == 0) {
depgraph.AddTransaction({1, 1});
} else if (i == 1) {
depgraph.AddTransaction({3, 1});
depgraph.AddDependency(0, 1);
} else if (i == 2) {
depgraph.AddTransaction({1, 1});
depgraph.AddDependency(0, 2);
} else if (i & 1) {
depgraph.AddTransaction({4, 1});
depgraph.AddDependency(i - 1, i);
} else {
depgraph.AddTransaction({0, 1});
depgraph.AddDependency(i, 3);
}
}
}
return depgraph;
}

/** Benchmark that does search-based candidate finding with 10000 iterations. */
template<typename SetType>
void BenchLinearizePerIterWorstCase(ClusterIndex ntx, benchmark::Bench& bench)
{
const auto depgraph = MakeHardGraph<SetType>(ntx);
const auto iter_limit = std::min<uint64_t>(10000, uint64_t{1} << (ntx / 2 - 1));
uint64_t rng_seed = 0;
bench.batch(iter_limit).unit("iters").run([&] {
uint64_t iters = iter_limit;
SearchCandidateFinder finder(depgraph, rng_seed++);
finder.FindCandidateSet(iters, {});
assert(iters == 0);
});
}

/** Benchmark for linearization of a trivial linear graph using just ancestor sort. */
template<typename SetType>
void BenchLinearizeNoItersWorstCase(ClusterIndex ntx, benchmark::Bench& bench)
{
const auto depgraph = MakeLinearGraph<SetType>(ntx);
uint64_t rng_seed = 0;
std::vector<ClusterIndex> old_lin(ntx);
for (ClusterIndex i = 0; i < ntx; ++i) old_lin[i] = i;
bench.run([&] {
// Do 10 iterations just to make sure some of that logic is executed, but this is
// effectively negligible.
uint64_t iters = 10;
Linearize(depgraph, iters, rng_seed++, old_lin);
});
}

template<typename SetType>
void BenchPostLinearizeWorstCase(ClusterIndex ntx, benchmark::Bench& bench)
{
DepGraph<SetType> depgraph;
for (ClusterIndex i = 0; i < ntx; ++i) {
depgraph.AddTransaction({i, 1});
if (i) depgraph.AddDependency(0, i);
}
std::vector<ClusterIndex> lin(ntx);
bench.run([&] {
for (ClusterIndex i = 0; i < ntx; ++i) lin[i] = i;
PostLinearize(depgraph, lin);
});
}

template<typename SetType>
void BenchMergeLinearizationsWorstCase(ClusterIndex ntx, benchmark::Bench& bench)
{
DepGraph<SetType> depgraph;
for (ClusterIndex i = 0; i < ntx; ++i) {
depgraph.AddTransaction({i, 1});
if (i) depgraph.AddDependency(0, i);
}
std::vector<ClusterIndex> lin1;
std::vector<ClusterIndex> lin2;
lin1.push_back(0);
lin2.push_back(0);
for (ClusterIndex i = 1; i < ntx; ++i) {
lin1.push_back(i);
lin2.push_back(ntx - i);
}
bench.run([&] {
MergeLinearizations(depgraph, lin1, lin2);
});
}

} // namespace

static void LinearizePerIter16TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<16>>(16, bench); }
static void LinearizePerIter32TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<32>>(32, bench); }
static void LinearizePerIter48TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<48>>(48, bench); }
static void LinearizePerIter64TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<64>>(64, bench); }
static void LinearizePerIter75TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<75>>(75, bench); }
static void LinearizePerIter99TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<99>>(99, bench); }

static void LinearizeNoIters16TxWorstCase(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCase<BitSet<16>>(16, bench); }
static void LinearizeNoIters32TxWorstCase(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCase<BitSet<32>>(32, bench); }
static void LinearizeNoIters48TxWorstCase(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCase<BitSet<48>>(48, bench); }
static void LinearizeNoIters64TxWorstCase(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCase<BitSet<64>>(64, bench); }
static void LinearizeNoIters75TxWorstCase(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCase<BitSet<75>>(75, bench); }
static void LinearizeNoIters99TxWorstCase(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCase<BitSet<99>>(99, bench); }

static void PostLinearize16TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<16>>(16, bench); }
static void PostLinearize32TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<32>>(32, bench); }
static void PostLinearize48TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<48>>(48, bench); }
static void PostLinearize64TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<64>>(64, bench); }
static void PostLinearize75TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<75>>(75, bench); }
static void PostLinearize99TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<99>>(99, bench); }

static void MergeLinearizations16TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<16>>(16, bench); }
static void MergeLinearizations32TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<32>>(32, bench); }
static void MergeLinearizations48TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<48>>(48, bench); }
static void MergeLinearizations64TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<64>>(64, bench); }
static void MergeLinearizations75TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<75>>(75, bench); }
static void MergeLinearizations99TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<99>>(99, bench); }

BENCHMARK(LinearizePerIter16TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(LinearizePerIter32TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(LinearizePerIter48TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(LinearizePerIter64TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(LinearizePerIter75TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(LinearizePerIter99TxWorstCase, benchmark::PriorityLevel::HIGH);

BENCHMARK(LinearizeNoIters16TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(LinearizeNoIters32TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(LinearizeNoIters48TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(LinearizeNoIters64TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(LinearizeNoIters75TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(LinearizeNoIters99TxWorstCase, benchmark::PriorityLevel::HIGH);

BENCHMARK(PostLinearize16TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(PostLinearize32TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(PostLinearize48TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(PostLinearize64TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(PostLinearize75TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(PostLinearize99TxWorstCase, benchmark::PriorityLevel::HIGH);

BENCHMARK(MergeLinearizations16TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(MergeLinearizations32TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(MergeLinearizations48TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(MergeLinearizations64TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(MergeLinearizations75TxWorstCase, benchmark::PriorityLevel::HIGH);
BENCHMARK(MergeLinearizations99TxWorstCase, benchmark::PriorityLevel::HIGH);