@ -1496,12 +1496,13 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// Check against previous transactions
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
if ( ! CheckInputs ( tx , state , view , true , scriptVerifyFlags , true ) ) {
PrecomputedTransactionData txdata ( tx ) ;
if ( ! CheckInputs ( tx , state , view , true , scriptVerifyFlags , true , txdata ) ) {
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
// need to turn both off, and compare against just turning off CLEANSTACK
// need to turn both off, and compare against just turning off CLEANSTACK
// to see if the failure is specifically due to witness validation.
// to see if the failure is specifically due to witness validation.
if ( CheckInputs ( tx , state , view , true , scriptVerifyFlags & ~ ( SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK ) , true ) & &
if ( CheckInputs ( tx , state , view , true , scriptVerifyFlags & ~ ( SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK ) , true , txdata ) & &
! CheckInputs ( tx , state , view , true , scriptVerifyFlags & ~ SCRIPT_VERIFY_CLEANSTACK , true ) ) {
! CheckInputs ( tx , state , view , true , scriptVerifyFlags & ~ SCRIPT_VERIFY_CLEANSTACK , true , txdata ) ) {
// Only the witness is wrong, so the transaction itself may be fine.
// Only the witness is wrong, so the transaction itself may be fine.
state . SetCorruptionPossible ( ) ;
state . SetCorruptionPossible ( ) ;
}
}
@ -1517,7 +1518,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// There is a similar check in CreateNewBlock() to prevent creating
// There is a similar check in CreateNewBlock() to prevent creating
// invalid blocks, however allowing such transactions into the mempool
// invalid blocks, however allowing such transactions into the mempool
// can be exploited as a DoS attack.
// can be exploited as a DoS attack.
if ( ! CheckInputs ( tx , state , view , true , MANDATORY_SCRIPT_VERIFY_FLAGS , true ) )
if ( ! CheckInputs ( tx , state , view , true , MANDATORY_SCRIPT_VERIFY_FLAGS , true , txdata ) )
{
{
return error ( " %s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s " ,
return error ( " %s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s " ,
__func__ , hash . ToString ( ) , FormatStateMessage ( state ) ) ;
__func__ , hash . ToString ( ) , FormatStateMessage ( state ) ) ;
@ -1914,7 +1915,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
bool CScriptCheck : : operator ( ) ( ) {
bool CScriptCheck : : operator ( ) ( ) {
const CScript & scriptSig = ptxTo - > vin [ nIn ] . scriptSig ;
const CScript & scriptSig = ptxTo - > vin [ nIn ] . scriptSig ;
const CScriptWitness * witness = ( nIn < ptxTo - > wit . vtxinwit . size ( ) ) ? & ptxTo - > wit . vtxinwit [ nIn ] . scriptWitness : NULL ;
const CScriptWitness * witness = ( nIn < ptxTo - > wit . vtxinwit . size ( ) ) ? & ptxTo - > wit . vtxinwit [ nIn ] . scriptWitness : NULL ;
if ( ! VerifyScript ( scriptSig , scriptPubKey , witness , nFlags , CachingTransactionSignatureChecker ( ptxTo , nIn , amount , cacheStore ) , & error ) ) {
if ( ! VerifyScript ( scriptSig , scriptPubKey , witness , nFlags , CachingTransactionSignatureChecker ( ptxTo , nIn , amount , cacheStore , * txdata ) , & error ) ) {
return false ;
return false ;
}
}
return true ;
return true ;
@ -1973,7 +1974,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
}
}
} // namespace Consensus
} // namespace Consensus
bool CheckInputs ( const CTransaction & tx , CValidationState & state , const CCoinsViewCache & inputs , bool fScriptChecks , unsigned int flags , bool cacheStore , std : : vector < CScriptCheck > * pvChecks )
bool CheckInputs ( const CTransaction & tx , CValidationState & state , const CCoinsViewCache & inputs , bool fScriptChecks , unsigned int flags , bool cacheStore , PrecomputedTransactionData & txdata , std : : vector < CScriptCheck > * pvChecks )
{
{
if ( ! tx . IsCoinBase ( ) )
if ( ! tx . IsCoinBase ( ) )
{
{
@ -2000,7 +2001,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
assert ( coins ) ;
assert ( coins ) ;
// Verify signature
// Verify signature
CScriptCheck check ( * coins , tx , i , flags , cacheStore ) ;
CScriptCheck check ( * coins , tx , i , flags , cacheStore , & txdata ) ;
if ( pvChecks ) {
if ( pvChecks ) {
pvChecks - > push_back ( CScriptCheck ( ) ) ;
pvChecks - > push_back ( CScriptCheck ( ) ) ;
check . swap ( pvChecks - > back ( ) ) ;
check . swap ( pvChecks - > back ( ) ) ;
@ -2013,7 +2014,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// avoid splitting the network between upgraded and
// avoid splitting the network between upgraded and
// non-upgraded nodes.
// non-upgraded nodes.
CScriptCheck check2 ( * coins , tx , i ,
CScriptCheck check2 ( * coins , tx , i ,
flags & ~ STANDARD_NOT_MANDATORY_VERIFY_FLAGS , cacheStore ) ;
flags & ~ STANDARD_NOT_MANDATORY_VERIFY_FLAGS , cacheStore , & txdata ) ;
if ( check2 ( ) )
if ( check2 ( ) )
return state . Invalid ( false , REJECT_NONSTANDARD , strprintf ( " non-mandatory-script-verify-flag (%s) " , ScriptErrorString ( check . GetScriptError ( ) ) ) ) ;
return state . Invalid ( false , REJECT_NONSTANDARD , strprintf ( " non-mandatory-script-verify-flag (%s) " , ScriptErrorString ( check . GetScriptError ( ) ) ) ) ;
}
}
@ -2409,6 +2410,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
std : : vector < std : : pair < uint256 , CDiskTxPos > > vPos ;
std : : vector < std : : pair < uint256 , CDiskTxPos > > vPos ;
vPos . reserve ( block . vtx . size ( ) ) ;
vPos . reserve ( block . vtx . size ( ) ) ;
blockundo . vtxundo . reserve ( block . vtx . size ( ) - 1 ) ;
blockundo . vtxundo . reserve ( block . vtx . size ( ) - 1 ) ;
std : : vector < PrecomputedTransactionData > txdata ;
txdata . reserve ( block . vtx . size ( ) ) ; // Required so that pointers to individual PrecomputedTransactionData don't get invalidated
for ( unsigned int i = 0 ; i < block . vtx . size ( ) ; i + + )
for ( unsigned int i = 0 ; i < block . vtx . size ( ) ; i + + )
{
{
const CTransaction & tx = block . vtx [ i ] ;
const CTransaction & tx = block . vtx [ i ] ;
@ -2455,13 +2458,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return state . DoS ( 100 , error ( " ConnectBlock(): too many sigops " ) ,
return state . DoS ( 100 , error ( " ConnectBlock(): too many sigops " ) ,
REJECT_INVALID , " bad-blk-sigops " ) ;
REJECT_INVALID , " bad-blk-sigops " ) ;
txdata . emplace_back ( tx ) ;
if ( ! tx . IsCoinBase ( ) )
if ( ! tx . IsCoinBase ( ) )
{
{
nFees + = view . GetValueIn ( tx ) - tx . GetValueOut ( ) ;
nFees + = view . GetValueIn ( tx ) - tx . GetValueOut ( ) ;
std : : vector < CScriptCheck > vChecks ;
std : : vector < CScriptCheck > vChecks ;
bool fCacheResults = fJustCheck ; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
bool fCacheResults = fJustCheck ; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
if ( ! CheckInputs ( tx , state , view , fScriptChecks , flags , fCacheResults , nScriptCheckThreads ? & vChecks : NULL ) )
if ( ! CheckInputs ( tx , state , view , fScriptChecks , flags , fCacheResults , txdata [ i ] , nScriptCheckThreads ? & vChecks : NULL ) )
return error ( " ConnectBlock(): CheckInputs on %s failed with %s " ,
return error ( " ConnectBlock(): CheckInputs on %s failed with %s " ,
tx . GetHash ( ) . ToString ( ) , FormatStateMessage ( state ) ) ;
tx . GetHash ( ) . ToString ( ) , FormatStateMessage ( state ) ) ;
control . Add ( vChecks ) ;
control . Add ( vChecks ) ;