diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -543,7 +543,7 @@ argsman.AddArg("-mempoolexpiry=<n>", strprintf("Do not keep transactions in the mempool longer " "than <n> hours (default: %u)", - DEFAULT_MEMPOOL_EXPIRY), + DEFAULT_MEMPOOL_EXPIRY_HOURS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg( "-minimumchainwork=<hex>", diff --git a/src/kernel/mempool_options.h b/src/kernel/mempool_options.h --- a/src/kernel/mempool_options.h +++ b/src/kernel/mempool_options.h @@ -4,10 +4,15 @@ #ifndef BITCOIN_KERNEL_MEMPOOL_OPTIONS_H #define BITCOIN_KERNEL_MEMPOOL_OPTIONS_H +#include <chrono> #include <cstdint> /** Default for -maxmempool, maximum megabytes of mempool memory usage */ static constexpr unsigned int DEFAULT_MAX_MEMPOOL_SIZE_MB{300}; +/** + * Default for -mempoolexpiry, expiration time for mempool transactions in hours + */ +static constexpr unsigned int DEFAULT_MEMPOOL_EXPIRY_HOURS{336}; namespace kernel { /** @@ -21,6 +26,8 @@ /** The ratio used to determine how often sanity checks will run. */ int check_ratio{0}; int64_t max_size_bytes{DEFAULT_MAX_MEMPOOL_SIZE_MB * 1'000'000}; + std::chrono::seconds expiry{ + std::chrono::hours{DEFAULT_MEMPOOL_EXPIRY_HOURS}}; }; } // namespace kernel diff --git a/src/mempool_args.cpp b/src/mempool_args.cpp --- a/src/mempool_args.cpp +++ b/src/mempool_args.cpp @@ -18,4 +18,8 @@ if (auto mb = argsman.GetIntArg("-maxmempool")) { mempool_opts.max_size_bytes = *mb * 1'000'000; } + + if (auto hours = argsman.GetIntArg("-mempoolexpiry")) { + mempool_opts.expiry = std::chrono::hours{*hours}; + } } diff --git a/src/txmempool.h b/src/txmempool.h --- a/src/txmempool.h +++ b/src/txmempool.h @@ -476,6 +476,7 @@ using Options = kernel::MemPoolOptions; const int64_t m_max_size_bytes; + const std::chrono::seconds m_expiry; /** * Create a new CTxMemPool. @@ -600,7 +601,7 @@ /** * Reduce the size of the mempool by expiring and then trimming the mempool. */ - void LimitSize(CCoinsViewCache &coins_cache, std::chrono::seconds age) + void LimitSize(CCoinsViewCache &coins_cache) EXCLUSIVE_LOCKS_REQUIRED(cs, ::cs_main); /** @returns true if the mempool is fully loaded */ diff --git a/src/txmempool.cpp b/src/txmempool.cpp --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -159,7 +159,8 @@ } CTxMemPool::CTxMemPool(const Options &opts) - : m_check_ratio(opts.check_ratio), m_max_size_bytes{opts.max_size_bytes} { + : m_check_ratio(opts.check_ratio), + m_max_size_bytes{opts.max_size_bytes}, m_expiry{opts.expiry} { // lock free clear _clear(); } @@ -741,11 +742,10 @@ return stage.size(); } -void CTxMemPool::LimitSize(CCoinsViewCache &coins_cache, - std::chrono::seconds age) { +void CTxMemPool::LimitSize(CCoinsViewCache &coins_cache) { AssertLockHeld(::cs_main); AssertLockHeld(cs); - int expired = Expire(GetTime<std::chrono::seconds>() - age); + int expired = Expire(GetTime<std::chrono::seconds>() - m_expiry); if (expired != 0) { LogPrint(BCLog::MEMPOOL, "Expired %i transactions from the memory pool\n", expired); @@ -1034,7 +1034,5 @@ txInfo.clear(); // Re-limit mempool size, in case we added any transactions - pool.LimitSize(active_chainstate.CoinsTip(), - std::chrono::hours{gArgs.GetIntArg("-mempoolexpiry", - DEFAULT_MEMPOOL_EXPIRY)}); + pool.LimitSize(active_chainstate.CoinsTip()); } diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -76,11 +76,6 @@ #define MIN_TRANSACTION_SIZE \ (::GetSerializeSize(CTransaction(), PROTOCOL_VERSION)) -/** - * Default for -mempoolexpiry, expiration time for mempool transactions in - * hours. - */ -static const unsigned int DEFAULT_MEMPOOL_EXPIRY = 336; /** Maximum number of dedicated script-checking threads allowed */ static const int MAX_SCRIPTCHECK_THREADS = 15; /** -par default (number of script-checking threads, 0 = auto) */ diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -731,9 +731,7 @@ // at the very end to make sure the mempool is still within limits and // package submission happens atomically. if (!args.m_package_submission && !bypass_limits) { - m_pool.LimitSize(m_active_chainstate.CoinsTip(), - std::chrono::hours{gArgs.GetIntArg( - "-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); + m_pool.LimitSize(m_active_chainstate.CoinsTip()); if (!m_pool.exists(txid)) { return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool full"); @@ -799,9 +797,7 @@ // It may or may not be the case that all the transactions made it into the // mempool. Regardless, make sure we haven't exceeded max mempool size. - m_pool.LimitSize(m_active_chainstate.CoinsTip(), - std::chrono::hours{gArgs.GetIntArg( - "-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); + m_pool.LimitSize(m_active_chainstate.CoinsTip()); if (!all_submitted) { return false; } @@ -5740,8 +5736,7 @@ bool LoadMempool(const Config &config, CTxMemPool &pool, Chainstate &active_chainstate) { - int64_t nExpiryTimeout = - gArgs.GetIntArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60; + int64_t nExpiryTimeout = std::chrono::seconds{pool.m_expiry}.count(); FILE *filestr = fsbridge::fopen(gArgs.GetDataDirNet() / "mempool.dat", "rb"); CAutoFile file(filestr, SER_DISK, CLIENT_VERSION); diff --git a/test/functional/mempool_expiry.py b/test/functional/mempool_expiry.py --- a/test/functional/mempool_expiry.py +++ b/test/functional/mempool_expiry.py @@ -5,7 +5,7 @@ """Tests that a mempool transaction expires after a given timeout and that its children are removed as well. -Both the default expiry timeout defined by DEFAULT_MEMPOOL_EXPIRY and a user +Both the default expiry timeout defined by DEFAULT_MEMPOOL_EXPIRY_HOURS and a user definable expiry timeout via the '-mempoolexpiry=<n>' command line argument (<n> is the timeout in hours) are tested. """ @@ -16,7 +16,7 @@ from test_framework.util import assert_equal, assert_raises_rpc_error from test_framework.wallet import MiniWallet -DEFAULT_MEMPOOL_EXPIRY = 336 # hours +DEFAULT_MEMPOOL_EXPIRY_HOURS = 336 # hours CUSTOM_MEMPOOL_EXPIRY = 10 # hours @@ -112,9 +112,9 @@ def run_test(self): self.log.info( - f"Test default mempool expiry timeout of {DEFAULT_MEMPOOL_EXPIRY} hours." + f"Test default mempool expiry timeout of {DEFAULT_MEMPOOL_EXPIRY_HOURS} hours." ) - self.test_transaction_expiry(DEFAULT_MEMPOOL_EXPIRY) + self.test_transaction_expiry(DEFAULT_MEMPOOL_EXPIRY_HOURS) self.log.info( f"Test custom mempool expiry timeout of {CUSTOM_MEMPOOL_EXPIRY} hours."