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:
TheCharlatan 2024-05-18 11:18:44 +02:00
parent 66d74bfc45
commit 606a7ab862
No known key found for this signature in database
GPG Key ID: 9B79B45691DB4173
17 changed files with 54 additions and 153 deletions

View File

@ -195,7 +195,6 @@ BITCOIN_CORE_H = \
kernel/mempool_removal_reason.h \
kernel/messagestartchars.h \
kernel/notifications_interface.h \
kernel/validation_cache_sizes.h \
kernel/warning.h \
key.h \
key_io.h \
@ -240,7 +239,6 @@ BITCOIN_CORE_H = \
node/txreconciliation.h \
node/types.h \
node/utxo_snapshot.h \
node/validation_cache_args.h \
node/warnings.h \
noui.h \
outputtype.h \
@ -445,7 +443,6 @@ libbitcoin_node_a_SOURCES = \
node/transaction.cpp \
node/txreconciliation.cpp \
node/utxo_snapshot.cpp \
node/validation_cache_args.cpp \
node/warnings.cpp \
noui.cpp \
policy/v3_policy.cpp \

View File

@ -15,7 +15,6 @@
#include <kernel/chainstatemanager_opts.h>
#include <kernel/checks.h>
#include <kernel/context.h>
#include <kernel/validation_cache_sizes.h>
#include <kernel/warning.h>
#include <consensus/validation.h>
@ -63,12 +62,6 @@ int main(int argc, char* argv[])
// properly
assert(kernel::SanityChecks(kernel_context));
// Necessary for CheckInputScripts (eventually called by ProcessNewBlock),
// which will try the script cache first and fall back to actually
// performing the check with the signature cache.
kernel::ValidationCacheSizes validation_cache_sizes{};
Assert(InitSignatureCache(validation_cache_sizes.signature_cache_bytes));
ValidationSignals validation_signals{std::make_unique<util::ImmediateTaskRunner>()};
class KernelNotifications : public kernel::Notifications

View File

@ -8,7 +8,6 @@
#include <init.h>
#include <kernel/checks.h>
#include <kernel/validation_cache_sizes.h>
#include <addrman.h>
#include <banman.h>
@ -54,7 +53,6 @@
#include <node/mempool_persist_args.h>
#include <node/miner.h>
#include <node/peerman_args.h>
#include <node/validation_cache_args.h>
#include <policy/feerate.h>
#include <policy/fees.h>
#include <policy/fees_args.h>
@ -119,7 +117,6 @@
using common::AmountErrMsg;
using common::InvalidPortErrMsg;
using common::ResolveErrMsg;
using kernel::ValidationCacheSizes;
using node::ApplyArgsManOptions;
using node::BlockManager;
@ -619,7 +616,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-test=<option>", "Pass a test-only option. Options include : " + Join(TEST_OPTIONS_DOC, ", ") + ".", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-capturemessages", "Capture all P2P messages to disk", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-mocktime=<n>", "Replace actual time with " + UNIX_EPOCH_TIME + " (default: 0)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_BYTES >> 20), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_VALIDATION_CACHE_BYTES >> 20), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-maxtipage=<n>",
strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)",
Ticks<std::chrono::seconds>(DEFAULT_MAX_TIP_AGE)),
@ -1154,10 +1151,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
args.GetArg("-datadir", ""), fs::PathToString(fs::current_path()));
}
ValidationCacheSizes validation_cache_sizes{};
ApplyArgsManOptions(args, validation_cache_sizes);
(void)InitSignatureCache(validation_cache_sizes.signature_cache_bytes);
assert(!node.scheduler);
node.scheduler = std::make_unique<CScheduler>();
auto& scheduler = *node.scheduler;

View File

@ -50,6 +50,7 @@ struct ChainstateManagerOpts {
//! Number of script check worker threads. Zero means no parallel verification.
int worker_threads_num{0};
size_t script_execution_cache_bytes{DEFAULT_SCRIPT_EXECUTION_CACHE_BYTES};
size_t signature_cache_bytes{DEFAULT_SIGNATURE_CACHE_BYTES};
};
} // namespace kernel

View File

