Repository: bitcoin/bitcoin
File: src/test/fuzz/coinscache_sim.cpp (C++)

Code before:
    /* Type of entry. */
    EntryType entrytype;

    /* Index in the coins array this entry corresponds to (only if entrytype == UNSPENT). */
    coinidx_type coinidx;

    /* nHeight value for this entry (so the coins[coinidx].nHeight value is ignored; only if entrytype == UNSPENT). */
    uint32_t height;
};

struct CacheLevel
{
    CacheEntry entry[NUM_OUTPOINTS];

    void Wipe() {
        for (uint32_t i = 0; i < NUM_OUTPOINTS; ++i) {
            entry[i].entrytype = EntryType::NONE;
        }
    }
};

/** Class for the base of the hierarchy (roughly simulating a memory-backed CCoinsViewDB).
 *
 * The initial state consists of the empty UTXO set, though coins whose output index
 * is 3 (mod 5) always have GetCoin() succeed (but returning an IsSpent() coin unless a UTXO
 * exists). Coins whose output index is 4 (mod 5) have GetCoin() always succeed after being spent.
 * This exercises code paths with spent, non-DIRTY cache entries.
 */
class CoinsViewBottom final : public CCoinsView
{
    std::map<COutPoint, Coin> m_data;

public:
    bool GetCoin(const COutPoint& outpoint, Coin& coin) const final
    {
        auto it = m_data.find(outpoint);
        if (it == m_data.end()) {
            if ((outpoint.n % 5) == 3) {
                coin.Clear();
                return true;
            }
            return false;
        } else {
            coin = it->second;
            return true;
        }
    }

    bool HaveCoin(const COutPoint& outpoint) const final
    {
        return m_data.count(outpoint);

Review comment (refactor):
This part `Coins whose output index is 4 (mod 5) have GetCoin() always succeed after being spent` is due to us not erasing these coins with this condition on line 169 below. Since we are not yet not returning spent coins (`// TODO GetCoin shouldn't return spent coins`), we shouldn't remove this line of the comment.

Code after:
    /* Type of entry. */
    EntryType entrytype;

    /* Index in the coins array this entry corresponds to (only if entrytype == UNSPENT). */
    coinidx_type coinidx;

    /* nHeight value for this entry (so the coins[coinidx].nHeight value is ignored; only if entrytype == UNSPENT). */
    uint32_t height;
};

struct CacheLevel
{
    CacheEntry entry[NUM_OUTPOINTS];

    void Wipe() {
        for (uint32_t i = 0; i < NUM_OUTPOINTS; ++i) {
            entry[i].entrytype = EntryType::NONE;
        }
    }
};

/** Class for the base of the hierarchy (roughly simulating a memory-backed CCoinsViewDB).
 *
 * The initial state consists of the empty UTXO set.
 * Coins whose output index is 4 (mod 5) have GetCoin() always succeed after being spent.
 * This exercises code paths with spent, non-DIRTY cache entries.
 */
class CoinsViewBottom final : public CCoinsView
{
    std::map<COutPoint, Coin> m_data;

public:
    std::optional<Coin> GetCoin(const COutPoint& outpoint) const final
    {
        // TODO GetCoin shouldn't return spent coins
        if (auto it = m_data.find(outpoint); it != m_data.end()) return it->second;
        return std::nullopt;
    }

    bool HaveCoin(const COutPoint& outpoint) const final
    {
        return m_data.count(outpoint);
    }

    uint256 GetBestBlock() const final { return {}; }
    std::vector<uint256> GetHeadBlocks() const final { return {}; }
    std::unique_ptr<CCoinsViewCursor> Cursor() const final { return {}; }
    size_t EstimateSize() const final { return m_data.size(); }

    bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256&) final
    {