diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp index 04f6aae4f7..2b139cf908 100644 --- a/src/bitcoin-chainstate.cpp +++ b/src/bitcoin-chainstate.cpp @@ -86,7 +86,10 @@ int main(int argc, char* argv[]) .datadir = gArgs.GetDataDirNet(), .adjusted_time_callback = NodeClock::now, }; - ChainstateManager chainman{chainman_opts, {}}; + const node::BlockManager::Options blockman_opts{ + .chainparams = chainman_opts.chainparams, + }; + ChainstateManager chainman{chainman_opts, blockman_opts}; node::CacheSizes cache_sizes; cache_sizes.block_tree_db = 2 << 20; diff --git a/src/init.cpp b/src/init.cpp index c8137f60c1..f3325dea4f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1112,7 +1112,9 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb if (const auto error{ApplyArgsManOptions(args, chainman_opts_dummy)}) { return InitError(*error); } - node::BlockManager::Options blockman_opts_dummy{}; + node::BlockManager::Options blockman_opts_dummy{ + .chainparams = chainman_opts_dummy.chainparams, + }; if (const auto error{ApplyArgsManOptions(args, blockman_opts_dummy)}) { return InitError(*error); } @@ -1581,7 +1583,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) }; Assert(!ApplyArgsManOptions(args, chainman_opts)); // no error can happen, already checked in AppInitParameterInteraction - node::BlockManager::Options blockman_opts{}; + node::BlockManager::Options blockman_opts{ + .chainparams = chainman_opts.chainparams, + }; Assert(!ApplyArgsManOptions(args, blockman_opts)); // no error can happen, already checked in AppInitParameterInteraction // cache size calculations diff --git a/src/kernel/blockmanager_opts.h b/src/kernel/blockmanager_opts.h index 9dc93b6dd2..5584a66e02 100644 --- a/src/kernel/blockmanager_opts.h +++ b/src/kernel/blockmanager_opts.h @@ -5,6 +5,8 @@ #ifndef BITCOIN_KERNEL_BLOCKMANAGER_OPTS_H #define BITCOIN_KERNEL_BLOCKMANAGER_OPTS_H +class CChainParams; + namespace kernel { /** @@ -12,6 +14,7 @@ namespace kernel { * `BlockManager::Options` due to the using-declaration in `BlockManager`. */ struct BlockManagerOpts { + const CChainParams& chainparams; uint64_t prune_target{0}; }; diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index c1aa698059..a329972336 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -259,13 +259,13 @@ CBlockIndex* BlockManager::InsertBlockIndex(const uint256& hash) return pindex; } -bool BlockManager::LoadBlockIndex(ChainstateManager& chainman, const Consensus::Params& consensus_params) +bool BlockManager::LoadBlockIndex(ChainstateManager& chainman) { int trim_below_height = 0; if (fTrimHeaders) { trim_below_height = std::numeric_limits::max(); } - if (!m_block_tree_db->LoadBlockIndexGuts(consensus_params, [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); }, trim_below_height)) { + if (!m_block_tree_db->LoadBlockIndexGuts(GetConsensus(), [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); }, trim_below_height)) { return false; } @@ -331,9 +331,9 @@ bool BlockManager::WriteBlockIndexDB() return true; } -bool BlockManager::LoadBlockIndexDB(ChainstateManager& chainman, const Consensus::Params& consensus_params) +bool BlockManager::LoadBlockIndexDB(ChainstateManager& chainman) { - if (!LoadBlockIndex(chainman, consensus_params)) { + if (!LoadBlockIndex(chainman)) { return false; } @@ -731,16 +731,16 @@ static bool WriteBlockToDisk(const CBlock& block, FlatFilePos& pos, const CMessa return true; } -bool BlockManager::WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams) +bool BlockManager::WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex& block) { AssertLockHeld(::cs_main); // Write undo information to disk - if (pindex->GetUndoPos().IsNull()) { + if (block.GetUndoPos().IsNull()) { FlatFilePos _pos; - if (!FindUndoPos(state, pindex->nFile, _pos, ::GetSerializeSize(blockundo, CLIENT_VERSION) + 40)) { + if (!FindUndoPos(state, block.nFile, _pos, ::GetSerializeSize(blockundo, CLIENT_VERSION) + 40)) { return error("ConnectBlock(): FindUndoPos failed"); } - if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart())) { + if (!UndoWriteToDisk(blockundo, _pos, block.pprev->GetBlockHash(), GetParams().MessageStart())) { return AbortNode(state, "Failed to write undo data"); } // rev files are written in block height order, whereas blk files are written as blocks come in (often out of order) @@ -748,14 +748,14 @@ bool BlockManager::WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValid // in the block file info as below; note that this does not catch the case where the undo writes are keeping up // with the block writes (usually when a synced up node is getting newly mined blocks) -- this case is caught in // the FindBlockPos function - if (_pos.nFile < m_last_blockfile && static_cast(pindex->nHeight) == m_blockfile_info[_pos.nFile].nHeightLast) { + if (_pos.nFile < m_last_blockfile && static_cast(block.nHeight) == m_blockfile_info[_pos.nFile].nHeightLast) { FlushUndoFile(_pos.nFile, true); } // update nUndoPos in block index - pindex->nUndoPos = _pos.nPos; - pindex->nStatus |= BLOCK_HAVE_UNDO; - m_dirty_blockindex.insert(pindex); + block.nUndoPos = _pos.nPos; + block.nStatus |= BLOCK_HAVE_UNDO; + m_dirty_blockindex.insert(&block); } return true; @@ -842,7 +842,7 @@ bool ReadRawBlockFromDisk(std::vector& block, const FlatFilePos& pos, c return true; } -FlatFilePos BlockManager::SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const CChainParams& chainparams, const FlatFilePos* dbp) +FlatFilePos BlockManager::SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const FlatFilePos* dbp) { unsigned int nBlockSize = ::GetSerializeSize(block, CLIENT_VERSION); FlatFilePos blockPos; @@ -860,7 +860,7 @@ FlatFilePos BlockManager::SaveBlockToDisk(const CBlock& block, int nHeight, CCha return FlatFilePos(); } if (!position_known) { - if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) { + if (!WriteBlockToDisk(block, blockPos, GetParams().MessageStart())) { AbortNode("Failed to write block"); return FlatFilePos(); } diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h index ec2ec542a9..03e6774a1d 100644 --- a/src/node/blockstorage.h +++ b/src/node/blockstorage.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -91,12 +92,14 @@ class BlockManager friend CBlockIndex; private: + const CChainParams& GetParams() const { return m_opts.chainparams; } + const Consensus::Params& GetConsensus() const { return m_opts.chainparams.GetConsensus(); } /** * Load the blocktree off disk and into memory. Populate certain metadata * per index entry (nStatus, nChainWork, nTimeMax, etc.) as well as peripheral * collections like m_dirty_blockindex. */ - bool LoadBlockIndex(ChainstateManager& chainman, const Consensus::Params& consensus_params) + bool LoadBlockIndex(ChainstateManager& chainman) EXCLUSIVE_LOCKS_REQUIRED(cs_main); void FlushBlockFile(bool fFinalize = false, bool finalize_undo = false); void FlushUndoFile(int block_file, bool finalize = false); @@ -172,7 +175,7 @@ public: std::unique_ptr m_block_tree_db GUARDED_BY(::cs_main); bool WriteBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); - bool LoadBlockIndexDB(ChainstateManager& chainman, const Consensus::Params& consensus_params) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + bool LoadBlockIndexDB(ChainstateManager& chainman) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); /** * Remove any pruned block & undo files that are still on disk. @@ -194,11 +197,11 @@ public: /** Get block file info entry for one block file */ CBlockFileInfo* GetBlockFileInfo(size_t n); - bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams) + bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex& block) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); /** Store block on disk. If dbp is not nullptr, then it provides the known position of the block within a block file on disk. */ - FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const CChainParams& chainparams, const FlatFilePos* dbp); + FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const FlatFilePos* dbp); /** Whether running in -prune mode. */ [[nodiscard]] bool IsPruneMode() const { return m_prune_mode; } diff --git a/src/test/blockmanager_tests.cpp b/src/test/blockmanager_tests.cpp index 2118f476cd..321c86ebfa 100644 --- a/src/test/blockmanager_tests.cpp +++ b/src/test/blockmanager_tests.cpp @@ -21,23 +21,26 @@ BOOST_FIXTURE_TEST_SUITE(blockmanager_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(blockmanager_find_block_pos) { const auto params {CreateChainParams(ArgsManager{}, CBaseChainParams::MAIN)}; - BlockManager blockman{{}}; + node::BlockManager::Options blockman_opts{ + .chainparams = *params, + }; + BlockManager blockman{blockman_opts}; CChain chain {}; // simulate adding a genesis block normally - BOOST_CHECK_EQUAL(blockman.SaveBlockToDisk(params->GenesisBlock(), 0, chain, *params, nullptr).nPos, BLOCK_SERIALIZATION_HEADER_SIZE); + BOOST_CHECK_EQUAL(blockman.SaveBlockToDisk(params->GenesisBlock(), 0, chain, nullptr).nPos, BLOCK_SERIALIZATION_HEADER_SIZE); // simulate what happens during reindex // simulate a well-formed genesis block being found at offset 8 in the blk00000.dat file // the block is found at offset 8 because there is an 8 byte serialization header // consisting of 4 magic bytes + 4 length bytes before each block in a well-formed blk file. FlatFilePos pos{0, BLOCK_SERIALIZATION_HEADER_SIZE}; - BOOST_CHECK_EQUAL(blockman.SaveBlockToDisk(params->GenesisBlock(), 0, chain, *params, &pos).nPos, BLOCK_SERIALIZATION_HEADER_SIZE); + BOOST_CHECK_EQUAL(blockman.SaveBlockToDisk(params->GenesisBlock(), 0, chain, &pos).nPos, BLOCK_SERIALIZATION_HEADER_SIZE); // now simulate what happens after reindex for the first new block processed // the actual block contents don't matter, just that it's a block. // verify that the write position is at offset 0x12d. // this is a check to make sure that https://github.com/bitcoin/bitcoin/issues/21379 does not recur // 8 bytes (for serialization header) + 285 (for serialized genesis block) = 293 // add another 8 bytes for the second block's serialization header and we get 293 + 8 = 301 - FlatFilePos actual{blockman.SaveBlockToDisk(params->GenesisBlock(), 1, chain, *params, nullptr)}; + FlatFilePos actual{blockman.SaveBlockToDisk(params->GenesisBlock(), 1, chain, nullptr)}; BOOST_CHECK_EQUAL(actual.nPos, BLOCK_SERIALIZATION_HEADER_SIZE + ::GetSerializeSize(params->GenesisBlock(), CLIENT_VERSION) + BLOCK_SERIALIZATION_HEADER_SIZE); } diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index e724942fc9..5dbddf605f 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -208,7 +208,10 @@ ChainTestingSetup::ChainTestingSetup(const std::string& chainName, const std::ve .minimum_chain_work = std::nullopt, .assumed_valid_block = std::nullopt, }; - m_node.chainman = std::make_unique(chainman_opts, node::BlockManager::Options{}); + node::BlockManager::Options blockman_opts{ + .chainparams = chainman_opts.chainparams, + }; + m_node.chainman = std::make_unique(chainman_opts, blockman_opts); m_node.chainman->m_blockman.m_block_tree_db = std::make_unique(DBParams{ .path = m_args.GetDataDirNet() / "blocks" / "index", .cache_bytes = static_cast(m_cache_sizes.block_tree_db), diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp index 99cfb13fa7..009ab46d76 100644 --- a/src/test/validation_chainstatemanager_tests.cpp +++ b/src/test/validation_chainstatemanager_tests.cpp @@ -384,10 +384,13 @@ struct SnapshotTestSetup : TestChain100Setup { .minimum_chain_work = std::nullopt, .assumed_valid_block = std::nullopt, }; + node::BlockManager::Options blockman_opts{ + .chainparams = chainman_opts.chainparams, + }; // For robustness, ensure the old manager is destroyed before creating a // new one. m_node.chainman.reset(); - m_node.chainman = std::make_unique(chainman_opts, node::BlockManager::Options{}); + m_node.chainman = std::make_unique(chainman_opts, blockman_opts); } return *Assert(m_node.chainman); } diff --git a/src/validation.cpp b/src/validation.cpp index e9357b8a11..7427aa55da 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2612,7 +2612,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, if (fJustCheck) return true; - if (!m_blockman.WriteUndoDataForBlock(blockundo, state, pindex, params)) { + if (!m_blockman.WriteUndoDataForBlock(blockundo, state, *pindex)) { return false; } @@ -4475,7 +4475,7 @@ bool Chainstate::AcceptBlock(const std::shared_ptr& pblock, BlockV // Write block to history file if (fNewBlock) *fNewBlock = true; try { - FlatFilePos blockPos{m_blockman.SaveBlockToDisk(block, pindex->nHeight, m_chain, m_chainman.GetParams(), dbp)}; + FlatFilePos blockPos{m_blockman.SaveBlockToDisk(block, pindex->nHeight, m_chain, dbp)}; if (blockPos.IsNull()) { state.Error(strprintf("%s: Failed to find position to write new block to disk", __func__)); return false; @@ -4893,7 +4893,7 @@ bool ChainstateManager::LoadBlockIndex() // Load block index from databases bool needs_init = fReindex; if (!fReindex) { - bool ret = m_blockman.LoadBlockIndexDB(*this, GetConsensus()); + bool ret{m_blockman.LoadBlockIndexDB(*this)}; if (!ret) return false; m_blockman.ScanAndUnlinkAlreadyPrunedFiles(); @@ -4997,7 +4997,7 @@ bool Chainstate::LoadGenesisBlock() try { const CBlock& block = params.GenesisBlock(); - FlatFilePos blockPos{m_blockman.SaveBlockToDisk(block, 0, m_chain, params, nullptr)}; + FlatFilePos blockPos{m_blockman.SaveBlockToDisk(block, 0, m_chain, nullptr)}; if (blockPos.IsNull()) { return error("%s: writing genesis block to disk failed", __func__); } diff --git a/src/wallet/rpc/elements.cpp b/src/wallet/rpc/elements.cpp index 525960af4e..58a30f85d3 100644 --- a/src/wallet/rpc/elements.cpp +++ b/src/wallet/rpc/elements.cpp @@ -203,11 +203,12 @@ RPCHelpMan getpeginaddress() // option for dynafed-enabled ones as well ChainstateManager::Options opts{ .chainparams = chainparams, + .datadir = gArgs.GetDataDirNet(), .adjusted_time_callback = GetAdjustedTime, .minimum_chain_work = UintToArith256(consensus.nMinimumChainWork), .assumed_valid_block = consensus.defaultAssumeValid, }; - if (!DeploymentActiveAfter(pwallet->chain().getTip(), ChainstateManager(opts, {}), Consensus::DEPLOYMENT_DYNA_FED) || + if (!DeploymentActiveAfter(pwallet->chain().getTip(), ChainstateManager(opts, {chainparams}), Consensus::DEPLOYMENT_DYNA_FED) || fedpegscripts.front().first.IsPayToScriptHash()) { mainchain_dest = ScriptHash(GetScriptForDestination(mainchain_dest)); } diff --git a/test/functional/feature_trim_headers.py b/test/functional/feature_trim_headers.py index 9cf544ff68..41162e651d 100755 --- a/test/functional/feature_trim_headers.py +++ b/test/functional/feature_trim_headers.py @@ -41,6 +41,9 @@ class TrimHeadersTest(BitcoinTestFramework): self.skip_if_no_wallet() self.skip_if_no_bdb() + def add_options(self, parser): + self.add_wallet_options(parser) + # Dynamically generate N keys to be used for block signing. def init_keys(self, num_keys): self.keys = []