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

Code before:
                         __func__, GetName());
            return false;
        }

        // If the DB_FILTER_POS is not set, then initialize to the first location.
        m_next_filter_pos.nFile = 0;
        m_next_filter_pos.nPos = 0;
    }

    if (block) {
        auto op_last_header = ReadFilterHeader(block->height, block->hash);
        if (!op_last_header) {
            LogError("Cannot read last block filter header; index may be corrupted\n");
            return false;
        }
        m_last_header = *op_last_header;
    }

    return true;
}

bool BlockFilterIndex::CustomCommit(CDBBatch& batch)
{
    const FlatFilePos& pos = m_next_filter_pos;

    // Flush current filter file to disk.
    AutoFile file{m_filter_fileseq->Open(pos)};
    if (file.IsNull()) {
        LogError("%s: Failed to open filter file %d\n", __func__, pos.nFile);
        return false;
    }
    if (!file.Commit()) {
        LogError("%s: Failed to commit filter file %d\n", __func__, pos.nFile);
        return false;
    }

    batch.Write(DB_FILTER_POS, pos);
    return true;
}

bool BlockFilterIndex::ReadFilterFromDisk(const FlatFilePos& pos, const uint256& hash, BlockFilter& filter) const
{
    AutoFile filein{m_filter_fileseq->Open(pos, true)};
    if (filein.IsNull()) {
        return false;
    }

    // Check that the hash of the encoded_filter matches the one stored in the db.
    uint256 block_hash;
    std::vector<uint8_t> encoded_filter;
    try {

Review comment (bug):
If we can't fully commit to disk, we won't call `fclose` directly - we'll rely on the destructor's close.
We'd get a commitment failure message (though that could have been successful) - and maybe another message from the destructor.

Could we separate the two errors?
```C++
if (!file.Commit()) {
    LogError("%s: Failed to commit filter file %d", __func__, pos.nFile);
    return false;
}
if (file.fclose()) {
    LogError("%s: Failed to close filter file %d", __func__, pos.nFile);
    return false;
}
```

or unify them to a single error like we're doing in https://github.com/bitcoin/bitcoin/pull/29307/files?w=1#diff-7194b705e3c48e34fbd6e648fbbee39c6e0b49ee9658658b930678a9a2d31dd6R957
```C++
if (file.IsNull() || !file.Commit() || file.fclose()) {
    LogError("%s: Failed to flush filter file %d", __func__, pos.nFile);
    return false;
}
```

Code after:
            LogError("%s: Cannot read current %s state; index may be corrupted\n",
                         __func__, GetName());
            return false;
        }

        // If the DB_FILTER_POS is not set, then initialize to the first location.
        m_next_filter_pos.nFile = 0;
        m_next_filter_pos.nPos = 0;
    }

    if (block) {
        auto op_last_header = ReadFilterHeader(block->height, block->hash);
        if (!op_last_header) {
            LogError("Cannot read last block filter header; index may be corrupted\n");
            return false;
        }
        m_last_header = *op_last_header;
    }

    return true;
}

bool BlockFilterIndex::CustomCommit(CDBBatch& batch)
{
    const FlatFilePos& pos = m_next_filter_pos;

    // Flush current filter file to disk.
    AutoFile file{m_filter_fileseq->Open(pos)};
    if (file.IsNull()) {
        LogError("%s: Failed to open filter file %d\n", __func__, pos.nFile);
        return false;
    }
    if (!file.Commit()) {
        LogError("%s: Failed to commit filter file %d\n", __func__, pos.nFile);
        (void)file.fclose();
        return false;
    }
    if (file.fclose() != 0) {
        LogError("Failed to close filter file %d after commit: %s", pos.nFile, SysErrorString(errno));
        return false;
    }

    batch.Write(DB_FILTER_POS, pos);
    return true;
}

bool BlockFilterIndex::ReadFilterFromDisk(const FlatFilePos& pos, const uint256& hash, BlockFilter& filter) const
{
    AutoFile filein{m_filter_fileseq->Open(pos, true)};
    if (filein.IsNull()) {
        return false;