@ -1,19 +0,0 @@
// Copyright (c) 2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_KERNEL_VALIDATION_CACHE_SIZES_H
#define BITCOIN_KERNEL_VALIDATION_CACHE_SIZES_H
#include <script/sigcache.h>
#include <cstddef>
#include <limits>
namespace kernel {
struct ValidationCacheSizes {
size_t signature_cache_bytes{DEFAULT_MAX_SIG_CACHE_BYTES / 2};
};
}
#endif // BITCOIN_KERNEL_VALIDATION_CACHE_SIZES_H

View File

@ -63,6 +63,7 @@ util::Result<void> ApplyArgsManOptions(const ArgsManager& args, ChainstateManage
// 2. Multiply first, divide after to avoid integer truncation.
size_t clamped_size_each = std::max<int64_t>(*max_size, 0) * (1 << 20) / 2;
opts.script_execution_cache_bytes = clamped_size_each;
opts.signature_cache_bytes = clamped_size_each;
}
return {};

View File

@ -1,33 +0,0 @@
// Copyright (c) 2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <node/validation_cache_args.h>
#include <kernel/validation_cache_sizes.h>
#include <common/args.h>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
using kernel::ValidationCacheSizes;
namespace node {
void ApplyArgsManOptions(const ArgsManager& argsman, ValidationCacheSizes& cache_sizes)
{
if (auto max_size = argsman.GetIntArg("-maxsigcachesize")) {
// 1. When supplied with a max_size of 0, both InitSignatureCache and
// InitScriptExecutionCache create the minimum possible cache (2
// elements). Therefore, we can use 0 as a floor here.
// 2. Multiply first, divide after to avoid integer truncation.
size_t clamped_size_each = std::max<int64_t>(*max_size, 0) * (1 << 20) / 2;
cache_sizes = {
.signature_cache_bytes = clamped_size_each,
};
}
}
} // namespace node

View File

@ -1,17 +0,0 @@
// Copyright (c) 2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_NODE_VALIDATION_CACHE_ARGS_H
#define BITCOIN_NODE_VALIDATION_CACHE_ARGS_H
class ArgsManager;
namespace kernel {
struct ValidationCacheSizes;
};
namespace node {
void ApplyArgsManOptions(const ArgsManager& argsman, kernel::ValidationCacheSizes& cache_sizes);
} // namespace node
#endif // BITCOIN_NODE_VALIDATION_CACHE_ARGS_H

View File

@ -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;
}

View File

@ -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

View File

