0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-03-05 14:06:27 -05:00

test, refactor: Remove remaining unbounded flags from coins_tests

This commit is contained in:
Lőrinc 2024-09-17 17:52:41 +02:00
parent c0b4b2c1ee
commit 0a159f0914

View file

@ -567,38 +567,47 @@ constexpr CAmount VALUE1{100};
constexpr CAmount VALUE2{200}; constexpr CAmount VALUE2{200};
constexpr CAmount VALUE3{300}; constexpr CAmount VALUE3{300};
constexpr char DIRTY{CCoinsCacheEntry::DIRTY};
constexpr char FRESH{CCoinsCacheEntry::FRESH};
constexpr char CLEAN{0};
struct CoinEntry { struct CoinEntry {
const CAmount value; enum class State { CLEAN, DIRTY, FRESH, DIRTY_FRESH };
const char flags;
constexpr CoinEntry(const CAmount v, const char s) : value{v}, flags{s} {} const CAmount value;
const State state;
constexpr CoinEntry(const CAmount v, const State s) : value{v}, state{s} {}
bool operator==(const CoinEntry& o) const = default; bool operator==(const CoinEntry& o) const = default;
friend std::ostream& operator<<(std::ostream& os, const CoinEntry& e) { return os << e.value << ", " << e.flags; } friend std::ostream& operator<<(std::ostream& os, const CoinEntry& e) { return os << e.value << ", " << e.state; }
constexpr bool IsDirtyFresh() const { return state == State::DIRTY_FRESH; }
constexpr bool IsDirty() const { return state == State::DIRTY || IsDirtyFresh(); }
constexpr bool IsFresh() const { return state == State::FRESH || IsDirtyFresh(); }
static constexpr State ToState(const bool is_dirty, const bool is_fresh) {
if (is_dirty && is_fresh) return State::DIRTY_FRESH;
if (is_dirty) return State::DIRTY;
if (is_fresh) return State::FRESH;
return State::CLEAN;
}
}; };
using MaybeCoin = std::optional<CoinEntry>; using MaybeCoin = std::optional<CoinEntry>;
using CoinOrError = std::variant<MaybeCoin, std::string>; using CoinOrError = std::variant<MaybeCoin, std::string>;
constexpr MaybeCoin MISSING {std::nullopt}; constexpr MaybeCoin MISSING {std::nullopt};
constexpr MaybeCoin SPENT_DIRTY {{SPENT, DIRTY}}; constexpr MaybeCoin SPENT_DIRTY {{SPENT, CoinEntry::State::DIRTY}};
constexpr MaybeCoin SPENT_DIRTY_FRESH {{SPENT, DIRTY | FRESH}}; constexpr MaybeCoin SPENT_DIRTY_FRESH {{SPENT, CoinEntry::State::DIRTY_FRESH}};
constexpr MaybeCoin SPENT_FRESH {{SPENT, FRESH}}; constexpr MaybeCoin SPENT_FRESH {{SPENT, CoinEntry::State::FRESH}};
constexpr MaybeCoin SPENT_CLEAN {{SPENT, CLEAN}}; constexpr MaybeCoin SPENT_CLEAN {{SPENT, CoinEntry::State::CLEAN}};
constexpr MaybeCoin VALUE1_DIRTY {{VALUE1, DIRTY}}; constexpr MaybeCoin VALUE1_DIRTY {{VALUE1, CoinEntry::State::DIRTY}};
constexpr MaybeCoin VALUE1_DIRTY_FRESH{{VALUE1, DIRTY | FRESH}}; constexpr MaybeCoin VALUE1_DIRTY_FRESH{{VALUE1, CoinEntry::State::DIRTY_FRESH}};
constexpr MaybeCoin VALUE1_FRESH {{VALUE1, FRESH}}; constexpr MaybeCoin VALUE1_FRESH {{VALUE1, CoinEntry::State::FRESH}};
constexpr MaybeCoin VALUE1_CLEAN {{VALUE1, CLEAN}}; constexpr MaybeCoin VALUE1_CLEAN {{VALUE1, CoinEntry::State::CLEAN}};
constexpr MaybeCoin VALUE2_DIRTY {{VALUE2, DIRTY}}; constexpr MaybeCoin VALUE2_DIRTY {{VALUE2, CoinEntry::State::DIRTY}};
constexpr MaybeCoin VALUE2_DIRTY_FRESH{{VALUE2, DIRTY | FRESH}}; constexpr MaybeCoin VALUE2_DIRTY_FRESH{{VALUE2, CoinEntry::State::DIRTY_FRESH}};
constexpr MaybeCoin VALUE2_FRESH {{VALUE2, FRESH}}; constexpr MaybeCoin VALUE2_FRESH {{VALUE2, CoinEntry::State::FRESH}};
constexpr MaybeCoin VALUE2_CLEAN {{VALUE2, CLEAN}}; constexpr MaybeCoin VALUE2_CLEAN {{VALUE2, CoinEntry::State::CLEAN}};
constexpr MaybeCoin VALUE3_DIRTY {{VALUE3, DIRTY}}; constexpr MaybeCoin VALUE3_DIRTY {{VALUE3, CoinEntry::State::DIRTY}};
constexpr MaybeCoin VALUE3_DIRTY_FRESH{{VALUE3, DIRTY | FRESH}}; constexpr MaybeCoin VALUE3_DIRTY_FRESH{{VALUE3, CoinEntry::State::DIRTY_FRESH}};
constexpr auto EX_OVERWRITE_UNSPENT{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}; constexpr auto EX_OVERWRITE_UNSPENT{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"};
constexpr auto EX_FRESH_MISAPPLIED {"FRESH flag misapplied to coin that exists in parent cache"}; constexpr auto EX_FRESH_MISAPPLIED {"FRESH flag misapplied to coin that exists in parent cache"};
@ -621,22 +630,22 @@ static size_t InsertCoinsMapEntry(CCoinsMap& map, CoinsCachePair& sentinel, cons
SetCoinsValue(cache_coin.value, entry.coin); SetCoinsValue(cache_coin.value, entry.coin);
auto [iter, inserted] = map.emplace(OUTPOINT, std::move(entry)); auto [iter, inserted] = map.emplace(OUTPOINT, std::move(entry));
assert(inserted); assert(inserted);
if (cache_coin.flags & DIRTY) CCoinsCacheEntry::SetDirty(*iter, sentinel); if (cache_coin.IsDirty()) CCoinsCacheEntry::SetDirty(*iter, sentinel);
if (cache_coin.flags & FRESH) CCoinsCacheEntry::SetFresh(*iter, sentinel); if (cache_coin.IsFresh()) CCoinsCacheEntry::SetFresh(*iter, sentinel);
return iter->second.coin.DynamicMemoryUsage(); return iter->second.coin.DynamicMemoryUsage();
} }
MaybeCoin GetCoinsMapEntry(const CCoinsMap& map, const COutPoint& outp = OUTPOINT) static MaybeCoin GetCoinsMapEntry(const CCoinsMap& map, const COutPoint& outp = OUTPOINT)
{ {
if (auto it{map.find(outp)}; it != map.end()) { if (auto it{map.find(outp)}; it != map.end()) {
return CoinEntry{ return CoinEntry{
it->second.coin.IsSpent() ? SPENT : it->second.coin.out.nValue, it->second.coin.IsSpent() ? SPENT : it->second.coin.out.nValue,
static_cast<char>((it->second.IsDirty() ? DIRTY : 0) | (it->second.IsFresh() ? FRESH : 0))}; CoinEntry::ToState(it->second.IsDirty(), it->second.IsFresh())};
} }
return MISSING; return MISSING;
} }
void WriteCoinsViewEntry(CCoinsView& view, const MaybeCoin& cache_coin) static void WriteCoinsViewEntry(CCoinsView& view, const MaybeCoin& cache_coin)
{ {
CoinsCachePair sentinel{}; CoinsCachePair sentinel{};
sentinel.second.SelfRef(sentinel); sentinel.second.SelfRef(sentinel);
@ -652,7 +661,7 @@ class SingleEntryCacheTest
public: public:
SingleEntryCacheTest(const CAmount base_value, const MaybeCoin& cache_coin) SingleEntryCacheTest(const CAmount base_value, const MaybeCoin& cache_coin)
{ {
auto base_cache_coin{base_value == ABSENT ? MISSING : CoinEntry{base_value, DIRTY}}; auto base_cache_coin{base_value == ABSENT ? MISSING : CoinEntry{base_value, CoinEntry::State::DIRTY}};
WriteCoinsViewEntry(base, base_cache_coin); WriteCoinsViewEntry(base, base_cache_coin);
if (cache_coin) cache.usage() += InsertCoinsMapEntry(cache.map(), cache.sentinel(), *cache_coin); if (cache_coin) cache.usage() += InsertCoinsMapEntry(cache.map(), cache.sentinel(), *cache_coin);
} }
@ -800,7 +809,7 @@ BOOST_AUTO_TEST_CASE(ccoins_add)
} }
} }
void CheckWriteCoins(const MaybeCoin& parent, const MaybeCoin& child, const CoinOrError& expected) static void CheckWriteCoins(const MaybeCoin& parent, const MaybeCoin& child, const CoinOrError& expected)
{ {
SingleEntryCacheTest test{ABSENT, parent}; SingleEntryCacheTest test{ABSENT, parent};
auto write_coins{[&] { WriteCoinsViewEntry(test.cache, child); }}; auto write_coins{[&] { WriteCoinsViewEntry(test.cache, child); }};
@ -870,7 +879,7 @@ BOOST_AUTO_TEST_CASE(ccoins_write)
CheckWriteCoins(VALUE1_DIRTY_FRESH, VALUE2_DIRTY, VALUE2_DIRTY_FRESH ); CheckWriteCoins(VALUE1_DIRTY_FRESH, VALUE2_DIRTY, VALUE2_DIRTY_FRESH );
CheckWriteCoins(VALUE1_DIRTY_FRESH, VALUE2_DIRTY_FRESH, EX_FRESH_MISAPPLIED); CheckWriteCoins(VALUE1_DIRTY_FRESH, VALUE2_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
// The checks above omit cases where the child flags are not DIRTY, since // The checks above omit cases where the child state is not DIRTY, since
// they would be too repetitive (the parent cache is never updated in these // they would be too repetitive (the parent cache is never updated in these
// cases). The loop below covers these cases and makes sure the parent cache // cases). The loop below covers these cases and makes sure the parent cache
// is always left unchanged. // is always left unchanged.
@ -946,7 +955,7 @@ void TestFlushBehavior(
BOOST_CHECK(!base.HaveCoin(outp)); BOOST_CHECK(!base.HaveCoin(outp));
BOOST_CHECK(view->HaveCoin(outp)); BOOST_CHECK(view->HaveCoin(outp));
BOOST_CHECK_EQUAL(GetCoinsMapEntry(view->map(), outp), CoinEntry(coin.out.nValue, DIRTY|FRESH)); BOOST_CHECK_EQUAL(GetCoinsMapEntry(view->map(), outp), CoinEntry(coin.out.nValue, CoinEntry::State::DIRTY_FRESH));
// --- 2. Flushing all caches (without erasing) // --- 2. Flushing all caches (without erasing)
// //
@ -958,7 +967,7 @@ void TestFlushBehavior(
// --- 3. Ensuring the entry still exists in the cache and has been written to parent // --- 3. Ensuring the entry still exists in the cache and has been written to parent
// //
BOOST_CHECK_EQUAL(GetCoinsMapEntry(view->map(), outp), CoinEntry(coin.out.nValue, CLEAN)); // Flags should have been wiped. BOOST_CHECK_EQUAL(GetCoinsMapEntry(view->map(), outp), CoinEntry(coin.out.nValue, CoinEntry::State::CLEAN)); // State should have been wiped.
// Both views should now have the coin. // Both views should now have the coin.
BOOST_CHECK(base.HaveCoin(outp)); BOOST_CHECK(base.HaveCoin(outp));
@ -978,7 +987,7 @@ void TestFlushBehavior(
// //
BOOST_CHECK(!GetCoinsMapEntry(view->map(), outp)); BOOST_CHECK(!GetCoinsMapEntry(view->map(), outp));
view->AccessCoin(outp); view->AccessCoin(outp);
BOOST_CHECK_EQUAL(GetCoinsMapEntry(view->map(), outp), CoinEntry(coin.out.nValue, CLEAN)); BOOST_CHECK_EQUAL(GetCoinsMapEntry(view->map(), outp), CoinEntry(coin.out.nValue, CoinEntry::State::CLEAN));
} }
// Can't overwrite an entry without specifying that an overwrite is // Can't overwrite an entry without specifying that an overwrite is
@ -1043,7 +1052,7 @@ void TestFlushBehavior(
all_caches[0]->AddCoin(outp, std::move(coin), false); all_caches[0]->AddCoin(outp, std::move(coin), false);
// Coin should be FRESH in the cache. // Coin should be FRESH in the cache.
BOOST_CHECK_EQUAL(GetCoinsMapEntry(all_caches[0]->map(), outp), CoinEntry(coin_val, DIRTY|FRESH)); BOOST_CHECK_EQUAL(GetCoinsMapEntry(all_caches[0]->map(), outp), CoinEntry(coin_val, CoinEntry::State::DIRTY_FRESH));
// Base shouldn't have seen coin. // Base shouldn't have seen coin.
BOOST_CHECK(!base.HaveCoin(outp)); BOOST_CHECK(!base.HaveCoin(outp));