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

Code before:
        bool out_of_space;
        size_t bytes_allocated = BlockFileSeq().Allocate(pos, nAddSize, out_of_space);
        if (out_of_space) {
            m_opts.notifications.fatalError(_("Disk space is too low!"));
            return false;
        }
        if (bytes_allocated != 0 && IsPruneMode()) {
            m_check_for_pruning = true;
        }
    }

    m_dirty_fileinfo.insert(nFile);
    return true;
}

bool BlockManager::FindUndoPos(BlockValidationState& state, int nFile, FlatFilePos& pos, unsigned int nAddSize)
{
    pos.nFile = nFile;

    LOCK(cs_LastBlockFile);

    pos.nPos = m_blockfile_info[nFile].nUndoSize;
    m_blockfile_info[nFile].nUndoSize += nAddSize;
    m_dirty_fileinfo.insert(nFile);

    bool out_of_space;
    size_t bytes_allocated = UndoFileSeq().Allocate(pos, nAddSize, out_of_space);
    if (out_of_space) {
        return FatalError(m_opts.notifications, state, _("Disk space is too low!"));
    }
    if (bytes_allocated != 0 && IsPruneMode()) {
        m_check_for_pruning = true;
    }

    return true;
}

bool BlockManager::WriteBlockToDisk(const CBlock& block, FlatFilePos& pos) const
{
    // Open history file to append
    AutoFile fileout{OpenBlockFile(pos)};
    if (fileout.IsNull()) {
        LogError("WriteBlockToDisk: OpenBlockFile failed\n");
        return false;
    }

    // Write index header
    unsigned int nSize = GetSerializeSize(TX_WITH_WITNESS(block));
    fileout << GetParams().MessageStart() << nSize;

    // Write block

Review comment (suggestion):
In commit "blockstorage: split up FindBlockPos function" (2b6d274af050ea21e39ce59b6a6b3b7fb61e8cbd)

I think this comment is not really accurate in this context. There should be no need to reset `BlockfileCursor::undo_height` here, only to set a new `BlockfileCursor::file_num` value so `MaxBlockfileNum()` returns the right thing. So the comment could be changed to something like "update the cursor so it points to the last file".

Maybe it would also make sense to make this a little more robust so doesn't move the cursor backwards if `UpdateBlockInfo` calls are made out of order. We are already doing this for blocks within the file by using std::max to set the file size below. Generalizing this would also allow dropping the `Assume()` checks:

```diff
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -942,24 +942,19 @@ void BlockManager::UpdateBlockInfo(const CBlock& block, unsigned int nHeight, co
 {
     LOCK(cs_LastBlockFile);
 
+    // Update the cursor so it points to the last file.
+    const BlockfileType chain_type{BlockfileTypeForHeight(nHeight)};
+    auto& cursor{m_blockfile_cursors[chain_type]};
+    if (!cursor || cursor->file_num < pos.nFile) {
+        m_blockfile_cursors[chain_type] = BlockfileCursor{pos.nFile};
+    }
+
+    // Update the file information so it points to the last block.
     const unsigned int added_size = ::GetSerializeSize(TX_WITH_WITNESS(block));
-    const BlockfileType chain_type = BlockfileTypeForHeight(nHeight);
-    // Check that chain type is NORMAL, because this function is only
-    // called during reindexing, and reindexing deletes snapshot chainstates, so
-    // chain_type will not be SNAPSHOT. Also check that cursor exists, because
-    // the normal cursor should never be null.
-    Assume(chain_type == BlockfileType::NORMAL);
-    Assume(m_blockfile_cursors[chain_type]);
     const int nFile = pos.nFile;
     if (static_cast<int>(m_blockfile_info.size()) <= nFile) {
         m_blockfile_info.resize(nFile + 1);
     }
-
-    const int last_blockfile = m_blockfile_cursors[chain_type]->file_num;
-    if (nFile != last_blockfile) {
-        // No undo data yet in the new file, so reset our undo-height tracking.
-        m_blockfile_cursors[chain_type] = BlockfileCursor{nFile};
-    }
     m_blockfile_info[nFile].AddBlock(nHeight, block.GetBlockTime());
     m_blockfile_info[nFile].nSize = std::max(pos.nPos + added_size, m_blockfile_info[nFile].nSize);
     m_dirty_fileinfo.insert(nFile);
```


Code after:
    }

    m_dirty_fileinfo.insert(nFile);
    return pos;
}

void BlockManager::UpdateBlockInfo(const CBlock& block, unsigned int nHeight, const FlatFilePos& pos)
{
    LOCK(cs_LastBlockFile);

    // Update the cursor so it points to the last file.
    const BlockfileType chain_type{BlockfileTypeForHeight(nHeight)};
    auto& cursor{m_blockfile_cursors[chain_type]};
    if (!cursor || cursor->file_num < pos.nFile) {
        m_blockfile_cursors[chain_type] = BlockfileCursor{pos.nFile};
    }

    // Update the file information with the current block.
    const unsigned int added_size = ::GetSerializeSize(TX_WITH_WITNESS(block));
    const int nFile = pos.nFile;
    if (static_cast<int>(m_blockfile_info.size()) <= nFile) {
        m_blockfile_info.resize(nFile + 1);
    }
    m_blockfile_info[nFile].AddBlock(nHeight, block.GetBlockTime());
    m_blockfile_info[nFile].nSize = std::max(pos.nPos + added_size, m_blockfile_info[nFile].nSize);
    m_dirty_fileinfo.insert(nFile);
}

bool BlockManager::FindUndoPos(BlockValidationState& state, int nFile, FlatFilePos& pos, unsigned int nAddSize)
{
    pos.nFile = nFile;

    LOCK(cs_LastBlockFile);

    pos.nPos = m_blockfile_info[nFile].nUndoSize;
    m_blockfile_info[nFile].nUndoSize += nAddSize;
    m_dirty_fileinfo.insert(nFile);

    bool out_of_space;
    size_t bytes_allocated = UndoFileSeq().Allocate(pos, nAddSize, out_of_space);
    if (out_of_space) {
        return FatalError(m_opts.notifications, state, _("Disk space is too low!"));
    }
    if (bytes_allocated != 0 && IsPruneMode()) {
        m_check_for_pruning = true;
    }

    return true;
}

bool BlockManager::WriteBlockToDisk(const CBlock& block, FlatFilePos& pos) const