1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 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.
14 #include <boost/thread.hpp>
15 #include <boost/unordered_set.hpp>
20 * We're hashing a nonce into the entries themselves, so we don't need extra
21 * blinding in the set hash computation.
23 class CSignatureCacheHasher
26 size_t operator()(const uint256
& key
) const {
27 return key
.GetCheapHash();
32 * Valid signature cache, to avoid doing expensive ECDSA signature checking
33 * twice for every transaction (once when accepted into memory pool, and
34 * again when accepted into the block chain)
39 //! Entries are SHA256(nonce || signature hash || public key || signature):
41 typedef boost::unordered_set
<uint256
, CSignatureCacheHasher
> map_type
;
43 boost::shared_mutex cs_sigcache
;
49 GetRandBytes(nonce
.begin(), 32);
53 ComputeEntry(uint256
& entry
, const uint256
&hash
, const std::vector
<unsigned char>& vchSig
, const CPubKey
& pubkey
)
55 CSHA256().Write(nonce
.begin(), 32).Write(hash
.begin(), 32).Write(&pubkey
[0], pubkey
.size()).Write(&vchSig
[0], vchSig
.size()).Finalize(entry
.begin());
59 Get(const uint256
& entry
)
61 boost::shared_lock
<boost::shared_mutex
> lock(cs_sigcache
);
62 return setValid
.count(entry
);
65 void Erase(const uint256
& entry
)
67 boost::unique_lock
<boost::shared_mutex
> lock(cs_sigcache
);
68 setValid
.erase(entry
);
71 void Set(const uint256
& entry
)
73 size_t nMaxCacheSize
= GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE
) * ((size_t) 1 << 20);
74 if (nMaxCacheSize
<= 0) return;
76 boost::unique_lock
<boost::shared_mutex
> lock(cs_sigcache
);
77 while (memusage::DynamicUsage(setValid
) > nMaxCacheSize
)
79 map_type::size_type s
= GetRand(setValid
.bucket_count());
80 map_type::local_iterator it
= setValid
.begin(s
);
81 if (it
!= setValid
.end(s
)) {
86 setValid
.insert(entry
);
92 bool CachingTransactionSignatureChecker::VerifySignature(const std::vector
<unsigned char>& vchSig
, const CPubKey
& pubkey
, const uint256
& sighash
) const
94 static CSignatureCache signatureCache
;
97 signatureCache
.ComputeEntry(entry
, sighash
, vchSig
, pubkey
);
99 if (signatureCache
.Get(entry
)) {
101 signatureCache
.Erase(entry
);
106 if (!TransactionSignatureChecker::VerifySignature(vchSig
, pubkey
, sighash
))
110 signatureCache
.Set(entry
);