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

Code before:
    BlockFilter filter(m_filter_type, *Assert(block.data), block_undo);

    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;
    }

    m_next_filter_pos.nPos += bytes_written;
    return true;
}

[[nodiscard]] static bool CopyHeightIndexToHashIndex(CDBIterator& db_it, CDBBatch& batch,
                                                     const std::string& index_name, int height)
{
    DBHeightKey key(height);
    db_it.Seek(key);

    if (!db_it.GetKey(key) || key.height != height) {
        LogError("%s: unexpected key in %s: expected (%c, %d)\n",
                 __func__, index_name, DB_BLOCK_HEIGHT, height);
        return false;
    }

    std::pair<uint256, DBVal> value;
    if (!db_it.GetValue(value)) {
        LogError("%s: unable to read value in %s at key (%c, %d)\n",
                 __func__, index_name, DB_BLOCK_HEIGHT, height);
        return false;
    }

    batch.Write(DBHashKey(value.first), std::move(value.second));
    return true;
}

bool BlockFilterIndex::CustomRemove(const interfaces::BlockInfo& block)

Review comment (bug):
Out of scope for this PR since it is incorrect on master, but `db_it` needs a `Valid()` check before `GetKey()`, since leveldb `assert()`'s on trying to read the key of an invalid iterator:

https://github.com/bitcoin-core/leveldb-subtree/tree/bitcoin-fork/db/db_iter.cc#L64-L67


Code after:
}

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;
    }

    m_next_filter_pos.nPos += bytes_written;
    return true;
}

[[nodiscard]] static bool CopyHeightIndexToHashIndex(CDBIterator& db_it, CDBBatch& batch,
                                                     const std::string& index_name, int height)
{
    DBHeightKey key(height);
    db_it.Seek(key);

    if (!db_it.GetKey(key) || key.height != height) {
        LogError("%s: unexpected key in %s: expected (%c, %d)\n",
                 __func__, index_name, DB_BLOCK_HEIGHT, height);
        return false;
    }

    std::pair<uint256, DBVal> value;
    if (!db_it.GetValue(value)) {
        LogError("%s: unable to read value in %s at key (%c, %d)\n",
                 __func__, index_name, DB_BLOCK_HEIGHT, height);
        return false;
    }

    batch.Write(DBHashKey(value.first), std::move(value.second));
    return true;
}

bool BlockFilterIndex::CustomRemove(const interfaces::BlockInfo& block)
{
    CDBBatch batch(*m_db);
    std::unique_ptr<CDBIterator> db_it(m_db->NewIterator());

    // During a reorg, we need to copy block filter that is getting disconnected from the
    // height index to the hash index so we can still find it when the height index entry