@ -14,6 +14,7 @@
@@ -14,6 +14,7 @@
# include "consensus/merkle.h"
# include "consensus/tx_verify.h"
# include "consensus/validation.h"
# include "cuckoocache.h"
# include "fs.h"
# include "hash.h"
# include "init.h"
@ -189,7 +190,7 @@ enum FlushStateMode {
@@ -189,7 +190,7 @@ enum FlushStateMode {
static bool FlushStateToDisk ( const CChainParams & chainParams , CValidationState & state , FlushStateMode mode , int nManualPruneHeight = 0 ) ;
static void FindFilesToPruneManual ( std : : set < int > & setFilesToPrune , int nManualPruneHeight ) ;
static void FindFilesToPrune ( std : : set < int > & setFilesToPrune , uint64_t nPruneAfterHeight ) ;
static bool CheckInputs ( const CTransaction & tx , CValidationState & state , const CCoinsViewCache & inputs , bool fScriptChecks , unsigned int flags , bool cacheStore , PrecomputedTransactionData & txdata , std : : vector < CScriptCheck > * pvChecks = NULL ) ;
static bool CheckInputs ( const CTransaction & tx , CValidationState & state , const CCoinsViewCache & inputs , bool fScriptChecks , unsigned int flags , bool cacheSigStore , bool cacheFullScriptS tore , PrecomputedTransactionData & txdata , std : : vector < CScriptCheck > * pvChecks = nullptr ) ;
static FILE * OpenUndoFile ( const CDiskBlockPos & pos , bool fReadOnly = false ) ;
bool CheckFinalTx ( const CTransaction & tx , int flags )
@ -752,29 +753,36 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
@@ -752,29 +753,36 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
PrecomputedTransactionData txdata ( tx ) ;
if ( ! CheckInputs ( tx , state , view , true , scriptVerifyFlags , true , txdata ) ) {
if ( ! CheckInputs ( tx , state , view , true , scriptVerifyFlags , true , false , txdata ) ) {
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
// need to turn both off, and compare against just turning off CLEANSTACK
// to see if the failure is specifically due to witness validation.
CValidationState stateDummy ; // Want reported failures to be from first CheckInputs
if ( ! tx . HasWitness ( ) & & CheckInputs ( tx , stateDummy , view , true , scriptVerifyFlags & ~ ( SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK ) , true , txdata ) & &
! CheckInputs ( tx , stateDummy , view , true , scriptVerifyFlags & ~ SCRIPT_VERIFY_CLEANSTACK , true , txdata ) ) {
if ( ! tx . HasWitness ( ) & & CheckInputs ( tx , stateDummy , view , true , scriptVerifyFlags & ~ ( SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK ) , true , false , txdata ) & &
! CheckInputs ( tx , stateDummy , view , true , scriptVerifyFlags & ~ SCRIPT_VERIFY_CLEANSTACK , true , false , txdata ) ) {
// Only the witness is missing, so the transaction itself may be fine.
state . SetCorruptionPossible ( ) ;
}
return false ; // state filled in by CheckInputs
}
// Check again against just the consensus-critical mandatory script
// verification flags, in case of bugs in the standard flags that cause
// Check again against the current block tip's script verification
// flags to cache our script execution flags. This is, of course,
// useless if the next block has different script flags from the
// previous one, but because the cache tracks script flags for us it
// will auto-invalidate and we'll just have a few blocks of extra
// misses on soft-fork activation.
//
// This is also useful in case of bugs in the standard flags that cause
// transactions to pass as valid when they're actually invalid. For
// instance the STRICTENC flag was incorrectly allowing certain
// CHECKSIG NOT scripts to pass, even though they were invalid.
//
// There is a similar check in CreateNewBlock() to prevent creating
// invalid blocks, however allowing such transactions into the mempool
// can be exploited as a DoS attack.
if ( ! CheckInputs ( tx , state , view , true , MANDATORY_SCRIPT_VERIFY_FLAGS , true , txdata ) )
// invalid blocks (using TestBlockValidity), however allowing such
// transactions into the mempool can be exploited as a DoS attack.
unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags ( chainActive . Tip ( ) , Params ( ) . GetConsensus ( ) ) ;
if ( ! CheckInputs ( tx , state , view , true , currentBlockScriptVerifyFlags , true , true , txdata ) )
{
return error ( " %s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s " ,
__func__ , hash . ToString ( ) , FormatStateMessage ( state ) ) ;
@ -1152,12 +1160,25 @@ int GetSpendHeight(const CCoinsViewCache& inputs)
@@ -1152,12 +1160,25 @@ int GetSpendHeight(const CCoinsViewCache& inputs)
return pindexPrev - > nHeight + 1 ;
}
static CuckooCache : : cache < uint256 , SignatureCacheHasher > scriptExecutionCache ;
static uint256 scriptExecutionCacheNonce ( GetRandHash ( ) ) ;
void InitScriptExecutionCache ( ) {
// nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero,
// setup_bytes creates the minimum possible cache (2 elements).
size_t nMaxCacheSize = std : : min ( std : : max ( ( int64_t ) 0 , GetArg ( " -maxsigcachesize " , DEFAULT_MAX_SIG_CACHE_SIZE ) / 2 ) , MAX_MAX_SIG_CACHE_SIZE ) * ( ( size_t ) 1 < < 20 ) ;
size_t nElems = scriptExecutionCache . setup_bytes ( nMaxCacheSize ) ;
LogPrintf ( " Using %zu MiB out of %zu requested for script execution cache, able to store %zu elements \n " ,
( nElems * sizeof ( uint256 ) ) > > 20 , nMaxCacheSize > > 20 , nElems ) ;
}
/**
* Check whether all inputs of this transaction are valid ( no double spends , scripts & sigs , amounts )
* This does not modify the UTXO set . If pvChecks is not NULL , script checks are pushed onto it
* instead of being performed inline .
*/
static bool CheckInputs ( const CTransaction & tx , CValidationState & state , const CCoinsViewCache & inputs , bool fScriptChecks , unsigned int flags , bool cacheStore , PrecomputedTransactionData & txdata , std : : vector < CScriptCheck > * pvChecks )
static bool CheckInputs ( const CTransaction & tx , CValidationState & state , const CCoinsViewCache & inputs , bool fScriptChecks , unsigned int flags , bool cacheSigStore , bool cacheFullScriptS tore , PrecomputedTransactionData & txdata , std : : vector < CScriptCheck > * pvChecks )
{
if ( ! tx . IsCoinBase ( ) )
{
@ -1177,6 +1198,21 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
@@ -1177,6 +1198,21 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
// Of course, if an assumed valid block is invalid due to false scriptSigs
// this optimization would allow an invalid chain to be accepted.
if ( fScriptChecks ) {
// First check if script executions have been cached with the same
// flags. Note that this assumes that the inputs provided are
// correct (ie that the transaction hash which is in tx's prevouts
// properly commits to the scriptPubKey in the inputs view of that
// transaction).
uint256 hashCacheEntry ;
// We only use the first 19 bytes of nonce to avoid a second SHA
// round - giving us 19 + 32 + 4 = 55 bytes (+ 8 + 1 = 64)
static_assert ( 55 - sizeof ( flags ) - 32 > = 128 / 8 , " Want at least 128 bits of nonce for script execution cache " ) ;
CSHA256 ( ) . Write ( scriptExecutionCacheNonce . begin ( ) , 55 - sizeof ( flags ) - 32 ) . Write ( tx . GetWitnessHash ( ) . begin ( ) , 32 ) . Write ( ( unsigned char * ) & flags , sizeof ( flags ) ) . Finalize ( hashCacheEntry . begin ( ) ) ;
AssertLockHeld ( cs_main ) ; //TODO: Remove this requirement by making CuckooCache not require external locks
if ( scriptExecutionCache . contains ( hashCacheEntry , ! cacheFullScriptStore ) ) {
return true ;
}
for ( unsigned int i = 0 ; i < tx . vin . size ( ) ; i + + ) {
const COutPoint & prevout = tx . vin [ i ] . prevout ;
const Coin & coin = inputs . AccessCoin ( prevout ) ;
@ -1191,7 +1227,7 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
@@ -1191,7 +1227,7 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
const CAmount amount = coin . out . nValue ;
// Verify signature
CScriptCheck check ( scriptPubKey , amount , tx , i , flags , cacheStore , & txdata ) ;
CScriptCheck check ( scriptPubKey , amount , tx , i , flags , cacheSigS tore , & txdata ) ;
if ( pvChecks ) {
pvChecks - > push_back ( CScriptCheck ( ) ) ;
check . swap ( pvChecks - > back ( ) ) ;
@ -1204,7 +1240,7 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
@@ -1204,7 +1240,7 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
// avoid splitting the network between upgraded and
// non-upgraded nodes.
CScriptCheck check2 ( scriptPubKey , amount , tx , i ,
flags & ~ STANDARD_NOT_MANDATORY_VERIFY_FLAGS , cacheStore , & txdata ) ;
flags & ~ STANDARD_NOT_MANDATORY_VERIFY_FLAGS , cacheSigS tore , & txdata ) ;
if ( check2 ( ) )
return state . Invalid ( false , REJECT_NONSTANDARD , strprintf ( " non-mandatory-script-verify-flag (%s) " , ScriptErrorString ( check . GetScriptError ( ) ) ) ) ;
}
@ -1218,6 +1254,12 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
@@ -1218,6 +1254,12 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
return state . DoS ( 100 , false , REJECT_INVALID , strprintf ( " mandatory-script-verify-flag-failed (%s) " , ScriptErrorString ( check . GetScriptError ( ) ) ) ) ;
}
}
if ( cacheFullScriptStore & & ! pvChecks ) {
// We executed all of the provided scripts, and were told to
// cache the result. Do so now.
scriptExecutionCache . insert ( hashCacheEntry ) ;
}
}
}
@ -1684,7 +1726,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
@@ -1684,7 +1726,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
std : : vector < CScriptCheck > vChecks ;
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 , txdata [ i ] , nScriptCheckThreads ? & vChecks : NULL ) )
if ( ! CheckInputs ( tx , state , view , fScriptChecks , flags , fCacheResults , fCacheResults , txdata [ i ] , nScriptCheckThreads ? & vChecks : NULL ) )
return error ( " ConnectBlock(): CheckInputs on %s failed with %s " ,
tx . GetHash ( ) . ToString ( ) , FormatStateMessage ( state ) ) ;
control . Add ( vChecks ) ;