@ -170,6 +170,7 @@ CBlockIndex *CCoinsView::GetBestBlock() { return NULL; }
bool CCoinsView : : SetBestBlock ( CBlockIndex * pindex ) { return false ; }
bool CCoinsView : : SetBestBlock ( CBlockIndex * pindex ) { return false ; }
bool CCoinsView : : BatchWrite ( const std : : map < uint256 , CCoins > & mapCoins , CBlockIndex * pindex ) { return false ; }
bool CCoinsView : : BatchWrite ( const std : : map < uint256 , CCoins > & mapCoins , CBlockIndex * pindex ) { return false ; }
CCoinsViewBacked : : CCoinsViewBacked ( CCoinsView & viewIn ) : base ( & viewIn ) { }
CCoinsViewBacked : : CCoinsViewBacked ( CCoinsView & viewIn ) : base ( & viewIn ) { }
bool CCoinsViewBacked : : GetCoins ( uint256 txid , CCoins & coins ) { return base - > GetCoins ( txid , coins ) ; }
bool CCoinsViewBacked : : GetCoins ( uint256 txid , CCoins & coins ) { return base - > GetCoins ( txid , coins ) ; }
bool CCoinsViewBacked : : SetCoins ( uint256 txid , const CCoins & coins ) { return base - > SetCoins ( txid , coins ) ; }
bool CCoinsViewBacked : : SetCoins ( uint256 txid , const CCoins & coins ) { return base - > SetCoins ( txid , coins ) ; }
@ -193,13 +194,30 @@ bool CCoinsViewCache::GetCoins(uint256 txid, CCoins &coins) {
return false ;
return false ;
}
}
std : : map < uint256 , CCoins > : : iterator CCoinsViewCache : : FetchCoins ( uint256 txid ) {
std : : map < uint256 , CCoins > : : iterator it = cacheCoins . find ( txid ) ;
if ( it ! = cacheCoins . end ( ) )
return it ;
CCoins tmp ;
if ( ! base - > GetCoins ( txid , tmp ) )
return it ;
std : : pair < std : : map < uint256 , CCoins > : : iterator , bool > ret = cacheCoins . insert ( std : : make_pair ( txid , tmp ) ) ;
return ret . first ;
}
CCoins & CCoinsViewCache : : GetCoins ( uint256 txid ) {
std : : map < uint256 , CCoins > : : iterator it = FetchCoins ( txid ) ;
assert ( it ! = cacheCoins . end ( ) ) ;
return it - > second ;
}
bool CCoinsViewCache : : SetCoins ( uint256 txid , const CCoins & coins ) {
bool CCoinsViewCache : : SetCoins ( uint256 txid , const CCoins & coins ) {
cacheCoins [ txid ] = coins ;
cacheCoins [ txid ] = coins ;
return true ;
return true ;
}
}
bool CCoinsViewCache : : HaveCoins ( uint256 txid ) {
bool CCoinsViewCache : : HaveCoins ( uint256 txid ) {
return cacheCoins . count ( txid ) | | base - > HaveCoins ( txid ) ;
return FetchCoins ( txid ) ! = cacheCoins . end ( ) ;
}
}
CBlockIndex * CCoinsViewCache : : GetBestBlock ( ) {
CBlockIndex * CCoinsViewCache : : GetBestBlock ( ) {
@ -369,7 +387,7 @@ bool CTransaction::IsStandard() const
// expensive-to-check-upon-redemption script like:
// expensive-to-check-upon-redemption script like:
// DUP CHECKSIG DROP ... repeated 100 times... OP_1
// DUP CHECKSIG DROP ... repeated 100 times... OP_1
//
//
bool CTransaction : : AreInputsStandard ( CCoinsView & mapInputs ) const
bool CTransaction : : AreInputsStandard ( CCoinsViewCache & mapInputs ) const
{
{
if ( IsCoinBase ( ) )
if ( IsCoinBase ( ) )
return true ; // Coinbases don't use vin normally
return true ; // Coinbases don't use vin normally
@ -683,6 +701,9 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
}
}
}
}
if ( ! tx . HaveInputs ( view ) )
return error ( " CTxMemPool::accept() : inputs already spent " ) ;
// Check for non-standard pay-to-script-hash in inputs
// Check for non-standard pay-to-script-hash in inputs
if ( ! tx . AreInputsStandard ( view ) & & ! fTestNet )
if ( ! tx . AreInputsStandard ( view ) & & ! fTestNet )
return error ( " CTxMemPool::accept() : nonstandard transaction input " ) ;
return error ( " CTxMemPool::accept() : nonstandard transaction input " ) ;
@ -1154,23 +1175,14 @@ void CBlock::UpdateTime(const CBlockIndex* pindexPrev)
CTxOut CTransaction : : GetOutputFor ( const CTxIn & input , CCoinsView & view )
const CTxOut & CTransaction : : GetOutputFor ( const CTxIn & input , CCoinsViewCache & view )
{
{
CCoins coins ;
const CCoins & coins = view . GetCoins ( input . prevout . hash ) ;
if ( ! view . GetCoins ( input . prevout . hash , coins ) )
assert ( coins . IsAvailable ( input . prevout . n ) ) ;
throw std : : runtime_error ( " CTransaction::GetOutputFor() : prevout.hash not found " ) ;
return coins . vout [ input . prevout . n ] ;
if ( input . prevout . n > = coins . vout . size ( ) )
throw std : : runtime_error ( " CTransaction::GetOutputFor() : prevout.n out of range or already spent " ) ;
const CTxOut & out = coins . vout [ input . prevout . n ] ;
if ( out . IsNull ( ) )
throw std : : runtime_error ( " CTransaction::GetOutputFor() : already spent " ) ;
return out ;
}
}
int64 CTransaction : : GetValueIn ( CCoinsView & inputs ) const
int64 CTransaction : : GetValueIn ( CCoinsViewCache & inputs ) const
{
{
if ( IsCoinBase ( ) )
if ( IsCoinBase ( ) )
return 0 ;
return 0 ;
@ -1182,7 +1194,7 @@ int64 CTransaction::GetValueIn(CCoinsView& inputs) const
return nResult ;
return nResult ;
}
}
unsigned int CTransaction : : GetP2SHSigOpCount ( CCoinsView & inputs ) const
unsigned int CTransaction : : GetP2SHSigOpCount ( CCoinsViewCache & inputs ) const
{
{
if ( IsCoinBase ( ) )
if ( IsCoinBase ( ) )
return 0 ;
return 0 ;
@ -1190,27 +1202,23 @@ unsigned int CTransaction::GetP2SHSigOpCount(CCoinsView& inputs) const
unsigned int nSigOps = 0 ;
unsigned int nSigOps = 0 ;
for ( unsigned int i = 0 ; i < vin . size ( ) ; i + + )
for ( unsigned int i = 0 ; i < vin . size ( ) ; i + + )
{
{
CTxOut prevout = GetOutputFor ( vin [ i ] , inputs ) ;
const CTxOut & prevout = GetOutputFor ( vin [ i ] , inputs ) ;
if ( prevout . scriptPubKey . IsPayToScriptHash ( ) )
if ( prevout . scriptPubKey . IsPayToScriptHash ( ) )
nSigOps + = prevout . scriptPubKey . GetSigOpCount ( vin [ i ] . scriptSig ) ;
nSigOps + = prevout . scriptPubKey . GetSigOpCount ( vin [ i ] . scriptSig ) ;
}
}
return nSigOps ;
return nSigOps ;
}
}
bool CTransaction : : UpdateCoins ( CCoinsView & inputs , CTxUndo & txundo , int nHeight , const uint256 & txhash ) const
bool CTransaction : : UpdateCoins ( CCoinsViewCache & inputs , CTxUndo & txundo , int nHeight , const uint256 & txhash ) const
{
{
// mark inputs spent
// mark inputs spent
if ( ! IsCoinBase ( ) ) {
if ( ! IsCoinBase ( ) ) {
BOOST_FOREACH ( const CTxIn & txin , vin ) {
BOOST_FOREACH ( const CTxIn & txin , vin ) {
CCoins coins ;
CCoins & coins = inputs . GetCoins ( txin . prevout . hash ) ;
if ( ! inputs . GetCoins ( txin . prevout . hash , coins ) )
return error ( " UpdateCoins() : cannot find prevtx " ) ;
CTxInUndo undo ;
CTxInUndo undo ;
if ( ! coins . Spend ( txin . prevout , undo ) )
if ( ! coins . Spend ( txin . prevout , undo ) )
return error ( " UpdateCoins() : cannot spend input " ) ;
return error ( " UpdateCoins() : cannot spend input " ) ;
txundo . vprevout . push_back ( undo ) ;
txundo . vprevout . push_back ( undo ) ;
if ( ! inputs . SetCoins ( txin . prevout . hash , coins ) )
return error ( " UpdateCoins() : cannot update input " ) ;
}
}
}
}
@ -1221,7 +1229,7 @@ bool CTransaction::UpdateCoins(CCoinsView &inputs, CTxUndo &txundo, int nHeight,
return true ;
return true ;
}
}
bool CTransaction : : HaveInputs ( CCoinsView & inputs ) const
bool CTransaction : : HaveInputs ( CCoinsViewCache & inputs ) const
{
{
if ( ! IsCoinBase ( ) ) {
if ( ! IsCoinBase ( ) ) {
// first check whether information about the prevout hash is available
// first check whether information about the prevout hash is available
@ -1234,8 +1242,7 @@ bool CTransaction::HaveInputs(CCoinsView &inputs) const
// then check whether the actual outputs are available
// then check whether the actual outputs are available
for ( unsigned int i = 0 ; i < vin . size ( ) ; i + + ) {
for ( unsigned int i = 0 ; i < vin . size ( ) ; i + + ) {
const COutPoint & prevout = vin [ i ] . prevout ;
const COutPoint & prevout = vin [ i ] . prevout ;
CCoins coins ;
const CCoins & coins = inputs . GetCoins ( prevout . hash ) ;
inputs . GetCoins ( prevout . hash , coins ) ;
if ( ! coins . IsAvailable ( prevout . n ) )
if ( ! coins . IsAvailable ( prevout . n ) )
return false ;
return false ;
}
}
@ -1243,28 +1250,25 @@ bool CTransaction::HaveInputs(CCoinsView &inputs) const
return true ;
return true ;
}
}
bool CTransaction : : CheckInputs ( CCoinsView & inputs , enum CheckSig_mode csmode , bool fStrictPayToScriptHash , bool fStrictEncodings ) const
bool CTransaction : : CheckInputs ( CCoinsViewCache & inputs , enum CheckSig_mode csmode , bool fStrictPayToScriptHash , bool fStrictEncodings ) const
{
{
if ( ! IsCoinBase ( ) )
if ( ! IsCoinBase ( ) )
{
{
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
// for an attacker to attempt to split the network.
if ( ! HaveInputs ( inputs ) )
return error ( " CheckInputs() : % s inputs unavailable " , GetHash().ToString().substr(0,10).c_str()) ;
CBlockIndex * pindexBlock = inputs . GetBestBlock ( ) ;
int64 nValueIn = 0 ;
int64 nValueIn = 0 ;
int64 nFees = 0 ;
int64 nFees = 0 ;
for ( unsigned int i = 0 ; i < vin . size ( ) ; i + + )
for ( unsigned int i = 0 ; i < vin . size ( ) ; i + + )
{
{
const COutPoint & prevout = vin [ i ] . prevout ;
const COutPoint & prevout = vin [ i ] . prevout ;
CCoins coins ;
const CCoins & coins = inputs . GetCoins ( prevout . hash ) ;
if ( ! inputs . GetCoins ( prevout . hash , coins ) )
return error ( " CheckInputs() : cannot find prevout tx " ) ;
// Check for conflicts (double-spend)
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
// for an attacker to attempt to split the network.
if ( ! coins . IsAvailable ( prevout . n ) )
return error ( " CheckInputs() : % s prev tx already used " , GetHash().ToString().substr(0,10).c_str()) ;
// If prev is coinbase, check that it's matured
// If prev is coinbase, check that it's matured
if ( coins . IsCoinBase ( ) ) {
if ( coins . IsCoinBase ( ) ) {
CBlockIndex * pindexBlock = inputs . GetBestBlock ( ) ;
if ( pindexBlock - > nHeight - coins . nHeight < COINBASE_MATURITY )
if ( pindexBlock - > nHeight - coins . nHeight < COINBASE_MATURITY )
return error ( " CheckInputs() : tried to spend coinbase at depth % d " , pindexBlock->nHeight - coins.nHeight) ;
return error ( " CheckInputs() : tried to spend coinbase at depth % d " , pindexBlock->nHeight - coins.nHeight) ;
}
}
@ -1298,8 +1302,7 @@ bool CTransaction::CheckInputs(CCoinsView &inputs, enum CheckSig_mode csmode, bo
( csmode = = CS_AFTER_CHECKPOINT & & inputs . GetBestBlock ( ) - > nHeight > = Checkpoints : : GetTotalBlocksEstimate ( ) ) ) {
( csmode = = CS_AFTER_CHECKPOINT & & inputs . GetBestBlock ( ) - > nHeight > = Checkpoints : : GetTotalBlocksEstimate ( ) ) ) {
for ( unsigned int i = 0 ; i < vin . size ( ) ; i + + ) {
for ( unsigned int i = 0 ; i < vin . size ( ) ; i + + ) {
const COutPoint & prevout = vin [ i ] . prevout ;
const COutPoint & prevout = vin [ i ] . prevout ;
CCoins coins ;
const CCoins & coins = inputs . GetCoins ( prevout . hash ) ;
inputs . GetCoins ( prevout . hash , coins ) ;
// Verify signature
// Verify signature
if ( ! VerifySignature ( coins , * this , i , fStrictPayToScriptHash , fStrictEncodings , 0 ) ) {
if ( ! VerifySignature ( coins , * this , i , fStrictPayToScriptHash , fStrictEncodings , 0 ) ) {
@ -1367,7 +1370,7 @@ bool CTransaction::ClientCheckInputs() const
bool CBlock : : DisconnectBlock ( CBlockIndex * pindex , CCoinsView & view )
bool CBlock : : DisconnectBlock ( CBlockIndex * pindex , CCoinsViewCache & view )
{
{
assert ( pindex = = view . GetBestBlock ( ) ) ;
assert ( pindex = = view . GetBestBlock ( ) ) ;
@ -1391,17 +1394,16 @@ bool CBlock::DisconnectBlock(CBlockIndex *pindex, CCoinsView &view)
uint256 hash = tx . GetHash ( ) ;
uint256 hash = tx . GetHash ( ) ;
// check that all outputs are available
// check that all outputs are available
CCoins outs ;
if ( ! view . HaveCoins ( hash ) )
if ( ! view . GetCoins ( hash , outs ) )
return error ( " DisconnectBlock() : outputs still spent ? database corrupted " ) ;
return error ( " DisconnectBlock() : outputs still spent ? database corrupted " ) ;
CCoins & outs = view . GetCoins ( hash ) ;
CCoins outsBlock = CCoins ( tx , pindex - > nHeight ) ;
CCoins outsBlock = CCoins ( tx , pindex - > nHeight ) ;
if ( outs ! = outsBlock )
if ( outs ! = outsBlock )
return error ( " DisconnectBlock() : added transaction mismatch ? database corrupted " ) ;
return error ( " DisconnectBlock() : added transaction mismatch ? database corrupted " ) ;
// remove outputs
// remove outputs
if ( ! view . SetCoins ( hash , CCoins ( ) ) )
outs = CCoins ( ) ;
return error ( " DisconnectBlock() : cannot delete coin outputs " ) ;
// restore inputs
// restore inputs
if ( i > 0 ) { // not coinbases
if ( i > 0 ) { // not coinbases
@ -1441,7 +1443,7 @@ bool CBlock::DisconnectBlock(CBlockIndex *pindex, CCoinsView &view)
bool FindUndoPos ( CChainDB & chaindb , int nFile , CDiskBlockPos & pos , unsigned int nAddSize ) ;
bool FindUndoPos ( CChainDB & chaindb , int nFile , CDiskBlockPos & pos , unsigned int nAddSize ) ;
bool CBlock : : ConnectBlock ( CBlockIndex * pindex , CCoinsView & view , bool fJustCheck )
bool CBlock : : ConnectBlock ( CBlockIndex * pindex , CCoinsViewCache & view , bool fJustCheck )
{
{
// Check it again in case a previous version let a bad block in
// Check it again in case a previous version let a bad block in
if ( ! CheckBlock ( ! fJustCheck , ! fJustCheck ) )
if ( ! CheckBlock ( ! fJustCheck , ! fJustCheck ) )
@ -1467,8 +1469,7 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsView &view, bool fJustCheck
if ( fEnforceBIP30 ) {
if ( fEnforceBIP30 ) {
for ( unsigned int i = 0 ; i < vtx . size ( ) ; i + + ) {
for ( unsigned int i = 0 ; i < vtx . size ( ) ; i + + ) {
uint256 hash = GetTxHash ( i ) ;
uint256 hash = GetTxHash ( i ) ;
CCoins coins ;
if ( view . HaveCoins ( hash ) & & ! view . GetCoins ( hash ) . IsPruned ( ) )
if ( view . GetCoins ( hash , coins ) & & ! coins . IsPruned ( ) )
return error ( " ConnectBlock() : tried to overwrite transaction " ) ;
return error ( " ConnectBlock() : tried to overwrite transaction " ) ;
}
}
}
}
@ -3719,7 +3720,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
std : : make_heap ( vecPriority . begin ( ) , vecPriority . end ( ) , comparer ) ;
std : : make_heap ( vecPriority . begin ( ) , vecPriority . end ( ) , comparer ) ;
}
}
if ( ! tx . Check Inputs( viewTemp , CS_ALWAYS , true , false ) )
if ( ! tx . Have Inputs( viewTemp ) )
continue ;
continue ;
int64 nTxFees = tx . GetValueIn ( viewTemp ) - tx . GetValueOut ( ) ;
int64 nTxFees = tx . GetValueIn ( viewTemp ) - tx . GetValueOut ( ) ;
@ -3728,6 +3729,9 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
if ( nBlockSigOps + nTxSigOps > = MAX_BLOCK_SIGOPS )
if ( nBlockSigOps + nTxSigOps > = MAX_BLOCK_SIGOPS )
continue ;
continue ;
if ( ! tx . CheckInputs ( viewTemp , CS_ALWAYS , true , false ) )
continue ;
CTxUndo txundo ;
CTxUndo txundo ;
uint256 hash = tx . GetHash ( ) ;
uint256 hash = tx . GetHash ( ) ;
if ( ! tx . UpdateCoins ( viewTemp , txundo , pindexPrev - > nHeight + 1 , hash ) )
if ( ! tx . UpdateCoins ( viewTemp , txundo , pindexPrev - > nHeight + 1 , hash ) )