mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-02 09:46:52 -05:00
Merge bitcoin/bitcoin#28830: [refactor] Check CTxMemPool options in ctor
09ef322acc
[[refactor]] Check CTxMemPool options in constructor (TheCharlatan) Pull request description: The tests should run the same checks on the mempool options that the init code also applies. The downside to this patch is that the log line may now be printed more than once in the for loop. This was originally noticed here https://github.com/bitcoin/bitcoin/pull/25290#discussion_r900272797. ACKs for top commit: stickies-v: re-ACK09ef322acc
. Fixed unreachable assert and updated docstring, and also added an exception for "-maxmempool must be at least " in the `tx_pool` fuzz test, which makes sense when looking at how the mempool options are constructed in `SetMempoolConstraints`. achow101: ACK09ef322acc
ryanofsky: Code review ACK09ef322acc
. Just fuzz test error checking fix and updated comment since last review Tree-SHA512: eb3361411c2db70be17f912e3b14d9cb9c60fb0697a1eded952c3b7e8675b7d783780d45c52e091931d1d80fe0f0280cee98dd57a3100def13af20259d9d1b9e
This commit is contained in:
commit
2251460f3e
11 changed files with 83 additions and 30 deletions
14
src/init.cpp
14
src/init.cpp
|
@ -1522,19 +1522,17 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
|||
if (!result) {
|
||||
return InitError(util::ErrorString(result));
|
||||
}
|
||||
mempool_opts.check_ratio = std::clamp<int>(mempool_opts.check_ratio, 0, 1'000'000);
|
||||
|
||||
int64_t descendant_limit_bytes = mempool_opts.limits.descendant_size_vbytes * 40;
|
||||
if (mempool_opts.max_size_bytes < 0 || mempool_opts.max_size_bytes < descendant_limit_bytes) {
|
||||
return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(descendant_limit_bytes / 1'000'000.0)));
|
||||
}
|
||||
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));
|
||||
|
||||
bool do_reindex{args.GetBoolArg("-reindex", false)};
|
||||
const bool do_reindex_chainstate{args.GetBoolArg("-reindex-chainstate", false)};
|
||||
|
||||
for (bool fLoaded = false; !fLoaded && !ShutdownRequested(node);) {
|
||||
node.mempool = std::make_unique<CTxMemPool>(mempool_opts);
|
||||
bilingual_str mempool_error;
|
||||
node.mempool = std::make_unique<CTxMemPool>(mempool_opts, mempool_error);
|
||||
if (!mempool_error.empty()) {
|
||||
return InitError(mempool_error);
|
||||
}
|
||||
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));
|
||||
|
||||
node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown), chainman_opts, blockman_opts);
|
||||
ChainstateManager& chainman = *node.chainman;
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
#include <test/util/txmempool.h>
|
||||
#include <test/util/mining.h>
|
||||
|
||||
#include <node/mini_miner.h>
|
||||
#include <node/miner.h>
|
||||
#include <node/mini_miner.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <random.h>
|
||||
#include <txmempool.h>
|
||||
#include <util/check.h>
|
||||
#include <util/translation.h>
|
||||
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
@ -33,7 +35,9 @@ void initialize_miner()
|
|||
FUZZ_TARGET(mini_miner, .init = initialize_miner)
|
||||
{
|
||||
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
|
||||
CTxMemPool pool{CTxMemPool::Options{}};
|
||||
bilingual_str error;
|
||||
CTxMemPool pool{CTxMemPool::Options{}, error};
|
||||
Assert(error.empty());
|
||||
std::vector<COutPoint> outpoints;
|
||||
std::deque<COutPoint> available_coins = g_available_coins;
|
||||
LOCK2(::cs_main, pool.cs);
|
||||
|
@ -109,7 +113,9 @@ FUZZ_TARGET(mini_miner, .init = initialize_miner)
|
|||
FUZZ_TARGET(mini_miner_selection, .init = initialize_miner)
|
||||
{
|
||||
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
|
||||
CTxMemPool pool{CTxMemPool::Options{}};
|
||||
bilingual_str error;
|
||||
CTxMemPool pool{CTxMemPool::Options{}, error};
|
||||
Assert(error.empty());
|
||||
// Make a copy to preserve determinism.
|
||||
std::deque<COutPoint> available_coins = g_available_coins;
|
||||
std::vector<CTransactionRef> transactions;
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
#include <test/util/script.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <test/util/txmempool.h>
|
||||
#include <util/check.h>
|
||||
#include <util/rbf.h>
|
||||
#include <util/translation.h>
|
||||
#include <validation.h>
|
||||
#include <validationinterface.h>
|
||||
|
||||
|
@ -107,7 +109,7 @@ void MockTime(FuzzedDataProvider& fuzzed_data_provider, const Chainstate& chains
|
|||
SetMockTime(time);
|
||||
}
|
||||
|
||||
CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeContext& node)
|
||||
std::unique_ptr<CTxMemPool> MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeContext& node)
|
||||
{
|
||||
// Take the default options for tests...
|
||||
CTxMemPool::Options mempool_opts{MemPoolOptionsForTest(node)};
|
||||
|
@ -126,8 +128,13 @@ CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeConte
|
|||
mempool_opts.check_ratio = 1;
|
||||
mempool_opts.require_standard = fuzzed_data_provider.ConsumeBool();
|
||||
|
||||
bilingual_str error;
|
||||
// ...and construct a CTxMemPool from it
|
||||
return CTxMemPool{mempool_opts};
|
||||
auto mempool{std::make_unique<CTxMemPool>(std::move(mempool_opts), error)};
|
||||
// ... ignore the error since it might be beneficial to fuzz even when the
|
||||
// mempool size is unreasonably small
|
||||
Assert(error.empty() || error.original.starts_with("-maxmempool must be at least "));
|
||||
return mempool;
|
||||
}
|
||||
|
||||
FUZZ_TARGET(tx_package_eval, .init = initialize_tx_pool)
|
||||
|
@ -149,8 +156,8 @@ FUZZ_TARGET(tx_package_eval, .init = initialize_tx_pool)
|
|||
auto outpoints_updater = std::make_shared<OutpointsUpdater>(mempool_outpoints);
|
||||
node.validation_signals->RegisterSharedValidationInterface(outpoints_updater);
|
||||
|
||||
CTxMemPool tx_pool_{MakeMempool(fuzzed_data_provider, node)};
|
||||
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
|
||||
auto tx_pool_{MakeMempool(fuzzed_data_provider, node)};
|
||||
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.get());
|
||||
|
||||
chainstate.SetMempool(&tx_pool);
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include <test/util/setup_common.h>
|
||||
#include <test/util/txmempool.h>
|
||||
#include <txmempool.h>
|
||||
#include <util/check.h>
|
||||
#include <util/translation.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
@ -52,7 +54,9 @@ FUZZ_TARGET(partially_downloaded_block, .init = initialize_pdb)
|
|||
|
||||
CBlockHeaderAndShortTxIDs cmpctblock{*block};
|
||||
|
||||
CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};
|
||||
bilingual_str error;
|
||||
CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node), error};
|
||||
Assert(error.empty());
|
||||
PartiallyDownloadedBlock pdb{&pool};
|
||||
|
||||
// Set of available transactions (mempool or extra_txn)
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include <test/util/setup_common.h>
|
||||
#include <test/util/txmempool.h>
|
||||
#include <txmempool.h>
|
||||
#include <util/check.h>
|
||||
#include <util/translation.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
@ -56,7 +58,9 @@ FUZZ_TARGET(rbf, .init = initialize_rbf)
|
|||
return;
|
||||
}
|
||||
|
||||
CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};
|
||||
bilingual_str error;
|
||||
CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node), error};
|
||||
Assert(error.empty());
|
||||
|
||||
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), NUM_ITERS)
|
||||
{
|
||||
|
@ -90,7 +94,9 @@ FUZZ_TARGET(package_rbf, .init = initialize_package_rbf)
|
|||
std::optional<CMutableTransaction> child = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider, TX_WITH_WITNESS);
|
||||
if (!child) return;
|
||||
|
||||
CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};
|
||||
bilingual_str error;
|
||||
CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node), error};
|
||||
Assert(error.empty());
|
||||
|
||||
// Add a bunch of parent-child pairs to the mempool, and remember them.
|
||||
std::vector<CTransaction> mempool_txs;
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
#include <test/util/script.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <test/util/txmempool.h>
|
||||
#include <util/check.h>
|
||||
#include <util/rbf.h>
|
||||
#include <util/translation.h>
|
||||
#include <validation.h>
|
||||
#include <validationinterface.h>
|
||||
|
||||
|
@ -116,7 +118,7 @@ void MockTime(FuzzedDataProvider& fuzzed_data_provider, const Chainstate& chains
|
|||
SetMockTime(time);
|
||||
}
|
||||
|
||||
CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeContext& node)
|
||||
std::unique_ptr<CTxMemPool> MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeContext& node)
|
||||
{
|
||||
// Take the default options for tests...
|
||||
CTxMemPool::Options mempool_opts{MemPoolOptionsForTest(node)};
|
||||
|
@ -126,7 +128,12 @@ CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeConte
|
|||
mempool_opts.require_standard = fuzzed_data_provider.ConsumeBool();
|
||||
|
||||
// ...and construct a CTxMemPool from it
|
||||
return CTxMemPool{mempool_opts};
|
||||
bilingual_str error;
|
||||
auto mempool{std::make_unique<CTxMemPool>(std::move(mempool_opts), error)};
|
||||
// ... ignore the error since it might be beneficial to fuzz even when the
|
||||
// mempool size is unreasonably small
|
||||
Assert(error.empty() || error.original.starts_with("-maxmempool must be at least "));
|
||||
return mempool;
|
||||
}
|
||||
|
||||
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)
|
|||
constexpr CAmount SUPPLY_TOTAL{COINBASE_MATURITY * 50 * COIN};
|
||||
|
||||
SetMempoolConstraints(*node.args, fuzzed_data_provider);
|
||||
CTxMemPool tx_pool_{MakeMempool(fuzzed_data_provider, node)};
|
||||
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
|
||||
auto tx_pool_{MakeMempool(fuzzed_data_provider, node)};
|
||||
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.get());
|
||||
|
||||
chainstate.SetMempool(&tx_pool);
|
||||
|
||||
|
@ -376,8 +383,8 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool)
|
|||
}
|
||||
|
||||
SetMempoolConstraints(*node.args, fuzzed_data_provider);
|
||||
CTxMemPool tx_pool_{MakeMempool(fuzzed_data_provider, node)};
|
||||
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
|
||||
auto tx_pool_{MakeMempool(fuzzed_data_provider, node)};
|
||||
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.get());
|
||||
|
||||
chainstate.SetMempool(&tx_pool);
|
||||
|
||||
|
|
|
@ -13,7 +13,9 @@
|
|||
#include <test/util/setup_common.h>
|
||||
#include <test/util/txmempool.h>
|
||||
#include <txmempool.h>
|
||||
#include <util/check.h>
|
||||
#include <util/time.h>
|
||||
#include <util/translation.h>
|
||||
#include <validation.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
@ -40,7 +42,9 @@ FUZZ_TARGET(validation_load_mempool, .init = initialize_validation_load_mempool)
|
|||
SetMockTime(ConsumeTime(fuzzed_data_provider));
|
||||
FuzzedFileProvider fuzzed_file_provider{fuzzed_data_provider};
|
||||
|
||||
CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};
|
||||
bilingual_str error;
|
||||
CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node), error};
|
||||
Assert(error.empty());
|
||||
|
||||
auto& chainstate{static_cast<DummyChainState&>(g_setup->m_node.chainman->ActiveChainstate())};
|
||||
chainstate.SetMempool(&pool);
|
||||
|
|
|
@ -14,8 +14,10 @@
|
|||
#include <test/util/txmempool.h>
|
||||
#include <txmempool.h>
|
||||
#include <uint256.h>
|
||||
#include <util/check.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/time.h>
|
||||
#include <util/translation.h>
|
||||
#include <validation.h>
|
||||
#include <versionbits.h>
|
||||
|
||||
|
@ -46,7 +48,9 @@ struct MinerTestingSetup : public TestingSetup {
|
|||
// pointer is not accessed, when the new one should be accessed
|
||||
// instead.
|
||||
m_node.mempool.reset();
|
||||
m_node.mempool = std::make_unique<CTxMemPool>(MemPoolOptionsForTest(m_node));
|
||||
bilingual_str error;
|
||||
m_node.mempool = std::make_unique<CTxMemPool>(MemPoolOptionsForTest(m_node), error);
|
||||
Assert(error.empty());
|
||||
return *m_node.mempool;
|
||||
}
|
||||
BlockAssembler AssemblerForTest(CTxMemPool& tx_mempool);
|
||||
|
|
|
@ -227,7 +227,9 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, const std::vecto
|
|||
m_node.validation_signals = std::make_unique<ValidationSignals>(std::make_unique<SerialTaskRunner>(*m_node.scheduler));
|
||||
|
||||
m_node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(FeeestPath(*m_node.args), DEFAULT_ACCEPT_STALE_FEE_ESTIMATES);
|
||||
m_node.mempool = std::make_unique<CTxMemPool>(MemPoolOptionsForTest(m_node));
|
||||
bilingual_str error{};
|
||||
m_node.mempool = std::make_unique<CTxMemPool>(MemPoolOptionsForTest(m_node), error);
|
||||
Assert(error.empty());
|
||||
|
||||
m_cache_sizes = CalculateCacheSizes(m_args);
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <policy/settings.h>
|
||||
#include <random.h>
|
||||
#include <reverse_iterator.h>
|
||||
#include <tinyformat.h>
|
||||
#include <util/check.h>
|
||||
#include <util/feefrac.h>
|
||||
#include <util/moneystr.h>
|
||||
|
@ -26,6 +27,7 @@
|
|||
#include <util/translation.h>
|
||||
#include <validationinterface.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
|
@ -395,8 +397,19 @@ void CTxMemPoolEntry::UpdateAncestorState(int32_t modifySize, CAmount modifyFee,
|
|||
assert(int(nSigOpCostWithAncestors) >= 0);
|
||||
}
|
||||
|
||||
CTxMemPool::CTxMemPool(const Options& opts)
|
||||
: m_opts{opts}
|
||||
//! Clamp option values and populate the error if options are not valid.
|
||||
static CTxMemPool::Options&& Flatten(CTxMemPool::Options&& opts, bilingual_str& error)
|
||||
{
|
||||
opts.check_ratio = std::clamp<int>(opts.check_ratio, 0, 1'000'000);
|
||||
int64_t descendant_limit_bytes = opts.limits.descendant_size_vbytes * 40;
|
||||
if (opts.max_size_bytes < 0 || opts.max_size_bytes < descendant_limit_bytes) {
|
||||
error = strprintf(_("-maxmempool must be at least %d MB"), std::ceil(descendant_limit_bytes / 1'000'000.0));
|
||||
}
|
||||
return std::move(opts);
|
||||
}
|
||||
|
||||
CTxMemPool::CTxMemPool(Options opts, bilingual_str& error)
|
||||
: m_opts{Flatten(std::move(opts), error)}
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
class CChain;
|
||||
class ValidationSignals;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -442,7 +444,7 @@ public:
|
|||
* accepting transactions becomes O(N^2) where N is the number of transactions
|
||||
* in the pool.
|
||||
*/
|
||||
explicit CTxMemPool(const Options& opts);
|
||||
explicit CTxMemPool(Options opts, bilingual_str& error);
|
||||
|
||||
/**
|
||||
* If sanity-checking is turned on, check makes sure the pool is
|
||||
|
|
Loading…
Add table
Reference in a new issue