message: Make last disconnected block BLOCK_FAILED_VALID, even when aborted
diff: @@ -2829,25 +2829,30 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
  // and be left unable to start as they have no tip candidates (as there
  // are no blocks that meet the "have data and are not invalid per
  // nStatus" criteria for inclusion in setBlockIndexCandidates).
  - invalid_walk_tip->nStatus |= BLOCK_FAILED_CHILD;
  + invalid_walk_tip->nStatus |= BLOCK_FAILED_VALID;
  setDirtyBlockIndex.insert(invalid_walk_tip);
  setBlockIndexCandidates.erase(invalid_walk_tip);
  setBlockIndexCandidates.insert(invalid_walk_tip->pprev);
  + if (invalid_walk_tip->pprev == to_mark_failed && (to_mark_failed->nStatus & BLOCK_FAILED_VALID)) {
  + // We only want to mark the last disconnected block as BLOCK_FAILED_VALID; its children
  + // need to be BLOCK_FAILED_CHILD instead.
  + to_mark_failed->nStatus = (to_mark_failed->nStatus ^ BLOCK_FAILED_VALID) | BLOCK_FAILED_CHILD;
  + setDirtyBlockIndex.insert(to_mark_failed);
  + }
  - // If we abort invalidation after this iteration, make sure
  - // the last disconnected block gets marked failed (rather than
  - // just child of failed)
  + // Track the last disconnected block, so we can correct its BLOCK_FAILED_CHILD status in future
  + // iterations, or, if it's the last one, call InvalidChainFound on it.
  to_mark_failed = invalid_walk_tip;
  }
  {
  - // Mark pindex (or the last disconnected block) as invalid, regardless of whether it was in the main chain or not.
  LOCK(cs_main);
  if (chainActive.Contains(to_mark_failed)) {
  // If the to-be-marked invalid block is in the active chain, something is interfering and we can't proceed.
  return false;
  }
  + // Mark pindex (or the last disconnected block) as invalid, even when it never was in the main chain
  to_mark_failed->nStatus |= BLOCK_FAILED_VALID;
  setDirtyBlockIndex.insert(to_mark_failed);
  setBlockIndexCandidates.erase(to_mark_failed);
  