src/validation.cpp
/**
 * Make the best chain active, in multiple steps. The result is either failure
 * or an activated best chain. pblock is either nullptr or a pointer to a block
 * that is already loaded (to avoid loading it again from disk).
 *
 * ActivateBestChain is split into steps (see ActivateBestChainStep) so that
 * we avoid holding cs_main for an extended period of time; the length of this
 * call may be quite long during reindexing or a substantial reorg.
 */
Make the best chain active, in multiple steps. The result is either failure
or an activated best chain. pblock is either nullptr or a pointer to a block
that is already loaded (to avoid loading it again from disk).

ActivateBestChain is split into steps  so that
we avoid holding cs_main for an extended period of time; the length of this
call may be quite long during reindexing or a substantial reorg.
Make the best chain active in multiple steps . The result is either failure or an activated best chain . pblock is either nullptr or a pointer to a block that is already loaded ( to avoid loading it again from disk ) . ActivateBestChain is split into steps so that we avoid holding cs_main for an extended period of time ; the length of this call may be quite long during reindexing or a substantial reorg .
bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
    AssertLockNotHeld(cs_main);
    LOCK(m_cs_chainstate);
    CBlockIndex *pindexMostWork = nullptr;
    CBlockIndex *pindexNewTip = nullptr;
    int nStopAtHeight = gArgs.GetArg("-stopatheight", DEFAULT_STOPATHEIGHT);
    do {
        boost::this_thread::interruption_point();
        LimitValidationInterfaceQueue();
        {
            LOCK(cs_main);
            CBlockIndex* starting_tip = chainActive.Tip();
            bool blocks_connected = false;
            do {
                ConnectTrace connectTrace(mempool); 
                if (pindexMostWork == nullptr) {
                    pindexMostWork = FindMostWorkChain();
                }
                if (pindexMostWork == nullptr || pindexMostWork == chainActive.Tip()) {
                    break;
                }
                bool fInvalidFound = false;
                std::shared_ptr<const CBlock> nullBlockPtr;
                if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : nullBlockPtr, fInvalidFound, connectTrace))
                    return false;
                blocks_connected = true;
                if (fInvalidFound) {
                    pindexMostWork = nullptr;
                }
                pindexNewTip = chainActive.Tip();
                for (const PerBlockConnectTrace& trace : connectTrace.GetBlocksConnected()) {
                    assert(trace.pblock && trace.pindex);
                    GetMainSignals().BlockConnected(trace.pblock, trace.pindex, trace.conflictedTxs);
                    for (const CTransactionRef& ptx : *trace.conflictedTxs) {
                        RemoveFromMarkerCache(ptx->GetHash());
                    }
                    for (size_t i = 0; i < trace.pblock->vtx.size(); i++) {
                        RemoveFromMarkerCache(trace.pblock->vtx[i]->GetHash());
                    }
                }
            } while (!chainActive.Tip() || (starting_tip && CBlockIndexWorkComparator()(chainActive.Tip(), starting_tip)));
            if (!blocks_connected) return true;
            const CBlockIndex* pindexFork = chainActive.FindFork(starting_tip);
            bool fInitialDownload = IsInitialBlockDownload();
            if (pindexFork != pindexNewTip) {
                GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
                uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip);
            }
        }
        if (nStopAtHeight && pindexNewTip && pindexNewTip->nHeight >= nStopAtHeight) StartShutdown();
        if (ShutdownRequested())
            break;
    } while (pindexNewTip != pindexMostWork);
    CheckBlockIndex(chainparams.GetConsensus());
    if (!FlushStateToDisk(chainparams, state, FlushStateMode::PERIODIC)) {
        return false;
    }
    return true;
}
bool CChainState :: ActivateBestChain ( CValidationState & state , const CChainParams & chainparams , std :: shared_ptr < const CBlock > pblock ) { AssertLockNotHeld ( cs_main ) ; LOCK ( m_cs_chainstate ) ; CBlockIndex * pindexMostWork = nullptr ; CBlockIndex * pindexNewTip = nullptr ; int nStopAtHeight = gArgs . GetArg ( " " , DEFAULT_STOPATHEIGHT ) ; do { boost :: this_thread :: interruption_point ( ) ; LimitValidationInterfaceQueue ( ) ; { LOCK ( cs_main ) ; CBlockIndex * starting_tip = chainActive . Tip ( ) ; bool blocks_connected = false ; do { ConnectTrace connectTrace ( mempool ) ; if ( pindexMostWork == nullptr ) { pindexMostWork = FindMostWorkChain ( ) ; } if ( pindexMostWork == nullptr || pindexMostWork == chainActive . Tip ( ) ) { break ; } bool fInvalidFound = false ; std :: shared_ptr < const CBlock > nullBlockPtr ; if ( ! ActivateBestChainStep ( state , chainparams , pindexMostWork , pblock && pblock -> GetHash ( ) == pindexMostWork -> GetBlockHash ( ) ? pblock : nullBlockPtr , fInvalidFound , connectTrace ) ) return false ; blocks_connected = true ; if ( fInvalidFound ) { pindexMostWork = nullptr ; } pindexNewTip = chainActive . Tip ( ) ; for ( const PerBlockConnectTrace & trace : connectTrace . GetBlocksConnected ( ) ) { assert ( trace . pblock && trace . pindex ) ; GetMainSignals ( ) . BlockConnected ( trace . pblock , trace . pindex , trace . conflictedTxs ) ; for ( const CTransactionRef & ptx : * trace . conflictedTxs ) { RemoveFromMarkerCache ( ptx -> GetHash ( ) ) ; } for ( size_t i = 0 ; i < trace . pblock -> vtx . size ( ) ; i ++ ) { RemoveFromMarkerCache ( trace . pblock -> vtx [ i ] -> GetHash ( ) ) ; } } } while ( ! chainActive . Tip ( ) || ( starting_tip && CBlockIndexWorkComparator ( ) ( chainActive . Tip ( ) , starting_tip ) ) ) ; if ( ! blocks_connected ) return true ; const CBlockIndex * pindexFork = chainActive . FindFork ( starting_tip ) ; bool fInitialDownload = IsInitialBlockDownload ( ) ; if ( pindexFork != pindexNewTip ) { GetMainSignals ( ) . UpdatedBlockTip ( pindexNewTip , pindexFork , fInitialDownload ) ; uiInterface . NotifyBlockTip ( fInitialDownload , pindexNewTip ) ; } } if ( nStopAtHeight && pindexNewTip && pindexNewTip -> nHeight >= nStopAtHeight ) StartShutdown ( ) ; if ( ShutdownRequested ( ) ) break ; } while ( pindexNewTip != pindexMostWork ) ; CheckBlockIndex ( chainparams . GetConsensus ( ) ) ; if ( ! FlushStateToDisk ( chainparams , state , FlushStateMode :: PERIODIC ) ) { return false ; } return true ; }
Make the best chain active, in multiple steps.
Make the best chain active in multiple steps .
// Note that while we're often called here from ProcessNewBlock, this is // 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 // sanely for performance or correctness! // 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 // during large connects - and to allow for e.g. the callback queue to drain // we use m_cs_chainstate to enforce mutual exclusion so that only one caller may execute this function at a time // Block until the validation queue drains. This should largely // never happen in normal operation, however may happen during // reindex, causing memory blowup if we run too far ahead. // Note that if a validationinterface callback ends up calling // ActivateBestChain this may lead to a deadlock! We should // probably have a DEBUG_LOCKORDER test for this in the future. // We absolutely may not unlock cs_main until we've made forward progress // (with the exception of shutdown due to hardware issues, low disk space, etc). // Destructed before cs_main is unlocked // Whether we have anything to do at all. // Wipe cache, we may need another branch now. // Notify external listeners about the new tip. // Enqueue while holding cs_main to ensure that UpdatedBlockTip is called in the order in which blocks are connected // Notify ValidationInterface subscribers // Always notify the UI if a new block tip was connected // When we reach this point, we switched to a new tip (stored in pindexNewTip). // We check shutdown only after giving ActivateBestChainStep a chance to run once so that we // never shutdown before connecting the genesis block during LoadChainTip(). Previously this // caused an assert() failure during shutdown in such cases as the UTXO DB flushing checks // that the best block hash is non-null. // Write changes periodically to disk, after relay.