Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
6251bool ChainstateManager::DeleteChainstate(Chainstate& chainstate)6252{6253AssertLockHeld(::cs_main);6254assert(!chainstate.m_coins_views);6255const fs::path db_path{chainstate.StoragePath()};6256if (!DeleteCoinsDBFromDisk(db_path, /*is_snapshot=*/bool{chainstate.m_from_snapshot_blockhash})) {6257LogError("Deletion of %s failed. Please remove it manually to continue reindexing.",6258fs::PathToString(db_path));6259return false;6260}6261std::unique_ptr<Chainstate> prev_chainstate{Assert(RemoveChainstate(chainstate))};6262Chainstate& curr_chainstate{CurrentChainstate()};6263assert(!prev_chainstate->m_mempool || prev_chainstate->m_mempool->size() == 0);6264assert(!curr_chainstate.m_mempool);6265std::swap(curr_chainstate.m_mempool, prev_chainstate->m_mempool);6266return true;6267}6269ChainstateRole Chainstate::GetRole() const6270{6271return ChainstateRole{.validated = m_assumeutxo == Assumeutxo::VALIDATED, .historical = bool{m_target_blockhash}};6272}6274void ChainstateManager::RecalculateBestHeader()6275{6276AssertLockHeld(cs_main);6277m_best_header = ActiveChain().Tip();6278for (auto& entry : m_blockman.m_block_index) {6279if (!(entry.second.nStatus & BLOCK_FAILED_VALID) && m_best_header->nChainWork < entry.second.nChainWork) {6280m_best_header = &entry.second;6281}6282}6283}6285std::optional<int> ChainstateManager::BlocksAheadOfTip() const6286{6287LOCK(::cs_main);6288const CBlockIndex* best_header{m_best_header};6289const CBlockIndex* tip{ActiveChain().Tip()};6290// Only consider headers that extend the active tip; ignore competing branches.6291if (best_header && tip && best_header->nChainWork > tip->nChainWork &&6292best_header->GetAncestor(tip->nHeight) == tip) {6293return best_header->nHeight - tip->nHeight;6294}6295return std::nullopt;6296}6298bool ChainstateManager::ValidatedSnapshotCleanup(Chainstate& validated_cs, Chainstate& unvalidated_cs)6299{6300AssertLockHeld(::cs_main);6301if (unvalidated_cs.m_assumeutxo != Assumeutxo::VALIDATED) {6302// No need to clean up.6303return false;6304}6306const fs::path validated_path{validated_cs.StoragePath()};6307const fs::path assumed_valid_path{unvalidated_cs.StoragePath()};6308const fs::path delete_path{validated_path + "_todelete"};6310// Since we're going to be moving around the underlying leveldb filesystem content6311// for each chainstate, make sure that the chainstates (and their constituent6312// CoinsViews members) have been destructed first.6313//6314// The caller of this method will be responsible for reinitializing chainstates6315// if they want to continue operation.6316this->ResetChainstates();6317assert(this->m_chainstates.size() == 0);6319LogInfo("[snapshot] deleting background chainstate directory (now unnecessary) (%s)",6320fs::PathToString(validated_path));6322auto rename_failed_abort = [this](6323fs::path p_old,6324fs::path p_new,6325const fs::filesystem_error& err) {6326LogError("[snapshot] Error renaming path (%s) -> (%s): %s\n",6327fs::PathToString(p_old), fs::PathToString(p_new), err.what());6328GetNotifications().fatalError(strprintf(_(6329"Rename of '%s' -> '%s' failed. "6330"Cannot clean up the background chainstate leveldb directory."),6331fs::PathToString(p_old), fs::PathToString(p_new)));6332};6334try {6335fs::rename(validated_path, delete_path);6336} catch (const fs::filesystem_error& e) {6337rename_failed_abort(validated_path, delete_path, e);6338throw;6339}6341LogInfo("[snapshot] moving snapshot chainstate (%s) to "6342"default chainstate directory (%s)",6343fs::PathToString(assumed_valid_path), fs::PathToString(validated_path));6345try {6346fs::rename(assumed_valid_path, validated_path);6347} catch (const fs::filesystem_error& e) {6348rename_failed_abort(assumed_valid_path, validated_path, e);6349throw;6350}6352if (!DeleteCoinsDBFromDisk(delete_path, /*is_snapshot=*/false)) {6353// No need to FatalError because once the unneeded bg chainstate data is6354// moved, it will not interfere with subsequent initialization.6355LogWarning("Deletion of %s failed. Please remove it manually, as the "6356"directory is now unnecessary.",6357fs::PathToString(delete_path));6358} else {6359LogInfo("[snapshot] deleted background chainstate directory (%s)",6360fs::PathToString(validated_path));6361}6362return true;6363}6365std::pair<int, int> Chainstate::GetPruneRange(int last_height_can_prune) const6366{6367if (m_chain.Height() <= 0) {6368return {0, 0};6369}6370int prune_start{0};6372if (m_from_snapshot_blockhash && m_assumeutxo != Assumeutxo::VALIDATED) {6373// Only prune blocks _after_ the snapshot if this is a snapshot chain6374// that has not been fully validated yet. The earlier blocks need to be6375// kept to validate the snapshot6376prune_start = Assert(SnapshotBase())->nHeight + 1;6377}6379int max_prune = std::max<int>(63800, m_chain.Height() - static_cast<int>(MIN_BLOCKS_TO_KEEP));6382// last block to prune is the lesser of (caller-specified height, MIN_BLOCKS_TO_KEEP from the tip)6383//6384// While you might be tempted to prune the background chainstate more6385// aggressively (i.e. fewer MIN_BLOCKS_TO_KEEP), this won't work with index6386// building - specifically blockfilterindex requires undo data, and if6387// we don't maintain this trailing window, we hit indexing failures.6388int prune_end = std::min(last_height_can_prune, max_prune);6390return {prune_start, prune_end};6391}6393std::optional<std::pair<const CBlockIndex*, const CBlockIndex*>> ChainstateManager::GetHistoricalBlockRange() const6394{6395const Chainstate* chainstate{HistoricalChainstate()};6396if (!chainstate) return {};6397return std::make_pair(chainstate->m_chain.Tip(), chainstate->TargetBlock());6398}6400util::Result<void> ChainstateManager::ActivateBestChains()6401{6402// We can't hold cs_main during ActivateBestChain even though we're accessing6403// the chainman unique_ptrs since ABC requires us not to be holding cs_main, so retrieve6404// the relevant pointers before the ABC call.6405AssertLockNotHeld(cs_main);6406std::vector<Chainstate*> chainstates;6407{6408LOCK(GetMutex());6409chainstates.reserve(m_chainstates.size());6410for (const auto& chainstate : m_chainstates) {6411if (chainstate && chainstate->m_assumeutxo != Assumeutxo::INVALID && !chainstate->m_target_utxohash) {6412chainstates.push_back(chainstate.get());6413}6414}6415}6416for (Chainstate* chainstate : chainstates) {6417BlockValidationState state;6418if (!chainstate->ActivateBestChain(state, nullptr)) {6419LOCK(GetMutex());6420return util::Error{Untranslated(strprintf("%s Failed to connect best block (%s)", chainstate->ToString(), state.ToString()))};6421}6422}6423return {};6424}