Skip to content

Commit ca74aa7

Browse files
committed
test, refactor: Migrate GetCoinsMapEntry to return MaybeCoin
1 parent 15aaa81 commit ca74aa7

File tree

1 file changed

+70
-92
lines changed

1 file changed

+70
-92
lines changed

src/test/coins_tests.cpp

Lines changed: 70 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -565,10 +565,23 @@ const static CAmount FAIL = -3;
565565
const static CAmount VALUE1 = 100;
566566
const static CAmount VALUE2 = 200;
567567
const static CAmount VALUE3 = 300;
568+
568569
const static char DIRTY = CCoinsCacheEntry::DIRTY;
569570
const static char FRESH = CCoinsCacheEntry::FRESH;
570571
const static char NO_ENTRY = -1;
571572

573+
struct CoinEntry {
574+
const CAmount value;
575+
const char flags;
576+
577+
constexpr CoinEntry(const CAmount v, const char s) : value{v}, flags{s} {}
578+
579+
bool operator==(const CoinEntry& o) const = default;
580+
friend std::ostream& operator<<(std::ostream& os, const CoinEntry& e) { return os << e.value << ", " << e.flags; }
581+
};
582+
583+
using MaybeCoin = std::optional<CoinEntry>;
584+
572585
const static auto FLAGS = {char(0), FRESH, DIRTY, char(DIRTY | FRESH)};
573586
const static auto CLEAN_FLAGS = {char(0), FRESH};
574587
const static auto ABSENT_FLAGS = {NO_ENTRY};
@@ -585,77 +598,67 @@ static void SetCoinsValue(CAmount value, Coin& coin)
585598
}
586599
}
587600

