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

Code before:
{
    const CBlockIndex* base = this->GetSnapshotBaseBlock();
    return base ? std::make_optional(base->nHeight) : std::nullopt;
}

bool ChainstateManager::ValidatedSnapshotCleanup()
{
    AssertLockHeld(::cs_main);
    auto get_storage_path = [](auto& chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) -> std::optional<fs::path> {
        if (!(chainstate && chainstate->HasCoinsViews())) {
            return {};
        }
        return chainstate->CoinsDB().StoragePath();
    };
    std::optional<fs::path> ibd_chainstate_path_maybe = get_storage_path(m_ibd_chainstate);
    std::optional<fs::path> snapshot_chainstate_path_maybe = get_storage_path(m_snapshot_chainstate);

    if (!this->IsSnapshotValidated()) {
        // No need to clean up.
        return false;
    }
    // If either path doesn't exist, that means at least one of the chainstates
    // is in-memory, in which case we can't do on-disk cleanup. You'd better be
    // in a unittest!
    if (!ibd_chainstate_path_maybe || !snapshot_chainstate_path_maybe) {
        LogPrintf("[snapshot] snapshot chainstate cleanup cannot happen with "
                  "in-memory chainstates. You are testing, right?\n");
        return false;
    }

    const auto& snapshot_chainstate_path = *snapshot_chainstate_path_maybe;
    const auto& ibd_chainstate_path = *ibd_chainstate_path_maybe;

    // Since we're going to be moving around the underlying leveldb filesystem content
    // for each chainstate, make sure that the chainstates (and their constituent
    // CoinsViews members) have been destructed first.
    //
    // The caller of this method will be responsible for reinitializing chainstates
    // if they want to continue operation.
    this->ResetChainstates();

    // No chainstates should be considered usable.
    assert(this->GetAll().size() == 0);

    LogPrintf("[snapshot] deleting background chainstate directory (now unnecessary) (%s)\n",
              fs::PathToString(ibd_chainstate_path));

    fs::path tmp_old{ibd_chainstate_path + "_todelete"};

    auto rename_failed_abort = [this](
                                   fs::path p_old,

Review comment (suggestion):
I've been looking the logic over again and think it might be a good idea to call `NotifyHeaderTip` here too. It basically tracks along `m_best_header`, but with the current code will only notify when processing the next block or header. 

Code after:
    }
    return (this != &m_chainman.ActiveChainstate()) ?
               ChainstateRole::BACKGROUND :
               ChainstateRole::ASSUMEDVALID;
}

const CBlockIndex* ChainstateManager::GetSnapshotBaseBlock() const
{
    return m_active_chainstate ? m_active_chainstate->SnapshotBase() : nullptr;
}

std::optional<int> ChainstateManager::GetSnapshotBaseHeight() const
{
    const CBlockIndex* base = this->GetSnapshotBaseBlock();
    return base ? std::make_optional(base->nHeight) : std::nullopt;
}

void ChainstateManager::RecalculateBestHeader()
{
    AssertLockHeld(cs_main);
    m_best_header = ActiveChain().Tip();
    for (auto& entry : m_blockman.m_block_index) {
        if (!(entry.second.nStatus & BLOCK_FAILED_MASK) && m_best_header->nChainWork < entry.second.nChainWork) {
            m_best_header = &entry.second;
        }
    }
}

bool ChainstateManager::ValidatedSnapshotCleanup()
{
    AssertLockHeld(::cs_main);
    auto get_storage_path = [](auto& chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) -> std::optional<fs::path> {
        if (!(chainstate && chainstate->HasCoinsViews())) {
            return {};
        }
        return chainstate->CoinsDB().StoragePath();
    };
    std::optional<fs::path> ibd_chainstate_path_maybe = get_storage_path(m_ibd_chainstate);
    std::optional<fs::path> snapshot_chainstate_path_maybe = get_storage_path(m_snapshot_chainstate);

    if (!this->IsSnapshotValidated()) {
        // No need to clean up.
        return false;
    }
    // If either path doesn't exist, that means at least one of the chainstates
    // is in-memory, in which case we can't do on-disk cleanup. You'd better be
    // in a unittest!
    if (!ibd_chainstate_path_maybe || !snapshot_chainstate_path_maybe) {
        LogPrintf("[snapshot] snapshot chainstate cleanup cannot happen with "
                  "in-memory chainstates. You are testing, right?\n");
        return false;