@ -4,6 +4,7 @@
# include "coins.h"
# include "coins.h"
# include "consensus/consensus.h"
# include "memusage.h"
# include "memusage.h"
# include "random.h"
# include "random.h"
@ -70,7 +71,7 @@ size_t CCoinsViewCache::DynamicMemoryUsage() const {
return memusage : : DynamicUsage ( cacheCoins ) + cachedCoinsUsage ;
return memusage : : DynamicUsage ( cacheCoins ) + cachedCoinsUsage ;
}
}
CCoinsMap : : const_ iterator CCoinsViewCache : : FetchCoins ( const uint256 & txid ) const {
CCoinsMap : : iterator CCoinsViewCache : : FetchCoins ( const uint256 & txid ) const {
CCoinsMap : : iterator it = cacheCoins . find ( txid ) ;
CCoinsMap : : iterator it = cacheCoins . find ( txid ) ;
if ( it ! = cacheCoins . end ( ) )
if ( it ! = cacheCoins . end ( ) )
return it ;
return it ;
@ -153,6 +154,58 @@ CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid, bool coinbas
return CCoinsModifier ( * this , ret . first , 0 ) ;
return CCoinsModifier ( * this , ret . first , 0 ) ;
}
}
void CCoinsViewCache : : AddCoin ( const COutPoint & outpoint , Coin & & coin , bool possible_overwrite ) {
assert ( ! coin . IsPruned ( ) ) ;
if ( coin . out . scriptPubKey . IsUnspendable ( ) ) return ;
CCoinsMap : : iterator it ;
bool inserted ;
std : : tie ( it , inserted ) = cacheCoins . emplace ( std : : piecewise_construct , std : : forward_as_tuple ( outpoint . hash ) , std : : tuple < > ( ) ) ;
bool fresh = false ;
if ( ! inserted ) {
cachedCoinsUsage - = it - > second . coins . DynamicMemoryUsage ( ) ;
}
if ( ! possible_overwrite ) {
if ( it - > second . coins . IsAvailable ( outpoint . n ) ) {
throw std : : logic_error ( " Adding new coin that replaces non-pruned entry " ) ;
}
fresh = it - > second . coins . IsPruned ( ) & & ! ( it - > second . flags & CCoinsCacheEntry : : DIRTY ) ;
}
if ( it - > second . coins . vout . size ( ) < = outpoint . n ) {
it - > second . coins . vout . resize ( outpoint . n + 1 ) ;
}
it - > second . coins . vout [ outpoint . n ] = std : : move ( coin . out ) ;
it - > second . coins . nHeight = coin . nHeight ;
it - > second . coins . fCoinBase = coin . fCoinBase ;
it - > second . flags | = CCoinsCacheEntry : : DIRTY | ( fresh ? CCoinsCacheEntry : : FRESH : 0 ) ;
cachedCoinsUsage + = it - > second . coins . DynamicMemoryUsage ( ) ;
}
void AddCoins ( CCoinsViewCache & cache , const CTransaction & tx , int nHeight ) {
bool fCoinbase = tx . IsCoinBase ( ) ;
const uint256 & txid = tx . GetHash ( ) ;
for ( size_t i = 0 ; i < tx . vout . size ( ) ; + + i ) {
// Pass fCoinbase as the possible_overwrite flag to AddCoin, in order to correctly
// deal with the pre-BIP30 occurrances of duplicate coinbase transactions.
cache . AddCoin ( COutPoint ( txid , i ) , Coin ( tx . vout [ i ] , nHeight , fCoinbase ) , fCoinbase ) ;
}
}
void CCoinsViewCache : : SpendCoin ( const COutPoint & outpoint , Coin * moveout ) {
CCoinsMap : : iterator it = FetchCoins ( outpoint . hash ) ;
if ( it = = cacheCoins . end ( ) ) return ;
cachedCoinsUsage - = it - > second . coins . DynamicMemoryUsage ( ) ;
if ( moveout & & it - > second . coins . IsAvailable ( outpoint . n ) ) {
* moveout = Coin ( it - > second . coins . vout [ outpoint . n ] , it - > second . coins . nHeight , it - > second . coins . fCoinBase ) ;
}
it - > second . coins . Spend ( outpoint . n ) ; // Ignore return value: SpendCoin has no effect if no UTXO found.
if ( it - > second . coins . IsPruned ( ) & & it - > second . flags & CCoinsCacheEntry : : FRESH ) {
cacheCoins . erase ( it ) ;
} else {
cachedCoinsUsage + = it - > second . coins . DynamicMemoryUsage ( ) ;
it - > second . flags | = CCoinsCacheEntry : : DIRTY ;
}
}
const CCoins * CCoinsViewCache : : AccessCoins ( const uint256 & txid ) const {
const CCoins * CCoinsViewCache : : AccessCoins ( const uint256 & txid ) const {
CCoinsMap : : const_iterator it = FetchCoins ( txid ) ;
CCoinsMap : : const_iterator it = FetchCoins ( txid ) ;
if ( it = = cacheCoins . end ( ) ) {
if ( it = = cacheCoins . end ( ) ) {
@ -162,6 +215,18 @@ const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const {
}
}
}
}
static const Coin coinEmpty ;
const Coin CCoinsViewCache : : AccessCoin ( const COutPoint & outpoint ) const {
CCoinsMap : : const_iterator it = FetchCoins ( outpoint . hash ) ;
if ( it = = cacheCoins . end ( ) | | ! it - > second . coins . IsAvailable ( outpoint . n ) ) {
return coinEmpty ;
} else {
return Coin ( it - > second . coins . vout [ outpoint . n ] , it - > second . coins . nHeight , it - > second . coins . fCoinBase ) ;
}
}
bool CCoinsViewCache : : HaveCoins ( const uint256 & txid ) const {
bool CCoinsViewCache : : HaveCoins ( const uint256 & txid ) const {
CCoinsMap : : const_iterator it = FetchCoins ( txid ) ;
CCoinsMap : : const_iterator it = FetchCoins ( txid ) ;
// We're using vtx.empty() instead of IsPruned here for performance reasons,
// We're using vtx.empty() instead of IsPruned here for performance reasons,
@ -171,6 +236,11 @@ bool CCoinsViewCache::HaveCoins(const uint256 &txid) const {
return ( it ! = cacheCoins . end ( ) & & ! it - > second . coins . vout . empty ( ) ) ;
return ( it ! = cacheCoins . end ( ) & & ! it - > second . coins . vout . empty ( ) ) ;
}
}
bool CCoinsViewCache : : HaveCoins ( const COutPoint & outpoint ) const {
CCoinsMap : : const_iterator it = FetchCoins ( outpoint . hash ) ;
return ( it ! = cacheCoins . end ( ) & & it - > second . coins . IsAvailable ( outpoint . n ) ) ;
}
bool CCoinsViewCache : : HaveCoinsInCache ( const uint256 & txid ) const {
bool CCoinsViewCache : : HaveCoinsInCache ( const uint256 & txid ) const {
CCoinsMap : : const_iterator it = cacheCoins . find ( txid ) ;
CCoinsMap : : const_iterator it = cacheCoins . find ( txid ) ;
return it ! = cacheCoins . end ( ) ;
return it ! = cacheCoins . end ( ) ;
@ -318,3 +388,16 @@ CCoinsModifier::~CCoinsModifier()
CCoinsViewCursor : : ~ CCoinsViewCursor ( )
CCoinsViewCursor : : ~ CCoinsViewCursor ( )
{
{
}
}
static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_BASE_SIZE / : : GetSerializeSize ( CTxOut ( ) , SER_NETWORK , PROTOCOL_VERSION ) ; // TODO: merge with similar definition in undo.h.
const Coin AccessByTxid ( const CCoinsViewCache & view , const uint256 & txid )
{
COutPoint iter ( txid , 0 ) ;
while ( iter . n < MAX_OUTPUTS_PER_BLOCK ) {
const Coin & alternate = view . AccessCoin ( iter ) ;
if ( ! alternate . IsPruned ( ) ) return alternate ;
+ + iter . n ;
}
return coinEmpty ;
}