@@ -2789,64 +2789,74 @@ bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIn
2789
2789
2790
2790
bool CChainState::InvalidateBlock (CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
2791
2791
{
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;
2800
2793
bool pindex_was_in_chain = false ;
2801
- CBlockIndex *invalid_walk_tip = chainActive.Tip ();
2802
2794
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 ;
2805
2801
pindex_was_in_chain = true ;
2802
+ CBlockIndex *invalid_walk_tip = chainActive.Tip ();
2803
+
2806
2804
// ActivateBestChain considers blocks already in chainActive
2807
2805
// 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 ());
2815
2814
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).
2819
2820
invalid_walk_tip->nStatus |= BLOCK_FAILED_CHILD;
2820
2821
setDirtyBlockIndex.insert (invalid_walk_tip);
2821
2822
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;
2823
2829
}
2824
2830
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
+ }
2830
2838
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);
2834
2843
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++;
2841
2852
}
2842
- it++;
2843
- }
2844
2853
2845
- InvalidChainFound (pindex);
2854
+ InvalidChainFound (to_mark_failed);
2855
+ }
2846
2856
2847
2857
// Only notify about a new block tip if the active chain was modified.
2848
2858
if (pindex_was_in_chain) {
2849
- uiInterface.NotifyBlockTip (IsInitialBlockDownload (), pindex ->pprev );
2859
+ uiInterface.NotifyBlockTip (IsInitialBlockDownload (), to_mark_failed ->pprev );
2850
2860
}
2851
2861
return true ;
2852
2862
}
0 commit comments