diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -2559,7 +2559,7 @@ const int64_t load_block_index_start_time = GetTimeMillis(); try { LOCK(cs_main); - chainman.InitializeChainstate(); + chainman.InitializeChainstate(*Assert(node.mempool)); chainman.m_total_coinstip_cache = nCoinCacheUsage; chainman.m_total_coinsdb_cache = nCoinDBCache; 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 @@ -177,8 +177,11 @@ pblocktree.reset(new CBlockTreeDB(1 << 20, true)); + m_node.mempool = &::g_mempool; + m_node.mempool->setSanityCheck(1.0); + m_node.chainman = &::g_chainman; - m_node.chainman->InitializeChainstate(); + m_node.chainman->InitializeChainstate(*m_node.mempool); ::ChainstateActive().InitCoinsDB( /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false); @@ -200,8 +203,6 @@ threadGroup.create_thread([i]() { return ThreadScriptCheck(i); }); } - m_node.mempool = &::g_mempool; - m_node.mempool->setSanityCheck(1.0); m_node.banman = std::make_unique(GetDataDir() / "banlist.dat", chainparams, nullptr, DEFAULT_MISBEHAVING_BANTIME); diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp --- a/src/test/validation_chainstate_tests.cpp +++ b/src/test/validation_chainstate_tests.cpp @@ -19,6 +19,7 @@ //! BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches) { ChainstateManager manager; + CTxMemPool mempool; //! Create and add a Coin with DynamicMemoryUsage of 80 bytes to the given //! view. @@ -35,7 +36,7 @@ }; CChainState &c1 = - *WITH_LOCK(cs_main, return &manager.InitializeChainstate()); + *WITH_LOCK(cs_main, return &manager.InitializeChainstate(mempool)); c1.InitCoinsDB( /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false); 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 @@ -22,13 +22,14 @@ //! First create a legacy (IBD) chainstate, then create a snapshot chainstate. BOOST_AUTO_TEST_CASE(chainstatemanager) { ChainstateManager manager; + CTxMemPool mempool; std::vector chainstates; const CChainParams &chainparams = Params(); // Create a legacy (IBD) chainstate. // CChainState &c1 = - *WITH_LOCK(::cs_main, return &manager.InitializeChainstate()); + *WITH_LOCK(::cs_main, return &manager.InitializeChainstate(mempool)); chainstates.push_back(&c1); c1.InitCoinsDB( /* cache_size_bytes */ 1 << 23, /* in_memory */ true, @@ -56,9 +57,9 @@ // Create a snapshot-based chainstate. // - CChainState &c2 = *WITH_LOCK( - ::cs_main, - return &manager.InitializeChainstate(BlockHash{GetRandHash()})); + CChainState &c2 = + *WITH_LOCK(::cs_main, return &manager.InitializeChainstate( + mempool, BlockHash{GetRandHash()})); chainstates.push_back(&c2); c2.InitCoinsDB( /* cache_size_bytes */ 1 << 23, /* in_memory */ true, @@ -110,6 +111,7 @@ //! Test rebalancing the caches associated with each chainstate. BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches) { ChainstateManager manager; + CTxMemPool mempool; size_t max_cache = 10000; manager.m_total_coinsdb_cache = max_cache; manager.m_total_coinstip_cache = max_cache; @@ -119,7 +121,7 @@ // Create a legacy (IBD) chainstate. // CChainState &c1 = - *WITH_LOCK(cs_main, return &manager.InitializeChainstate()); + *WITH_LOCK(cs_main, return &manager.InitializeChainstate(mempool)); chainstates.push_back(&c1); c1.InitCoinsDB( /* cache_size_bytes */ 1 << 23, /* in_memory */ true, @@ -137,8 +139,9 @@ // Create a snapshot-based chainstate. // - CChainState &c2 = *WITH_LOCK(cs_main, return &manager.InitializeChainstate( - BlockHash{GetRandHash()})); + CChainState &c2 = + *WITH_LOCK(cs_main, return &manager.InitializeChainstate( + mempool, BlockHash{GetRandHash()})); chainstates.push_back(&c2); c2.InitCoinsDB( /* cache_size_bytes */ 1 << 23, /* in_memory */ true, diff --git a/src/test/validation_flush_tests.cpp b/src/test/validation_flush_tests.cpp --- a/src/test/validation_flush_tests.cpp +++ b/src/test/validation_flush_tests.cpp @@ -17,8 +17,9 @@ //! @sa CChainState::GetCoinsCacheSizeState() //! BOOST_AUTO_TEST_CASE(getcoinscachesizestate) { + CTxMemPool mempool; BlockManager blockman{}; - CChainState chainstate{blockman}; + CChainState chainstate{mempool, blockman}; chainstate.InitCoinsDB(/*cache_size_bytes*/ 1 << 10, /*in_memory*/ true, /*should_wipe*/ false); WITH_LOCK(::cs_main, chainstate.InitCoinsCache(1 << 10)); diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -719,6 +719,9 @@ //! easily as opposed to referencing a global. BlockManager &m_blockman; + //! mempool that is kept in sync with the chain + CTxMemPool &m_mempool; + //! Manages the UTXO set, which is a reflection of the contents of //! `m_chain`. std::unique_ptr m_coins_views; @@ -730,7 +733,7 @@ const CBlockIndex *m_finalizedBlockIndex GUARDED_BY(cs_main) = nullptr; public: - explicit CChainState(BlockManager &blockman, + explicit CChainState(CTxMemPool &mempool, BlockManager &blockman, BlockHash from_snapshot_blockhash = BlockHash()); /** @@ -864,7 +867,7 @@ // Block disconnection on our pcoinsTip: bool DisconnectTip(const CChainParams ¶ms, BlockValidationState &state, DisconnectedBlockTransactions *disconnectpool) - EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::g_mempool.cs); + EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs); // Manual block validity manipulation: bool PreciousBlock(const Config &config, BlockValidationState &state, @@ -952,13 +955,13 @@ CBlockIndex *pindexMostWork, const std::shared_ptr &pblock, bool &fInvalidFound, ConnectTrace &connectTrace) - EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::g_mempool.cs); + EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs); bool ConnectTip(const Config &config, BlockValidationState &state, CBlockIndex *pindexNew, const std::shared_ptr &pblock, ConnectTrace &connectTrace, DisconnectedBlockTransactions &disconnectpool) - EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::g_mempool.cs); + EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool.cs); void InvalidBlockFound(CBlockIndex *pindex, const BlockValidationState &state) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -1105,10 +1108,13 @@ //! Instantiate a new chainstate and assign it based upon whether it is //! from a snapshot. //! + //! @param[in] mempool The mempool to pass to the chainstate + // constructor //! @param[in] snapshot_blockhash If given, signify that this chainstate //! is based on a snapshot. CChainState & - InitializeChainstate(const BlockHash &snapshot_blockhash = BlockHash()) + InitializeChainstate(CTxMemPool &mempool, + const BlockHash &snapshot_blockhash = BlockHash()) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); //! Get all chainstates currently being used. diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -881,10 +881,10 @@ m_cacheview = std::make_unique(&m_catcherview); } -CChainState::CChainState(BlockManager &blockman, +CChainState::CChainState(CTxMemPool &mempool, BlockManager &blockman, BlockHash from_snapshot_blockhash) - : m_blockman(blockman), m_from_snapshot_blockhash(from_snapshot_blockhash) { -} + : m_blockman(blockman), m_mempool(mempool), + m_from_snapshot_blockhash(from_snapshot_blockhash) {} void CChainState::InitCoinsDB(size_t cache_size_bytes, bool in_memory, bool should_wipe, std::string leveldb_name) { @@ -2128,7 +2128,7 @@ bool fFlushForPrune = false; bool fDoFullFlush = false; CoinsCacheSizeState cache_state = - GetCoinsCacheSizeState(&::g_mempool); + GetCoinsCacheSizeState(&m_mempool); LOCK(cs_LastBlockFile); if (fPruneMode && (fCheckForPruning || nManualPruneHeight > 0) && !fReindex) { @@ -2292,10 +2292,11 @@ } /** Check warning conditions and do some notifications on new chain tip set. */ -static void UpdateTip(const CChainParams ¶ms, CBlockIndex *pindexNew) +static void UpdateTip(CTxMemPool &mempool, const CChainParams ¶ms, + CBlockIndex *pindexNew) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { // New best block - g_mempool.AddTransactionsUpdated(1); + mempool.AddTransactionsUpdated(1); { LOCK(g_best_block_mutex); @@ -2331,6 +2332,7 @@ BlockValidationState &state, DisconnectedBlockTransactions *disconnectpool) { AssertLockHeld(cs_main); + AssertLockHeld(m_mempool.cs); CBlockIndex *pindexDelete = m_chain.Tip(); const Consensus::Params &consensusParams = params.GetConsensus(); @@ -2375,13 +2377,13 @@ LogPrint(BCLog::MEMPOOL, "Disconnecting mempool due to rewind of upgrade block\n"); if (disconnectpool) { - disconnectpool->importMempool(g_mempool); + disconnectpool->importMempool(m_mempool); } - g_mempool.clear(); + m_mempool.clear(); } if (disconnectpool) { - disconnectpool->addForBlock(block.vtx, g_mempool); + disconnectpool->addForBlock(block.vtx, m_mempool); } // If the tip is finalized, then undo it. @@ -2392,7 +2394,7 @@ m_chain.SetTip(pindexDelete->pprev); // Update ::ChainActive() and related variables. - UpdateTip(params, pindexDelete->pprev); + UpdateTip(m_mempool, params, pindexDelete->pprev); // Let wallets know transactions went from 1-confirmed to // 0-confirmed or conflicted: GetMainSignals().BlockDisconnected(pblock, pindexDelete); @@ -2539,7 +2541,7 @@ ConnectTrace &connectTrace, DisconnectedBlockTransactions &disconnectpool) { AssertLockHeld(cs_main); - AssertLockHeld(g_mempool.cs); + AssertLockHeld(m_mempool.cs); const CChainParams ¶ms = config.GetChainParams(); const Consensus::Params &consensusParams = params.GetConsensus(); @@ -2620,7 +2622,7 @@ nTimeChainState * MILLI / nBlocksTotal); // Remove conflicting transactions from the mempool.; - g_mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight); + m_mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight); disconnectpool.removeForBlock(blockConnecting.vtx); // If this block is activating a fork, we move all mempool transactions @@ -2631,12 +2633,12 @@ GetNextBlockScriptFlags(consensusParams, pindexNew->pprev)) { LogPrint(BCLog::MEMPOOL, "Disconnecting mempool due to acceptance of upgrade block\n"); - disconnectpool.importMempool(g_mempool); + disconnectpool.importMempool(m_mempool); } // Update m_chain & related variables. m_chain.SetTip(pindexNew); - UpdateTip(params, pindexNew); + UpdateTip(m_mempool, params, pindexNew); int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; @@ -2849,6 +2851,7 @@ CBlockIndex *pindexMostWork, const std::shared_ptr &pblock, bool &fInvalidFound, ConnectTrace &connectTrace) { AssertLockHeld(cs_main); + AssertLockHeld(m_mempool.cs); const CBlockIndex *pindexOldTip = m_chain.Tip(); const CBlockIndex *pindexFork = m_chain.FindFork(pindexMostWork); @@ -2860,7 +2863,7 @@ if (!DisconnectTip(config.GetChainParams(), state, &disconnectpool)) { // This is likely a fatal error, but keep the mempool consistent, // just in case. Only remove from the mempool in this case. - disconnectpool.updateMempoolForReorg(config, false, g_mempool); + disconnectpool.updateMempoolForReorg(config, false, m_mempool); // If we're unable to disconnect a block during normal operation, // then that is a failure of our local system -- we should abort @@ -2913,7 +2916,7 @@ // A system error occurred (disk space, database error, ...). // Make the mempool consistent with the current tip, just in // case any observers try to use it before shutdown. - disconnectpool.updateMempoolForReorg(config, false, g_mempool); + disconnectpool.updateMempoolForReorg(config, false, m_mempool); return false; } else { PruneBlockIndexCandidates(); @@ -2935,10 +2938,10 @@ // effect. LogPrint(BCLog::MEMPOOL, "Updating mempool due to reorganization or " "rules upgrade/downgrade\n"); - disconnectpool.updateMempoolForReorg(config, true, g_mempool); + disconnectpool.updateMempoolForReorg(config, true, m_mempool); } - g_mempool.check(&CoinsTip()); + m_mempool.check(&CoinsTip()); // Callbacks/notifications for a new best chain. if (fInvalidFound) { @@ -3025,9 +3028,10 @@ LimitValidationInterfaceQueue(); { + LOCK(cs_main); // Lock transaction pool for at least as long as it takes for // connectTrace to be consumed - LOCK2(cs_main, ::g_mempool.cs); + LOCK(m_mempool.cs); CBlockIndex *starting_tip = m_chain.Tip(); bool blocks_connected = false; do { @@ -3234,7 +3238,7 @@ // Lock for as long as disconnectpool is in scope to make sure // UpdateMempoolForReorg is called after DisconnectTip without unlocking // in between - LOCK(::g_mempool.cs); + LOCK(m_mempool.cs); if (!m_chain.Contains(pindex)) { break; @@ -3257,7 +3261,7 @@ // keeping the mempool up to date is probably futile anyway). disconnectpool.updateMempoolForReorg( config, /* fAddToMempool = */ (++disconnected <= 10) && ret, - ::g_mempool); + m_mempool); if (!ret) { return false; @@ -6067,7 +6071,8 @@ } CChainState & -ChainstateManager::InitializeChainstate(const BlockHash &snapshot_blockhash) { +ChainstateManager::InitializeChainstate(CTxMemPool &mempool, + const BlockHash &snapshot_blockhash) { bool is_snapshot = !snapshot_blockhash.IsNull(); std::unique_ptr &to_modify = is_snapshot ? m_snapshot_chainstate : m_ibd_chainstate; @@ -6075,8 +6080,7 @@ if (to_modify) { throw std::logic_error("should not be overwriting a chainstate"); } - - to_modify.reset(new CChainState(m_blockman, snapshot_blockhash)); + to_modify.reset(new CChainState(mempool, m_blockman, snapshot_blockhash)); // Snapshot chainstates and initial IBD chaintates always become active. if (is_snapshot || (!is_snapshot && !m_active_chainstate)) {