mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-27 11:43:26 -03:00
[docs] Improve commenting in coins.cpp|h
Remove references to 'pruned' coins, which don't exist since the move to per-txout coins db.
This commit is contained in:
parent
646f0ada02
commit
c205979031
2 changed files with 65 additions and 28 deletions
|
@ -77,8 +77,21 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi
|
||||||
}
|
}
|
||||||
if (!possible_overwrite) {
|
if (!possible_overwrite) {
|
||||||
if (!it->second.coin.IsSpent()) {
|
if (!it->second.coin.IsSpent()) {
|
||||||
throw std::logic_error("Adding new coin that replaces non-pruned entry");
|
throw std::logic_error("Attempted to overwrite an unspent coin (when possible_overwrite is false)");
|
||||||
}
|
}
|
||||||
|
// If the coin exists in this cache as a spent coin and is DIRTY, then
|
||||||
|
// its spentness hasn't been flushed to the parent cache. We're
|
||||||
|
// re-adding the coin to this cache now but we can't mark it as FRESH.
|
||||||
|
// If we mark it FRESH and then spend it before the cache is flushed
|
||||||
|
// we would remove it from this cache and would never flush spentness
|
||||||
|
// to the parent cache.
|
||||||
|
//
|
||||||
|
// Re-adding a spent coin can happen in the case of a re-org (the coin
|
||||||
|
// is 'spent' when the block adding it is disconnected and then
|
||||||
|
// re-added when it is also added in a newly connected block).
|
||||||
|
//
|
||||||
|
// If the coin doesn't exist in the current cache, or is spent but not
|
||||||
|
// DIRTY, then it can be marked FRESH.
|
||||||
fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY);
|
fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY);
|
||||||
}
|
}
|
||||||
it->second.coin = std::move(coin);
|
it->second.coin = std::move(coin);
|
||||||
|
@ -152,11 +165,11 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
|
||||||
}
|
}
|
||||||
CCoinsMap::iterator itUs = cacheCoins.find(it->first);
|
CCoinsMap::iterator itUs = cacheCoins.find(it->first);
|
||||||
if (itUs == cacheCoins.end()) {
|
if (itUs == cacheCoins.end()) {
|
||||||
// The parent cache does not have an entry, while the child does
|
// The parent cache does not have an entry, while the child cache does.
|
||||||
// We can ignore it if it's both FRESH and pruned in the child
|
// We can ignore it if it's both spent and FRESH in the child
|
||||||
if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) {
|
if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) {
|
||||||
// Otherwise we will need to create it in the parent
|
// Create the coin in the parent cache, move the data up
|
||||||
// and move the data up and mark it as dirty
|
// and mark it as dirty.
|
||||||
CCoinsCacheEntry& entry = cacheCoins[it->first];
|
CCoinsCacheEntry& entry = cacheCoins[it->first];
|
||||||
entry.coin = std::move(it->second.coin);
|
entry.coin = std::move(it->second.coin);
|
||||||
cachedCoinsUsage += entry.coin.DynamicMemoryUsage();
|
cachedCoinsUsage += entry.coin.DynamicMemoryUsage();
|
||||||
|
@ -169,19 +182,18 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Assert that the child cache entry was not marked FRESH if the
|
// Found the entry in the parent cache
|
||||||
// parent cache entry has unspent outputs. If this ever happens,
|
|
||||||
// it means the FRESH flag was misapplied and there is a logic
|
|
||||||
// error in the calling code.
|
|
||||||
if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent()) {
|
if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent()) {
|
||||||
throw std::logic_error("FRESH flag misapplied to cache entry for base transaction with spendable outputs");
|
// The coin was marked FRESH in the child cache, but the coin
|
||||||
|
// exists in the parent cache. If this ever happens, it means
|
||||||
|
// the FRESH flag was misapplied and there is a logic error in
|
||||||
|
// the calling code.
|
||||||
|
throw std::logic_error("FRESH flag misapplied to coin that exists in parent cache");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Found the entry in the parent cache
|
|
||||||
if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) {
|
if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) {
|
||||||
// The grandparent does not have an entry, and the child is
|
// The grandparent cache does not have an entry, and the coin
|
||||||
// modified and being pruned. This means we can just delete
|
// has been spent. We can just delete it from the parent cache.
|
||||||
// it from the parent.
|
|
||||||
cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
|
cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
|
||||||
cacheCoins.erase(itUs);
|
cacheCoins.erase(itUs);
|
||||||
} else {
|
} else {
|
||||||
|
@ -190,11 +202,10 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
|
||||||
itUs->second.coin = std::move(it->second.coin);
|
itUs->second.coin = std::move(it->second.coin);
|
||||||
cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage();
|
cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage();
|
||||||
itUs->second.flags |= CCoinsCacheEntry::DIRTY;
|
itUs->second.flags |= CCoinsCacheEntry::DIRTY;
|
||||||
// NOTE: It is possible the child has a FRESH flag here in
|
// NOTE: It isn't safe to mark the coin as FRESH in the parent
|
||||||
// the event the entry we found in the parent is pruned. But
|
// cache. If it already existed and was spent in the parent
|
||||||
// we must not copy that FRESH flag to the parent as that
|
// cache then marking it FRESH would prevent that spentness
|
||||||
// pruned state likely still needs to be communicated to the
|
// from being flushed to the grandparent.
|
||||||
// grandparent.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
44
src/coins.h
44
src/coins.h
|
@ -109,19 +109,45 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Coin in one level of the coins database caching hierarchy.
|
||||||
|
*
|
||||||
|
* A coin can either be:
|
||||||
|
* - unspent or spent (in which case the Coin object will be nulled out - see Coin.Clear())
|
||||||
|
* - DIRTY or not DIRTY
|
||||||
|
* - FRESH or not FRESH
|
||||||
|
*
|
||||||
|
* Out of these 2^3 = 8 states, only some combinations are valid:
|
||||||
|
* - unspent, FRESH, DIRTY (e.g. a new coin created in the cache)
|
||||||
|
* - unspent, not FRESH, DIRTY (e.g. a coin changed in the cache during a reorg)
|
||||||
|
* - unspent, not FRESH, not DIRTY (e.g. an unspent coin fetched from the parent cache)
|
||||||
|
* - spent, FRESH, not DIRTY (e.g. a spent coin fetched from the parent cache)
|
||||||
|
* - spent, not FRESH, DIRTY (e.g. a coin is spent and spentness needs to be flushed to the parent)
|
||||||
|
*/
|
||||||
struct CCoinsCacheEntry
|
struct CCoinsCacheEntry
|
||||||
{
|
{
|
||||||
Coin coin; // The actual cached data.
|
Coin coin; // The actual cached data.
|
||||||
unsigned char flags;
|
unsigned char flags;
|
||||||
|
|
||||||
enum Flags {
|
enum Flags {
|
||||||
DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view.
|
/**
|
||||||
FRESH = (1 << 1), // The parent view does not have this entry (or it is pruned).
|
* DIRTY means the CCoinsCacheEntry is potentially different from the
|
||||||
/* Note that FRESH is a performance optimization with which we can
|
* version in the parent cache. Failure to mark a coin as DIRTY when
|
||||||
* erase coins that are fully spent if we know we do not need to
|
* it is potentially different from the parent cache will cause a
|
||||||
* flush the changes to the parent cache. It is always safe to
|
* consensus failure, since the coin's state won't get written to the
|
||||||
* not mark FRESH if that condition is not guaranteed.
|
* parent when the cache is flushed.
|
||||||
*/
|
*/
|
||||||
|
DIRTY = (1 << 0),
|
||||||
|
/**
|
||||||
|
* FRESH means the parent cache does not have this coin or that it is a
|
||||||
|
* spent coin in the parent cache. If a FRESH coin in the cache is
|
||||||
|
* later spent, it can be deleted entirely and doesn't ever need to be
|
||||||
|
* flushed to the parent. This is a performance optimization. Marking a
|
||||||
|
* coin as FRESH when it exists unspent in the parent cache will cause a
|
||||||
|
* consensus failure, since it might not be deleted from the parent
|
||||||
|
* when this cache is flushed.
|
||||||
|
*/
|
||||||
|
FRESH = (1 << 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
CCoinsCacheEntry() : flags(0) {}
|
CCoinsCacheEntry() : flags(0) {}
|
||||||
|
@ -246,7 +272,7 @@ public:
|
||||||
bool HaveCoinInCache(const COutPoint &outpoint) const;
|
bool HaveCoinInCache(const COutPoint &outpoint) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a reference to Coin in the cache, or a pruned one if not found. This is
|
* Return a reference to Coin in the cache, or coinEmpty if not found. This is
|
||||||
* more efficient than GetCoin.
|
* more efficient than GetCoin.
|
||||||
*
|
*
|
||||||
* Generally, do not hold the reference returned for more than a short scope.
|
* Generally, do not hold the reference returned for more than a short scope.
|
||||||
|
@ -258,8 +284,8 @@ public:
|
||||||
const Coin& AccessCoin(const COutPoint &output) const;
|
const Coin& AccessCoin(const COutPoint &output) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a coin. Set potential_overwrite to true if a non-pruned version may
|
* Add a coin. Set potential_overwrite to true if an unspent version may
|
||||||
* already exist.
|
* already exist in the cache.
|
||||||
*/
|
*/
|
||||||
void AddCoin(const COutPoint& outpoint, Coin&& coin, bool potential_overwrite);
|
void AddCoin(const COutPoint& outpoint, Coin&& coin, bool potential_overwrite);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue