@@ -565,10 +565,23 @@ const static CAmount FAIL = -3;
565
565
const static CAmount VALUE1 = 100 ;
566
566
const static CAmount VALUE2 = 200 ;
567
567
const static CAmount VALUE3 = 300 ;
568
+
568
569
const static char DIRTY = CCoinsCacheEntry::DIRTY;
569
570
const static char FRESH = CCoinsCacheEntry::FRESH;
570
571
const static char NO_ENTRY = -1 ;
571
572
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
+
572
585
const static auto FLAGS = {char (0 ), FRESH, DIRTY, char (DIRTY | FRESH)};
573
586
const static auto CLEAN_FLAGS = {char (0 ), FRESH};
574
587
const static auto ABSENT_FLAGS = {NO_ENTRY};
@@ -585,77 +598,67 @@ static void SetCoinsValue(CAmount value, Coin& coin)
585
598
}
586
599
}
587
600
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 )
589
602
{
590
- if (value == ABSENT) {
591
- assert (flags == NO_ENTRY);
603
+ if (cache_coin. value == ABSENT) {
604
+ assert (cache_coin. flags == NO_ENTRY);
592
605
return 0 ;
593
606
}
594
- assert (flags != NO_ENTRY);
607
+ assert (cache_coin. flags != NO_ENTRY);
595
608
CCoinsCacheEntry entry;
596
- SetCoinsValue (value, entry.coin );
609
+ SetCoinsValue (cache_coin. value , entry.coin );
597
610
auto inserted = map.emplace (OUTPOINT, std::move (entry));
598
611
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);
601
614
return inserted.first ->second .coin .DynamicMemoryUsage ();
602
615
}
603
616
604
- void GetCoinsMapEntry (const CCoinsMap& map, CAmount& value, char & flags , const COutPoint& outp = OUTPOINT)
617
+ MaybeCoin GetCoinsMapEntry (const CCoinsMap& map, const COutPoint& outp = OUTPOINT)
605
618
{
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 ))};
620
623
}
624
+ return CoinEntry{ABSENT, NO_ENTRY}; // TODO empty
621
625
}
622
626
623
- void WriteCoinsViewEntry (CCoinsView& view, CAmount value, char flags )
627
+ void WriteCoinsViewEntry (CCoinsView& view, const CoinEntry& cache_coin )
624
628
{
625
629
CoinsCachePair sentinel{};
626
630
sentinel.second .SelfRef (sentinel);
627
631
CCoinsMapMemoryResource resource;
628
632
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 )};
630
634
auto cursor{CoinsViewCacheCursor (usage, sentinel, map, /* will_erase=*/ true )};
631
635
BOOST_CHECK (view.BatchWrite (cursor, {}));
632
636
}
633
637
634
638
class SingleEntryCacheTest
635
639
{
636
640
public:
637
- SingleEntryCacheTest (CAmount base_value, CAmount cache_value, char cache_flags )
641
+ SingleEntryCacheTest (CAmount base_value, const CoinEntry& cache_coin )
638
642
{
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 );
641
645
}
642
646
643
647
CCoinsView root;
644
648
CCoinsViewCacheTest base{&root};
645
649
CCoinsViewCacheTest cache{&base};
646
650
};
647
651
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 )
649
653
{
650
- SingleEntryCacheTest test ( base_value, cache_value, cache_flags) ;
654
+ SingleEntryCacheTest test{ base_value, cache_coin} ;
651
655
test.cache .AccessCoin (OUTPOINT);
652
656
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});
659
662
}
660
663
661
664
BOOST_AUTO_TEST_CASE (ccoins_access)
@@ -696,18 +699,17 @@ BOOST_AUTO_TEST_CASE(ccoins_access)
696
699
CheckAccessCoin (VALUE1, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);
697
700
}
698
701
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 )
700
703
{
701
- SingleEntryCacheTest test ( base_value, cache_value, cache_flags) ;
704
+ SingleEntryCacheTest test{ base_value, cache_coin} ;
702
705
test.cache .SpendCoin (OUTPOINT);
703
706
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
+ }
711
713
712
714
BOOST_AUTO_TEST_CASE (ccoins_spend)
713
715
{
@@ -747,25 +749,22 @@ BOOST_AUTO_TEST_CASE(ccoins_spend)
747
749
CheckSpendCoins (VALUE1, VALUE2, ABSENT, DIRTY|FRESH, NO_ENTRY );
748
750
}
749
751
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)
751
753
{
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};
756
755
try {
757
756
CTxOut output;
758
757
output.nValue = modify_value;
759
758
test.cache .AddCoin (OUTPOINT, Coin (std::move (output), 1 , coinbase), coinbase);
760
759
test.cache .SelfTest ();
761
- GetCoinsMapEntry (test.cache .map (), result_value, result_flags );
760
+ BOOST_CHECK_EQUAL ( GetCoinsMapEntry (test.cache .map ()), expected );
762
761
} catch (std::logic_error&) {
763
- result_value = FAIL;
764
- result_flags = NO_ENTRY;
762
+ BOOST_CHECK_EQUAL (CoinEntry (FAIL, NO_ENTRY), expected); // TODO empty
765
763
}
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);
769
768
}
770
769
771
770
// Simple wrapper for CheckAddCoinBase function above that loops through
@@ -810,23 +809,20 @@ BOOST_AUTO_TEST_CASE(ccoins_add)
810
809
CheckAddCoin (VALUE2, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true );
811
810
}
812
811
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 )
814
813
{
815
- SingleEntryCacheTest test (ABSENT, parent_value, parent_flags);
816
-
817
- CAmount result_value;
818
- char result_flags;
814
+ SingleEntryCacheTest test{ABSENT, parent};
819
815
try {
820
- WriteCoinsViewEntry (test.cache , child_value, child_flags );
816
+ WriteCoinsViewEntry (test.cache , child );
821
817
test.cache .SelfTest (/* sanity_check=*/ false );
822
- GetCoinsMapEntry (test.cache .map (), result_value, result_flags );
818
+ BOOST_CHECK_EQUAL ( GetCoinsMapEntry (test.cache .map ()), expected );
823
819
} catch (std::logic_error&) {
824
- result_value = FAIL;
825
- result_flags = NO_ENTRY;
820
+ BOOST_CHECK_EQUAL (CoinEntry (FAIL, NO_ENTRY), expected); // TODO empty
826
821
}
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});
830
826
}
831
827
832
828
BOOST_AUTO_TEST_CASE (ccoins_write)
@@ -923,8 +919,6 @@ void TestFlushBehavior(
923
919
std::vector<std::unique_ptr<CCoinsViewCacheTest>>& all_caches,
924
920
bool do_erasing_flush)
925
921
{
926
- CAmount value;
927
- char flags;
928
922
size_t cache_usage;
929
923
size_t cache_size;
930
924
@@ -958,9 +952,7 @@ void TestFlushBehavior(
958
952
BOOST_CHECK (!base.HaveCoin (outp));
959
953
BOOST_CHECK (view->HaveCoin (outp));
960
954
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));
964
956
965
957
// --- 2. Flushing all caches (without erasing)
966
958
//
@@ -972,9 +964,7 @@ void TestFlushBehavior(
972
964
973
965
// --- 3. Ensuring the entry still exists in the cache and has been written to parent
974
966
//
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.
978
968
979
969
// Both views should now have the coin.
980
970
BOOST_CHECK (base.HaveCoin (outp));
@@ -992,14 +982,9 @@ void TestFlushBehavior(
992
982
993
983
// --- 5. Ensuring the entry is no longer in the cache
994
984
//
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));
999
986
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 ));
1003
988
}
1004
989
1005
990
// Can't overwrite an entry without specifying that an overwrite is
@@ -1013,9 +998,7 @@ void TestFlushBehavior(
1013
998
BOOST_CHECK (view->SpendCoin (outp));
1014
999
1015
1000
// 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));
1019
1002
BOOST_CHECK (!view->HaveCoin (outp)); // Coin should be considered spent in `view`.
1020
1003
BOOST_CHECK (base.HaveCoin (outp)); // But coin should still be unspent in `base`.
1021
1004
@@ -1066,20 +1049,15 @@ void TestFlushBehavior(
1066
1049
all_caches[0 ]->AddCoin (outp, std::move (coin), false );
1067
1050
1068
1051
// 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));
1073
1053
// Base shouldn't have seen coin.
1074
1054
BOOST_CHECK (!base.HaveCoin (outp));
1075
1055
1076
1056
BOOST_CHECK (all_caches[0 ]->SpendCoin (outp));
1077
1057
all_caches[0 ]->Sync ();
1078
1058
1079
1059
// 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));
1083
1061
BOOST_CHECK (!all_caches[0 ]->HaveCoinInCache (outp));
1084
1062
BOOST_CHECK (!base.HaveCoin (outp));
1085
1063
}
0 commit comments