Merge bitcoin/bitcoin#24177: validation, refactor: add missing thread safety lock assertions

f485a07454 Add missing thread safety lock assertions in validation.h (Jon Atack)
37af8a20cf Add missing thread safety lock assertions in validation.cpp (Jon Atack)

Pull request description:

  A number of functions in validation.{h,cpp} have a thread safety lock annotation in the declaration but are missing the corresponding run-time lock assertion in the definition.

ACKs for top commit:
  hebasto:
    re-ACK f485a07454, only suggested change since my [previous](https://github.com/bitcoin/bitcoin/pull/24177#pullrequestreview-877810465) review.
  vasild:
    ACK f485a07454

Tree-SHA512: c86c0c0e8fe6ec7ae9ed9890f1dd7d042aa482ecf99feb6679a670aa004f6e9a99f7bc047205a34968fab7f1f841898c59b48c3ed6245c166e3b5abbf0867445
This commit is contained in:
MarcoFalke 2022-02-17 08:01:45 +01:00
commit 03c8c6937e
No known key found for this signature in database
GPG key ID: CE2B75697E69A548
2 changed files with 54 additions and 11 deletions

View file

@ -286,8 +286,10 @@ bool CheckSequenceLocks(CBlockIndex* tip,
static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& chainparams); static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& chainparams);
static void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache, size_t limit, std::chrono::seconds age) static void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache, size_t limit, std::chrono::seconds age)
EXCLUSIVE_LOCKS_REQUIRED(pool.cs, ::cs_main) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs)
{ {
AssertLockHeld(::cs_main);
AssertLockHeld(pool.cs);
int expired = pool.Expire(GetTime<std::chrono::seconds>() - age); int expired = pool.Expire(GetTime<std::chrono::seconds>() - age);
if (expired != 0) { if (expired != 0) {
LogPrint(BCLog::MEMPOOL, "Expired %i transactions from the memory pool\n", expired); LogPrint(BCLog::MEMPOOL, "Expired %i transactions from the memory pool\n", expired);
@ -628,8 +630,10 @@ private:
EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs); EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
// Compare a package's feerate against minimum allowed. // Compare a package's feerate against minimum allowed.
bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs) bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_pool.cs)
{ {
AssertLockHeld(::cs_main);
AssertLockHeld(m_pool.cs);
CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size); CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size);
if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) { if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) {
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee)); return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee));
@ -663,6 +667,8 @@ private:
bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
{ {
AssertLockHeld(cs_main);
AssertLockHeld(m_pool.cs);
const CTransactionRef& ptx = ws.m_ptx; const CTransactionRef& ptx = ws.m_ptx;
const CTransaction& tx = *ws.m_ptx; const CTransaction& tx = *ws.m_ptx;
const uint256& hash = ws.m_hash; const uint256& hash = ws.m_hash;
@ -963,6 +969,8 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn
bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws) bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws)
{ {
AssertLockHeld(cs_main);
AssertLockHeld(m_pool.cs);
const CTransaction& tx = *ws.m_ptx; const CTransaction& tx = *ws.m_ptx;
TxValidationState& state = ws.m_state; TxValidationState& state = ws.m_state;
@ -989,6 +997,8 @@ bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws)
bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws) bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws)
{ {
AssertLockHeld(cs_main);
AssertLockHeld(m_pool.cs);
const CTransaction& tx = *ws.m_ptx; const CTransaction& tx = *ws.m_ptx;
const uint256& hash = ws.m_hash; const uint256& hash = ws.m_hash;
TxValidationState& state = ws.m_state; TxValidationState& state = ws.m_state;
@ -1021,6 +1031,8 @@ bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws)
bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws) bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
{ {
AssertLockHeld(cs_main);
AssertLockHeld(m_pool.cs);
const CTransaction& tx = *ws.m_ptx; const CTransaction& tx = *ws.m_ptx;
const uint256& hash = ws.m_hash; const uint256& hash = ws.m_hash;
TxValidationState& state = ws.m_state; TxValidationState& state = ws.m_state;
@ -1342,8 +1354,9 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package,
MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, const CTransactionRef& tx, MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, const CTransactionRef& tx,
int64_t accept_time, bool bypass_limits, bool test_accept) int64_t accept_time, bool bypass_limits, bool test_accept)
EXCLUSIVE_LOCKS_REQUIRED(cs_main) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{ {
AssertLockHeld(::cs_main);
const CChainParams& chainparams{active_chainstate.m_params}; const CChainParams& chainparams{active_chainstate.m_params};
assert(active_chainstate.GetMempool() != nullptr); assert(active_chainstate.GetMempool() != nullptr);
CTxMemPool& pool{*active_chainstate.GetMempool()}; CTxMemPool& pool{*active_chainstate.GetMempool()};
@ -1421,6 +1434,7 @@ CoinsViews::CoinsViews(
void CoinsViews::InitCache() void CoinsViews::InitCache()
{ {
AssertLockHeld(::cs_main);
m_cacheview = std::make_unique<CCoinsViewCache>(&m_catcherview); m_cacheview = std::make_unique<CCoinsViewCache>(&m_catcherview);
} }
@ -1451,6 +1465,7 @@ void CChainState::InitCoinsDB(
void CChainState::InitCoinsCache(size_t cache_size_bytes) void CChainState::InitCoinsCache(size_t cache_size_bytes)
{ {
AssertLockHeld(::cs_main);
assert(m_coins_views != nullptr); assert(m_coins_views != nullptr);
m_coinstip_cache_size_bytes = cache_size_bytes; m_coinstip_cache_size_bytes = cache_size_bytes;
m_coins_views->InitCache(); m_coins_views->InitCache();
@ -1524,6 +1539,7 @@ void CChainState::CheckForkWarningConditions()
// Called both upon regular invalid block discovery *and* InvalidateBlock // Called both upon regular invalid block discovery *and* InvalidateBlock
void CChainState::InvalidChainFound(CBlockIndex* pindexNew) void CChainState::InvalidChainFound(CBlockIndex* pindexNew)
{ {
AssertLockHeld(cs_main);
if (!m_chainman.m_best_invalid || pindexNew->nChainWork > m_chainman.m_best_invalid->nChainWork) { if (!m_chainman.m_best_invalid || pindexNew->nChainWork > m_chainman.m_best_invalid->nChainWork) {
m_chainman.m_best_invalid = pindexNew; m_chainman.m_best_invalid = pindexNew;
} }
@ -1546,6 +1562,7 @@ void CChainState::InvalidChainFound(CBlockIndex* pindexNew)
// which does its own setBlockIndexCandidates management. // which does its own setBlockIndexCandidates management.
void CChainState::InvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state) void CChainState::InvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state)
{ {
AssertLockHeld(cs_main);
if (state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { if (state.GetResult() != BlockValidationResult::BLOCK_MUTATED) {
pindex->nStatus |= BLOCK_FAILED_VALID; pindex->nStatus |= BLOCK_FAILED_VALID;
m_chainman.m_failed_blocks.insert(pindex); m_chainman.m_failed_blocks.insert(pindex);
@ -2210,6 +2227,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
CoinsCacheSizeState CChainState::GetCoinsCacheSizeState() CoinsCacheSizeState CChainState::GetCoinsCacheSizeState()
{ {
AssertLockHeld(::cs_main);
return this->GetCoinsCacheSizeState( return this->GetCoinsCacheSizeState(
m_coinstip_cache_size_bytes, m_coinstip_cache_size_bytes,
gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000); gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
@ -2219,6 +2237,7 @@ CoinsCacheSizeState CChainState::GetCoinsCacheSizeState(
size_t max_coins_cache_size_bytes, size_t max_coins_cache_size_bytes,
size_t max_mempool_size_bytes) size_t max_mempool_size_bytes)
{ {
AssertLockHeld(::cs_main);
const int64_t nMempoolUsage = m_mempool ? m_mempool->DynamicMemoryUsage() : 0; const int64_t nMempoolUsage = m_mempool ? m_mempool->DynamicMemoryUsage() : 0;
int64_t cacheSize = CoinsTip().DynamicMemoryUsage(); int64_t cacheSize = CoinsTip().DynamicMemoryUsage();
int64_t nTotalSpace = int64_t nTotalSpace =
@ -2427,6 +2446,7 @@ static void UpdateTipLog(
void CChainState::UpdateTip(const CBlockIndex* pindexNew) void CChainState::UpdateTip(const CBlockIndex* pindexNew)
{ {
AssertLockHeld(::cs_main);
const auto& coins_tip = this->CoinsTip(); const auto& coins_tip = this->CoinsTip();
// The remainder of the function isn't relevant if we are not acting on // The remainder of the function isn't relevant if we are not acting on
@ -2650,7 +2670,9 @@ bool CChainState::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew
* Return the tip of the chain with the most work in it, that isn't * Return the tip of the chain with the most work in it, that isn't
* known to be invalid (it's however far from certain to be valid). * known to be invalid (it's however far from certain to be valid).
*/ */
CBlockIndex* CChainState::FindMostWorkChain() { CBlockIndex* CChainState::FindMostWorkChain()
{
AssertLockHeld(::cs_main);
do { do {
CBlockIndex *pindexNew = nullptr; CBlockIndex *pindexNew = nullptr;
@ -2854,7 +2876,7 @@ bool CChainState::ActivateBestChain(BlockValidationState& state, std::shared_ptr
// far from a guarantee. Things in the P2P/RPC will often end up calling // far from a guarantee. Things in the P2P/RPC will often end up calling
// us in the middle of ProcessNewBlock - do not assume pblock is set // us in the middle of ProcessNewBlock - do not assume pblock is set
// sanely for performance or correctness! // sanely for performance or correctness!
AssertLockNotHeld(cs_main); AssertLockNotHeld(::cs_main);
// ABC maintains a fair degree of expensive-to-calculate internal state // ABC maintains a fair degree of expensive-to-calculate internal state
// because this function periodically releases cs_main so that it does not lock up other threads for too long // because this function periodically releases cs_main so that it does not lock up other threads for too long
@ -2950,6 +2972,8 @@ bool CChainState::ActivateBestChain(BlockValidationState& state, std::shared_ptr
bool CChainState::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex) bool CChainState::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex)
{ {
AssertLockNotHeld(m_chainstate_mutex);
AssertLockNotHeld(::cs_main);
{ {
LOCK(cs_main); LOCK(cs_main);
if (pindex->nChainWork < m_chain.Tip()->nChainWork) { if (pindex->nChainWork < m_chain.Tip()->nChainWork) {
@ -2980,6 +3004,7 @@ bool CChainState::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex
bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pindex) bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pindex)
{ {
AssertLockNotHeld(m_chainstate_mutex); AssertLockNotHeld(m_chainstate_mutex);
AssertLockNotHeld(::cs_main);
// Genesis block can't be invalidated // Genesis block can't be invalidated
assert(pindex); assert(pindex);
@ -3158,6 +3183,7 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */ /** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */
void CChainState::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos) void CChainState::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos)
{ {
AssertLockHeld(cs_main);
pindexNew->nTx = block.vtx.size(); pindexNew->nTx = block.vtx.size();
pindexNew->nChainTx = 0; pindexNew->nChainTx = 0;
pindexNew->nFile = pos.nFile; pindexNew->nFile = pos.nFile;
@ -3330,8 +3356,9 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
* in ConnectBlock(). * in ConnectBlock().
* Note that -reindex-chainstate skips the validation that happens here! * Note that -reindex-chainstate skips the validation that happens here!
*/ */
static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, BlockManager& blockman, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(cs_main) static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, BlockManager& blockman, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{ {
AssertLockHeld(::cs_main);
assert(pindexPrev != nullptr); assert(pindexPrev != nullptr);
const int nHeight = pindexPrev->nHeight + 1; const int nHeight = pindexPrev->nHeight + 1;
@ -3702,6 +3729,7 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s
MempoolAcceptResult ChainstateManager::ProcessTransaction(const CTransactionRef& tx, bool test_accept) MempoolAcceptResult ChainstateManager::ProcessTransaction(const CTransactionRef& tx, bool test_accept)
{ {
AssertLockHeld(cs_main);
CChainState& active_chainstate = ActiveChainstate(); CChainState& active_chainstate = ActiveChainstate();
if (!active_chainstate.GetMempool()) { if (!active_chainstate.GetMempool()) {
TxValidationState state; TxValidationState state;
@ -3915,6 +3943,7 @@ bool CVerifyDB::VerifyDB(
/** Apply the effects of a block on the utxo cache, ignoring that it may already have been applied. */ /** Apply the effects of a block on the utxo cache, ignoring that it may already have been applied. */
bool CChainState::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs) bool CChainState::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs)
{ {
AssertLockHeld(cs_main);
// TODO: merge with ConnectBlock // TODO: merge with ConnectBlock
CBlock block; CBlock block;
if (!ReadBlockFromDisk(block, pindex, m_params.GetConsensus())) { if (!ReadBlockFromDisk(block, pindex, m_params.GetConsensus())) {
@ -4018,7 +4047,9 @@ bool CChainState::NeedsRedownload() const
return false; return false;
} }
void CChainState::UnloadBlockIndex() { void CChainState::UnloadBlockIndex()
{
AssertLockHeld(::cs_main);
nBlockSequenceId = 1; nBlockSequenceId = 1;
setBlockIndexCandidates.clear(); setBlockIndexCandidates.clear();
} }
@ -4090,6 +4121,7 @@ bool CChainState::LoadGenesisBlock()
void CChainState::LoadExternalBlockFile(FILE* fileIn, FlatFilePos* dbp) void CChainState::LoadExternalBlockFile(FILE* fileIn, FlatFilePos* dbp)
{ {
AssertLockNotHeld(m_chainstate_mutex);
// Map of disk positions for blocks with unknown parent (only used for reindex) // Map of disk positions for blocks with unknown parent (only used for reindex)
static std::multimap<uint256, FlatFilePos> mapBlocksUnknownParent; static std::multimap<uint256, FlatFilePos> mapBlocksUnknownParent;
int64_t nStart = GetTimeMillis(); int64_t nStart = GetTimeMillis();
@ -4430,6 +4462,7 @@ void CChainState::CheckBlockIndex()
std::string CChainState::ToString() std::string CChainState::ToString()
{ {
AssertLockHeld(::cs_main);
CBlockIndex* tip = m_chain.Tip(); CBlockIndex* tip = m_chain.Tip();
return strprintf("Chainstate [%s] @ height %d (%s)", return strprintf("Chainstate [%s] @ height %d (%s)",
m_from_snapshot_blockhash ? "snapshot" : "ibd", m_from_snapshot_blockhash ? "snapshot" : "ibd",
@ -4438,6 +4471,7 @@ std::string CChainState::ToString()
bool CChainState::ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size) bool CChainState::ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size)
{ {
AssertLockHeld(::cs_main);
if (coinstip_size == m_coinstip_cache_size_bytes && if (coinstip_size == m_coinstip_cache_size_bytes &&
coinsdb_size == m_coinsdb_cache_size_bytes) { coinsdb_size == m_coinsdb_cache_size_bytes) {
// Cache sizes are unchanged, no need to continue. // Cache sizes are unchanged, no need to continue.
@ -4662,6 +4696,7 @@ std::vector<CChainState*> ChainstateManager::GetAll()
CChainState& ChainstateManager::InitializeChainstate( CChainState& ChainstateManager::InitializeChainstate(
CTxMemPool* mempool, const std::optional<uint256>& snapshot_blockhash) CTxMemPool* mempool, const std::optional<uint256>& snapshot_blockhash)
{ {
AssertLockHeld(::cs_main);
bool is_snapshot = snapshot_blockhash.has_value(); bool is_snapshot = snapshot_blockhash.has_value();
std::unique_ptr<CChainState>& to_modify = std::unique_ptr<CChainState>& to_modify =
is_snapshot ? m_snapshot_chainstate : m_ibd_chainstate; is_snapshot ? m_snapshot_chainstate : m_ibd_chainstate;
@ -4999,6 +5034,7 @@ bool ChainstateManager::IsSnapshotActive() const
void ChainstateManager::Unload() void ChainstateManager::Unload()
{ {
AssertLockHeld(::cs_main);
for (CChainState* chainstate : this->GetAll()) { for (CChainState* chainstate : this->GetAll()) {
chainstate->m_chain.SetTip(nullptr); chainstate->m_chain.SetTip(nullptr);
chainstate->UnloadBlockIndex(); chainstate->UnloadBlockIndex();
@ -5020,6 +5056,7 @@ void ChainstateManager::Reset()
void ChainstateManager::MaybeRebalanceCaches() void ChainstateManager::MaybeRebalanceCaches()
{ {
AssertLockHeld(::cs_main);
if (m_ibd_chainstate && !m_snapshot_chainstate) { if (m_ibd_chainstate && !m_snapshot_chainstate) {
LogPrintf("[snapshot] allocating all cache to the IBD chainstate\n"); LogPrintf("[snapshot] allocating all cache to the IBD chainstate\n");
// Allocate everything to the IBD chainstate. // Allocate everything to the IBD chainstate.

View file

@ -529,7 +529,9 @@ public:
//! @returns whether or not the CoinsViews object has been fully initialized and we can //! @returns whether or not the CoinsViews object has been fully initialized and we can
//! safely flush this object to disk. //! safely flush this object to disk.
bool CanFlushToDisk() const EXCLUSIVE_LOCKS_REQUIRED(cs_main) { bool CanFlushToDisk() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
AssertLockHeld(::cs_main);
return m_coins_views && m_coins_views->m_cacheview; return m_coins_views && m_coins_views->m_cacheview;
} }
@ -557,15 +559,17 @@ public:
std::set<CBlockIndex*, node::CBlockIndexWorkComparator> setBlockIndexCandidates; std::set<CBlockIndex*, node::CBlockIndexWorkComparator> setBlockIndexCandidates;
//! @returns A reference to the in-memory cache of the UTXO set. //! @returns A reference to the in-memory cache of the UTXO set.
CCoinsViewCache& CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(cs_main) CCoinsViewCache& CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{ {
AssertLockHeld(::cs_main);
assert(m_coins_views->m_cacheview); assert(m_coins_views->m_cacheview);
return *m_coins_views->m_cacheview.get(); return *m_coins_views->m_cacheview.get();
} }
//! @returns A reference to the on-disk UTXO set database. //! @returns A reference to the on-disk UTXO set database.
CCoinsViewDB& CoinsDB() EXCLUSIVE_LOCKS_REQUIRED(cs_main) CCoinsViewDB& CoinsDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{ {
AssertLockHeld(::cs_main);
return m_coins_views->m_dbview; return m_coins_views->m_dbview;
} }
@ -577,8 +581,9 @@ public:
//! @returns A reference to a wrapped view of the in-memory UTXO set that //! @returns A reference to a wrapped view of the in-memory UTXO set that
//! handles disk read errors gracefully. //! handles disk read errors gracefully.
CCoinsViewErrorCatcher& CoinsErrorCatcher() EXCLUSIVE_LOCKS_REQUIRED(cs_main) CCoinsViewErrorCatcher& CoinsErrorCatcher() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{ {
AssertLockHeld(::cs_main);
return m_coins_views->m_catcherview; return m_coins_views->m_catcherview;
} }
@ -924,6 +929,7 @@ public:
node::BlockMap& BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(::cs_main) node::BlockMap& BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{ {
AssertLockHeld(::cs_main);
return m_blockman.m_block_index; return m_blockman.m_block_index;
} }