diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2014-11-19 09:39:42 +0100 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2014-11-26 16:36:25 +0100 |
commit | 9b0a8d3152b43b63c99878d0223a1681993ad608 (patch) | |
tree | 33eaad082c1eaf52a331a57e027d7ded4288cc1a /src/main.cpp | |
parent | 9ff0bc9beb90cf96fb0a9698de22e2bc60fed2f2 (diff) |
Add 'invalidateblock' and 'reconsiderblock' RPC commands.
These can be used for testing reorganizations or for manual intervention in case of
chain forks.
Diffstat (limited to 'src/main.cpp')
-rw-r--r-- | src/main.cpp | 73 |
1 files changed, 73 insertions, 0 deletions
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 |