1 // Copyright (c) 2012-2014 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
10 #include "policy/fees.h"
11 #include "komodo_defs.h"
14 #include <unordered_map>
17 * calculate number of bytes for the bitmask, and its number of non-zero bytes
18 * each bit in the bitmask represents the availability of one output, but the
19 * availabilities of the first two outputs are encoded separately
21 void CCoins::CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const {
22 unsigned int nLastUsedByte = 0;
23 for (unsigned int b = 0; 2+b*8 < vout.size(); b++) {
25 for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++) {
26 if (!vout[2+b*8+i].IsNull()) {
32 nLastUsedByte = b + 1;
36 nBytes += nLastUsedByte;
39 bool CCoins::Spend(uint32_t nPos)
41 if (nPos >= vout.size() || vout[nPos].IsNull())
47 bool CCoinsView::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return false; }
48 bool CCoinsView::GetNullifier(const uint256 &nullifier) const { return false; }
49 bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; }
50 bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; }
51 uint256 CCoinsView::GetBestBlock() const { return uint256(); }
52 uint256 CCoinsView::GetBestAnchor() const { return uint256(); };
53 bool CCoinsView::BatchWrite(CCoinsMap &mapCoins,
54 const uint256 &hashBlock,
55 const uint256 &hashAnchor,
56 CAnchorsMap &mapAnchors,
57 CNullifiersMap &mapNullifiers) { return false; }
58 bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; }
61 CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
63 bool CCoinsViewBacked::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return base->GetAnchorAt(rt, tree); }
64 bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier) const { return base->GetNullifier(nullifier); }
65 bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); }
66 bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); }
67 uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
68 uint256 CCoinsViewBacked::GetBestAnchor() const { return base->GetBestAnchor(); }
69 void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
70 bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins,
71 const uint256 &hashBlock,
72 const uint256 &hashAnchor,
73 CAnchorsMap &mapAnchors,
74 CNullifiersMap &mapNullifiers) { return base->BatchWrite(mapCoins, hashBlock, hashAnchor, mapAnchors, mapNullifiers); }
75 bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); }
77 CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
79 CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false), cachedCoinsUsage(0) { }
81 CCoinsViewCache::~CCoinsViewCache()
86 size_t CCoinsViewCache::DynamicMemoryUsage() const {
87 return memusage::DynamicUsage(cacheCoins) +
88 memusage::DynamicUsage(cacheAnchors) +
89 memusage::DynamicUsage(cacheNullifiers) +
93 CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const {
94 CCoinsMap::iterator it = cacheCoins.find(txid);
95 if (it != cacheCoins.end())
98 if (!base->GetCoins(txid, tmp))
99 return cacheCoins.end();
100 CCoinsMap::iterator ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())).first;
101 tmp.swap(ret->second.coins);
102 if (ret->second.coins.IsPruned()) {
103 // The parent only has an empty entry for this txid; we can consider our
105 ret->second.flags = CCoinsCacheEntry::FRESH;
107 cachedCoinsUsage += ret->second.coins.DynamicMemoryUsage();
112 bool CCoinsViewCache::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const {
113 CAnchorsMap::const_iterator it = cacheAnchors.find(rt);
114 if (it != cacheAnchors.end()) {
115 if (it->second.entered) {
116 tree = it->second.tree;
123 if (!base->GetAnchorAt(rt, tree)) {
127 CAnchorsMap::iterator ret = cacheAnchors.insert(std::make_pair(rt, CAnchorsCacheEntry())).first;
128 ret->second.entered = true;
129 ret->second.tree = tree;
130 cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
135 bool CCoinsViewCache::GetNullifier(const uint256 &nullifier) const {
136 CNullifiersMap::iterator it = cacheNullifiers.find(nullifier);
137 if (it != cacheNullifiers.end())
138 return it->second.entered;
140 CNullifiersCacheEntry entry;
141 bool tmp = base->GetNullifier(nullifier);
144 cacheNullifiers.insert(std::make_pair(nullifier, entry));
149 void CCoinsViewCache::PushAnchor(const ZCIncrementalMerkleTree &tree) {
150 uint256 newrt = tree.root();
152 auto currentRoot = GetBestAnchor();
154 // We don't want to overwrite an anchor we already have.
155 // This occurs when a block doesn't modify mapAnchors at all,
156 // because there are no joinsplits. We could get around this a
157 // different way (make all blocks modify mapAnchors somehow)
158 // but this is simpler to reason about.
159 if (currentRoot != newrt) {
160 auto insertRet = cacheAnchors.insert(std::make_pair(newrt, CAnchorsCacheEntry()));
161 CAnchorsMap::iterator ret = insertRet.first;
163 ret->second.entered = true;
164 ret->second.tree = tree;
165 ret->second.flags = CAnchorsCacheEntry::DIRTY;
167 if (insertRet.second) {
168 // An insert took place
169 cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage();
176 void CCoinsViewCache::PopAnchor(const uint256 &newrt) {
177 auto currentRoot = GetBestAnchor();
179 // Blocks might not change the commitment tree, in which
180 // case restoring the "old" anchor during a reorg must
182 if (currentRoot != newrt) {
183 // Bring the current best anchor into our local cache
184 // so that its tree exists in memory.
186 ZCIncrementalMerkleTree tree;
187 assert(GetAnchorAt(currentRoot, tree));
190 // Mark the anchor as unentered, removing it from view
191 cacheAnchors[currentRoot].entered = false;
193 // Mark the cache entry as dirty so it's propagated
194 cacheAnchors[currentRoot].flags = CAnchorsCacheEntry::DIRTY;
196 // Mark the new root as the best anchor
201 void CCoinsViewCache::SetNullifier(const uint256 &nullifier, bool spent) {
202 std::pair<CNullifiersMap::iterator, bool> ret = cacheNullifiers.insert(std::make_pair(nullifier, CNullifiersCacheEntry()));
203 ret.first->second.entered = spent;
204 ret.first->second.flags |= CNullifiersCacheEntry::DIRTY;
207 bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const {
208 CCoinsMap::const_iterator it = FetchCoins(txid);
209 if (it != cacheCoins.end()) {
210 coins = it->second.coins;
216 CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) {
217 assert(!hasModifier);
218 std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry()));
219 size_t cachedCoinUsage = 0;
221 if (!base->GetCoins(txid, ret.first->second.coins)) {
222 // The parent view does not have this entry; mark it as fresh.
223 ret.first->second.coins.Clear();
224 ret.first->second.flags = CCoinsCacheEntry::FRESH;
225 } else if (ret.first->second.coins.IsPruned()) {
226 // The parent view only has a pruned entry for this; mark it as fresh.
227 ret.first->second.flags = CCoinsCacheEntry::FRESH;
230 cachedCoinUsage = ret.first->second.coins.DynamicMemoryUsage();
232 // Assume that whenever ModifyCoins is called, the entry will be modified.
233 ret.first->second.flags |= CCoinsCacheEntry::DIRTY;
234 return CCoinsModifier(*this, ret.first, cachedCoinUsage);
237 const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const {
238 CCoinsMap::const_iterator it = FetchCoins(txid);
239 if (it == cacheCoins.end()) {
242 return &it->second.coins;
246 bool CCoinsViewCache::HaveCoins(const uint256 &txid) const {
247 CCoinsMap::const_iterator it = FetchCoins(txid);
248 // We're using vtx.empty() instead of IsPruned here for performance reasons,
249 // as we only care about the case where a transaction was replaced entirely
250 // in a reorganization (which wipes vout entirely, as opposed to spending
251 // which just cleans individual outputs).
252 return (it != cacheCoins.end() && !it->second.coins.vout.empty());
255 uint256 CCoinsViewCache::GetBestBlock() const {
256 if (hashBlock.IsNull())
257 hashBlock = base->GetBestBlock();
262 uint256 CCoinsViewCache::GetBestAnchor() const {
263 if (hashAnchor.IsNull())
264 hashAnchor = base->GetBestAnchor();
268 void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
269 hashBlock = hashBlockIn;
272 bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
273 const uint256 &hashBlockIn,
274 const uint256 &hashAnchorIn,
275 CAnchorsMap &mapAnchors,
276 CNullifiersMap &mapNullifiers) {
277 assert(!hasModifier);
278 for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
279 if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
280 CCoinsMap::iterator itUs = cacheCoins.find(it->first);
281 if (itUs == cacheCoins.end()) {
282 if (!it->second.coins.IsPruned()) {
283 // The parent cache does not have an entry, while the child
284 // cache does have (a non-pruned) one. Move the data up, and
285 // mark it as fresh (if the grandparent did have it, we
286 // would have pulled it in at first GetCoins).
287 assert(it->second.flags & CCoinsCacheEntry::FRESH);
288 CCoinsCacheEntry& entry = cacheCoins[it->first];
289 entry.coins.swap(it->second.coins);
290 cachedCoinsUsage += entry.coins.DynamicMemoryUsage();
291 entry.flags = CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH;
294 if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) {
295 // The grandparent does not have an entry, and the child is
296 // modified and being pruned. This means we can just delete
297 // it from the parent.
298 cachedCoinsUsage -= itUs->second.coins.DynamicMemoryUsage();
299 cacheCoins.erase(itUs);
301 // A normal modification.
302 cachedCoinsUsage -= itUs->second.coins.DynamicMemoryUsage();
303 itUs->second.coins.swap(it->second.coins);
304 cachedCoinsUsage += itUs->second.coins.DynamicMemoryUsage();
305 itUs->second.flags |= CCoinsCacheEntry::DIRTY;
309 CCoinsMap::iterator itOld = it++;
310 mapCoins.erase(itOld);
313 for (CAnchorsMap::iterator child_it = mapAnchors.begin(); child_it != mapAnchors.end();)
315 if (child_it->second.flags & CAnchorsCacheEntry::DIRTY) {
316 CAnchorsMap::iterator parent_it = cacheAnchors.find(child_it->first);
318 if (parent_it == cacheAnchors.end()) {
319 CAnchorsCacheEntry& entry = cacheAnchors[child_it->first];
320 entry.entered = child_it->second.entered;
321 entry.tree = child_it->second.tree;
322 entry.flags = CAnchorsCacheEntry::DIRTY;
324 cachedCoinsUsage += entry.tree.DynamicMemoryUsage();
326 if (parent_it->second.entered != child_it->second.entered) {
327 // The parent may have removed the entry.
328 parent_it->second.entered = child_it->second.entered;
329 parent_it->second.flags |= CAnchorsCacheEntry::DIRTY;
334 CAnchorsMap::iterator itOld = child_it++;
335 mapAnchors.erase(itOld);
338 for (CNullifiersMap::iterator child_it = mapNullifiers.begin(); child_it != mapNullifiers.end();)
340 if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
341 CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first);
343 if (parent_it == cacheNullifiers.end()) {
344 CNullifiersCacheEntry& entry = cacheNullifiers[child_it->first];
345 entry.entered = child_it->second.entered;
346 entry.flags = CNullifiersCacheEntry::DIRTY;
348 if (parent_it->second.entered != child_it->second.entered) {
349 parent_it->second.entered = child_it->second.entered;
350 parent_it->second.flags |= CNullifiersCacheEntry::DIRTY;
354 CNullifiersMap::iterator itOld = child_it++;
355 mapNullifiers.erase(itOld);
358 hashAnchor = hashAnchorIn;
359 hashBlock = hashBlockIn;
363 bool CCoinsViewCache::Flush() {
364 bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashAnchor, cacheAnchors, cacheNullifiers);
366 cacheAnchors.clear();
367 cacheNullifiers.clear();
368 cachedCoinsUsage = 0;
372 unsigned int CCoinsViewCache::GetCacheSize() const {
373 return cacheCoins.size();
376 const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) const
378 const CCoins* coins = AccessCoins(input.prevout.hash);
379 assert(coins && coins->IsAvailable(input.prevout.n));
380 return coins->vout[input.prevout.n];
383 const CScript &CCoinsViewCache::GetSpendFor(const CCoins *coins, const CTxIn& input) const
386 if (launchMap.launchMap.count(input.prevout.hash))
388 return launchMap.launchMap[input.prevout.hash];
390 else return coins->vout[input.prevout.n].scriptPubKey;
393 const CScript &CCoinsViewCache::GetSpendFor(const CTxIn& input) const
395 const CCoins* coins = AccessCoins(input.prevout.hash);
396 return GetSpendFor(coins, input);
399 //uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
400 uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight);
401 extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
403 CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTransaction& tx,uint32_t tiptime) const
405 if ( interestp != 0 )
407 if ( tx.IsCoinBase() != 0 )
409 CAmount value,nResult = 0;
410 for (unsigned int i = 0; i < tx.vin.size(); i++)
412 value = GetOutputFor(tx.vin[i]).nValue;
414 #ifdef KOMODO_ENABLE_INTEREST
415 if ( ASSETCHAINS_SYMBOL[0] == 0 && nHeight >= 60000 )
417 if ( value >= 10*COIN )
419 int64_t interest; int32_t txheight; uint32_t locktime;
420 interest = komodo_accrued_interest(&txheight,&locktime,tx.vin[i].prevout.hash,tx.vin[i].prevout.n,0,value,(int32_t)nHeight);
421 //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);
422 //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);
424 (*interestp) += interest;
429 nResult += tx.GetJoinSplitValueIn();
434 bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const
436 boost::unordered_map<uint256, ZCIncrementalMerkleTree, CCoinsKeyHasher> intermediates;
438 BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit)
440 BOOST_FOREACH(const uint256& nullifier, joinsplit.nullifiers)
442 if (GetNullifier(nullifier)) {
443 // If the nullifier is set, this transaction
449 ZCIncrementalMerkleTree tree;
450 auto it = intermediates.find(joinsplit.anchor);
451 if (it != intermediates.end()) {
453 } else if (!GetAnchorAt(joinsplit.anchor, tree)) {
457 BOOST_FOREACH(const uint256& commitment, joinsplit.commitments)
459 tree.append(commitment);
462 intermediates.insert(std::make_pair(tree.root(), tree));
468 bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
470 if (!tx.IsCoinBase()) {
471 for (unsigned int i = 0; i < tx.vin.size(); i++) {
472 const COutPoint &prevout = tx.vin[i].prevout;
473 const CCoins* coins = AccessCoins(prevout.hash);
474 if (!coins || !coins->IsAvailable(prevout.n)) {
475 fprintf(stderr,"HaveInputs missing input %s/v%d\n",prevout.hash.ToString().c_str(),prevout.n);
483 double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
487 // Joinsplits do not reveal any information about the value or age of a note, so we
488 // cannot apply the priority algorithm used for transparent utxos. Instead, we just
489 // use the maximum priority whenever a transaction contains any JoinSplits.
490 // (Note that coinbase transactions cannot contain JoinSplits.)
491 // FIXME: this logic is partially duplicated between here and CreateNewBlock in miner.cpp.
493 if (tx.vjoinsplit.size() > 0) {
497 double dResult = 0.0;
498 BOOST_FOREACH(const CTxIn& txin, tx.vin)
500 const CCoins* coins = AccessCoins(txin.prevout.hash);
502 if (!coins->IsAvailable(txin.prevout.n)) continue;
503 if (coins->nHeight < nHeight) {
504 dResult += coins->vout[txin.prevout.n].nValue * (nHeight-coins->nHeight);
508 return tx.ComputePriority(dResult);
511 CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_, size_t usage) : cache(cache_), it(it_), cachedCoinUsage(usage) {
512 assert(!cache.hasModifier);
513 cache.hasModifier = true;
516 CCoinsModifier::~CCoinsModifier()
518 assert(cache.hasModifier);
519 cache.hasModifier = false;
520 it->second.coins.Cleanup();
521 cache.cachedCoinsUsage -= cachedCoinUsage; // Subtract the old usage
522 if ((it->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) {
523 cache.cacheCoins.erase(it);
525 // If the coin still exists after the modification, add the new usage
526 cache.cachedCoinsUsage += it->second.coins.DynamicMemoryUsage();