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.
1001BOOST_CHECK(pushdata2Stack == directStack);1002BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));1004std::vector<std::vector<unsigned char> > pushdata4Stack;1005BOOST_CHECK(EvalScript(pushdata4Stack, CScript(pushdata4, pushdata4 + sizeof(pushdata4)), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err));1006BOOST_CHECK(pushdata4Stack == directStack);1007BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));1009const std::vector<unsigned char> pushdata1_trunc{OP_PUSHDATA1, 1};1010const std::vector<unsigned char> pushdata2_trunc{OP_PUSHDATA2, 1, 0};1011const std::vector<unsigned char> pushdata4_trunc{OP_PUSHDATA4, 1, 0, 0, 0};1013std::vector<std::vector<unsigned char>> stack_ignore;1014BOOST_CHECK(!EvalScript(stack_ignore, CScript(pushdata1_trunc.begin(), pushdata1_trunc.end()), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err));1015BOOST_CHECK_EQUAL(err, SCRIPT_ERR_BAD_OPCODE);1016BOOST_CHECK(!EvalScript(stack_ignore, CScript(pushdata2_trunc.begin(), pushdata2_trunc.end()), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err));1017BOOST_CHECK_EQUAL(err, SCRIPT_ERR_BAD_OPCODE);1018BOOST_CHECK(!EvalScript(stack_ignore, CScript(pushdata4_trunc.begin(), pushdata4_trunc.end()), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err));1019BOOST_CHECK_EQUAL(err, SCRIPT_ERR_BAD_OPCODE);1020}1022BOOST_AUTO_TEST_CASE(script_cltv_truncated)1023{1024const auto script_cltv_trunc = CScript() << OP_CHECKLOCKTIMEVERIFY;1026std::vector<std::vector<unsigned char>> stack_ignore;1027ScriptError err;1028BOOST_CHECK(!EvalScript(stack_ignore, script_cltv_trunc, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, BaseSignatureChecker(), SigVersion::BASE, &err));1029BOOST_CHECK_EQUAL(err, SCRIPT_ERR_INVALID_STACK_OPERATION);1030}1032static CScript1033sign_multisig(const CScript& scriptPubKey, const std::vector<CKey>& keys, const CTransaction& transaction)1034{1035uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, SigVersion::BASE);1037CScript result;1038//1039// NOTE: CHECKMULTISIG has an unfortunate bug; it requires1040// one extra item on the stack, before the signatures.1041// Putting OP_0 on the stack is the workaround;1042// fixing the bug would mean splitting the block chain (old1043// clients would not accept new CHECKMULTISIG transactions,1044// and vice-versa)1045//1046result << OP_0;1047for (const CKey &key : keys)1048{1049std::vector<unsigned char> vchSig;1050BOOST_CHECK(key.Sign(hash, vchSig));1051vchSig.push_back((unsigned char)SIGHASH_ALL);1052result << vchSig;1053}1054return result;1055}1056static CScript1057sign_multisig(const CScript& scriptPubKey, const CKey& key, const CTransaction& transaction)1058{1059std::vector<CKey> keys;1060keys.push_back(key);1061return sign_multisig(scriptPubKey, keys, transaction);1062}1064BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)1065{1066ScriptError err;1067CKey key1 = GenerateRandomKey();1068CKey key2 = GenerateRandomKey(/*compressed=*/false);1069CKey key3 = GenerateRandomKey();1071CScript scriptPubKey12;1072scriptPubKey12 << OP_1 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << OP_2 << OP_CHECKMULTISIG;1074const CTransaction txFrom12{BuildCreditingTransaction(scriptPubKey12)};1075CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), CScriptWitness(), txFrom12);1077CScript goodsig1 = sign_multisig(scriptPubKey12, key1, CTransaction(txTo12));1078BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err));1079BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));1080txTo12.vout[0].nValue = 2;1081BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err));1082BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));1084CScript goodsig2 = sign_multisig(scriptPubKey12, key2, CTransaction(txTo12));1085BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err));1086BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));1088CScript badsig1 = sign_multisig(scriptPubKey12, key3, CTransaction(txTo12));1089BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err));1090BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));1091}1093BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)1094{1095ScriptError err;1096CKey key1 = GenerateRandomKey();1097CKey key2 = GenerateRandomKey(/*compressed=*/false);1098CKey key3 = GenerateRandomKey();1099CKey key4 = GenerateRandomKey(/*compressed=*/false);1101CScript scriptPubKey23;1102scriptPubKey23 << OP_2 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << ToByteVector(key3.GetPubKey()) << OP_3 << OP_CHECKMULTISIG;1104const CTransaction txFrom23{BuildCreditingTransaction(scriptPubKey23)};1105CMutableTransaction txTo23 = BuildSpendingTransaction(CScript(), CScriptWitness(), txFrom23);1107std::vector<CKey> keys;1108keys.push_back(key1); keys.push_back(key2);1109CScript goodsig1 = sign_multisig(scriptPubKey23, keys, CTransaction(txTo23));1110BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err));1111BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));1113keys.clear();1114keys.push_back(key1); keys.push_back(key3);1115CScript goodsig2 = sign_multisig(scriptPubKey23, keys, CTransaction(txTo23));1116BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err));1117BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));1119keys.clear();1120keys.push_back(key2); keys.push_back(key3);1121CScript goodsig3 = sign_multisig(scriptPubKey23, keys, CTransaction(txTo23));1122BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err));1123BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));1125keys.clear();1126keys.push_back(key2); keys.push_back(key2); // Can't reuse sig1127CScript badsig1 = sign_multisig(scriptPubKey23, keys, CTransaction(txTo23));1128BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err));1129BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));1131keys.clear();1132keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order1133CScript badsig2 = sign_multisig(scriptPubKey23, keys, CTransaction(txTo23));1134BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err));1135BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));1137keys.clear();1138keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order1139CScript badsig3 = sign_multisig(scriptPubKey23, keys, CTransaction(txTo23));1140BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err));1141BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));1143keys.clear();1144keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys1145CScript badsig4 = sign_multisig(scriptPubKey23, keys, CTransaction(txTo23));1146BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err));1147BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));1149keys.clear();1150keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys1151CScript badsig5 = sign_multisig(scriptPubKey23, keys, CTransaction(txTo23));1152BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err));1153BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));1155keys.clear(); // Must have signatures1156CScript badsig6 = sign_multisig(scriptPubKey23, keys, CTransaction(txTo23));1157BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, nullptr, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err));1158BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));1159}1161/** Return the TxoutType of a script without exposing Solver details. */1162static TxoutType GetTxoutType(const CScript& output_script)1163{1164std::vector<std::vector<uint8_t>> unused;1165return Solver(output_script, unused);1166}1168#define CHECK_SCRIPT_STATIC_SIZE(script, expected_size) \1169do { \1170BOOST_CHECK_EQUAL((script).size(), (expected_size)); \1171BOOST_CHECK_EQUAL((script).capacity(), CScriptBase::STATIC_SIZE); \1172BOOST_CHECK_EQUAL((script).allocated_memory(), 0); \1173} while (0)1175#define CHECK_SCRIPT_DYNAMIC_SIZE(script, expected_size, expected_extra) \1176do { \1177BOOST_CHECK_EQUAL((script).size(), (expected_size)); \1178BOOST_CHECK_EQUAL((script).capacity(), (expected_extra)); \1179BOOST_CHECK_EQUAL((script).allocated_memory(), (expected_extra)); \1180} while (0)1182BOOST_AUTO_TEST_CASE(script_size_and_capacity_test)1183{1184BOOST_CHECK_EQUAL(sizeof(CompressedScript), 40);1185BOOST_CHECK_EQUAL(sizeof(CScriptBase), 40);1186BOOST_CHECK_NE(sizeof(CScriptBase), sizeof(prevector<CScriptBase::STATIC_SIZE + 1, uint8_t>)); // CScriptBase size should be set to avoid wasting space in padding1187BOOST_CHECK_EQUAL(sizeof(CScript), 40);1188BOOST_CHECK_EQUAL(sizeof(CTxOut), 48);1190CKey dummy_key;1191dummy_key.MakeNewKey(/*fCompressed=*/true);1192const CPubKey dummy_pubkey{dummy_key.GetPubKey()};1194// Small OP_RETURN has direct allocation1195{1196const auto script{CScript() << OP_RETURN << std::vector<uint8_t>(10, 0xaa)};1197BOOST_CHECK_EQUAL(GetTxoutType(script), TxoutType::NULL_DATA);1198CHECK_SCRIPT_STATIC_SIZE(script, 12);1199}1201// P2WPKH has direct allocation1202{1203const auto script{GetScriptForDestination(WitnessV0KeyHash{PKHash{dummy_pubkey}})};1204BOOST_CHECK_EQUAL(GetTxoutType(script), TxoutType::WITNESS_V0_KEYHASH);1205CHECK_SCRIPT_STATIC_SIZE(script, 22);1206}1208// P2SH has direct allocation1209{1210const auto script{GetScriptForDestination(ScriptHash{CScript{} << OP_TRUE})};1211BOOST_CHECK(script.IsPayToScriptHash());1212CHECK_SCRIPT_STATIC_SIZE(script, 23);1213}1215// P2PKH has direct allocation1216{1217const auto script{GetScriptForDestination(PKHash{dummy_pubkey})};1218BOOST_CHECK_EQUAL(GetTxoutType(script), TxoutType::PUBKEYHASH);1219CHECK_SCRIPT_STATIC_SIZE(script, 25);1220}1222// P2WSH has direct allocation1223{1224const auto script{GetScriptForDestination(WitnessV0ScriptHash{CScript{} << OP_TRUE})};1225BOOST_CHECK(script.IsPayToWitnessScriptHash());1226CHECK_SCRIPT_STATIC_SIZE(script, 34);1227}1229// P2TR has direct allocation1230{1231const auto script{GetScriptForDestination(WitnessV1Taproot{XOnlyPubKey{dummy_pubkey}})};1232BOOST_CHECK_EQUAL(GetTxoutType(script), TxoutType::WITNESS_V1_TAPROOT);1233CHECK_SCRIPT_STATIC_SIZE(script, 34);1234}1236// Compressed P2PK has direct allocation1237{1238const auto script{GetScriptForRawPubKey(dummy_pubkey)};1239BOOST_CHECK_EQUAL(GetTxoutType(script), TxoutType::PUBKEY);1240CHECK_SCRIPT_STATIC_SIZE(script, 35);1241}1243// Uncompressed P2PK needs extra allocation1244{1245CKey uncompressed_key;1246uncompressed_key.MakeNewKey(/*fCompressed=*/false);1247const CPubKey uncompressed_pubkey{uncompressed_key.GetPubKey()};1249const auto script{GetScriptForRawPubKey(uncompressed_pubkey)};1250BOOST_CHECK_EQUAL(GetTxoutType(script), TxoutType::PUBKEY);
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.