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

Code before:
        }
        if (!last_file.Truncate(pos.nPos)) {
            LogPrintf("%s: Failed to truncate filter file %d\n", __func__, pos.nFile);
            return 0;
        }
        if (!last_file.Commit()) {
            LogPrintf("%s: Failed to commit filter file %d\n", __func__, pos.nFile);
            return 0;
        }

        pos.nFile++;
        pos.nPos = 0;
    }

    // Pre-allocate sufficient space for filter data.
    bool out_of_space;
    m_filter_fileseq->Allocate(pos, data_size, out_of_space);
    if (out_of_space) {
        LogPrintf("%s: out of disk space\n", __func__);
        return 0;
    }

    AutoFile fileout{m_filter_fileseq->Open(pos)};
    if (fileout.IsNull()) {
        LogPrintf("%s: Failed to open filter file %d\n", __func__, pos.nFile);
        return 0;
    }

    fileout << filter.GetBlockHash() << filter.GetEncodedFilter();
    return data_size;
}

std::optional<uint256> BlockFilterIndex::ReadFilterHeader(int height, const uint256& expected_block_hash)
{
    std::pair<uint256, DBVal> read_out;
    if (!m_db->Read(DBHeightKey(height), read_out)) {
        return std::nullopt;
    }

    if (read_out.first != expected_block_hash) {
        LogError("%s: previous block header belongs to unexpected block %s; expected %s\n",
                         __func__, read_out.first.ToString(), expected_block_hash.ToString());
        return std::nullopt;
    }

    return read_out.second.header;
}

bool BlockFilterIndex::CustomAppend(const interfaces::BlockInfo& block)
{
    BlockFilter filter(m_filter_type, *Assert(block.data), *Assert(block.undo_data));

Review comment (bug):
Could use `SystemErr(err)` here?
```suggestion
    if (int err{fileout.fclose()}; err != 0) {
        LogPrintf("Failed to close filter file %d: %s", pos.nFile, SysErrorString(err));
```
Could be done in other files too (*net.cpp*, *blockstorage.cpp*). (I can understand not wanting to do it further above in this specific file though).

Code after:
    // If writing the filter would overflow the file, flush and move to the next one.
    if (pos.nPos + data_size > MAX_FLTR_FILE_SIZE) {
        AutoFile last_file{m_filter_fileseq->Open(pos)};
        if (last_file.IsNull()) {
            LogPrintf("%s: Failed to open filter file %d\n", __func__, pos.nFile);
            return 0;
        }
        if (!last_file.Truncate(pos.nPos)) {
            LogPrintf("%s: Failed to truncate filter file %d\n", __func__, pos.nFile);
            return 0;
        }
        if (!last_file.Commit()) {
            LogPrintf("%s: Failed to commit filter file %d\n", __func__, pos.nFile);
            (void)last_file.fclose();
            return 0;
        }
        if (last_file.fclose() != 0) {
            LogError("Failed to close filter file %d after commit: %s", pos.nFile, SysErrorString(errno));
            return 0;
        }

        pos.nFile++;
        pos.nPos = 0;
    }

    // Pre-allocate sufficient space for filter data.
    bool out_of_space;
    m_filter_fileseq->Allocate(pos, data_size, out_of_space);
    if (out_of_space) {
        LogPrintf("%s: out of disk space\n", __func__);
        return 0;
    }

    AutoFile fileout{m_filter_fileseq->Open(pos)};
    if (fileout.IsNull()) {
        LogPrintf("%s: Failed to open filter file %d\n", __func__, pos.nFile);
        return 0;
    }

    fileout << filter.GetBlockHash() << filter.GetEncodedFilter();

    if (fileout.fclose() != 0) {
        LogError("Failed to close filter file %d: %s", pos.nFile, SysErrorString(errno));
        return 0;
    }

    return data_size;
}

std::optional<uint256> BlockFilterIndex::ReadFilterHeader(int height, const uint256& expected_block_hash)
{