1414#include " consensus/merkle.h"
1515#include " consensus/tx_verify.h"
1616#include " consensus/validation.h"
17+ #include " cuckoocache.h"
1718#include " fs.h"
1819#include " hash.h"
1920#include " init.h"
@@ -189,7 +190,7 @@ enum FlushStateMode {
189190static bool FlushStateToDisk (const CChainParams& chainParams, CValidationState &state, FlushStateMode mode, int nManualPruneHeight=0 );
190191static void FindFilesToPruneManual (std::set<int >& setFilesToPrune, int nManualPruneHeight);
191192static void FindFilesToPrune (std::set<int >& setFilesToPrune, uint64_t nPruneAfterHeight);
192- 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 );
193+ static bool CheckInputs (const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks , unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = nullptr );
193194static FILE* OpenUndoFile (const CDiskBlockPos &pos, bool fReadOnly = false );
194195
195196bool CheckFinalTx (const CTransaction &tx, int flags)
@@ -752,29 +753,36 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
752753 // Check against previous transactions
753754 // This is done last to help prevent CPU exhaustion denial-of-service attacks.
754755 PrecomputedTransactionData txdata (tx);
755- if (!CheckInputs (tx, state, view, true , scriptVerifyFlags, true , txdata)) {
756+ if (!CheckInputs (tx, state, view, true , scriptVerifyFlags, true , false , txdata)) {
756757 // SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
757758 // need to turn both off, and compare against just turning off CLEANSTACK
758759 // to see if the failure is specifically due to witness validation.
759760 CValidationState stateDummy; // Want reported failures to be from first CheckInputs
760- if (!tx.HasWitness () && CheckInputs (tx, stateDummy, view, true , scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true , txdata) &&
761- !CheckInputs (tx, stateDummy, view, true , scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true , txdata)) {
761+ if (!tx.HasWitness () && CheckInputs (tx, stateDummy, view, true , scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true , false , txdata) &&
762+ !CheckInputs (tx, stateDummy, view, true , scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true , false , txdata)) {
762763 // Only the witness is missing, so the transaction itself may be fine.
763764 state.SetCorruptionPossible ();
764765 }
765766 return false ; // state filled in by CheckInputs
766767 }
767768
768- // Check again against just the consensus-critical mandatory script
769- // verification flags, in case of bugs in the standard flags that cause
769+ // Check again against the current block tip's script verification
770+ // flags to cache our script execution flags. This is, of course,
771+ // useless if the next block has different script flags from the
772+ // previous one, but because the cache tracks script flags for us it
773+ // will auto-invalidate and we'll just have a few blocks of extra
774+ // misses on soft-fork activation.
775+ //
776+ // This is also useful in case of bugs in the standard flags that cause
770777 // transactions to pass as valid when they're actually invalid. For
771778 // instance the STRICTENC flag was incorrectly allowing certain
772779 // CHECKSIG NOT scripts to pass, even though they were invalid.
773780 //
774781 // There is a similar check in CreateNewBlock() to prevent creating
775- // invalid blocks, however allowing such transactions into the mempool
776- // can be exploited as a DoS attack.
777- if (!CheckInputs (tx, state, view, true , MANDATORY_SCRIPT_VERIFY_FLAGS, true , txdata))
782+ // invalid blocks (using TestBlockValidity), however allowing such
783+ // transactions into the mempool can be exploited as a DoS attack.
784+ unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags (chainActive.Tip (), Params ().GetConsensus ());
785+ if (!CheckInputs (tx, state, view, true , currentBlockScriptVerifyFlags, true , true , txdata))
778786 {
779787 return error (" %s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s" ,
780788 __func__, hash.ToString (), FormatStateMessage (state));
@@ -1152,12 +1160,25 @@ int GetSpendHeight(const CCoinsViewCache& inputs)
11521160 return pindexPrev->nHeight + 1 ;
11531161}
11541162
1163+
1164+ static CuckooCache::cache<uint256, SignatureCacheHasher> scriptExecutionCache;
1165+ static uint256 scriptExecutionCacheNonce (GetRandHash());
1166+
1167+ void InitScriptExecutionCache () {
1168+ // nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero,
1169+ // setup_bytes creates the minimum possible cache (2 elements).
1170+ 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 );
1171+ size_t nElems = scriptExecutionCache.setup_bytes (nMaxCacheSize);
1172+ LogPrintf (" Using %zu MiB out of %zu requested for script execution cache, able to store %zu elements\n " ,
1173+ (nElems*sizeof (uint256)) >>20 , nMaxCacheSize>>20 , nElems);
1174+ }
1175+
11551176/* *
11561177 * Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
11571178 * This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
11581179 * instead of being performed inline.
11591180 */
1160- static bool CheckInputs (const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks , unsigned int flags, bool cacheStore , PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks)
1181+ static bool CheckInputs (const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks , unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore , PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks)
11611182{
11621183 if (!tx.IsCoinBase ())
11631184 {
@@ -1177,6 +1198,21 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
11771198 // Of course, if an assumed valid block is invalid due to false scriptSigs
11781199 // this optimization would allow an invalid chain to be accepted.
11791200 if (fScriptChecks ) {
1201+ // First check if script executions have been cached with the same
1202+ // flags. Note that this assumes that the inputs provided are
1203+ // correct (ie that the transaction hash which is in tx's prevouts
1204+ // properly commits to the scriptPubKey in the inputs view of that
1205+ // transaction).
1206+ uint256 hashCacheEntry;
1207+ // We only use the first 19 bytes of nonce to avoid a second SHA
1208+ // round - giving us 19 + 32 + 4 = 55 bytes (+ 8 + 1 = 64)
1209+ static_assert (55 - sizeof (flags) - 32 >= 128 /8 , " Want at least 128 bits of nonce for script execution cache" );
1210+ CSHA256 ().Write (scriptExecutionCacheNonce.begin (), 55 - sizeof (flags) - 32 ).Write (tx.GetWitnessHash ().begin (), 32 ).Write ((unsigned char *)&flags, sizeof (flags)).Finalize (hashCacheEntry.begin ());
1211+ AssertLockHeld (cs_main); // TODO: Remove this requirement by making CuckooCache not require external locks
1212+ if (scriptExecutionCache.contains (hashCacheEntry, !cacheFullScriptStore)) {
1213+ return true ;
1214+ }
1215+
11801216 for (unsigned int i = 0 ; i < tx.vin .size (); i++) {
11811217 const COutPoint &prevout = tx.vin [i].prevout ;
11821218 const Coin& coin = inputs.AccessCoin (prevout);
@@ -1191,7 +1227,7 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
11911227 const CAmount amount = coin.out .nValue ;
11921228
11931229 // Verify signature
1194- CScriptCheck check (scriptPubKey, amount, tx, i, flags, cacheStore , &txdata);
1230+ CScriptCheck check (scriptPubKey, amount, tx, i, flags, cacheSigStore , &txdata);
11951231 if (pvChecks) {
11961232 pvChecks->push_back (CScriptCheck ());
11971233 check.swap (pvChecks->back ());
@@ -1204,7 +1240,7 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
12041240 // avoid splitting the network between upgraded and
12051241 // non-upgraded nodes.
12061242 CScriptCheck check2 (scriptPubKey, amount, tx, i,
1207- flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore , &txdata);
1243+ flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore , &txdata);
12081244 if (check2 ())
12091245 return state.Invalid (false , REJECT_NONSTANDARD, strprintf (" non-mandatory-script-verify-flag (%s)" , ScriptErrorString (check.GetScriptError ())));
12101246 }
@@ -1218,6 +1254,12 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
12181254 return state.DoS (100 ,false , REJECT_INVALID, strprintf (" mandatory-script-verify-flag-failed (%s)" , ScriptErrorString (check.GetScriptError ())));
12191255 }
12201256 }
1257+
1258+ if (cacheFullScriptStore && !pvChecks) {
1259+ // We executed all of the provided scripts, and were told to
1260+ // cache the result. Do so now.
1261+ scriptExecutionCache.insert (hashCacheEntry);
1262+ }
12211263 }
12221264 }
12231265
@@ -1684,7 +1726,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
16841726
16851727 std::vector<CScriptCheck> vChecks;
16861728 bool fCacheResults = fJustCheck ; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
1687- if (!CheckInputs (tx, state, view, fScriptChecks , flags, fCacheResults , txdata[i], nScriptCheckThreads ? &vChecks : NULL ))
1729+ if (!CheckInputs (tx, state, view, fScriptChecks , flags, fCacheResults , fCacheResults , txdata[i], nScriptCheckThreads ? &vChecks : NULL ))
16881730 return error (" ConnectBlock(): CheckInputs on %s failed with %s" ,
16891731 tx.GetHash ().ToString (), FormatStateMessage (state));
16901732 control.Add (vChecks);
0 commit comments