@@ -2789,64 +2789,74 @@ bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIn
27892789
27902790bool CChainState::InvalidateBlock (CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
27912791{
2792- LOCK (cs_main);
2793-
2794- // We first disconnect backwards and then mark the blocks as invalid.
2795- // This prevents a case where pruned nodes may fail to invalidateblock
2796- // and be left unable to start as they have no tip candidates (as there
2797- // are no blocks that meet the "have data and are not invalid per
2798- // nStatus" criteria for inclusion in setBlockIndexCandidates).
2799-
2792+ CBlockIndex* to_mark_failed = pindex;
28002793 bool pindex_was_in_chain = false ;
2801- CBlockIndex *invalid_walk_tip = chainActive.Tip ();
28022794
2803- DisconnectedBlockTransactions disconnectpool;
2804- while (chainActive.Contains (pindex)) {
2795+ // Disconnect (descendants of) pindex, and mark them invalid.
2796+ while (true ) {
2797+ if (ShutdownRequested ()) break ;
2798+
2799+ LOCK (cs_main);
2800+ if (!chainActive.Contains (pindex)) break ;
28052801 pindex_was_in_chain = true ;
2802+ CBlockIndex *invalid_walk_tip = chainActive.Tip ();
2803+
28062804 // ActivateBestChain considers blocks already in chainActive
28072805 // unconditionally valid already, so force disconnect away from it.
2808- if (!DisconnectTip (state, chainparams, &disconnectpool)) {
2809- // It's probably hopeless to try to make the mempool consistent
2810- // here if DisconnectTip failed, but we can try.
2811- UpdateMempoolForReorg (disconnectpool, false );
2812- return false ;
2813- }
2814- }
2806+ DisconnectedBlockTransactions disconnectpool;
2807+ bool ret = DisconnectTip (state, chainparams, &disconnectpool);
2808+ // DisconnectTip will add transactions to disconnectpool.
2809+ // Adjust the mempool to be consistent with the new tip, adding
2810+ // transactions back to the mempool if disconnecting was succesful.
2811+ UpdateMempoolForReorg (disconnectpool, /* fAddToMempool = */ ret);
2812+ if (!ret) return false ;
2813+ assert (invalid_walk_tip->pprev == chainActive.Tip ());
28152814
2816- // Now mark the blocks we just disconnected as descendants invalid
2817- // (note this may not be all descendants).
2818- while (pindex_was_in_chain && invalid_walk_tip != pindex) {
2815+ // We immediately mark the disconnected blocks as invalid.
2816+ // This prevents a case where pruned nodes may fail to invalidateblock
2817+ // and be left unable to start as they have no tip candidates (as there
2818+ // are no blocks that meet the "have data and are not invalid per
2819+ // nStatus" criteria for inclusion in setBlockIndexCandidates).
28192820 invalid_walk_tip->nStatus |= BLOCK_FAILED_CHILD;
28202821 setDirtyBlockIndex.insert (invalid_walk_tip);
28212822 setBlockIndexCandidates.erase (invalid_walk_tip);
2822- invalid_walk_tip = invalid_walk_tip->pprev ;
2823+ setBlockIndexCandidates.insert (invalid_walk_tip->pprev );
2824+
2825+ // If we abort invalidation after this iteration, make sure
2826+ // the last disconnected block gets marked failed (rather than
2827+ // just child of failed)
2828+ to_mark_failed = invalid_walk_tip;
28232829 }
28242830
2825- // Mark the block itself as invalid.
2826- pindex->nStatus |= BLOCK_FAILED_VALID;
2827- setDirtyBlockIndex.insert (pindex);
2828- setBlockIndexCandidates.erase (pindex);
2829- m_failed_blocks.insert (pindex);
2831+ {
2832+ // Mark pindex (or the last disconnected block) as invalid, regardless of whether it was in the main chain or not.
2833+ LOCK (cs_main);
2834+ if (chainActive.Contains (to_mark_failed)) {
2835+ // If the to-be-marked invalid block is in the active chain, something is interfering and we can't proceed.
2836+ return false ;
2837+ }
28302838
2831- // DisconnectTip will add transactions to disconnectpool; try to add these
2832- // back to the mempool.
2833- UpdateMempoolForReorg (disconnectpool, true );
2839+ to_mark_failed->nStatus |= BLOCK_FAILED_VALID;
2840+ setDirtyBlockIndex.insert (to_mark_failed);
2841+ setBlockIndexCandidates.erase (to_mark_failed);
2842+ m_failed_blocks.insert (to_mark_failed);
28342843
2835- // The resulting new best tip may not be in setBlockIndexCandidates anymore, so
2836- // add it again.
2837- BlockMap::iterator it = mapBlockIndex.begin ();
2838- while (it != mapBlockIndex.end ()) {
2839- if (it->second ->IsValid (BLOCK_VALID_TRANSACTIONS) && it->second ->HaveTxsDownloaded () && !setBlockIndexCandidates.value_comp ()(it->second , chainActive.Tip ())) {
2840- setBlockIndexCandidates.insert (it->second );
2844+ // The resulting new best tip may not be in setBlockIndexCandidates anymore, so
2845+ // add it again.
2846+ BlockMap::iterator it = mapBlockIndex.begin ();
2847+ while (it != mapBlockIndex.end ()) {
2848+ if (it->second ->IsValid (BLOCK_VALID_TRANSACTIONS) && it->second ->HaveTxsDownloaded () && !setBlockIndexCandidates.value_comp ()(it->second , chainActive.Tip ())) {
2849+ setBlockIndexCandidates.insert (it->second );
2850+ }
2851+ it++;
28412852 }
2842- it++;
2843- }
28442853
2845- InvalidChainFound (pindex);
2854+ InvalidChainFound (to_mark_failed);
2855+ }
28462856
28472857 // Only notify about a new block tip if the active chain was modified.
28482858 if (pindex_was_in_chain) {
2849- uiInterface.NotifyBlockTip (IsInitialBlockDownload (), pindex ->pprev );
2859+ uiInterface.NotifyBlockTip (IsInitialBlockDownload (), to_mark_failed ->pprev );
28502860 }
28512861 return true ;
28522862}
0 commit comments