diff options
Diffstat (limited to 'src/script/interpreter.cpp')
-rw-r--r-- | src/script/interpreter.cpp | 104 |
1 files changed, 22 insertions, 82 deletions
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index fd3e4f1ff7..56140f19db 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 <boost/thread.hpp> -#include <boost/tuple/tuple_comparison.hpp> - using namespace std; typedef vector<unsigned char> valtype; @@ -132,7 +128,7 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { return true; } -bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags) +bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker) { CScript::const_iterator pc = script.begin(); CScript::const_iterator pend = script.end(); @@ -637,19 +633,19 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co valtype& vch = stacktop(-1); valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32); if (opcode == OP_RIPEMD160) - CRIPEMD160().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); + CRIPEMD160().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); else if (opcode == OP_SHA1) - CSHA1().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); + CSHA1().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); else if (opcode == OP_SHA256) - CSHA256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); + CSHA256().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); else if (opcode == OP_HASH160) - CHash160().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); + CHash160().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); else if (opcode == OP_HASH256) - CHash256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); + CHash256().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); popstack(stack); stack.push_back(vchHash); } - break; + break; case OP_CODESEPARATOR: { @@ -675,7 +671,7 @@ bool EvalScript(vector<vector<unsigned char> >& 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); popstack(stack); popstack(stack); @@ -736,7 +732,7 @@ bool EvalScript(vector<vector<unsigned char> >& 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); if (fOk) { isig++; @@ -839,7 +835,8 @@ public: itBegin = it; } } - s.write((char*)&itBegin[0], it-itBegin); + if (itBegin != scriptCode.end()) + s.write((char*)&itBegin[0], it-itBegin); } /** Serialize an input of txTo */ @@ -896,7 +893,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); @@ -920,70 +917,19 @@ 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<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const { -private: - // sigdata_type is (signature hash, signature, public key): - typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type; - std::set< sigdata_type> setValid; - boost::shared_mutex cs_sigcache; - -public: - bool - Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey) - { - boost::shared_lock<boost::shared_mutex> lock(cs_sigcache); - - sigdata_type k(hash, vchSig, pubKey); - std::set<sigdata_type>::iterator mi = setValid.find(k); - if (mi != setValid.end()) - return true; - return false; - } - - void Set(const uint256 &hash, const std::vector<unsigned char>& 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<boost::shared_mutex> lock(cs_sigcache); - - while (static_cast<int64_t>(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<unsigned char> unused; - std::set<sigdata_type>::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 CheckSig(vector<unsigned char> vchSig, const vector<unsigned char>& vchPubKey, const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int flags) +bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode) const { - static CSignatureCache signatureCache; - CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) return false; // Hash type is one byte tacked on to the end of the signature + vector<unsigned char> vchSig(vchSigIn); if (vchSig.empty()) return false; int nHashType = vchSig.back(); @@ -991,26 +937,20 @@ bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char>& vchPubK 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)) return false; - if (!(flags & SCRIPT_VERIFY_NOCACHE)) - signatureCache.Set(sighash, vchSig, pubkey); - 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 BaseSignatureChecker& checker) { vector<vector<unsigned char> > 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; @@ -1033,7 +973,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; |