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 0a81d0d7b..eeef51352 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 From 0dd06b2515cd4d1f0be4dcf9060e34f3b9abde76 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 25 Nov 2014 12:33:43 +0100 Subject: Delay writing block indexes in invalidate/reconsider --- src/main.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index eeef51352..5695c8ba5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2140,17 +2140,13 @@ bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) { // Mark the block itself as invalid. pindex->nStatus |= BLOCK_FAILED_VALID; - if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex))) { - return state.Abort("Failed to update block index"); - } + setDirtyBlockIndex.insert(pindex); 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"); - } + setDirtyBlockIndex.insert(pindexWalk); setBlockIndexCandidates.erase(pindexWalk); // ActivateBestChain considers blocks already in chainActive // unconditionally valid already, so force disconnect away from it. @@ -2183,9 +2179,7 @@ bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex) { 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"); - } + setDirtyBlockIndex.insert(it->second); if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && setBlockIndexCandidates.value_comp()(chainActive.Tip(), it->second)) { setBlockIndexCandidates.insert(it->second); } @@ -2199,9 +2193,9 @@ bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex) { // 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"); + if (pindex->nStatus & BLOCK_FAILED_MASK) { + pindex->nStatus &= ~BLOCK_FAILED_MASK; + setDirtyBlockIndex.insert(pindex); } pindex = pindex->pprev; } -- cgit v1.2.3