Skip to content

Commit f92dc65

Browse files
committed
validation: Guard the active_chainstate with cs_main
This avoids a potential race-condition where a thread is reading the ChainstateManager::m_active_chainstate pointer while another one is writing to it. There is no portable guarantee that reading/writing the pointer is thread-safe. This is also done in way that mimics ::ChainstateActive(), so the transition from that function to this method is easy. More discussion: 1. #20749 (comment) 2. #19806 (comment) 3. #19806 (comment) 4. #19806 (comment)
1 parent e130ff3 commit f92dc65

File tree

2 files changed

+8
-3
lines changed

2 files changed

+8
-3
lines changed

src/validation.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5143,6 +5143,7 @@ double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex *pin
51435143
}
51445144

51455145
Optional<uint256> ChainstateManager::SnapshotBlockhash() const {
5146+
LOCK(::cs_main); // for m_active_chainstate access
51465147
if (m_active_chainstate != nullptr) {
51475148
// If a snapshot chainstate exists, it will always be our active.
51485149
return m_active_chainstate->m_from_snapshot_blockhash;
@@ -5189,13 +5190,14 @@ CChainState& ChainstateManager::InitializeChainstate(CTxMemPool& mempool, const
51895190

51905191
CChainState& ChainstateManager::ActiveChainstate() const
51915192
{
5193+
LOCK(::cs_main);
51925194
assert(m_active_chainstate);
51935195
return *m_active_chainstate;
51945196
}
51955197

51965198
bool ChainstateManager::IsSnapshotActive() const
51975199
{
5198-
return m_snapshot_chainstate && m_active_chainstate == m_snapshot_chainstate.get();
5200+
return m_snapshot_chainstate && WITH_LOCK(::cs_main, return m_active_chainstate) == m_snapshot_chainstate.get();
51995201
}
52005202

52015203
CChainState& ChainstateManager::ValidatedChainstate() const
@@ -5226,7 +5228,10 @@ void ChainstateManager::Reset()
52265228
{
52275229
m_ibd_chainstate.reset();
52285230
m_snapshot_chainstate.reset();
5229-
m_active_chainstate = nullptr;
5231+
{
5232+
LOCK(::cs_main);
5233+
m_active_chainstate = nullptr;
5234+
}
52305235
m_snapshot_validated = false;
52315236
}
52325237

src/validation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,7 @@ class ChainstateManager
817817
//! This is especially important when, e.g., calling ActivateBestChain()
818818
//! on all chainstates because we are not able to hold ::cs_main going into
819819
//! that call.
820-
CChainState* m_active_chainstate{nullptr};
820+
CChainState* m_active_chainstate GUARDED_BY(::cs_main) {nullptr};
821821

822822
//! If true, the assumed-valid chainstate has been fully validated
823823
//! by the background validation chainstate.

0 commit comments

Comments
 (0)