diff --git a/src/bench/duplicate_inputs.cpp b/src/bench/duplicate_inputs.cpp --- a/src/bench/duplicate_inputs.cpp +++ b/src/bench/duplicate_inputs.cpp @@ -29,6 +29,7 @@ CMutableTransaction coinbaseTx{}; CMutableTransaction naughtyTx{}; + LOCK(cs_main); CBlockIndex *pindexPrev = ::ChainActive().Tip(); assert(pindexPrev != nullptr); block.nBits = diff --git a/src/chain.h b/src/chain.h --- a/src/chain.h +++ b/src/chain.h @@ -266,7 +266,8 @@ typedef std::unordered_map BlockMap; extern BlockMap &mapBlockIndex GUARDED_BY(cs_main); -inline CBlockIndex *LookupBlockIndex(const BlockHash &hash) { +inline CBlockIndex *LookupBlockIndex(const BlockHash &hash) + EXCLUSIVE_LOCKS_REQUIRED(cs_main) { AssertLockHeld(cs_main); BlockMap::const_iterator it = mapBlockIndex.find(hash); return it == mapBlockIndex.end() ? nullptr : it->second; diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -23,7 +23,8 @@ return hash == i->second; } -CBlockIndex *GetLastCheckpoint(const CCheckpointData &data) { +CBlockIndex *GetLastCheckpoint(const CCheckpointData &data) + EXCLUSIVE_LOCKS_REQUIRED(cs_main) { const MapCheckpoints &checkpoints = data.mapCheckpoints; for (const MapCheckpoints::value_type &i : reverse_iterate(checkpoints)) { diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -38,6 +38,7 @@ class LockImpl : public Chain::Lock, public UniqueLock { Optional getHeight() override { + LockAnnotation lock(::cs_main); int height = ::ChainActive().Height(); if (height >= 0) { return height; @@ -45,6 +46,7 @@ return nullopt; } Optional getBlockHeight(const BlockHash &hash) override { + LockAnnotation lock(::cs_main); CBlockIndex *block = LookupBlockIndex(hash); if (block && ::ChainActive().Contains(block)) { return block->nHeight; @@ -57,27 +59,32 @@ return tip_height && height ? *tip_height - *height + 1 : 0; } BlockHash getBlockHash(int height) override { + LockAnnotation lock(::cs_main); CBlockIndex *block = ::ChainActive()[height]; assert(block != nullptr); return block->GetBlockHash(); } int64_t getBlockTime(int height) override { + LockAnnotation lock(::cs_main); CBlockIndex *block = ::ChainActive()[height]; assert(block != nullptr); return block->GetBlockTime(); } int64_t getBlockMedianTimePast(int height) override { + LockAnnotation lock(::cs_main); CBlockIndex *block = ::ChainActive()[height]; assert(block != nullptr); return block->GetMedianTimePast(); } bool haveBlockOnDisk(int height) override { + LockAnnotation lock(::cs_main); CBlockIndex *block = ::ChainActive()[height]; return block && (block->nStatus.hasData() != 0) && block->nTx > 0; } Optional findFirstBlockWithTimeAndHeight(int64_t time, int height, BlockHash *hash) override { + LockAnnotation lock(::cs_main); CBlockIndex *block = ::ChainActive().FindEarliestAtLeast(time, height); if (block) { @@ -90,6 +97,7 @@ } Optional findPruned(int start_height, Optional stop_height) override { + LockAnnotation lock(::cs_main); if (::fPruneMode) { CBlockIndex *block = stop_height ? ::ChainActive()[*stop_height] : ::ChainActive().Tip(); @@ -104,6 +112,7 @@ } Optional findFork(const BlockHash &hash, Optional *height) override { + LockAnnotation lock(::cs_main); const CBlockIndex *block = LookupBlockIndex(hash); const CBlockIndex *fork = block ? ::ChainActive().FindFork(block) : nullptr; @@ -120,6 +129,7 @@ return nullopt; } CBlockLocator getTipLocator() override { + LockAnnotation lock(::cs_main); return ::ChainActive().GetLocator(); } Optional findLocatorFork(const CBlockLocator &locator) override { @@ -146,7 +156,7 @@ } using UniqueLock::UniqueLock; - }; + }; // namespace interfaces class NotificationsHandlerImpl : public Handler, CValidationInterface { public: diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -130,6 +130,8 @@ } { auto locked_chain = wallet->chain().lock(); + LockAnnotation lock(::cs_main); + WalletRescanReserver reserver(wallet.get()); reserver.reserve(); CWallet::ScanResult result = wallet->ScanForWalletTransactions( diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -85,7 +85,8 @@ {2, 0xbbbeb305}, {2, 0xfe1c810a}, }; -static CBlockIndex CreateBlockIndex(int nHeight) { +static CBlockIndex CreateBlockIndex(int nHeight) + EXCLUSIVE_LOCKS_REQUIRED(cs_main) { CBlockIndex index; index.nHeight = nHeight; index.pprev = ::ChainActive().Tip(); diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -64,18 +64,27 @@ // Test 1: block with both of those transactions should be rejected. block = CreateAndProcessBlock(spends, scriptPubKey); - BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); + { + LOCK(cs_main); + BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); + } // Test 2: ... and should be rejected if spend1 is in the memory pool BOOST_CHECK(ToMemPool(spends[0])); block = CreateAndProcessBlock(spends, scriptPubKey); - BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); + { + LOCK(cs_main); + BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); + } g_mempool.clear(); // Test 3: ... and should be rejected if spend2 is in the memory pool BOOST_CHECK(ToMemPool(spends[1])); block = CreateAndProcessBlock(spends, scriptPubKey); - BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); + { + LOCK(cs_main); + BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); + } g_mempool.clear(); // Final sanity test: first spend in mempool, second in block, that's OK: @@ -83,7 +92,10 @@ oneSpend.push_back(spends[0]); BOOST_CHECK(ToMemPool(spends[1])); block = CreateAndProcessBlock(oneSpend, scriptPubKey); - BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() == block.GetHash()); + { + LOCK(cs_main); + BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() == block.GetHash()); + } // spends[1] should have been removed from the mempool when the block with // spends[0] is accepted: BOOST_CHECK_EQUAL(g_mempool.size(), 0U); diff --git a/src/test/util.cpp b/src/test/util.cpp --- a/src/test/util.cpp +++ b/src/test/util.cpp @@ -80,6 +80,7 @@ .CreateNewBlock(coinbase_scriptPubKey) ->block); + LOCK(cs_main); block->nTime = ::ChainActive().Tip()->GetMedianTimePast() + 1; block->hashMerkleRoot = BlockMerkleRoot(*block); diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -207,6 +207,7 @@ UnregisterValidationInterface(&sub); + LOCK(cs_main); BOOST_CHECK_EQUAL(sub.m_expected_tip, ::ChainActive().Tip()->GetBlockHash()); } diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3508,11 +3508,11 @@ * in ConnectBlock(). * Note that -reindex-chainstate skips the validation that happens here! */ -static bool ContextualCheckBlockHeader(const CChainParams ¶ms, - const CBlockHeader &block, - CValidationState &state, - const CBlockIndex *pindexPrev, - int64_t nAdjustedTime) { +static bool +ContextualCheckBlockHeader(const CChainParams ¶ms, + const CBlockHeader &block, CValidationState &state, + const CBlockIndex *pindexPrev, int64_t nAdjustedTime) + EXCLUSIVE_LOCKS_REQUIRED(cs_main) { assert(pindexPrev != nullptr); const int nHeight = pindexPrev->nHeight + 1; diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -32,16 +33,15 @@ } BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) { - auto chain = interfaces::MakeChain(); - // Cap last block file size, and mine new block in a new block file. CBlockIndex *oldTip = ::ChainActive().Tip(); GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE; CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); CBlockIndex *newTip = ::ChainActive().Tip(); - LockAnnotation lock(::cs_main); + auto chain = interfaces::MakeChain(); auto locked_chain = chain->lock(); + LockAnnotation lock(::cs_main); // Verify ScanForWalletTransactions accommodates a null start block. { @@ -119,16 +119,15 @@ } BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup) { - auto chain = interfaces::MakeChain(); - // Cap last block file size, and mine new block in a new block file. CBlockIndex *oldTip = ::ChainActive().Tip(); GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE; CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); CBlockIndex *newTip = ::ChainActive().Tip(); - LockAnnotation lock(::cs_main); + auto chain = interfaces::MakeChain(); auto locked_chain = chain->lock(); + LockAnnotation lock(::cs_main); // Prune the older block file. PruneOneBlockFile(oldTip->GetBlockPos().nFile); @@ -189,8 +188,6 @@ // importwallet RPC would start the scan at the latest block with timestamp less // than or equal to key birthday. BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) { - auto chain = interfaces::MakeChain(); - // Create two blocks with same timestamp to verify that importwallet rescan // will pick up both blocks, not just the first. const int64_t BLOCK_TIME = ::ChainActive().Tip()->GetBlockTimeMax() + 5; @@ -213,7 +210,9 @@ GetScriptForRawPubKey(coinbaseKey.GetPubKey())) .vtx[0]); + auto chain = interfaces::MakeChain(); auto locked_chain = chain->lock(); + LockAnnotation lock(::cs_main); std::string backup_file = (GetDataDir() / "wallet.backup").string(); @@ -271,8 +270,11 @@ CWallet wallet(Params(), chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWalletTx wtx(&wallet, m_coinbase_txns.back()); + auto locked_chain = chain->lock(); + LockAnnotation lock(::cs_main); LOCK(wallet.cs_wallet); + wtx.hashBlock = ::ChainActive().Tip()->GetBlockHash(); wtx.nIndex = 0; @@ -406,6 +408,8 @@ } CreateAndProcessBlock({CMutableTransaction(blocktx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); + + LOCK(cs_main); LOCK(wallet->cs_wallet); auto it = wallet->mapWallet.find(tx->GetId()); BOOST_CHECK(it != wallet->mapWallet.end());