diff --git a/src/Makefile.test.include b/src/Makefile.test.include --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -115,6 +115,7 @@ test/sigencoding_tests.cpp \ test/sighash_tests.cpp \ test/sighashtype_tests.cpp \ + test/sigcheckcount_tests.cpp \ test/sigopcount_tests.cpp \ test/sigutil.h \ test/skiplist_tests.cpp \ diff --git a/src/script/interpreter.h b/src/script/interpreter.h --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -82,9 +82,23 @@ using MutableTransactionSignatureChecker = GenericTransactionSignatureChecker; +/** Struct for holding cumulative results from executing a script or a sequence + * of scripts. + */ +struct ScriptExecutionMetrics { + int nSigChecks = 0; +}; + bool EvalScript(std::vector> &stack, const CScript &script, uint32_t flags, const BaseSignatureChecker &checker, - ScriptError *error = nullptr); + ScriptError *error, ScriptExecutionMetrics &metrics); +static inline bool EvalScript(std::vector> &stack, + const CScript &script, uint32_t flags, + const BaseSignatureChecker &checker, + ScriptError *error = nullptr) { + ScriptExecutionMetrics dummymetrics; + return EvalScript(stack, script, flags, checker, error, dummymetrics); +} bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, uint32_t flags, const BaseSignatureChecker &checker, ScriptError *serror = nullptr); diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -102,7 +102,7 @@ bool EvalScript(std::vector &stack, const CScript &script, uint32_t flags, const BaseSignatureChecker &checker, - ScriptError *serror) { + ScriptError *serror, ScriptExecutionMetrics &metrics) { static const CScriptNum bnZero(0); static const CScriptNum bnOne(1); static const valtype vchFalse(0); @@ -903,6 +903,10 @@ return set_error(serror, ScriptError::SIG_NULLFAIL); } + if (vchSig.size()) { + metrics.nSigChecks += 1; + } + popstack(stack); popstack(stack); stack.push_back(fSuccess ? vchTrue : vchFalse); @@ -943,6 +947,8 @@ .Finalize(vchHash.data()); fSuccess = checker.VerifySignature( vchSig, CPubKey(vchPubKey), uint256(vchHash)); + + metrics.nSigChecks += 1; } if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && @@ -1105,6 +1111,8 @@ return set_error( serror, ScriptError::INVALID_BIT_COUNT); } + + metrics.nSigChecks += nSigsCount; } else { // LEGACY MULTISIG (ECDSA / NULL) @@ -1168,6 +1176,14 @@ return set_error(serror, ScriptError::SIG_NULLFAIL); } + + if (!allsigsnull) { + // This is not identical to the number of actual + // ECDSA verifies, but, it is an upper bound + // that can be easily determined without doing + // CPU-intensive checks. + metrics.nSigChecks += nKeysCount; + } } // Clean up stack of all arguments diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -128,6 +128,7 @@ sigencoding_tests.cpp sighash_tests.cpp sighashtype_tests.cpp + sigcheckcount_tests.cpp sigopcount_tests.cpp sigutil.cpp skiplist_tests.cpp diff --git a/src/test/sigcheckcount_tests.cpp b/src/test/sigcheckcount_tests.cpp new file mode 100644 --- /dev/null +++ b/src/test/sigcheckcount_tests.cpp @@ -0,0 +1,296 @@ +// Copyright (c) 2019 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include