diff options
Diffstat (limited to 'src/index/base.cpp')
-rw-r--r-- | src/index/base.cpp | 79 |
1 files changed, 60 insertions, 19 deletions
diff --git a/src/index/base.cpp b/src/index/base.cpp index 3d3dda95b1..6fd2701e2e 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -4,15 +4,16 @@ #include <chainparams.h> #include <index/base.h> +#include <node/blockstorage.h> #include <node/ui_interface.h> #include <shutdown.h> #include <tinyformat.h> -#include <util/system.h> +#include <util/thread.h> #include <util/translation.h> -#include <validation.h> +#include <validation.h> // For g_chainman #include <warnings.h> -constexpr char DB_BEST_BLOCK = 'B'; +constexpr uint8_t DB_BEST_BLOCK{'B'}; constexpr int64_t SYNC_LOG_INTERVAL = 30; // seconds constexpr int64_t SYNC_LOCATOR_WRITE_INTERVAL = 30; // seconds @@ -59,29 +60,65 @@ bool BaseIndex::Init() } LOCK(cs_main); + CChain& active_chain = m_chainstate->m_chain; if (locator.IsNull()) { m_best_block_index = nullptr; } else { - m_best_block_index = g_chainman.m_blockman.FindForkInGlobalIndex(::ChainActive(), locator); + m_best_block_index = m_chainstate->m_blockman.FindForkInGlobalIndex(active_chain, locator); + } + m_synced = m_best_block_index.load() == active_chain.Tip(); + if (!m_synced) { + bool prune_violation = false; + if (!m_best_block_index) { + // index is not built yet + // make sure we have all block data back to the genesis + const CBlockIndex* block = active_chain.Tip(); + while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) { + block = block->pprev; + } + prune_violation = block != active_chain.Genesis(); + } + // in case the index has a best block set and is not fully synced + // check if we have the required blocks to continue building the index + else { + const CBlockIndex* block_to_test = m_best_block_index.load(); + if (!active_chain.Contains(block_to_test)) { + // if the bestblock is not part of the mainchain, find the fork + // and make sure we have all data down to the fork + block_to_test = active_chain.FindFork(block_to_test); + } + const CBlockIndex* block = active_chain.Tip(); + prune_violation = true; + // check backwards from the tip if we have all block data until we reach the indexes bestblock + while (block_to_test && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) { + if (block_to_test == block) { + prune_violation = false; + break; + } + block = block->pprev; + } + } + if (prune_violation) { + return InitError(strprintf(Untranslated("%s best block of the index goes beyond pruned data. Please disable the index or reindex (which will download the whole blockchain again)"), GetName())); + } } - m_synced = m_best_block_index.load() == ::ChainActive().Tip(); return true; } -static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev, CChain& chain) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { AssertLockHeld(cs_main); if (!pindex_prev) { - return ::ChainActive().Genesis(); + return chain.Genesis(); } - const CBlockIndex* pindex = ::ChainActive().Next(pindex_prev); + const CBlockIndex* pindex = chain.Next(pindex_prev); if (pindex) { return pindex; } - return ::ChainActive().Next(::ChainActive().FindFork(pindex_prev)); + return chain.Next(chain.FindFork(pindex_prev)); } void BaseIndex::ThreadSync() @@ -104,7 +141,7 @@ void BaseIndex::ThreadSync() { LOCK(cs_main); - const CBlockIndex* pindex_next = NextSyncBlock(pindex); + const CBlockIndex* pindex_next = NextSyncBlock(pindex, m_chainstate->m_chain); if (!pindex_next) { m_best_block_index = pindex; m_synced = true; @@ -167,7 +204,7 @@ bool BaseIndex::Commit() bool BaseIndex::CommitInternal(CDBBatch& batch) { LOCK(cs_main); - GetDB().WriteBestBlock(batch, ::ChainActive().GetLocator(m_best_block_index)); + GetDB().WriteBestBlock(batch, m_chainstate->m_chain.GetLocator(m_best_block_index)); return true; } @@ -177,6 +214,10 @@ bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_ti assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip); // In the case of a reorg, ensure persisted block locator is not stale. + // Pruning has a minimum of 288 blocks-to-keep and getting the index + // out of sync may be possible but a users fault. + // In case we reorg beyond the pruned depth, ReadBlockFromDisk would + // throw and lead to a graceful shutdown m_best_block_index = new_tip; if (!Commit()) { // If commit fails, revert the best block index to avoid corruption. @@ -239,7 +280,7 @@ void BaseIndex::ChainStateFlushed(const CBlockLocator& locator) const CBlockIndex* locator_tip_index; { LOCK(cs_main); - locator_tip_index = g_chainman.m_blockman.LookupBlockIndex(locator_tip_hash); + locator_tip_index = m_chainstate->m_blockman.LookupBlockIndex(locator_tip_hash); } if (!locator_tip_index) { @@ -280,7 +321,7 @@ bool BaseIndex::BlockUntilSyncedToCurrentChain() const // Skip the queue-draining stuff if we know we're caught up with // ::ChainActive().Tip(). LOCK(cs_main); - const CBlockIndex* chain_tip = ::ChainActive().Tip(); + const CBlockIndex* chain_tip = m_chainstate->m_chain.Tip(); const CBlockIndex* best_block_index = m_best_block_index.load(); if (best_block_index->GetAncestor(chain_tip->nHeight) == chain_tip) { return true; @@ -297,18 +338,18 @@ void BaseIndex::Interrupt() m_interrupt(); } -void BaseIndex::Start() +bool BaseIndex::Start(CChainState& active_chainstate) { + m_chainstate = &active_chainstate; // Need to register this ValidationInterface before running Init(), so that // callbacks are not missed if Init sets m_synced to true. RegisterValidationInterface(this); if (!Init()) { - FatalError("%s: %s failed to initialize", __func__, GetName()); - return; + return false; } - m_thread_sync = std::thread(&TraceThread<std::function<void()>>, GetName(), - std::bind(&BaseIndex::ThreadSync, this)); + m_thread_sync = std::thread(&util::TraceThread, GetName(), [this] { ThreadSync(); }); + return true; } void BaseIndex::Stop() @@ -325,6 +366,6 @@ IndexSummary BaseIndex::GetSummary() const IndexSummary summary{}; summary.name = GetName(); summary.synced = m_synced; - summary.best_block_height = m_best_block_index.load()->nHeight; + summary.best_block_height = m_best_block_index ? m_best_block_index.load()->nHeight : 0; return summary; } |