diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -814,13 +814,18 @@ //! easily as opposed to referencing a global. BlockManager &m_blockman; + /** + * The best finalized block. + * This block cannot be reorged in any way except by explicit user action. + */ + const CBlockIndex *m_finalizedBlockIndex = nullptr; + public: explicit CChainState(BlockManager &blockman) : m_blockman(blockman) {} //! The current chain of blockheaders we consult and build on. //! @see CChain, CBlockIndex. CChain m_chain; - CBlockIndex const *pindexFinalized = nullptr; /** * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for * itself and all ancestors) and as good as our current tip or better. @@ -886,13 +891,14 @@ bool ParkBlock(const Config &config, BlockValidationState &state, CBlockIndex *pindex) LOCKS_EXCLUDED(cs_main, m_cs_chainstate); - /** - * Finalize a block. - * A finalized block can not be reorged in any way. - */ + + /** Finalize a block. A finalized block can not be reorged in any way. */ bool FinalizeBlock(const Config &config, BlockValidationState &state, CBlockIndex *pindex) LOCKS_EXCLUDED(cs_main, m_cs_chainstate); + /** Return the currently finalized block index. */ + const CBlockIndex *finalizedBlockIndex() const; + void ResetBlockFailureFlags(CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); template @@ -946,9 +952,12 @@ void InvalidChainFound(CBlockIndex *pindexNew) EXCLUSIVE_LOCKS_REQUIRED(cs_main); CBlockIndex *FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + /** Change the currently finalized block index. */ bool MarkBlockAsFinal(const Config &config, BlockValidationState &state, const CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + void ReceivedBlockTransactions(const CBlock &block, CBlockIndex *pindexNew, const FlatFilePos &pos) EXCLUSIVE_LOCKS_REQUIRED(cs_main); diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -115,11 +115,6 @@ namespace { CBlockIndex *pindexBestInvalid = nullptr; CBlockIndex *pindexBestParked = nullptr; -/** - * The best finalized block. - * This block cannot be reorged in any way except by explicit user action. - */ -CBlockIndex const *&pindexFinalized = ::ChainstateActive().pindexFinalized; RecursiveMutex cs_LastBlockFile; std::vector vinfoBlockFile; @@ -939,7 +934,7 @@ // If the invalid chain found is supposed to be finalized, we need to move // back the finalization point. if (IsBlockFinalized(pindexNew)) { - pindexFinalized = pindexNew->pprev; + m_finalizedBlockIndex = pindexNew->pprev; } LogPrintf("%s: invalid block=%s height=%d log2_work=%.8g date=%s\n", @@ -2160,8 +2155,8 @@ } // If the tip is finalized, then undo it. - if (pindexFinalized == pindexDelete) { - pindexFinalized = pindexDelete->pprev; + if (finalizedBlockIndex() == pindexDelete) { + m_finalizedBlockIndex = pindexDelete->pprev; } m_chain.SetTip(pindexDelete->pprev); @@ -2262,7 +2257,8 @@ } // Check that the request is consistent with current finalization. - if (pindexFinalized && !AreOnTheSameFork(pindex, pindexFinalized)) { + if (finalizedBlockIndex() && + !AreOnTheSameFork(pindex, finalizedBlockIndex())) { LogPrintf("ERROR: %s: Trying to finalize block %s which conflicts with " "already finalized block\n", __func__, pindex->GetBlockHash().ToString()); @@ -2277,7 +2273,7 @@ } // We have a new block to finalize. - pindexFinalized = pindex; + m_finalizedBlockIndex = pindex; return true; } @@ -2309,7 +2305,7 @@ // While our candidate is not eligible (finalization delay not expired), try // the previous one. - while (pindex && (pindex != pindexFinalized)) { + while (pindex && (pindex != ::ChainstateActive().finalizedBlockIndex())) { // Check that the block to finalize is known for a long enough time. // This test will ensure that an attacker could not cause a block to // finalize by forking the chain with a depth > maxreorgdepth. @@ -2479,11 +2475,12 @@ // If this block will cause a finalized block to be reorged, then we // mark it as invalid. - if (pindexFinalized && !AreOnTheSameFork(pindexNew, pindexFinalized)) { + if (finalizedBlockIndex() && + !AreOnTheSameFork(pindexNew, finalizedBlockIndex())) { LogPrintf("Mark block %s invalid because it forks prior to the " "finalization point %d.\n", pindexNew->GetBlockHash().ToString(), - pindexFinalized->nHeight); + finalizedBlockIndex()->nHeight); pindexNew->nStatus = pindexNew->nStatus.withFailed(); InvalidChainFound(pindexNew); } @@ -3221,6 +3218,11 @@ return UnwindBlock(config, state, pindexToInvalidate, true /* invalidating */); } +/** Return the currently finalized block index. */ +const CBlockIndex *CChainState::finalizedBlockIndex() const { + AssertLockHeld(cs_main); + return m_finalizedBlockIndex; +} template bool CChainState::UpdateFlagsForBlock(CBlockIndex *pindexBase, @@ -3283,8 +3285,9 @@ // In case we are reconsidering something before the finalization point, // move the finalization point to the last common ancestor. - if (pindexFinalized) { - pindexFinalized = LastCommonAncestor(pindex, pindexFinalized); + if (finalizedBlockIndex()) { + m_finalizedBlockIndex = + LastCommonAncestor(pindex, finalizedBlockIndex()); } UpdateFlags( @@ -3330,14 +3333,14 @@ } const CBlockIndex *GetFinalizedBlock() { - AssertLockHeld(cs_main); - return pindexFinalized; + return ::ChainstateActive().finalizedBlockIndex(); } bool IsBlockFinalized(const CBlockIndex *pindex) { AssertLockHeld(cs_main); - return pindexFinalized && - pindexFinalized->GetAncestor(pindex->nHeight) == pindex; + auto finalizedBlockIndex = ::ChainstateActive().finalizedBlockIndex(); + return finalizedBlockIndex && + finalizedBlockIndex->GetAncestor(pindex->nHeight) == pindex; } CBlockIndex *BlockManager::AddToBlockIndex(const CBlockHeader &block) { @@ -5002,6 +5005,9 @@ void CChainState::UnloadBlockIndex() { nBlockSequenceId = 1; setBlockIndexCandidates.clear(); + + // Do not point to CBlockIndex that has been free'd + m_finalizedBlockIndex = nullptr; } // May NOT be used after any connections are up as much @@ -5011,7 +5017,6 @@ LOCK(cs_main); ::ChainActive().SetTip(nullptr); g_blockman.Unload(); - pindexFinalized = nullptr; pindexBestInvalid = nullptr; pindexBestParked = nullptr; pindexBestHeader = nullptr;