@@ -85,6 +85,9 @@ static ChainstateLoadResult CompleteChainstateInitialization(
8585 return options.reindex || options.reindex_chainstate || chainstate->CoinsTip ().GetBestBlock ().IsNull ();
8686 };
8787
88+ assert (chainman.m_total_coinstip_cache > 0 );
89+ assert (chainman.m_total_coinsdb_cache > 0 );
90+
8891 // Conservative value which is arbitrarily chosen, as it will ultimately be changed
8992 // by a call to `chainman.MaybeRebalanceCaches()`. We just need to make sure
9093 // that the sum of the two caches (40%) does not exceed the allowable amount
@@ -183,6 +186,47 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
183186 return {init_status, init_error};
184187 }
185188
189+ // If a snapshot chainstate was fully validated by a background chainstate during
190+ // the last run, detect it here and clean up the now-unneeded background
191+ // chainstate.
192+ //
193+ // Why is this cleanup done here (on subsequent restart) and not just when the
194+ // snapshot is actually validated? Because this entails unusual
195+ // filesystem operations to move leveldb data directories around, and that seems
196+ // too risky to do in the middle of normal runtime.
197+ auto snapshot_completion = chainman.MaybeCompleteSnapshotValidation ();
198+
199+ if (snapshot_completion == SnapshotCompletionResult::SKIPPED) {
200+ // do nothing; expected case
201+ } else if (snapshot_completion == SnapshotCompletionResult::SUCCESS) {
202+ LogPrintf (" [snapshot] cleaning up unneeded background chainstate, then reinitializing\n " );
203+ if (!chainman.ValidatedSnapshotCleanup ()) {
204+ AbortNode (" Background chainstate cleanup failed unexpectedly." );
205+ }
206+
207+ // Because ValidatedSnapshotCleanup() has torn down chainstates with
208+ // ChainstateManager::ResetChainstates(), reinitialize them here without
209+ // duplicating the blockindex work above.
210+ assert (chainman.GetAll ().empty ());
211+ assert (!chainman.IsSnapshotActive ());
212+ assert (!chainman.IsSnapshotValidated ());
213+
214+ chainman.InitializeChainstate (options.mempool );
215+
216+ // A reload of the block index is required to recompute setBlockIndexCandidates
217+ // for the fully validated chainstate.
218+ chainman.ActiveChainstate ().UnloadBlockIndex ();
219+
220+ auto [init_status, init_error] = CompleteChainstateInitialization (chainman, cache_sizes, options);
221+ if (init_status != ChainstateLoadStatus::SUCCESS) {
222+ return {init_status, init_error};
223+ }
224+ } else {
225+ return {ChainstateLoadStatus::FAILURE, _ (
226+ " UTXO snapshot failed to validate. "
227+ " Restart to resume normal initial block download, or try loading a different snapshot." )};
228+ }
229+
186230 return {ChainstateLoadStatus::SUCCESS, {}};
187231}
188232
0 commit comments