Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto 2 : // Copyright (c) 2009-2014 The Bitcoin developers 3 : // Copyright (c) 2018-2021 The PIVX Core developers 4 : // Distributed under the MIT software license, see the accompanying 5 : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 6 : 7 : #include "sigcache.h" 8 : 9 : #include "cuckoocache.h" 10 : #include "memusage.h" 11 : #include "pubkey.h" 12 : #include "random.h" 13 : #include "uint256.h" 14 : #include "util/system.h" 15 : 16 : #include <boost/thread/thread.hpp> 17 : 18 : namespace { 19 : /** 20 : * Valid signature cache, to avoid doing expensive ECDSA signature checking 21 : * twice for every transaction (once when accepted into memory pool, and 22 : * again when accepted into the block chain) 23 : */ 24 : class CSignatureCache 25 : { 26 : private: 27 : //! Entries are SHA256(nonce || signature hash || public key || signature): 28 : uint256 nonce; 29 : typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type; 30 : map_type setValid; 31 : boost::shared_mutex cs_sigcache; 32 : 33 : public: 34 479 : CSignatureCache() 35 958 : { 36 479 : GetRandBytes(nonce.begin(), 32); 37 479 : } 38 : 39 : void 40 1419348 : ComputeEntry(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey) 41 : { 42 1423848 : CSHA256().Write(nonce.begin(), 32).Write(hash.begin(), 32).Write(pubkey.data(), pubkey.size()).Write(vchSig.data(), vchSig.size()).Finalize(entry.begin()); 43 1419348 : } 44 : 45 : bool 46 1419348 : Get(const uint256& entry, const bool erase) 47 : { 48 1419348 : boost::shared_lock<boost::shared_mutex> lock(cs_sigcache); 49 1419348 : return setValid.contains(entry, erase); 50 : } 51 : 52 211326 : void Set(uint256& entry) 53 : { 54 211326 : boost::unique_lock<boost::shared_mutex> lock(cs_sigcache); 55 211326 : setValid.insert(entry); 56 211326 : } 57 791 : uint32_t setup_bytes(size_t n) 58 : { 59 1582 : return setValid.setup_bytes(n); 60 : } 61 : }; 62 : 63 : /* In previous versions of this code, signatureCache was a local static variable 64 : * in CachingTransactionSignatureChecker::VerifySignature. We initialize 65 : * signatureCache outside of VerifySignature to avoid the atomic operation per 66 : * call overhead associated with local static variables even though 67 : * signatureCache could be made local to VerifySignature. 68 : */ 69 : static CSignatureCache signatureCache; 70 : } 71 : 72 : // To be called once in AppInitMain/BasicTestingSetup to initialize the 73 : // signatureCache. 74 791 : void InitSignatureCache() 75 : { 76 : // nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero, 77 : // setup_bytes creates the minimum possible cache (2 elements). 78 1582 : size_t nMaxCacheSize = std::min(std::max((int64_t)0, gArgs.GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE)), MAX_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20); 79 791 : size_t nElems = signatureCache.setup_bytes(nMaxCacheSize); 80 791 : LogPrintf("Using %zu MiB out of %zu requested for signature cache, able to store %zu elements\n", 81 791 : (nElems*sizeof(uint256)) >>20, nMaxCacheSize>>20, nElems); 82 791 : } 83 : 84 1419348 : bool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const 85 : { 86 1419348 : uint256 entry; 87 1419348 : signatureCache.ComputeEntry(entry, sighash, vchSig, pubkey); 88 1419348 : if (signatureCache.Get(entry, !store)) 89 : return true; 90 397519 : if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash)) 91 : return false; 92 397508 : if (store) 93 211326 : signatureCache.Set(entry); 94 : return true; 95 : }