@@ -567,38 +567,47 @@ constexpr CAmount VALUE1{100};
567567constexpr CAmount VALUE2{200 };
568568constexpr CAmount VALUE3{300 };
569569
570- constexpr char DIRTY{CCoinsCacheEntry::DIRTY};
571- constexpr char FRESH{CCoinsCacheEntry::FRESH};
572- constexpr char CLEAN{0 };
573-
574570struct CoinEntry {
571+ enum class State { CLEAN, DIRTY, FRESH, DIRTY_FRESH };
572+
575573 const CAmount value;
576- const char flags ;
574+ const State state ;
577575
578- constexpr CoinEntry (const CAmount v, const char s) : value{v}, flags {s} {}
576+ constexpr CoinEntry (const CAmount v, const State s) : value{v}, state {s} {}
579577
580578 bool operator ==(const CoinEntry& o) const = default ;
581- friend std::ostream& operator <<(std::ostream& os, const CoinEntry& e) { return os << e.value << " , " << e.flags ; }
579+ friend std::ostream& operator <<(std::ostream& os, const CoinEntry& e) { return os << e.value << " , " << e.state ; }
580+
581+ constexpr bool IsDirtyFresh () const { return state == State::DIRTY_FRESH; }
582+ constexpr bool IsDirty () const { return state == State::DIRTY || IsDirtyFresh (); }
583+ constexpr bool IsFresh () const { return state == State::FRESH || IsDirtyFresh (); }
584+
585+ static constexpr State ToState (const bool is_dirty, const bool is_fresh) {
586+ if (is_dirty && is_fresh) return State::DIRTY_FRESH;
587+ if (is_dirty) return State::DIRTY;
588+ if (is_fresh) return State::FRESH;
589+ return State::CLEAN;
590+ }
582591};
583592
584593using MaybeCoin = std::optional<CoinEntry>;
585594using CoinOrError = std::variant<MaybeCoin, std::string>;
586595
587596constexpr MaybeCoin MISSING {std::nullopt };
588- constexpr MaybeCoin SPENT_DIRTY {{SPENT, DIRTY}};
589- constexpr MaybeCoin SPENT_DIRTY_FRESH {{SPENT, DIRTY | FRESH }};
590- constexpr MaybeCoin SPENT_FRESH {{SPENT, FRESH}};
591- constexpr MaybeCoin SPENT_CLEAN {{SPENT, CLEAN}};
592- constexpr MaybeCoin VALUE1_DIRTY {{VALUE1, DIRTY}};
593- constexpr MaybeCoin VALUE1_DIRTY_FRESH{{VALUE1, DIRTY | FRESH }};
594- constexpr MaybeCoin VALUE1_FRESH {{VALUE1, FRESH}};
595- constexpr MaybeCoin VALUE1_CLEAN {{VALUE1, CLEAN}};
596- constexpr MaybeCoin VALUE2_DIRTY {{VALUE2, DIRTY}};
597- constexpr MaybeCoin VALUE2_DIRTY_FRESH{{VALUE2, DIRTY | FRESH }};
598- constexpr MaybeCoin VALUE2_FRESH {{VALUE2, FRESH}};
599- constexpr MaybeCoin VALUE2_CLEAN {{VALUE2, CLEAN}};
600- constexpr MaybeCoin VALUE3_DIRTY {{VALUE3, DIRTY}};
601- constexpr MaybeCoin VALUE3_DIRTY_FRESH{{VALUE3, DIRTY | FRESH }};
597+ constexpr MaybeCoin SPENT_DIRTY {{SPENT, CoinEntry::State:: DIRTY}};
598+ constexpr MaybeCoin SPENT_DIRTY_FRESH {{SPENT, CoinEntry::State::DIRTY_FRESH }};
599+ constexpr MaybeCoin SPENT_FRESH {{SPENT, CoinEntry::State:: FRESH}};
600+ constexpr MaybeCoin SPENT_CLEAN {{SPENT, CoinEntry::State:: CLEAN}};
601+ constexpr MaybeCoin VALUE1_DIRTY {{VALUE1, CoinEntry::State:: DIRTY}};
602+ constexpr MaybeCoin VALUE1_DIRTY_FRESH{{VALUE1, CoinEntry::State::DIRTY_FRESH }};
603+ constexpr MaybeCoin VALUE1_FRESH {{VALUE1, CoinEntry::State:: FRESH}};
604+ constexpr MaybeCoin VALUE1_CLEAN {{VALUE1, CoinEntry::State:: CLEAN}};
605+ constexpr MaybeCoin VALUE2_DIRTY {{VALUE2, CoinEntry::State:: DIRTY}};
606+ constexpr MaybeCoin VALUE2_DIRTY_FRESH{{VALUE2, CoinEntry::State::DIRTY_FRESH }};
607+ constexpr MaybeCoin VALUE2_FRESH {{VALUE2, CoinEntry::State:: FRESH}};
608+ constexpr MaybeCoin VALUE2_CLEAN {{VALUE2, CoinEntry::State:: CLEAN}};
609+ constexpr MaybeCoin VALUE3_DIRTY {{VALUE3, CoinEntry::State:: DIRTY}};
610+ constexpr MaybeCoin VALUE3_DIRTY_FRESH{{VALUE3, CoinEntry::State::DIRTY_FRESH }};
602611
603612constexpr auto EX_OVERWRITE_UNSPENT{" Attempted to overwrite an unspent coin (when possible_overwrite is false)" };
604613constexpr 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
621630 SetCoinsValue (cache_coin.value , entry.coin );
622631 auto [iter, inserted] = map.emplace (OUTPOINT, std::move (entry));
623632 assert (inserted);
624- if (cache_coin.flags & DIRTY ) CCoinsCacheEntry::SetDirty (*iter, sentinel);
625- if (cache_coin.flags & FRESH ) CCoinsCacheEntry::SetFresh (*iter, sentinel);
633+ if (cache_coin.IsDirty () ) CCoinsCacheEntry::SetDirty (*iter, sentinel);
634+ if (cache_coin.IsFresh () ) CCoinsCacheEntry::SetFresh (*iter, sentinel);
626635 return iter->second .coin .DynamicMemoryUsage ();
627636}
628637
629- MaybeCoin GetCoinsMapEntry (const CCoinsMap& map, const COutPoint& outp = OUTPOINT)
638+ static MaybeCoin GetCoinsMapEntry (const CCoinsMap& map, const COutPoint& outp = OUTPOINT)
630639{
631640 if (auto it{map.find (outp)}; it != map.end ()) {
632641 return CoinEntry{
633642 it->second .coin .IsSpent () ? SPENT : it->second .coin .out .nValue ,
634- static_cast < char >(( it->second .IsDirty () ? DIRTY : 0 ) | ( it->second .IsFresh () ? FRESH : 0 ))};
643+ CoinEntry::ToState ( it->second .IsDirty (), it->second .IsFresh ())};
635644 }
636645 return MISSING;
637646}
638647
639- void WriteCoinsViewEntry (CCoinsView& view, const MaybeCoin& cache_coin)
648+ static void WriteCoinsViewEntry (CCoinsView& view, const MaybeCoin& cache_coin)
640649{
641650 CoinsCachePair sentinel{};
642651 sentinel.second .SelfRef (sentinel);
@@ -652,7 +661,7 @@ class SingleEntryCacheTest
652661public:
653662 SingleEntryCacheTest (const CAmount base_value, const MaybeCoin& cache_coin)
654663 {
655- auto base_cache_coin{base_value == ABSENT ? MISSING : CoinEntry{base_value, DIRTY}};
664+ auto base_cache_coin{base_value == ABSENT ? MISSING : CoinEntry{base_value, CoinEntry::State:: DIRTY}};
656665 WriteCoinsViewEntry (base, base_cache_coin);
657666 if (cache_coin) cache.usage () += InsertCoinsMapEntry (cache.map (), cache.sentinel (), *cache_coin);
658667 }
@@ -800,7 +809,7 @@ BOOST_AUTO_TEST_CASE(ccoins_add)
800809 }
801810}
802811
803- void CheckWriteCoins (const MaybeCoin& parent, const MaybeCoin& child, const CoinOrError& expected)
812+ static void CheckWriteCoins (const MaybeCoin& parent, const MaybeCoin& child, const CoinOrError& expected)
804813{
805814 SingleEntryCacheTest test{ABSENT, parent};
806815 auto write_coins{[&] { WriteCoinsViewEntry (test.cache , child); }};
@@ -870,7 +879,7 @@ BOOST_AUTO_TEST_CASE(ccoins_write)
870879 CheckWriteCoins (VALUE1_DIRTY_FRESH, VALUE2_DIRTY, VALUE2_DIRTY_FRESH );
871880 CheckWriteCoins (VALUE1_DIRTY_FRESH, VALUE2_DIRTY_FRESH, EX_FRESH_MISAPPLIED);
872881
873- // The checks above omit cases where the child flags are not DIRTY, since
882+ // The checks above omit cases where the child state is not DIRTY, since
874883 // they would be too repetitive (the parent cache is never updated in these
875884 // cases). The loop below covers these cases and makes sure the parent cache
876885 // is always left unchanged.
@@ -946,7 +955,7 @@ void TestFlushBehavior(
946955 BOOST_CHECK (!base.HaveCoin (outp));
947956 BOOST_CHECK (view->HaveCoin (outp));
948957
949- BOOST_CHECK_EQUAL (GetCoinsMapEntry (view->map (), outp), CoinEntry (coin.out .nValue , DIRTY|FRESH ));
958+ BOOST_CHECK_EQUAL (GetCoinsMapEntry (view->map (), outp), CoinEntry (coin.out .nValue , CoinEntry::State::DIRTY_FRESH ));
950959
951960 // --- 2. Flushing all caches (without erasing)
952961 //
@@ -958,7 +967,7 @@ void TestFlushBehavior(
958967
959968 // --- 3. Ensuring the entry still exists in the cache and has been written to parent
960969 //
961- BOOST_CHECK_EQUAL (GetCoinsMapEntry (view->map (), outp), CoinEntry (coin.out .nValue , CLEAN)); // Flags should have been wiped.
970+ BOOST_CHECK_EQUAL (GetCoinsMapEntry (view->map (), outp), CoinEntry (coin.out .nValue , CoinEntry::State:: CLEAN)); // State should have been wiped.
962971
963972 // Both views should now have the coin.
964973 BOOST_CHECK (base.HaveCoin (outp));
@@ -978,7 +987,7 @@ void TestFlushBehavior(
978987 //
979988 BOOST_CHECK (!GetCoinsMapEntry (view->map (), outp));
980989 view->AccessCoin (outp);
981- BOOST_CHECK_EQUAL (GetCoinsMapEntry (view->map (), outp), CoinEntry (coin.out .nValue , CLEAN));
990+ BOOST_CHECK_EQUAL (GetCoinsMapEntry (view->map (), outp), CoinEntry (coin.out .nValue , CoinEntry::State:: CLEAN));
982991 }
983992
984993 // Can't overwrite an entry without specifying that an overwrite is
@@ -1043,7 +1052,7 @@ void TestFlushBehavior(
10431052 all_caches[0 ]->AddCoin (outp, std::move (coin), false );
10441053
10451054 // Coin should be FRESH in the cache.
1046- BOOST_CHECK_EQUAL (GetCoinsMapEntry (all_caches[0 ]->map (), outp), CoinEntry (coin_val, DIRTY|FRESH ));
1055+ BOOST_CHECK_EQUAL (GetCoinsMapEntry (all_caches[0 ]->map (), outp), CoinEntry (coin_val, CoinEntry::State::DIRTY_FRESH ));
10471056 // Base shouldn't have seen coin.
10481057 BOOST_CHECK (!base.HaveCoin (outp));
10491058
0 commit comments