We need this method because of the specialized database access which doesn’t need to deserialize the read value:
Otherwise we could of course replace it with !!GetCoin(outpoint):
We’re not even really using the former in production code anyway (see #34132), we could probably easily inline the !!GetCoin(outpoint) to the few remaining call sites instead. Regardless, the current change should simplify usage and we can investigate that later.
Also, the underlying problem is that having a separate CCoinsView makes adding defaults weird, there’s no logical default behavior.
But we could inline it into CCoinsViewBacked (and delete CCoinsView and rename CCoinsViewBacked back to CCoinsView) and use that as the base for the other caches, with the default implementation simply delegating to base, something like:
0diff --git a/src/coins.cpp b/src/coins.cpp
1index 9bdcb42f45..4f66ed447b 100644
2--- a/src/coins.cpp
3+++ b/src/coins.cpp
4@@ -14,7 +14,7 @@ TRACEPOINT_SEMAPHORE(utxocache, spent);
5 TRACEPOINT_SEMAPHORE(utxocache, uncache);
6
7 CCoinsViewCache::CCoinsViewCache(CCoinsView* baseIn, bool deterministic) :
8- CCoinsViewBacked(baseIn), m_deterministic(deterministic),
9+ CCoinsView(baseIn), m_deterministic(deterministic),
10 cacheCoins(0, SaltedOutpointHasher(/*deterministic=*/deterministic), CCoinsMap::key_equal{}, &m_cache_coins_memory_resource)
11 {
12 m_sentinel.second.SelfRef(m_sentinel);
13@@ -362,10 +362,10 @@ static ReturnType ExecuteBackedWrapper(Func func, const std::vector<std::functio
14
15 std::optional<Coin> CCoinsViewErrorCatcher::GetCoin(const COutPoint& outpoint) const
16 {
17- return ExecuteBackedWrapper<std::optional<Coin>>([&]() { return CCoinsViewBacked::GetCoin(outpoint); }, m_err_callbacks);
18+ return ExecuteBackedWrapper<std::optional<Coin>>([&]() { return CCoinsView::GetCoin(outpoint); }, m_err_callbacks);
19 }
20
21 bool CCoinsViewErrorCatcher::HaveCoin(const COutPoint& outpoint) const
22 {
23- return ExecuteBackedWrapper<bool>([&]() { return CCoinsViewBacked::HaveCoin(outpoint); }, m_err_callbacks);
24+ return ExecuteBackedWrapper<bool>([&]() { return CCoinsView::HaveCoin(outpoint); }, m_err_callbacks);
25 }
26diff --git a/src/coins.h b/src/coins.h
27index a64f30376d..7e8120f710 100644
28--- a/src/coins.h
29+++ b/src/coins.h
30@@ -303,37 +303,46 @@ private:
31 bool m_will_erase;
32 };
33
34-/** Pure abstract view on the open txout dataset. */
35+/** Coins view backed by another CCoinsView. */
36 class CCoinsView
37 {
38+protected:
39+ CCoinsView* base{nullptr};
40+
41+ CCoinsView() = default;
42+
43 public:
44+ explicit CCoinsView(CCoinsView* viewIn) : base(Assert(viewIn)) {}
45+
46 //! As we use CCoinsViews polymorphically, have a virtual destructor
47 virtual ~CCoinsView() = default;
48
49+ void SetBackend(CCoinsView& viewIn) { base = &viewIn; }
50+
51 //! Retrieve the Coin (unspent transaction output) for a given outpoint.
52- virtual std::optional<Coin> GetCoin(const COutPoint& outpoint) const = 0;
53+ virtual std::optional<Coin> GetCoin(const COutPoint& outpoint) const { return base->GetCoin(outpoint); }
54
55 //! Just check whether a given outpoint is unspent.
56- virtual bool HaveCoin(const COutPoint& outpoint) const = 0;
57+ virtual bool HaveCoin(const COutPoint& outpoint) const { return base->HaveCoin(outpoint); }
58
59 //! Retrieve the block hash whose state this CCoinsView currently represents
60- virtual uint256 GetBestBlock() const = 0;
61+ virtual uint256 GetBestBlock() const { return base->GetBestBlock(); }
62
63 //! Retrieve the range of blocks that may have been only partially written.
64 //! If the database is in a consistent state, the result is the empty vector.
65 //! Otherwise, a two-element vector is returned consisting of the new and
66 //! the old block hash, in that order.
67- virtual std::vector<uint256> GetHeadBlocks() const = 0;
68+ virtual std::vector<uint256> GetHeadBlocks() const { return base->GetHeadBlocks(); }
69
70 //! Do a bulk modification (multiple Coin changes + BestBlock change).
71 //! The passed cursor is used to iterate through the coins.
72- virtual bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock) = 0;
73+ virtual bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock) { return base->BatchWrite(cursor, hashBlock); }
74
75 //! Get a cursor to iterate over the whole state
76- virtual std::unique_ptr<CCoinsViewCursor> Cursor() const = 0;
77+ virtual std::unique_ptr<CCoinsViewCursor> Cursor() const { return base->Cursor(); }
78
79 //! Estimate database size
80- virtual size_t EstimateSize() const = 0;
81+ virtual size_t EstimateSize() const { return base->EstimateSize(); }
82 };
83
84 /** Noop coins view. */
85@@ -361,28 +370,8 @@ public:
86 size_t EstimateSize() const override { return 0; }
87 };
88
89-/** CCoinsView backed by another CCoinsView */
90-class CCoinsViewBacked : public CCoinsView
91-{
92-protected:
93- CCoinsView* base;
94-
95-public:
96- explicit CCoinsViewBacked(CCoinsView* viewIn) : base{viewIn} {}
97-
98- void SetBackend(CCoinsView& viewIn) { base = &viewIn; }
99-
100- std::optional<Coin> GetCoin(const COutPoint& outpoint) const override { return base->GetCoin(outpoint); }
101- bool HaveCoin(const COutPoint& outpoint) const override { return base->HaveCoin(outpoint); }
102- uint256 GetBestBlock() const override { return base->GetBestBlock(); }
103- std::vector<uint256> GetHeadBlocks() const override { return base->GetHeadBlocks(); }
104- bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock) override { return base->BatchWrite(cursor, hashBlock); }
105- std::unique_ptr<CCoinsViewCursor> Cursor() const override { return base->Cursor(); }
106- size_t EstimateSize() const override { return base->EstimateSize(); }
107-};
108-
109 /** CCoinsView that adds a memory cache for transactions to another CCoinsView */
110-class CCoinsViewCache : public CCoinsViewBacked
111+class CCoinsViewCache : public CCoinsView
112 {
113 private:
114 const bool m_deterministic;
115@@ -534,10 +523,10 @@ const Coin& AccessByTxid(const CCoinsViewCache& cache, const Txid& txid);
116 *
117 * Writes do not need similar protection, as failure to write is handled by the caller.
118 */
119-class CCoinsViewErrorCatcher final : public CCoinsViewBacked
120+class CCoinsViewErrorCatcher final : public CCoinsView
121 {
122 public:
123- explicit CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {}
124+ explicit CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsView(view) {}
125
126 void AddReadErrCallback(std::function<void()> f) {
127 m_err_callbacks.emplace_back(std::move(f));
128diff --git a/src/txmempool.cpp b/src/txmempool.cpp
129index 4dc692bfd8..3e47428e8e 100644
130--- a/src/txmempool.cpp
131+++ b/src/txmempool.cpp
132@@ -720,7 +720,7 @@ bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const
133 return true;
134 }
135
136-CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
137+CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn) : CCoinsView(baseIn), mempool(mempoolIn) { }
138
139 std::optional<Coin> CCoinsViewMemPool::GetCoin(const COutPoint& outpoint) const
140 {
141diff --git a/src/txmempool.h b/src/txmempool.h
142index 166a024823..4c24766c77 100644
143--- a/src/txmempool.h
144+++ b/src/txmempool.h
145@@ -778,7 +778,7 @@ public:
146 * signrawtransactionwithkey and signrawtransactionwithwallet,
147 * as long as the conflicting transaction is not yet confirmed.
148 */
149-class CCoinsViewMemPool : public CCoinsViewBacked
150+class CCoinsViewMemPool : public CCoinsView
151 {
152 /**
153 * Coins made available by transactions being validated. Tracking these allows for package
This would introduce a sensible default as the base class behavior (always delegating) and we’d instantiate it with the empty sigleton, which would always do nothin’.
I haven’t included this yet, we can discuss if it’s a good idea.