@ -71,18 +71,6 @@ CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
CCoinsViewCache : : CCoinsViewCache ( CCoinsView & baseIn , bool fDummy ) : CCoinsViewBacked ( baseIn ) , hasModifier ( false ) , hashBlock ( 0 ) { }
bool CCoinsViewCache : : GetCoins ( const uint256 & txid , CCoins & coins ) const {
if ( cacheCoins . count ( txid ) ) {
coins = cacheCoins [ txid ] ;
return true ;
}
if ( base - > GetCoins ( txid , coins ) ) {
cacheCoins [ txid ] = coins ;
return true ;
}
return false ;
}
CCoinsViewCache : : ~ CCoinsViewCache ( )
{
assert ( ! hasModifier ) ;
@ -93,21 +81,43 @@ CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const
if ( it ! = cacheCoins . end ( ) )
return it ;
CCoins tmp ;
if ( ! base - > GetCoins ( txid , tmp ) )
if ( ! base - > GetCoins ( txid , tmp ) )
return cacheCoins . end ( ) ;
CCoinsMap : : iterator ret = cacheCoins . insert ( it , std : : make_pair ( txid , CCoins ( ) ) ) ;
tmp . swap ( ret - > second ) ;
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 ;
}
bool CCoinsViewCache : : GetCoins ( const uint256 & txid , CCoins & coins ) const {
CCoinsMap : : const_iterator it = FetchCoins ( txid ) ;
if ( it ! = cacheCoins . end ( ) ) {
coins = it - > second . coins ;
return true ;
}
return false ;
}
CCoinsModifier CCoinsViewCache : : ModifyCoins ( const uint256 & txid ) {
assert ( ! hasModifier ) ;
hasModifier = true ;
std : : pair < CCoinsMap : : iterator , bool > ret = cacheCoins . insert ( std : : make_pair ( txid , CCoins ( ) ) ) ;
std : : pair < CCoinsMap : : iterator , bool > ret = cacheCoins . insert ( std : : make_pair ( txid , CCoins CacheEntry ( ) ) ) ;
if ( ret . second ) {
if ( ! base - > GetCoins ( txid , ret . first - > second ) )
ret . first - > second . Clear ( ) ;
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 ) ;
}
@ -116,7 +126,7 @@ const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const {
if ( it = = cacheCoins . end ( ) ) {
return NULL ;
} else {
return & it - > second ;
return & it - > second .coins ;
}
}
@ -126,7 +136,7 @@ bool CCoinsViewCache::HaveCoins(const uint256 &txid) const {
// as we only care about the case where an transaction was replaced entirely
// in a reorganization (which wipes vout entirely, as opposed to spending
// which just cleans individual outputs).
return ( it ! = cacheCoins . end ( ) & & ! it - > second . vout. empty ( ) ) ;
return ( it ! = cacheCoins . end ( ) & & ! it - > second . coins. vout. empty ( ) ) ;
}
uint256 CCoinsViewCache : : GetBestBlock ( ) const {
@ -142,7 +152,32 @@ void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
bool CCoinsViewCache : : BatchWrite ( CCoinsMap & mapCoins , const uint256 & hashBlockIn ) {
assert ( ! hasModifier ) ;
for ( CCoinsMap : : iterator it = mapCoins . begin ( ) ; it ! = mapCoins . end ( ) ; ) {
cacheCoins [ it - > first ] . swap ( it - > second ) ;
if ( it - > second . flags & CCoinsCacheEntry : : DIRTY ) { // Ignore non-dirty entries (optimization).
CCoinsMap : : iterator itUs = cacheCoins . find ( it - > first ) ;
if ( itUs = = cacheCoins . end ( ) ) {
if ( ! it - > second . coins . IsPruned ( ) ) {
// The parent cache does not have an entry, while the child
// cache does have (a non-pruned) one. Move the data up, and
// mark it as fresh (if the grandparent did have it, we
// would have pulled it in at first GetCoins).
assert ( it - > second . flags & CCoinsCacheEntry : : FRESH ) ;
CCoinsCacheEntry & entry = cacheCoins [ it - > first ] ;
entry . coins . swap ( it - > second . coins ) ;
entry . flags = CCoinsCacheEntry : : DIRTY | CCoinsCacheEntry : : FRESH ;
}
} else {
if ( ( itUs - > second . flags & CCoinsCacheEntry : : FRESH ) & & it - > second . coins . IsPruned ( ) ) {
// The grandparent does not have an entry, and the child is
// modified and being pruned. This means we can just delete
// it from the parent.
cacheCoins . erase ( itUs ) ;
} else {
// A normal modification.
itUs - > second . coins . swap ( it - > second . coins ) ;
itUs - > second . flags | = CCoinsCacheEntry : : DIRTY ;
}
}
}
CCoinsMap : : iterator itOld = it + + ;
mapCoins . erase ( itOld ) ;
}
@ -212,8 +247,12 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
CCoinsModifier : : CCoinsModifier ( CCoinsViewCache & cache_ , CCoinsMap : : iterator it_ ) : cache ( cache_ ) , it ( it_ ) { }
CCoinsModifier : : ~ CCoinsModifier ( ) {
CCoinsModifier : : ~ CCoinsModifier ( )
{
assert ( cache . hasModifier ) ;
cache . hasModifier = false ;
it - > second . Cleanup ( ) ;
it - > second . coins . Cleanup ( ) ;
if ( ( it - > second . flags & CCoinsCacheEntry : : FRESH ) & & it - > second . coins . IsPruned ( ) ) {
cache . cacheCoins . erase ( it ) ;
}
}