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

Code before:
    GetCoinsMapEntry(view->map(), value, flags, outp);
    BOOST_CHECK_EQUAL(value, coin.out.nValue);
    BOOST_CHECK_EQUAL(flags, 0);  // Flags should have been wiped.

    // Both views should now have the coin.
    BOOST_CHECK(base.HaveCoin(outp));
    BOOST_CHECK(view->HaveCoin(outp));

    if (do_erasing_flush) {
        // --- 4. Flushing the caches again (with erasing)
        //
        flush_all(/*erase*/ true);

        // Memory usage should have gone down.
        BOOST_CHECK(view->DynamicMemoryUsage() < cache_usage);

        // --- 5. Ensuring the entry is no longer in the cache
        //
        GetCoinsMapEntry(view->map(), value, flags, outp);
        BOOST_CHECK_EQUAL(value, ABSENT);
        BOOST_CHECK_EQUAL(flags, NO_ENTRY);

        view->AccessCoin(outp);
        GetCoinsMapEntry(view->map(), value, flags, outp);
        BOOST_CHECK_EQUAL(value, coin.out.nValue);
        BOOST_CHECK_EQUAL(flags, 0);
    }

    // Can't overwrite an entry without specifying that an overwrite is
    // expected.
    Coin tmpCoin2{coin};
    BOOST_CHECK_THROW(
        view->AddCoin(outp, std::move(tmpCoin2), /*possible_overwrite*/ false),
        std::logic_error);

    // --- 6. Spend the coin.
    //
    BOOST_CHECK(view->SpendCoin(outp));

    // The coin should be in the cache, but spent and marked dirty.
    GetCoinsMapEntry(view->map(), value, flags, outp);
    BOOST_CHECK_EQUAL(value, SPENT);
    BOOST_CHECK_EQUAL(flags, DIRTY);
    BOOST_CHECK(!view->HaveCoin(outp)); // Coin should be considered spent in `view`.
    BOOST_CHECK(base.HaveCoin(outp));  // But coin should still be unspent in `base`.

    flush_all(/*erase*/ false);

    // Coin should be considered spent in both views.
    BOOST_CHECK(!view->HaveCoin(outp));
    BOOST_CHECK(!base.HaveCoin(outp));

Review comment (bug):
```bash
test/coins_tests.cpp:1004:39: error: 'tmpCoin2' used after it was moved [bugprone-use-after-move,-warnings-as-errors]
        view->AddCoin(outp, std::move(tmpCoin2), /*possible_overwrite*/ false),
                                      ^
test/coins_tests.cpp:1004:15: note: move occurred here
        view->AddCoin(outp, std::move(tmpCoin2), /*possible_overwrite*/ false),
              ^
test/coins_tests.cpp:1004:39: note: the use happens in a later loop iteration than the move
        view->AddCoin(outp, std::move(tmpCoin2), /*possible_overwrite*/ false),
```

Code after:
    BOOST_CHECK(base.HaveCoin(outp));
    BOOST_CHECK(view->HaveCoin(outp));

    if (do_erasing_flush) {
        // --- 4. Flushing the caches again (with erasing)
        //
        flush_all(/*erase=*/ true);

        // Memory usage should have gone down.
        BOOST_CHECK(view->DynamicMemoryUsage() < cache_usage);

        // --- 5. Ensuring the entry is no longer in the cache
        //
        GetCoinsMapEntry(view->map(), value, flags, outp);
        BOOST_CHECK_EQUAL(value, ABSENT);
        BOOST_CHECK_EQUAL(flags, NO_ENTRY);

        view->AccessCoin(outp);
        GetCoinsMapEntry(view->map(), value, flags, outp);
        BOOST_CHECK_EQUAL(value, coin.out.nValue);
        BOOST_CHECK_EQUAL(flags, 0);
    }

    // Can't overwrite an entry without specifying that an overwrite is
    // expected.
    BOOST_CHECK_THROW(
        view->AddCoin(outp, Coin(coin), /*possible_overwrite=*/ false),
        std::logic_error);

    // --- 6. Spend the coin.
    //
    BOOST_CHECK(view->SpendCoin(outp));

    // The coin should be in the cache, but spent and marked dirty.
    GetCoinsMapEntry(view->map(), value, flags, outp);
    BOOST_CHECK_EQUAL(value, SPENT);
    BOOST_CHECK_EQUAL(flags, DIRTY);
    BOOST_CHECK(!view->HaveCoin(outp)); // Coin should be considered spent in `view`.
    BOOST_CHECK(base.HaveCoin(outp));  // But coin should still be unspent in `base`.

    flush_all(/*erase=*/ false);

    // Coin should be considered spent in both views.
    BOOST_CHECK(!view->HaveCoin(outp));
    BOOST_CHECK(!base.HaveCoin(outp));

    // Spent coin should not be spendable.
    BOOST_CHECK(!view->SpendCoin(outp));

    // --- Bonus check: ensure that a coin added to the base view via one cache
    //     can be spent by another cache which has never seen it.