@@ -85,6 +85,9 @@ static ChainstateLoadResult CompleteChainstateInitialization(
85
85
return options.reindex || options.reindex_chainstate || chainstate->CoinsTip ().GetBestBlock ().IsNull ();
86
86
};
87
87
88
+ assert (chainman.m_total_coinstip_cache > 0 );
89
+ assert (chainman.m_total_coinsdb_cache > 0 );
90
+
88
91
// Conservative value which is arbitrarily chosen, as it will ultimately be changed
89
92
// by a call to `chainman.MaybeRebalanceCaches()`. We just need to make sure
90
93
// that the sum of the two caches (40%) does not exceed the allowable amount
@@ -183,6 +186,47 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
183
186
return {init_status, init_error};
184
187
}
185
188
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
+
186
230
return {ChainstateLoadStatus::SUCCESS, {}};
187
231
}
188
232
0 commit comments