Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
252// Test CHECKLOCKTIMEVERIFY253{254CMutableTransaction invalid_with_cltv_tx;255invalid_with_cltv_tx.version = 1;256invalid_with_cltv_tx.nLockTime = 100;257invalid_with_cltv_tx.vin = {CTxIn{spend_tx.GetHash(), 2, {}, /*nSequenceIn=*/0}};258invalid_with_cltv_tx.vout = {CTxOut{11*CENT, p2pk_scriptPubKey}};260// Sign261std::vector<unsigned char> vchSig;262uint256 hash = SignatureHash(spend_tx.vout[2].scriptPubKey, invalid_with_cltv_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE);263BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));264vchSig.push_back((unsigned char)SIGHASH_ALL);265invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101;267ValidateCheckInputsForAllFlags(CTransaction(invalid_with_cltv_tx), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);269// Make it valid, and check again270invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;271TxValidationState state;272PrecomputedTransactionData txdata;273BOOST_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));274}276// TEST CHECKSEQUENCEVERIFY277{278CMutableTransaction invalid_with_csv_tx;279invalid_with_csv_tx.version = 2;280invalid_with_csv_tx.vin = {CTxIn{spend_tx.GetHash(), 3, {}, /*nSequenceIn=*/100}};281invalid_with_csv_tx.vout = {CTxOut{11*CENT, p2pk_scriptPubKey}};283// Sign284std::vector<unsigned char> vchSig;285uint256 hash = SignatureHash(spend_tx.vout[3].scriptPubKey, invalid_with_csv_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE);286BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));287vchSig.push_back((unsigned char)SIGHASH_ALL);288invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101;290ValidateCheckInputsForAllFlags(CTransaction(invalid_with_csv_tx), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);292// Make it valid, and check again293invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;294TxValidationState state;295PrecomputedTransactionData txdata;296BOOST_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));297}299// TODO: add tests for remaining script flags301// Test that passing CheckInputScripts with a valid witness doesn't imply success302// for the same tx with a different witness.303{304CMutableTransaction valid_with_witness_tx;305valid_with_witness_tx.version = 1;306valid_with_witness_tx.vin = {CTxIn{spend_tx.GetHash(), 1}};307valid_with_witness_tx.vout = {CTxOut{11*CENT, p2pk_scriptPubKey}};309// Sign310SignatureData sigdata;311BOOST_CHECK(ProduceSignature(keystore, MutableTransactionSignatureCreator(valid_with_witness_tx, 0, 11 * CENT, {.sighash_type = SIGHASH_DEFAULT}), spend_tx.vout[1].scriptPubKey, sigdata));312UpdateInput(valid_with_witness_tx.vin[0], sigdata);314// This should be valid under all script flags.315ValidateCheckInputsForAllFlags(CTransaction(valid_with_witness_tx), 0, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);317// Remove the witness, and check that it is now invalid.318valid_with_witness_tx.vin[0].scriptWitness.SetNull();319ValidateCheckInputsForAllFlags(CTransaction(valid_with_witness_tx), SCRIPT_VERIFY_WITNESS, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);320}322// Test a Taproot (witness v1) key-path spend, to exercise the Schnorr branch of the signature cache.323{324CMutableTransaction tr_tx;325tr_tx.vin = {CTxIn{spend_tx.GetHash(), 4}};326tr_tx.vout = {CTxOut{11*CENT, p2pk_scriptPubKey}};328// Sign P2TR output for key-path spending (i.e. add Schnorr signature to witness stack)329FlatSigningProvider tr_keystore;330tr_keystore.keys.emplace(coinbaseKey.GetPubKey().GetID(), coinbaseKey);331const std::map<COutPoint, Coin> coins{332{tr_tx.vin[0].prevout, Coin(spend_tx.vout[4], /*nHeightIn=*/0, /*fCoinBaseIn=*/false)}333};334std::map<int, bilingual_str> input_errors;335BOOST_REQUIRE(SignTransaction(tr_tx, &tr_keystore, coins, {.sighash_type = SIGHASH_DEFAULT}, input_errors));336auto& witness_stack = tr_tx.vin[0].scriptWitness.stack;337BOOST_REQUIRE(witness_stack.size() == 1 && witness_stack[0].size() == 64);339// Invalidate signature; an invalid Taproot key-path spend is only invalid if SCRIPT_VERIFY_TAPROOT is set340witness_stack[0][63] ^= 0x01; // damage signature341ValidateCheckInputsForAllFlags(CTransaction(tr_tx), SCRIPT_VERIFY_TAPROOT, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);342witness_stack[0][63] ^= 0x01; // repair signature344// A valid Taproot key-path spend is valid under all flags345ValidateCheckInputsForAllFlags(CTransaction(tr_tx), 0, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);346}348{349// Test a transaction with multiple inputs.350CMutableTransaction tx;352tx.version = 1;353tx.vin = {354CTxIn{spend_tx.GetHash(), 0},355CTxIn{spend_tx.GetHash(), 1},356};357tx.vout = {CTxOut{22*CENT, p2pk_scriptPubKey}};359// Sign360for (int i = 0; i < 2; ++i) {361SignatureData sigdata;362BOOST_CHECK(ProduceSignature(keystore, MutableTransactionSignatureCreator(tx, i, 11 * CENT, {.sighash_type = SIGHASH_DEFAULT}), spend_tx.vout[i].scriptPubKey, sigdata));363UpdateInput(tx.vin[i], sigdata);364}366// This should be valid under all script flags367ValidateCheckInputsForAllFlags(CTransaction(tx), 0, true, m_node.chainman->ActiveChainstate().CoinsTip(), m_node.chainman->m_validation_cache);369// Check that if the second input is invalid, but the first input is370// valid, the transaction is not cached.371// Invalidate vin[1]372tx.vin[1].scriptWitness.SetNull();374TxValidationState state;375PrecomputedTransactionData txdata;376// This transaction is now invalid under segwit, because of the second input.377BOOST_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));379std::vector<CScriptCheck> scriptchecks;380// Make sure this transaction was not cached (ie because the first381// input was valid)382BOOST_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.384BOOST_CHECK_EQUAL(scriptchecks.size(), 2U);385}386}388BOOST_AUTO_TEST_SUITE_END()
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.