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_VERIFY_CHECKDATASIG_SIGOPS | SCRIPT_DISALLOW_SEGWIT_RECOVERY; | |||||
/** | |||||
* 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 || flags || signature hash || public key || | //! Entries are SHA256(nonce || signature hash || public key || signature): | ||||
//! 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 std::vector<uint8_t> &vchSig, | void ComputeEntry(uint256 &entry, const uint256 &hash, | ||||
const CPubKey &pubkey, const uint256 &hash, | const std::vector<uint8_t> &vchSig, | ||||
uint32_t flags) { | const CPubKey &pubkey) { | ||||
jasonbcox: I realize this ordering is going back to what it used to be. But that begs the question why it… | |||||
markblundebergAuthorUnsubmitted Done Inline ActionsIIRC I changed it in order to match the order of its caller, VerifySignature. Perhaps we can keep that order, just take out flags. An alternative order that would also make sense is hash,pubkey,sig, which would match order of hashing. markblundeberg: IIRC I changed it in order to match the order of its caller, VerifySignature. Perhaps we can… | |||||
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 30 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, uint32_t flags, bool storeOrErase, | const uint256 &sighash, bool storeOrErase, const F &fun) { | ||||
const F &fun) { | |||||
uint256 entry; | uint256 entry; | ||||
signatureCache.ComputeEntry(entry, vchSig, pubkey, sighash, flags); | signatureCache.ComputeEntry(entry, sighash, vchSig, pubkey); | ||||
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, uint32_t flags) const { | const uint256 &sighash) const { | ||||
return RunMemoizedCheck(vchSig, pubkey, sighash, flags, true, | return RunMemoizedCheck(vchSig, pubkey, sighash, 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, uint32_t flags) const { | const uint256 &sighash) const { | ||||
return RunMemoizedCheck(vchSig, pubkey, sighash, flags, store, [&] { | return RunMemoizedCheck(vchSig, pubkey, sighash, store, [&] { | ||||
return TransactionSignatureChecker::VerifySignature(vchSig, pubkey, | return TransactionSignatureChecker::VerifySignature(vchSig, pubkey, | ||||
sighash, flags); | sighash); | ||||
}); | }); | ||||
} | } |
I realize this ordering is going back to what it used to be. But that begs the question why it was changed in the first place?