Allow ActivateBestChain to release its lock on cs_main

pull/4148/head
Pieter Wuille 11 years ago
parent 77339e5aec
commit 4e0eed88ac

@ -2079,47 +2079,43 @@ static CBlockIndex* FindMostWorkChain() {
} while(true); } while(true);
} }
// Try to activate to the most-work chain (thereby connecting it). // Try to make some progress towards making pindexMostWork the active block.
bool ActivateBestChain(CValidationState &state) { static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork) {
LOCK(cs_main); AssertLockHeld(cs_main);
CBlockIndex *pindexOldTip = chainActive.Tip(); CBlockIndex *pindexOldTip = chainActive.Tip();
bool fComplete = false; CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
while (!fComplete) {
CBlockIndex *pindexMostWork = FindMostWorkChain();
CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
fComplete = true;
// Check whether we have something to do.
if (pindexMostWork == NULL) break;
// Disconnect active blocks which are no longer in the best chain. // Disconnect active blocks which are no longer in the best chain.
while (chainActive.Tip() && chainActive.Tip() != pindexFork) { while (chainActive.Tip() && chainActive.Tip() != pindexFork) {
if (!DisconnectTip(state)) if (!DisconnectTip(state))
return false; return false;
} }
// Build list of new blocks to connect. // Build list of new blocks to connect.
std::vector<CBlockIndex*> vpindexToConnect; std::vector<CBlockIndex*> vpindexToConnect;
vpindexToConnect.reserve(pindexMostWork->nHeight - (pindexFork ? pindexFork->nHeight : -1)); vpindexToConnect.reserve(pindexMostWork->nHeight - (pindexFork ? pindexFork->nHeight : -1));
while (pindexMostWork && pindexMostWork != pindexFork) { while (pindexMostWork && pindexMostWork != pindexFork) {
vpindexToConnect.push_back(pindexMostWork); vpindexToConnect.push_back(pindexMostWork);
pindexMostWork = pindexMostWork->pprev; pindexMostWork = pindexMostWork->pprev;
} }
// Connect new blocks. // Connect new blocks.
BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) {
if (!ConnectTip(state, pindexConnect)) { if (!ConnectTip(state, pindexConnect)) {
if (state.IsInvalid()) { if (state.IsInvalid()) {
// The block violates a consensus rule. // The block violates a consensus rule.
if (!state.CorruptionPossible()) if (!state.CorruptionPossible())
InvalidChainFound(vpindexToConnect.back()); InvalidChainFound(vpindexToConnect.back());
fComplete = false; state = CValidationState();
state = CValidationState(); break;
break; } else {
} else { // A system error occurred (disk space, database error, ...).
// A system error occurred (disk space, database error, ...). return false;
return false; }
} } else {
if (!pindexOldTip || chainActive.Tip()->nChainWork > pindexOldTip->nChainWork) {
// We're in a better position than we were. Return temporarily to release the lock.
break;
} }
} }
} }
@ -2136,6 +2132,28 @@ bool ActivateBestChain(CValidationState &state) {
return true; return true;
} }
bool ActivateBestChain(CValidationState &state) {
do {
boost::this_thread::interruption_point();
LOCK(cs_main);
// Check whether we're done (this could be avoided after the first run,
// but that's not worth optimizing.
CBlockIndex *pindexMostWork = FindMostWorkChain();
if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip())
return true;
if (!ActivateBestChainStep(state, pindexMostWork))
return false;
// Check whether we're done now.
if (pindexMostWork == chainActive.Tip())
return true;
} while(true);
return true;
}
CBlockIndex* AddToBlockIndex(CBlockHeader& block) CBlockIndex* AddToBlockIndex(CBlockHeader& block)
{ {

Loading…
Cancel
Save