Repository: bitcoin/bitcoin
File: src/node/chainstate.cpp (C++)

Code before:
#include <atomic>
#include <cassert>
#include <limits>
#include <memory>
#include <vector>

namespace node {
// Complete initialization of chainstates after the initial call has been made
// to ChainstateManager::InitializeChainstate().
static ChainstateLoadResult CompleteChainstateInitialization(
    ChainstateManager& chainman,
    const CacheSizes& cache_sizes,
    const ChainstateLoadOptions& options) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
    auto& pblocktree{chainman.m_blockman.m_block_tree_db};
    // new BlockTreeDB tries to delete the existing file, which
    // fails if it's still open from the previous loop. Close it first:
    pblocktree.reset();
    try {
        pblocktree = std::make_unique<BlockTreeDB>(DBParams{
            .path = chainman.m_options.datadir / "blocks" / "index",
            .cache_bytes = static_cast<size_t>(cache_sizes.block_tree_db),
            .memory_only = options.block_tree_db_in_memory,
            .wipe_data = options.wipe_block_tree_db,
            .options = chainman.m_options.block_tree_db});
    } catch (dbwrapper_error&) {
        return {ChainstateLoadStatus::FAILURE, _("Error opening block database")};
    }

    if (options.wipe_block_tree_db) {
        pblocktree->WriteReindexing(true);
        chainman.m_blockman.m_blockfiles_indexed = false;
        //If we're reindexing in prune mode, wipe away unusable block files and all undo data files
        if (options.prune) {
            chainman.m_blockman.CleanupBlockRevFiles();
        }
    }

    if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};

    // LoadBlockIndex will load m_have_pruned if we've ever removed a
    // block file from disk.
    // Note that it also sets m_blockfiles_indexed based on the disk flag!
    if (!chainman.LoadBlockIndex()) {
        if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};
        return {ChainstateLoadStatus::FAILURE, _("Error loading block database")};
    }

    if (!chainman.BlockIndex().empty() &&
            !chainman.m_blockman.LookupBlockIndex(chainman.GetConsensus().hashGenesisBlock)) {
        // If the loaded chain has a wrong genesis, bail out immediately

Review comment (bug):
Note: instantiating a `CDBWrapper` can throw other errors such as a `fs::filesystem_error` from [here](https://github.com/bitcoin/bitcoin/blob/62e4516722115c2d5aeb6c197abc73ca7c078b23/src/dbwrapper.cpp#L240), but I suppose that is not something the user can recover from with a reindex so not catching that here seems correct.

I think it logging the `dbwrapper_error` would be useful though?

<details>
<summary>git diff on 1bec418e77</summary>

```diff
diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp
index 76094105fa..b9c3981910 100644
--- a/src/node/chainstate.cpp
+++ b/src/node/chainstate.cpp
@@ -48,8 +48,10 @@ static ChainstateLoadResult CompleteChainstateInitialization(
             .memory_only = options.block_tree_db_in_memory,
             .wipe_data = options.wipe_block_tree_db,
             .options = chainman.m_options.block_tree_db});
-    } catch (dbwrapper_error&) {
-        return {ChainstateLoadStatus::FAILURE, _("Error opening block database")};
+    } catch (dbwrapper_error& err) {
+        auto msg{_("Error opening block database")};
+        LogError("%s: %s\n", msg.original, err.what());
+        return {ChainstateLoadStatus::FAILURE, msg};
     }
 
     if (options.wipe_block_tree_db) {
@@ -116,8 +118,10 @@ static ChainstateLoadResult CompleteChainstateInitialization(
                 /*cache_size_bytes=*/chainman.m_total_coinsdb_cache * init_cache_fraction,
                 /*in_memory=*/options.coins_db_in_memory,
                 /*should_wipe=*/options.wipe_chainstate_db);
-        } catch (dbwrapper_error&) {
-            return {ChainstateLoadStatus::FAILURE, _("Error opening coins database")};
+        } catch (dbwrapper_error& err) {
+            auto msg{_("Error opening coins database")};
+            LogError("%s: %s\n", msg.original, err.what());
+            return {ChainstateLoadStatus::FAILURE, msg};
         }
 
         if (options.coins_error_cb) {

```
</details>


Code after:
#include <atomic>
#include <cassert>
#include <limits>
#include <memory>
#include <vector>

namespace node {
// Complete initialization of chainstates after the initial call has been made
// to ChainstateManager::InitializeChainstate().
static ChainstateLoadResult CompleteChainstateInitialization(
    ChainstateManager& chainman,
    const CacheSizes& cache_sizes,
    const ChainstateLoadOptions& options) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
    auto& pblocktree{chainman.m_blockman.m_block_tree_db};
    // new BlockTreeDB tries to delete the existing file, which
    // fails if it's still open from the previous loop. Close it first:
    pblocktree.reset();
    try {
        pblocktree = std::make_unique<BlockTreeDB>(DBParams{
            .path = chainman.m_options.datadir / "blocks" / "index",
            .cache_bytes = static_cast<size_t>(cache_sizes.block_tree_db),
            .memory_only = options.block_tree_db_in_memory,
            .wipe_data = options.wipe_block_tree_db,
            .options = chainman.m_options.block_tree_db});
    } catch (dbwrapper_error& err) {
        LogError("%s\n", err.what());
        return {ChainstateLoadStatus::FAILURE, _("Error opening block database")};
    }

    if (options.wipe_block_tree_db) {
        pblocktree->WriteReindexing(true);
        chainman.m_blockman.m_blockfiles_indexed = false;
        //If we're reindexing in prune mode, wipe away unusable block files and all undo data files
        if (options.prune) {
            chainman.m_blockman.CleanupBlockRevFiles();
        }
    }

    if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};

    // LoadBlockIndex will load m_have_pruned if we've ever removed a
    // block file from disk.
    // Note that it also sets m_blockfiles_indexed based on the disk flag!
    if (!chainman.LoadBlockIndex()) {
        if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};
        return {ChainstateLoadStatus::FAILURE, _("Error loading block database")};
    }

    if (!chainman.BlockIndex().empty() &&
            !chainman.m_blockman.LookupBlockIndex(chainman.GetConsensus().hashGenesisBlock)) {