Changeset View
Changeset View
Standalone View
Standalone View
src/coins.cpp
Show First 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | |||||
size_t CCoinsViewCache::DynamicMemoryUsage() const { | size_t CCoinsViewCache::DynamicMemoryUsage() const { | ||||
return memusage::DynamicUsage(cacheCoins) + cachedCoinsUsage; | return memusage::DynamicUsage(cacheCoins) + cachedCoinsUsage; | ||||
} | } | ||||
CCoinsMap::const_iterator | CCoinsMap::const_iterator | ||||
CCoinsViewCache::FetchCoins(const uint256 &txid) const { | CCoinsViewCache::FetchCoins(const uint256 &txid) const { | ||||
CCoinsMap::iterator it = cacheCoins.find(txid); | CCoinsMap::iterator it = cacheCoins.find(txid); | ||||
if (it != cacheCoins.end()) return it; | if (it != cacheCoins.end()) { | ||||
return it; | |||||
} | |||||
CCoins tmp; | CCoins tmp; | ||||
if (!base->GetCoins(txid, tmp)) return cacheCoins.end(); | if (!base->GetCoins(txid, tmp)) { | ||||
return cacheCoins.end(); | |||||
} | |||||
CCoinsMap::iterator ret = | CCoinsMap::iterator ret = | ||||
cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())).first; | cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())).first; | ||||
tmp.swap(ret->second.coins); | tmp.swap(ret->second.coins); | ||||
if (ret->second.coins.IsPruned()) { | if (ret->second.coins.IsPruned()) { | ||||
// The parent only has an empty entry for this txid; we can consider our | // The parent only has an empty entry for this txid; we can consider our | ||||
// version as fresh. | // version as fresh. | ||||
ret->second.flags = CCoinsCacheEntry::FRESH; | ret->second.flags = CCoinsCacheEntry::FRESH; | ||||
} | } | ||||
Show All 28 Lines | CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) { | ||||
} else { | } else { | ||||
cachedCoinUsage = ret.first->second.coins.DynamicMemoryUsage(); | cachedCoinUsage = ret.first->second.coins.DynamicMemoryUsage(); | ||||
} | } | ||||
// Assume that whenever ModifyCoins is called, the entry will be modified. | // Assume that whenever ModifyCoins is called, the entry will be modified. | ||||
ret.first->second.flags |= CCoinsCacheEntry::DIRTY; | ret.first->second.flags |= CCoinsCacheEntry::DIRTY; | ||||
return CCoinsModifier(*this, ret.first, cachedCoinUsage); | return CCoinsModifier(*this, ret.first, cachedCoinUsage); | ||||
} | } | ||||
/* ModifyNewCoins allows for faster coin modification when creating the new | /** | ||||
* ModifyNewCoins allows for faster coin modification when creating the new | |||||
* outputs from a transaction. It assumes that BIP 30 (no duplicate txids) | * 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 | * 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 | * 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 | * 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 | * 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 | * 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 | * 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 | * 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 | * 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, | * 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 | * 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. | * that they will still be properly overwritten when spent. | ||||
*/ | */ | ||||
CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid, | CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid, | ||||
bool coinbase) { | bool coinbase) { | ||||
assert(!hasModifier); | assert(!hasModifier); | ||||
std::pair<CCoinsMap::iterator, bool> ret = | std::pair<CCoinsMap::iterator, bool> ret = | ||||
cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())); | cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())); | ||||
if (!coinbase) { | if (!coinbase) { | ||||
// New coins must not already exist. | // New coins must not already exist. | ||||
if (!ret.first->second.coins.IsPruned()) | if (!ret.first->second.coins.IsPruned()) | ||||
throw std::logic_error("ModifyNewCoins should not find " | throw std::logic_error("ModifyNewCoins should not find " | ||||
"pre-existing coins on a non-coinbase " | "pre-existing coins on a non-coinbase " | ||||
"unless they are pruned!"); | "unless they are pruned!"); | ||||
if (!(ret.first->second.flags & CCoinsCacheEntry::DIRTY)) { | if (!(ret.first->second.flags & CCoinsCacheEntry::DIRTY)) { | ||||
// If the coin is known to be pruned (have no unspent outputs) in | // 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 | // 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 | // coin also must be pruned in the parent view as well, so it is | ||||
// safe | // safe to mark this fresh. | ||||
// to mark this fresh. | |||||
ret.first->second.flags |= CCoinsCacheEntry::FRESH; | ret.first->second.flags |= CCoinsCacheEntry::FRESH; | ||||
} | } | ||||
} | } | ||||
ret.first->second.coins.Clear(); | ret.first->second.coins.Clear(); | ||||
ret.first->second.flags |= CCoinsCacheEntry::DIRTY; | ret.first->second.flags |= CCoinsCacheEntry::DIRTY; | ||||
return CCoinsModifier(*this, ret.first, 0); | return CCoinsModifier(*this, ret.first, 0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 188 Lines • Show Last 20 Lines |