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 135220 : CCoinsViewBacked::CCoinsViewBacked(CCoinsView* viewIn) : base(viewIn) {}
34 195014 : 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 20555 : uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
37 0 : std::vector<uint256> CCoinsViewBacked::GetHeadBlocks() const { return base->GetHeadBlocks(); }
38 53563 : void CCoinsViewBacked::SetBackend(CCoinsView& viewIn) { base = &viewIn; }
39 657 : CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }
40 6 : size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }
41 :
42 629 : bool CCoinsViewBacked::BatchWrite(CCoinsMap& mapCoins,
43 : const uint256& hashBlock,
44 : const uint256& hashSaplingAnchor,
45 : CAnchorsSaplingMap& mapSaplingAnchors,
46 : CNullifiersMap& mapSaplingNullifiers)
47 629 : { return base->BatchWrite(mapCoins, hashBlock, hashSaplingAnchor, mapSaplingAnchors, mapSaplingNullifiers); }
48 :
49 : // Sapling
50 367 : bool CCoinsViewBacked::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { return base->GetSaplingAnchorAt(rt, tree); }
51 147 : bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier) const { return base->GetNullifier(nullifier); }
52 186 : uint256 CCoinsViewBacked::GetBestAnchor() const { return base->GetBestAnchor(); }
53 :
54 104743 : SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
55 229095 : SaltedIdHasher::SaltedIdHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
56 :
57 304974 : CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {}
58 :
59 110908 : size_t CCoinsViewCache::DynamicMemoryUsage() const {
60 110908 : return memusage::DynamicUsage(cacheCoins) +
61 110908 : memusage::DynamicUsage(cacheSaplingAnchors) +
62 110908 : memusage::DynamicUsage(cacheSaplingNullifiers) +
63 110908 : cachedCoinsUsage;
64 : }
65 :
66 51738800 : CCoinsMap::iterator CCoinsViewCache::FetchCoin(const COutPoint& outpoint) const
67 : {
68 51738800 : CCoinsMap::iterator it = cacheCoins.find(outpoint);
69 51738800 : if (it != cacheCoins.end())
70 23364439 : return it;
71 80113200 : Coin tmp;
72 28374410 : if (!base->GetCoin(outpoint, tmp))
73 28374410 : return cacheCoins.end();
74 6093644 : CCoinsMap::iterator ret = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::forward_as_tuple(std::move(tmp))).first;
75 6093644 : 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 262647 : ret->second.flags = CCoinsCacheEntry::FRESH;
79 : }
80 6093644 : cachedCoinsUsage += memusage::DynamicUsage(ret->second.coin);
81 6093644 : return ret;
82 : }
83 :
84 17760510 : bool CCoinsViewCache::GetCoin(const COutPoint& outpoint, Coin& coin) const
85 : {
86 17760510 : CCoinsMap::const_iterator it = FetchCoin(outpoint);
87 17760510 : if (it != cacheCoins.end()) {
88 5854007 : coin = it->second.coin;
89 5854007 : return true;
90 : }
91 : return false;
92 : }
93 :
94 7777087 : void CCoinsViewCache::AddCoin(const COutPoint& outpoint, Coin&& coin, bool possible_overwrite) {
95 7777087 : assert(!coin.IsSpent());
96 7778387 : if (coin.out.scriptPubKey.IsUnspendable()) return;
97 7775787 : if (coin.out.IsZerocoinMint()) return;
98 7775787 : CCoinsMap::iterator it;
99 7775787 : bool inserted;
100 7775787 : std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>());
101 7775787 : bool fresh = false;
102 7775787 : if (!inserted) {
103 23763 : cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
104 : }
105 7775787 : if (!possible_overwrite) {
106 7743932 : if (!it->second.coin.IsSpent()) {
107 12 : throw std::logic_error("Adding new coin that replaces non-pruned entry");
108 : }
109 7743920 : fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY);
110 : }
111 7775775 : it->second.coin = std::move(coin);
112 7775775 : it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0);
113 7775775 : cachedCoinsUsage += it->second.coin.DynamicMemoryUsage();
114 : }
115 :
116 4063139 : void AddCoins(CCoinsViewCache& cache, const CTransaction& tx, int nHeight, bool check, bool fSkipInvalid)
117 : {
118 4063139 : bool fCoinbase = tx.IsCoinBase();
119 4063139 : bool fCoinstake = tx.IsCoinStake();
120 4063139 : const uint256& txid = tx.GetHash();
121 11707708 : for (size_t i = 0; i < tx.vout.size(); ++i) {
122 7644549 : const COutPoint out(txid, i);
123 : // Don't add fraudulent/banned outputs
124 7644549 : 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 7644549 : bool overwrite = check && cache.HaveCoin(out);
129 15289138 : cache.AddCoin(out, Coin(tx.vout[i], nHeight, fCoinbase, fCoinstake), overwrite);
130 : }
131 4063139 : }
132 :
133 5614045 : void CCoinsViewCache::SpendCoin(const COutPoint& outpoint, Coin* moveout)
134 : {
135 5614045 : CCoinsMap::iterator it = FetchCoin(outpoint);
136 5614045 : if (it == cacheCoins.end()) return;
137 5605574 : cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
138 5605574 : if (moveout) {
139 5578221 : *moveout = std::move(it->second.coin);
140 : }
141 5605574 : if (it->second.flags & CCoinsCacheEntry::FRESH) {
142 104128 : cacheCoins.erase(it);
143 : } else {
144 5501446 : it->second.flags |= CCoinsCacheEntry::DIRTY;
145 11107060 : it->second.coin.Clear();
146 : }
147 : }
148 :
149 : static const Coin coinEmpty;
150 :
151 16369210 : const Coin& CCoinsViewCache::AccessCoin(const COutPoint& outpoint) const
152 : {
153 16369210 : CCoinsMap::const_iterator it = FetchCoin(outpoint);
154 16369210 : if (it == cacheCoins.end()) {
155 : return coinEmpty;
156 : } else {
157 6731202 : return it->second.coin;
158 : }
159 : }
160 :
161 11995048 : bool CCoinsViewCache::HaveCoin(const COutPoint& outpoint) const
162 : {
163 11995048 : CCoinsMap::const_iterator it = FetchCoin(outpoint);
164 11995048 : return (it != cacheCoins.end() && !it->second.coin.IsSpent());
165 : }
166 :
167 280862 : bool CCoinsViewCache::HaveCoinInCache(const COutPoint& outpoint) const
168 : {
169 280862 : CCoinsMap::const_iterator it = cacheCoins.find(outpoint);
170 280862 : return it != cacheCoins.end();
171 : }
172 :
173 4183127 : uint256 CCoinsViewCache::GetBestBlock() const
174 : {
175 8366264 : if (hashBlock.IsNull())
176 65983 : hashBlock = base->GetBestBlock();
177 4183127 : return hashBlock;
178 : }
179 :
180 26240 : void CCoinsViewCache::SetBestBlock(const uint256& hashBlockIn)
181 : {
182 26240 : hashBlock = hashBlockIn;
183 26240 : }
184 :
185 : template<typename Map, typename MapIterator, typename MapEntry>
186 25738 : void BatchWriteAnchors(
187 : Map &mapAnchors,
188 : Map &cacheAnchors,
189 : size_t &cachedCoinsUsage
190 : )
191 : {
192 50557 : for (MapIterator child_it = mapAnchors.begin(); child_it != mapAnchors.end();)
193 : {
194 24819 : if (child_it->second.flags & MapEntry::DIRTY) {
195 230 : MapIterator parent_it = cacheAnchors.find(child_it->first);
196 :
197 230 : if (parent_it == cacheAnchors.end()) {
198 220 : MapEntry& entry = cacheAnchors[child_it->first];
199 220 : entry.entered = child_it->second.entered;
200 220 : entry.tree = child_it->second.tree;
201 220 : entry.flags = MapEntry::DIRTY;
202 :
203 220 : 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 24819 : MapIterator itOld = child_it++;
214 24819 : mapAnchors.erase(itOld);
215 : }
216 25738 : }
217 :
218 25738 : void BatchWriteNullifiers(CNullifiersMap &mapNullifiers, CNullifiersMap &cacheNullifiers)
219 : {
220 25886 : for (CNullifiersMap::iterator child_it = mapNullifiers.begin(); child_it != mapNullifiers.end();) {
221 148 : if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
222 147 : CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first);
223 :
224 147 : 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 146 : if (parent_it->second.entered != child_it->second.entered) {
230 146 : parent_it->second.entered = child_it->second.entered;
231 146 : parent_it->second.flags |= CNullifiersCacheEntry::DIRTY;
232 : }
233 : }
234 : }
235 148 : CNullifiersMap::iterator itOld = child_it++;
236 148 : mapNullifiers.erase(itOld);
237 : }
238 25738 : }
239 :
240 25746 : bool CCoinsViewCache::BatchWrite(CCoinsMap& mapCoins,
241 : const uint256& hashBlockIn,
242 : const uint256 &hashSaplingAnchorIn,
243 : CAnchorsSaplingMap& mapSaplingAnchors,
244 : CNullifiersMap& mapSaplingNullifiers)
245 : {
246 1034114 : for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = mapCoins.erase(it)) {
247 : // Ignore non-dirty entries (optimization).
248 1008376 : if (!(it->second.flags & CCoinsCacheEntry::DIRTY)) {
249 299905 : continue;
250 : }
251 708471 : CCoinsMap::iterator itUs = cacheCoins.find(it->first);
252 708471 : 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 409764 : 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 409763 : CCoinsCacheEntry& entry = cacheCoins[it->first];
259 409763 : entry.coin = std::move(it->second.coin);
260 409763 : cachedCoinsUsage += memusage::DynamicUsage(entry.coin);
261 409763 : 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 409763 : if (it->second.flags & CCoinsCacheEntry::FRESH) {
266 382627 : 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 298707 : 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 298699 : 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 250338 : cachedCoinsUsage -= memusage::DynamicUsage(itUs->second.coin);
284 250338 : cacheCoins.erase(itUs);
285 : } else {
286 : // A normal modification.
287 48361 : cachedCoinsUsage -= memusage::DynamicUsage(itUs->second.coin);
288 48361 : itUs->second.coin = std::move(it->second.coin);
289 48361 : cachedCoinsUsage += memusage::DynamicUsage(itUs->second.coin);
290 48361 : 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 25738 : ::BatchWriteAnchors<CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(mapSaplingAnchors, cacheSaplingAnchors, cachedCoinsUsage);
302 25738 : ::BatchWriteNullifiers(mapSaplingNullifiers, cacheSaplingNullifiers);
303 25738 : hashSaplingAnchor = hashSaplingAnchorIn;
304 :
305 25738 : hashBlock = hashBlockIn;
306 25738 : return true;
307 : }
308 :
309 26316 : bool CCoinsViewCache::Flush()
310 : {
311 52632 : bool fOk = base->BatchWrite(cacheCoins,
312 26316 : hashBlock,
313 26316 : hashSaplingAnchor,
314 26316 : cacheSaplingAnchors,
315 26316 : cacheSaplingNullifiers);
316 26316 : cacheCoins.clear();
317 26316 : cacheSaplingAnchors.clear();
318 26316 : cacheSaplingNullifiers.clear();
319 26316 : cachedCoinsUsage = 0;
320 26316 : return fOk;
321 : }
322 :
323 20785 : void CCoinsViewCache::Uncache(const COutPoint& outpoint)
324 : {
325 20785 : CCoinsMap::iterator it = cacheCoins.find(outpoint);
326 20785 : if (it != cacheCoins.end() && it->second.flags == 0) {
327 761 : cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
328 761 : cacheCoins.erase(it);
329 : }
330 20785 : }
331 :
332 26016 : unsigned int CCoinsViewCache::GetCacheSize() const
333 : {
334 26016 : return cacheCoins.size();
335 : }
336 :
337 156001 : CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
338 : {
339 156001 : if (tx.IsCoinBase())
340 : return 0;
341 :
342 156001 : CAmount nResult = 0;
343 409006 : for (const CTxIn& in : tx.vin) {
344 253005 : if (in.IsZerocoinSpend() || in.IsZerocoinPublicSpend()) {
345 0 : nResult += in.nSequence * COIN;
346 : } else {
347 253005 : nResult += AccessCoin(in.prevout).out.nValue;
348 : }
349 : }
350 :
351 : // Sapling
352 156001 : nResult += tx.GetShieldedValueIn();
353 :
354 156001 : return nResult;
355 : }
356 :
357 4161657 : bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
358 : {
359 4161657 : if (!tx.IsCoinBase() && !tx.HasZerocoinSpendInputs()) {
360 9846467 : for (unsigned int i = 0; i < tx.vin.size(); i++) {
361 5684814 : if (!HaveCoin(tx.vin[i].prevout)) {
362 : return false;
363 : }
364 : }
365 : }
366 : return true;
367 : }
368 :
369 7 : int CCoinsViewCache::GetCoinDepthAtHeight(const COutPoint& output, int nHeight) const
370 : {
371 7 : const Coin& coin = AccessCoin(output);
372 7 : if (!coin.IsSpent())
373 7 : return nHeight - coin.nHeight + 1;
374 : return -1;
375 : }
376 :
377 327 : CAmount CCoinsViewCache::GetTotalAmount() const
378 : {
379 327 : CAmount nTotal = 0;
380 :
381 327 : std::unique_ptr<CCoinsViewCursor> pcursor(Cursor());
382 158209 : while (pcursor->Valid()) {
383 315764 : Coin coin;
384 157882 : if (pcursor->GetValue(coin) && !coin.IsSpent()) {
385 157882 : nTotal += coin.out.nValue;
386 : }
387 157882 : pcursor->Next();
388 : }
389 :
390 654 : 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 86 : const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid)
410 : {
411 86 : COutPoint iter(txid, 0);
412 9111190 : while (iter.n < MAX_OUTPUTS_PER_BLOCK) {
413 9111150 : const Coin& alternate = view.AccessCoin(iter);
414 9111150 : if (!alternate.IsSpent()) return alternate;
415 9111100 : ++iter.n;
416 : }
417 : return coinEmpty;
418 : }
419 :
420 : // Sapling
421 :
422 98979 : bool CCoinsViewCache::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const {
423 :
424 98979 : CAnchorsSaplingMap::const_iterator it = cacheSaplingAnchors.find(rt);
425 98979 : if (it != cacheSaplingAnchors.end()) {
426 63745 : if (it->second.entered) {
427 63741 : tree = it->second.tree;
428 63741 : return true;
429 : } else {
430 : return false;
431 : }
432 : }
433 :
434 35234 : if (!base->GetSaplingAnchorAt(rt, tree)) {
435 : return false;
436 : }
437 :
438 70466 : CAnchorsSaplingMap::iterator ret = cacheSaplingAnchors.insert(std::make_pair(rt, CAnchorsSaplingCacheEntry())).first;
439 35233 : ret->second.entered = true;
440 35233 : ret->second.tree = tree;
441 35233 : cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
442 :
443 35233 : return true;
444 : }
445 :
446 1512 : bool CCoinsViewCache::GetNullifier(const uint256 &nullifier) const {
447 1512 : CNullifiersMap* cacheToUse = &cacheSaplingNullifiers;
448 1512 : CNullifiersMap::iterator it = cacheToUse->find(nullifier);
449 1512 : if (it != cacheToUse->end())
450 904 : return it->second.entered;
451 :
452 608 : CNullifiersCacheEntry entry;
453 608 : bool tmp = base->GetNullifier(nullifier);
454 608 : entry.entered = tmp;
455 :
456 608 : cacheToUse->insert(std::make_pair(nullifier, entry));
457 608 : return tmp;
458 : }
459 :
460 : template<typename Tree, typename Cache, typename CacheIterator, typename CacheEntry>
461 34682 : void CCoinsViewCache::AbstractPushAnchor(
462 : const Tree &tree,
463 : Cache &cacheAnchors,
464 : uint256 &hash
465 : )
466 : {
467 34682 : uint256 newrt = tree.root();
468 :
469 34682 : 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 34682 : if (currentRoot != newrt) {
477 618 : auto insertRet = cacheAnchors.insert(std::make_pair(newrt, CacheEntry()));
478 309 : CacheIterator ret = insertRet.first;
479 :
480 309 : ret->second.entered = true;
481 309 : ret->second.tree = tree;
482 309 : ret->second.flags = CacheEntry::DIRTY;
483 :
484 309 : if (insertRet.second) {
485 : // An insert took place
486 309 : cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
487 : }
488 :
489 309 : hash = newrt;
490 : }
491 34682 : }
492 :
493 34682 : template<> void CCoinsViewCache::PushAnchor(const SaplingMerkleTree &tree)
494 : {
495 34682 : AbstractPushAnchor<SaplingMerkleTree, CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(
496 : tree,
497 34682 : cacheSaplingAnchors,
498 34682 : hashSaplingAnchor
499 : );
500 34682 : }
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 1393 : void CCoinsViewCache::AbstractPopAnchor(
513 : const uint256 &newrt,
514 : Cache &cacheAnchors,
515 : uint256 &hash
516 : )
517 : {
518 1393 : 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 1393 : 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 1393 : }
541 :
542 1393 : void CCoinsViewCache::PopAnchor(const uint256 &newrt) {
543 1393 : AbstractPopAnchor<SaplingMerkleTree, CAnchorsSaplingMap, CAnchorsSaplingCacheEntry>(
544 : newrt,
545 1393 : cacheSaplingAnchors,
546 1393 : hashSaplingAnchor
547 : );
548 1393 : }
549 :
550 4109924 : void CCoinsViewCache::SetNullifiers(const CTransaction& tx, bool spent) {
551 4109924 : if (tx.sapData) {
552 4110246 : for (const SpendDescription& spendDescription : tx.sapData->vShieldedSpend) {
553 328 : std::pair<CNullifiersMap::iterator, bool> ret = cacheSaplingNullifiers.insert(
554 328 : std::make_pair(spendDescription.nullifier, CNullifiersCacheEntry()));
555 328 : ret.first->second.entered = spent;
556 328 : ret.first->second.flags |= CNullifiersCacheEntry::DIRTY;
557 : }
558 : }
559 4109924 : }
560 :
561 109583 : uint256 CCoinsViewCache::GetBestAnchor() const {
562 219166 : if (hashSaplingAnchor.IsNull())
563 35314 : hashSaplingAnchor = base->GetBestAnchor();
564 109583 : return hashSaplingAnchor;
565 : }
566 :
567 4181593 : bool CCoinsViewCache::HaveShieldedRequirements(const CTransaction& tx) const
568 : {
569 4659164 : if (tx.IsShieldedTx()) {
570 477044 : for (const SpendDescription &spendDescription : tx.sapData->vShieldedSpend) {
571 921 : if (GetNullifier(spendDescription.nullifier)) // Prevent double spends
572 2 : return false;
573 :
574 1838 : SaplingMerkleTree tree;
575 919 : if (!GetSaplingAnchorAt(spendDescription.anchor, tree)) {
576 2 : return false;
577 : }
578 : }
579 : }
580 :
581 : return true;
582 : }
583 :
584 365 : bool CCoinsViewCache::GetUTXOCoin(const COutPoint& outpoint, Coin& coin) const
585 : {
586 365 : return GetCoin(outpoint, coin) && !coin.IsSpent();
587 : }
|