Skip to content

Commit bb79aaf

Browse files
skeeesMarcoFalke
authored andcommitted
Fix concurrency-related bugs in ActivateBestChain
If multiple threads are invoking ActivateBestChain, it was possible to have them working towards different tips, and we could arrive at a less work tip than we should. Fix this by introducing a ChainState lock which must be held for the entire duration of ActivateBestChain to enforce exclusion in ABC. Github-Pull: #13023 Rebased-From: a3ae8e6
1 parent 0948153 commit bb79aaf

File tree

1 file changed

+13
-0
lines changed

1 file changed

+13
-0
lines changed

src/validation.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,12 @@ class CChainState {
144144
*/
145145
std::set<CBlockIndex*> g_failed_blocks;
146146

147+
/**
148+
* the ChainState CriticalSection
149+
* A lock that must be held when modifying this ChainState - held in ActivateBestChain()
150+
*/
151+
CCriticalSection m_cs_chainstate;
152+
147153
public:
148154
CChain chainActive;
149155
BlockMap mapBlockIndex;
@@ -2451,6 +2457,7 @@ void CChainState::PruneBlockIndexCandidates() {
24512457
bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
24522458
{
24532459
AssertLockHeld(cs_main);
2460+
24542461
const CBlockIndex *pindexOldTip = chainActive.Tip();
24552462
const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
24562463

@@ -2562,6 +2569,12 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
25622569
// sanely for performance or correctness!
25632570
AssertLockNotHeld(cs_main);
25642571

2572+
// ABC maintains a fair degree of expensive-to-calculate internal state
2573+
// because this function periodically releases cs_main so that it does not lock up other threads for too long
2574+
// during large connects - and to allow for e.g. the callback queue to drain
2575+
// we use m_cs_chainstate to enforce mutual exclusion so that only one caller may execute this function at a time
2576+
LOCK(m_cs_chainstate);
2577+
25652578
CBlockIndex *pindexMostWork = nullptr;
25662579
CBlockIndex *pindexNewTip = nullptr;
25672580
int nStopAtHeight = gArgs.GetArg("-stopatheight", DEFAULT_STOPATHEIGHT);

0 commit comments

Comments
 (0)