// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "serverchecker.h" #include "script/cc.h" #include "cc/eval.h" #include "pubkey.h" #include "random.h" #include "uint256.h" #include "util.h" #undef __cpuid #include #include namespace { /** * 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, CPubKey> sigdata_type; std::set< sigdata_type> setValid; boost::shared_mutex cs_serverchecker; public: bool Get(const uint256 &hash, const std::vector& vchSig, const CPubKey& pubKey) { boost::shared_lock lock(cs_serverchecker); 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 can be no more than 20,000 signature operations per block // 50,000 is a reasonable default. int64_t nMaxCacheSize = GetArg("-maxservercheckersize", 50000); if (nMaxCacheSize <= 0) return; boost::unique_lock lock(cs_serverchecker); 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 ServerTransactionSignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash) const { static CSignatureCache signatureCache; if (signatureCache.Get(sighash, vchSig, pubkey)) return true; if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash)) return false; if (store) signatureCache.Set(sighash, vchSig, pubkey); return true; } /* * The reason that these functions are here is that the what used to be the * CachingTransactionSignatureChecker, now the ServerTransactionSignatureChecker, * is an entry point that the server uses to validate signatures and which is not * included as part of bitcoin common libs. Since Crypto-Condtions eval methods * may call server code (GetTransaction etc), the best way to get it to run this * code without pulling the whole bitcoin server code into bitcoin common was * using this class. Thus it has been renamed to ServerTransactionSignatureChecker. */ int ServerTransactionSignatureChecker::CheckEvalCondition(const CC *cond) const { return RunCCEval(cond, *txTo, nIn); }