588-
static size_t InsertCoinsMapEntry(CCoinsMap& map, CoinsCachePair& sentinel, CAmount value, char flags)
601+
static size_t InsertCoinsMapEntry(CCoinsMap& map, CoinsCachePair& sentinel, const CoinEntry& cache_coin)
589602
{
590-
if (value == ABSENT) {
591-
assert(flags == NO_ENTRY);
603+
if (cache_coin.value == ABSENT) {
604+
assert(cache_coin.flags == NO_ENTRY);
592605
return 0;
593606
}
594-
assert(flags != NO_ENTRY);
607+
assert(cache_coin.flags != NO_ENTRY);
595608
CCoinsCacheEntry entry;
596-
SetCoinsValue(value, entry.coin);
609+
SetCoinsValue(cache_coin.value, entry.coin);
597610
auto inserted = map.emplace(OUTPOINT, std::move(entry));
598611
assert(inserted.second);
599-
if (flags & DIRTY) CCoinsCacheEntry::SetDirty(*inserted.first, sentinel);
600-
if (flags & FRESH) CCoinsCacheEntry::SetFresh(*inserted.first, sentinel);
612+
if (cache_coin.flags & DIRTY) CCoinsCacheEntry::SetDirty(*inserted.first, sentinel);
613+
if (cache_coin.flags & FRESH) CCoinsCacheEntry::SetFresh(*inserted.first, sentinel);
601614
return inserted.first->second.coin.DynamicMemoryUsage();
602615
}
603616

604-
void GetCoinsMapEntry(const CCoinsMap& map, CAmount& value, char& flags, const COutPoint& outp = OUTPOINT)
617+
MaybeCoin GetCoinsMapEntry(const CCoinsMap& map, const COutPoint& outp = OUTPOINT)
605618
{
606-
auto it = map.find(outp);
607-
if (it == map.end()) {
608-
value = ABSENT;
609-
flags = NO_ENTRY;
610-
} else {
611-
if (it->second.coin.IsSpent()) {
612-
value = SPENT;
613-
} else {
614-
value = it->second.coin.out.nValue;
615-
}
616-
flags = 0;
617-
if (it->second.IsDirty()) flags |= DIRTY;
618-
if (it->second.IsFresh()) flags |= FRESH;
619-
assert(flags != NO_ENTRY);
619+
if (auto it{map.find(outp)}; it != map.end()) {
620+
return CoinEntry{
621+
it->second.coin.IsSpent() ? SPENT : it->second.coin.out.nValue,
622+
static_cast<char>((it->second.IsDirty() ? DIRTY : 0) | (it->second.IsFresh() ? FRESH : 0))};
620623
}
624+
return CoinEntry{ABSENT, NO_ENTRY}; // TODO empty
621625
}
622626

623-
void WriteCoinsViewEntry(CCoinsView& view, CAmount value, char flags)
627+
void WriteCoinsViewEntry(CCoinsView& view, const CoinEntry& cache_coin)
624628
{
625629
CoinsCachePair sentinel{};
626630
sentinel.second.SelfRef(sentinel);
627631
CCoinsMapMemoryResource resource;
628632
CCoinsMap map{0, CCoinsMap::hasher{}, CCoinsMap::key_equal{}, &resource};
629-
auto usage{InsertCoinsMapEntry(map, sentinel, value, flags)};
633+
auto usage{InsertCoinsMapEntry(map, sentinel, cache_coin)};
630634
auto cursor{CoinsViewCacheCursor(usage, sentinel, map, /*will_erase=*/true)};
631635
BOOST_CHECK(view.BatchWrite(cursor, {}));
632636
}
633637

634638
class SingleEntryCacheTest
635639
{
636640
public:
637-
SingleEntryCacheTest(CAmount base_value, CAmount cache_value, char cache_flags)
641+
SingleEntryCacheTest(CAmount base_value, const CoinEntry& cache_coin)
638642
{
639-
WriteCoinsViewEntry(base, base_value, base_value == ABSENT ? NO_ENTRY : DIRTY);
640-
cache.usage() += InsertCoinsMapEntry(cache.map(), cache.sentinel(), cache_value, cache_flags);
643+
WriteCoinsViewEntry(base, CoinEntry{base_value, base_value == ABSENT ? NO_ENTRY : DIRTY}); // TODO complete state should be absent
644+
cache.usage() += InsertCoinsMapEntry(cache.map(), cache.sentinel(), cache_coin);
641645
}
642646

643647
CCoinsView root;
644648
CCoinsViewCacheTest base{&root};
645649
CCoinsViewCacheTest cache{&base};
646650
};
647651

648-
static void CheckAccessCoin(CAmount base_value, CAmount cache_value, CAmount expected_value, char cache_flags, char expected_flags)
652+
static void CheckAccessCoin(CAmount base_value, const CoinEntry& cache_coin, const CoinEntry& expected)
649653
{
650-
SingleEntryCacheTest test(base_value, cache_value, cache_flags);
654+
SingleEntryCacheTest test{base_value, cache_coin};
651655
test.cache.AccessCoin(OUTPOINT);
652656
test.cache.SelfTest(/*sanity_check=*/false);
653-
654-
CAmount result_value;
655-
char result_flags;
656-
GetCoinsMapEntry(test.cache.map(), result_value, result_flags);
657-
BOOST_CHECK_EQUAL(result_value, expected_value);
658-
BOOST_CHECK_EQUAL(result_flags, expected_flags);
657+
BOOST_CHECK_EQUAL(GetCoinsMapEntry(test.cache.map()), expected);
658+
}
659+
static void CheckAccessCoin(CAmount base_value, CAmount cache_value, CAmount expected_value, char cache_flags, char expected_flags)
660+
{
661+
CheckAccessCoin(base_value, CoinEntry{cache_value, cache_flags}, CoinEntry{expected_value, expected_flags});
659662
}
660663

661664
BOOST_AUTO_TEST_CASE(ccoins_access)
@@ -696,18 +699,17 @@ BOOST_AUTO_TEST_CASE(ccoins_access)
696699
CheckAccessCoin(VALUE1, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);
697700
}
698701

699-
static void CheckSpendCoins(CAmount base_value, CAmount cache_value, CAmount expected_value, char cache_flags, char expected_flags)
702+
static void CheckSpendCoins(CAmount base_value, const CoinEntry& cache_coin, const CoinEntry& expected)
700703
{
701-
SingleEntryCacheTest test(base_value, cache_value, cache_flags);
704+
SingleEntryCacheTest test{base_value, cache_coin};
702705
test.cache.SpendCoin(OUTPOINT);
703706
test.cache.SelfTest();
704-
705-
CAmount result_value;
706-
char result_flags;
707-
GetCoinsMapEntry(test.cache.map(), result_value, result_flags);
708-
BOOST_CHECK_EQUAL(result_value, expected_value);
709-
BOOST_CHECK_EQUAL(result_flags, expected_flags);
710-
};
707+
BOOST_CHECK_EQUAL(GetCoinsMapEntry(test.cache.map()), expected);
708+
}
709+
static void CheckSpendCoins(CAmount base_value, CAmount cache_value, CAmount expected_value, char cache_flags, char expected_flags)
710+
{
711+
CheckSpendCoins(base_value, CoinEntry{cache_value, cache_flags}, CoinEntry{expected_value, expected_flags});
712+
}
711713

