Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
txvalidationcache_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
6#include <key.h>
7#include <random.h>
8#include <script/sigcache.h>
9#include <script/sign.h>
12#include <txmempool.h>
13#include <util/chaintype.h>
14#include <validation.h>
15
16#include <boost/test/unit_test.hpp>
17
20 : TestChain100Setup{ChainType::REGTEST, {.extra_args = {"-testactivationheight=dersig@102"}}} {}
21};
22
24
26{
27 // Make sure skipping validation of transactions that were
28 // validated going into the memory pool does not allow
29 // double-spends in blocks to pass validation when they should not.
30
31 CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
32
33 const auto ToMemPool = [this](const CMutableTransaction& tx) {
35
36 const MempoolAcceptResult result = m_node.chainman->ProcessTransaction(MakeTransactionRef(tx));
38 };
39
40 // Create a double-spend of mature coinbase txn:
41 std::vector<CMutableTransaction> spends;
42 spends.resize(2);
43 for (int i = 0; i < 2; i++)
44 {
45 spends[i].version = 1;
46 spends[i].vin = {CTxIn{m_coinbase_txns[0]->GetHash(), 0}};
47 spends[i].vout = {CTxOut{11*CENT, scriptPubKey}};
48
49 // Sign:
50 std::vector<unsigned char> vchSig;
51 uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL, 0, SigVersion::BASE);
52 BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
53 vchSig.push_back((unsigned char)SIGHASH_ALL);
54 spends[i].vin[0].scriptSig << vchSig;
55 }
56
57 CBlock block;
58
59 // Test 1: block with both of those transactions should be rejected.
60 block = CreateAndProcessBlock(spends, scriptPubKey);
61 {
63 BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->GetBlockHash() != block.GetHash());
64 }
65
66 // Test 2: ... and should be rejected if spend1 is in the memory pool
68 block = CreateAndProcessBlock(spends, scriptPubKey);
69 {
71 BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->GetBlockHash() != block.GetHash());
72 }
73 BOOST_CHECK_EQUAL(m_node.mempool->size(), 1U);
76
77 // Test 3: ... and should be rejected if spend2 is in the memory pool
79 block = CreateAndProcessBlock(spends, scriptPubKey);
80 {
82 BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->GetBlockHash() != block.GetHash());
83 }
84 BOOST_CHECK_EQUAL(m_node.mempool->size(), 1U);
87
88 // Final sanity test: first spend in *m_node.mempool, second in block, that's OK:
89 std::vector<CMutableTransaction> oneSpend;
90 oneSpend.push_back(spends[0]);
92 block = CreateAndProcessBlock(oneSpend, scriptPubKey);
93 {
95 BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->GetBlockHash() == block.GetHash());
96 }
97 // spends[1] should have been removed from the mempool when the
98 // block with spends[0] is accepted:
100}
101
102// Run CheckInputScripts (using CoinsTip()) on the given transaction, for all script
103// flags. Test that CheckInputScripts passes for all flags that don't overlap with
104// the failing_flags argument, but otherwise fails.
105// CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY (and future NOP codes that may
106// get reassigned) have an interaction with DISCOURAGE_UPGRADABLE_NOPS: if
107// the script flags used contain DISCOURAGE_UPGRADABLE_NOPS but don't contain
108// CHECKLOCKTIMEVERIFY (or CHECKSEQUENCEVERIFY), but the script does contain
109// OP_CHECKLOCKTIMEVERIFY (or OP_CHECKSEQUENCEVERIFY), then script execution
110// should fail.
112{
114
116
117 for (int count = 0; count < 10000; ++count) {
118 TxValidationState state;
119
120 // Randomly selects flag combinations
122
123 // Filter out incompatible flag choices
125 // CLEANSTACK requires P2SH and WITNESS, see VerifyScript() in
126 // script/interpreter.cpp
128 }
130 // TAPROOT requires WITNESS
132 }
134 // WITNESS requires P2SH
136 }
138 // CheckInputScripts should succeed iff test_flags doesn't intersect with
139 // failing_flags
142
143 // Test the caching
144 if (ret && add_to_cache) {
145 // Check that we get a cache hit if the tx was valid
146 std::vector<CScriptCheck> scriptchecks;
148 BOOST_CHECK(scriptchecks.empty());
149 } else {
150 // Check that we get script executions to check, if the transaction
151 // was invalid, or we didn't add to cache.
152 std::vector<CScriptCheck> scriptchecks;
154 BOOST_CHECK_EQUAL(scriptchecks.size(), tx.vin.size());
155 }
156 }
157}
158
160{
161 // Test that passing CheckInputScripts with one set of script flags doesn't imply
162 // that we would pass again with a different set of flags.
163 CScript p2pk_scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
165 CScript p2pkh_scriptPubKey = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey()));
168
170 BOOST_CHECK(keystore.AddKey(coinbaseKey));
172
173 // flags to test: SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, SCRIPT_VERIFY_CHECKSEQUENCE_VERIFY, SCRIPT_VERIFY_NULLDUMMY, uncompressed pubkey thing
174
175 // Create 2 outputs that match the three scripts above, spending the first
176 // coinbase tx.
178
179 spend_tx.version = 1;
180 spend_tx.vin = {CTxIn{m_coinbase_txns[0]->GetHash(), 0}};
181 spend_tx.vout = {
184 CTxOut{11*CENT, CScript() << OP_CHECKLOCKTIMEVERIFY << OP_DROP << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG},
185 CTxOut{11*CENT, CScript() << OP_CHECKSEQUENCEVERIFY << OP_DROP << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG},
187 };
188
189 // Sign, with a non-DER signature
190 {
191 std::vector<unsigned char> vchSig;
193 BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
194 vchSig.push_back((unsigned char) 0); // padding byte makes this non-DER
195 vchSig.push_back((unsigned char)SIGHASH_ALL);
196 spend_tx.vin[0].scriptSig << vchSig;
197 }
198
199 // Test that invalidity under a set of flags doesn't preclude validity
200 // under other (eg consensus) flags.
201 // spend_tx is invalid according to DERSIG
202 {
203 LOCK(cs_main);
204
205 TxValidationState state;
207
208 BOOST_CHECK(!CheckInputScripts(CTransaction(spend_tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, CheckInputScriptsFor::Mempool, true, true, ptd_spend_tx, m_node.chainman->m_validation_cache, nullptr));
209
210 // If we call again asking for scriptchecks (as happens in
211 // ConnectBlock), we should add a script check object for this -- we're
212 // not caching invalidity (if that changes, delete this test case).
213 std::vector<CScriptCheck> scriptchecks;
216
217 // Test that CheckInputScripts returns true iff DERSIG-enforcing flags are
218 // not present. Don't add these checks to the cache, so that we can
219 // test later that block validation works fine in the absence of cached
220 // successes.
222 }
223
224 // And if we produce a block with this tx, it should be valid (DERSIG not
225 // enabled yet), even though there's no cache entry.
226 CBlock block;
227
228 block = CreateAndProcessBlock({spend_tx}, p2pk_scriptPubKey);
229 LOCK(cs_main);
230 BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->GetBlockHash() == block.GetHash());
231 BOOST_CHECK(m_node.chainman->ActiveChainstate().CoinsTip().GetBestBlock() == block.GetHash());
232
233 // Test P2SH: construct a transaction that is valid without P2SH, and
234 // then test validity with P2SH.
235 {
238 invalid_under_p2sh_tx.vin = {CTxIn{spend_tx.GetHash(), 0}};
240 std::vector<unsigned char> vchSig2(p2pk_scriptPubKey.begin(), p2pk_scriptPubKey.end());
241 invalid_under_p2sh_tx.vin[0].scriptSig << vchSig2;
242
243 ValidateCheckInputsForAllFlags(CTransaction(invalid_under_p2sh_tx), SCRIPT_VERIFY_P2SH, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);
244 }
245
246 // Test CHECKLOCKTIMEVERIFY
247 {
250 invalid_with_cltv_tx.nLockTime = 100;
251 invalid_with_cltv_tx.vin = {CTxIn{spend_tx.GetHash(), 2, {}, /*nSequenceIn=*/0}};
253
254 // Sign
255 std::vector<unsigned char> vchSig;
257 BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
258 vchSig.push_back((unsigned char)SIGHASH_ALL);
259 invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101;
260
262
263 // Make it valid, and check again
264 invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
265 TxValidationState state;
267 BOOST_CHECK(CheckInputScripts(CTransaction(invalid_with_cltv_tx), state, m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, CheckInputScriptsFor::Mempool, true, true, txdata, m_node.chainman->m_validation_cache, nullptr));
268 }
269
270 // TEST CHECKSEQUENCEVERIFY
271 {
274 invalid_with_csv_tx.vin = {CTxIn{spend_tx.GetHash(), 3, {}, /*nSequenceIn=*/100}};
276
277 // Sign
278 std::vector<unsigned char> vchSig;
280 BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
281 vchSig.push_back((unsigned char)SIGHASH_ALL);
282 invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101;
283
285
286 // Make it valid, and check again
287 invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
288 TxValidationState state;
290 BOOST_CHECK(CheckInputScripts(CTransaction(invalid_with_csv_tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, CheckInputScriptsFor::Mempool, true, true, txdata, m_node.chainman->m_validation_cache, nullptr));
291 }
292
293 // TODO: add tests for remaining script flags
294
295 // Test that passing CheckInputScripts with a valid witness doesn't imply success
296 // for the same tx with a different witness.
297 {
300 valid_with_witness_tx.vin = {CTxIn{spend_tx.GetHash(), 1}};
302
303 // Sign
304 SignatureData sigdata;
306 UpdateInput(valid_with_witness_tx.vin[0], sigdata);
307
308 // This should be valid under all script flags.
309 ValidateCheckInputsForAllFlags(CTransaction(valid_with_witness_tx), 0, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);
310
311 // Remove the witness, and check that it is now invalid.
312 valid_with_witness_tx.vin[0].scriptWitness.SetNull();
313 ValidateCheckInputsForAllFlags(CTransaction(valid_with_witness_tx), SCRIPT_VERIFY_WITNESS, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);
314 }
315
316 // Test a Taproot (witness v1) key-path spend, to exercise the Schnorr branch of the signature cache.
317 {
319 tr_tx.vin = {CTxIn{spend_tx.GetHash(), 4}};
320 tr_tx.vout = {CTxOut{11*CENT, p2pk_scriptPubKey}};
321
322 // Sign P2TR output for key-path spending (i.e. add Schnorr signature to witness stack)
324 tr_keystore.keys.emplace(coinbaseKey.GetPubKey().GetID(), coinbaseKey);
325 const std::map<COutPoint, Coin> coins{
326 {tr_tx.vin[0].prevout, Coin(spend_tx.vout[4], /*nHeightIn=*/0, /*fCoinBaseIn=*/false)}
327 };
328 std::map<int, bilingual_str> input_errors;
330 auto& witness_stack = tr_tx.vin[0].scriptWitness.stack;
331 BOOST_REQUIRE(witness_stack.size() == 1 && witness_stack[0].size() == 64);
332
333 // Invalidate signature; an invalid Taproot key-path spend is only invalid if SCRIPT_VERIFY_TAPROOT is set
334 witness_stack[0][63] ^= 0x01; // damage signature
335 ValidateCheckInputsForAllFlags(CTransaction(tr_tx), SCRIPT_VERIFY_TAPROOT, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);
336 witness_stack[0][63] ^= 0x01; // repair signature
337
338 // A valid Taproot key-path spend is valid under all flags
339 ValidateCheckInputsForAllFlags(CTransaction(tr_tx), 0, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);
340 }
341
342 {
343 // Test a transaction with multiple inputs.
345
346 tx.version = 1;
347 tx.vin = {
348 CTxIn{spend_tx.GetHash(), 0},
349 CTxIn{spend_tx.GetHash(), 1},
350 };
351 tx.vout = {CTxOut{22*CENT, p2pk_scriptPubKey}};
352
353 // Sign
354 for (int i = 0; i < 2; ++i) {
355 SignatureData sigdata;
356 BOOST_CHECK(ProduceSignature(keystore, MutableTransactionSignatureCreator(tx, i, 11 * CENT, {.sighash_type = SIGHASH_DEFAULT}), spend_tx.vout[i].scriptPubKey, sigdata));
357 UpdateInput(tx.vin[i], sigdata);
358 }
359
360 // This should be valid under all script flags
361 ValidateCheckInputsForAllFlags(CTransaction(tx), 0, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);
362
363 // Check that if the second input is invalid, but the first input is
364 // valid, the transaction is not cached.
365 // Invalidate vin[1]
366 tx.vin[1].scriptWitness.SetNull();
367
368 TxValidationState state;
370 // This transaction is now invalid under segwit, because of the second input.
371 BOOST_CHECK(!CheckInputScripts(CTransaction(tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, CheckInputScriptsFor::Mempool, true, true, txdata, m_node.chainman->m_validation_cache, nullptr));
372
373 std::vector<CScriptCheck> scriptchecks;
374 // Make sure this transaction was not cached (ie because the first
375 // input was valid)
376 BOOST_CHECK(CheckInputScripts(CTransaction(tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, CheckInputScriptsFor::Mempool, true, true, txdata, m_node.chainman->m_validation_cache, &scriptchecks));
377 // Should get 2 script checks back -- caching is on a whole-transaction basis.
379 }
380}
381
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
int ret
node::NodeContext m_node
ChainType
Definition chaintype.h:12
uint256 GetHash() const
Definition block.cpp:14
Definition block.h:74
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition coins.h:437
Serialized script, used inside transaction inputs and outputs.
Definition script.h:406
The basic transaction that is broadcasted on the network and contained in blocks.
An input of a transaction.
Definition transaction.h:63
An output of a transaction.
A UTXO entry.
Definition coins.h:46
Fast randomness source.
Definition random.h:386
Fillable signing provider that keeps keys in an address->secret map.
A signature creator for transactions.
Definition sign.h:54
Convenience class for initializing and passing the script execution cache and signature cache.
Definition validation.h:370
static constexpr script_verify_flags from_int(value_type f)
256-bit opaque blob.
Definition uint256.h:196
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition cs_main.cpp:8
BOOST_AUTO_TEST_SUITE_END()
uint256 SignatureHash(const CScript &scriptCode, const T &txTo, unsigned int nIn, int32_t nHashType, const CAmount &amount, SigVersion sigversion, const PrecomputedTransactionData *cache, SigHashCache *sighash_cache)
constexpr script_verify_flags::value_type MAX_SCRIPT_VERIFY_FLAGS
@ BASE
Bare scripts and BIP16 P2SH-wrapped redeemscripts.
@ SIGHASH_DEFAULT
Taproot only; implied when sighash byte is missing, and equivalent to SIGHASH_ALL.
Definition interpreter.h:37
@ SIGHASH_ALL
Definition interpreter.h:32
@ CONFLICT
Removed for conflict with in-block transaction.
#define BOOST_CHECK_EQUAL(v1, v2)
Definition object.cpp:17
#define BOOST_CHECK(expr)
Definition object.cpp:16
static CTransactionRef MakeTransactionRef(Tx &&txIn)
void SignTransaction(CMutableTransaction &mtx, const SigningProvider *keystore, const std::map< COutPoint, Coin > &coins, const UniValue &hashType, UniValue &result)
Sign a transaction with the given keystore and previous transactions.
@ OP_CHECKSIG
Definition script.h:191
@ OP_CHECKLOCKTIMEVERIFY
Definition script.h:198
@ OP_DROP
Definition script.h:125
@ OP_CHECKSEQUENCEVERIFY
Definition script.h:200
std::vector< unsigned char > ToByteVector(const T &in)
Definition script.h:68
constexpr CAmount CENT
bool ProduceSignature(const SigningProvider &provider, const BaseSignatureCreator &creator, const CScript &fromPubKey, SignatureData &sigdata)
Produce a script signature using a generic signature creator.
Definition sign.cpp:750
void UpdateInput(CTxIn &input, const SignatureData &data)
Definition sign.cpp:923
A mutable version of CTransaction.
std::vector< CTxOut > vout
std::vector< CTxIn > vin
std::map< CKeyID, CKey > keys
Validation result for a transaction evaluated by MemPoolAccept (single or package).
Definition validation.h:134
const ResultType m_result_type
Result type.
Definition validation.h:143
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
std::unique_ptr< CTxMemPool > mempool
Definition context.h:69
std::unique_ptr< ChainstateManager > chainman
Definition context.h:74
#define LOCK(cs)
Definition sync.h:268
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition sync.h:299
static int count
#define EXCLUSIVE_LOCKS_REQUIRED(...)
static void ValidateCheckInputsForAllFlags(const CTransaction &tx, script_verify_flags failing_flags, bool add_to_cache, CCoinsViewCache &active_coins_tip, ValidationCache &validation_cache) EXCLUSIVE_LOCKS_REQUIRED(
BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, Dersig100Setup)
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82
return CheckInputScripts(tx, state, view, flags, CheckInputScriptsFor::Mempool, true, true, txdata, validation_cache)