@ -18,12 +18,15 @@
namespace {
const BasicTestingSetup* g_setup;
SignatureCache* g_signature_cache;
} // namespace
void initialize_script_sigcache()
{
static const auto testing_setup = MakeNoLogFileContext<>();
static SignatureCache signature_cache{DEFAULT_SIGNATURE_CACHE_BYTES};
g_setup = testing_setup.get();
g_signature_cache = &signature_cache;
}
FUZZ_TARGET(script_sigcache, .init = initialize_script_sigcache)
@ -36,7 +39,7 @@ FUZZ_TARGET(script_sigcache, .init = initialize_script_sigcache)
const CAmount amount = ConsumeMoney(fuzzed_data_provider);
const bool store = fuzzed_data_provider.ConsumeBool();
PrecomputedTransactionData tx_data;
CachingTransactionSignatureChecker caching_transaction_signature_checker{mutable_transaction ? &tx : nullptr, n_in, amount, store, tx_data};
CachingTransactionSignatureChecker caching_transaction_signature_checker{mutable_transaction ? &tx : nullptr, n_in, amount, store, *g_signature_cache, tx_data};
if (fuzzed_data_provider.ConsumeBool()) {
const auto random_bytes = fuzzed_data_provider.ConsumeBytes<unsigned char>(64);
const XOnlyPubKey pub_key(ConsumeUInt256(fuzzed_data_provider));

View File

@ -113,13 +113,14 @@ BOOST_AUTO_TEST_CASE(sign)
}
// All of the above should be OK, and the txTos have valid signatures
// Check to make sure signature verification fails if we use the wrong ScriptSig:
SignatureCache signature_cache{DEFAULT_SIGNATURE_CACHE_BYTES};
for (int i = 0; i < 8; i++) {
PrecomputedTransactionData txdata(txTo[i]);
for (int j = 0; j < 8; j++)
{
CScript sigSave = txTo[i].vin[0].scriptSig;
txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
bool sigOK = CScriptCheck(txFrom.vout[txTo[i].vin[0].prevout.n], CTransaction(txTo[i]), 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata)();
bool sigOK = CScriptCheck(txFrom.vout[txTo[i].vin[0].prevout.n], CTransaction(txTo[i]), signature_cache, 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata)();
if (i == j)
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
else

View File

@ -1526,7 +1526,7 @@ static std::vector<unsigned int> AllConsensusFlags()
/** Precomputed list of all valid combinations of consensus-relevant script validation flags. */
static const std::vector<unsigned int> ALL_CONSENSUS_FLAGS = AllConsensusFlags();
static void AssetTest(const UniValue& test)
static void AssetTest(const UniValue& test, SignatureCache& signature_cache)
{
BOOST_CHECK(test.isObject());
@ -1543,7 +1543,7 @@ static void AssetTest(const UniValue& test)
CTransaction tx(mtx);
PrecomputedTransactionData txdata;
txdata.Init(tx, std::vector<CTxOut>(prevouts));
CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, txdata);
CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, signature_cache, txdata);
for (const auto flags : ALL_CONSENSUS_FLAGS) {
// "final": true tests are valid for all flags. Others are only valid with flags that are
@ -1561,7 +1561,7 @@ static void AssetTest(const UniValue& test)
CTransaction tx(mtx);
PrecomputedTransactionData txdata;
txdata.Init(tx, std::vector<CTxOut>(prevouts));
CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, txdata);
CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, signature_cache, txdata);
for (const auto flags : ALL_CONSENSUS_FLAGS) {
// If a test is supposed to fail with test_flags, it should also fail with any superset thereof.
@ -1577,6 +1577,7 @@ BOOST_AUTO_TEST_CASE(script_assets_test)
{
// See src/test/fuzz/script_assets_test_minimizer.cpp for information on how to generate
// the script_assets_test.json file used by this test.
SignatureCache signature_cache{DEFAULT_SIGNATURE_CACHE_BYTES};
const char* dir = std::getenv("DIR_UNIT_TEST_DATA");
BOOST_WARN_MESSAGE(dir != nullptr, "Variable DIR_UNIT_TEST_DATA unset, skipping script_assets_test");
@ -1597,7 +1598,7 @@ BOOST_AUTO_TEST_CASE(script_assets_test)
BOOST_CHECK(tests.size() > 0);
for (size_t i = 0; i < tests.size(); i++) {
AssetTest(tests[i]);
AssetTest(tests[i], signature_cache);
}
file.close();
}

View File

@ -17,6 +17,7 @@
#include <policy/settings.h>
#include <script/script.h>
#include <script/script_error.h>
#include <script/sigcache.h>
#include <script/sign.h>
#include <script/signingprovider.h>
#include <script/solver.h>
@ -578,9 +579,11 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction)
coins.emplace_back(std::move(coin));
}
SignatureCache signature_cache{DEFAULT_SIGNATURE_CACHE_BYTES};
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
std::vector<CScriptCheck> vChecks;
vChecks.emplace_back(coins[tx.vin[i].prevout.n].out, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata);
vChecks.emplace_back(coins[tx.vin[i].prevout.n].out, tx, signature_cache, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata);
control.Add(std::move(vChecks));
}

View File

