diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -650,6 +650,7 @@ minerfund.cpp net.cpp net_processing.cpp + node/blockmanager_args.cpp node/blockstorage.cpp node/caches.cpp node/chainstate.cpp diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp --- a/src/bitcoin-chainstate.cpp +++ b/src/bitcoin-chainstate.cpp @@ -89,7 +89,7 @@ .config = config, .adjusted_time_callback = NodeClock::now, }; - ChainstateManager chainman{chainman_opts}; + ChainstateManager chainman{chainman_opts, {}}; node::CacheSizes cache_sizes; cache_sizes.block_tree_db = 2 << 20; diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -122,7 +123,6 @@ using node::LoadChainstate; using node::MempoolPath; using node::NodeContext; -using node::nPruneTarget; using node::ShouldPersistMempool; using node::ThreadImport; using node::VerifyLoadedChainstate; @@ -1878,28 +1878,6 @@ "(excessiveblocksize)")); } - // block pruning; get the amount of disk space (in MiB) to allot for block & - // undo files - int64_t nPruneArg = args.GetIntArg("-prune", 0); - if (nPruneArg < 0) { - return InitError( - _("Prune cannot be configured with a negative value.")); - } - nPruneTarget = (uint64_t)nPruneArg * 1024 * 1024; - if (nPruneArg == 1) { - // manual pruning: -prune=1 - nPruneTarget = std::numeric_limits::max(); - fPruneMode = true; - } else if (nPruneTarget) { - if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) { - return InitError( - strprintf(_("Prune configured below the minimum of %d MiB. " - "Please use a higher number."), - MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); - } - fPruneMode = true; - } - nConnectTimeout = args.GetIntArg("-timeout", DEFAULT_CONNECT_TIMEOUT); if (nConnectTimeout <= 0) { nConnectTimeout = DEFAULT_CONNECT_TIMEOUT; @@ -2007,6 +1985,10 @@ if (const auto error{ApplyArgsManOptions(args, chainman_opts_dummy)}) { return InitError(*error); } + node::BlockManager::Options blockman_opts_dummy{}; + if (const auto error{ApplyArgsManOptions(args, blockman_opts_dummy)}) { + return InitError(*error); + } } return true; @@ -2391,6 +2373,10 @@ LogPrintf("Skipping checkpoint verification.\n"); } + node::BlockManager::Options blockman_opts{}; + // no error can happen, already checked in AppInitParameterInteraction + Assert(!ApplyArgsManOptions(args, blockman_opts)); + // cache size calculations CacheSizes cache_sizes = CalculateCacheSizes(args, g_enabled_filter_types.size()); @@ -2441,7 +2427,8 @@ for (bool fLoaded = false; !fLoaded && !ShutdownRequested();) { node.mempool = std::make_unique(mempool_opts); - node.chainman = std::make_unique(chainman_opts); + node.chainman = + std::make_unique(chainman_opts, blockman_opts); ChainstateManager &chainman = *node.chainman; node::ChainstateLoadOptions options; diff --git a/src/kernel/blockmanager_opts.h b/src/kernel/blockmanager_opts.h new file mode 100644 --- /dev/null +++ b/src/kernel/blockmanager_opts.h @@ -0,0 +1,20 @@ +// Copyright (c) 2022 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_KERNEL_BLOCKMANAGER_OPTS_H +#define BITCOIN_KERNEL_BLOCKMANAGER_OPTS_H + +namespace kernel { + +/** + * An options struct for `BlockManager`, more ergonomically referred to as + * `BlockManager::Options` due to the using-declaration in `BlockManager`. + */ +struct BlockManagerOpts { + uint64_t prune_target{0}; +}; + +} // namespace kernel + +#endif // BITCOIN_KERNEL_BLOCKMANAGER_OPTS_H diff --git a/src/node/blockmanager_args.h b/src/node/blockmanager_args.h new file mode 100644 --- /dev/null +++ b/src/node/blockmanager_args.h @@ -0,0 +1,20 @@ +// Copyright (c) 2023 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_NODE_BLOCKMANAGER_ARGS_H +#define BITCOIN_NODE_BLOCKMANAGER_ARGS_H + +#include + +#include + +class ArgsManager; +struct bilingual_str; + +namespace node { +std::optional ApplyArgsManOptions(const ArgsManager &args, + BlockManager::Options &opts); +} // namespace node + +#endif // BITCOIN_NODE_BLOCKMANAGER_ARGS_H diff --git a/src/node/blockmanager_args.cpp b/src/node/blockmanager_args.cpp new file mode 100644 --- /dev/null +++ b/src/node/blockmanager_args.cpp @@ -0,0 +1,36 @@ +// Copyright (c) 2023 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 + +#include +#include + +namespace node { +std::optional ApplyArgsManOptions(const ArgsManager &args, + BlockManager::Options &opts) { + // block pruning; get the amount of disk space (in MiB) to allot for block & + // undo files + int64_t nPruneArg{args.GetIntArg("-prune", opts.prune_target)}; + if (nPruneArg < 0) { + return _("Prune cannot be configured with a negative value."); + } + uint64_t nPruneTarget{uint64_t(nPruneArg) * 1024 * 1024}; + // manual pruning: -prune=1 + if (nPruneArg == 1) { + nPruneTarget = std::numeric_limits::max(); + fPruneMode = true; + } else if (nPruneTarget) { + if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) { + return strprintf(_("Prune configured below the minimum of %d MiB. " + "Please use a higher number."), + MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024); + } + fPruneMode = true; + } + opts.prune_target = nPruneTarget; + + return std::nullopt; +} +} // namespace node diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h --- a/src/node/blockstorage.h +++ b/src/node/blockstorage.h @@ -10,6 +10,7 @@ #include #include +#include #include #include // For CMessageHeader::MessageStartChars #include @@ -50,7 +51,6 @@ extern std::atomic_bool fImporting; extern std::atomic_bool fReindex; extern bool fPruneMode; -extern uint64_t nPruneTarget; // Because validation code takes pointers to the map's CBlockIndex objects, if // we ever switch to another associative container, we need to either use a @@ -133,7 +133,13 @@ /** Dirty block file entries. */ std::set m_dirty_fileinfo; + const kernel::BlockManagerOpts m_opts; + public: + using Options = kernel::BlockManagerOpts; + + explicit BlockManager(Options opts) : m_opts{std::move(opts)} {}; + BlockMap m_block_index GUARDED_BY(cs_main); std::vector GetAllBlockIndices() @@ -189,7 +195,9 @@ [[nodiscard]] bool IsPruneMode() const { return fPruneMode; } /** Attempt to stay below this number of bytes of block files. */ - [[nodiscard]] uint64_t GetPruneTarget() const { return nPruneTarget; } + [[nodiscard]] uint64_t GetPruneTarget() const { + return m_opts.prune_target; + } [[nodiscard]] bool LoadingBlocks() const { return fImporting || fReindex; } diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -27,7 +27,6 @@ std::atomic_bool fImporting(false); std::atomic_bool fReindex(false); bool fPruneMode = false; -uint64_t nPruneTarget = 0; static FILE *OpenUndoFile(const FlatFilePos &pos, bool fReadOnly = false); @@ -163,7 +162,7 @@ int chain_tip_height, int prune_height, bool is_ibd) { LOCK2(cs_main, cs_LastBlockFile); - if (chain_tip_height < 0 || nPruneTarget == 0) { + if (chain_tip_height < 0 || GetPruneTarget() == 0) { return; } if (uint64_t(chain_tip_height) <= nPruneAfterHeight) { @@ -180,7 +179,7 @@ uint64_t nBytesToPrune; int count = 0; - if (nCurrentUsage + nBuffer >= nPruneTarget) { + if (nCurrentUsage + nBuffer >= GetPruneTarget()) { // On a prune event, the chainstate DB is flushed. // To avoid excessive prune events negating the benefit of high dbcache // values, we should not prune too rapidly. @@ -188,7 +187,7 @@ // too soon. if (is_ibd) { // Since this is only relevant during IBD, we use a fixed 10% - nBuffer += nPruneTarget / 10; + nBuffer += GetPruneTarget() / 10; } for (int fileNumber = 0; fileNumber < m_last_blockfile; fileNumber++) { @@ -200,7 +199,7 @@ } // are we below our target? - if (nCurrentUsage + nBuffer < nPruneTarget) { + if (nCurrentUsage + nBuffer < GetPruneTarget()) { break; } @@ -222,8 +221,8 @@ LogPrint(BCLog::PRUNE, "Prune: target=%dMiB actual=%dMiB diff=%dMiB " "max_prune_height=%d removed %d blk/rev pairs\n", - nPruneTarget / 1024 / 1024, nCurrentUsage / 1024 / 1024, - ((int64_t)nPruneTarget - (int64_t)nCurrentUsage) / 1024 / 1024, + GetPruneTarget() / 1024 / 1024, nCurrentUsage / 1024 / 1024, + (int64_t(GetPruneTarget()) - int64_t(nCurrentUsage)) / 1024 / 1024, nLastBlockWeCanPrune, count); } diff --git a/src/test/blockmanager_tests.cpp b/src/test/blockmanager_tests.cpp --- a/src/test/blockmanager_tests.cpp +++ b/src/test/blockmanager_tests.cpp @@ -19,7 +19,7 @@ BOOST_AUTO_TEST_CASE(blockmanager_find_block_pos) { const auto params{CreateChainParams(CBaseChainParams::MAIN)}; - BlockManager blockman{}; + BlockManager blockman{{}}; CChain chain{}; // simulate adding a genesis block normally BOOST_CHECK_EQUAL( diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -217,7 +217,8 @@ .check_block_index = true, }; ApplyArgsManOptions(*m_node.args, chainman_opts); - m_node.chainman = std::make_unique(chainman_opts); + m_node.chainman = std::make_unique( + chainman_opts, node::BlockManager::Options{}); m_node.chainman->m_blockman.m_block_tree_db = std::make_unique(m_cache_sizes.block_tree_db, true); // Call Upgrade on the block database so that the version field is set, diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp --- a/src/test/validation_chainstatemanager_tests.cpp +++ b/src/test/validation_chainstatemanager_tests.cpp @@ -403,7 +403,8 @@ // For robustness, ensure the old manager is destroyed before // creating a new one. m_node.chainman.reset(); - m_node.chainman.reset(new ChainstateManager(chainman_opts)); + m_node.chainman = std::make_unique( + chainman_opts, node::BlockManager::Options{}); } return *Assert(m_node.chainman); } @@ -623,7 +624,7 @@ // chainstate_snapshot should still exist. BOOST_CHECK(fs::exists(snapshot_chainstate_dir)); - // Test that simulating a shutdown (reseting ChainstateManager) and then + // Test that simulating a shutdown (resetting ChainstateManager) and then // performing chainstate reinitializing successfully cleans up the // background-validation chainstate data, and we end up with a single // chainstate that is at tip. @@ -701,7 +702,7 @@ gArgs.GetDataDirNet() / "chainstate_snapshot_INVALID"; BOOST_CHECK(fs::exists(snapshot_invalid_dir)); - // Test that simulating a shutdown (reseting ChainstateManager) and then + // Test that simulating a shutdown (resetting ChainstateManager) and then // performing chainstate reinitializing successfully loads only the // fully-validated chainstate data, and we end up with a single chainstate // that is at tip. diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -1228,7 +1228,8 @@ public: using Options = kernel::ChainstateManagerOpts; - explicit ChainstateManager(Options options); + explicit ChainstateManager(Options options, + node::BlockManager::Options blockman_options); const Config &GetConfig() const { return m_options.config; } diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -82,7 +82,6 @@ using node::CoinStatsHashType; using node::ComputeUTXOStats; using node::fReindex; -using node::nPruneTarget; using node::OpenBlockFile; using node::ReadBlockFromDisk; using node::SnapshotMetadata; @@ -6405,8 +6404,10 @@ return std::move(opts); } -ChainstateManager::ChainstateManager(Options options) - : m_options{Flatten(std::move(options))} {} +ChainstateManager::ChainstateManager( + Options options, node::BlockManager::Options blockman_options) + : m_options{Flatten(std::move(options))}, m_blockman{std::move( + blockman_options)} {} bool ChainstateManager::DetectSnapshotChainstate(CTxMemPool *mempool) { assert(!m_snapshot_chainstate);