CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const { CCoinsMap::iterator it = cacheCoins.find(txid); if (it != cacheCoins.end()) return it; CCoins tmp; if (!base->GetCoins(txid, tmp)) return cacheCoins.end(); CCoinsMap::iterator ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())).first; tmp.swap(ret->second.coins); if (ret->second.coins.IsPruned()) { // The parent only has an empty entry for this txid; we can consider our // version as fresh. ret->second.flags = CCoinsCacheEntry::FRESH; } return ret; }
CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256& txid) const { CCoinsMap::iterator it = cacheCoins.find(txid); if (it != cacheCoins.end()) return it; CCoins tmp; if (!base->GetCoins(txid, tmp)) return cacheCoins.end(); CCoinsMap::iterator ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())).first; tmp.swap(ret->second.coins); if (ret->second.coins.IsPruned()) { ret->second.flags = CCoinsCacheEntry::FRESH; } cachedCoinsUsage += ret->second.coins.DynamicMemoryUsage(); return ret; }
CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) { assert(!hasModifier); std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())); if (ret.second) { if (!base->GetCoins(txid, ret.first->second.coins)) { // The parent view does not have this entry; mark it as fresh. ret.first->second.coins.Clear(); ret.first->second.flags = CCoinsCacheEntry::FRESH; } else if (ret.first->second.coins.IsPruned()) { // The parent view only has a pruned entry for this; mark it as fresh. ret.first->second.flags = CCoinsCacheEntry::FRESH; } } // Assume that whenever ModifyCoins is called, the entry will be modified. ret.first->second.flags |= CCoinsCacheEntry::DIRTY; return CCoinsModifier(*this, ret.first); }
// ModifyNewCoins has to know whether the new outputs its creating are for a // coinbase or not. If they are for a coinbase, it can not mark them as fresh. // This is to ensure that the historical duplicate coinbases before BIP30 was // in effect will still be properly overwritten when spent. CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid, bool coinbase) { assert(!hasModifier); std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())); ret.first->second.coins.Clear(); if (!coinbase) { ret.first->second.flags = CCoinsCacheEntry::FRESH; } ret.first->second.flags |= CCoinsCacheEntry::DIRTY; return CCoinsModifier(*this, ret.first, 0); }
CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256& txid) { assert(!hasModifier); std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())); size_t cachedCoinUsage = 0; if (ret.second) { if (!base->GetCoins(txid, ret.first->second.coins)) { ret.first->second.coins.Clear(); ret.first->second.flags = CCoinsCacheEntry::FRESH; } else if (ret.first->second.coins.IsPruned()) { ret.first->second.flags = CCoinsCacheEntry::FRESH; } } else { cachedCoinUsage = ret.first->second.coins.DynamicMemoryUsage(); } ret.first->second.flags |= CCoinsCacheEntry::DIRTY; return CCoinsModifier(*this, ret.first, cachedCoinUsage); }
CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false), cachedCoinsUsage(0) { // emercoin: insert special randpay utxo that can be spent unlimited number of times // you can only spent 0 emc from it std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(randpaytx, CCoinsCacheEntry())); if (!ret.second) throw std::logic_error("Failed to insert randpay utxo!"); CCoins& coins = ret.first->second.coins; coins.fCoinBase = false; coins.fCoinStake = false; coins.nHeight = 0; coins.nVersion = 1; coins.nTime = 0; CTxOut txout = CTxOut(); txout.nValue = 0; coins.vout.push_back(txout); ret.first->second.flags = CCoinsCacheEntry::DIRTY; // set DIRTY/FRESH flags }
/* ModifyNewCoins allows for faster coin modification when creating the new * outputs from a transaction. It assumes that BIP 30 (no duplicate txids) * applies and has already been tested for (or the test is not required due to * BIP 34, height in coinbase). If we can assume BIP 30 then we know that any * non-coinbase transaction we are adding to the UTXO must not already exist in * the utxo unless it is fully spent. Thus we can check only if it exists DIRTY * at the current level of the cache, in which case it is not safe to mark it * FRESH (b/c then its spentness still needs to flushed). If it's not dirty and * doesn't exist or is pruned in the current cache, we know it either doesn't * exist or is pruned in parent caches, which is the definition of FRESH. The * exception to this is the two historical violations of BIP 30 in the chain, * both of which were coinbases. We do not mark these fresh so we we can ensure * that they will still be properly overwritten when spent. */ CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid, bool coinbase) { assert(!hasModifier); std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())); if (!coinbase) { // New coins must not already exist. if (!ret.first->second.coins.IsPruned()) throw std::logic_error("ModifyNewCoins should not find pre-existing coins on a non-coinbase unless they are pruned!"); if (!(ret.first->second.flags & CCoinsCacheEntry::DIRTY)) { // If the coin is known to be pruned (have no unspent outputs) in // the current view and the cache entry is not dirty, we know the // coin also must be pruned in the parent view as well, so it is safe // to mark this fresh. ret.first->second.flags |= CCoinsCacheEntry::FRESH; } } ret.first->second.coins.Clear(); ret.first->second.flags |= CCoinsCacheEntry::DIRTY; return CCoinsModifier(*this, ret.first, 0); }