712714
BOOST_AUTO_TEST_CASE(ccoins_spend)
713715
{
@@ -747,25 +749,22 @@ BOOST_AUTO_TEST_CASE(ccoins_spend)
747749
CheckSpendCoins(VALUE1, VALUE2, ABSENT, DIRTY|FRESH, NO_ENTRY );
748750
}
749751

750-
static void CheckAddCoinBase(CAmount base_value, CAmount cache_value, CAmount modify_value, CAmount expected_value, char cache_flags, char expected_flags, bool coinbase)
752+
static void CheckAddCoinBase(CAmount base_value, CAmount modify_value, const CoinEntry& cache_coin, const CoinEntry& expected, bool coinbase)
751753
{
752-
SingleEntryCacheTest test(base_value, cache_value, cache_flags);
753-
754-
CAmount result_value;
755-
char result_flags;
754+
SingleEntryCacheTest test{base_value, cache_coin};
756755
try {
757756
CTxOut output;
758757
output.nValue = modify_value;
759758
test.cache.AddCoin(OUTPOINT, Coin(std::move(output), 1, coinbase), coinbase);
760759
test.cache.SelfTest();
761-
GetCoinsMapEntry(test.cache.map(), result_value, result_flags);
760+
BOOST_CHECK_EQUAL(GetCoinsMapEntry(test.cache.map()), expected);
762761
} catch (std::logic_error&) {
763-
result_value = FAIL;
764-
result_flags = NO_ENTRY;
762+
BOOST_CHECK_EQUAL(CoinEntry(FAIL, NO_ENTRY), expected); // TODO empty
765763
}
766-
767-
BOOST_CHECK_EQUAL(result_value, expected_value);
768-
BOOST_CHECK_EQUAL(result_flags, expected_flags);
764+
}
765+
static void CheckAddCoinBase(CAmount base_value, CAmount cache_value, CAmount modify_value, CAmount expected_value, char cache_flags, char expected_flags, bool coinbase)
766+
{
767+
CheckAddCoinBase(base_value, modify_value, CoinEntry{cache_value, cache_flags}, CoinEntry{expected_value, expected_flags}, coinbase);
769768
}
770769

771770
// Simple wrapper for CheckAddCoinBase function above that loops through
@@ -810,23 +809,20 @@ BOOST_AUTO_TEST_CASE(ccoins_add)
810809
CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true );
811810
}
812811

813-
void CheckWriteCoins(CAmount parent_value, CAmount child_value, CAmount expected_value, char parent_flags, char child_flags, char expected_flags)
812+
void CheckWriteCoins(const CoinEntry& parent, const CoinEntry& child, const CoinEntry& expected)
814813
{
815-
SingleEntryCacheTest test(ABSENT, parent_value, parent_flags);
816-
817-
CAmount result_value;
818-
char result_flags;
814+
SingleEntryCacheTest test{ABSENT, parent};
819815
try {
820-
WriteCoinsViewEntry(test.cache, child_value, child_flags);
816+
WriteCoinsViewEntry(test.cache, child);
821817
test.cache.SelfTest(/*sanity_check=*/false);
822-
GetCoinsMapEntry(test.cache.map(), result_value, result_flags);
818+
BOOST_CHECK_EQUAL(GetCoinsMapEntry(test.cache.map()), expected);
823819
} catch (std::logic_error&) {
824-
result_value = FAIL;
825-
result_flags = NO_ENTRY;
820+
BOOST_CHECK_EQUAL(CoinEntry(FAIL, NO_ENTRY), expected); // TODO empty
826821
}
827-
828-
BOOST_CHECK_EQUAL(result_value, expected_value);
829-
BOOST_CHECK_EQUAL(result_flags, expected_flags);
822+
}
823+
void CheckWriteCoins(CAmount parent_value, CAmount child_value, CAmount expected_value, char parent_flags, char child_flags, char expected_flags)
824+
{
825+
CheckWriteCoins(CoinEntry{parent_value, parent_flags}, CoinEntry{child_value, child_flags}, CoinEntry{expected_value, expected_flags});
830826
}
831827

