diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp index 432bdc8e33b..da42372a6a3 100644 --- a/src/bitcoin-chainstate.cpp +++ b/src/bitcoin-chainstate.cpp @@ -113,7 +113,7 @@ int main(int argc, char* argv[]) .chainparams = chainman_opts.chainparams, .blocks_dir = abs_datadir / "blocks", }; - ChainstateManager chainman{chainman_opts, blockman_opts}; + ChainstateManager chainman{kernel_context.interrupt, 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 e9421606efe..ac81ebab820 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1462,7 +1462,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) for (bool fLoaded = false; !fLoaded && !ShutdownRequested();) { node.mempool = std::make_unique(mempool_opts); - node.chainman = std::make_unique(chainman_opts, blockman_opts); + node.chainman = std::make_unique(node.kernel->interrupt, chainman_opts, blockman_opts); ChainstateManager& chainman = *node.chainman; node::ChainstateLoadOptions options; diff --git a/src/kernel/mempool_persist.cpp b/src/kernel/mempool_persist.cpp index 71f3aac3664..d060e45af30 100644 --- a/src/kernel/mempool_persist.cpp +++ b/src/kernel/mempool_persist.cpp @@ -9,13 +9,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include @@ -95,7 +95,7 @@ bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active } else { ++expired; } - if (ShutdownRequested()) + if (active_chainstate.m_chainman.m_interrupt) return false; } std::map mapDeltas; diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index 223b0e6a17c..a27a7a54663 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -13,12 +13,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include @@ -250,7 +250,8 @@ CBlockIndex* BlockManager::InsertBlockIndex(const uint256& hash) bool BlockManager::LoadBlockIndex() { - if (!m_block_tree_db->LoadBlockIndexGuts(GetConsensus(), [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); })) { + if (!m_block_tree_db->LoadBlockIndexGuts( + GetConsensus(), [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); }, m_interrupt)) { return false; } @@ -260,7 +261,7 @@ bool BlockManager::LoadBlockIndex() CBlockIndexHeightOnlyComparator()); for (CBlockIndex* pindex : vSortedByHeight) { - if (ShutdownRequested()) return false; + if (m_interrupt) return false; pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex); pindex->nTimeMax = (pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime) : pindex->nTime); @@ -890,8 +891,8 @@ void ThreadImport(ChainstateManager& chainman, std::vector vImportFile } LogPrintf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile); chainman.ActiveChainstate().LoadExternalBlockFile(file, &pos, &blocks_with_unknown_parent); - if (ShutdownRequested()) { - LogPrintf("Shutdown requested. Exit %s\n", __func__); + if (chainman.m_interrupt) { + LogPrintf("Interrupt requested. Exit %s\n", __func__); return; } nFile++; @@ -909,8 +910,8 @@ void ThreadImport(ChainstateManager& chainman, std::vector vImportFile if (file) { LogPrintf("Importing blocks file %s...\n", fs::PathToString(path)); chainman.ActiveChainstate().LoadExternalBlockFile(file); - if (ShutdownRequested()) { - LogPrintf("Shutdown requested. Exit %s\n", __func__); + if (chainman.m_interrupt) { + LogPrintf("Interrupt requested. Exit %s\n", __func__); return; } } else { diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h index a1ebb0df0a8..36b8aa48061 100644 --- a/src/node/blockstorage.h +++ b/src/node/blockstorage.h @@ -33,6 +33,9 @@ struct FlatFilePos; namespace Consensus { struct Params; } +namespace util { +class SignalInterrupt; +} // namespace util namespace node { @@ -153,10 +156,12 @@ private: public: using Options = kernel::BlockManagerOpts; - explicit BlockManager(Options opts) + explicit BlockManager(const util::SignalInterrupt& interrupt, Options opts) : m_prune_mode{opts.prune_target > 0}, - m_opts{std::move(opts)} {}; + m_opts{std::move(opts)}, + m_interrupt{interrupt} {}; + const util::SignalInterrupt& m_interrupt; std::atomic m_importing{false}; BlockMap m_block_index GUARDED_BY(cs_main); diff --git a/src/test/blockmanager_tests.cpp b/src/test/blockmanager_tests.cpp index f094766886c..631f85908e1 100644 --- a/src/test/blockmanager_tests.cpp +++ b/src/test/blockmanager_tests.cpp @@ -25,7 +25,7 @@ BOOST_AUTO_TEST_CASE(blockmanager_find_block_pos) .chainparams = *params, .blocks_dir = m_args.GetBlocksDirPath(), }; - BlockManager blockman{blockman_opts}; + BlockManager blockman{m_node.kernel->interrupt, blockman_opts}; CChain chain {}; // simulate adding a genesis block normally BOOST_CHECK_EQUAL(blockman.SaveBlockToDisk(params->GenesisBlock(), 0, chain, nullptr).nPos, BLOCK_SERIALIZATION_HEADER_SIZE); diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 93a60db8322..514df73922d 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -197,7 +197,7 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, const std::vecto .chainparams = chainman_opts.chainparams, .blocks_dir = m_args.GetBlocksDirPath(), }; - m_node.chainman = std::make_unique(chainman_opts, blockman_opts); + m_node.chainman = std::make_unique(m_node.kernel->interrupt, 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 b797de46af6..f918ed6f958 100644 --- a/src/test/validation_chainstatemanager_tests.cpp +++ b/src/test/validation_chainstatemanager_tests.cpp @@ -393,7 +393,7 @@ struct SnapshotTestSetup : TestChain100Setup { // 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, blockman_opts); + m_node.chainman = std::make_unique(m_node.kernel->interrupt, chainman_opts, blockman_opts); } return *Assert(m_node.chainman); } diff --git a/src/txdb.cpp b/src/txdb.cpp index b2095bd4a30..e5b5e0b8a12 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -9,8 +9,8 @@ #include #include #include -#include #include +#include #include #include @@ -291,7 +291,7 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) { return true; } -bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function insertBlockIndex) +bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function insertBlockIndex, const util::SignalInterrupt& interrupt) { AssertLockHeld(::cs_main); std::unique_ptr pcursor(NewIterator()); @@ -299,7 +299,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, // Load m_block_index while (pcursor->Valid()) { - if (ShutdownRequested()) return false; + if (interrupt) return false; std::pair key; if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) { CDiskBlockIndex diskindex; diff --git a/src/txdb.h b/src/txdb.h index 04d0ecb39f2..6405437be93 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -29,6 +29,9 @@ class uint256; namespace Consensus { struct Params; }; +namespace util { +class SignalInterrupt; +} // namespace util //! -dbcache default (MiB) static const int64_t nDefaultDbCache = 450; @@ -98,7 +101,7 @@ public: void ReadReindexing(bool &fReindexing); bool WriteFlag(const std::string &name, bool fValue); bool ReadFlag(const std::string &name, bool &fValue); - bool LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function insertBlockIndex) + bool LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function insertBlockIndex, const util::SignalInterrupt& interrupt) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); }; diff --git a/src/validation.cpp b/src/validation.cpp index 6836498a640..fc8d292d6a1 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -3183,11 +3184,11 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr< break; } - // We check shutdown only after giving ActivateBestChainStep a chance to run once so that we - // never shutdown before connecting the genesis block during LoadChainTip(). Previously this - // caused an assert() failure during shutdown in such cases as the UTXO DB flushing checks + // We check interrupt only after giving ActivateBestChainStep a chance to run once so that we + // never interrupt before connecting the genesis block during LoadChainTip(). Previously this + // caused an assert() failure during interrupt in such cases as the UTXO DB flushing checks // that the best block hash is non-null. - if (ShutdownRequested()) break; + if (m_chainman.m_interrupt) break; } while (pindexNewTip != pindexMostWork); CheckBlockIndex(); @@ -3277,7 +3278,7 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde // Disconnect (descendants of) pindex, and mark them invalid. while (true) { - if (ShutdownRequested()) break; + if (m_chainman.m_interrupt) break; // Make sure the queue of validation callbacks doesn't grow unboundedly. LimitValidationInterfaceQueue(); @@ -4079,7 +4080,7 @@ void Chainstate::LoadMempool(const fs::path& load_path, FopenFn mockable_fopen_f { if (!m_mempool) return; ::LoadMempool(*m_mempool, load_path, *this, mockable_fopen_function); - m_mempool->SetLoadTried(!ShutdownRequested()); + m_mempool->SetLoadTried(!m_chainman.m_interrupt); } bool Chainstate::LoadChainTip() @@ -4212,7 +4213,7 @@ VerifyDBResult CVerifyDB::VerifyDB( skipped_l3_checks = true; } } - if (ShutdownRequested()) return VerifyDBResult::INTERRUPTED; + if (chainstate.m_chainman.m_interrupt) return VerifyDBResult::INTERRUPTED; } if (pindexFailure) { LogPrintf("Verification error: coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainstate.m_chain.Height() - pindexFailure->nHeight + 1, nGoodTransactions); @@ -4245,7 +4246,7 @@ VerifyDBResult CVerifyDB::VerifyDB( LogPrintf("Verification error: found unconnectable block at %d, hash=%s (%s)\n", pindex->nHeight, pindex->GetBlockHash().ToString(), state.ToString()); return VerifyDBResult::CORRUPTED_BLOCK_DB; } - if (ShutdownRequested()) return VerifyDBResult::INTERRUPTED; + if (chainstate.m_chainman.m_interrupt) return VerifyDBResult::INTERRUPTED; } } @@ -4413,7 +4414,7 @@ bool ChainstateManager::LoadBlockIndex() } for (CBlockIndex* pindex : vSortedByHeight) { - if (ShutdownRequested()) return false; + if (m_interrupt) return false; if (pindex->IsAssumedValid() || (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->HaveTxsDownloaded() || pindex->pprev == nullptr))) { @@ -4519,7 +4520,7 @@ void Chainstate::LoadExternalBlockFile( // such as a block fails to deserialize. uint64_t nRewind = blkdat.GetPos(); while (!blkdat.eof()) { - if (ShutdownRequested()) return; + if (m_chainman.m_interrupt) return; blkdat.SetPos(nRewind); nRewind++; // start one byte further next time, in case of failure @@ -5152,13 +5153,13 @@ struct StopHashingException : public std::exception { const char* what() const throw() override { - return "ComputeUTXOStats interrupted by shutdown."; + return "ComputeUTXOStats interrupted."; } }; -static void SnapshotUTXOHashBreakpoint() +static void SnapshotUTXOHashBreakpoint(const util::SignalInterrupt& interrupt) { - if (ShutdownRequested()) throw StopHashingException(); + if (interrupt) throw StopHashingException(); } bool ChainstateManager::PopulateAndValidateSnapshot( @@ -5235,7 +5236,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot( // If our average Coin size is roughly 41 bytes, checking every 120,000 coins // means <5MB of memory imprecision. if (coins_processed % 120000 == 0) { - if (ShutdownRequested()) { + if (m_interrupt) { return false; } @@ -5292,7 +5293,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot( try { maybe_stats = ComputeUTXOStats( - CoinStatsHashType::HASH_SERIALIZED, snapshot_coinsdb, m_blockman, SnapshotUTXOHashBreakpoint); + CoinStatsHashType::HASH_SERIALIZED, snapshot_coinsdb, m_blockman, [&interrupt = m_interrupt] { SnapshotUTXOHashBreakpoint(interrupt); }); } catch (StopHashingException const&) { return false; } @@ -5470,7 +5471,7 @@ SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation( CoinStatsHashType::HASH_SERIALIZED, &ibd_coins_db, m_blockman, - SnapshotUTXOHashBreakpoint); + [&interrupt = m_interrupt] { SnapshotUTXOHashBreakpoint(interrupt); }); } catch (StopHashingException const&) { return SnapshotCompletionResult::STATS_FAILED; } @@ -5579,9 +5580,10 @@ static ChainstateManager::Options&& Flatten(ChainstateManager::Options&& opts) return std::move(opts); } -ChainstateManager::ChainstateManager(Options options, node::BlockManager::Options blockman_options) - : m_options{Flatten(std::move(options))}, - m_blockman{std::move(blockman_options)} {} +ChainstateManager::ChainstateManager(const util::SignalInterrupt& interrupt, Options options, node::BlockManager::Options blockman_options) + : m_interrupt{interrupt}, + m_options{Flatten(std::move(options))}, + m_blockman{interrupt, std::move(blockman_options)} {} ChainstateManager::~ChainstateManager() { diff --git a/src/validation.h b/src/validation.h index 8bc8842c54d..5412cb1d48a 100644 --- a/src/validation.h +++ b/src/validation.h @@ -62,6 +62,9 @@ class SnapshotMetadata; namespace Consensus { struct Params; } // namespace Consensus +namespace util { +class SignalInterrupt; +} // namespace util /** Maximum number of dedicated script-checking threads allowed */ static const int MAX_SCRIPTCHECK_THREADS = 15; @@ -959,7 +962,7 @@ private: public: using Options = kernel::ChainstateManagerOpts; - explicit ChainstateManager(Options options, node::BlockManager::Options blockman_options); + explicit ChainstateManager(const util::SignalInterrupt& interrupt, Options options, node::BlockManager::Options blockman_options); const CChainParams& GetParams() const { return m_options.chainparams; } const Consensus::Params& GetConsensus() const { return m_options.chainparams.GetConsensus(); } @@ -982,6 +985,7 @@ public: */ RecursiveMutex& GetMutex() const LOCK_RETURNED(::cs_main) { return ::cs_main; } + const util::SignalInterrupt& m_interrupt; const Options m_options; std::thread m_load_block; //! A single BlockManager instance is shared across each constructed