@@ -1891,6 +1891,29 @@ const CBlockIndex* Chainstate::SnapshotBase() const
18911891 return m_cached_snapshot_base;
18921892}
18931893
1894+ const CBlockIndex* Chainstate::TargetBlock () const
1895+ {
1896+ if (!m_target_blockhash) return nullptr ;
1897+ if (!m_cached_target_block) m_cached_target_block = Assert (m_chainman.m_blockman .LookupBlockIndex (*m_target_blockhash));
1898+ return m_cached_target_block;
1899+ }
1900+
1901+ void Chainstate::SetTargetBlock (CBlockIndex* block)
1902+ {
1903+ if (block) {
1904+ m_target_blockhash = block->GetBlockHash ();
1905+ } else {
1906+ m_target_blockhash.reset ();
1907+ }
1908+ m_cached_target_block = block;
1909+ }
1910+
1911+ void Chainstate::SetTargetBlockHash (uint256 block_hash)
1912+ {
1913+ m_target_blockhash = block_hash;
1914+ m_cached_target_block = nullptr ;
1915+ }
1916+
18941917void Chainstate::InitCoinsDB (
18951918 size_t cache_size_bytes,
18961919 bool in_memory,
@@ -3144,8 +3167,6 @@ bool Chainstate::ConnectTip(
31443167 // If we are the background validation chainstate, check to see if we are done
31453168 // validating the snapshot (i.e. our tip has reached the snapshot's base block).
31463169 if (this != &m_chainman.ActiveChainstate ()) {
3147- // This call may set `m_disabled`, which is referenced immediately afterwards in
3148- // ActivateBestChain, so that we stop connecting blocks past the snapshot base.
31493170 m_chainman.MaybeCompleteSnapshotValidation ();
31503171 }
31513172
@@ -3439,12 +3460,8 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
34393460 }
34403461 }
34413462
3442- // This will have been toggled in
3443- // ActivateBestChainStep -> ConnectTip -> MaybeCompleteSnapshotValidation,
3444- // if at all, so we should catch it here.
3445- //
3446- // Break this do-while to ensure we don't advance past the base snapshot.
3447- if (m_disabled) {
3463+ // Break this do-while to ensure we don't advance past the target block.
3464+ if (ReachedTarget ()) {
34483465 break ;
34493466 }
34503467 } while (!m_chain.Tip () || (starting_tip && CBlockIndexWorkComparator ()(m_chain.Tip (), starting_tip)));
@@ -3486,7 +3503,7 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
34863503 } // release cs_main
34873504 // When we reach this point, we switched to a new tip (stored in pindexNewTip).
34883505
3489- bool disabled{ false } ;
3506+ bool reached_target ;
34903507 {
34913508 LOCK (m_chainman.GetMutex ());
34923509 if (exited_ibd) {
@@ -3500,15 +3517,14 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
35003517 return false ;
35013518 }
35023519
3503- disabled = m_disabled ;
3520+ reached_target = ReachedTarget () ;
35043521 }
35053522
3506- if (disabled) {
3507- // Background chainstate has reached the snapshot base block, so exit.
3508-
3509- // Restart indexes to resume indexing for all blocks unique to the snapshot
3510- // chain. This resumes indexing "in order" from where the indexing on the
3511- // background validation chain left off.
3523+ if (reached_target) {
3524+ // Chainstate has reached the target block, so exit.
3525+ //
3526+ // Restart indexes so indexes can resync and index new blocks after
3527+ // the target block.
35123528 //
35133529 // This cannot be done while holding cs_main (within
35143530 // MaybeCompleteSnapshotValidation) or a cs_main deadlock will occur.
@@ -3789,17 +3805,15 @@ void Chainstate::TryAddBlockIndexCandidate(CBlockIndex* pindex)
37893805 return ;
37903806 }
37913807
3792- bool is_active_chainstate = this == &m_chainman. ActiveChainstate () ;
3793- if (is_active_chainstate ) {
3794- // The active chainstate should always add entries that have more
3808+ const CBlockIndex* target_block{ TargetBlock ()} ;
3809+ if (!target_block ) {
3810+ // If no specific target block, add all entries that have more
37953811 // work than the tip.
37963812 setBlockIndexCandidates.insert (pindex);
3797- } else if (!m_disabled) {
3798- // For the background chainstate, we only consider connecting blocks
3799- // towards the snapshot base (which can't be nullptr or else we'll
3800- // never make progress).
3801- const CBlockIndex* snapshot_base{Assert (m_chainman.GetSnapshotBaseBlock ())};
3802- if (snapshot_base->GetAncestor (pindex->nHeight ) == pindex) {
3813+ } else {
3814+ // If there is a target block, only consider connecting blocks
3815+ // towards the target block.
3816+ if (target_block->GetAncestor (pindex->nHeight ) == pindex) {
38033817 setBlockIndexCandidates.insert (pindex);
38043818 }
38053819 }
@@ -4483,7 +4497,7 @@ bool ChainstateManager::ProcessNewBlock(const std::shared_ptr<const CBlock>& blo
44834497 return false ;
44844498 }
44854499
4486- Chainstate* bg_chain{WITH_LOCK (cs_main, return BackgroundSyncInProgress () ? m_ibd_chainstate. get () : nullptr )};
4500+ Chainstate* bg_chain{WITH_LOCK (cs_main, return HistoricalChainstate () )};
44874501 BlockValidationState bg_state;
44884502 if (bg_chain && !bg_chain->ActivateBestChain (bg_state, block)) {
44894503 LogError (" %s: [background] ActivateBestChain failed (%s)\n " , __func__, bg_state.ToString ());
@@ -5787,6 +5801,11 @@ util::Result<CBlockIndex*> ChainstateManager::ActivateSnapshot(
57875801 const bool chaintip_loaded = m_snapshot_chainstate->LoadChainTip ();
57885802 assert (chaintip_loaded);
57895803
5804+ // Set snapshot block as the target block for the historical chainstate.
5805+ assert (m_ibd_chainstate.get ());
5806+ assert (!m_ibd_chainstate->m_target_blockhash );
5807+ m_ibd_chainstate->SetTargetBlockHash (base_blockhash);
5808+
57905809 // Transfer possession of the mempool to the snapshot chainstate.
57915810 // Mempool is empty at this point because we're still in IBD.
57925811 Assert (m_active_chainstate->m_mempool ->size () == 0 );
@@ -6048,23 +6067,25 @@ util::Result<void> ChainstateManager::PopulateAndValidateSnapshot(
60486067SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation ()
60496068{
60506069 AssertLockHeld (cs_main);
6070+
6071+ // If a snapshot does not need to be validated...
60516072 if (m_ibd_chainstate.get () == &this ->ActiveChainstate () ||
6073+ // Or if either chainstate is unusable...
60526074 !this ->IsUsable (m_snapshot_chainstate.get ()) ||
60536075 !this ->IsUsable (m_ibd_chainstate.get ()) ||
6054- !m_ibd_chainstate->m_chain .Tip ()) {
6055- // Nothing to do - this function only applies to the background
6056- // validation chainstate.
6076+ !m_snapshot_chainstate->m_from_snapshot_blockhash ||
6077+ !m_ibd_chainstate->m_chain .Tip () ||
6078+ // Or the validated chainstate is not targeting the snapshot block...
6079+ !m_ibd_chainstate->m_target_blockhash ||
6080+ *m_ibd_chainstate->m_target_blockhash != *m_snapshot_chainstate->m_from_snapshot_blockhash ||
6081+ // Or the validated chainstate has not reached the snapshot block yet...
6082+ !m_ibd_chainstate->ReachedTarget ()) {
6083+ // Then a snapshot cannot be validated and there is nothing to do.
60576084 return SnapshotCompletionResult::SKIPPED;
60586085 }
60596086 const int snapshot_tip_height = this ->ActiveHeight ();
60606087 const int snapshot_base_height = *Assert (this ->GetSnapshotBaseHeight ());
60616088 const CBlockIndex& index_new = *Assert (m_ibd_chainstate->m_chain .Tip ());
6062-
6063- if (index_new.nHeight < snapshot_base_height) {
6064- // Background IBD not complete yet.
6065- return SnapshotCompletionResult::SKIPPED;
6066- }
6067-
60686089 assert (SnapshotBlockhash ());
60696090 uint256 snapshot_blockhash = *Assert (SnapshotBlockhash ());
60706091
@@ -6087,6 +6108,9 @@ SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation()
60876108 LogError (" [snapshot] !!! %s\n " , user_error.original );
60886109 LogError (" [snapshot] deleting snapshot, reverting to validated chain, and stopping node\n " );
60896110
6111+ // Reset chainstate target to network tip instead of snapshot block.
6112+ m_ibd_chainstate->SetTargetBlock (nullptr );
6113+
60906114 m_active_chainstate = m_ibd_chainstate.get ();
60916115 m_snapshot_chainstate->m_disabled = true ;
60926116 assert (!this ->IsUsable (m_snapshot_chainstate.get ()));
@@ -6100,14 +6124,7 @@ SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation()
61006124 GetNotifications ().fatalError (user_error);
61016125 };
61026126
6103- if (index_new.GetBlockHash () != snapshot_blockhash) {
6104- LogWarning (" [snapshot] supposed base block %s does not match the "
6105- " snapshot base block %s (height %d). Snapshot is not valid." ,
6106- index_new.ToString (), snapshot_blockhash.ToString (), snapshot_base_height);
6107- handle_invalid_snapshot ();
6108- return SnapshotCompletionResult::BASE_BLOCKHASH_MISMATCH;
6109- }
6110-
6127+ assert (index_new.GetBlockHash () == snapshot_blockhash);
61116128 assert (index_new.nHeight == snapshot_base_height);
61126129
61136130 int curr_height = m_ibd_chainstate->m_chain .Height ();
@@ -6286,6 +6303,12 @@ Chainstate& ChainstateManager::ActivateExistingSnapshot(uint256 base_blockhash)
62866303 std::make_unique<Chainstate>(nullptr , m_blockman, *this , base_blockhash);
62876304 LogInfo (" [snapshot] switching active chainstate to %s" , m_snapshot_chainstate->ToString ());
62886305
6306+ // Set target block for historical chainstate to snapshot block.
6307+ assert (m_ibd_chainstate.get ());
6308+ assert (!m_ibd_chainstate->m_target_blockhash );
6309+ m_ibd_chainstate->SetTargetBlockHash (base_blockhash);
6310+
6311+ // Transfer possession of the mempool to the chainstate.
62896312 // Mempool is empty at this point because we're still in IBD.
62906313 Assert (m_active_chainstate->m_mempool ->size () == 0 );
62916314 Assert (!m_snapshot_chainstate->m_mempool );
@@ -6522,3 +6545,10 @@ std::pair<int, int> ChainstateManager::GetPruneRange(const Chainstate& chainstat
65226545
65236546 return {prune_start, prune_end};
65246547}
6548+
6549+ std::optional<std::pair<const CBlockIndex*, const CBlockIndex*>> ChainstateManager::GetHistoricalBlockRange () const
6550+ {
6551+ const Chainstate* chainstate{HistoricalChainstate ()};
6552+ if (!chainstate) return {};
6553+ return std::make_pair (chainstate->m_chain .Tip (), chainstate->TargetBlock ());
6554+ }
0 commit comments