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