/Users/eugenesiegel/btc/bitcoin/src/node/chainstate.cpp
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | // Copyright (c) 2021-2022 The Bitcoin Core developers | 
| 2 |  | // Distributed under the MIT software license, see the accompanying | 
| 3 |  | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | 
| 4 |  |  | 
| 5 |  | #include <node/chainstate.h> | 
| 6 |  |  | 
| 7 |  | #include <arith_uint256.h> | 
| 8 |  | #include <chain.h> | 
| 9 |  | #include <coins.h> | 
| 10 |  | #include <consensus/params.h> | 
| 11 |  | #include <kernel/caches.h> | 
| 12 |  | #include <logging.h> | 
| 13 |  | #include <node/blockstorage.h> | 
| 14 |  | #include <sync.h> | 
| 15 |  | #include <threadsafety.h> | 
| 16 |  | #include <tinyformat.h> | 
| 17 |  | #include <txdb.h> | 
| 18 |  | #include <uint256.h> | 
| 19 |  | #include <util/fs.h> | 
| 20 |  | #include <util/signalinterrupt.h> | 
| 21 |  | #include <util/time.h> | 
| 22 |  | #include <util/translation.h> | 
| 23 |  | #include <validation.h> | 
| 24 |  |  | 
| 25 |  | #include <algorithm> | 
| 26 |  | #include <cassert> | 
| 27 |  | #include <vector> | 
| 28 |  |  | 
| 29 |  | using kernel::CacheSizes; | 
| 30 |  |  | 
| 31 |  | namespace node { | 
| 32 |  | // Complete initialization of chainstates after the initial call has been made | 
| 33 |  | // to ChainstateManager::InitializeChainstate(). | 
| 34 |  | static ChainstateLoadResult CompleteChainstateInitialization( | 
| 35 |  |     ChainstateManager& chainman, | 
| 36 |  |     const ChainstateLoadOptions& options) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) | 
| 37 | 51.2k | { | 
| 38 | 51.2k |     if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}}0; | 
| 39 |  |  | 
| 40 |  |     // LoadBlockIndex will load m_have_pruned if we've ever removed a | 
| 41 |  |     // block file from disk. | 
| 42 |  |     // Note that it also sets m_blockfiles_indexed based on the disk flag! | 
| 43 | 51.2k |     if (!chainman.LoadBlockIndex()) { | 
| 44 | 0 |         if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}}; | 
| 45 | 0 |         return {ChainstateLoadStatus::FAILURE, _("Error loading block database")}; | 
| 46 | 0 |     } | 
| 47 |  |  | 
| 48 | 51.2k |     if (!chainman.BlockIndex().empty() && | 
| 49 | 51.2k |             !chainman.m_blockman.LookupBlockIndex(chainman.GetConsensus().hashGenesisBlock)) { | 
| 50 |  |         // If the loaded chain has a wrong genesis, bail out immediately | 
| 51 |  |         // (we're likely using a testnet datadir, or the other way around). | 
| 52 | 0 |         return {ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB, _("Incorrect or no genesis block found. Wrong datadir for network?")}; | 
| 53 | 0 |     } | 
| 54 |  |  | 
| 55 |  |     // Check for changed -prune state.  What we are concerned about is a user who has pruned blocks | 
| 56 |  |     // in the past, but is now trying to run unpruned. | 
| 57 | 51.2k |     if (chainman.m_blockman.m_have_pruned && !options.prune0) { | 
| 58 | 0 |         return {ChainstateLoadStatus::FAILURE, _("You need to rebuild the database using -reindex to go back to unpruned mode.  This will redownload the entire blockchain")}; | 
| 59 | 0 |     } | 
| 60 |  |  | 
| 61 |  |     // At this point blocktree args are consistent with what's on disk. | 
| 62 |  |     // If we're not mid-reindex (based on disk + args), add a genesis block on disk | 
| 63 |  |     // (otherwise we use the one already on disk). | 
| 64 |  |     // This is called again in ImportBlocks after the reindex completes. | 
| 65 | 51.2k |     if (chainman.m_blockman.m_blockfiles_indexed && !chainman.ActiveChainstate().LoadGenesisBlock()) { | 
| 66 | 0 |         return {ChainstateLoadStatus::FAILURE, _("Error initializing block database")}; | 
| 67 | 0 |     } | 
| 68 |  |  | 
| 69 | 51.2k |     auto is_coinsview_empty = [&](Chainstate* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { | 
| 70 | 51.2k |         return options.wipe_chainstate_db || chainstate->CoinsTip().GetBestBlock().IsNull(); | 
| 71 | 51.2k |     }; | 
| 72 |  |  | 
| 73 | 51.2k |     assert(chainman.m_total_coinstip_cache > 0); | 
| 74 | 51.2k |     assert(chainman.m_total_coinsdb_cache > 0); | 
| 75 |  |  | 
| 76 |  |     // If running with multiple chainstates, limit the cache sizes with a | 
| 77 |  |     // discount factor. If discounted the actual cache size will be | 
| 78 |  |     // recalculated by `chainman.MaybeRebalanceCaches()`. The discount factor | 
| 79 |  |     // is conservatively chosen such that the sum of the caches does not exceed | 
| 80 |  |     // the allowable amount during this temporary initialization state. | 
| 81 | 51.2k |     double init_cache_fraction = chainman.GetAll().size() > 1 ? 0.20: 1.0; | 
| 82 |  |  | 
| 83 |  |     // At this point we're either in reindex or we've loaded a useful | 
| 84 |  |     // block tree into BlockIndex()! | 
| 85 |  |  | 
| 86 | 51.2k |     for (Chainstate* chainstate : chainman.GetAll()) { | 
| 87 | 51.2k |         LogInfo("Initializing chainstate %s", chainstate->ToString());| Line | Count | Source |  | 356 | 51.2k | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 51.2k | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 88 |  |  | 
| 89 | 51.2k |         try { | 
| 90 | 51.2k |             chainstate->InitCoinsDB( | 
| 91 | 51.2k |                 /*cache_size_bytes=*/chainman.m_total_coinsdb_cache * init_cache_fraction, | 
| 92 | 51.2k |                 /*in_memory=*/options.coins_db_in_memory, | 
| 93 | 51.2k |                 /*should_wipe=*/options.wipe_chainstate_db); | 
| 94 | 51.2k |         } catch (dbwrapper_error& err) { | 
| 95 | 0 |             LogError("%s\n", err.what());| Line | Count | Source |  | 358 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 96 | 0 |             return {ChainstateLoadStatus::FAILURE, _("Error opening coins database")}; | 
| 97 | 0 |         } | 
| 98 |  |  | 
| 99 | 51.2k |         if (options.coins_error_cb) { | 
| 100 | 0 |             chainstate->CoinsErrorCatcher().AddReadErrCallback(options.coins_error_cb); | 
| 101 | 0 |         } | 
| 102 |  |  | 
| 103 |  |         // Refuse to load unsupported database format. | 
| 104 |  |         // This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate | 
| 105 | 51.2k |         if (chainstate->CoinsDB().NeedsUpgrade()) { | 
| 106 | 0 |             return {ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB, _("Unsupported chainstate database format found. " | 
| 107 | 0 |                                                                      "Please restart with -reindex-chainstate. This will " | 
| 108 | 0 |                                                                      "rebuild the chainstate database.")}; | 
| 109 | 0 |         } | 
| 110 |  |  | 
| 111 |  |         // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate | 
| 112 | 51.2k |         if (!chainstate->ReplayBlocks()) { | 
| 113 | 0 |             return {ChainstateLoadStatus::FAILURE, _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.")}; | 
| 114 | 0 |         } | 
| 115 |  |  | 
| 116 |  |         // The on-disk coinsdb is now in a good state, create the cache | 
| 117 | 51.2k |         chainstate->InitCoinsCache(chainman.m_total_coinstip_cache * init_cache_fraction); | 
| 118 | 51.2k |         assert(chainstate->CanFlushToDisk()); | 
| 119 |  |  | 
| 120 | 51.2k |         if (!is_coinsview_empty(chainstate)) { | 
| 121 |  |             // LoadChainTip initializes the chain based on CoinsTip()'s best block | 
| 122 | 51.2k |             if (!chainstate->LoadChainTip()) { | 
| 123 | 0 |                 return {ChainstateLoadStatus::FAILURE, _("Error initializing block database")}; | 
| 124 | 0 |             } | 
| 125 | 51.2k |             assert(chainstate->m_chain.Tip() != nullptr); | 
| 126 | 51.2k |         } | 
| 127 | 51.2k |     } | 
| 128 |  |  | 
| 129 | 51.2k |     auto chainstates{chainman.GetAll()}; | 
| 130 | 51.2k |     if (std::any_of(chainstates.begin(), chainstates.end(), | 
| 131 | 51.2k |                     [](const Chainstate* cs) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return cs->NeedsRedownload(); })) { | 
| 132 | 0 |         return {ChainstateLoadStatus::FAILURE, strprintf(_("Witness data for blocks after height %d requires validation. Please restart with -reindex."),| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 133 | 0 |                                                          chainman.GetConsensus().SegwitHeight)}; | 
| 134 | 51.2k |     }; | 
| 135 |  |  | 
| 136 |  |     // Now that chainstates are loaded and we're able to flush to | 
| 137 |  |     // disk, rebalance the coins caches to desired levels based | 
| 138 |  |     // on the condition of each chainstate. | 
| 139 | 51.2k |     chainman.MaybeRebalanceCaches(); | 
| 140 |  |  | 
| 141 | 51.2k |     return {ChainstateLoadStatus::SUCCESS, {}}; | 
| 142 | 51.2k | } | 
| 143 |  |  | 
| 144 |  | ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSizes& cache_sizes, | 
| 145 |  |                                     const ChainstateLoadOptions& options) | 
| 146 | 51.2k | { | 
| 147 | 51.2k |     if (!chainman.AssumedValidBlock().IsNull()) { | 
| 148 | 0 |         LogInfo("Assuming ancestors of block %s have valid signatures.", chainman.AssumedValidBlock().GetHex());| Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 149 | 51.2k |     } else { | 
| 150 | 51.2k |         LogInfo("Validating signatures for all blocks.");| Line | Count | Source |  | 356 | 51.2k | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 51.2k | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 151 | 51.2k |     } | 
| 152 | 51.2k |     LogInfo("Setting nMinimumChainWork=%s", chainman.MinimumChainWork().GetHex());| Line | Count | Source |  | 356 | 51.2k | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 51.2k | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 153 | 51.2k |     if (chainman.MinimumChainWork() < UintToArith256(chainman.GetConsensus().nMinimumChainWork)) { | 
| 154 | 0 |         LogPrintf("Warning: nMinimumChainWork set below default value of %s\n", chainman.GetConsensus().nMinimumChainWork.GetHex());| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 155 | 0 |     } | 
| 156 | 51.2k |     if (chainman.m_blockman.GetPruneTarget() == BlockManager::PRUNE_TARGET_MANUAL) { | 
| 157 | 0 |         LogInfo("Block pruning enabled. Use RPC call pruneblockchain(height) to manually prune block and undo files.");| Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 158 | 51.2k |     } else if (chainman.m_blockman.GetPruneTarget()) { | 
| 159 | 0 |         LogInfo("Prune configured to target %u MiB on disk for block and undo files.",| Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 160 | 0 |                 chainman.m_blockman.GetPruneTarget() / 1024 / 1024); | 
| 161 | 0 |     } | 
| 162 |  |  | 
| 163 | 51.2k |     LOCK(cs_main); | Line | Count | Source |  | 259 | 51.2k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 51.2k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 51.2k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 51.2k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 164 |  |  | 
| 165 | 51.2k |     chainman.m_total_coinstip_cache = cache_sizes.coins; | 
| 166 | 51.2k |     chainman.m_total_coinsdb_cache = cache_sizes.coins_db; | 
| 167 |  |  | 
| 168 |  |     // Load the fully validated chainstate. | 
| 169 | 51.2k |     chainman.InitializeChainstate(options.mempool); | 
| 170 |  |  | 
| 171 |  |     // Load a chain created from a UTXO snapshot, if any exist. | 
| 172 | 51.2k |     bool has_snapshot = chainman.DetectSnapshotChainstate(); | 
| 173 |  |  | 
| 174 | 51.2k |     if (has_snapshot && options.wipe_chainstate_db0) { | 
| 175 | 0 |         LogInfo("[snapshot] deleting snapshot chainstate due to reindexing");| Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 176 | 0 |         if (!chainman.DeleteSnapshotChainstate()) { | 
| 177 | 0 |             return {ChainstateLoadStatus::FAILURE_FATAL, Untranslated("Couldn't remove snapshot chainstate.")}; | 
| 178 | 0 |         } | 
| 179 | 0 |     } | 
| 180 |  |  | 
| 181 | 51.2k |     auto [init_status, init_error] = CompleteChainstateInitialization(chainman, options); | 
| 182 | 51.2k |     if (init_status != ChainstateLoadStatus::SUCCESS) { | 
| 183 | 0 |         return {init_status, init_error}; | 
| 184 | 0 |     } | 
| 185 |  |  | 
| 186 |  |     // If a snapshot chainstate was fully validated by a background chainstate during | 
| 187 |  |     // the last run, detect it here and clean up the now-unneeded background | 
| 188 |  |     // chainstate. | 
| 189 |  |     // | 
| 190 |  |     // Why is this cleanup done here (on subsequent restart) and not just when the | 
| 191 |  |     // snapshot is actually validated? Because this entails unusual | 
| 192 |  |     // filesystem operations to move leveldb data directories around, and that seems | 
| 193 |  |     // too risky to do in the middle of normal runtime. | 
| 194 | 51.2k |     auto snapshot_completion = chainman.MaybeCompleteSnapshotValidation(); | 
| 195 |  |  | 
| 196 | 51.2k |     if (snapshot_completion == SnapshotCompletionResult::SKIPPED) { | 
| 197 |  |         // do nothing; expected case | 
| 198 | 51.2k |     } else if (0 snapshot_completion == SnapshotCompletionResult::SUCCESS0) { | 
| 199 | 0 |         LogInfo("[snapshot] cleaning up unneeded background chainstate, then reinitializing");| Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
| 200 | 0 |         if (!chainman.ValidatedSnapshotCleanup()) { | 
| 201 | 0 |             return {ChainstateLoadStatus::FAILURE_FATAL, Untranslated("Background chainstate cleanup failed unexpectedly.")}; | 
| 202 | 0 |         } | 
| 203 |  |  | 
| 204 |  |         // Because ValidatedSnapshotCleanup() has torn down chainstates with | 
| 205 |  |         // ChainstateManager::ResetChainstates(), reinitialize them here without | 
| 206 |  |         // duplicating the blockindex work above. | 
| 207 | 0 |         assert(chainman.GetAll().empty()); | 
| 208 | 0 |         assert(!chainman.IsSnapshotActive()); | 
| 209 | 0 |         assert(!chainman.IsSnapshotValidated()); | 
| 210 |  |  | 
| 211 | 0 |         chainman.InitializeChainstate(options.mempool); | 
| 212 |  |  | 
| 213 |  |         // A reload of the block index is required to recompute setBlockIndexCandidates | 
| 214 |  |         // for the fully validated chainstate. | 
| 215 | 0 |         chainman.ActiveChainstate().ClearBlockIndexCandidates(); | 
| 216 |  | 
 | 
| 217 | 0 |         auto [init_status, init_error] = CompleteChainstateInitialization(chainman, options); | 
| 218 | 0 |         if (init_status != ChainstateLoadStatus::SUCCESS) { | 
| 219 | 0 |             return {init_status, init_error}; | 
| 220 | 0 |         } | 
| 221 | 0 |     } else { | 
| 222 | 0 |         return {ChainstateLoadStatus::FAILURE_FATAL, _( | 
| 223 | 0 |            "UTXO snapshot failed to validate. " | 
| 224 | 0 |            "Restart to resume normal initial block download, or try loading a different snapshot.")}; | 
| 225 | 0 |     } | 
| 226 |  |  | 
| 227 | 51.2k |     return {ChainstateLoadStatus::SUCCESS, {}}; | 
| 228 | 51.2k | } | 
| 229 |  |  | 
| 230 |  | ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const ChainstateLoadOptions& options) | 
| 231 | 51.2k | { | 
| 232 | 51.2k |     auto is_coinsview_empty = [&](Chainstate* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { | 
| 233 | 51.2k |         return options.wipe_chainstate_db || chainstate->CoinsTip().GetBestBlock().IsNull(); | 
| 234 | 51.2k |     }; | 
| 235 |  |  | 
| 236 | 51.2k |     LOCK(cs_main); | Line | Count | Source |  | 259 | 51.2k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 51.2k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 51.2k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 51.2k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 237 |  |  | 
| 238 | 51.2k |     for (Chainstate* chainstate : chainman.GetAll()) { | 
| 239 | 51.2k |         if (!is_coinsview_empty(chainstate)) { | 
| 240 | 51.2k |             const CBlockIndex* tip = chainstate->m_chain.Tip(); | 
| 241 | 51.2k |             if (tip && tip->nTime > GetTime() + MAX_FUTURE_BLOCK_TIME) { | 
| 242 | 0 |                 return {ChainstateLoadStatus::FAILURE, _("The block database contains a block which appears to be from the future. " | 
| 243 | 0 |                                                          "This may be due to your computer's date and time being set incorrectly. " | 
| 244 | 0 |                                                          "Only rebuild the block database if you are sure that your computer's date and time are correct")}; | 
| 245 | 0 |             } | 
| 246 |  |  | 
| 247 | 51.2k |             VerifyDBResult result = CVerifyDB(chainman.GetNotifications()).VerifyDB( | 
| 248 | 51.2k |                 *chainstate, chainman.GetConsensus(), chainstate->CoinsDB(), | 
| 249 | 51.2k |                 options.check_level, | 
| 250 | 51.2k |                 options.check_blocks); | 
| 251 | 51.2k |             switch (result) { | 
| 252 | 51.2k |             case VerifyDBResult::SUCCESS: | 
| 253 | 51.2k |             case VerifyDBResult::SKIPPED_MISSING_BLOCKS: | 
| 254 | 51.2k |                 break; | 
| 255 | 0 |             case VerifyDBResult::INTERRUPTED: | 
| 256 | 0 |                 return {ChainstateLoadStatus::INTERRUPTED, _("Block verification was interrupted")}; | 
| 257 | 0 |             case VerifyDBResult::CORRUPTED_BLOCK_DB: | 
| 258 | 0 |                 return {ChainstateLoadStatus::FAILURE, _("Corrupted block database detected")}; | 
| 259 | 0 |             case VerifyDBResult::SKIPPED_L3_CHECKS: | 
| 260 | 0 |                 if (options.require_full_verification) { | 
| 261 | 0 |                     return {ChainstateLoadStatus::FAILURE_INSUFFICIENT_DBCACHE, _("Insufficient dbcache for block verification")}; | 
| 262 | 0 |                 } | 
| 263 | 0 |                 break; | 
| 264 | 51.2k |             } // no default case, so the compiler can warn about missing cases | 
| 265 | 51.2k |         } | 
| 266 | 51.2k |     } | 
| 267 |  |  | 
| 268 | 51.2k |     return {ChainstateLoadStatus::SUCCESS, {}}; | 
| 269 | 51.2k | } | 
| 270 |  | } // namespace node |