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.
751{752FlatFilePos undo_pos_old(block_file, m_blockfile_info[block_file].nUndoSize);753if (!m_undo_file_seq.Flush(undo_pos_old, finalize)) {754m_opts.notifications.flushError(_("Flushing undo file to disk failed. This is likely the result of an I/O error."));755return false;756}757return true;758}760bool BlockManager::FlushBlockFile(int blockfile_num, bool fFinalize, bool finalize_undo)761{762AssertLockHeld(::cs_main);763bool success = true;765if (m_blockfile_info.size() < 1) {766// Return if we haven't loaded any blockfiles yet. This happens during767// chainstate init, when we call ChainstateManager::MaybeRebalanceCaches() (which768// then calls FlushStateToDisk()), resulting in a call to this function before we769// have populated `m_blockfile_info` via LoadBlockIndexDB().770return true;771}772assert(static_cast<int>(m_blockfile_info.size()) > blockfile_num);774FlatFilePos block_pos_old(blockfile_num, m_blockfile_info[blockfile_num].nSize);775if (!m_block_file_seq.Flush(block_pos_old, fFinalize)) {776m_opts.notifications.flushError(_("Flushing block file to disk failed. This is likely the result of an I/O error."));777success = false;778}779// we do not always flush the undo file, as the chain tip may be lagging behind the incoming blocks,780// e.g. during IBD or a sync after a node going offline781if (!fFinalize || finalize_undo) {782if (!FlushUndoFile(blockfile_num, finalize_undo)) {783success = false;784}785}786return success;787}789BlockfileType BlockManager::BlockfileTypeForHeight(int height)790{791if (!m_snapshot_height) {792return BlockfileType::NORMAL;793}794return (height >= *m_snapshot_height) ? BlockfileType::ASSUMED : BlockfileType::NORMAL;795}797bool BlockManager::FlushChainstateBlockFile(int tip_height)798{799AssertLockHeld(::cs_main);800auto& cursor = m_blockfile_cursors[BlockfileTypeForHeight(tip_height)];801// If the cursor does not exist, it means an assumeutxo snapshot is loaded,802// but no blocks past the snapshot height have been written yet, so there803// is no data associated with the chainstate, and it is safe not to flush.804if (cursor) {805return FlushBlockFile(cursor->file_num, /*fFinalize=*/false, /*finalize_undo=*/false);806}807// No need to log warnings in this case.808return true;809}811uint64_t BlockManager::CalculateCurrentUsage()812{813AssertLockHeld(::cs_main);814uint64_t retval = 0;815for (const CBlockFileInfo& file : m_blockfile_info) {816retval += file.nSize + file.nUndoSize;817}818return retval;819}821void BlockManager::UnlinkPrunedFiles(const std::set<int>& setFilesToPrune) const822{823std::error_code ec;824for (std::set<int>::iterator it = setFilesToPrune.begin(); it != setFilesToPrune.end(); ++it) {825FlatFilePos pos(*it, 0);826const bool removed_blockfile{fs::remove(m_block_file_seq.FileName(pos), ec)};827const bool removed_undofile{fs::remove(m_undo_file_seq.FileName(pos), ec)};828if (removed_blockfile || removed_undofile) {829LogDebug(BCLog::BLOCKSTORAGE, "Prune: %s deleted blk/rev (%05u)\n", __func__, *it);830}831}832}834AutoFile BlockManager::OpenBlockFile(const FlatFilePos& pos, bool fReadOnly) const835{836return AutoFile{m_block_file_seq.Open(pos, fReadOnly), m_obfuscation};837}839/** Open an undo file (rev?????.dat) */840AutoFile BlockManager::OpenUndoFile(const FlatFilePos& pos, bool fReadOnly) const841{842return AutoFile{m_undo_file_seq.Open(pos, fReadOnly), m_obfuscation};843}845fs::path BlockManager::GetBlockPosFilename(const FlatFilePos& pos) const846{847return m_block_file_seq.FileName(pos);848}850FlatFilePos BlockManager::FindNextBlockPos(unsigned int nAddSize, unsigned int nHeight, uint64_t nTime)851{852AssertLockHeld(::cs_main);853const BlockfileType chain_type = BlockfileTypeForHeight(nHeight);855if (!m_blockfile_cursors[chain_type]) {856// If a snapshot is loaded during runtime, we may not have initialized this cursor yet.857assert(chain_type == BlockfileType::ASSUMED);858const auto new_cursor = BlockfileCursor{this->MaxBlockfileNum() + 1};859m_blockfile_cursors[chain_type] = new_cursor;860LogDebug(BCLog::BLOCKSTORAGE, "[%s] initializing blockfile cursor to %s\n", chain_type, new_cursor);861}862const int last_blockfile = m_blockfile_cursors[chain_type]->file_num;864int nFile = last_blockfile;865if (static_cast<int>(m_blockfile_info.size()) <= nFile) {866m_blockfile_info.resize(nFile + 1);867}869bool finalize_undo = false;870unsigned int max_blockfile_size{MAX_BLOCKFILE_SIZE};871// Use smaller blockfiles in test-only -fastprune mode - but avoid872// the possibility of having a block not fit into the block file.873if (m_opts.fast_prune) {874max_blockfile_size = 0x10000; // 64kiB875if (nAddSize >= max_blockfile_size) {876// dynamically adjust the blockfile size to be larger than the added size877max_blockfile_size = nAddSize + 1;878}879}880assert(nAddSize < max_blockfile_size);882while (m_blockfile_info[nFile].nSize + nAddSize >= max_blockfile_size) {883// when the undo file is keeping up with the block file, we want to flush it explicitly884// when it is lagging behind (more blocks arrive than are being connected), we let the885// undo block write case handle it886finalize_undo = (static_cast<int>(m_blockfile_info[nFile].nHeightLast) ==887Assert(m_blockfile_cursors[chain_type])->undo_height);889// Try the next unclaimed blockfile number890nFile = this->MaxBlockfileNum() + 1;891// Set to increment MaxBlockfileNum() for next iteration892m_blockfile_cursors[chain_type] = BlockfileCursor{nFile};894if (static_cast<int>(m_blockfile_info.size()) <= nFile) {895m_blockfile_info.resize(nFile + 1);896}897}898FlatFilePos pos;899pos.nFile = nFile;900pos.nPos = m_blockfile_info[nFile].nSize;902if (nFile != last_blockfile) {903LogDebug(BCLog::BLOCKSTORAGE, "Leaving block file %i: %s (onto %i) (height %i)\n",904last_blockfile, m_blockfile_info[last_blockfile].ToString(), nFile, nHeight);906// Do not propagate the return code. The flush concerns a previous block907// and undo file that has already been written to. If a flush fails908// here, and we crash, there is no expected additional block data909// inconsistency arising from the flush failure here. However, the undo910// data may be inconsistent after a crash if the flush is called during911// a reindex. A flush error might also leave some of the data files912// untrimmed.913if (!FlushBlockFile(last_blockfile, /*fFinalize=*/true, finalize_undo)) {914LogWarning(915"Failed to flush previous block file %05i (finalize=1, finalize_undo=%i) before opening new block file %05i\n",916last_blockfile, finalize_undo, nFile);917}918// No undo data yet in the new file, so reset our undo-height tracking.919m_blockfile_cursors[chain_type] = BlockfileCursor{nFile};920}922m_blockfile_info[nFile].AddBlock(nHeight, nTime);923m_blockfile_info[nFile].nSize += nAddSize;925bool out_of_space;926size_t bytes_allocated = m_block_file_seq.Allocate(pos, nAddSize, out_of_space);927if (out_of_space) {928m_opts.notifications.fatalError(_("Disk space is too low!"));929return {};930}931if (bytes_allocated != 0 && IsPruneMode()) {932m_check_for_pruning = true;933}935m_dirty_fileinfo.insert(nFile);936return pos;937}939void BlockManager::UpdateBlockInfo(const CBlock& block, unsigned int nHeight, const FlatFilePos& pos)940{941AssertLockHeld(::cs_main);942// Update the cursor so it points to the last file.943const BlockfileType chain_type{BlockfileTypeForHeight(nHeight)};944auto& cursor{m_blockfile_cursors[chain_type]};945if (!cursor || cursor->file_num < pos.nFile) {946m_blockfile_cursors[chain_type] = BlockfileCursor{pos.nFile};947}949// Update the file information with the current block.950const unsigned int added_size = ::GetSerializeSize(TX_WITH_WITNESS(block));951const int nFile = pos.nFile;952if (static_cast<int>(m_blockfile_info.size()) <= nFile) {953m_blockfile_info.resize(nFile + 1);954}955m_blockfile_info[nFile].AddBlock(nHeight, block.GetBlockTime());956m_blockfile_info[nFile].nSize = std::max(pos.nPos + added_size, m_blockfile_info[nFile].nSize);957m_dirty_fileinfo.insert(nFile);958}960bool BlockManager::FindUndoPos(BlockValidationState& state, int nFile, FlatFilePos& pos, unsigned int nAddSize)961{962AssertLockHeld(::cs_main);963pos.nFile = nFile;965pos.nPos = m_blockfile_info[nFile].nUndoSize;966m_blockfile_info[nFile].nUndoSize += nAddSize;967m_dirty_fileinfo.insert(nFile);969bool out_of_space;970size_t bytes_allocated = m_undo_file_seq.Allocate(pos, nAddSize, out_of_space);971if (out_of_space) {972return FatalError(m_opts.notifications, state, _("Disk space is too low!"));973}974if (bytes_allocated != 0 && IsPruneMode()) {975m_check_for_pruning = true;976}978return true;979}981bool BlockManager::WriteBlockUndo(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex& block)982{983AssertLockHeld(::cs_main);984const BlockfileType type = BlockfileTypeForHeight(block.nHeight);985auto& cursor = *Assert(m_blockfile_cursors[type]);987// Write undo information to disk988if (block.GetUndoPos().IsNull()) {989FlatFilePos pos;990const auto blockundo_size{static_cast<uint32_t>(GetSerializeSize(blockundo))};991if (!FindUndoPos(state, block.nFile, pos, blockundo_size + UNDO_DATA_DISK_OVERHEAD)) {992LogError("FindUndoPos failed for %s while writing block undo", pos.ToString());993return false;994}996// Open history file to append997AutoFile file{OpenUndoFile(pos)};998if (file.IsNull()) {999LogError("OpenUndoFile failed for %s while writing block undo", pos.ToString());1000return FatalError(m_opts.notifications, state, _("Failed to write undo data."));