Line data Source code
1 : // Copyright (c) 2012-2014 The Bitcoin developers
2 : // Copyright (c) 2015-2021 The PIVX Core developers
3 : // Distributed under the MIT software license, see the accompanying
4 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 :
6 : #include "coins.h"
7 :
8 : #include "consensus/consensus.h"
9 : #include "invalid.h"
10 : #include "logging.h"
11 : #include "random.h"
12 : #include "version.h"
13 :
14 : #include <assert.h>
15 :
16 25 : bool CCoinsView::GetCoin(const COutPoint& outpoint, Coin& coin) const { return false; }
17 0 : bool CCoinsView::HaveCoin(const COutPoint& outpoint) const { return false; }
18 0 : uint256 CCoinsView::GetBestBlock() const { return UINT256_ZERO; }
19 0 : std::vector<uint256> CCoinsView::GetHeadBlocks() const { return std::vector<uint256>(); }
20 0 : CCoinsViewCursor *CCoinsView::Cursor() const { return 0; }
21 :
22 0 : bool CCoinsView::BatchWrite(CCoinsMap& mapCoins,
23 : const uint256& hashBlock,
24 : const uint256& hashSaplingAnchor,
25 : CAnchorsSaplingMap& mapSaplingAnchors,
26 0 : CNullifiersMap& mapSaplingNullifiers) { return false; }
27 :
28 : // Sapling
29 0 : bool CCoinsView::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { return false; }
30 0 : bool CCoinsView::GetNullifier(const uint256 &nullifier) const { return false; }
31 0 : uint256 CCoinsView::GetBestAnchor() const { return uint256(); };
32 :
33 689335 : CCoinsViewBacked::CCoinsViewBacked(CCoinsView* viewIn) : base(viewIn) {}
34 1598190 : bool CCoinsViewBacked::GetCoin(const COutPoint& outpoint, Coin& coin) const { return base->GetCoin(outpoint, coin); }
35 0 : bool CCoinsViewBacked::HaveCoin(const COutPoint& outpoint) const { return base->HaveCoin(outpoint); }
36 187480 : uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
37 0 : std::vector<uint256> CCoinsViewBacked::GetHeadBlocks() const { return base->GetHeadBlocks(); }
38 574065 : void CCoinsViewBacked::SetBackend(CCoinsView& viewIn) { base = &viewIn; }
39 971 : CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }
40 98 : size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }
41 :
42 802 : bool CCoinsViewBacked::BatchWrite(CCoinsMap& mapCoins,
43 : const uint256& hashBlock,
44 : const uint256& hashSaplingAnchor,
45 : CAnchorsSaplingMap& mapSaplingAnchors,
46 : CNullifiersMap& mapSaplingNullifiers)
47 802 : { return base->BatchWrite(mapCoins, hashBlock, hashSaplingAnchor, mapSaplingAnchors, mapSaplingNullifiers); }
48 :
49 : // Sapling
50 472 : bool CCoinsViewBacked::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { return base->GetSaplingAnchorAt(rt, tree); }
51 155 : bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier) const { return base->GetNullifier(nullifier); }
52 244 : uint256 CCoinsViewBacked::GetBestAnchor() const { return base->GetBestAnchor(); }
53 :
54 405506 : SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
55 839587 : SaltedIdHasher::SaltedIdHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
56 :
57 1195165 : CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {}
58 :
59 323081 : size_t CCoinsViewCache::DynamicMemoryUsage() const {
60 323081 : return memusage::DynamicUsage(cacheCoins) +
61 323081 : memusage::DynamicUsage(cacheSaplingAnchors) +
62 323081 : memusage::DynamicUsage(cacheSaplingNullifiers) +
63 323081 : cachedCoinsUsage;
64 : }
65 :
66 65868300 : CCoinsMap::iterator CCoinsViewCache::FetchCoin(const COutPoint& outpoint) const
67 : {
68 65868300 : CCoinsMap::iterator it = cacheCoins.find(outpoint);
69 65868300 : if (it != cacheCoins.end())
70 31546016 : return it;
71 100190600 : Coin tmp;
72 34322330 : if (!base->GetCoin(outpoint, tmp))
73 34322330 : return cacheCoins.end();
74 7904839 : CCoinsMap::iterator ret = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::forward_as_tuple(std::move(tmp))).first;
75 7904839 : if (ret->second.coin.IsSpent()) {
76 : // The parent only has an empty entry for this outpoint; we can consider our
77 : // version as fresh.
78 292680 : ret->second.flags = CCoinsCacheEntry::FRESH;
79 : }
80 7904839 : cachedCoinsUsage += memusage::DynamicUsage(ret->second.coin);
81 7904839 : return ret;
82 : }
83 :
84 21506560 : bool CCoinsViewCache::GetCoin(const COutPoint& outpoint, Coin& coin) const
85 : {
86 21506560 : CCoinsMap::const_iterator it = FetchCoin(outpoint);
87 21506560 : if (it != cacheCoins.end()) {
88 7184907 : coin = it->second.coin;
89 7184907 : return true;
90 : }
91 : return false;
92 : }
93 :
94 9118240 : void CCoinsViewCache::AddCoin(const COutPoint& outpoint, Coin&& coin, bool possible_overwrite) {
95 9118240 : assert(!coin.IsSpent());
96 9119675 : if (coin.out.scriptPubKey.IsUnspendable()) return;
97 9116795 : if (coin.out.IsZerocoinMint()) return;
98 9116795 : CCoinsMap::iterator it;
99 9116795 : bool inserted;
100 9116795 : std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>());
101 9116795 : bool fresh = false;
102 9116795 : if (!inserted) {
103 47384 : cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
104 : }
105 9116795 : if (!possible_overwrite) {
106 9076150 : if (!it->second.coin.IsSpent()) {
107 12 : throw std::logic_error("Adding new coin that replaces non-pruned entry");
108 : }
109 9076138 : fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY);
110 : }
111 9116783 : it->second.coin = std::move(coin);
112 9116783 : it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0);
113 9116783 : cachedCoinsUsage += it->second.coin.DynamicMemoryUsage();
114 : }
115 :
116 4363363 : void AddCoins(CCoinsViewCache& cache, const CTransaction& tx, int nHeight, bool check, bool fSkipInvalid)
117 : {
118 4363363 : bool fCoinbase = tx.IsCoinBase();
119 4363363 : bool fCoinstake = tx.IsCoinStake();
120 4363363 : const uint256& txid = tx.GetHash();
121 12994419 : for (size_t i = 0; i < tx.vout.size(); ++i) {
122 8631006 : const COutPoint out(txid, i);
123 : // Don't add fraudulent/banned outputs
124 8631006 : if (fSkipInvalid && invalid_out::ContainsOutPoint(out)) {
125 0 : cache.SpendCoin(out); // no-op if the coin is not in the cache
126 0 : continue;
127 : }
128 8631006 : bool overwrite = check && cache.HaveCoin(out);
129 17262052 : cache.AddCoin(out, Coin(tx.vout[i], nHeight, fCoinbase, fCoinstake), overwrite);
130 : }
131 4363363 : }
132 :
133 6644946 : void CCoinsViewCache::SpendCoin(const COutPoint& outpoint, Coin* moveout)
134 : {
135 6644946 : CCoinsMap::iterator it = FetchCoin(outpoint);
136 6644946 : if (it == cacheCoins.end()) return;
137 6643885 : cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
138 6643885 : if (moveout) {
139 6597259 : *moveout = std::move(it->second.coin);
140 : }
141 6643885 : if (it->second.flags & CCoinsCacheEntry::FRESH) {
142 360870 : cacheCoins.erase(it);
143 : } else {
144 6283019 : it->second.flags |= CCoinsCacheEntry::DIRTY;
145 12926904 : it->second.coin.Clear();
146 : }
147 : }
148 :
149 : static const Coin coinEmpty;
150 :
151 22748700 : const Coin& CCoinsViewCache::AccessCoin(const COutPoint& outpoint) const
152 : {
153 22748700 : CCoinsMap::const_iterator it = FetchCoin(outpoint);
154 22748700 : if (it == cacheCoins.end()) {
155 : return coinEmpty;
156 : } else {
157 12299377 : return it->second.coin;
158 : }
159 : }
160 :
161 14968090 : bool CCoinsViewCache::HaveCoin(const COutPoint& outpoint) const
162 : {
163 14968090 : CCoinsMap::const_iterator it = FetchCoin(outpoint);
164 14968090 : return (it != cacheCoins.end() && !it->second.coin.IsSpent());
165 : }
166 :
167 1077093 : bool CCoinsViewCache::HaveCoinInCache(const COutPoint& outpoint) const
168 : {
169 1077093 : CCoinsMap::const_iterator it = cacheCoins.find(outpoint);
170 1077093 : return it != cacheCoins.end();
171 : }
172 :
173 5185397 : uint256 CCoinsViewCache::GetBestBlock() const
174 : {
175 10370774 : if (hashBlock.IsNull())
176 255260 : hashBlock = base->GetBestBlock();
177 5185397 : return hashBlock;
178 : }
179 :
180 43331 : void CCoinsViewCache::SetBestBlock(const uint256& hashBlockIn)
181 : {
182 43331 : hashBlock = hashBlockIn;
183 43331 : }
184 :
185 : template<typename Map, typename MapIterator, typename MapEntry>
186 42838 : void BatchWriteAnchors(
187 : Map &mapAnchors,
188 : Map &cacheAnchors,
189 : size_t &cachedCoinsUsage
190 : )
191 : {
192 84589 : for (MapIterator child_it = mapAnchors.begin(); child_it != mapAnchors.end();)
193 : {
194 41751 : if (child_it->second.flags & MapEntry::DIRTY) {
195 238 : MapIterator parent_it = cacheAnchors.find(child_it->first);
196 :
197 238 : if (parent_it == cacheAnchors.end()) {
198 228 : MapEntry& entry = cacheAnchors[child_it->first];
199 228 : entry.entered = child_it->second.entered;
200 228 : entry.tree = child_it->second.tree;
201 228 : entry.flags = MapEntry::DIRTY;
202 :
203 228 : cachedCoinsUsage += entry.tree.DynamicMemoryUsage();
204 : } else {
205 10 : if (parent_it->second.entered != child_it->second.entered) {
206 : // The parent may have removed the entry.
207 10 : parent_it->second.entered = child_it->second.entered;
208 10 : parent_it->second.flags |= MapEntry::DIRTY;
209 : }
210 : }
211 : }
212 :
213 41751 : MapIterator itOld = child_it++;
214 41751 : mapAnchors.erase(itOld);
215 : }
216 42838 : }
217 :
218 42838 : void BatchWriteNullifiers(CNullifiersMap &mapNullifiers, CNullifiersMap &cacheNullifiers)
219 : {
220 42994 : for (CNullifiersMap::iterator child_it = mapNullifiers.begin(); child_it != mapNullifiers.end();) {
221 156 : if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
222 155 : CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first);
223 :
224 155 : if (parent_it == cacheNullifiers.end()) {
225 1 : CNullifiersCacheEntry& entry = cacheNullifiers[child_it->first];
226 1 : entry.entered = child_it->second.entered;
227 1 : entry.flags = CNullifiersCacheEntry::DIRTY;
228 : } else {
229 154 : if (parent_it->second.entered != child_it->second.entered) {
230 154 : parent_it->second.entered = child_it->second.entered;
231 154 : parent_it->second.flags |= CNullifiersCacheEntry::DIRTY;
232 : }
233 : }
234 : }
235 156 : CNullifiersMap::iterator itOld = child_it++;
236 156 : mapNullifiers.erase(itOld);
237 : }
238 42838 : }
239 :
240 42846 : bool CCoinsViewCache::BatchWrite(CCoinsMap& mapCoins,
241 : const uint256& hashBlockIn,
242 : const uint256 &hashSaplingAnchorIn,
243 : CAnchorsSaplingMap& mapSaplingAnchors,
244 : CNullifiersMap& mapSaplingNullifiers)
245 : {
246 2535444 : for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = mapCoins.erase(it)) {
247 : // Ignore non-dirty entries (optimization).
248 2492604 : if (!(it->second.flags & CCoinsCacheEntry::DIRTY)) {
249 337971 : continue;
250 : }
251 2154639 : CCoinsMap::iterator itUs = cacheCoins.find(it->first);
252 2154639 : if (itUs == cacheCoins.end()) {
253 : // The parent cache does not have an entry, while the child does
254 : // We can ignore it if it's both FRESH and pruned in the child
255 1000392 : if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) {
256 : // Otherwise we will need to create it in the parent
257 : // and move the data up and mark it as dirty
258 1000391 : CCoinsCacheEntry& entry = cacheCoins[it->first];
259 1000391 : entry.coin = std::move(it->second.coin);
260 1000391 : cachedCoinsUsage += memusage::DynamicUsage(entry.coin);
261 1000391 : entry.flags = CCoinsCacheEntry::DIRTY;
262 : // We can mark it FRESH in the parent if it was FRESH in the child
263 : // Otherwise it might have just been flushed from the parent's cache
264 : // and already exist in the grandparent
265 1000391 : if (it->second.flags & CCoinsCacheEntry::FRESH) {
266 973750 : entry.flags |= CCoinsCacheEntry::FRESH;
267 : }
268 : }
269 : } else {
270 : // Assert that the child cache entry was not marked FRESH if the
271 : // parent cache entry has unspent outputs. If this ever happens,
272 : // it means the FRESH flag was misapplied and there is a logic
273 : // error in the calling code.
274 1154243 : if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent()) {
275 8 : throw std::logic_error("FRESH flag misapplied to cache entry for base transaction with spendable outputs");
276 : }
277 :
278 : // Found the entry in the parent cache
279 1154235 : if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) {
280 : // The grandparent does not have an entry, and the child is
281 : // modified and being pruned. This means we can just delete
282 : // it from the parent.
283 451575 : cachedCoinsUsage -= memusage::DynamicUsage(itUs->second.coin);
284 451575 : cacheCoins.erase(itUs);
285 : } else {
286 : // A normal modification.
287 702662 : cachedCoinsUsage -= memusage::DynamicUsage(itUs->second.coin);
288 702662 : itUs->second.coin = std::move(it->second.coin);
289 702662 : cachedCoinsUsage += memusage::DynamicUsage(itUs->second.coin);
290 702662 : itUs->second.flags |= CCoinsCacheEntry::DIRTY;
291 : // NOTE: It is possible the child has a FRESH flag here in
292 : // the event the entry we found in the parent is pruned. But
293 : // we must not copy that FRESH flag to the parent as that
294 : // pruned state likely still needs to be communicated to the
295 : // grandparent.
296 : }
297 : }
298 : }
299 :
300 : // Sapling
301 42838 : ::BatchWriteAnchors<CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(mapSaplingAnchors, cacheSaplingAnchors, cachedCoinsUsage);
302 42838 : ::BatchWriteNullifiers(mapSaplingNullifiers, cacheSaplingNullifiers);
303 42838 : hashSaplingAnchor = hashSaplingAnchorIn;
304 :
305 42838 : hashBlock = hashBlockIn;
306 42838 : return true;
307 : }
308 :
309 43553 : bool CCoinsViewCache::Flush()
310 : {
311 87106 : bool fOk = base->BatchWrite(cacheCoins,
312 43553 : hashBlock,
313 43553 : hashSaplingAnchor,
314 43553 : cacheSaplingAnchors,
315 43553 : cacheSaplingNullifiers);
316 43553 : cacheCoins.clear();
317 43553 : cacheSaplingAnchors.clear();
318 43553 : cacheSaplingNullifiers.clear();
319 43553 : cachedCoinsUsage = 0;
320 43553 : return fOk;
321 : }
322 :
323 17014 : void CCoinsViewCache::Uncache(const COutPoint& outpoint)
324 : {
325 17014 : CCoinsMap::iterator it = cacheCoins.find(outpoint);
326 17014 : if (it != cacheCoins.end() && it->second.flags == 0) {
327 1269 : cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
328 1269 : cacheCoins.erase(it);
329 : }
330 17014 : }
331 :
332 43276 : unsigned int CCoinsViewCache::GetCacheSize() const
333 : {
334 43276 : return cacheCoins.size();
335 : }
336 :
337 669597 : CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
338 : {
339 669597 : if (tx.IsCoinBase())
340 : return 0;
341 :
342 669597 : CAmount nResult = 0;
343 1931492 : for (const CTxIn& in : tx.vin) {
344 1261894 : if (in.IsZerocoinSpend() || in.IsZerocoinPublicSpend()) {
345 0 : nResult += in.nSequence * COIN;
346 : } else {
347 1261894 : nResult += AccessCoin(in.prevout).out.nValue;
348 : }
349 : }
350 :
351 : // Sapling
352 669597 : nResult += tx.GetShieldedValueIn();
353 :
354 669597 : return nResult;
355 : }
356 :
357 5186599 : bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
358 : {
359 5186599 : if (!tx.IsCoinBase() && !tx.HasZerocoinSpendInputs()) {
360 12811941 : for (unsigned int i = 0; i < tx.vin.size(); i++) {
361 7644146 : if (!HaveCoin(tx.vin[i].prevout)) {
362 : return false;
363 : }
364 : }
365 : }
366 : return true;
367 : }
368 :
369 245 : int CCoinsViewCache::GetCoinDepthAtHeight(const COutPoint& output, int nHeight) const
370 : {
371 245 : const Coin& coin = AccessCoin(output);
372 245 : if (!coin.IsSpent())
373 245 : return nHeight - coin.nHeight + 1;
374 : return -1;
375 : }
376 :
377 438 : CAmount CCoinsViewCache::GetTotalAmount() const
378 : {
379 438 : CAmount nTotal = 0;
380 :
381 438 : std::unique_ptr<CCoinsViewCursor> pcursor(Cursor());
382 2270397 : while (pcursor->Valid()) {
383 4539928 : Coin coin;
384 2269964 : if (pcursor->GetValue(coin) && !coin.IsSpent()) {
385 2269964 : nTotal += coin.out.nValue;
386 : }
387 2269964 : pcursor->Next();
388 : }
389 :
390 876 : return nTotal;
391 : }
392 :
393 0 : bool CCoinsViewCache::PruneInvalidEntries()
394 : {
395 : // Prune zerocoin Mints and fraudulent/frozen outputs
396 0 : bool loaded = invalid_out::LoadOutpoints();
397 0 : assert(loaded);
398 0 : for (const COutPoint& out: invalid_out::setInvalidOutPoints) {
399 0 : if (HaveCoin(out)) {
400 0 : LogPrintf("Pruning invalid output %s\n", out.ToString());
401 0 : SpendCoin(out);
402 : }
403 : }
404 0 : return Flush();
405 : }
406 :
407 : static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_SIZE_CURRENT / ::GetSerializeSize(CTxOut(), PROTOCOL_VERSION); // TODO: merge with similar definition in undo.h.
408 :
409 84 : const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid)
410 : {
411 84 : COutPoint iter(txid, 0);
412 9555630 : while (iter.n < MAX_OUTPUTS_PER_BLOCK) {
413 9555590 : const Coin& alternate = view.AccessCoin(iter);
414 9555590 : if (!alternate.IsSpent()) return alternate;
415 9555550 : ++iter.n;
416 : }
417 : return coinEmpty;
418 : }
419 :
420 : // Sapling
421 :
422 162069 : bool CCoinsViewCache::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const {
423 :
424 162069 : CAnchorsSaplingMap::const_iterator it = cacheSaplingAnchors.find(rt);
425 162069 : if (it != cacheSaplingAnchors.end()) {
426 104782 : if (it->second.entered) {
427 104778 : tree = it->second.tree;
428 104778 : return true;
429 : } else {
430 : return false;
431 : }
432 : }
433 :
434 57287 : if (!base->GetSaplingAnchorAt(rt, tree)) {
435 : return false;
436 : }
437 :
438 114572 : CAnchorsSaplingMap::iterator ret = cacheSaplingAnchors.insert(std::make_pair(rt, CAnchorsSaplingCacheEntry())).first;
439 57286 : ret->second.entered = true;
440 57286 : ret->second.tree = tree;
441 57286 : cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
442 :
443 57286 : return true;
444 : }
445 :
446 1564 : bool CCoinsViewCache::GetNullifier(const uint256 &nullifier) const {
447 1564 : CNullifiersMap* cacheToUse = &cacheSaplingNullifiers;
448 1564 : CNullifiersMap::iterator it = cacheToUse->find(nullifier);
449 1564 : if (it != cacheToUse->end())
450 932 : return it->second.entered;
451 :
452 632 : CNullifiersCacheEntry entry;
453 632 : bool tmp = base->GetNullifier(nullifier);
454 632 : entry.entered = tmp;
455 :
456 632 : cacheToUse->insert(std::make_pair(nullifier, entry));
457 632 : return tmp;
458 : }
459 :
460 : template<typename Tree, typename Cache, typename CacheIterator, typename CacheEntry>
461 56630 : void CCoinsViewCache::AbstractPushAnchor(
462 : const Tree &tree,
463 : Cache &cacheAnchors,
464 : uint256 &hash
465 : )
466 : {
467 56630 : uint256 newrt = tree.root();
468 :
469 56630 : auto currentRoot = GetBestAnchor();
470 :
471 : // We don't want to overwrite an anchor we already have.
472 : // This occurs when a block doesn't modify mapAnchors at all,
473 : // because there are no joinsplits. We could get around this a
474 : // different way (make all blocks modify mapAnchors somehow)
475 : // but this is simpler to reason about.
476 56630 : if (currentRoot != newrt) {
477 642 : auto insertRet = cacheAnchors.insert(std::make_pair(newrt, CacheEntry()));
478 321 : CacheIterator ret = insertRet.first;
479 :
480 321 : ret->second.entered = true;
481 321 : ret->second.tree = tree;
482 321 : ret->second.flags = CacheEntry::DIRTY;
483 :
484 321 : if (insertRet.second) {
485 : // An insert took place
486 321 : cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
487 : }
488 :
489 321 : hash = newrt;
490 : }
491 56630 : }
492 :
493 56630 : template<> void CCoinsViewCache::PushAnchor(const SaplingMerkleTree &tree)
494 : {
495 56630 : AbstractPushAnchor<SaplingMerkleTree, CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(
496 : tree,
497 56630 : cacheSaplingAnchors,
498 56630 : hashSaplingAnchor
499 : );
500 56630 : }
501 :
502 : template<>
503 48 : void CCoinsViewCache::BringBestAnchorIntoCache(
504 : const uint256 ¤tRoot,
505 : SaplingMerkleTree &tree
506 : )
507 : {
508 48 : assert(GetSaplingAnchorAt(currentRoot, tree));
509 48 : }
510 :
511 : template<typename Tree, typename Cache, typename CacheEntry>
512 1504 : void CCoinsViewCache::AbstractPopAnchor(
513 : const uint256 &newrt,
514 : Cache &cacheAnchors,
515 : uint256 &hash
516 : )
517 : {
518 1504 : auto currentRoot = GetBestAnchor();
519 :
520 : // Blocks might not change the commitment tree, in which
521 : // case restoring the "old" anchor during a reorg must
522 : // have no effect.
523 1504 : if (currentRoot != newrt) {
524 : // Bring the current best anchor into our local cache
525 : // so that its tree exists in memory.
526 : {
527 48 : Tree tree;
528 48 : BringBestAnchorIntoCache(currentRoot, tree);
529 : }
530 :
531 : // Mark the anchor as unentered, removing it from view
532 48 : cacheAnchors[currentRoot].entered = false;
533 :
534 : // Mark the cache entry as dirty so it's propagated
535 48 : cacheAnchors[currentRoot].flags = CacheEntry::DIRTY;
536 :
537 : // Mark the new root as the best anchor
538 48 : hash = newrt;
539 : }
540 1504 : }
541 :
542 1504 : void CCoinsViewCache::PopAnchor(const uint256 &newrt) {
543 1504 : AbstractPopAnchor<SaplingMerkleTree, CAnchorsSaplingMap, CAnchorsSaplingCacheEntry>(
544 : newrt,
545 1504 : cacheSaplingAnchors,
546 1504 : hashSaplingAnchor
547 : );
548 1504 : }
549 :
550 4579508 : void CCoinsViewCache::SetNullifiers(const CTransaction& tx, bool spent) {
551 4579508 : if (tx.sapData) {
552 4579850 : for (const SpendDescription& spendDescription : tx.sapData->vShieldedSpend) {
553 340 : std::pair<CNullifiersMap::iterator, bool> ret = cacheSaplingNullifiers.insert(
554 340 : std::make_pair(spendDescription.nullifier, CNullifiersCacheEntry()));
555 340 : ret.first->second.entered = spent;
556 340 : ret.first->second.flags |= CNullifiersCacheEntry::DIRTY;
557 : }
558 : }
559 4579508 : }
560 :
561 177603 : uint256 CCoinsViewCache::GetBestAnchor() const {
562 355206 : if (hashSaplingAnchor.IsNull())
563 57418 : hashSaplingAnchor = base->GetBestAnchor();
564 177603 : return hashSaplingAnchor;
565 : }
566 :
567 5297245 : bool CCoinsViewCache::HaveShieldedRequirements(const CTransaction& tx) const
568 : {
569 5817306 : if (tx.IsShieldedTx()) {
570 513275 : for (const SpendDescription &spendDescription : tx.sapData->vShieldedSpend) {
571 957 : if (GetNullifier(spendDescription.nullifier)) // Prevent double spends
572 2 : return false;
573 :
574 1910 : SaplingMerkleTree tree;
575 955 : if (!GetSaplingAnchorAt(spendDescription.anchor, tree)) {
576 2 : return false;
577 : }
578 : }
579 : }
580 :
581 : return true;
582 : }
583 :
584 1831 : bool CCoinsViewCache::GetUTXOCoin(const COutPoint& outpoint, Coin& coin) const
585 : {
586 1831 : return GetCoin(outpoint, coin) && !coin.IsSpent();
587 : }
|