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