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

Code before:
        // and that we should restore the active chainstate caches to their original size).
        //
        current_coinsdb_cache_size = this->ActiveChainstate().m_coinsdb_cache_size_bytes;
        current_coinstip_cache_size = this->ActiveChainstate().m_coinstip_cache_size_bytes;

        // Temporarily resize the active coins cache to make room for the newly-created
        // snapshot chain.
        this->ActiveChainstate().ResizeCoinsCaches(
            static_cast<size_t>(current_coinstip_cache_size * IBD_CACHE_PERC),
            static_cast<size_t>(current_coinsdb_cache_size * IBD_CACHE_PERC));
    }

    auto snapshot_chainstate = WITH_LOCK(::cs_main,
        return std::make_unique<Chainstate>(
            /*mempool=*/nullptr, m_blockman, *this, base_blockhash));

    {
        LOCK(::cs_main);
        snapshot_chainstate->InitCoinsDB(
            static_cast<size_t>(current_coinsdb_cache_size * SNAPSHOT_CACHE_PERC),
            in_memory, false, "chainstate");
        snapshot_chainstate->InitCoinsCache(
            static_cast<size_t>(current_coinstip_cache_size * SNAPSHOT_CACHE_PERC));
    }

    auto cleanup_bad_snapshot = [&](const char* reason) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
        this->MaybeRebalanceCaches();

        // PopulateAndValidateSnapshot can return (in error) before the leveldb datadir
        // has been created, so only attempt removal if we got that far.
        if (auto snapshot_datadir = node::FindSnapshotChainstateDir(m_options.datadir)) {
            // We have to destruct leveldb::DB in order to release the db lock, otherwise
            // DestroyDB() (in DeleteCoinsDBFromDisk()) will fail. See `leveldb::~DBImpl()`.
            // Destructing the chainstate (and so resetting the coinsviews object) does this.
            snapshot_chainstate.reset();
            bool removed = DeleteCoinsDBFromDisk(*snapshot_datadir, /*is_snapshot=*/true);
            if (!removed) {
                GetNotifications().fatalError(strprintf(_("Failed to remove snapshot chainstate dir (%s). "
                    "Manually remove it before restarting.\n"), fs::PathToString(*snapshot_datadir)));
            }
        }
        return util::Error{_(reason)};
    };

    if (!this->PopulateAndValidateSnapshot(*snapshot_chainstate, coins_file, metadata)) {
        LOCK(::cs_main);
        return cleanup_bad_snapshot("population failed");
    }

    LOCK(::cs_main);  // cs_main required for rest of snapshot activation.


Review comment (suggestion):
In commit "rpc: Use untranslated error strings in loadtxoutset" (fa5b8920be041380fbfa4c7b443918637423d7a0)

Not important, but you could change this from `bilingual_str&&` to just `bilingual_str` so it is simpler, and function can be called naturally with both lvalues and rvalues, not just rvalues. Rvalues will be moved in any case.

Code after:
        // and that we should restore the active chainstate caches to their original size).
        //
        current_coinsdb_cache_size = this->ActiveChainstate().m_coinsdb_cache_size_bytes;
        current_coinstip_cache_size = this->ActiveChainstate().m_coinstip_cache_size_bytes;

        // Temporarily resize the active coins cache to make room for the newly-created
        // snapshot chain.
        this->ActiveChainstate().ResizeCoinsCaches(
            static_cast<size_t>(current_coinstip_cache_size * IBD_CACHE_PERC),
            static_cast<size_t>(current_coinsdb_cache_size * IBD_CACHE_PERC));
    }

    auto snapshot_chainstate = WITH_LOCK(::cs_main,
        return std::make_unique<Chainstate>(
            /*mempool=*/nullptr, m_blockman, *this, base_blockhash));

    {
        LOCK(::cs_main);
        snapshot_chainstate->InitCoinsDB(
            static_cast<size_t>(current_coinsdb_cache_size * SNAPSHOT_CACHE_PERC),
            in_memory, false, "chainstate");
        snapshot_chainstate->InitCoinsCache(
            static_cast<size_t>(current_coinstip_cache_size * SNAPSHOT_CACHE_PERC));
    }

    auto cleanup_bad_snapshot = [&](bilingual_str&& reason) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
        this->MaybeRebalanceCaches();

        // PopulateAndValidateSnapshot can return (in error) before the leveldb datadir
        // has been created, so only attempt removal if we got that far.
        if (auto snapshot_datadir = node::FindSnapshotChainstateDir(m_options.datadir)) {
            // We have to destruct leveldb::DB in order to release the db lock, otherwise
            // DestroyDB() (in DeleteCoinsDBFromDisk()) will fail. See `leveldb::~DBImpl()`.
            // Destructing the chainstate (and so resetting the coinsviews object) does this.
            snapshot_chainstate.reset();
            bool removed = DeleteCoinsDBFromDisk(*snapshot_datadir, /*is_snapshot=*/true);
            if (!removed) {
                GetNotifications().fatalError(strprintf(_("Failed to remove snapshot chainstate dir (%s). "
                    "Manually remove it before restarting.\n"), fs::PathToString(*snapshot_datadir)));
            }
        }
        return util::Error{std::move(reason)};
    };

    if (!this->PopulateAndValidateSnapshot(*snapshot_chainstate, coins_file, metadata)) {
        LOCK(::cs_main);
        return cleanup_bad_snapshot(Untranslated("population failed"));
    }

    LOCK(::cs_main);  // cs_main required for rest of snapshot activation.