X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fscript.cpp;h=ccb19c388e933efee2faf8711560bfe557a4c475;hb=23e7583a8c9a0dcee9cbbf3be8bfc453298773f0;hp=21f101e1c59c9b81bf255201fe76f8e8247bda35;hpb=0aa0bb1ead81641480c0c7533a1f52dd6a07434e;p=novacoin.git diff --git a/src/script.cpp b/src/script.cpp index 21f101e..ccb19c3 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1,12 +1,20 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying -// file license.txt or http://www.opensource.org/licenses/mit-license.php. -#include "headers.h" +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include +#include using namespace std; using namespace boost; +#include "script.h" +#include "keystore.h" +#include "bignum.h" +#include "key.h" +#include "main.h" +#include "util.h" + bool CheckSig(vector vchSig, vector vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); @@ -32,7 +40,7 @@ CBigNum CastToBigNum(const valtype& vch) bool CastToBool(const valtype& vch) { - for (int i = 0; i < vch.size(); i++) + for (unsigned int i = 0; i < vch.size(); i++) { if (vch[i] != 0) { @@ -530,7 +538,7 @@ bool EvalScript(vector >& stack, const CScript& script, co return false; int n = CastToBigNum(stacktop(-1)).getint(); popstack(stack); - if (n < 0 || n >= stack.size()) + if (n < 0 || n >= (int)stack.size()) return false; valtype vch = stacktop(-n-1); if (opcode == OP_ROLL) @@ -598,9 +606,9 @@ bool EvalScript(vector >& stack, const CScript& script, co int nEnd = nBegin + CastToBigNum(stacktop(-1)).getint(); if (nBegin < 0 || nEnd < nBegin) return false; - if (nBegin > vch.size()) + if (nBegin > (int)vch.size()) nBegin = vch.size(); - if (nEnd > vch.size()) + if (nEnd > (int)vch.size()) nEnd = vch.size(); vch.erase(vch.begin() + nEnd, vch.end()); vch.erase(vch.begin(), vch.begin() + nBegin); @@ -619,7 +627,7 @@ bool EvalScript(vector >& stack, const CScript& script, co int nSize = CastToBigNum(stacktop(-1)).getint(); if (nSize < 0) return false; - if (nSize > vch.size()) + if (nSize > (int)vch.size()) nSize = vch.size(); if (opcode == OP_LEFT) vch.erase(vch.begin() + nSize, vch.end()); @@ -649,7 +657,7 @@ bool EvalScript(vector >& stack, const CScript& script, co if (stack.size() < 1) return false; valtype& vch = stacktop(-1); - for (int i = 0; i < vch.size(); i++) + for (unsigned int i = 0; i < vch.size(); i++) vch[i] = ~vch[i]; } break; @@ -666,17 +674,17 @@ bool EvalScript(vector >& stack, const CScript& script, co MakeSameSize(vch1, vch2); if (opcode == OP_AND) { - for (int i = 0; i < vch1.size(); i++) + for (unsigned int i = 0; i < vch1.size(); i++) vch1[i] &= vch2[i]; } else if (opcode == OP_OR) { - for (int i = 0; i < vch1.size(); i++) + for (unsigned int i = 0; i < vch1.size(); i++) vch1[i] |= vch2[i]; } else if (opcode == OP_XOR) { - for (int i = 0; i < vch1.size(); i++) + for (unsigned int i = 0; i < vch1.size(); i++) vch1[i] ^= vch2[i]; } popstack(stack); @@ -1044,7 +1052,7 @@ uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR)); // Blank out other inputs' signatures - for (int i = 0; i < txTmp.vin.size(); i++) + for (unsigned int i = 0; i < txTmp.vin.size(); i++) txTmp.vin[i].scriptSig = CScript(); txTmp.vin[nIn].scriptSig = scriptCode; @@ -1055,7 +1063,7 @@ uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int txTmp.vout.clear(); // Let the others update at will - for (int i = 0; i < txTmp.vin.size(); i++) + for (unsigned int i = 0; i < txTmp.vin.size(); i++) if (i != nIn) txTmp.vin[i].nSequence = 0; } @@ -1069,11 +1077,11 @@ uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int return 1; } txTmp.vout.resize(nOut+1); - for (int i = 0; i < nOut; i++) + for (unsigned int i = 0; i < nOut; i++) txTmp.vout[i].SetNull(); // Let the others update at will - for (int i = 0; i < txTmp.vin.size(); i++) + for (unsigned int i = 0; i < txTmp.vin.size(); i++) if (i != nIn) txTmp.vin[i].nSequence = 0; } @@ -1086,19 +1094,74 @@ uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int } // Serialize and hash - CDataStream ss(SER_GETHASH); + CDataStream ss(SER_GETHASH, 0); ss.reserve(10000); ss << txTmp << nHashType; return Hash(ss.begin(), ss.end()); } +// 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 +{ +private: + // sigdata_type is (signature hash, signature, public key): + typedef boost::tuple, std::vector > sigdata_type; + std::set< sigdata_type> setValid; + CCriticalSection cs_sigcache; + +public: + bool + Get(uint256 hash, const std::vector& vchSig, const std::vector& pubKey) + { + 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(uint256 hash, const std::vector& vchSig, const std::vector& 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 nMaxCacheSize = GetArg("-maxsigcachesize", 50000); + if (nMaxCacheSize <= 0) return; + + 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); + } +}; + bool CheckSig(vector vchSig, vector vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) { - CKey key; - if (!key.SetPubKey(vchPubKey)) - return false; + static CSignatureCache signatureCache; // Hash type is one byte tacked on to the end of the signature if (vchSig.empty()) @@ -1109,7 +1172,20 @@ bool CheckSig(vector vchSig, vector vchPubKey, CSc return false; vchSig.pop_back(); - return key.Verify(SignatureHash(scriptCode, txTo, nIn, nHashType), vchSig); + uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType); + + if (signatureCache.Get(sighash, vchSig, vchPubKey)) + return true; + + CKey key; + if (!key.SetPubKey(vchPubKey)) + return false; + + if (!key.Verify(sighash, vchSig)) + return false; + + signatureCache.Set(sighash, vchSig, vchPubKey); + return true; } @@ -1354,9 +1430,9 @@ bool IsStandard(const CScript& scriptPubKey) } -int HaveKeys(const vector& pubkeys, const CKeyStore& keystore) +unsigned int HaveKeys(const vector& pubkeys, const CKeyStore& keystore) { - int nResult = 0; + unsigned int nResult = 0; BOOST_FOREACH(const valtype& pubkey, pubkeys) { CBitcoinAddress address; @@ -1443,7 +1519,7 @@ bool ExtractAddresses(const CScript& scriptPubKey, txnouttype& typeRet, vector