832828
BOOST_AUTO_TEST_CASE(ccoins_write)
@@ -923,8 +919,6 @@ void TestFlushBehavior(
923919
std::vector<std::unique_ptr<CCoinsViewCacheTest>>& all_caches,
924920
bool do_erasing_flush)
925921
{
926-
CAmount value;
927-
char flags;
928922
size_t cache_usage;
929923
size_t cache_size;
930924

@@ -958,9 +952,7 @@ void TestFlushBehavior(
958952
BOOST_CHECK(!base.HaveCoin(outp));
959953
BOOST_CHECK(view->HaveCoin(outp));
960954

961-
GetCoinsMapEntry(view->map(), value, flags, outp);
962-
BOOST_CHECK_EQUAL(value, coin.out.nValue);
963-
BOOST_CHECK_EQUAL(flags, DIRTY|FRESH);
955+
BOOST_CHECK_EQUAL(GetCoinsMapEntry(view->map(), outp), CoinEntry(coin.out.nValue, DIRTY|FRESH));
964956

965957
// --- 2. Flushing all caches (without erasing)
966958
//
@@ -972,9 +964,7 @@ void TestFlushBehavior(
972964

973965
// --- 3. Ensuring the entry still exists in the cache and has been written to parent
974966
//
975-
GetCoinsMapEntry(view->map(), value, flags, outp);
976-
BOOST_CHECK_EQUAL(value, coin.out.nValue);
977-
BOOST_CHECK_EQUAL(flags, 0); // Flags should have been wiped.
967+
BOOST_CHECK_EQUAL(GetCoinsMapEntry(view->map(), outp), CoinEntry(coin.out.nValue, 0)); // Flags should have been wiped.
978968

979969
// Both views should now have the coin.
980970
BOOST_CHECK(base.HaveCoin(outp));
@@ -992,14 +982,9 @@ void TestFlushBehavior(
992982

993983
// --- 5. Ensuring the entry is no longer in the cache
994984
//
995-
GetCoinsMapEntry(view->map(), value, flags, outp);
996-
BOOST_CHECK_EQUAL(value, ABSENT);
997-
BOOST_CHECK_EQUAL(flags, NO_ENTRY);
998-
985+
BOOST_CHECK_EQUAL(GetCoinsMapEntry(view->map(), outp), CoinEntry(ABSENT, NO_ENTRY));
999986
view->AccessCoin(outp);
1000-
GetCoinsMapEntry(view->map(), value, flags, outp);
1001-
BOOST_CHECK_EQUAL(value, coin.out.nValue);
1002-
BOOST_CHECK_EQUAL(flags, 0);
987+
BOOST_CHECK_EQUAL(GetCoinsMapEntry(view->map(), outp), CoinEntry(coin.out.nValue, 0));
1003988
}
1004989

1005990
// Can't overwrite an entry without specifying that an overwrite is
@@ -1013,9 +998,7 @@ void TestFlushBehavior(
1013998
BOOST_CHECK(view->SpendCoin(outp));
1014999

10151000
// The coin should be in the cache, but spent and marked dirty.
1016-
GetCoinsMapEntry(view->map(), value, flags, outp);
1017-
BOOST_CHECK_EQUAL(value, SPENT);
1018-
BOOST_CHECK_EQUAL(flags, DIRTY);
1001+
BOOST_CHECK_EQUAL(GetCoinsMapEntry(view->map(), outp), CoinEntry(SPENT, DIRTY));
10191002
BOOST_CHECK(!view->HaveCoin(outp)); // Coin should be considered spent in `view`.
10201003
BOOST_CHECK(base.HaveCoin(outp)); // But coin should still be unspent in `base`.
10211004

@@ -1066,20 +1049,15 @@ void TestFlushBehavior(
10661049
all_caches[0]->AddCoin(outp, std::move(coin), false);
10671050

10681051
// Coin should be FRESH in the cache.
1069-
GetCoinsMapEntry(all_caches[0]->map(), value, flags, outp);
1070-
BOOST_CHECK_EQUAL(value, coin_val);
1071-
BOOST_CHECK_EQUAL(flags, DIRTY|FRESH);
1072-
1052+
BOOST_CHECK_EQUAL(GetCoinsMapEntry(all_caches[0]->map(), outp), CoinEntry(coin_val, DIRTY|FRESH));
10731053
// Base shouldn't have seen coin.
10741054
BOOST_CHECK(!base.HaveCoin(outp));
10751055

10761056
BOOST_CHECK(all_caches[0]->SpendCoin(outp));
10771057
all_caches[0]->Sync();
10781058

10791059
// Ensure there is no sign of the coin after spend/flush.
1080-
GetCoinsMapEntry(all_caches[0]->map(), value, flags, outp);
1081-
BOOST_CHECK_EQUAL(value, ABSENT);
1082-
BOOST_CHECK_EQUAL(flags, NO_ENTRY);
1060+
BOOST_CHECK_EQUAL(GetCoinsMapEntry(all_caches[0]->map(), outp), CoinEntry(ABSENT, NO_ENTRY));
10831061
BOOST_CHECK(!all_caches[0]->HaveCoinInCache(outp));
10841062
BOOST_CHECK(!base.HaveCoin(outp));
10851063
}

0 commit comments

Comments
 (0)