diff --git a/src/index/base.cpp b/src/index/base.cpp index 15ad04d46..9e48f0bd2 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -113,6 +113,11 @@ void BaseIndex::ThreadSync() Commit(); break; } + if (pindex_next->pprev != pindex && !Rewind(pindex, pindex_next->pprev)) { + FatalError("%s: Failed to rewind index %s to a previous chain tip", + __func__, GetName()); + return; + } pindex = pindex_next; } @@ -167,6 +172,22 @@ bool BaseIndex::CommitInternal(CDBBatch& batch) return true; } +bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip) +{ + assert(current_tip == m_best_block_index); + assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip); + + // In the case of a reorg, ensure persisted block locator is not stale. + m_best_block_index = new_tip; + if (!Commit()) { + // If commit fails, revert the best block index to avoid corruption. + m_best_block_index = current_tip; + return false; + } + + return true; +} + void BaseIndex::BlockConnected(const std::shared_ptr& block, const CBlockIndex* pindex, const std::vector& txn_conflicted) { @@ -194,6 +215,11 @@ void BaseIndex::BlockConnected(const std::shared_ptr& block, const best_block_index->GetBlockHash().ToString()); return; } + if (best_block_index != pindex->pprev && !Rewind(best_block_index, pindex->pprev)) { + FatalError("%s: Failed to rewind index %s to a previous chain tip", + __func__, GetName()); + return; + } } if (WriteBlock(*block, pindex)) { diff --git a/src/index/base.h b/src/index/base.h index 77e614a3a..31acbed0c 100644 --- a/src/index/base.h +++ b/src/index/base.h @@ -80,6 +80,10 @@ protected: /// commit more index state. virtual bool CommitInternal(CDBBatch& batch); + /// Rewind index to an earlier chain tip during a chain reorg. The tip must + /// be an ancestor of the current best block. + virtual bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip); + virtual DB& GetDB() const = 0; /// Get the name of the index for display in logs.