@ -6,8 +6,6 @@
#include <test/util/setup_common.h>
#include <kernel/validation_cache_sizes.h>
#include <addrman.h>
#include <banman.h>
#include <chainparams.h>
@ -30,7 +28,6 @@
#include <node/mempool_args.h>
#include <node/miner.h>
#include <node/peerman_args.h>
#include <node/validation_cache_args.h>
#include <node/warnings.h>
#include <noui.h>
#include <policy/fees.h>
@ -68,7 +65,6 @@
#include <stdexcept>
using kernel::BlockTreeDB;
using kernel::ValidationCacheSizes;
using node::ApplyArgsManOptions;
using node::BlockAssembler;
using node::BlockManager;
@ -188,10 +184,6 @@ BasicTestingSetup::BasicTestingSetup(const ChainType chainType, const std::vecto
m_node.ecc_context = std::make_unique<ECC_Context>();
SetupEnvironment();
ValidationCacheSizes validation_cache_sizes{};
ApplyArgsManOptions(*m_node.args, validation_cache_sizes);
Assert(InitSignatureCache(validation_cache_sizes.signature_cache_bytes));
m_node.chain = interfaces::MakeChain(m_node);
static bool noui_connected = false;
if (!noui_connected) {

View File

@ -2091,10 +2091,11 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund
bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
const CScriptWitness *witness = &ptxTo->vin[nIn].scriptWitness;
return VerifyScript(scriptSig, m_tx_out.scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, m_tx_out.nValue, cacheStore, *txdata), &error);
return VerifyScript(scriptSig, m_tx_out.scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, m_tx_out.nValue, cacheStore, *m_signature_cache, *txdata), &error);
}
ValidationCache::ValidationCache(const size_t script_execution_cache_bytes)
ValidationCache::ValidationCache(const size_t script_execution_cache_bytes, const size_t signature_cache_bytes)
: m_signature_cache{signature_cache_bytes}
{
// Setup the salted hasher
uint256 nonce = GetRandHash();
@ -2176,7 +2177,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
// spent being checked as a part of CScriptCheck.
// Verify signature
CScriptCheck check(txdata.m_spent_outputs[i], tx, i, flags, cacheSigStore, &txdata);
CScriptCheck check(txdata.m_spent_outputs[i], tx, validation_cache.m_signature_cache, i, flags, cacheSigStore, &txdata);
if (pvChecks) {
pvChecks->emplace_back(std::move(check));
} else if (!check()) {
@ -2189,7 +2190,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
// splitting the network between upgraded and
// non-upgraded nodes by banning CONSENSUS-failing
// data providers.
CScriptCheck check2(txdata.m_spent_outputs[i], tx, i,
CScriptCheck check2(txdata.m_spent_outputs[i], tx, validation_cache.m_signature_cache, i,
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore, &txdata);
if (check2())
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
@ -6231,7 +6232,7 @@ ChainstateManager::ChainstateManager(const util::SignalInterrupt& interrupt, Opt
m_interrupt{interrupt},
m_options{Flatten(std::move(options))},
m_blockman{interrupt, std::move(blockman_options)},
m_validation_cache{m_options.script_execution_cache_bytes}
m_validation_cache{m_options.script_execution_cache_bytes, m_options.signature_cache_bytes}
{
}

View File

@ -22,6 +22,7 @@
#include <policy/packages.h>
#include <policy/policy.h>
#include <script/script_error.h>
#include <script/sigcache.h>
#include <sync.h>
#include <txdb.h>
#include <txmempool.h> // For CTxMemPool::cs
@ -341,10 +342,11 @@ private:
bool cacheStore;
ScriptError error{SCRIPT_ERR_UNKNOWN_ERROR};
PrecomputedTransactionData *txdata;
SignatureCache* m_signature_cache;
public:
CScriptCheck(const CTxOut& outIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), txdata(txdataIn) { }
CScriptCheck(const CTxOut& outIn, const CTransaction& txToIn, SignatureCache& signature_cache, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), txdata(txdataIn), m_signature_cache(&signature_cache) { }
CScriptCheck(const CScriptCheck&) = delete;
CScriptCheck& operator=(const CScriptCheck&) = delete;
@ -362,7 +364,8 @@ static_assert(std::is_nothrow_move_constructible_v<CScriptCheck>);
static_assert(std::is_nothrow_destructible_v<CScriptCheck>);
/**
* Convenience class for initializing and passing the script execution cache.
* Convenience class for initializing and passing the script execution cache
* and signature cache.
*/
class ValidationCache
{
@ -372,8 +375,9 @@ private:
public:
CuckooCache::cache<uint256, SignatureCacheHasher> m_script_execution_cache;
SignatureCache m_signature_cache;
ValidationCache(size_t script_execution_cache_bytes);
ValidationCache(size_t script_execution_cache_bytes, size_t signature_cache_bytes);
ValidationCache(const ValidationCache&) = delete;
ValidationCache& operator=(const ValidationCache&) = delete;