@ -503,20 +503,17 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
if ( ! AreInputsStandard ( mapInputs ) )
if ( ! AreInputsStandard ( mapInputs ) )
return error ( " AcceptToMemoryPool() : nonstandard transaction input " ) ;
return error ( " AcceptToMemoryPool() : nonstandard transaction input " ) ;
// Note: if you modify this code to accept non-standard transactions, then
// you should add code here to check that the transaction does a
// reasonable number of ECDSA signature verifications.
int64 nFees = GetValueIn ( mapInputs ) - GetValueOut ( ) ;
int64 nFees = GetValueIn ( mapInputs ) - GetValueOut ( ) ;
int nSigOps = GetSigOpCount ( mapInputs ) ;
unsigned int nSize = : : GetSerializeSize ( * this , SER_NETWORK ) ;
unsigned int nSize = : : GetSerializeSize ( * this , SER_NETWORK ) ;
// Don't accept it if it can't get into a block
// Don't accept it if it can't get into a block
if ( nFees < GetMinFee ( 1000 , true , GMF_RELAY ) )
if ( nFees < GetMinFee ( 1000 , true , GMF_RELAY ) )
return error ( " AcceptToMemoryPool() : not enough fees " ) ;
return error ( " AcceptToMemoryPool() : not enough fees " ) ;
// Checking ECDSA signatures is a CPU bottleneck, so to avoid denial-of-service
// attacks disallow transactions with more than one SigOp per 65 bytes.
// 65 bytes because that is the minimum size of an ECDSA signature
if ( nSigOps > nSize / 65 | | nSize < 100 )
return error ( " AcceptToMemoryPool() : transaction with out - of - bounds SigOpCount " ) ;
// Continuously rate-limit free transactions
// Continuously rate-limit free transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make other's transactions take longer to confirm.
// be annoying or make other's transactions take longer to confirm.
@ -1013,7 +1010,7 @@ int64 CTransaction::GetValueIn(const MapPrevTx& inputs) const
}
}
int CTransaction : : GetSigOpCount ( const MapPrevTx & inputs ) const
int CTransaction : : GetP2SH SigOpCount ( const MapPrevTx & inputs ) const
{
{
if ( IsCoinBase ( ) )
if ( IsCoinBase ( ) )
return 0 ;
return 0 ;
@ -1021,14 +1018,16 @@ int CTransaction::GetSigOpCount(const MapPrevTx& inputs) const
int nSigOps = 0 ;
int nSigOps = 0 ;
for ( int i = 0 ; i < vin . size ( ) ; i + + )
for ( int i = 0 ; i < vin . size ( ) ; i + + )
{
{
nSigOps + = GetOutputFor ( vin [ i ] , inputs ) . scriptPubKey . GetSigOpCount ( vin [ i ] . scriptSig ) ;
const CTxOut & prevout = GetOutputFor ( vin [ i ] , inputs ) ;
if ( prevout . scriptPubKey . IsPayToScriptHash ( ) )
nSigOps + = prevout . scriptPubKey . GetSigOpCount ( vin [ i ] . scriptSig ) ;
}
}
return nSigOps ;
return nSigOps ;
}
}
bool CTransaction : : ConnectInputs ( MapPrevTx inputs ,
bool CTransaction : : ConnectInputs ( MapPrevTx inputs ,
map < uint256 , CTxIndex > & mapTestPool , const CDiskTxPos & posThisTx ,
map < uint256 , CTxIndex > & mapTestPool , const CDiskTxPos & posThisTx ,
const CBlockIndex * pindexBlock , bool fBlock , bool fMiner )
const CBlockIndex * pindexBlock , bool fBlock , bool fMiner , bool fStrictPayToScriptHash )
{
{
// Take over previous transactions' spent pointers
// Take over previous transactions' spent pointers
// fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain
// fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain
@ -1065,20 +1064,6 @@ bool CTransaction::ConnectInputs(MapPrevTx inputs,
if ( ! MoneyRange ( txPrev . vout [ prevout . n ] . nValue ) | | ! MoneyRange ( nValueIn ) )
if ( ! MoneyRange ( txPrev . vout [ prevout . n ] . nValue ) | | ! MoneyRange ( nValueIn ) )
return DoS ( 100 , error ( " ConnectInputs() : txin values out of range " )) ;
return DoS ( 100 , error ( " ConnectInputs() : txin values out of range " )) ;
bool fStrictPayToScriptHash = true ;
if ( fBlock )
{
// To avoid being on the short end of a block-chain split,
// don't do secondary validation of pay-to-script-hash transactions
// until blocks with timestamps after paytoscripthashtime:
int64 nEvalSwitchTime = GetArg ( " paytoscripthashtime " , 1329264000 ) ; // Feb 15, 2012
fStrictPayToScriptHash = ( pindexBlock - > nTime > = nEvalSwitchTime ) ;
}
// if !fBlock, then always be strict-- don't accept
// invalid-under-new-rules pay-to-script-hash transactions into
// our memory pool (don't relay them, don't include them
// in blocks we mine).
// Skip ECDSA signature verification when connecting blocks (fBlock=true)
// Skip ECDSA signature verification when connecting blocks (fBlock=true)
// before the last blockchain checkpoint. This is safe because block merkle hashes are
// before the last blockchain checkpoint. This is safe because block merkle hashes are
// still computed and checked, and any change will be caught at the next checkpoint.
// still computed and checked, and any change will be caught at the next checkpoint.
@ -1189,6 +1174,12 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
if ( ! CheckBlock ( ) )
if ( ! CheckBlock ( ) )
return false ;
return false ;
// To avoid being on the short end of a block-chain split,
// don't do secondary validation of pay-to-script-hash transactions
// until blocks with timestamps after paytoscripthashtime:
int64 nEvalSwitchTime = GetArg ( " -paytoscripthashtime " , 1329264000 ) ; // Feb 15, 2012
bool fStrictPayToScriptHash = ( pindex - > nTime > = nEvalSwitchTime ) ;
//// issue here: it doesn't know the version
//// issue here: it doesn't know the version
unsigned int nTxPos = pindex - > nBlockPos + : : GetSerializeSize ( CBlock ( ) , SER_DISK ) - 1 + GetSizeOfCompactSize ( vtx . size ( ) ) ;
unsigned int nTxPos = pindex - > nBlockPos + : : GetSerializeSize ( CBlock ( ) , SER_DISK ) - 1 + GetSizeOfCompactSize ( vtx . size ( ) ) ;
@ -1197,6 +1188,10 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
int nSigOps = 0 ;
int nSigOps = 0 ;
BOOST_FOREACH ( CTransaction & tx , vtx )
BOOST_FOREACH ( CTransaction & tx , vtx )
{
{
nSigOps + = tx . GetLegacySigOpCount ( ) ;
if ( nSigOps > MAX_BLOCK_SIGOPS )
return DoS ( 100 , error ( " ConnectBlock() : too many sigops " )) ;
CDiskTxPos posThisTx ( pindex - > nFile , pindex - > nBlockPos , nTxPos ) ;
CDiskTxPos posThisTx ( pindex - > nFile , pindex - > nBlockPos , nTxPos ) ;
nTxPos + = : : GetSerializeSize ( tx , SER_DISK ) ;
nTxPos + = : : GetSerializeSize ( tx , SER_DISK ) ;
@ -1206,17 +1201,19 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
if ( ! tx . FetchInputs ( txdb , mapQueuedChanges , true , false , mapInputs ) )
if ( ! tx . FetchInputs ( txdb , mapQueuedChanges , true , false , mapInputs ) )
return false ;
return false ;
int nTxOps = tx . GetSigOpCount ( mapInputs ) ;
if ( fStrictPayToScriptHash )
nSigOps + = nTxOps ;
{
// Add in sigops done by pay-to-script-hash inputs;
// this is to prevent a "rogue miner" from creating
// an incredibly-expensive-to-validate block.
nSigOps + = tx . GetP2SHSigOpCount ( mapInputs ) ;
if ( nSigOps > MAX_BLOCK_SIGOPS )
if ( nSigOps > MAX_BLOCK_SIGOPS )
return DoS ( 100 , error ( " ConnectBlock() : too many sigops " )) ;
return DoS ( 100 , error ( " ConnectBlock() : too many sigops " )) ;
// There is a different MAX_BLOCK_SIGOPS check in AcceptBlock();
}
// a block must satisfy both to make it into the best-chain
// (AcceptBlock() is always called before ConnectBlock())
nFees + = tx . GetValueIn ( mapInputs ) - tx . GetValueOut ( ) ;
nFees + = tx . GetValueIn ( mapInputs ) - tx . GetValueOut ( ) ;
if ( ! tx . ConnectInputs ( mapInputs , mapQueuedChanges , posThisTx , pindex , true , false ) )
if ( ! tx . ConnectInputs ( mapInputs , mapQueuedChanges , posThisTx , pindex , true , false , fStrictPayToScriptHash ) )
return false ;
return false ;
}
}
@ -1500,9 +1497,6 @@ bool CBlock::CheckBlock() const
if ( ! tx . CheckTransaction ( ) )
if ( ! tx . CheckTransaction ( ) )
return DoS ( tx . nDoS , error ( " CheckBlock() : CheckTransaction failed " )) ;
return DoS ( tx . nDoS , error ( " CheckBlock() : CheckTransaction failed " )) ;
// Pre-pay-to-script-hash (before version 0.6), this is how sigops
// were counted; there is another check in ConnectBlock when
// transaction inputs are fetched to count pay-to-script-hash sigops:
int nSigOps = 0 ;
int nSigOps = 0 ;
BOOST_FOREACH ( const CTransaction & tx , vtx )
BOOST_FOREACH ( const CTransaction & tx , vtx )
{
{
@ -3036,8 +3030,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
map < uint256 , CTxIndex > mapTestPool ;
map < uint256 , CTxIndex > mapTestPool ;
uint64 nBlockSize = 1000 ;
uint64 nBlockSize = 1000 ;
uint64 nBlockTx = 0 ;
uint64 nBlockTx = 0 ;
int nBlockSigOps1 = 100 ; // pre-0.6 count of sigOps
int nBlockSigOps = 100 ;
int nBlockSigOps2 = 100 ; // post-0.6 count of sigOps
while ( ! mapPriority . empty ( ) )
while ( ! mapPriority . empty ( ) )
{
{
// Take highest priority transaction off priority queue
// Take highest priority transaction off priority queue
@ -3051,8 +3044,8 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
continue ;
continue ;
// Legacy limits on sigOps:
// Legacy limits on sigOps:
int nTxSigOps1 = tx . GetLegacySigOpCount ( ) ;
int nTxSigOps = tx . GetLegacySigOpCount ( ) ;
if ( nBlockSigOps1 + nTxSigOps1 > = MAX_BLOCK_SIGOPS )
if ( nBlockSigOps + nTxSigOps > = MAX_BLOCK_SIGOPS )
continue ;
continue ;
// Transaction fee required depends on block size
// Transaction fee required depends on block size
@ -3070,8 +3063,8 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
if ( nFees < nMinFee )
if ( nFees < nMinFee )
continue ;
continue ;
int nTxSigOps2 = tx . GetSigOpCount ( mapInputs ) ;
nTxSigOps + = tx . GetP2SH SigOpCount ( mapInputs ) ;
if ( nBlockSigOps2 + nTxSigOps2 > = MAX_BLOCK_SIGOPS )
if ( nBlockSigOps + nTxSigOps > = MAX_BLOCK_SIGOPS )
continue ;
continue ;
if ( ! tx . ConnectInputs ( mapInputs , mapTestPoolTmp , CDiskTxPos ( 1 , 1 , 1 ) , pindexPrev , false , true ) )
if ( ! tx . ConnectInputs ( mapInputs , mapTestPoolTmp , CDiskTxPos ( 1 , 1 , 1 ) , pindexPrev , false , true ) )
@ -3083,8 +3076,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
pblock - > vtx . push_back ( tx ) ;
pblock - > vtx . push_back ( tx ) ;
nBlockSize + = nTxSize ;
nBlockSize + = nTxSize ;
+ + nBlockTx ;
+ + nBlockTx ;
nBlockSigOps1 + = nTxSigOps1 ;
nBlockSigOps + = nTxSigOps ;
nBlockSigOps2 + = nTxSigOps2 ;
// Add transactions that depend on this one to the priority queue
// Add transactions that depend on this one to the priority queue
uint256 hash = tx . GetHash ( ) ;
uint256 hash = tx . GetHash ( ) ;