4
4
5
5
#include " coins.h"
6
6
7
+ #include " consensus/consensus.h"
7
8
#include " memusage.h"
8
9
#include " random.h"
9
10
@@ -70,7 +71,7 @@ size_t CCoinsViewCache::DynamicMemoryUsage() const {
70
71
return memusage::DynamicUsage (cacheCoins) + cachedCoinsUsage;
71
72
}
72
73
73
- CCoinsMap::const_iterator CCoinsViewCache::FetchCoins (const uint256 &txid) const {
74
+ CCoinsMap::iterator CCoinsViewCache::FetchCoins (const uint256 &txid) const {
74
75
CCoinsMap::iterator it = cacheCoins.find (txid);
75
76
if (it != cacheCoins.end ())
76
77
return it;
@@ -153,6 +154,58 @@ CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid, bool coinbas
153
154
return CCoinsModifier (*this , ret.first , 0 );
154
155
}
155
156
157
+ void CCoinsViewCache::AddCoin (const COutPoint &outpoint, Coin&& coin, bool possible_overwrite) {
158
+ assert (!coin.IsPruned ());
159
+ if (coin.out .scriptPubKey .IsUnspendable ()) return ;
160
+ CCoinsMap::iterator it;
161
+ bool inserted;
162
+ std::tie (it, inserted) = cacheCoins.emplace (std::piecewise_construct, std::forward_as_tuple (outpoint.hash ), std::tuple<>());
163
+ bool fresh = false ;
164
+ if (!inserted) {
165
+ cachedCoinsUsage -= it->second .coins .DynamicMemoryUsage ();
166
+ }
167
+ if (!possible_overwrite) {
168
+ if (it->second .coins .IsAvailable (outpoint.n )) {
169
+ throw std::logic_error (" Adding new coin that replaces non-pruned entry" );
170
+ }
171
+ fresh = it->second .coins .IsPruned () && !(it->second .flags & CCoinsCacheEntry::DIRTY);
172
+ }
173
+ if (it->second .coins .vout .size () <= outpoint.n ) {
174
+ it->second .coins .vout .resize (outpoint.n + 1 );
175
+ }
176
+ it->second .coins .vout [outpoint.n ] = std::move (coin.out );
177
+ it->second .coins .nHeight = coin.nHeight ;
178
+ it->second .coins .fCoinBase = coin.fCoinBase ;
179
+ it->second .flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0 );
180
+ cachedCoinsUsage += it->second .coins .DynamicMemoryUsage ();
181
+ }
182
+
183
+ void AddCoins (CCoinsViewCache& cache, const CTransaction &tx, int nHeight) {
184
+ bool fCoinbase = tx.IsCoinBase ();
185
+ const uint256& txid = tx.GetHash ();
186
+ for (size_t i = 0 ; i < tx.vout .size (); ++i) {
187
+ // Pass fCoinbase as the possible_overwrite flag to AddCoin, in order to correctly
188
+ // deal with the pre-BIP30 occurrances of duplicate coinbase transactions.
189
+ cache.AddCoin (COutPoint (txid, i), Coin (tx.vout [i], nHeight, fCoinbase ), fCoinbase );
190
+ }
191
+ }
192
+
193
+ void CCoinsViewCache::SpendCoin (const COutPoint &outpoint, Coin* moveout) {
194
+ CCoinsMap::iterator it = FetchCoins (outpoint.hash );
195
+ if (it == cacheCoins.end ()) return ;
196
+ cachedCoinsUsage -= it->second .coins .DynamicMemoryUsage ();
197
+ if (moveout && it->second .coins .IsAvailable (outpoint.n )) {
198
+ *moveout = Coin (it->second .coins .vout [outpoint.n ], it->second .coins .nHeight , it->second .coins .fCoinBase );
199
+ }
200
+ it->second .coins .Spend (outpoint.n ); // Ignore return value: SpendCoin has no effect if no UTXO found.
201
+ if (it->second .coins .IsPruned () && it->second .flags & CCoinsCacheEntry::FRESH) {
202
+ cacheCoins.erase (it);
203
+ } else {
204
+ cachedCoinsUsage += it->second .coins .DynamicMemoryUsage ();
205
+ it->second .flags |= CCoinsCacheEntry::DIRTY;
206
+ }
207
+ }
208
+
156
209
const CCoins* CCoinsViewCache::AccessCoins (const uint256 &txid) const {
157
210
CCoinsMap::const_iterator it = FetchCoins (txid);
158
211
if (it == cacheCoins.end ()) {
@@ -162,6 +215,18 @@ const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const {
162
215
}
163
216
}
164
217
218
+ static const Coin coinEmpty;
219
+
220
+ const Coin CCoinsViewCache::AccessCoin (const COutPoint &outpoint) const {
221
+ CCoinsMap::const_iterator it = FetchCoins (outpoint.hash );
222
+ if (it == cacheCoins.end () || !it->second .coins .IsAvailable (outpoint.n )) {
223
+ return coinEmpty;
224
+ } else {
225
+ return Coin (it->second .coins .vout [outpoint.n ], it->second .coins .nHeight , it->second .coins .fCoinBase );
226
+ }
227
+ }
228
+
229
+
165
230
bool CCoinsViewCache::HaveCoins (const uint256 &txid) const {
166
231
CCoinsMap::const_iterator it = FetchCoins (txid);
167
232
// We're using vtx.empty() instead of IsPruned here for performance reasons,
@@ -171,6 +236,11 @@ bool CCoinsViewCache::HaveCoins(const uint256 &txid) const {
171
236
return (it != cacheCoins.end () && !it->second .coins .vout .empty ());
172
237
}
173
238
239
+ bool CCoinsViewCache::HaveCoins (const COutPoint &outpoint) const {
240
+ CCoinsMap::const_iterator it = FetchCoins (outpoint.hash );
241
+ return (it != cacheCoins.end () && it->second .coins .IsAvailable (outpoint.n ));
242
+ }
243
+
174
244
bool CCoinsViewCache::HaveCoinsInCache (const uint256 &txid) const {
175
245
CCoinsMap::const_iterator it = cacheCoins.find (txid);
176
246
return it != cacheCoins.end ();
@@ -318,3 +388,16 @@ CCoinsModifier::~CCoinsModifier()
318
388
CCoinsViewCursor::~CCoinsViewCursor ()
319
389
{
320
390
}
391
+
392
+ static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_BASE_SIZE / ::GetSerializeSize(CTxOut(), SER_NETWORK, PROTOCOL_VERSION); // TODO: merge with similar definition in undo.h.
393
+
394
+ const Coin AccessByTxid (const CCoinsViewCache& view, const uint256& txid)
395
+ {
396
+ COutPoint iter (txid, 0 );
397
+ while (iter.n < MAX_OUTPUTS_PER_BLOCK) {
398
+ const Coin& alternate = view.AccessCoin (iter);
399
+ if (!alternate.IsPruned ()) return alternate;
400
+ ++iter.n ;
401
+ }
402
+ return coinEmpty;
403
+ }
0 commit comments