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 669111 : CCoinsViewBacked::CCoinsViewBacked(CCoinsView* viewIn) : base(viewIn) {}
34 1307110 : 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 171907 : uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
37 0 : std::vector<uint256> CCoinsViewBacked::GetHeadBlocks() const { return base->GetHeadBlocks(); }
38 554757 : void CCoinsViewBacked::SetBackend(CCoinsView& viewIn) { base = &viewIn; }
39 975 : CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }
40 98 : size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }
41 :
42 804 : bool CCoinsViewBacked::BatchWrite(CCoinsMap& mapCoins,
43 : const uint256& hashBlock,
44 : const uint256& hashSaplingAnchor,
45 : CAnchorsSaplingMap& mapSaplingAnchors,
46 : CNullifiersMap& mapSaplingNullifiers)
47 804 : { return base->BatchWrite(mapCoins, hashBlock, hashSaplingAnchor, mapSaplingAnchors, mapSaplingNullifiers); }
48 :
49 : // Sapling
50 464 : bool CCoinsViewBacked::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { return base->GetSaplingAnchorAt(rt, tree); }
51 149 : bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier) const { return base->GetNullifier(nullifier); }
52 242 : uint256 CCoinsViewBacked::GetBestAnchor() const { return base->GetBestAnchor(); }
53 :
54 394906 : SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
55 818417 : SaltedIdHasher::SaltedIdHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
56 :
57 1163789 : CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {}
58 :
59 306500 : size_t CCoinsViewCache::DynamicMemoryUsage() const {
60 306500 : return memusage::DynamicUsage(cacheCoins) +
61 306500 : memusage::DynamicUsage(cacheSaplingAnchors) +
62 306500 : memusage::DynamicUsage(cacheSaplingNullifiers) +
63 306500 : cachedCoinsUsage;
64 : }
65 :
66 59025300 : CCoinsMap::iterator CCoinsViewCache::FetchCoin(const COutPoint& outpoint) const
67 : {
68 59025300 : CCoinsMap::iterator it = cacheCoins.find(outpoint);
69 59025300 : if (it != cacheCoins.end())
70 27289522 : return it;
71 90761000 : Coin tmp;
72 31735730 : if (!base->GetCoin(outpoint, tmp))
73 31735730 : return cacheCoins.end();
74 6825780 : CCoinsMap::iterator ret = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::forward_as_tuple(std::move(tmp))).first;
75 6825780 : 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 285066 : ret->second.flags = CCoinsCacheEntry::FRESH;
79 : }
80 6825780 : cachedCoinsUsage += memusage::DynamicUsage(ret->second.coin);
81 6825780 : return ret;
82 : }
83 :
84 21235220 : bool CCoinsViewCache::GetCoin(const COutPoint& outpoint, Coin& coin) const
85 : {
86 21235220 : CCoinsMap::const_iterator it = FetchCoin(outpoint);
87 21235220 : if (it != cacheCoins.end()) {
88 6168778 : coin = it->second.coin;
89 6168778 : return true;
90 : }
91 : return false;
92 : }
93 :
94 7325393 : void CCoinsViewCache::AddCoin(const COutPoint& outpoint, Coin&& coin, bool possible_overwrite) {
95 7325393 : assert(!coin.IsSpent());
96 7326813 : if (coin.out.scriptPubKey.IsUnspendable()) return;
97 7323963 : if (coin.out.IsZerocoinMint()) return;
98 7323963 : CCoinsMap::iterator it;
99 7323963 : bool inserted;
100 7323963 : std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>());
101 7323963 : bool fresh = false;
102 7323963 : if (!inserted) {
103 83196 : cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
104 : }
105 7323963 : if (!possible_overwrite) {
106 7273200 : if (!it->second.coin.IsSpent()) {
107 12 : throw std::logic_error("Adding new coin that replaces non-pruned entry");
108 : }
109 7273188 : fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY);
110 : }
111 7323951 : it->second.coin = std::move(coin);
112 7323951 : it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0);
113 7323951 : cachedCoinsUsage += it->second.coin.DynamicMemoryUsage();
114 : }
115 :
116 3622926 : void AddCoins(CCoinsViewCache& cache, const CTransaction& tx, int nHeight, bool check, bool fSkipInvalid)
117 : {
118 3622926 : bool fCoinbase = tx.IsCoinBase();
119 3622926 : bool fCoinstake = tx.IsCoinStake();
120 3622926 : const uint256& txid = tx.GetHash();
121 10703083 : for (size_t i = 0; i < tx.vout.size(); ++i) {
122 7080117 : const COutPoint out(txid, i);
123 : // Don't add fraudulent/banned outputs
124 7080117 : 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 7080117 : bool overwrite = check && cache.HaveCoin(out);
129 14160214 : cache.AddCoin(out, Coin(tx.vout[i], nHeight, fCoinbase, fCoinstake), overwrite);
130 : }
131 3622926 : }
132 :
133 5476193 : void CCoinsViewCache::SpendCoin(const COutPoint& outpoint, Coin* moveout)
134 : {
135 5476193 : CCoinsMap::iterator it = FetchCoin(outpoint);
136 5476193 : if (it == cacheCoins.end()) return;
137 5462462 : cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
138 5462462 : if (moveout) {
139 5408863 : *moveout = std::move(it->second.coin);
140 : }
141 5462462 : if (it->second.flags & CCoinsCacheEntry::FRESH) {
142 182580 : cacheCoins.erase(it);
143 : } else {
144 5279879 : it->second.flags |= CCoinsCacheEntry::DIRTY;
145 10742381 : it->second.coin.Clear();
146 : }
147 : }
148 :
149 : static const Coin coinEmpty;
150 :
151 19502440 : const Coin& CCoinsViewCache::AccessCoin(const COutPoint& outpoint) const
152 : {
153 19502440 : CCoinsMap::const_iterator it = FetchCoin(outpoint);
154 19502440 : if (it == cacheCoins.end()) {
155 : return coinEmpty;
156 : } else {
157 10918175 : return it->second.coin;
158 : }
159 : }
160 :
161 12811445 : bool CCoinsViewCache::HaveCoin(const COutPoint& outpoint) const
162 : {
163 12811445 : CCoinsMap::const_iterator it = FetchCoin(outpoint);
164 12811445 : return (it != cacheCoins.end() && !it->second.coin.IsSpent());
165 : }
166 :
167 1006628 : bool CCoinsViewCache::HaveCoinInCache(const COutPoint& outpoint) const
168 : {
169 1006628 : CCoinsMap::const_iterator it = cacheCoins.find(outpoint);
170 1006628 : return it != cacheCoins.end();
171 : }
172 :
173 4374561 : uint256 CCoinsViewCache::GetBestBlock() const
174 : {
175 8749122 : if (hashBlock.IsNull())
176 239231 : hashBlock = base->GetBestBlock();
177 4374561 : return hashBlock;
178 : }
179 :
180 43028 : void CCoinsViewCache::SetBestBlock(const uint256& hashBlockIn)
181 : {
182 43028 : hashBlock = hashBlockIn;
183 43028 : }
184 :
185 : template<typename Map, typename MapIterator, typename MapEntry>
186 42553 : void BatchWriteAnchors(
187 : Map &mapAnchors,
188 : Map &cacheAnchors,
189 : size_t &cachedCoinsUsage
190 : )
191 : {
192 84029 : for (MapIterator child_it = mapAnchors.begin(); child_it != mapAnchors.end();)
193 : {
194 41476 : if (child_it->second.flags & MapEntry::DIRTY) {
195 226 : MapIterator parent_it = cacheAnchors.find(child_it->first);
196 :
197 226 : if (parent_it == cacheAnchors.end()) {
198 216 : MapEntry& entry = cacheAnchors[child_it->first];
199 216 : entry.entered = child_it->second.entered;
200 216 : entry.tree = child_it->second.tree;
201 216 : entry.flags = MapEntry::DIRTY;
202 :
203 216 : 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 41476 : MapIterator itOld = child_it++;
214 41476 : mapAnchors.erase(itOld);
215 : }
216 42553 : }
217 :
218 42553 : void BatchWriteNullifiers(CNullifiersMap &mapNullifiers, CNullifiersMap &cacheNullifiers)
219 : {
220 42703 : for (CNullifiersMap::iterator child_it = mapNullifiers.begin(); child_it != mapNullifiers.end();) {
221 150 : if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
222 149 : CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first);
223 :
224 149 : 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 148 : if (parent_it->second.entered != child_it->second.entered) {
230 148 : parent_it->second.entered = child_it->second.entered;
231 148 : parent_it->second.flags |= CNullifiersCacheEntry::DIRTY;
232 : }
233 : }
234 : }
235 150 : CNullifiersMap::iterator itOld = child_it++;
236 150 : mapNullifiers.erase(itOld);
237 : }
238 42553 : }
239 :
240 42561 : bool CCoinsViewCache::BatchWrite(CCoinsMap& mapCoins,
241 : const uint256& hashBlockIn,
242 : const uint256 &hashSaplingAnchorIn,
243 : CAnchorsSaplingMap& mapSaplingAnchors,
244 : CNullifiersMap& mapSaplingNullifiers)
245 : {
246 1929411 : for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = mapCoins.erase(it)) {
247 : // Ignore non-dirty entries (optimization).
248 1886864 : if (!(it->second.flags & CCoinsCacheEntry::DIRTY)) {
249 276806 : continue;
250 : }
251 1610054 : CCoinsMap::iterator itUs = cacheCoins.find(it->first);
252 1610054 : 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 791740 : 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 791739 : CCoinsCacheEntry& entry = cacheCoins[it->first];
259 791739 : entry.coin = std::move(it->second.coin);
260 791739 : cachedCoinsUsage += memusage::DynamicUsage(entry.coin);
261 791739 : 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 791739 : if (it->second.flags & CCoinsCacheEntry::FRESH) {
266 757974 : 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 818313 : 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 818305 : 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 208911 : cachedCoinsUsage -= memusage::DynamicUsage(itUs->second.coin);
284 208911 : cacheCoins.erase(itUs);
285 : } else {
286 : // A normal modification.
287 609394 : cachedCoinsUsage -= memusage::DynamicUsage(itUs->second.coin);
288 609394 : itUs->second.coin = std::move(it->second.coin);
289 609394 : cachedCoinsUsage += memusage::DynamicUsage(itUs->second.coin);
290 609394 : 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 42553 : ::BatchWriteAnchors<CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(mapSaplingAnchors, cacheSaplingAnchors, cachedCoinsUsage);
302 42553 : ::BatchWriteNullifiers(mapSaplingNullifiers, cacheSaplingNullifiers);
303 42553 : hashSaplingAnchor = hashSaplingAnchorIn;
304 :
305 42553 : hashBlock = hashBlockIn;
306 42553 : return true;
307 : }
308 :
309 43306 : bool CCoinsViewCache::Flush()
310 : {
311 86612 : bool fOk = base->BatchWrite(cacheCoins,
312 43306 : hashBlock,
313 43306 : hashSaplingAnchor,
314 43306 : cacheSaplingAnchors,
315 43306 : cacheSaplingNullifiers);
316 43306 : cacheCoins.clear();
317 43306 : cacheSaplingAnchors.clear();
318 43306 : cacheSaplingNullifiers.clear();
319 43306 : cachedCoinsUsage = 0;
320 43306 : return fOk;
321 : }
322 :
323 14754 : void CCoinsViewCache::Uncache(const COutPoint& outpoint)
324 : {
325 14754 : CCoinsMap::iterator it = cacheCoins.find(outpoint);
326 14754 : if (it != cacheCoins.end() && it->second.flags == 0) {
327 789 : cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
328 789 : cacheCoins.erase(it);
329 : }
330 14754 : }
331 :
332 42990 : unsigned int CCoinsViewCache::GetCacheSize() const
333 : {
334 42990 : return cacheCoins.size();
335 : }
336 :
337 600063 : CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
338 : {
339 600063 : if (tx.IsCoinBase())
340 : return 0;
341 :
342 600063 : CAmount nResult = 0;
343 1723730 : for (const CTxIn& in : tx.vin) {
344 1123663 : if (in.IsZerocoinSpend() || in.IsZerocoinPublicSpend()) {
345 0 : nResult += in.nSequence * COIN;
346 : } else {
347 1123663 : nResult += AccessCoin(in.prevout).out.nValue;
348 : }
349 : }
350 :
351 : // Sapling
352 600063 : nResult += tx.GetShieldedValueIn();
353 :
354 600063 : return nResult;
355 : }
356 :
357 4313367 : bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
358 : {
359 4313367 : if (!tx.IsCoinBase() && !tx.HasZerocoinSpendInputs()) {
360 10888537 : for (unsigned int i = 0; i < tx.vin.size(); i++) {
361 6580954 : if (!HaveCoin(tx.vin[i].prevout)) {
362 : return false;
363 : }
364 : }
365 : }
366 : return true;
367 : }
368 :
369 284 : int CCoinsViewCache::GetCoinDepthAtHeight(const COutPoint& output, int nHeight) const
370 : {
371 284 : const Coin& coin = AccessCoin(output);
372 284 : if (!coin.IsSpent())
373 284 : return nHeight - coin.nHeight + 1;
374 : return -1;
375 : }
376 :
377 440 : CAmount CCoinsViewCache::GetTotalAmount() const
378 : {
379 440 : CAmount nTotal = 0;
380 :
381 440 : std::unique_ptr<CCoinsViewCursor> pcursor(Cursor());
382 3579797 : while (pcursor->Valid()) {
383 7158708 : Coin coin;
384 3579354 : if (pcursor->GetValue(coin) && !coin.IsSpent()) {
385 3579354 : nTotal += coin.out.nValue;
386 : }
387 3579354 : pcursor->Next();
388 : }
389 :
390 880 : 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 7777860 : while (iter.n < MAX_OUTPUTS_PER_BLOCK) {
413 7777820 : const Coin& alternate = view.AccessCoin(iter);
414 7777820 : if (!alternate.IsSpent()) return alternate;
415 7777770 : ++iter.n;
416 : }
417 : return coinEmpty;
418 : }
419 :
420 : // Sapling
421 :
422 161385 : bool CCoinsViewCache::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const {
423 :
424 161385 : CAnchorsSaplingMap::const_iterator it = cacheSaplingAnchors.find(rt);
425 161385 : if (it != cacheSaplingAnchors.end()) {
426 104304 : if (it->second.entered) {
427 104300 : tree = it->second.tree;
428 104300 : return true;
429 : } else {
430 : return false;
431 : }
432 : }
433 :
434 57081 : if (!base->GetSaplingAnchorAt(rt, tree)) {
435 : return false;
436 : }
437 :
438 114160 : CAnchorsSaplingMap::iterator ret = cacheSaplingAnchors.insert(std::make_pair(rt, CAnchorsSaplingCacheEntry())).first;
439 57080 : ret->second.entered = true;
440 57080 : ret->second.tree = tree;
441 57080 : cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
442 :
443 57080 : return true;
444 : }
445 :
446 1511 : bool CCoinsViewCache::GetNullifier(const uint256 &nullifier) const {
447 1511 : CNullifiersMap* cacheToUse = &cacheSaplingNullifiers;
448 1511 : CNullifiersMap::iterator it = cacheToUse->find(nullifier);
449 1511 : if (it != cacheToUse->end())
450 901 : return it->second.entered;
451 :
452 610 : CNullifiersCacheEntry entry;
453 610 : bool tmp = base->GetNullifier(nullifier);
454 610 : entry.entered = tmp;
455 :
456 610 : cacheToUse->insert(std::make_pair(nullifier, entry));
457 610 : return tmp;
458 : }
459 :
460 : template<typename Tree, typename Cache, typename CacheIterator, typename CacheEntry>
461 56433 : void CCoinsViewCache::AbstractPushAnchor(
462 : const Tree &tree,
463 : Cache &cacheAnchors,
464 : uint256 &hash
465 : )
466 : {
467 56433 : uint256 newrt = tree.root();
468 :
469 56433 : 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 56433 : if (currentRoot != newrt) {
477 606 : auto insertRet = cacheAnchors.insert(std::make_pair(newrt, CacheEntry()));
478 303 : CacheIterator ret = insertRet.first;
479 :
480 303 : ret->second.entered = true;
481 303 : ret->second.tree = tree;
482 303 : ret->second.flags = CacheEntry::DIRTY;
483 :
484 303 : if (insertRet.second) {
485 : // An insert took place
486 303 : cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
487 : }
488 :
489 303 : hash = newrt;
490 : }
491 56433 : }
492 :
493 56433 : template<> void CCoinsViewCache::PushAnchor(const SaplingMerkleTree &tree)
494 : {
495 56433 : AbstractPushAnchor<SaplingMerkleTree, CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(
496 : tree,
497 56433 : cacheSaplingAnchors,
498 56433 : hashSaplingAnchor
499 : );
500 56433 : }
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 1464 : void CCoinsViewCache::AbstractPopAnchor(
513 : const uint256 &newrt,
514 : Cache &cacheAnchors,
515 : uint256 &hash
516 : )
517 : {
518 1464 : 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 1464 : 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 1464 : }
541 :
542 1464 : void CCoinsViewCache::PopAnchor(const uint256 &newrt) {
543 1464 : AbstractPopAnchor<SaplingMerkleTree, CAnchorsSaplingMap, CAnchorsSaplingCacheEntry>(
544 : newrt,
545 1464 : cacheSaplingAnchors,
546 1464 : hashSaplingAnchor
547 : );
548 1464 : }
549 :
550 3708861 : void CCoinsViewCache::SetNullifiers(const CTransaction& tx, bool spent) {
551 3708861 : if (tx.sapData) {
552 3709193 : for (const SpendDescription& spendDescription : tx.sapData->vShieldedSpend) {
553 329 : std::pair<CNullifiersMap::iterator, bool> ret = cacheSaplingNullifiers.insert(
554 329 : std::make_pair(spendDescription.nullifier, CNullifiersCacheEntry()));
555 329 : ret.first->second.entered = spent;
556 329 : ret.first->second.flags |= CNullifiersCacheEntry::DIRTY;
557 : }
558 : }
559 3708861 : }
560 :
561 176847 : uint256 CCoinsViewCache::GetBestAnchor() const {
562 353694 : if (hashSaplingAnchor.IsNull())
563 57178 : hashSaplingAnchor = base->GetBestAnchor();
564 176847 : return hashSaplingAnchor;
565 : }
566 :
567 4448913 : bool CCoinsViewCache::HaveShieldedRequirements(const CTransaction& tx) const
568 : {
569 4968914 : if (tx.IsShieldedTx()) {
570 513172 : for (const SpendDescription &spendDescription : tx.sapData->vShieldedSpend) {
571 922 : if (GetNullifier(spendDescription.nullifier)) // Prevent double spends
572 2 : return false;
573 :
574 1840 : SaplingMerkleTree tree;
575 920 : if (!GetSaplingAnchorAt(spendDescription.anchor, tree)) {
576 2 : return false;
577 : }
578 : }
579 : }
580 :
581 : return true;
582 : }
583 :
584 1820 : bool CCoinsViewCache::GetUTXOCoin(const COutPoint& outpoint, Coin& coin) const
585 : {
586 1820 : return GetCoin(outpoint, coin) && !coin.IsSpent();
587 : }
|