diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1688,16 +1688,16 @@ BlockHash hash(uint256S(strHash)); BlockValidationState state; + CBlockIndex *pblockindex{nullptr}; { LOCK(cs_main); - CBlockIndex *pblockindex = LookupBlockIndex(hash); - + pblockindex = LookupBlockIndex(hash); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } + } // end of locked cs_main scope - ::ChainstateActive().FinalizeBlock(config, state, pblockindex); - } + ::ChainstateActive().FinalizeBlock(config, state, pblockindex); if (state.IsValid()) { ActivateBestChain(config, state); diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -835,7 +835,7 @@ * A finalized block can not be reorged in any way. */ bool FinalizeBlock(const Config &config, BlockValidationState &state, - CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + CBlockIndex *pindex); bool UnwindBlock(const Config &config, BlockValidationState &state, CBlockIndex *pindex, bool invalidate); void ResetBlockFailureFlags(CBlockIndex *pindex) diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2908,27 +2908,38 @@ bool CChainState::FinalizeBlock(const Config &config, BlockValidationState &state, CBlockIndex *pindex) { - AssertLockHeld(cs_main); - if (!MarkBlockAsFinal(config, state, pindex)) { - // state is set by MarkBlockAsFinal. - return false; - } + CBlockIndex *pindexToInvalidate{nullptr}; + { + LOCK(cs_main); + if (!MarkBlockAsFinal(config, state, pindex)) { + // state is set by MarkBlockAsFinal. + return false; + } - // We have a valid candidate, make sure it is not parked. - if (pindex->nStatus.isOnParkedChain()) { - UnparkBlock(pindex); - } + // We have a valid candidate, make sure it is not parked. + if (pindex->nStatus.isOnParkedChain()) { + UnparkBlock(pindex); + } + + // If the finalized block is on the active chain, there is no need to + // rewind. + if (::ChainActive().Contains(pindex)) { + return true; + } - // If the finalized block is not on the active chain, we may need to rewind. - if (!::ChainActive().Contains(pindex)) { + // If the finalized block is not on the active chain, that chain is + // invalid + // ... const CBlockIndex *pindexFork = ::ChainActive().FindFork(pindex); - CBlockIndex *pindexToInvalidate = ::ChainActive().Next(pindexFork); - if (pindexToInvalidate) { - return InvalidateBlock(config, state, pindexToInvalidate); + pindexToInvalidate = ::ChainActive().Next(pindexFork); + if (!pindexToInvalidate) { + return false; } - } + } // end of locked cs_main scope - return true; + // ... therefore, we invalidate the block on the active chain that comes + // immediately after it + return InvalidateBlock(config, state, pindexToInvalidate); } bool CChainState::PreciousBlock(const Config &config,