From 9b0a8d3152b43b63c99878d0223a1681993ad608 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 19 Nov 2014 09:39:42 +0100 Subject: Add 'invalidateblock' and 'reconsiderblock' RPC commands. These can be used for testing reorganizations or for manual intervention in case of chain forks. --- src/main.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index 0a81d0d7b4..eeef513528 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2135,6 +2135,79 @@ bool ActivateBestChain(CValidationState &state, CBlock *pblock) { return true; } +bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) { + AssertLockHeld(cs_main); + + // Mark the block itself as invalid. + pindex->nStatus |= BLOCK_FAILED_VALID; + if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex))) { + return state.Abort("Failed to update block index"); + } + setBlockIndexCandidates.erase(pindex); + + while (chainActive.Contains(pindex)) { + CBlockIndex *pindexWalk = chainActive.Tip(); + pindexWalk->nStatus |= BLOCK_FAILED_CHILD; + if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexWalk))) { + return state.Abort("Failed to update block index"); + } + setBlockIndexCandidates.erase(pindexWalk); + // ActivateBestChain considers blocks already in chainActive + // unconditionally valid already, so force disconnect away from it. + if (!DisconnectTip(state)) { + return false; + } + } + + // The resulting new best tip may not be in setBlockIndexCandidates anymore, so + // add them again. + BlockMap::iterator it = mapBlockIndex.begin(); + while (it != mapBlockIndex.end()) { + if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && setBlockIndexCandidates.value_comp()(chainActive.Tip(), it->second)) { + setBlockIndexCandidates.insert(pindex); + } + it++; + } + + InvalidChainFound(pindex); + return true; +} + +bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex) { + AssertLockHeld(cs_main); + + int nHeight = pindex->nHeight; + + // Remove the invalidity flag from this block and all its descendants. + BlockMap::iterator it = mapBlockIndex.begin(); + while (it != mapBlockIndex.end()) { + if (!it->second->IsValid() && it->second->GetAncestor(nHeight) == pindex) { + it->second->nStatus &= ~BLOCK_FAILED_MASK; + if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex))) { + return state.Abort("Failed to update block index"); + } + if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && setBlockIndexCandidates.value_comp()(chainActive.Tip(), it->second)) { + setBlockIndexCandidates.insert(it->second); + } + if (it->second == pindexBestInvalid) { + // Reset invalid block marker if it was pointing to one of those. + pindexBestInvalid = NULL; + } + } + it++; + } + + // Remove the invalidity flag from all ancestors too. + while (pindex != NULL) { + pindex->nStatus &= ~BLOCK_FAILED_MASK; + if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex))) { + return state.Abort("Failed to update block index"); + } + pindex = pindex->pprev; + } + return true; +} + CBlockIndex* AddToBlockIndex(const CBlockHeader& block) { // Check for duplicate -- cgit v1.2.3