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:
parent
c0b4b2c1ee
commit
0a159f0914
1 changed files with 43 additions and 34 deletions
|
@ -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));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue