Skip to content

Commit 09ef322

Browse files
committed
[[refactor]] Check CTxMemPool options in constructor
This ensures that the tests run the same checks on the mempool options that the init code also applies.
1 parent 3d24189 commit 09ef322

11 files changed

+83
-30
lines changed

src/init.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,16 +1525,14 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
15251525
if (!result) {
15261526
return InitError(util::ErrorString(result));
15271527
}
1528-
mempool_opts.check_ratio = std::clamp<int>(mempool_opts.check_ratio, 0, 1'000'000);
1529-
1530-
int64_t descendant_limit_bytes = mempool_opts.limits.descendant_size_vbytes * 40;
1531-
if (mempool_opts.max_size_bytes < 0 || mempool_opts.max_size_bytes < descendant_limit_bytes) {
1532-
return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(descendant_limit_bytes / 1'000'000.0)));
1533-
}
1534-
LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", cache_sizes.coins * (1.0 / 1024 / 1024), mempool_opts.max_size_bytes * (1.0 / 1024 / 1024));
15351528

15361529
for (bool fLoaded = false; !fLoaded && !ShutdownRequested(node);) {
1537-
node.mempool = std::make_unique<CTxMemPool>(mempool_opts);
1530+
bilingual_str mempool_error;
1531+
node.mempool = std::make_unique<CTxMemPool>(mempool_opts, mempool_error);
1532+
if (!mempool_error.empty()) {
1533+
return InitError(mempool_error);
1534+
}
1535+
LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", cache_sizes.coins * (1.0 / 1024 / 1024), mempool_opts.max_size_bytes * (1.0 / 1024 / 1024));
15381536

15391537
node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown), chainman_opts, blockman_opts);
15401538
ChainstateManager& chainman = *node.chainman;

src/test/fuzz/mini_miner.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
#include <test/util/txmempool.h>
88
#include <test/util/mining.h>
99

10-
#include <node/mini_miner.h>
1110
#include <node/miner.h>
11+
#include <node/mini_miner.h>
1212
#include <primitives/transaction.h>
1313
#include <random.h>
1414
#include <txmempool.h>
15+
#include <util/check.h>
16+
#include <util/translation.h>
1517

1618
#include <deque>
1719
#include <vector>
@@ -33,7 +35,9 @@ void initialize_miner()
3335
FUZZ_TARGET(mini_miner, .init = initialize_miner)
3436
{
3537
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
36-
CTxMemPool pool{CTxMemPool::Options{}};
38+
bilingual_str error;
39+
CTxMemPool pool{CTxMemPool::Options{}, error};
40+
Assert(error.empty());
3741
std::vector<COutPoint> outpoints;
3842
std::deque<COutPoint> available_coins = g_available_coins;
3943
LOCK2(::cs_main, pool.cs);
@@ -109,7 +113,9 @@ FUZZ_TARGET(mini_miner, .init = initialize_miner)
109113
FUZZ_TARGET(mini_miner_selection, .init = initialize_miner)
110114
{
111115
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
112-
CTxMemPool pool{CTxMemPool::Options{}};
116+
bilingual_str error;
117+
CTxMemPool pool{CTxMemPool::Options{}, error};
118+
Assert(error.empty());
113119
// Make a copy to preserve determinism.
114120
std::deque<COutPoint> available_coins = g_available_coins;
115121
std::vector<CTransactionRef> transactions;

src/test/fuzz/package_eval.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
#include <test/util/script.h>
1616
#include <test/util/setup_common.h>
1717
#include <test/util/txmempool.h>
18+
#include <util/check.h>
1819
#include <util/rbf.h>
20+
#include <util/translation.h>
1921
#include <validation.h>
2022
#include <validationinterface.h>
2123

@@ -107,7 +109,7 @@ void MockTime(FuzzedDataProvider& fuzzed_data_provider, const Chainstate& chains
107109
SetMockTime(time);
108110
}
109111

110-
CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeContext& node)
112+
std::unique_ptr<CTxMemPool> MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeContext& node)
111113
{
112114
// Take the default options for tests...
113115
CTxMemPool::Options mempool_opts{MemPoolOptionsForTest(node)};
@@ -126,8 +128,13 @@ CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeConte
126128
mempool_opts.check_ratio = 1;
127129
mempool_opts.require_standard = fuzzed_data_provider.ConsumeBool();
128130

131+
bilingual_str error;
129132
// ...and construct a CTxMemPool from it
130-
return CTxMemPool{mempool_opts};
133+
auto mempool{std::make_unique<CTxMemPool>(std::move(mempool_opts), error)};
134+
// ... ignore the error since it might be beneficial to fuzz even when the
135+
// mempool size is unreasonably small
136+
Assert(error.empty() || error.original.starts_with("-maxmempool must be at least "));
137+
return mempool;
131138
}
132139

