@ -146,56 +146,58 @@ void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
}
}
bool CCoinsViewCache : : BatchWrite ( CCoinsMap & mapCoins , const uint256 & hashBlockIn ) {
bool CCoinsViewCache : : BatchWrite ( CCoinsMap & mapCoins , const uint256 & hashBlockIn ) {
for ( CCoinsMap : : iterator it = mapCoins . begin ( ) ; it ! = mapCoins . end ( ) ; ) {
for ( CCoinsMap : : iterator it = mapCoins . begin ( ) ; it ! = mapCoins . end ( ) ; it = mapCoins . erase ( it ) ) {
if ( it - > second . flags & CCoinsCacheEntry : : DIRTY ) { // Ignore non-dirty entries (optimization).
// Ignore non-dirty entries (optimization).
CCoinsMap : : iterator itUs = cacheCoins . find ( it - > first ) ;
if ( ! ( it - > second . flags & CCoinsCacheEntry : : DIRTY ) ) {
if ( itUs = = cacheCoins . end ( ) ) {
continue ;
// The parent cache does not have an entry, while the child does
}
// We can ignore it if it's both FRESH and pruned in the child
CCoinsMap : : iterator itUs = cacheCoins . find ( it - > first ) ;
if ( ! ( it - > second . flags & CCoinsCacheEntry : : FRESH & & it - > second . coin . IsSpent ( ) ) ) {
if ( itUs = = cacheCoins . end ( ) ) {
// Otherwise we will need to create it in the parent
// The parent cache does not have an entry, while the child does
// and move the data up and mark it as dirty
// We can ignore it if it's both FRESH and pruned in the child
CCoinsCacheEntry & entry = cacheCoins [ it - > first ] ;
if ( ! ( it - > second . flags & CCoinsCacheEntry : : FRESH & & it - > second . coin . IsSpent ( ) ) ) {
entry . coin = std : : move ( it - > second . coin ) ;
// Otherwise we will need to create it in the parent
cachedCoinsUsage + = entry . coin . DynamicMemoryUsage ( ) ;
// and move the data up and mark it as dirty
entry . flags = CCoinsCacheEntry : : DIRTY ;
CCoinsCacheEntry & entry = cacheCoins [ it - > first ] ;
// We can mark it FRESH in the parent if it was FRESH in the child
entry . coin = std : : move ( it - > second . coin ) ;
// Otherwise it might have just been flushed from the parent's cache
cachedCoinsUsage + = entry . coin . DynamicMemoryUsage ( ) ;
// and already exist in the grandparent
entry . flags = CCoinsCacheEntry : : DIRTY ;
if ( it - > second . flags & CCoinsCacheEntry : : FRESH )
// We can mark it FRESH in the parent if it was FRESH in the child
entry . flags | = CCoinsCacheEntry : : FRESH ;
// Otherwise it might have just been flushed from the parent's cache
// and already exist in the grandparent
if ( it - > second . flags & CCoinsCacheEntry : : FRESH ) {
entry . flags | = CCoinsCacheEntry : : FRESH ;
}
}
} else {
}
// Assert that the child cache entry was not marked FRESH if the
} else {
// parent cache entry has unspent outputs. If this ever happens,
// Assert that the child cache entry was not marked FRESH if the
// it means the FRESH flag was misapplied and there is a logic
// parent cache entry has unspent outputs. If this ever happens,
// error in the calling code.
// it means the FRESH flag was misapplied and there is a logic
if ( ( it - > second . flags & CCoinsCacheEntry : : FRESH ) & & ! itUs - > second . coin . IsSpent ( ) )
// error in the calling code.
throw std : : logic_error ( " FRESH flag misapplied to cache entry for base transaction with spendable outputs " ) ;
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 " ) ;
}
// Found the entry in the 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 does not have an entry, and the child is
// modified and being pruned. This means we can just delete
// modified and being pruned. This means we can just delete
// it from the parent.
// it from the parent.
cachedCoinsUsage - = itUs - > second . coin . DynamicMemoryUsage ( ) ;
cachedCoinsUsage - = itUs - > second . coin . DynamicMemoryUsage ( ) ;
cacheCoins . erase ( itUs ) ;
cacheCoins . erase ( itUs ) ;
} else {
} else {
// A normal modification.
// A normal modification.
cachedCoinsUsage - = itUs - > second . coin . DynamicMemoryUsage ( ) ;
cachedCoinsUsage - = itUs - > second . coin . DynamicMemoryUsage ( ) ;
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 is possible the child has a FRESH flag here in
// the event the entry we found in the parent is pruned. But
// the event the entry we found in the parent is pruned. But
// we must not copy that FRESH flag to the parent as that
// we must not copy that FRESH flag to the parent as that
// pruned state likely still needs to be communicated to the
// pruned state likely still needs to be communicated to the
// grandparent.
// grandparent.
}
}
}
}
}
CCoinsMap : : iterator itOld = it + + ;
mapCoins . erase ( itOld ) ;
}
}
hashBlock = hashBlockIn ;
hashBlock = hashBlockIn ;
return true ;
return true ;