// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2015 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 "sigcache.h" #include "memusage.h" #include "pubkey.h" #include "random.h" #include "uint256.h" #include "util.h" #include #include namespace { /** * We're hashing a nonce into the entries themselves, so we don't need extra * blinding in the set hash computation. */ class CSignatureCacheHasher { public: size_t operator()(const uint256& key) const { return key.GetCheapHash(); } }; /** * 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: //! Entries are SHA256(nonce || signature hash || public key || signature): uint256 nonce; typedef boost::unordered_set map_type; map_type setValid; boost::shared_mutex cs_sigcache; public: CSignatureCache() { GetRandBytes(nonce.begin(), 32); } void ComputeEntry(uint256& entry, const uint256 &hash, const std::vector& vchSig, const CPubKey& pubkey) { CSHA256().Write(nonce.begin(), 32).Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin()); } bool Get(const uint256& entry) { boost::shared_lock lock(cs_sigcache); return setValid.count(entry); } void Erase(const uint256& entry) { boost::unique_lock lock(cs_sigcache); setValid.erase(entry); } void Set(const uint256& entry) { size_t nMaxCacheSize = GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20); if (nMaxCacheSize <= 0) return; boost::unique_lock lock(cs_sigcache); while (memusage::DynamicUsage(setValid) > nMaxCacheSize) { map_type::size_type s = GetRand(setValid.bucket_count()); map_type::local_iterator it = setValid.begin(s); if (it != setValid.end(s)) { setValid.erase(*it); } } setValid.insert(entry); } }; } bool CachingTransactionSignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash) const { static CSignatureCache signatureCache; uint256 entry; signatureCache.ComputeEntry(entry, sighash, vchSig, pubkey); if (signatureCache.Get(entry)) { if (!store) { signatureCache.Erase(entry); } return true; } if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash)) return false; if (store) { signatureCache.Set(entry); } return true; }