Skip to content

Commit 06e87c2

Browse files
committed
kernel: De-globalize script execution 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.
1 parent 71774fb commit 06e87c2

File tree

11 files changed

+72
-41
lines changed

11 files changed

+72
-41
lines changed

src/bitcoin-chainstate.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ int main(int argc, char* argv[])
6868
// performing the check with the signature cache.
6969
kernel::ValidationCacheSizes validation_cache_sizes{};
7070
Assert(InitSignatureCache(validation_cache_sizes.signature_cache_bytes));
71-
Assert(InitScriptExecutionCache(validation_cache_sizes.script_execution_cache_bytes));
7271

7372
ValidationSignals validation_signals{std::make_unique<util::ImmediateTaskRunner>()};
7473

src/init.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1157,7 +1157,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
11571157
ValidationCacheSizes validation_cache_sizes{};
11581158
ApplyArgsManOptions(args, validation_cache_sizes);
11591159
(void)InitSignatureCache(validation_cache_sizes.signature_cache_bytes);
1160-
(void)InitScriptExecutionCache(validation_cache_sizes.script_execution_cache_bytes);
11611160

11621161
assert(!node.scheduler);
11631162
node.scheduler = std::make_unique<CScheduler>();

src/kernel/chainstatemanager_opts.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <arith_uint256.h>
1111
#include <dbwrapper.h>
12+
#include <script/sigcache.h>
1213
#include <txdb.h>
1314
#include <uint256.h>
1415
#include <util/time.h>
@@ -48,6 +49,7 @@ struct ChainstateManagerOpts {
4849
ValidationSignals* signals{nullptr};
4950
//! Number of script check worker threads. Zero means no parallel verification.
5051
int worker_threads_num{0};
52+
size_t script_execution_cache_bytes{DEFAULT_SCRIPT_EXECUTION_CACHE_BYTES};
5153
};
5254

5355
} // namespace kernel

src/kernel/validation_cache_sizes.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
namespace kernel {
1414
struct ValidationCacheSizes {
1515
size_t signature_cache_bytes{DEFAULT_MAX_SIG_CACHE_BYTES / 2};
16-
size_t script_execution_cache_bytes{DEFAULT_MAX_SIG_CACHE_BYTES / 2};
1716
};
1817
}
1918

src/node/chainstatemanager_args.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,15 @@ util::Result<void> ApplyArgsManOptions(const ArgsManager& args, ChainstateManage
5656
opts.worker_threads_num = std::clamp(script_threads - 1, 0, MAX_SCRIPTCHECK_THREADS);
5757
LogPrintf("Script verification uses %d additional threads\n", opts.worker_threads_num);
5858

59+
if (auto max_size = args.GetIntArg("-maxsigcachesize")) {
60+
// 1. When supplied with a max_size of 0, both the signature cache and
61+
// script execution cache create the minimum possible cache (2
62+
// elements). Therefore, we can use 0 as a floor here.
63+
// 2. Multiply first, divide after to avoid integer truncation.
64+
size_t clamped_size_each = std::max<int64_t>(*max_size, 0) * (1 << 20) / 2;
65+
opts.script_execution_cache_bytes = clamped_size_each;
66+
}
67+
5968
return {};
6069
}
6170
} // namespace node

src/node/validation_cache_args.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ void ApplyArgsManOptions(const ArgsManager& argsman, ValidationCacheSizes& cache
2727
size_t clamped_size_each = std::max<int64_t>(*max_size, 0) * (1 << 20) / 2;
2828
cache_sizes = {
2929
.signature_cache_bytes = clamped_size_each,
30-
.script_execution_cache_bytes = clamped_size_each,
3130
};
3231
}
3332
}

src/script/sigcache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// systems). Due to how we count cache size, actual memory usage is slightly
1717
// more (~32.25 MiB)
1818
static constexpr size_t DEFAULT_MAX_SIG_CACHE_BYTES{32 << 20};
19+
static constexpr size_t DEFAULT_SCRIPT_EXECUTION_CACHE_BYTES{DEFAULT_MAX_SIG_CACHE_BYTES / 2};
1920

2021
class CPubKey;
2122

src/test/txvalidationcache_tests.cpp

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,27 @@
55
#include <consensus/validation.h>
66
#include <key.h>
77
#include <random.h>
8+
#include <script/sigcache.h>
89
#include <script/sign.h>
910
#include <script/signingprovider.h>
1011
#include <test/util/setup_common.h>
1112
#include <txmempool.h>
1213
#include <util/chaintype.h>
14+
#include <util/check.h>
1315
#include <validation.h>
1416

1517
#include <boost/test/unit_test.hpp>
1618

1719
struct Dersig100Setup : public TestChain100Setup {
20+
1821
Dersig100Setup()
1922
: TestChain100Setup{ChainType::REGTEST, {"-testactivationheight=dersig@102"}} {}
2023
};
2124

