]> Git Repo - VerusCoin.git/blame - src/coins.cpp
Mint currency fix
[VerusCoin.git] / src / coins.cpp
CommitLineData
f914f1a7 1// Copyright (c) 2012-2014 The Bitcoin Core developers
fa94b9d5 2// Distributed under the MIT software license, see the accompanying
bc909a7a 3// file COPYING or https://www.opensource.org/licenses/mit-license.php .
a0fa20a1
PW
4
5#include "coins.h"
6
046392dc 7#include "memusage.h"
bc42503f 8#include "random.h"
520ced14 9#include "version.h"
4d4a7cd5 10#include "policy/fees.h"
997cf5a1 11#include "komodo_defs.h"
20c3ac51 12#include "importcoin.h"
8577896f 13#include "pbaas/notarization.h"
989b1de1 14#include "pbaas/reserves.h"
bc42503f 15
a0fa20a1
PW
16#include <assert.h>
17
fa94b9d5
MF
18/**
19 * calculate number of bytes for the bitmask, and its number of non-zero bytes
20 * each bit in the bitmask represents the availability of one output, but the
21 * availabilities of the first two outputs are encoded separately
22 */
a0fa20a1
PW
23void CCoins::CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const {
24 unsigned int nLastUsedByte = 0;
25 for (unsigned int b = 0; 2+b*8 < vout.size(); b++) {
26 bool fZero = true;
27 for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++) {
28 if (!vout[2+b*8+i].IsNull()) {
29 fZero = false;
30 continue;
31 }
32 }
33 if (!fZero) {
34 nLastUsedByte = b + 1;
35 nNonzeroBytes++;
36 }
37 }
38 nBytes += nLastUsedByte;
39}
40
c444c620 41bool CCoins::Spend(uint32_t nPos)
42{
43 if (nPos >= vout.size() || vout[nPos].IsNull())
a0fa20a1 44 return false;
c444c620 45 vout[nPos].SetNull();
a0fa20a1 46 Cleanup();
a0fa20a1
PW
47 return true;
48}
4fc309f0
EOW
49bool CCoinsView::GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { return false; }
50bool CCoinsView::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { return false; }
28d20bdb 51bool CCoinsView::GetNullifier(const uint256 &nullifier, ShieldedType type) const { return false; }
a3dc587a 52bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; }
a3dc587a 53bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; }
4f152496 54uint256 CCoinsView::GetBestBlock() const { return uint256(); }
18322f07 55uint256 CCoinsView::GetBestAnchor(ShieldedType type) const { return uint256(); };
9f25631d
SB
56bool CCoinsView::BatchWrite(CCoinsMap &mapCoins,
57 const uint256 &hashBlock,
08f07288 58 const uint256 &hashSproutAnchor,
18322f07 59 const uint256 &hashSaplingAnchor,
d455828f 60 CAnchorsSproutMap &mapSproutAnchors,
27616b9a 61 CAnchorsSaplingMap &mapSaplingAnchors,
9669920f 62 CNullifiersMap &mapSproutNullifiers,
685e936c 63 CNullifiersMap &mapSaplingNullifiers) { return false; }
a3dc587a 64bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; }
a0fa20a1
PW
65
66
7c70438d 67CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
9f25631d 68
4fc309f0
EOW
69bool CCoinsViewBacked::GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { return base->GetSproutAnchorAt(rt, tree); }
70bool CCoinsViewBacked::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { return base->GetSaplingAnchorAt(rt, tree); }
28d20bdb 71bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier, ShieldedType type) const { return base->GetNullifier(nullifier, type); }
a3dc587a 72bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); }
a3dc587a
DK
73bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); }
74uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
18322f07 75uint256 CCoinsViewBacked::GetBestAnchor(ShieldedType type) const { return base->GetBestAnchor(type); }
a0fa20a1 76void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
9f25631d
SB
77bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins,
78 const uint256 &hashBlock,
08f07288 79 const uint256 &hashSproutAnchor,
18322f07 80 const uint256 &hashSaplingAnchor,
d455828f 81 CAnchorsSproutMap &mapSproutAnchors,
27616b9a 82 CAnchorsSaplingMap &mapSaplingAnchors,
9669920f 83 CNullifiersMap &mapSproutNullifiers,
27616b9a 84 CNullifiersMap &mapSaplingNullifiers) { return base->BatchWrite(mapCoins, hashBlock, hashSproutAnchor, hashSaplingAnchor, mapSproutAnchors, mapSaplingAnchors, mapSproutNullifiers, mapSaplingNullifiers); }
a3dc587a 85bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); }
a0fa20a1 86
bc42503f
PW
87CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
88
046392dc 89CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false), cachedCoinsUsage(0) { }
a0fa20a1 90
f28aec01
PW
91CCoinsViewCache::~CCoinsViewCache()
92{
93 assert(!hasModifier);
a0fa20a1
PW
94}
95
046392dc 96size_t CCoinsViewCache::DynamicMemoryUsage() const {
7f3c7a68 97 return memusage::DynamicUsage(cacheCoins) +
d455828f 98 memusage::DynamicUsage(cacheSproutAnchors) +
27616b9a 99 memusage::DynamicUsage(cacheSaplingAnchors) +
9669920f 100 memusage::DynamicUsage(cacheSproutNullifiers) +
685e936c 101 memusage::DynamicUsage(cacheSaplingNullifiers) +
7f3c7a68 102 cachedCoinsUsage;
046392dc
PW
103}
104
f28aec01 105CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const {
bc42503f
PW
106 CCoinsMap::iterator it = cacheCoins.find(txid);
107 if (it != cacheCoins.end())
a0fa20a1
PW
108 return it;
109 CCoins tmp;
058b08c1 110 if (!base->GetCoins(txid, tmp))
a0fa20a1 111 return cacheCoins.end();
058b08c1
PW
112 CCoinsMap::iterator ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())).first;
113 tmp.swap(ret->second.coins);
114 if (ret->second.coins.IsPruned()) {
115 // The parent only has an empty entry for this txid; we can consider our
116 // version as fresh.
117 ret->second.flags = CCoinsCacheEntry::FRESH;
118 }
6bd1d60c 119 cachedCoinsUsage += ret->second.coins.DynamicMemoryUsage();
a0fa20a1
PW
120 return ret;
121}
122
9f25631d 123
4fc309f0 124bool CCoinsViewCache::GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const {
d455828f
SB
125 CAnchorsSproutMap::const_iterator it = cacheSproutAnchors.find(rt);
126 if (it != cacheSproutAnchors.end()) {
9f25631d 127 if (it->second.entered) {
434f3284 128 tree = it->second.tree;
9f25631d
SB
129 return true;
130 } else {
131 return false;
132 }
133 }
134
008f4ee8 135 if (!base->GetSproutAnchorAt(rt, tree)) {
9f25631d
SB
136 return false;
137 }
138
d455828f 139 CAnchorsSproutMap::iterator ret = cacheSproutAnchors.insert(std::make_pair(rt, CAnchorsSproutCacheEntry())).first;
cf471983 140 ret->second.entered = true;
434f3284 141 ret->second.tree = tree;
43a03e3b 142 cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
9f25631d
SB
143
144 return true;
145}
146
4fc309f0 147bool CCoinsViewCache::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const {
27616b9a
SB
148 CAnchorsSaplingMap::const_iterator it = cacheSaplingAnchors.find(rt);
149 if (it != cacheSaplingAnchors.end()) {
150 if (it->second.entered) {
151 tree = it->second.tree;
152 return true;
153 } else {
154 return false;
155 }
156 }
157
158 if (!base->GetSaplingAnchorAt(rt, tree)) {
159 return false;
160 }
161
162 CAnchorsSaplingMap::iterator ret = cacheSaplingAnchors.insert(std::make_pair(rt, CAnchorsSaplingCacheEntry())).first;
163 ret->second.entered = true;
164 ret->second.tree = tree;
165 cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
166
167 return true;
168}
169
28d20bdb 170bool CCoinsViewCache::GetNullifier(const uint256 &nullifier, ShieldedType type) const {
708c87f1
EOW
171 CNullifiersMap* cacheToUse;
172 switch (type) {
28d20bdb 173 case SPROUT:
9669920f 174 cacheToUse = &cacheSproutNullifiers;
708c87f1 175 break;
28d20bdb 176 case SAPLING:
708c87f1
EOW
177 cacheToUse = &cacheSaplingNullifiers;
178 break;
179 default:
8c57bbac 180 throw std::runtime_error("Unknown shielded type");
708c87f1 181 }
685e936c
EOW
182 CNullifiersMap::iterator it = cacheToUse->find(nullifier);
183 if (it != cacheToUse->end())
45d6bee9
SB
184 return it->second.entered;
185
9e511dbb 186 CNullifiersCacheEntry entry;
708c87f1 187 bool tmp = base->GetNullifier(nullifier, type);
45d6bee9
SB
188 entry.entered = tmp;
189
685e936c 190 cacheToUse->insert(std::make_pair(nullifier, entry));
45d6bee9 191
45d6bee9
SB
192 return tmp;
193}
9f25631d 194
7703a673
SB
195template<typename Tree, typename Cache, typename CacheIterator, typename CacheEntry>
196void CCoinsViewCache::AbstractPushAnchor(
197 const Tree &tree,
198 ShieldedType type,
199 Cache &cacheAnchors,
200 uint256 &hash
201)
202{
434f3284 203 uint256 newrt = tree.root();
9f25631d 204
7703a673 205 auto currentRoot = GetBestAnchor(type);
9f25631d
SB
206
207 // We don't want to overwrite an anchor we already have.
208 // This occurs when a block doesn't modify mapAnchors at all,
b7e4abd6 209 // because there are no joinsplits. We could get around this a
9f25631d
SB
210 // different way (make all blocks modify mapAnchors somehow)
211 // but this is simpler to reason about.
212 if (currentRoot != newrt) {
7703a673
SB
213 auto insertRet = cacheAnchors.insert(std::make_pair(newrt, CacheEntry()));
214 CacheIterator ret = insertRet.first;
9f25631d
SB
215
216 ret->second.entered = true;
434f3284 217 ret->second.tree = tree;
7703a673 218 ret->second.flags = CacheEntry::DIRTY;
9f25631d 219
7f3c7a68
SB
220 if (insertRet.second) {
221 // An insert took place
43a03e3b 222 cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
7f3c7a68
SB
223 }
224
7703a673 225 hash = newrt;
9f25631d
SB
226 }
227}
228
4fc309f0 229template<> void CCoinsViewCache::PushAnchor(const SproutMerkleTree &tree)
3182b4ab 230{
4fc309f0 231 AbstractPushAnchor<SproutMerkleTree, CAnchorsSproutMap, CAnchorsSproutMap::iterator, CAnchorsSproutCacheEntry>(
7703a673
SB
232 tree,
233 SPROUT,
234 cacheSproutAnchors,
235 hashSproutAnchor
236 );
237}
238
4fc309f0 239template<> void CCoinsViewCache::PushAnchor(const SaplingMerkleTree &tree)
3182b4ab 240{
4fc309f0 241 AbstractPushAnchor<SaplingMerkleTree, CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(
85b39f57
SB
242 tree,
243 SAPLING,
244 cacheSaplingAnchors,
245 hashSaplingAnchor
246 );
247}
248
27616b9a
SB
249template<>
250void CCoinsViewCache::BringBestAnchorIntoCache(
251 const uint256 &currentRoot,
4fc309f0 252 SproutMerkleTree &tree
27616b9a
SB
253)
254{
255 assert(GetSproutAnchorAt(currentRoot, tree));
256}
257
258template<>
259void CCoinsViewCache::BringBestAnchorIntoCache(
260 const uint256 &currentRoot,
4fc309f0 261 SaplingMerkleTree &tree
27616b9a
SB
262)
263{
264 assert(GetSaplingAnchorAt(currentRoot, tree));
265}
266
9ea4e387
SB
267template<typename Tree, typename Cache, typename CacheEntry>
268void CCoinsViewCache::AbstractPopAnchor(
269 const uint256 &newrt,
270 ShieldedType type,
271 Cache &cacheAnchors,
272 uint256 &hash
273)
274{
275 auto currentRoot = GetBestAnchor(type);
9f25631d
SB
276
277 // Blocks might not change the commitment tree, in which
278 // case restoring the "old" anchor during a reorg must
279 // have no effect.
280 if (currentRoot != newrt) {
ebd9aa11
SB
281 // Bring the current best anchor into our local cache
282 // so that its tree exists in memory.
283 {
9ea4e387 284 Tree tree;
27616b9a 285 BringBestAnchorIntoCache(currentRoot, tree);
ebd9aa11 286 }
9f25631d 287
ebd9aa11
SB
288 // Mark the anchor as unentered, removing it from view
289 cacheAnchors[currentRoot].entered = false;
290
291 // Mark the cache entry as dirty so it's propagated
9ea4e387 292 cacheAnchors[currentRoot].flags = CacheEntry::DIRTY;
9f25631d 293
ebd9aa11 294 // Mark the new root as the best anchor
9ea4e387 295 hash = newrt;
9f25631d
SB
296 }
297}
298
c643ff0b
SB
299void CCoinsViewCache::PopAnchor(const uint256 &newrt, ShieldedType type) {
300 switch (type) {
301 case SPROUT:
4fc309f0 302 AbstractPopAnchor<SproutMerkleTree, CAnchorsSproutMap, CAnchorsSproutCacheEntry>(
c643ff0b
SB
303 newrt,
304 SPROUT,
305 cacheSproutAnchors,
306 hashSproutAnchor
307 );
308 break;
309 case SAPLING:
4fc309f0 310 AbstractPopAnchor<SaplingMerkleTree, CAnchorsSaplingMap, CAnchorsSaplingCacheEntry>(
c643ff0b
SB
311 newrt,
312 SAPLING,
313 cacheSaplingAnchors,
314 hashSaplingAnchor
315 );
316 break;
317 default:
8c57bbac 318 throw std::runtime_error("Unknown shielded type");
9f25631d
SB
319 }
320}
321
685e936c 322void CCoinsViewCache::SetNullifiers(const CTransaction& tx, bool spent) {
f57f76d7 323 for (const JSDescription &joinsplit : tx.vJoinSplit) {
685e936c 324 for (const uint256 &nullifier : joinsplit.nullifiers) {
9669920f 325 std::pair<CNullifiersMap::iterator, bool> ret = cacheSproutNullifiers.insert(std::make_pair(nullifier, CNullifiersCacheEntry()));
685e936c
EOW
326 ret.first->second.entered = spent;
327 ret.first->second.flags |= CNullifiersCacheEntry::DIRTY;
328 }
329 }
cab341e1
EOW
330 for (const SpendDescription &spendDescription : tx.vShieldedSpend) {
331 std::pair<CNullifiersMap::iterator, bool> ret = cacheSaplingNullifiers.insert(std::make_pair(spendDescription.nullifier, CNullifiersCacheEntry()));
332 ret.first->second.entered = spent;
333 ret.first->second.flags |= CNullifiersCacheEntry::DIRTY;
334 }
45d6bee9
SB
335}
336
058b08c1
PW
337bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const {
338 CCoinsMap::const_iterator it = FetchCoins(txid);
339 if (it != cacheCoins.end()) {
340 coins = it->second.coins;
341 return true;
342 }
343 return false;
a3dc587a
DK
344}
345
f28aec01
PW
346CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) {
347 assert(!hasModifier);
058b08c1 348 std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry()));
046392dc 349 size_t cachedCoinUsage = 0;
f28aec01 350 if (ret.second) {
058b08c1
PW
351 if (!base->GetCoins(txid, ret.first->second.coins)) {
352 // The parent view does not have this entry; mark it as fresh.
353 ret.first->second.coins.Clear();
354 ret.first->second.flags = CCoinsCacheEntry::FRESH;
355 } else if (ret.first->second.coins.IsPruned()) {
356 // The parent view only has a pruned entry for this; mark it as fresh.
357 ret.first->second.flags = CCoinsCacheEntry::FRESH;
358 }
046392dc 359 } else {
6bd1d60c 360 cachedCoinUsage = ret.first->second.coins.DynamicMemoryUsage();
f28aec01 361 }
058b08c1
PW
362 // Assume that whenever ModifyCoins is called, the entry will be modified.
363 ret.first->second.flags |= CCoinsCacheEntry::DIRTY;
046392dc 364 return CCoinsModifier(*this, ret.first, cachedCoinUsage);
a0fa20a1
PW
365}
366
7335afab
AM
367CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid) {
368 assert(!hasModifier);
369 std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry()));
370 ret.first->second.coins.Clear();
371 ret.first->second.flags = CCoinsCacheEntry::FRESH;
372 ret.first->second.flags |= CCoinsCacheEntry::DIRTY;
373 return CCoinsModifier(*this, ret.first, 0);
374}
375
629d75fa
PW
376const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const {
377 CCoinsMap::const_iterator it = FetchCoins(txid);
378 if (it == cacheCoins.end()) {
379 return NULL;
380 } else {
058b08c1 381 return &it->second.coins;
629d75fa 382 }
a3dc587a
DK
383}
384
a3dc587a
DK
385bool CCoinsViewCache::HaveCoins(const uint256 &txid) const {
386 CCoinsMap::const_iterator it = FetchCoins(txid);
d4d3fbd8 387 // We're using vtx.empty() instead of IsPruned here for performance reasons,
fa94b9d5 388 // as we only care about the case where a transaction was replaced entirely
d4d3fbd8
PW
389 // in a reorganization (which wipes vout entirely, as opposed to spending
390 // which just cleans individual outputs).
058b08c1 391 return (it != cacheCoins.end() && !it->second.coins.vout.empty());
a0fa20a1
PW
392}
393
a3dc587a 394uint256 CCoinsViewCache::GetBestBlock() const {
4f152496 395 if (hashBlock.IsNull())
37ad6886
MT
396 {
397 if (base)
398 {
399 hashBlock = base->GetBestBlock();
400 }
401 else
402 {
403 hashBlock = uint256();
404 }
405 }
a0fa20a1
PW
406 return hashBlock;
407}
408
9f25631d 409
18322f07
SB
410uint256 CCoinsViewCache::GetBestAnchor(ShieldedType type) const {
411 switch (type) {
412 case SPROUT:
413 if (hashSproutAnchor.IsNull())
414 hashSproutAnchor = base->GetBestAnchor(type);
415 return hashSproutAnchor;
416 break;
417 case SAPLING:
418 if (hashSaplingAnchor.IsNull())
419 hashSaplingAnchor = base->GetBestAnchor(type);
420 return hashSaplingAnchor;
421 break;
422 default:
8c57bbac 423 throw std::runtime_error("Unknown shielded type");
18322f07 424 }
9f25631d
SB
425}
426
c9d1a81c 427void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
a0fa20a1 428 hashBlock = hashBlockIn;
a0fa20a1
PW
429}
430
685e936c
EOW
431void BatchWriteNullifiers(CNullifiersMap &mapNullifiers, CNullifiersMap &cacheNullifiers)
432{
433 for (CNullifiersMap::iterator child_it = mapNullifiers.begin(); child_it != mapNullifiers.end();) {
434 if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
435 CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first);
436
437 if (parent_it == cacheNullifiers.end()) {
438 CNullifiersCacheEntry& entry = cacheNullifiers[child_it->first];
439 entry.entered = child_it->second.entered;
440 entry.flags = CNullifiersCacheEntry::DIRTY;
441 } else {
442 if (parent_it->second.entered != child_it->second.entered) {
443 parent_it->second.entered = child_it->second.entered;
444 parent_it->second.flags |= CNullifiersCacheEntry::DIRTY;
445 }
446 }
447 }
448 CNullifiersMap::iterator itOld = child_it++;
449 mapNullifiers.erase(itOld);
450 }
451}
452
27616b9a
SB
453template<typename Map, typename MapIterator, typename MapEntry>
454void BatchWriteAnchors(
455 Map &mapAnchors,
456 Map &cacheAnchors,
457 size_t &cachedCoinsUsage
458)
459{
460 for (MapIterator child_it = mapAnchors.begin(); child_it != mapAnchors.end();)
461 {
462 if (child_it->second.flags & MapEntry::DIRTY) {
463 MapIterator parent_it = cacheAnchors.find(child_it->first);
464
465 if (parent_it == cacheAnchors.end()) {
466 MapEntry& entry = cacheAnchors[child_it->first];
467 entry.entered = child_it->second.entered;
468 entry.tree = child_it->second.tree;
469 entry.flags = MapEntry::DIRTY;
470
471 cachedCoinsUsage += entry.tree.DynamicMemoryUsage();
472 } else {
473 if (parent_it->second.entered != child_it->second.entered) {
474 // The parent may have removed the entry.
475 parent_it->second.entered = child_it->second.entered;
476 parent_it->second.flags |= MapEntry::DIRTY;
477 }
478 }
479 }
480
481 MapIterator itOld = child_it++;
482 mapAnchors.erase(itOld);
483 }
484}
485
9f25631d
SB
486bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
487 const uint256 &hashBlockIn,
08f07288 488 const uint256 &hashSproutAnchorIn,
18322f07 489 const uint256 &hashSaplingAnchorIn,
d455828f 490 CAnchorsSproutMap &mapSproutAnchors,
27616b9a 491 CAnchorsSaplingMap &mapSaplingAnchors,
9669920f 492 CNullifiersMap &mapSproutNullifiers,
685e936c 493 CNullifiersMap &mapSaplingNullifiers) {
f28aec01 494 assert(!hasModifier);
b0875eb3 495 for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
058b08c1
PW
496 if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
497 CCoinsMap::iterator itUs = cacheCoins.find(it->first);
498 if (itUs == cacheCoins.end()) {
499 if (!it->second.coins.IsPruned()) {
500 // The parent cache does not have an entry, while the child
501 // cache does have (a non-pruned) one. Move the data up, and
502 // mark it as fresh (if the grandparent did have it, we
503 // would have pulled it in at first GetCoins).
504 assert(it->second.flags & CCoinsCacheEntry::FRESH);
505 CCoinsCacheEntry& entry = cacheCoins[it->first];
506 entry.coins.swap(it->second.coins);
6bd1d60c 507 cachedCoinsUsage += entry.coins.DynamicMemoryUsage();
058b08c1
PW
508 entry.flags = CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH;
509 }
510 } else {
511 if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) {
512 // The grandparent does not have an entry, and the child is
513 // modified and being pruned. This means we can just delete
514 // it from the parent.
6bd1d60c 515 cachedCoinsUsage -= itUs->second.coins.DynamicMemoryUsage();
058b08c1
PW
516 cacheCoins.erase(itUs);
517 } else {
518 // A normal modification.
6bd1d60c 519 cachedCoinsUsage -= itUs->second.coins.DynamicMemoryUsage();
058b08c1 520 itUs->second.coins.swap(it->second.coins);
6bd1d60c 521 cachedCoinsUsage += itUs->second.coins.DynamicMemoryUsage();
058b08c1
PW
522 itUs->second.flags |= CCoinsCacheEntry::DIRTY;
523 }
524 }
525 }
b0875eb3
PW
526 CCoinsMap::iterator itOld = it++;
527 mapCoins.erase(itOld);
528 }
9f25631d 529
27616b9a
SB
530 ::BatchWriteAnchors<CAnchorsSproutMap, CAnchorsSproutMap::iterator, CAnchorsSproutCacheEntry>(mapSproutAnchors, cacheSproutAnchors, cachedCoinsUsage);
531 ::BatchWriteAnchors<CAnchorsSaplingMap, CAnchorsSaplingMap::iterator, CAnchorsSaplingCacheEntry>(mapSaplingAnchors, cacheSaplingAnchors, cachedCoinsUsage);
45d6bee9 532
9669920f 533 ::BatchWriteNullifiers(mapSproutNullifiers, cacheSproutNullifiers);
685e936c 534 ::BatchWriteNullifiers(mapSaplingNullifiers, cacheSaplingNullifiers);
45d6bee9 535
08f07288 536 hashSproutAnchor = hashSproutAnchorIn;
18322f07 537 hashSaplingAnchor = hashSaplingAnchorIn;
a0fa20a1
PW
538 hashBlock = hashBlockIn;
539 return true;
540}
541
542bool CCoinsViewCache::Flush() {
27616b9a 543 bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashSproutAnchor, hashSaplingAnchor, cacheSproutAnchors, cacheSaplingAnchors, cacheSproutNullifiers, cacheSaplingNullifiers);
b0875eb3 544 cacheCoins.clear();
d455828f 545 cacheSproutAnchors.clear();
27616b9a 546 cacheSaplingAnchors.clear();
9669920f 547 cacheSproutNullifiers.clear();
685e936c 548 cacheSaplingNullifiers.clear();
046392dc 549 cachedCoinsUsage = 0;
a0fa20a1
PW
550 return fOk;
551}
552
a3dc587a 553unsigned int CCoinsViewCache::GetCacheSize() const {
a0fa20a1
PW
554 return cacheCoins.size();
555}
556
a3dc587a 557const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) const
a0fa20a1 558{
629d75fa
PW
559 const CCoins* coins = AccessCoins(input.prevout.hash);
560 assert(coins && coins->IsAvailable(input.prevout.n));
561 return coins->vout[input.prevout.n];
a0fa20a1
PW
562}
563
b0e452de
MT
564//uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
565uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight);
566extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
567
568const CScript &CCoinsViewCache::GetSpendFor(const CCoins *coins, const CTxIn& input)
6c8e1cdf
MT
569{
570 assert(coins);
b0e452de 571 if (coins->nHeight < 6400 && !strcmp(ASSETCHAINS_SYMBOL, "VRSC"))
6c8e1cdf 572 {
b0e452de
MT
573 std::string hc = input.prevout.hash.ToString();
574 if (LaunchMap().lmap.count(hc))
575 {
c6e21843
MT
576 CTransactionExceptionData &txData = LaunchMap().lmap[hc];
577 if ((txData.voutMask & (((uint64_t)1) << (uint64_t)input.prevout.n)) != 0)
578 {
579 return txData.scriptPubKey;
580 }
b0e452de 581 }
6c8e1cdf 582 }
c1e71947 583 return coins->vout[input.prevout.n].scriptPubKey;
6c8e1cdf
MT
584}
585
e4ca0031 586const CScript &CCoinsViewCache::GetSpendFor(const CTxIn& input) const
587{
588 const CCoins* coins = AccessCoins(input.prevout.hash);
6c8e1cdf 589 return GetSpendFor(coins, input);
e4ca0031 590}
591
56fe75cb 592CAmount CCoinsViewCache::GetValueIn(int32_t nHeight, int64_t *interestp, const CTransaction& tx, uint32_t tiptime) const
a0fa20a1 593{
0cb91a8d 594 CAmount value,nResult = 0;
5d2f557e 595 if ( interestp != 0 )
596 *interestp = 0;
0cb91a8d
SS
597 if ( tx.IsCoinImport() )
598 return GetCoinImportValue(tx);
63a9f526 599 if ( tx.IsCoinBase() != 0 )
a0fa20a1 600 return 0;
a0fa20a1 601 for (unsigned int i = 0; i < tx.vin.size(); i++)
602dc744 602 {
4a98cf25
MT
603 value = 0;
604 const CCoins* coins = AccessCoins(tx.vin[i].prevout.hash);
605 if (coins && coins->IsAvailable(tx.vin[i].prevout.n))
606 {
ebbd0d96 607 // if we are a PBaaS chain tx with a coinbase currency state input, all non-shielded inputs are effectively considered burned, since this must be the
45d7e5d5 608 // block's conversion transaction and they are assumed to all be converted
609 COptCCParams p;
8496077f 610 if (!_IsVerusActive() && coins->fCoinBase && coins->vout[tx.vin[i].prevout.n].scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid() && p.evalCode == EVAL_CURRENCYSTATE)
45d7e5d5 611 {
612 CCoinbaseCurrencyState cbcs;
613 if (p.vData.size() && (cbcs = CCoinbaseCurrencyState(p.vData[0])).IsValid() && cbcs.IsReserve())
614 {
615 nResult = coins->vout[tx.vin[i].prevout.n].nValue;
616 break;
617 }
618 }
619 else
620 {
621 value = coins->vout[tx.vin[i].prevout.n].nValue;
622 }
4a98cf25
MT
623 }
624 else
625 {
626 return 0;
627 }
628
63a9f526 629 nResult += value;
fdbf481f 630#ifdef KOMODO_ENABLE_INTEREST
1141b678 631 if ( ASSETCHAINS_SYMBOL[0] == 0 && nHeight >= 60000 )
4a4e912b 632 {
98f68225 633 if ( value >= 10*COIN )
3959e9f3 634 {
798f28c7 635 int64_t interest; int32_t txheight; uint32_t locktime;
c60397dd 636 interest = komodo_accrued_interest(&txheight,&locktime,tx.vin[i].prevout.hash,tx.vin[i].prevout.n,0,value,(int32_t)nHeight);
f6356642 637 //printf("nResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nResult/COIN,(double)value/COIN,(double)interest/COIN,txheight,locktime,tiptime);
638 //fprintf(stderr,"nResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nResult/COIN,(double)value/COIN,(double)interest/COIN,txheight,locktime,tiptime);
3b97ccc9 639 nResult += interest;
a6e612cc
MT
640 if (interestp)
641 (*interestp) += interest;
3959e9f3 642 }
4a4e912b 643 }
a130c5cb 644#endif
602dc744 645 }
97b46f00 646 nResult += tx.GetShieldedValueIn();
f512cf7c 647
a0fa20a1
PW
648 return nResult;
649}
650
56fe75cb 651CCurrencyValueMap CCoinsViewCache::GetReserveValueIn(int32_t nHeight, const CTransaction& tx) const
989b1de1 652{
56fe75cb 653 CCurrencyValueMap retMap;
4b7d1485 654
45d7e5d5 655 CAmount nResult = 0;
989b1de1 656
e7e14f44 657 // coinbases have no inputs
989b1de1 658 if ( tx.IsCoinBase() != 0 )
56fe75cb 659 return retMap;
989b1de1
MT
660
661 for (unsigned int i = 0; i < tx.vin.size(); i++)
662 {
989b1de1
MT
663 const CCoins* coins = AccessCoins(tx.vin[i].prevout.hash);
664 if (coins && coins->IsAvailable(tx.vin[i].prevout.n))
665 {
adeede49 666 retMap += coins->vout[tx.vin[i].prevout.n].scriptPubKey.ReserveOutValue();
989b1de1
MT
667 }
668 else
669 {
adeede49 670 // if coins aren't available, fail all
56fe75cb 671 return CCurrencyValueMap();
989b1de1 672 }
989b1de1 673 }
56fe75cb 674 return retMap;
989b1de1 675}
0cb91a8d 676
88d014d0 677//bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const
06affbca 678bool CCoinsViewCache::HaveShieldedRequirements(const CTransaction& tx) const
a8ac403d 679{
4fc309f0 680 boost::unordered_map<uint256, SproutMerkleTree, CCoinsKeyHasher> intermediates;
6c59778a 681
f57f76d7 682 BOOST_FOREACH(const JSDescription &joinsplit, tx.vJoinSplit)
a8ac403d 683 {
9e511dbb 684 BOOST_FOREACH(const uint256& nullifier, joinsplit.nullifiers)
d66877af 685 {
28d20bdb 686 if (GetNullifier(nullifier, SPROUT)) {
9e511dbb 687 // If the nullifier is set, this transaction
d66877af
SB
688 // double-spends!
689 return false;
690 }
691 }
692
4fc309f0 693 SproutMerkleTree tree;
b7e4abd6 694 auto it = intermediates.find(joinsplit.anchor);
6c59778a
SB
695 if (it != intermediates.end()) {
696 tree = it->second;
008f4ee8 697 } else if (!GetSproutAnchorAt(joinsplit.anchor, tree)) {
a8ac403d
SB
698 return false;
699 }
6c59778a 700
b7e4abd6 701 BOOST_FOREACH(const uint256& commitment, joinsplit.commitments)
6c59778a
SB
702 {
703 tree.append(commitment);
704 }
705
706 intermediates.insert(std::make_pair(tree.root(), tree));
a8ac403d
SB
707 }
708
cab341e1 709 for (const SpendDescription &spendDescription : tx.vShieldedSpend) {
28d20bdb 710 if (GetNullifier(spendDescription.nullifier, SAPLING)) // Prevent double spends
cab341e1 711 return false;
a8ac403d 712
4fc309f0 713 SaplingMerkleTree tree;
1f8be05b
SB
714 if (!GetSaplingAnchorAt(spendDescription.anchor, tree)) {
715 return false;
716 }
717 }
27616b9a 718
a8ac403d
SB
719 return true;
720}
721
a3dc587a 722bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
a0fa20a1 723{
0cb91a8d 724 if (!tx.IsMint()) {
6f45d897 725 for (unsigned int i = 0; i < tx.vin.size(); i++) {
a0fa20a1 726 const COutPoint &prevout = tx.vin[i].prevout;
629d75fa
PW
727 const CCoins* coins = AccessCoins(prevout.hash);
728 if (!coins || !coins->IsAvailable(prevout.n)) {
d6f8eeb9 729 //fprintf(stderr,"HaveInputs missing input %s/v%d\n",prevout.hash.ToString().c_str(),prevout.n);
a0fa20a1 730 return false;
629d75fa 731 }
a0fa20a1
PW
732 }
733 }
734 return true;
735}
4d707d51 736
c8c677c9 737double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight, const CReserveTransactionDescriptor *desc, const CCurrencyState *currencyState) const
4d707d51
GA
738{
739 if (tx.IsCoinBase())
740 return 0.0;
ec19e8e2 741
a1349274 742 // Shielded transfers do not reveal any information about the value or age of a note, so we
4d4a7cd5 743 // cannot apply the priority algorithm used for transparent utxos. Instead, we just
a1349274
EOW
744 // use the maximum priority for all (partially or fully) shielded transactions.
745 // (Note that coinbase transactions cannot contain JoinSplits, or Sapling shielded Spends or Outputs.)
ec19e8e2 746
88d014d0 747 if (tx.vJoinSplit.size() > 0 || tx.vShieldedSpend.size() > 0 || tx.vShieldedOutput.size() > 0 || tx.IsCoinImport()) {
0cb91a8d
SS
748 return MAX_PRIORITY;
749 }
4d4a7cd5 750
51e6ed61 751 // FIXME: this logic is partially duplicated between here and CreateNewBlock in miner.cpp.
4d707d51
GA
752 double dResult = 0.0;
753 BOOST_FOREACH(const CTxIn& txin, tx.vin)
754 {
629d75fa
PW
755 const CCoins* coins = AccessCoins(txin.prevout.hash);
756 assert(coins);
757 if (!coins->IsAvailable(txin.prevout.n)) continue;
758 if (coins->nHeight < nHeight) {
56fe75cb 759 if (currencyState && desc)
760 {
761 dResult += (coins->vout[txin.prevout.n].nValue + currencyState->ReserveToNative(coins->vout[txin.prevout.n].ReserveOutValue())) *
762 (nHeight-coins->nHeight);
763 }
764 else
765 {
766 dResult += coins->vout[txin.prevout.n].nValue * (nHeight-coins->nHeight);
767 }
4d707d51
GA
768 }
769 }
770 return tx.ComputePriority(dResult);
771}
f28aec01 772
046392dc 773CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_, size_t usage) : cache(cache_), it(it_), cachedCoinUsage(usage) {
02bced16
PW
774 assert(!cache.hasModifier);
775 cache.hasModifier = true;
776}
f28aec01 777
058b08c1
PW
778CCoinsModifier::~CCoinsModifier()
779{
f28aec01
PW
780 assert(cache.hasModifier);
781 cache.hasModifier = false;
058b08c1 782 it->second.coins.Cleanup();
046392dc 783 cache.cachedCoinsUsage -= cachedCoinUsage; // Subtract the old usage
058b08c1
PW
784 if ((it->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) {
785 cache.cacheCoins.erase(it);
046392dc
PW
786 } else {
787 // If the coin still exists after the modification, add the new usage
6bd1d60c 788 cache.cachedCoinsUsage += it->second.coins.DynamicMemoryUsage();
058b08c1 789 }
f28aec01 790}
This page took 0.450303 seconds and 4 git commands to generate.