14
14
#include " consensus/merkle.h"
15
15
#include " consensus/tx_verify.h"
16
16
#include " consensus/validation.h"
17
+ #include " cuckoocache.h"
17
18
#include " fs.h"
18
19
#include " hash.h"
19
20
#include " init.h"
@@ -189,7 +190,7 @@ enum FlushStateMode {
189
190
static bool FlushStateToDisk (const CChainParams& chainParams, CValidationState &state, FlushStateMode mode, int nManualPruneHeight=0 );
190
191
static void FindFilesToPruneManual (std::set<int >& setFilesToPrune, int nManualPruneHeight);
191
192
static 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 );
193
194
static FILE* OpenUndoFile (const CDiskBlockPos &pos, bool fReadOnly = false );
194
195
195
196
bool CheckFinalTx (const CTransaction &tx, int flags)
@@ -752,29 +753,36 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
752
753
// Check against previous transactions
753
754
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
754
755
PrecomputedTransactionData txdata (tx);
755
- if (!CheckInputs (tx, state, view, true , scriptVerifyFlags, true , txdata)) {
756
+ if (!CheckInputs (tx, state, view, true , scriptVerifyFlags, true , false , txdata)) {
756
757
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
757
758
// need to turn both off, and compare against just turning off CLEANSTACK
758
759
// to see if the failure is specifically due to witness validation.
759
760
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)) {
762
763
// Only the witness is missing, so the transaction itself may be fine.
763
764
state.SetCorruptionPossible ();
764
765
}
765
766
return false ; // state filled in by CheckInputs
766
767
}
767
768
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
770
777
// transactions to pass as valid when they're actually invalid. For
771
778
// instance the STRICTENC flag was incorrectly allowing certain
772
779
// CHECKSIG NOT scripts to pass, even though they were invalid.
773
780
//
774
781
// 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))
778
786
{
779
787
return error (" %s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s" ,
780
788
__func__, hash.ToString (), FormatStateMessage (state));
@@ -1152,12 +1160,25 @@ int GetSpendHeight(const CCoinsViewCache& inputs)
1152
1160
return pindexPrev->nHeight + 1 ;
1153
1161
}
1154
1162
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
+
1155
1176
/* *
1156
1177
* Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
1157
1178
* This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
1158
1179
* instead of being performed inline.
1159
1180
*/
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)
1161
1182
{
1162
1183
if (!tx.IsCoinBase ())
1163
1184
{
@@ -1177,6 +1198,21 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
1177
1198
// Of course, if an assumed valid block is invalid due to false scriptSigs
1178
1199
// this optimization would allow an invalid chain to be accepted.
1179
1200
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
+
1180
1216
for (unsigned int i = 0 ; i < tx.vin .size (); i++) {
1181
1217
const COutPoint &prevout = tx.vin [i].prevout ;
1182
1218
const Coin& coin = inputs.AccessCoin (prevout);
@@ -1191,7 +1227,7 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
1191
1227
const CAmount amount = coin.out .nValue ;
1192
1228
1193
1229
// Verify signature
1194
- CScriptCheck check (scriptPubKey, amount, tx, i, flags, cacheStore , &txdata);
1230
+ CScriptCheck check (scriptPubKey, amount, tx, i, flags, cacheSigStore , &txdata);
1195
1231
if (pvChecks) {
1196
1232
pvChecks->push_back (CScriptCheck ());
1197
1233
check.swap (pvChecks->back ());
@@ -1204,7 +1240,7 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
1204
1240
// avoid splitting the network between upgraded and
1205
1241
// non-upgraded nodes.
1206
1242
CScriptCheck check2 (scriptPubKey, amount, tx, i,
1207
- flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore , &txdata);
1243
+ flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore , &txdata);
1208
1244
if (check2 ())
1209
1245
return state.Invalid (false , REJECT_NONSTANDARD, strprintf (" non-mandatory-script-verify-flag (%s)" , ScriptErrorString (check.GetScriptError ())));
1210
1246
}
@@ -1218,6 +1254,12 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
1218
1254
return state.DoS (100 ,false , REJECT_INVALID, strprintf (" mandatory-script-verify-flag-failed (%s)" , ScriptErrorString (check.GetScriptError ())));
1219
1255
}
1220
1256
}
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
+ }
1221
1263
}
1222
1264
}
1223
1265
@@ -1684,7 +1726,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
1684
1726
1685
1727
std::vector<CScriptCheck> vChecks;
1686
1728
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 ))
1688
1730
return error (" ConnectBlock(): CheckInputs on %s failed with %s" ,
1689
1731
tx.GetHash ().ToString (), FormatStateMessage (state));
1690
1732
control.Add (vChecks);
0 commit comments