Changeset View
Changeset View
Standalone View
Standalone View
src/script/sigcache.cpp
Show All 11 Lines | |||||
#include "uint256.h" | #include "uint256.h" | ||||
#include "util.h" | #include "util.h" | ||||
#include <boost/thread/shared_mutex.hpp> | #include <boost/thread/shared_mutex.hpp> | ||||
namespace { | namespace { | ||||
/** | /** | ||||
* Declare which flags absolutely do not affect VerifySignature() result. | |||||
* We this to reduce unnecessary cache misses (such as when policy and consensus | |||||
* flags differ on unrelated aspects). | |||||
*/ | |||||
static const uint32_t INVARIANT_FLAGS = | |||||
SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC | SCRIPT_VERIFY_DERSIG | | |||||
SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_NULLDUMMY | SCRIPT_VERIFY_SIGPUSHONLY | | |||||
SCRIPT_VERIFY_MINIMALDATA | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS | | |||||
SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | | |||||
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY | SCRIPT_VERIFY_MINIMALIF | | |||||
SCRIPT_VERIFY_NULLFAIL | SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE | | |||||
SCRIPT_ENABLE_SIGHASH_FORKID | SCRIPT_ENABLE_REPLAY_PROTECTION | | |||||
SCRIPT_ENABLE_CHECKDATASIG; | |||||
/** | |||||
* Valid signature cache, to avoid doing expensive ECDSA signature checking | * Valid signature cache, to avoid doing expensive ECDSA signature checking | ||||
* twice for every transaction (once when accepted into memory pool, and | * twice for every transaction (once when accepted into memory pool, and | ||||
* again when accepted into the block chain) | * again when accepted into the block chain) | ||||
*/ | */ | ||||
class CSignatureCache { | class CSignatureCache { | ||||
private: | private: | ||||
//! Entries are SHA256(nonce || signature hash || public key || signature): | //! Entries are SHA256(nonce || flags || signature hash || public key || | ||||
//! signature): | |||||
uint256 nonce; | uint256 nonce; | ||||
typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type; | typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type; | ||||
map_type setValid; | map_type setValid; | ||||
boost::shared_mutex cs_sigcache; | boost::shared_mutex cs_sigcache; | ||||
public: | public: | ||||
CSignatureCache() { GetRandBytes(nonce.begin(), 32); } | CSignatureCache() { GetRandBytes(nonce.begin(), 32); } | ||||
void ComputeEntry(uint256 &entry, const uint256 &hash, | void ComputeEntry(uint256 &entry, const std::vector<uint8_t> &vchSig, | ||||
const std::vector<uint8_t> &vchSig, | const CPubKey &pubkey, const uint256 &hash, | ||||
const CPubKey &pubkey) { | uint32_t flags) { | ||||
flags &= ~INVARIANT_FLAGS; | |||||
CSHA256() | CSHA256() | ||||
.Write(nonce.begin(), 32) | .Write(nonce.begin(), 32) | ||||
.Write(reinterpret_cast<uint8_t *>(&flags), sizeof(flags)) | |||||
.Write(hash.begin(), 32) | .Write(hash.begin(), 32) | ||||
.Write(&pubkey[0], pubkey.size()) | .Write(&pubkey[0], pubkey.size()) | ||||
.Write(&vchSig[0], vchSig.size()) | .Write(&vchSig[0], vchSig.size()) | ||||
.Finalize(entry.begin()); | .Finalize(entry.begin()); | ||||
} | } | ||||
bool Get(const uint256 &entry, const bool erase) { | bool Get(const uint256 &entry, const bool erase) { | ||||
boost::shared_lock<boost::shared_mutex> lock(cs_sigcache); | boost::shared_lock<boost::shared_mutex> lock(cs_sigcache); | ||||
Show All 29 Lines | void InitSignatureCache() { | ||||
size_t nElems = signatureCache.setup_bytes(nMaxCacheSize); | size_t nElems = signatureCache.setup_bytes(nMaxCacheSize); | ||||
LogPrintf("Using %zu MiB out of %zu requested for signature cache, able to " | LogPrintf("Using %zu MiB out of %zu requested for signature cache, able to " | ||||
"store %zu elements\n", | "store %zu elements\n", | ||||
(nElems * sizeof(uint256)) >> 20, nMaxCacheSize >> 20, nElems); | (nElems * sizeof(uint256)) >> 20, nMaxCacheSize >> 20, nElems); | ||||
} | } | ||||
template <typename F> | template <typename F> | ||||
bool RunMemoizedCheck(const std::vector<uint8_t> &vchSig, const CPubKey &pubkey, | bool RunMemoizedCheck(const std::vector<uint8_t> &vchSig, const CPubKey &pubkey, | ||||
const uint256 &sighash, bool storeOrErase, const F &fun) { | const uint256 &sighash, uint32_t flags, bool storeOrErase, | ||||
const F &fun) { | |||||
uint256 entry; | uint256 entry; | ||||
signatureCache.ComputeEntry(entry, sighash, vchSig, pubkey); | signatureCache.ComputeEntry(entry, vchSig, pubkey, sighash, flags); | ||||
if (signatureCache.Get(entry, !storeOrErase)) { | if (signatureCache.Get(entry, !storeOrErase)) { | ||||
return true; | return true; | ||||
} | } | ||||
if (!fun()) { | if (!fun()) { | ||||
return false; | return false; | ||||
} | } | ||||
if (storeOrErase) { | if (storeOrErase) { | ||||
signatureCache.Set(entry); | signatureCache.Set(entry); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CachingTransactionSignatureChecker::IsCached( | bool CachingTransactionSignatureChecker::IsCached( | ||||
const std::vector<uint8_t> &vchSig, const CPubKey &pubkey, | const std::vector<uint8_t> &vchSig, const CPubKey &pubkey, | ||||
const uint256 &sighash) const { | const uint256 &sighash, uint32_t flags) const { | ||||
return RunMemoizedCheck(vchSig, pubkey, sighash, true, | return RunMemoizedCheck(vchSig, pubkey, sighash, flags, true, | ||||
[] { return false; }); | [] { return false; }); | ||||
} | } | ||||
bool CachingTransactionSignatureChecker::VerifySignature( | bool CachingTransactionSignatureChecker::VerifySignature( | ||||
const std::vector<uint8_t> &vchSig, const CPubKey &pubkey, | const std::vector<uint8_t> &vchSig, const CPubKey &pubkey, | ||||
const uint256 &sighash) const { | const uint256 &sighash, uint32_t flags) const { | ||||
return RunMemoizedCheck(vchSig, pubkey, sighash, store, [&] { | return RunMemoizedCheck(vchSig, pubkey, sighash, flags, store, [&] { | ||||
return TransactionSignatureChecker::VerifySignature(vchSig, pubkey, | return TransactionSignatureChecker::VerifySignature(vchSig, pubkey, | ||||
sighash); | sighash, flags); | ||||
}); | }); | ||||
} | } |