133140
FUZZ_TARGET(tx_package_eval, .init = initialize_tx_pool)
@@ -149,8 +156,8 @@ FUZZ_TARGET(tx_package_eval, .init = initialize_tx_pool)
149156
auto outpoints_updater = std::make_shared<OutpointsUpdater>(mempool_outpoints);
150157
node.validation_signals->RegisterSharedValidationInterface(outpoints_updater);
151158

152-
CTxMemPool tx_pool_{MakeMempool(fuzzed_data_provider, node)};
153-
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
159+
auto tx_pool_{MakeMempool(fuzzed_data_provider, node)};
160+
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.get());
154161

155162
chainstate.SetMempool(&tx_pool);
156163

src/test/fuzz/partially_downloaded_block.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include <test/util/setup_common.h>
1111
#include <test/util/txmempool.h>
1212
#include <txmempool.h>
13+
#include <util/check.h>
14+
#include <util/translation.h>
1315

1416
#include <cstddef>
1517
#include <cstdint>
@@ -52,7 +54,9 @@ FUZZ_TARGET(partially_downloaded_block, .init = initialize_pdb)
5254

5355
CBlockHeaderAndShortTxIDs cmpctblock{*block};
5456

55-
CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};
57+
bilingual_str error;
58+
CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node), error};
59+
Assert(error.empty());
5660
PartiallyDownloadedBlock pdb{&pool};
5761

5862
// Set of available transactions (mempool or extra_txn)

src/test/fuzz/rbf.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <test/util/setup_common.h>
1414
#include <test/util/txmempool.h>
1515
#include <txmempool.h>
16+
#include <util/check.h>
17+
#include <util/translation.h>
1618

1719
#include <cstdint>
1820
#include <optional>
@@ -56,7 +58,9 @@ FUZZ_TARGET(rbf, .init = initialize_rbf)
5658
return;
5759
}
5860

59-
CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};
61+
bilingual_str error;
62+
CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node), error};
63+
Assert(error.empty());
6064

6165
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), NUM_ITERS)
6266
{
@@ -90,7 +94,9 @@ FUZZ_TARGET(package_rbf, .init = initialize_package_rbf)
9094
std::optional<CMutableTransaction> child = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider, TX_WITH_WITNESS);
9195
if (!child) return;
9296

93-
CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};
97+
bilingual_str error;
98+
CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node), error};
99+
Assert(error.empty());
94100

95101
// Add a bunch of parent-child pairs to the mempool, and remember them.
96102
std::vector<CTransaction> mempool_txs;

src/test/fuzz/tx_pool.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
#include <test/util/script.h>
1616
#include <test/util/setup_common.h>
1717
#include <test/util/txmempool.h>
18+
#include <util/check.h>
1819
#include <util/rbf.h>
20+
#include <util/translation.h>
1921
#include <validation.h>
2022
#include <validationinterface.h>
2123

@@ -116,7 +118,7 @@ void MockTime(FuzzedDataProvider& fuzzed_data_provider, const Chainstate& chains
116118
SetMockTime(time);
117119
}
118120

119-
CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeContext& node)
121+
std::unique_ptr<CTxMemPool> MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeContext& node)
120122
{
121123
// Take the default options for tests...
122124
CTxMemPool::Options mempool_opts{MemPoolOptionsForTest(node)};
@@ -126,7 +128,12 @@ CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeConte
126128
mempool_opts.require_standard = fuzzed_data_provider.ConsumeBool();
127129

128130
// ...and construct a CTxMemPool from it
129-
return CTxMemPool{mempool_opts};
131+
bilingual_str error;
132+
auto mempool{std::make_unique<CTxMemPool>(std::move(mempool_opts), error)};
133+
// ... ignore the error since it might be beneficial to fuzz even when the
134+
// mempool size is unreasonably small
135+
Assert(error.empty() || error.original.starts_with("-maxmempool must be at least "));
136+
return mempool;
130137
}
131138

132139
void CheckATMPInvariants(const MempoolAcceptResult& res, bool txid_in_mempool, bool wtxid_in_mempool)
@@ -198,8 +205,8 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
198205
constexpr CAmount SUPPLY_TOTAL{COINBASE_MATURITY * 50 * COIN};
199206

200207
SetMempoolConstraints(*node.args, fuzzed_data_provider);
201-
CTxMemPool tx_pool_{MakeMempool(fuzzed_data_provider, node)};
202-
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
208+
auto tx_pool_{MakeMempool(fuzzed_data_provider, node)};
209+
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.get());
203210

204211
chainstate.SetMempool(&tx_pool);
205212

@@ -376,8 +383,8 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool)
376383
}
377384

