From 4e0eed88acdd41826868c151373068bfad18b84d Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 6 May 2014 01:23:13 +0200 Subject: [PATCH] Allow ActivateBestChain to release its lock on cs_main --- src/main.cpp | 92 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 37 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 806f1c20db2..860487dece8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2079,47 +2079,43 @@ static CBlockIndex* FindMostWorkChain() { } while(true); } -// Try to activate to the most-work chain (thereby connecting it). -bool ActivateBestChain(CValidationState &state) { - LOCK(cs_main); +// Try to make some progress towards making pindexMostWork the active block. +static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork) { + AssertLockHeld(cs_main); CBlockIndex *pindexOldTip = chainActive.Tip(); - bool fComplete = false; - while (!fComplete) { - CBlockIndex *pindexMostWork = FindMostWorkChain(); - CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork); - fComplete = true; - - // Check whether we have something to do. - if (pindexMostWork == NULL) break; + CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork); - // Disconnect active blocks which are no longer in the best chain. - while (chainActive.Tip() && chainActive.Tip() != pindexFork) { - if (!DisconnectTip(state)) - return false; - } + // Disconnect active blocks which are no longer in the best chain. + while (chainActive.Tip() && chainActive.Tip() != pindexFork) { + if (!DisconnectTip(state)) + return false; + } - // Build list of new blocks to connect. - std::vector vpindexToConnect; - vpindexToConnect.reserve(pindexMostWork->nHeight - (pindexFork ? pindexFork->nHeight : -1)); - while (pindexMostWork && pindexMostWork != pindexFork) { - vpindexToConnect.push_back(pindexMostWork); - pindexMostWork = pindexMostWork->pprev; - } + // Build list of new blocks to connect. + std::vector vpindexToConnect; + vpindexToConnect.reserve(pindexMostWork->nHeight - (pindexFork ? pindexFork->nHeight : -1)); + while (pindexMostWork && pindexMostWork != pindexFork) { + vpindexToConnect.push_back(pindexMostWork); + pindexMostWork = pindexMostWork->pprev; + } - // Connect new blocks. - BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { - if (!ConnectTip(state, pindexConnect)) { - if (state.IsInvalid()) { - // The block violates a consensus rule. - if (!state.CorruptionPossible()) - InvalidChainFound(vpindexToConnect.back()); - fComplete = false; - state = CValidationState(); - break; - } else { - // A system error occurred (disk space, database error, ...). - return false; - } + // Connect new blocks. + BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { + if (!ConnectTip(state, pindexConnect)) { + if (state.IsInvalid()) { + // The block violates a consensus rule. + if (!state.CorruptionPossible()) + InvalidChainFound(vpindexToConnect.back()); + state = CValidationState(); + break; + } else { + // A system error occurred (disk space, database error, ...). + 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; } +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) {