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.
501if (pindex->nStatus & BLOCK_HAVE_DATA) {502AddUnlinkedBlock(pindex);503}504}505} else {506pindex->m_chain_tx_count = pindex->nTx;507}508}510if (pindex->nStatus & BLOCK_FAILED_CHILD) {511// BLOCK_FAILED_CHILD is deprecated, but may still exist on disk. Replace it with BLOCK_FAILED_VALID.512pindex->nStatus = (pindex->nStatus & ~BLOCK_FAILED_CHILD) | BLOCK_FAILED_VALID;513m_dirty_blockindex.insert(pindex);514}515if (!(pindex->nStatus & BLOCK_FAILED_VALID) && pindex->pprev && (pindex->pprev->nStatus & BLOCK_FAILED_VALID)) {516// All descendants of invalid blocks are invalid too.517pindex->nStatus |= BLOCK_FAILED_VALID;518m_dirty_blockindex.insert(pindex);519}521if (pindex->pprev) {522pindex->BuildSkip();523}524}526return true;527}529void BlockManager::WriteBlockIndexDB()530{531AssertLockHeld(::cs_main);532std::vector<std::pair<int, const CBlockFileInfo*>> vFiles;533vFiles.reserve(m_dirty_fileinfo.size());534for (std::set<int>::iterator it = m_dirty_fileinfo.begin(); it != m_dirty_fileinfo.end();) {535vFiles.emplace_back(*it, &m_blockfile_info[*it]);536m_dirty_fileinfo.erase(it++);537}538std::vector<const CBlockIndex*> vBlocks;539vBlocks.reserve(m_dirty_blockindex.size());540for (std::set<CBlockIndex*>::iterator it = m_dirty_blockindex.begin(); it != m_dirty_blockindex.end();) {541vBlocks.push_back(*it);542m_dirty_blockindex.erase(it++);543}544int max_blockfile{this->MaxBlockfileNum()};545m_block_tree_db->WriteBatchSync(vFiles, max_blockfile, vBlocks);546}548bool BlockManager::LoadBlockIndexDB(const std::optional<uint256>& snapshot_blockhash)549{550AssertLockHeld(::cs_main);551if (!LoadBlockIndex(snapshot_blockhash)) {552return false;553}554int max_blockfile_num{0};556// Load block file info557m_block_tree_db->ReadLastBlockFile(max_blockfile_num);558m_blockfile_info.resize(max_blockfile_num + 1);559LogInfo("Loading block index db: last block file = %i", max_blockfile_num);560for (int nFile = 0; nFile <= max_blockfile_num; nFile++) {561m_block_tree_db->ReadBlockFileInfo(nFile, m_blockfile_info[nFile]);562}563LogInfo("Loading block index db: last block file info: %s", m_blockfile_info[max_blockfile_num].ToString());564for (int nFile = max_blockfile_num + 1; true; nFile++) {565CBlockFileInfo info;566if (m_block_tree_db->ReadBlockFileInfo(nFile, info)) {567m_blockfile_info.push_back(info);568} else {569break;570}571}573// Check presence of blk files574LogInfo("Checking all blk files are present...");575std::set<int> setBlkDataFiles;576for (const auto& [_, block_index] : m_block_index) {577if (block_index.nStatus & BLOCK_HAVE_DATA) {578setBlkDataFiles.insert(block_index.nFile);579}580}581for (std::set<int>::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++) {582FlatFilePos pos(*it, 0);583if (OpenBlockFile(pos, /*fReadOnly=*/true).IsNull()) {584return false;585}586}588{589// Initialize the blockfile cursors.590for (size_t i = 0; i < m_blockfile_info.size(); ++i) {591const auto last_height_in_file = m_blockfile_info[i].nHeightLast;592m_blockfile_cursors[BlockfileTypeForHeight(last_height_in_file)] = {static_cast<int>(i), 0};593}594}596// Check whether we have ever pruned block & undo files597m_block_tree_db->ReadFlag("prunedblockfiles", m_have_pruned);598if (m_have_pruned) {599LogInfo("Loading block index db: Block files have previously been pruned");600}602// Check whether we need to continue reindexing603bool fReindexing = false;604m_block_tree_db->ReadReindexing(fReindexing);605if (fReindexing) m_blockfiles_indexed = false;607return true;608}610void BlockManager::ScanAndUnlinkAlreadyPrunedFiles()611{612AssertLockHeld(::cs_main);613int max_blockfile{this->MaxBlockfileNum()};614if (!m_have_pruned) {615return;616}618std::set<int> block_files_to_prune;619for (int file_number = 0; file_number < max_blockfile; file_number++) {620if (m_blockfile_info[file_number].nSize == 0) {621block_files_to_prune.insert(file_number);622}623}625UnlinkPrunedFiles(block_files_to_prune);626}628bool BlockManager::IsBlockPruned(const CBlockIndex& block) const629{630AssertLockHeld(::cs_main);631return m_have_pruned && !(block.nStatus & BLOCK_HAVE_DATA) && (block.nTx > 0);632}634const CBlockIndex& BlockManager::GetFirstBlock(const CBlockIndex& upper_block, uint32_t status_mask, const CBlockIndex* lower_block) const635{636AssertLockHeld(::cs_main);637const CBlockIndex* last_block = &upper_block;638assert((last_block->nStatus & status_mask) == status_mask); // 'upper_block' must satisfy the status mask639while (last_block->pprev && ((last_block->pprev->nStatus & status_mask) == status_mask)) {640if (lower_block) {641// Return if we reached the lower_block642if (last_block == lower_block) return *lower_block;643// if range was surpassed, means that 'lower_block' is not part of the 'upper_block' chain644// and so far this is not allowed.645assert(last_block->nHeight >= lower_block->nHeight);646}647last_block = last_block->pprev;648}649assert(last_block != nullptr);650return *last_block;651}653bool BlockManager::CheckBlockDataAvailability(const CBlockIndex& upper_block, const CBlockIndex& lower_block, BlockStatus block_status)654{655if (!(upper_block.nStatus & block_status)) return false;656const auto& first_block = GetFirstBlock(upper_block, block_status, &lower_block);657// Special case: the genesis block has no undo data658if (block_status & BLOCK_HAVE_UNDO && lower_block.nHeight == 0 && first_block.nHeight == 1) {659// This might indicate missing data, or it could simply reflect the expected absence of undo data for the genesis block.660// To distinguish between the two, check if all required block data *except* undo is available up to the genesis block.661BlockStatus flags{block_status & ~BLOCK_HAVE_UNDO};662return first_block.pprev && first_block.pprev->nStatus & flags;663}664return &first_block == &lower_block;665}667// If we're using -prune with -reindex, then delete block files that will be ignored by the668// reindex. Since reindexing works by starting at block file 0 and looping until a blockfile669// is missing, do the same here to delete any later block files after a gap. Also delete all670// rev files since they'll be rewritten by the reindex anyway. This ensures that m_blockfile_info671// is in sync with what's actually on disk by the time we start downloading, so that pruning672// works correctly.673void BlockManager::CleanupBlockRevFiles() const674{675std::map<std::string, fs::path> mapBlockFiles;677// Glob all blk?????.dat and rev?????.dat files from the blocks directory.678// Remove the rev files immediately and insert the blk file paths into an679// ordered map keyed by block file index.680LogInfo("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune");681for (fs::directory_iterator it(m_opts.blocks_dir); it != fs::directory_iterator(); it++) {682const std::string path = fs::PathToString(it->path().filename());683if (fs::is_regular_file(*it) &&684path.length() == 12 &&685path.ends_with(".dat"))686{687if (path.starts_with("blk")) {688mapBlockFiles[path.substr(3, 5)] = it->path();689} else if (path.starts_with("rev")) {690remove(it->path());691}692}693}695// Remove all block files that aren't part of a contiguous set starting at696// zero by walking the ordered map (keys are block file indices) by697// keeping a separate counter. Once we hit a gap (or if 0 doesn't exist)698// start removing block files.699int nContigCounter = 0;700for (const std::pair<const std::string, fs::path>& item : mapBlockFiles) {701if (LocaleIndependentAtoi<int>(item.first) == nContigCounter) {702nContigCounter++;703continue;704}705remove(item.second);706}707}709CBlockFileInfo* BlockManager::GetBlockFileInfo(size_t n)710{711AssertLockHeld(::cs_main);712return &m_blockfile_info.at(n);713}715bool BlockManager::ReadBlockUndo(CBlockUndo& blockundo, const CBlockIndex& index) const716{717const FlatFilePos pos{WITH_LOCK(::cs_main, return index.GetUndoPos())};719// Open history file to read720AutoFile file{OpenUndoFile(pos, true)};721if (file.IsNull()) {722LogError("OpenUndoFile failed for %s while reading block undo", pos.ToString());723return false;724}725BufferedReader filein{std::move(file)};727try {728// Read block729HashVerifier verifier{filein}; // Use HashVerifier, as reserializing may lose data, c.f. commit d3424243731verifier << index.pprev->GetBlockHash();732verifier >> blockundo;734uint256 hashChecksum;735filein >> hashChecksum;737// Verify checksum738if (hashChecksum != verifier.GetHash()) {739LogError("Checksum mismatch at %s while reading block undo", pos.ToString());740return false;741}742} catch (const std::exception& e) {743LogError("Deserialize or I/O error - %s at %s while reading block undo", e.what(), pos.ToString());744return false;745}747return true;748}750bool BlockManager::FlushUndoFile(int block_file, bool finalize)