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

Code before:
        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));
    const uint256& header = filter.ComputeHeader(m_last_header);
    bool res = Write(filter, block.height, header);
    if (res) m_last_header = header; // update last header
    return res;
}

bool BlockFilterIndex::Write(const BlockFilter& filter, uint32_t block_height, const uint256& filter_header)
{
    size_t bytes_written = WriteFilterToDisk(m_next_filter_pos, filter);
    if (bytes_written == 0) return false;

    std::pair<uint256, DBVal> value;
    value.first = filter.GetBlockHash();
    value.second.hash = filter.GetHash();
    value.second.header = filter_header;
    value.second.pos = m_next_filter_pos;

    if (!m_db->Write(DBHeightKey(block_height), value)) {
        return false;

Review comment (bug):
Why is this a `LogInfo`, shouldn't it be a `LogError`?
```suggestion
    if (fileout.fclose()) {
        LogError("%s: Failed to close filter file %d: %s", __func__, pos.nFile, SysErrorString(errno));
        return 0;
    }
```

Code after:
        }

        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)
{
    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));
    const uint256& header = filter.ComputeHeader(m_last_header);
    bool res = Write(filter, block.height, header);