2225
bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
2326
const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore,
2427
bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
28+
ValidationCache& validation_cache,
2529
std::vector<CScriptCheck>* pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
2630

2731
BOOST_AUTO_TEST_SUITE(txvalidationcache_tests)
@@ -118,7 +122,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, Dersig100Setup)
118122
// should fail.
119123
// Capture this interaction with the upgraded_nop argument: set it when evaluating
120124
// any script flag that is implemented as an upgraded NOP code.
121-
static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t failing_flags, bool add_to_cache, CCoinsViewCache& active_coins_tip) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
125+
static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t failing_flags, bool add_to_cache, CCoinsViewCache& active_coins_tip, ValidationCache& validation_cache) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
122126
{
123127
PrecomputedTransactionData txdata;
124128

@@ -140,7 +144,7 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail
140144
// WITNESS requires P2SH
141145
test_flags |= SCRIPT_VERIFY_P2SH;
142146
}
143-
bool ret = CheckInputScripts(tx, state, &active_coins_tip, test_flags, true, add_to_cache, txdata, nullptr);
147+
bool ret = CheckInputScripts(tx, state, &active_coins_tip, test_flags, true, add_to_cache, txdata, validation_cache, nullptr);
144148
// CheckInputScripts should succeed iff test_flags doesn't intersect with
145149
// failing_flags
146150
bool expected_return_value = !(test_flags & failing_flags);
@@ -150,13 +154,13 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail
150154
if (ret && add_to_cache) {
151155
// Check that we get a cache hit if the tx was valid
152156
std::vector<CScriptCheck> scriptchecks;
153-
BOOST_CHECK(CheckInputScripts(tx, state, &active_coins_tip, test_flags, true, add_to_cache, txdata, &scriptchecks));
157+
BOOST_CHECK(CheckInputScripts(tx, state, &active_coins_tip, test_flags, true, add_to_cache, txdata, validation_cache, &scriptchecks));
154158
BOOST_CHECK(scriptchecks.empty());
155159
} else {
156160
// Check that we get script executions to check, if the transaction
157161
// was invalid, or we didn't add to cache.
158162
std::vector<CScriptCheck> scriptchecks;
159-
BOOST_CHECK(CheckInputScripts(tx, state, &active_coins_tip, test_flags, true, add_to_cache, txdata, &scriptchecks));
163+
BOOST_CHECK(CheckInputScripts(tx, state, &active_coins_tip, test_flags, true, add_to_cache, txdata, validation_cache, &scriptchecks));
160164
BOOST_CHECK_EQUAL(scriptchecks.size(), tx.vin.size());
161165
}
162166
}
@@ -214,20 +218,20 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup)
214218
TxValidationState state;
215219
PrecomputedTransactionData ptd_spend_tx;
216220

