diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -260,9 +260,9 @@ // FlushStateToDisk generates a ChainStateFlushed callback, which we should // avoid missing - { + if (node.chainman) { LOCK(cs_main); - for (CChainState *chainstate : g_chainman.GetAll()) { + for (CChainState *chainstate : node.chainman->GetAll()) { if (chainstate->CanFlushToDisk()) { chainstate->ForceFlushStateToDisk(); } @@ -279,9 +279,9 @@ // wallet catch up with our current chain to avoid any strange pruning edge // cases and make next startup faster by avoiding rescan. - { + if (node.chainman) { LOCK(cs_main); - for (CChainState *chainstate : g_chainman.GetAll()) { + for (CChainState *chainstate : node.chainman->GetAll()) { if (chainstate->CanFlushToDisk()) { chainstate->ForceFlushStateToDisk(); chainstate->ResetCoinsViews(); @@ -315,9 +315,8 @@ GetMainSignals().UnregisterBackgroundSignalScheduler(); globalVerifyHandle.reset(); ECC_Stop(); - if (node.mempool) { - node.mempool = nullptr; - } + node.mempool = nullptr; + node.chainman = nullptr; node.scheduler.reset(); LogPrintf("%s: done\n", __func__); } @@ -1316,7 +1315,7 @@ } } -static void ThreadImport(const Config &config, +static void ThreadImport(const Config &config, ChainstateManager &chainman, std::vector vImportFiles) { util::ThreadRename("loadblk"); ScheduleBatchPriority(); @@ -1386,11 +1385,11 @@ // connected in the active best chain // We can't hold cs_main during ActivateBestChain even though we're - // accessing the g_chainman unique_ptrs since ABC requires us not to be + // accessing the chainman unique_ptrs since ABC requires us not to be // holding cs_main, so retrieve the relevant pointers before the ABC // call. for (CChainState *chainstate : - WITH_LOCK(::cs_main, return g_chainman.GetAll())) { + WITH_LOCK(::cs_main, return chainman.GetAll())) { BlockValidationState state; if (!chainstate->ActivateBestChain(config, state, nullptr)) { LogPrintf("Failed to connect best block (%s)\n", @@ -2212,6 +2211,9 @@ node.connman = std::make_unique( config, GetRand(std::numeric_limits::max()), GetRand(std::numeric_limits::max())); + assert(!node.chainman); + node.chainman = &g_chainman; + ChainstateManager &chainman = EnsureChainman(node); node.peer_logic.reset(new PeerLogicValidation( node.connman.get(), node.banman.get(), *node.scheduler)); @@ -2447,7 +2449,7 @@ const int64_t load_block_index_start_time = GetTimeMillis(); try { LOCK(cs_main); - g_chainman.InitializeChainstate(); + chainman.InitializeChainstate(); UnloadBlockIndex(); // new CBlockTreeDB tries to delete the existing file, which @@ -2529,7 +2531,7 @@ bool failed_chainstate_init = false; - for (CChainState *chainstate : g_chainman.GetAll()) { + for (CChainState *chainstate : chainman.GetAll()) { LogPrintf("Initializing chainstate %s\n", chainstate->ToString()); chainstate->InitCoinsDB( @@ -2586,7 +2588,7 @@ break; } - for (CChainState *chainstate : g_chainman.GetAll()) { + for (CChainState *chainstate : chainman.GetAll()) { if (!is_coinsview_empty(chainstate)) { uiInterface.InitMessage( _("Verifying blocks...").translated); @@ -2717,7 +2719,7 @@ nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK); if (!fReindex) { LOCK(cs_main); - for (CChainState *chainstate : g_chainman.GetAll()) { + for (CChainState *chainstate : chainman.GetAll()) { uiInterface.InitMessage(_("Pruning blockstore...").translated); chainstate->PruneAndFlush(); } @@ -2759,8 +2761,9 @@ vImportFiles.push_back(strFile); } - threadGroup.create_thread( - std::bind(&ThreadImport, std::ref(config), vImportFiles)); + threadGroup.create_thread([=, &config, &chainman] { + ThreadImport(config, chainman, vImportFiles); + }); // Wait for genesis block to be processed { diff --git a/src/node/context.h b/src/node/context.h --- a/src/node/context.h +++ b/src/node/context.h @@ -5,6 +5,7 @@ #ifndef BITCOIN_NODE_CONTEXT_H #define BITCOIN_NODE_CONTEXT_H +#include #include #include @@ -12,6 +13,7 @@ class CConnman; class CScheduler; class CTxMemPool; +class ChainstateManager; class PeerLogicValidation; namespace interfaces { class Chain; @@ -33,6 +35,8 @@ // Currently a raw pointer because the memory is not managed by this struct CTxMemPool *mempool{nullptr}; std::unique_ptr peer_logic; + // Currently a raw pointer because the memory is not managed by this struct + ChainstateManager *chainman{nullptr}; std::unique_ptr banman; std::unique_ptr chain; std::vector> chain_clients; @@ -45,4 +49,9 @@ ~NodeContext(); }; +inline ChainstateManager &EnsureChainman(const NodeContext &node) { + assert(node.chainman); + return *node.chainman; +} + #endif // BITCOIN_NODE_CONTEXT_H 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 @@ -148,7 +148,8 @@ pblocktree.reset(new CBlockTreeDB(1 << 20, true)); - g_chainman.InitializeChainstate(); + m_node.chainman = &::g_chainman; + m_node.chainman->InitializeChainstate(); ::ChainstateActive().InitCoinsDB( /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false); @@ -194,7 +195,8 @@ m_node.mempool = nullptr; m_node.scheduler.reset(); UnloadBlockIndex(); - g_chainman.Reset(); + m_node.chainman->Reset(); + m_node.chainman = nullptr; pblocktree.reset(); } diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -44,6 +44,7 @@ class CChain; class CConnman; class CInv; +class ChainstateManager; class Config; class CScriptCheck; class CTxMemPool; @@ -781,9 +782,6 @@ void InitCache() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); }; -// Defined below, but needed for `friend` usage in CChainState. -class ChainstateManager; - /** * CChainState stores and provides an API to update our local knowledge of the * current best chain.