| 149 | } |
| 150 | |
| 151 | ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSizes& cache_sizes, |
| 152 | const ChainstateLoadOptions& options) |
| 153 | { |
| 154 | if (!chainman.AssumedValidBlock().IsNull()) { |
| 155 | LogInfo("Assuming ancestors of block %s have valid signatures.", chainman.AssumedValidBlock().GetHex()); |
| 156 | } else { |
| 157 | LogInfo("Validating signatures for all blocks."); |
| 158 | } |
| 159 | LogInfo("Setting nMinimumChainWork=%s", chainman.MinimumChainWork().GetHex()); |
| 160 | if (chainman.MinimumChainWork() < UintToArith256(chainman.GetConsensus().nMinimumChainWork)) { |
| 161 | LogWarning("nMinimumChainWork set below default value of %s", chainman.GetConsensus().nMinimumChainWork.GetHex()); |
| 162 | } |
| 163 | if (chainman.m_blockman.GetPruneTarget() == BlockManager::PRUNE_TARGET_MANUAL) { |
| 164 | LogInfo("Block pruning enabled. Use RPC call pruneblockchain(height) to manually prune block and undo files."); |
| 165 | } else if (chainman.m_blockman.GetPruneTarget()) { |
| 166 | LogInfo("Prune configured to target %u MiB on disk for block and undo files.", |
| 167 | chainman.m_blockman.GetPruneTarget() / 1_MiB); |
| 168 | } |
| 169 | |
| 170 | LOCK(cs_main); |
| 171 | |
| 172 | chainman.m_total_coinstip_cache = cache_sizes.coins; |
| 173 | chainman.m_total_coinsdb_cache = cache_sizes.coins_db; |
| 174 | |
| 175 | // Load the fully validated chainstate. |
| 176 | Chainstate& validated_cs{chainman.InitializeChainstate(options.mempool)}; |
| 177 | |
| 178 | // Load a chain created from a UTXO snapshot, if any exist. |
| 179 | Chainstate* assumeutxo_cs{chainman.LoadAssumeutxoChainstate()}; |
| 180 | |
| 181 | if (assumeutxo_cs && options.wipe_chainstate_db) { |
| 182 | // Reset chainstate target to network tip instead of snapshot block. |
| 183 | validated_cs.SetTargetBlock(nullptr); |
| 184 | LogInfo("[snapshot] deleting snapshot chainstate due to reindexing"); |
| 185 | if (!chainman.DeleteChainstate(*assumeutxo_cs)) { |
| 186 | return {ChainstateLoadStatus::FAILURE_FATAL, Untranslated("Couldn't remove snapshot chainstate.")}; |
| 187 | } |
| 188 | assumeutxo_cs = nullptr; |
| 189 | } |
| 190 | |
| 191 | auto [init_status, init_error] = CompleteChainstateInitialization(chainman, options); |
| 192 | if (init_status != ChainstateLoadStatus::SUCCESS) { |
| 193 | return {init_status, init_error}; |
| 194 | } |
| 195 | |
| 196 | // If a snapshot chainstate was fully validated by a background chainstate during |
| 197 | // the last run, detect it here and clean up the now-unneeded background |
| 198 | // chainstate. |
| 199 | // |
| 200 | // Why is this cleanup done here (on subsequent restart) and not just when the |
| 201 | // snapshot is actually validated? Because this entails unusual |
| 202 | // filesystem operations to move leveldb data directories around, and that seems |
| 203 | // too risky to do in the middle of normal runtime. |
| 204 | auto snapshot_completion{assumeutxo_cs |
| 205 | ? chainman.MaybeValidateSnapshot(validated_cs, *assumeutxo_cs) |
| 206 | : SnapshotCompletionResult::SKIPPED}; |
| 207 | |
| 208 | if (snapshot_completion == SnapshotCompletionResult::SKIPPED) { |