CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid) { assert(!hasModifier); std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())); ret.first->second.coins.Clear(); 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())); 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 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); }
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); }