217-
BOOST_CHECK(!CheckInputScripts(CTransaction(spend_tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
221+
BOOST_CHECK(!CheckInputScripts(CTransaction(spend_tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, m_node.chainman->m_validation_cache, nullptr));
218222

219223
// If we call again asking for scriptchecks (as happens in
220224
// ConnectBlock), we should add a script check object for this -- we're
221225
// not caching invalidity (if that changes, delete this test case).
222226
std::vector<CScriptCheck> scriptchecks;
223-
BOOST_CHECK(CheckInputScripts(CTransaction(spend_tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks));
227+
BOOST_CHECK(CheckInputScripts(CTransaction(spend_tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, m_node.chainman->m_validation_cache, &scriptchecks));
224228
BOOST_CHECK_EQUAL(scriptchecks.size(), 1U);
225229

226230
// Test that CheckInputScripts returns true iff DERSIG-enforcing flags are
227231
// not present. Don't add these checks to the cache, so that we can
228232
// test later that block validation works fine in the absence of cached
229233
// successes.
230-
ValidateCheckInputsForAllFlags(CTransaction(spend_tx), SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC, false, m_node.chainman->ActiveChainstate().CoinsTip());
234+
ValidateCheckInputsForAllFlags(CTransaction(spend_tx), SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC, false, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);
231235
}
232236

233237
// And if we produce a block with this tx, it should be valid (DERSIG not
@@ -253,7 +257,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup)
253257
std::vector<unsigned char> vchSig2(p2pk_scriptPubKey.begin(), p2pk_scriptPubKey.end());
254258
invalid_under_p2sh_tx.vin[0].scriptSig << vchSig2;
255259

256-
ValidateCheckInputsForAllFlags(CTransaction(invalid_under_p2sh_tx), SCRIPT_VERIFY_P2SH, true, m_node.chainman->ActiveChainstate().CoinsTip());
260+
ValidateCheckInputsForAllFlags(CTransaction(invalid_under_p2sh_tx), SCRIPT_VERIFY_P2SH, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);
257261
}
258262

259263
// Test CHECKLOCKTIMEVERIFY
@@ -276,13 +280,13 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup)
276280
vchSig.push_back((unsigned char)SIGHASH_ALL);
277281
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101;
278282

279-
ValidateCheckInputsForAllFlags(CTransaction(invalid_with_cltv_tx), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, m_node.chainman->ActiveChainstate().CoinsTip());
283+
ValidateCheckInputsForAllFlags(CTransaction(invalid_with_cltv_tx), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);
280284

281285
// Make it valid, and check again
282286
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
283287
TxValidationState state;
284288
PrecomputedTransactionData txdata;
285-
BOOST_CHECK(CheckInputScripts(CTransaction(invalid_with_cltv_tx), state, m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
289+
BOOST_CHECK(CheckInputScripts(CTransaction(invalid_with_cltv_tx), state, m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, m_node.chainman->m_validation_cache, nullptr));
286290
}
287291

288292
// TEST CHECKSEQUENCEVERIFY
@@ -304,13 +308,13 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup)
304308
vchSig.push_back((unsigned char)SIGHASH_ALL);
305309
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101;
306310

307-
ValidateCheckInputsForAllFlags(CTransaction(invalid_with_csv_tx), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, m_node.chainman->ActiveChainstate().CoinsTip());
311+
ValidateCheckInputsForAllFlags(CTransaction(invalid_with_csv_tx), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);
308312

309313
// Make it valid, and check again
310314
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
311315
TxValidationState state;
312316
PrecomputedTransactionData txdata;
313-
BOOST_CHECK(CheckInputScripts(CTransaction(invalid_with_csv_tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
317+
BOOST_CHECK(CheckInputScripts(CTransaction(invalid_with_csv_tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, m_node.chainman->m_validation_cache, nullptr));
314318
}
315319

316320
// TODO: add tests for remaining script flags
@@ -333,11 +337,11 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup)
333337
UpdateInput(valid_with_witness_tx.vin[0], sigdata);
334338

335339
// This should be valid under all script flags.
336-
ValidateCheckInputsForAllFlags(CTransaction(valid_with_witness_tx), 0, true, m_node.chainman->ActiveChainstate().CoinsTip());
340+
ValidateCheckInputsForAllFlags(CTransaction(valid_with_witness_tx), 0, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);
337341

338342
// Remove the witness, and check that it is now invalid.
339343
valid_with_witness_tx.vin[0].scriptWitness.SetNull();
340-
ValidateCheckInputsForAllFlags(CTransaction(valid_with_witness_tx), SCRIPT_VERIFY_WITNESS, true, m_node.chainman->ActiveChainstate().CoinsTip());
344+
ValidateCheckInputsForAllFlags(CTransaction(valid_with_witness_tx), SCRIPT_VERIFY_WITNESS, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);
341345
}
342346

343347
{
@@ -362,7 +366,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup)
362366
}
363367

364368
// This should be valid under all script flags
365-
ValidateCheckInputsForAllFlags(CTransaction(tx), 0, true, m_node.chainman->ActiveChainstate().CoinsTip());
369+
ValidateCheckInputsForAllFlags(CTransaction(tx), 0, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);
366370

367371
// Check that if the second input is invalid, but the first input is
368372
// valid, the transaction is not cached.
@@ -372,12 +376,12 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup)
372376
TxValidationState state;
373377
PrecomputedTransactionData txdata;
374378
// This transaction is now invalid under segwit, because of the second input.
375-
BOOST_CHECK(!CheckInputScripts(CTransaction(tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr));
379+
BOOST_CHECK(!CheckInputScripts(CTransaction(tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, m_node.chainman->m_validation_cache, nullptr));
376380

377381
std::vector<CScriptCheck> scriptchecks;
378382
// Make sure this transaction was not cached (ie because the first
379383
// input was valid)
380-
BOOST_CHECK(CheckInputScripts(CTransaction(tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, &scriptchecks));
384+
BOOST_CHECK(CheckInputScripts(CTransaction(tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, m_node.chainman->m_validation_cache, &scriptchecks));
381385
// Should get 2 script checks back -- caching is on a whole-transaction basis.
382386
BOOST_CHECK_EQUAL(scriptchecks.size(), 2U);
383387
}

src/test/util/setup_common.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,6 @@ BasicTestingSetup::BasicTestingSetup(const ChainType chainType, const std::vecto
191191
ValidationCacheSizes validation_cache_sizes{};
192192
ApplyArgsManOptions(*m_node.args, validation_cache_sizes);
193193
Assert(InitSignatureCache(validation_cache_sizes.signature_cache_bytes));
194-
Assert(InitScriptExecutionCache(validation_cache_sizes.script_execution_cache_bytes));
195194

196195
m_node.chain = interfaces::MakeChain(m_node);
197196
static bool noui_connected = false;

0 commit comments

Comments
 (0)