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 @@ -841,7 +841,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) LOCKS_EXCLUDED(cs_main); void ResetBlockFailureFlags(CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); template diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3098,28 +3098,40 @@ 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; - } + AssertLockNotHeld(cs_main); + 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 UnwindBlock(config, state, pindexToInvalidate, - true /* invalidating */); + 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 UnwindBlock(config, state, pindexToInvalidate, + true /* invalidating */); } template