From c7829ea797c840dda7888ee860a50b7a3308069d Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 10 Sep 2014 14:42:22 +0200 Subject: Abstract out SignatureChecker --- src/script/interpreter.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src/script/interpreter.cpp') diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index a71f55dd26..048d298f0b 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -132,7 +132,7 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { return true; } -bool EvalScript(vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags) +bool EvalScript(vector >& stack, const CScript& script, unsigned int flags, const SignatureChecker& checker) { CScript::const_iterator pc = script.begin(); CScript::const_iterator pend = script.end(); @@ -675,7 +675,7 @@ bool EvalScript(vector >& stack, const CScript& script, co scriptCode.FindAndDelete(CScript(vchSig)); bool fSuccess = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) && - CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, flags); + checker.CheckSig(vchSig, vchPubKey, scriptCode, flags); popstack(stack); popstack(stack); @@ -736,7 +736,7 @@ bool EvalScript(vector >& stack, const CScript& script, co // Check signature bool fOk = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) && - CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, flags); + checker.CheckSig(vchSig, vchPubKey, scriptCode, flags); if (fOk) { isig++; @@ -897,7 +897,7 @@ public: } // anon namespace -uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) +uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) { if (nIn >= txTo.vin.size()) { LogPrintf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn); @@ -976,7 +976,7 @@ public: } }; -bool CheckSig(vector vchSig, const vector& vchPubKey, const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int flags) +bool SignatureChecker::CheckSig(const vector& vchSigIn, const vector& vchPubKey, const CScript& scriptCode, int flags) const { static CSignatureCache signatureCache; @@ -985,6 +985,7 @@ bool CheckSig(vector vchSig, const vector& vchPubK return false; // Hash type is one byte tacked on to the end of the signature + vector vchSig(vchSigIn); if (vchSig.empty()) return false; int nHashType = vchSig.back(); @@ -1004,14 +1005,14 @@ bool CheckSig(vector vchSig, const vector& vchPubK return true; } -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags) +bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const SignatureChecker& checker) { vector > stack, stackCopy; - if (!EvalScript(stack, scriptSig, txTo, nIn, flags)) + if (!EvalScript(stack, scriptSig, flags, checker)) return false; if (flags & SCRIPT_VERIFY_P2SH) stackCopy = stack; - if (!EvalScript(stack, scriptPubKey, txTo, nIn, flags)) + if (!EvalScript(stack, scriptPubKey, flags, checker)) return false; if (stack.empty()) return false; @@ -1034,7 +1035,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); popstack(stackCopy); - if (!EvalScript(stackCopy, pubKey2, txTo, nIn, flags)) + if (!EvalScript(stackCopy, pubKey2, flags, checker)) return false; if (stackCopy.empty()) return false; -- cgit v1.2.3 From 5c1e798a8e9df15f8fbd120e57fc67e585f13843 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 10 Sep 2014 16:16:09 +0200 Subject: Make signature cache optional --- src/script/interpreter.cpp | 74 ++++------------------------------------------ 1 file changed, 6 insertions(+), 68 deletions(-) (limited to 'src/script/interpreter.cpp') diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 048d298f0b..f0b4268390 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -9,14 +9,10 @@ #include "crypto/ripemd160.h" #include "crypto/sha1.h" #include "crypto/sha2.h" -#include "random.h" #include "script/script.h" #include "uint256.h" #include "util.h" -#include -#include - using namespace std; typedef vector valtype; @@ -132,7 +128,7 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { return true; } -bool EvalScript(vector >& stack, const CScript& script, unsigned int flags, const SignatureChecker& checker) +bool EvalScript(vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker) { CScript::const_iterator pc = script.begin(); CScript::const_iterator pend = script.end(); @@ -921,65 +917,13 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig return ss.GetHash(); } -// Valid signature cache, to avoid doing expensive ECDSA signature checking -// twice for every transaction (once when accepted into memory pool, and -// again when accepted into the block chain) -class CSignatureCache +bool SignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash, int flags) const { -private: - // sigdata_type is (signature hash, signature, public key): - typedef boost::tuple, CPubKey> sigdata_type; - std::set< sigdata_type> setValid; - boost::shared_mutex cs_sigcache; - -public: - bool - Get(const uint256 &hash, const std::vector& vchSig, const CPubKey& pubKey) - { - boost::shared_lock lock(cs_sigcache); - - sigdata_type k(hash, vchSig, pubKey); - std::set::iterator mi = setValid.find(k); - if (mi != setValid.end()) - return true; - return false; - } - - void Set(const uint256 &hash, const std::vector& vchSig, const CPubKey& pubKey) - { - // DoS prevention: limit cache size to less than 10MB - // (~200 bytes per cache entry times 50,000 entries) - // Since there are a maximum of 20,000 signature operations per block - // 50,000 is a reasonable default. - int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000); - if (nMaxCacheSize <= 0) return; - - boost::unique_lock lock(cs_sigcache); - - while (static_cast(setValid.size()) > nMaxCacheSize) - { - // Evict a random entry. Random because that helps - // foil would-be DoS attackers who might try to pre-generate - // and re-use a set of valid signatures just-slightly-greater - // than our cache size. - uint256 randomHash = GetRandHash(); - std::vector unused; - std::set::iterator it = - setValid.lower_bound(sigdata_type(randomHash, unused, unused)); - if (it == setValid.end()) - it = setValid.begin(); - setValid.erase(*it); - } - - sigdata_type k(hash, vchSig, pubKey); - setValid.insert(k); - } -}; + return pubkey.Verify(sighash, vchSig); +} bool SignatureChecker::CheckSig(const vector& vchSigIn, const vector& vchPubKey, const CScript& scriptCode, int flags) const { - static CSignatureCache signatureCache; - CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) return false; @@ -993,19 +937,13 @@ bool SignatureChecker::CheckSig(const vector& vchSigIn, const vec uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType); - if (signatureCache.Get(sighash, vchSig, pubkey)) - return true; - - if (!pubkey.Verify(sighash, vchSig)) + if (!VerifySignature(vchSig, pubkey, sighash, flags)) return false; - if (!(flags & SCRIPT_VERIFY_NOCACHE)) - signatureCache.Set(sighash, vchSig, pubkey); - return true; } -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const SignatureChecker& checker) +bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker) { vector > stack, stackCopy; if (!EvalScript(stack, scriptSig, flags, checker)) -- cgit v1.2.3 From e790c370b5971dd096d1bbfd55960ccf71b7594a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 14 Sep 2014 04:48:32 +0200 Subject: Replace SCRIPT_VERIFY_NOCACHE by flag directly to checker --- src/script/interpreter.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/script/interpreter.cpp') diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index f0b4268390..56140f19db 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -671,7 +671,7 @@ bool EvalScript(vector >& stack, const CScript& script, un scriptCode.FindAndDelete(CScript(vchSig)); bool fSuccess = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) && - checker.CheckSig(vchSig, vchPubKey, scriptCode, flags); + checker.CheckSig(vchSig, vchPubKey, scriptCode); popstack(stack); popstack(stack); @@ -732,7 +732,7 @@ bool EvalScript(vector >& stack, const CScript& script, un // Check signature bool fOk = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) && - checker.CheckSig(vchSig, vchPubKey, scriptCode, flags); + checker.CheckSig(vchSig, vchPubKey, scriptCode); if (fOk) { isig++; @@ -917,12 +917,12 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig return ss.GetHash(); } -bool SignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash, int flags) const +bool SignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash) const { return pubkey.Verify(sighash, vchSig); } -bool SignatureChecker::CheckSig(const vector& vchSigIn, const vector& vchPubKey, const CScript& scriptCode, int flags) const +bool SignatureChecker::CheckSig(const vector& vchSigIn, const vector& vchPubKey, const CScript& scriptCode) const { CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) @@ -937,7 +937,7 @@ bool SignatureChecker::CheckSig(const vector& vchSigIn, const vec uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType); - if (!VerifySignature(vchSig, pubkey, sighash, flags)) + if (!VerifySignature(vchSig, pubkey, sighash)) return false; return true; -- cgit v1.2.3