mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-12-13 22:24:05 +01:00
kernel: De-globalize signature cache
Move its ownership to the ChainstateManager class. Next to simplifying usage of the kernel library by no longer requiring manual setup of the cache prior to using validation code, it also slims down the amount of memory allocated by BasicTestingSetup. Use this opportunity to make SignatureCache RAII styled Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
#include <shared_mutex>
|
||||
#include <vector>
|
||||
|
||||
SignatureCache::SignatureCache()
|
||||
SignatureCache::SignatureCache(const size_t max_size_bytes)
|
||||
{
|
||||
uint256 nonce = GetRandHash();
|
||||
// We want the nonce to be 64 bytes long to force the hasher to process
|
||||
@@ -30,6 +30,10 @@ SignatureCache::SignatureCache()
|
||||
m_salted_hasher_ecdsa.Write(PADDING_ECDSA, 32);
|
||||
m_salted_hasher_schnorr.Write(nonce.begin(), 32);
|
||||
m_salted_hasher_schnorr.Write(PADDING_SCHNORR, 32);
|
||||
|
||||
const auto [num_elems, approx_size_bytes] = setValid.setup_bytes(max_size_bytes);
|
||||
LogPrintf("Using %zu MiB out of %zu MiB requested for signature cache, able to store %zu elements\n",
|
||||
approx_size_bytes >> 20, max_size_bytes >> 20, num_elems);
|
||||
}
|
||||
|
||||
void SignatureCache::ComputeEntryECDSA(uint256& entry, const uint256& hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey) const
|
||||
@@ -56,48 +60,25 @@ void SignatureCache::Set(const uint256& entry)
|
||||
setValid.insert(entry);
|
||||
}
|
||||
|
||||
std::pair<uint32_t, size_t> SignatureCache::setup_bytes(size_t n)
|
||||
{
|
||||
return setValid.setup_bytes(n);
|
||||
}
|
||||
|
||||
/* In previous versions of this code, signatureCache was a local static variable
|
||||
* in CachingTransactionSignatureChecker::VerifySignature. We initialize
|
||||
* signatureCache outside of VerifySignature to avoid the atomic operation per
|
||||
* call overhead associated with local static variables even though
|
||||
* signatureCache could be made local to VerifySignature.
|
||||
*/
|
||||
static SignatureCache signatureCache;
|
||||
|
||||
// To be called once in AppInitMain/BasicTestingSetup to initialize the
|
||||
// signatureCache.
|
||||
bool InitSignatureCache(size_t max_size_bytes)
|
||||
{
|
||||
const auto [num_elems, approx_size_bytes] = signatureCache.setup_bytes(max_size_bytes);
|
||||
LogPrintf("Using %zu MiB out of %zu MiB requested for signature cache, able to store %zu elements\n",
|
||||
approx_size_bytes >> 20, max_size_bytes >> 20, num_elems);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CachingTransactionSignatureChecker::VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
|
||||
{
|
||||
uint256 entry;
|
||||
signatureCache.ComputeEntryECDSA(entry, sighash, vchSig, pubkey);
|
||||
if (signatureCache.Get(entry, !store))
|
||||
m_signature_cache.ComputeEntryECDSA(entry, sighash, vchSig, pubkey);
|
||||
if (m_signature_cache.Get(entry, !store))
|
||||
return true;
|
||||
if (!TransactionSignatureChecker::VerifyECDSASignature(vchSig, pubkey, sighash))
|
||||
return false;
|
||||
if (store)
|
||||
signatureCache.Set(entry);
|
||||
m_signature_cache.Set(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CachingTransactionSignatureChecker::VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const
|
||||
{
|
||||
uint256 entry;
|
||||
signatureCache.ComputeEntrySchnorr(entry, sighash, sig, pubkey);
|
||||
if (signatureCache.Get(entry, !store)) return true;
|
||||
m_signature_cache.ComputeEntrySchnorr(entry, sighash, sig, pubkey);
|
||||
if (m_signature_cache.Get(entry, !store)) return true;
|
||||
if (!TransactionSignatureChecker::VerifySchnorrSignature(sig, pubkey, sighash)) return false;
|
||||
if (store) signatureCache.Set(entry);
|
||||
if (store) m_signature_cache.Set(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -15,21 +15,20 @@
|
||||
#include <util/hasher.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <shared_mutex>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class CPubKey;
|
||||
class CTransaction;
|
||||
class XOnlyPubKey;
|
||||
|
||||
// DoS prevention: limit cache size to 32MiB (over 1000000 entries on 64-bit
|
||||
// systems). Due to how we count cache size, actual memory usage is slightly
|
||||
// more (~32.25 MiB)
|
||||
static constexpr size_t DEFAULT_MAX_SIG_CACHE_BYTES{32 << 20};
|
||||
static constexpr size_t DEFAULT_SCRIPT_EXECUTION_CACHE_BYTES{DEFAULT_MAX_SIG_CACHE_BYTES / 2};
|
||||
|
||||
class CPubKey;
|
||||
static constexpr size_t DEFAULT_VALIDATION_CACHE_BYTES{32 << 20};
|
||||
static constexpr size_t DEFAULT_SIGNATURE_CACHE_BYTES{DEFAULT_VALIDATION_CACHE_BYTES / 2};
|
||||
static constexpr size_t DEFAULT_SCRIPT_EXECUTION_CACHE_BYTES{DEFAULT_VALIDATION_CACHE_BYTES / 2};
|
||||
static_assert(DEFAULT_VALIDATION_CACHE_BYTES == DEFAULT_SIGNATURE_CACHE_BYTES + DEFAULT_SCRIPT_EXECUTION_CACHE_BYTES);
|
||||
|
||||
/**
|
||||
* Valid signature cache, to avoid doing expensive ECDSA signature checking
|
||||
@@ -47,7 +46,10 @@ private:
|
||||
std::shared_mutex cs_sigcache;
|
||||
|
||||
public:
|
||||
SignatureCache();
|
||||
SignatureCache(size_t max_size_bytes);
|
||||
|
||||
SignatureCache(const SignatureCache&) = delete;
|
||||
SignatureCache& operator=(const SignatureCache&) = delete;
|
||||
|
||||
void ComputeEntryECDSA(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey) const;
|
||||
|
||||
@@ -56,22 +58,19 @@ public:
|
||||
bool Get(const uint256& entry, const bool erase);
|
||||
|
||||
void Set(const uint256& entry);
|
||||
|
||||
std::pair<uint32_t, size_t> setup_bytes(size_t n);
|
||||
};
|
||||
|
||||
class CachingTransactionSignatureChecker : public TransactionSignatureChecker
|
||||
{
|
||||
private:
|
||||
bool store;
|
||||
SignatureCache& m_signature_cache;
|
||||
|
||||
public:
|
||||
CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amountIn, txdataIn, MissingDataBehavior::ASSERT_FAIL), store(storeIn) {}
|
||||
CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, bool storeIn, SignatureCache& signature_cache, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amountIn, txdataIn, MissingDataBehavior::ASSERT_FAIL), store(storeIn), m_signature_cache(signature_cache) {}
|
||||
|
||||
bool VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const override;
|
||||
bool VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const override;
|
||||
};
|
||||
|
||||
[[nodiscard]] bool InitSignatureCache(size_t max_size_bytes);
|
||||
|
||||
#endif // BITCOIN_SCRIPT_SIGCACHE_H
|
||||
|
||||
Reference in New Issue
Block a user