aboutsummaryrefslogtreecommitdiff
path: root/src/node
diff options
context:
space:
mode:
authorJames O'Beirne <james.obeirne@pm.me>2022-04-28 10:23:33 -0400
committerJames O'Beirne <james.obeirne@pm.me>2023-03-07 16:06:17 -0500
commitd96c59cc5cd2f73f1f55c133c52208671fe75ef3 (patch)
tree1a8031f6e3e087a9f902bc7a253d740dad547ed4 /src/node
parentf2a4f3376f1476b38a79a549bd81ba3006225df6 (diff)
validation: add ChainMan logic for completing UTXO snapshot validation
Trigger completion when a background validation chainstate reaches the same height as a UTXO snapshot, and handle cleaning up the chainstate on subsequent startup.
Diffstat (limited to 'src/node')
-rw-r--r--src/node/chainstate.cpp44
1 files changed, 44 insertions, 0 deletions
diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp
index e9eea90bcb..cd82d8743c 100644
--- a/src/node/chainstate.cpp
+++ b/src/node/chainstate.cpp
@@ -85,6 +85,9 @@ static ChainstateLoadResult CompleteChainstateInitialization(
return options.reindex || options.reindex_chainstate || chainstate->CoinsTip().GetBestBlock().IsNull();
};
+ assert(chainman.m_total_coinstip_cache > 0);
+ assert(chainman.m_total_coinsdb_cache > 0);
+
// Conservative value which is arbitrarily chosen, as it will ultimately be changed
// by a call to `chainman.MaybeRebalanceCaches()`. We just need to make sure
// that the sum of the two caches (40%) does not exceed the allowable amount
@@ -183,6 +186,47 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
return {init_status, init_error};
}
+ // If a snapshot chainstate was fully validated by a background chainstate during
+ // the last run, detect it here and clean up the now-unneeded background
+ // chainstate.
+ //
+ // Why is this cleanup done here (on subsequent restart) and not just when the
+ // snapshot is actually validated? Because this entails unusual
+ // filesystem operations to move leveldb data directories around, and that seems
+ // too risky to do in the middle of normal runtime.
+ auto snapshot_completion = chainman.MaybeCompleteSnapshotValidation();
+
+ if (snapshot_completion == SnapshotCompletionResult::SKIPPED) {
+ // do nothing; expected case
+ } else if (snapshot_completion == SnapshotCompletionResult::SUCCESS) {
+ LogPrintf("[snapshot] cleaning up unneeded background chainstate, then reinitializing\n");
+ if (!chainman.ValidatedSnapshotCleanup()) {
+ AbortNode("Background chainstate cleanup failed unexpectedly.");
+ }
+
+ // Because ValidatedSnapshotCleanup() has torn down chainstates with
+ // ChainstateManager::ResetChainstates(), reinitialize them here without
+ // duplicating the blockindex work above.
+ assert(chainman.GetAll().empty());
+ assert(!chainman.IsSnapshotActive());
+ assert(!chainman.IsSnapshotValidated());
+
+ chainman.InitializeChainstate(options.mempool);
+
+ // A reload of the block index is required to recompute setBlockIndexCandidates
+ // for the fully validated chainstate.
+ chainman.ActiveChainstate().UnloadBlockIndex();
+
+ auto [init_status, init_error] = CompleteChainstateInitialization(chainman, cache_sizes, options);
+ if (init_status != ChainstateLoadStatus::SUCCESS) {
+ return {init_status, init_error};
+ }
+ } else {
+ return {ChainstateLoadStatus::FAILURE, _(
+ "UTXO snapshot failed to validate. "
+ "Restart to resume normal initial block download, or try loading a different snapshot.")};
+ }
+
return {ChainstateLoadStatus::SUCCESS, {}};
}