378385
SetMempoolConstraints(*node.args, fuzzed_data_provider);
379-
CTxMemPool tx_pool_{MakeMempool(fuzzed_data_provider, node)};
380-
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
386+
auto tx_pool_{MakeMempool(fuzzed_data_provider, node)};
387+
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.get());
381388

382389
chainstate.SetMempool(&tx_pool);
383390

src/test/fuzz/validation_load_mempool.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
#include <test/util/setup_common.h>
1414
#include <test/util/txmempool.h>
1515
#include <txmempool.h>
16+
#include <util/check.h>
1617
#include <util/time.h>
18+
#include <util/translation.h>
1719
#include <validation.h>
1820

1921
#include <cstdint>
@@ -40,7 +42,9 @@ FUZZ_TARGET(validation_load_mempool, .init = initialize_validation_load_mempool)
4042
SetMockTime(ConsumeTime(fuzzed_data_provider));
4143
FuzzedFileProvider fuzzed_file_provider{fuzzed_data_provider};
4244

43-
CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};
45+
bilingual_str error;
46+
CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node), error};
47+
Assert(error.empty());
4448

4549
auto& chainstate{static_cast<DummyChainState&>(g_setup->m_node.chainman->ActiveChainstate())};
4650
chainstate.SetMempool(&pool);

src/test/miner_tests.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
#include <test/util/txmempool.h>
1515
#include <txmempool.h>
1616
#include <uint256.h>
17+
#include <util/check.h>
1718
#include <util/strencodings.h>
1819
#include <util/time.h>
20+
#include <util/translation.h>
1921
#include <validation.h>
2022
#include <versionbits.h>
2123

@@ -46,7 +48,9 @@ struct MinerTestingSetup : public TestingSetup {
4648
// pointer is not accessed, when the new one should be accessed
4749
// instead.
4850
m_node.mempool.reset();
49-
m_node.mempool = std::make_unique<CTxMemPool>(MemPoolOptionsForTest(m_node));
51+
bilingual_str error;
52+
m_node.mempool = std::make_unique<CTxMemPool>(MemPoolOptionsForTest(m_node), error);
53+
Assert(error.empty());
5054
return *m_node.mempool;
5155
}
5256
BlockAssembler AssemblerForTest(CTxMemPool& tx_mempool);

src/test/util/setup_common.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,9 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, const std::vecto
227227
m_node.validation_signals = std::make_unique<ValidationSignals>(std::make_unique<SerialTaskRunner>(*m_node.scheduler));
228228

229229
m_node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(FeeestPath(*m_node.args), DEFAULT_ACCEPT_STALE_FEE_ESTIMATES);
230-
m_node.mempool = std::make_unique<CTxMemPool>(MemPoolOptionsForTest(m_node));
230+
bilingual_str error{};
231+
m_node.mempool = std::make_unique<CTxMemPool>(MemPoolOptionsForTest(m_node), error);
232+
Assert(error.empty());
231233

232234
m_cache_sizes = CalculateCacheSizes(m_args);
233235

src/txmempool.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <policy/settings.h>
1717
#include <random.h>
1818
#include <reverse_iterator.h>
19+
#include <tinyformat.h>
1920
#include <util/check.h>
2021
#include <util/feefrac.h>
2122
#include <util/moneystr.h>
@@ -26,6 +27,7 @@
2627
#include <util/translation.h>
2728
#include <validationinterface.h>
2829

30+
#include <algorithm>
2931
#include <cmath>
3032
#include <numeric>
3133
#include <optional>
@@ -395,8 +397,19 @@ void CTxMemPoolEntry::UpdateAncestorState(int32_t modifySize, CAmount modifyFee,
395397
assert(int(nSigOpCostWithAncestors) >= 0);
396398
}
397399

398-
CTxMemPool::CTxMemPool(const Options& opts)
399-
: m_opts{opts}
400+
//! Clamp option values and populate the error if options are not valid.
401+
static CTxMemPool::Options&& Flatten(CTxMemPool::Options&& opts, bilingual_str& error)
402+
{
403+
opts.check_ratio = std::clamp<int>(opts.check_ratio, 0, 1'000'000);
404+
int64_t descendant_limit_bytes = opts.limits.descendant_size_vbytes * 40;
405+
if (opts.max_size_bytes < 0 || opts.max_size_bytes < descendant_limit_bytes) {
406+
error = strprintf(_("-maxmempool must be at least %d MB"), std::ceil(descendant_limit_bytes / 1'000'000.0));
407+
}
408+
return std::move(opts);
409+
}
410+
411+
CTxMemPool::CTxMemPool(Options opts, bilingual_str& error)
412+
: m_opts{Flatten(std::move(opts), error)}
400413
{
401414
}
402415

0 commit comments

Comments
 (0)