Branch data Line data Source code
1 : : // Copyright (c) 2011-2022 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 : :
5 : : #include <consensus/validation.h>
6 : : #include <key.h>
7 : : #include <random.h>
8 : : #include <script/sign.h>
9 : : #include <script/signingprovider.h>
10 : : #include <test/util/setup_common.h>
11 : : #include <txmempool.h>
12 : : #include <util/chaintype.h>
13 : : #include <validation.h>
14 : :
15 : : #include <boost/test/unit_test.hpp>
16 : :
17 : 0 : struct Dersig100Setup : public TestChain100Setup {
18 : 0 : Dersig100Setup()
19 : 0 : : TestChain100Setup{ChainType::REGTEST, {"-testactivationheight=dersig@102"}} {}
20 : : };
21 : :
22 : : bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
23 : : const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore,
24 : : bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
25 : : std::vector<CScriptCheck>* pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
26 : :
27 : 0 : BOOST_AUTO_TEST_SUITE(txvalidationcache_tests)
28 : :
29 : 0 : BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, Dersig100Setup)
30 : : {
31 : : // Make sure skipping validation of transactions that were
32 : : // validated going into the memory pool does not allow
33 : : // double-spends in blocks to pass validation when they should not.
34 : :
35 : 0 : CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
36 : :
37 : 0 : const auto ToMemPool = [this](const CMutableTransaction& tx) {
38 : 0 : LOCK(cs_main);
39 : :
40 : 0 : const MempoolAcceptResult result = m_node.chainman->ProcessTransaction(MakeTransactionRef(tx));
41 : 0 : return result.m_result_type == MempoolAcceptResult::ResultType::VALID;
42 : 0 : };
43 : :
44 : : // Create a double-spend of mature coinbase txn:
45 : 0 : std::vector<CMutableTransaction> spends;
46 : 0 : spends.resize(2);
47 : 0 : for (int i = 0; i < 2; i++)
48 : : {
49 : 0 : spends[i].nVersion = 1;
50 : 0 : spends[i].vin.resize(1);
51 : 0 : spends[i].vin[0].prevout.hash = m_coinbase_txns[0]->GetHash();
52 : 0 : spends[i].vin[0].prevout.n = 0;
53 : 0 : spends[i].vout.resize(1);
54 : 0 : spends[i].vout[0].nValue = 11*CENT;
55 : 0 : spends[i].vout[0].scriptPubKey = scriptPubKey;
56 : :
57 : : // Sign:
58 : 0 : std::vector<unsigned char> vchSig;
59 : 0 : uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL, 0, SigVersion::BASE);
60 : 0 : BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
61 : 0 : vchSig.push_back((unsigned char)SIGHASH_ALL);
62 : 0 : spends[i].vin[0].scriptSig << vchSig;
63 : 0 : }
64 : :
65 : 0 : CBlock block;
66 : :
67 : : // Test 1: block with both of those transactions should be rejected.
68 : 0 : block = CreateAndProcessBlock(spends, scriptPubKey);
69 : : {
70 : 0 : LOCK(cs_main);
71 : 0 : BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->GetBlockHash() != block.GetHash());
72 : 0 : }
73 : :
74 : 0 : // Test 2: ... and should be rejected if spend1 is in the memory pool
75 : 0 : BOOST_CHECK(ToMemPool(spends[0]));
76 : 0 : block = CreateAndProcessBlock(spends, scriptPubKey);
77 : : {
78 : 0 : LOCK(cs_main);
79 : 0 : BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->GetBlockHash() != block.GetHash());
80 : 0 : }
81 : 0 : BOOST_CHECK_EQUAL(m_node.mempool->size(), 1U);
82 : 0 : WITH_LOCK(m_node.mempool->cs, m_node.mempool->removeRecursive(CTransaction{spends[0]}, MemPoolRemovalReason::CONFLICT));
83 : 0 : BOOST_CHECK_EQUAL(m_node.mempool->size(), 0U);
84 : :
85 : : // Test 3: ... and should be rejected if spend2 is in the memory pool
86 : 0 : BOOST_CHECK(ToMemPool(spends[1]));
87 : 0 : block = CreateAndProcessBlock(spends, scriptPubKey);
88 : : {
89 : 0 : LOCK(cs_main);
90 : 0 : BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->GetBlockHash() != block.GetHash());
91 : 0 : }
92 : 0 : BOOST_CHECK_EQUAL(m_node.mempool->size(), 1U);
93 : 0 : WITH_LOCK(m_node.mempool->cs, m_node.mempool->removeRecursive(CTransaction{spends[1]}, MemPoolRemovalReason::CONFLICT));
94 : 0 : BOOST_CHECK_EQUAL(m_node.mempool->size(), 0U);
95 : :
96 : : // Final sanity test: first spend in *m_node.mempool, second in block, that's OK:
97 : 0 : std::vector<CMutableTransaction> oneSpend;
98 : 0 : oneSpend.push_back(spends[0]);
99 : 0 : BOOST_CHECK(ToMemPool(spends[1]));
100 : 0 : block = CreateAndProcessBlock(oneSpend, scriptPubKey);
101 : : {
102 : 0 : LOCK(cs_main);
103 : 0 : BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->GetBlockHash() == block.GetHash());
104 : 0 : }
105 : : // spends[1] should have been removed from the mempool when the
106 : : // block with spends[0] is accepted:
107 : 0 : BOOST_CHECK_EQUAL(m_node.mempool->size(), 0U);
108 : 0 : }
109 : :
110 : : // Run CheckInputScripts (using CoinsTip()) on the given transaction, for all script
111 : : // flags. Test that CheckInputScripts passes for all flags that don't overlap with
112 : : // the failing_flags argument, but otherwise fails.
113 : : // CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY (and future NOP codes that may
114 : : // get reassigned) have an interaction with DISCOURAGE_UPGRADABLE_NOPS: if
115 : : // the script flags used contain DISCOURAGE_UPGRADABLE_NOPS but don't contain
116 : : // CHECKLOCKTIMEVERIFY (or CHECKSEQUENCEVERIFY), but the script does contain
117 : : // OP_CHECKLOCKTIMEVERIFY (or OP_CHECKSEQUENCEVERIFY), then script execution
118 : : // should fail.
119 : : // Capture this interaction with the upgraded_nop argument: set it when evaluating
120 : : // any script flag that is implemented as an upgraded NOP code.
121 : 0 : static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t failing_flags, bool add_to_cache, CCoinsViewCache& active_coins_tip) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
122 : : {
123 : 0 : PrecomputedTransactionData txdata;
124 : :
125 : 0 : FastRandomContext insecure_rand(true);
126 : :
127 : 0 : for (int count = 0; count < 10000; ++count) {
128 : 0 : TxValidationState state;
129 : :
130 : : // Randomly selects flag combinations
131 : 0 : uint32_t test_flags = (uint32_t) insecure_rand.randrange((SCRIPT_VERIFY_END_MARKER - 1) << 1);
132 : :
133 : : // Filter out incompatible flag choices
134 : 0 : if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) {
135 : : // CLEANSTACK requires P2SH and WITNESS, see VerifyScript() in
136 : : // script/interpreter.cpp
137 : 0 : test_flags |= SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS;
138 : 0 : }
139 : 0 : if ((test_flags & SCRIPT_VERIFY_WITNESS)) {
140 : : // WITNESS requires P2SH
141 : 0 : test_flags |= SCRIPT_VERIFY_P2SH;
142 : 0 : }
143 : 0 : bool ret = CheckInputScripts(tx, state, &active_coins_tip, test_flags, true, add_to_cache, txdata, nullptr);
144 : : // CheckInputScripts should succeed iff test_flags doesn't intersect with
145 : : // failing_flags
146 : 0 : bool expected_return_value = !(test_flags & failing_flags);
147 : 0 : BOOST_CHECK_EQUAL(ret, expected_return_value);
148 : :
149 : : // Test the caching
150 : 0 : if (ret && add_to_cache) {
151 : : // Check that we get a cache hit if the tx was valid
152 : 0 : std::vector<CScriptCheck> scriptchecks;
153 : 0 : BOOST_CHECK(CheckInputScripts(tx, state, &active_coins_tip, test_flags, true, add_to_cache, txdata, &scriptchecks));
154 : 0 : BOOST_CHECK(scriptchecks.empty());
155 : 0 : } else {
156 : : // Check that we get script executions to check, if the transaction
157 : : // was invalid, or we didn't add to cache.
158 : 0 : std::vector<CScriptCheck> scriptchecks;
159 : 0 : BOOST_CHECK(CheckInputScripts(tx, state, &active_coins_tip, test_flags, true, add_to_cache, txdata, &scriptchecks));
160 : 0 : BOOST_CHECK_EQUAL(scriptchecks.size(), tx.vin.size());
161 : 0 : }
162 : 0 : }
163 : 0 : }
164 : :
165 : 0 : BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup)
166 : : {
167 : : // Test that passing CheckInputScripts with one set of script flags doesn't imply
168 : : // that we would pass again with a different set of flags.
169 : 0 : CScript p2pk_scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
170 : 0 : CScript p2sh_scriptPubKey = GetScriptForDestination(ScriptHash(p2pk_scriptPubKey));
171 : 0 : CScript p2pkh_scriptPubKey = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey()));
172 : 0 : CScript p2wpkh_scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(coinbaseKey.GetPubKey()));
173 : :
174 : 0 : FillableSigningProvider keystore;
175 : 0 : BOOST_CHECK(keystore.AddKey(coinbaseKey));
176 : 0 : BOOST_CHECK(keystore.AddCScript(p2pk_scriptPubKey));
177 : :
178 : : // flags to test: SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, SCRIPT_VERIFY_CHECKSEQUENCE_VERIFY, SCRIPT_VERIFY_NULLDUMMY, uncompressed pubkey thing
179 : :
180 : : // Create 2 outputs that match the three scripts above, spending the first
181 : : // coinbase tx.
182 : 0 : CMutableTransaction spend_tx;
183 : :
184 : 0 : spend_tx.nVersion = 1;
185 : 0 : spend_tx.vin.resize(1);
186 : 0 : spend_tx.vin[0].prevout.hash = m_coinbase_txns[0]->GetHash();
187 : 0 : spend_tx.vin[0].prevout.n = 0;
188 : 0 : spend_tx.vout.resize(4);
189 : 0 : spend_tx.vout[0].nValue = 11*CENT;
190 : 0 : spend_tx.vout[0].scriptPubKey = p2sh_scriptPubKey;
191 : 0 : spend_tx.vout[1].nValue = 11*CENT;
192 : 0 : spend_tx.vout[1].scriptPubKey = p2wpkh_scriptPubKey;
193 : 0 : spend_tx.vout[2].nValue = 11*CENT;
194 : 0 : spend_tx.vout[2].scriptPubKey = CScript() << OP_CHECKLOCKTIMEVERIFY << OP_DROP << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
195 : 0 : spend_tx.vout[3].nValue = 11*CENT;
196 : 0 : spend_tx.vout[3].scriptPubKey = CScript() << OP_CHECKSEQUENCEVERIFY << OP_DROP << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
197 : :
198 : : // Sign, with a non-DER signature
199 : : {
200 : 0 : std::vector<unsigned char> vchSig;
201 : 0 : uint256 hash = SignatureHash(p2pk_scriptPubKey, spend_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE);
202 : 0 : BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
203 : 0 : vchSig.push_back((unsigned char) 0); // padding byte makes this non-DER
204 : 0 : vchSig.push_back((unsigned char)SIGHASH_ALL);
205 : 0 : spend_tx.vin[0].scriptSig << vchSig;
206 : 0 : }
207 : :
208 : : // Test that invalidity under a set of flags doesn't preclude validity
209 : : // under other (eg consensus) flags.
210 : : // spend_tx is invalid according to DERSIG
211 : : {
212 : 0 : LOCK(cs_main);
213 : :
214 : 0 : TxValidationState state;
215 : 0 : PrecomputedTransactionData ptd_spend_tx;
216 : :
217 : 0 : BOOST_CHECK(!CheckInputScripts(CTransaction(spend_tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
218 : :
219 : : // If we call again asking for scriptchecks (as happens in
220 : : // ConnectBlock), we should add a script check object for this -- we're
221 : : // not caching invalidity (if that changes, delete this test case).
222 : 0 : std::vector<CScriptCheck> scriptchecks;
223 : 0 : BOOST_CHECK(CheckInputScripts(CTransaction(spend_tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks));
224 : 0 : BOOST_CHECK_EQUAL(scriptchecks.size(), 1U);
225 : :
226 : : // Test that CheckInputScripts returns true iff DERSIG-enforcing flags are
227 : 0 : // not present. Don't add these checks to the cache, so that we can
228 : : // test later that block validation works fine in the absence of cached
229 : : // successes.
230 : 0 : ValidateCheckInputsForAllFlags(CTransaction(spend_tx), SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC, false, m_node.chainman->ActiveChainstate().CoinsTip());
231 : 0 : }
232 : :
233 : : // And if we produce a block with this tx, it should be valid (DERSIG not
234 : : // enabled yet), even though there's no cache entry.
235 : 0 : CBlock block;
236 : :
237 : 0 : block = CreateAndProcessBlock({spend_tx}, p2pk_scriptPubKey);
238 : 0 : LOCK(cs_main);
239 : 0 : BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->GetBlockHash() == block.GetHash());
240 : 0 : BOOST_CHECK(m_node.chainman->ActiveChainstate().CoinsTip().GetBestBlock() == block.GetHash());
241 : :
242 : : // Test P2SH: construct a transaction that is valid without P2SH, and
243 : : // then test validity with P2SH.
244 : : {
245 : 0 : CMutableTransaction invalid_under_p2sh_tx;
246 : 0 : invalid_under_p2sh_tx.nVersion = 1;
247 : 0 : invalid_under_p2sh_tx.vin.resize(1);
248 : 0 : invalid_under_p2sh_tx.vin[0].prevout.hash = spend_tx.GetHash();
249 : 0 : invalid_under_p2sh_tx.vin[0].prevout.n = 0;
250 : 0 : invalid_under_p2sh_tx.vout.resize(1);
251 : 0 : invalid_under_p2sh_tx.vout[0].nValue = 11*CENT;
252 : 0 : invalid_under_p2sh_tx.vout[0].scriptPubKey = p2pk_scriptPubKey;
253 : 0 : std::vector<unsigned char> vchSig2(p2pk_scriptPubKey.begin(), p2pk_scriptPubKey.end());
254 : 0 : invalid_under_p2sh_tx.vin[0].scriptSig << vchSig2;
255 : :
256 : 0 : ValidateCheckInputsForAllFlags(CTransaction(invalid_under_p2sh_tx), SCRIPT_VERIFY_P2SH, true, m_node.chainman->ActiveChainstate().CoinsTip());
257 : 0 : }
258 : :
259 : : // Test CHECKLOCKTIMEVERIFY
260 : : {
261 : 0 : CMutableTransaction invalid_with_cltv_tx;
262 : 0 : invalid_with_cltv_tx.nVersion = 1;
263 : 0 : invalid_with_cltv_tx.nLockTime = 100;
264 : 0 : invalid_with_cltv_tx.vin.resize(1);
265 : 0 : invalid_with_cltv_tx.vin[0].prevout.hash = spend_tx.GetHash();
266 : 0 : invalid_with_cltv_tx.vin[0].prevout.n = 2;
267 : 0 : invalid_with_cltv_tx.vin[0].nSequence = 0;
268 : 0 : invalid_with_cltv_tx.vout.resize(1);
269 : 0 : invalid_with_cltv_tx.vout[0].nValue = 11*CENT;
270 : 0 : invalid_with_cltv_tx.vout[0].scriptPubKey = p2pk_scriptPubKey;
271 : :
272 : : // Sign
273 : 0 : std::vector<unsigned char> vchSig;
274 : 0 : uint256 hash = SignatureHash(spend_tx.vout[2].scriptPubKey, invalid_with_cltv_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE);
275 : 0 : BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
276 : 0 : vchSig.push_back((unsigned char)SIGHASH_ALL);
277 : 0 : invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101;
278 : :
279 : 0 : ValidateCheckInputsForAllFlags(CTransaction(invalid_with_cltv_tx), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, m_node.chainman->ActiveChainstate().CoinsTip());
280 : :
281 : : // Make it valid, and check again
282 : 0 : invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
283 : 0 : TxValidationState state;
284 : 0 : PrecomputedTransactionData txdata;
285 : 0 : BOOST_CHECK(CheckInputScripts(CTransaction(invalid_with_cltv_tx), state, m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
286 : 0 : }
287 : :
288 : : // TEST CHECKSEQUENCEVERIFY
289 : : {
290 : 0 : CMutableTransaction invalid_with_csv_tx;
291 : 0 : invalid_with_csv_tx.nVersion = 2;
292 : 0 : invalid_with_csv_tx.vin.resize(1);
293 : 0 : invalid_with_csv_tx.vin[0].prevout.hash = spend_tx.GetHash();
294 : 0 : invalid_with_csv_tx.vin[0].prevout.n = 3;
295 : 0 : invalid_with_csv_tx.vin[0].nSequence = 100;
296 : 0 : invalid_with_csv_tx.vout.resize(1);
297 : 0 : invalid_with_csv_tx.vout[0].nValue = 11*CENT;
298 : 0 : invalid_with_csv_tx.vout[0].scriptPubKey = p2pk_scriptPubKey;
299 : :
300 : : // Sign
301 : 0 : std::vector<unsigned char> vchSig;
302 : 0 : uint256 hash = SignatureHash(spend_tx.vout[3].scriptPubKey, invalid_with_csv_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE);
303 : 0 : BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
304 : 0 : vchSig.push_back((unsigned char)SIGHASH_ALL);
305 : 0 : invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101;
306 : :
307 : 0 : ValidateCheckInputsForAllFlags(CTransaction(invalid_with_csv_tx), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, m_node.chainman->ActiveChainstate().CoinsTip());
308 : :
309 : : // Make it valid, and check again
310 : 0 : invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
311 : 0 : TxValidationState state;
312 : 0 : PrecomputedTransactionData txdata;
313 : 0 : BOOST_CHECK(CheckInputScripts(CTransaction(invalid_with_csv_tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
314 : 0 : }
315 : :
316 : : // TODO: add tests for remaining script flags
317 : :
318 : : // Test that passing CheckInputScripts with a valid witness doesn't imply success
319 : : // for the same tx with a different witness.
320 : : {
321 : 0 : CMutableTransaction valid_with_witness_tx;
322 : 0 : valid_with_witness_tx.nVersion = 1;
323 : 0 : valid_with_witness_tx.vin.resize(1);
324 : 0 : valid_with_witness_tx.vin[0].prevout.hash = spend_tx.GetHash();
325 : 0 : valid_with_witness_tx.vin[0].prevout.n = 1;
326 : 0 : valid_with_witness_tx.vout.resize(1);
327 : 0 : valid_with_witness_tx.vout[0].nValue = 11*CENT;
328 : 0 : valid_with_witness_tx.vout[0].scriptPubKey = p2pk_scriptPubKey;
329 : :
330 : : // Sign
331 : 0 : SignatureData sigdata;
332 : 0 : BOOST_CHECK(ProduceSignature(keystore, MutableTransactionSignatureCreator(valid_with_witness_tx, 0, 11 * CENT, SIGHASH_ALL), spend_tx.vout[1].scriptPubKey, sigdata));
333 : 0 : UpdateInput(valid_with_witness_tx.vin[0], sigdata);
334 : :
335 : : // This should be valid under all script flags.
336 : 0 : ValidateCheckInputsForAllFlags(CTransaction(valid_with_witness_tx), 0, true, m_node.chainman->ActiveChainstate().CoinsTip());
337 : :
338 : : // Remove the witness, and check that it is now invalid.
339 : 0 : valid_with_witness_tx.vin[0].scriptWitness.SetNull();
340 : 0 : ValidateCheckInputsForAllFlags(CTransaction(valid_with_witness_tx), SCRIPT_VERIFY_WITNESS, true, m_node.chainman->ActiveChainstate().CoinsTip());
341 : 0 : }
342 : :
343 : : {
344 : : // Test a transaction with multiple inputs.
345 : 0 : CMutableTransaction tx;
346 : :
347 : 0 : tx.nVersion = 1;
348 : 0 : tx.vin.resize(2);
349 : 0 : tx.vin[0].prevout.hash = spend_tx.GetHash();
350 : 0 : tx.vin[0].prevout.n = 0;
351 : 0 : tx.vin[1].prevout.hash = spend_tx.GetHash();
352 : 0 : tx.vin[1].prevout.n = 1;
353 : 0 : tx.vout.resize(1);
354 : 0 : tx.vout[0].nValue = 22*CENT;
355 : 0 : tx.vout[0].scriptPubKey = p2pk_scriptPubKey;
356 : :
357 : : // Sign
358 : 0 : for (int i = 0; i < 2; ++i) {
359 : 0 : SignatureData sigdata;
360 : 0 : BOOST_CHECK(ProduceSignature(keystore, MutableTransactionSignatureCreator(tx, i, 11 * CENT, SIGHASH_ALL), spend_tx.vout[i].scriptPubKey, sigdata));
361 : 0 : UpdateInput(tx.vin[i], sigdata);
362 : 0 : }
363 : :
364 : : // This should be valid under all script flags
365 : 0 : ValidateCheckInputsForAllFlags(CTransaction(tx), 0, true, m_node.chainman->ActiveChainstate().CoinsTip());
366 : :
367 : : // Check that if the second input is invalid, but the first input is
368 : : // valid, the transaction is not cached.
369 : : // Invalidate vin[1]
370 : 0 : tx.vin[1].scriptWitness.SetNull();
371 : :
372 : 0 : TxValidationState state;
373 : 0 : PrecomputedTransactionData txdata;
374 : : // This transaction is now invalid under segwit, because of the second input.
375 : 0 : BOOST_CHECK(!CheckInputScripts(CTransaction(tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr));
376 : :
377 : 0 : std::vector<CScriptCheck> scriptchecks;
378 : : // Make sure this transaction was not cached (ie because the first
379 : : // input was valid)
380 : 0 : BOOST_CHECK(CheckInputScripts(CTransaction(tx), state, &m_node.chainman->ActiveChainstate().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, &scriptchecks));
381 : : // Should get 2 script checks back -- caching is on a whole-transaction basis.
382 : 0 : BOOST_CHECK_EQUAL(scriptchecks.size(), 2U);
383 : 0 : }
384 : 0 : }
385 : :
386 : 0 : BOOST_AUTO_TEST_SUITE_END()
|