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.
1251CHECK_SCRIPT_DYNAMIC_SIZE(script, 67, 67);1252}1254// Bare multisig needs extra allocation1255{1256const auto script{GetScriptForMultisig(1, std::vector{2, dummy_pubkey})};1257BOOST_CHECK_EQUAL(GetTxoutType(script), TxoutType::MULTISIG);1258CHECK_SCRIPT_DYNAMIC_SIZE(script, 71, 103);1259}1260}1262/* Wrapper around ProduceSignature to combine two scriptsigs */1263SignatureData CombineSignatures(const CTxOut& txout, const CMutableTransaction& tx, const SignatureData& scriptSig1, const SignatureData& scriptSig2)1264{1265SignatureData data;1266data.MergeSignatureData(scriptSig1);1267data.MergeSignatureData(scriptSig2);1268ProduceSignature(DUMMY_SIGNING_PROVIDER, MutableTransactionSignatureCreator(tx, 0, txout.nValue, {.sighash_type = SIGHASH_DEFAULT}), txout.scriptPubKey, data);1269return data;1270}1272BOOST_AUTO_TEST_CASE(script_combineSigs)1273{1274// Test the ProduceSignature's ability to combine signatures function1275FillableSigningProvider keystore;1276std::vector<CKey> keys;1277std::vector<CPubKey> pubkeys;1278for (int i = 0; i < 3; i++)1279{1280CKey key = GenerateRandomKey(/*compressed=*/i%2 == 1);1281keys.push_back(key);1282pubkeys.push_back(key.GetPubKey());1283BOOST_CHECK(keystore.AddKey(key));1284}1286CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(PKHash(keys[0].GetPubKey())));1287CMutableTransaction txTo = BuildSpendingTransaction(CScript(), CScriptWitness(), CTransaction(txFrom));1288CScript& scriptPubKey = txFrom.vout[0].scriptPubKey;1289SignatureData scriptSig;1291SignatureData empty;1292SignatureData combined = CombineSignatures(txFrom.vout[0], txTo, empty, empty);1293BOOST_CHECK(combined.scriptSig.empty());1295// Single signature case:1296SignatureData dummy;1297BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL, dummy)); // changes scriptSig1298scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);1299combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty);1300BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);1301combined = CombineSignatures(txFrom.vout[0], txTo, empty, scriptSig);1302BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);1303SignatureData scriptSigCopy = scriptSig;1304// Signing again will give a different, valid signature:1305SignatureData dummy_b;1306BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL, dummy_b));1307scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);1308combined = CombineSignatures(txFrom.vout[0], txTo, scriptSigCopy, scriptSig);1309BOOST_CHECK(combined.scriptSig == scriptSigCopy.scriptSig || combined.scriptSig == scriptSig.scriptSig);1311// P2SH, single-signature case:1312CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG;1313BOOST_CHECK(keystore.AddCScript(pkSingle));1314scriptPubKey = GetScriptForDestination(ScriptHash(pkSingle));1315SignatureData dummy_c;1316BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL, dummy_c));1317scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);1318combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty);1319BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);1320combined = CombineSignatures(txFrom.vout[0], txTo, empty, scriptSig);1321BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);1322scriptSigCopy = scriptSig;1323SignatureData dummy_d;1324BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL, dummy_d));1325scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);1326combined = CombineSignatures(txFrom.vout[0], txTo, scriptSigCopy, scriptSig);1327BOOST_CHECK(combined.scriptSig == scriptSigCopy.scriptSig || combined.scriptSig == scriptSig.scriptSig);1329// Hardest case: Multisig 2-of-31330scriptPubKey = GetScriptForMultisig(2, pubkeys);1331BOOST_CHECK(keystore.AddCScript(scriptPubKey));1332SignatureData dummy_e;1333BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL, dummy_e));1334scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);1335combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty);1336BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);1337combined = CombineSignatures(txFrom.vout[0], txTo, empty, scriptSig);1338BOOST_CHECK(combined.scriptSig == scriptSig.scriptSig);1340// A couple of partially-signed versions:1341std::vector<unsigned char> sig1;1342uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, SigVersion::BASE);1343BOOST_CHECK(keys[0].Sign(hash1, sig1));1344sig1.push_back(SIGHASH_ALL);1345std::vector<unsigned char> sig2;1346uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, SigVersion::BASE);1347BOOST_CHECK(keys[1].Sign(hash2, sig2));1348sig2.push_back(SIGHASH_NONE);1349std::vector<unsigned char> sig3;1350uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, SigVersion::BASE);1351BOOST_CHECK(keys[2].Sign(hash3, sig3));1352sig3.push_back(SIGHASH_SINGLE);1354// Not fussy about order (or even existence) of placeholders or signatures:1355CScript partial1a = CScript() << OP_0 << sig1 << OP_0;1356CScript partial1b = CScript() << OP_0 << OP_0 << sig1;1357CScript partial2a = CScript() << OP_0 << sig2;1358CScript partial2b = CScript() << sig2 << OP_0;1359CScript partial3a = CScript() << sig3;1360CScript partial3b = CScript() << OP_0 << OP_0 << sig3;1361CScript partial3c = CScript() << OP_0 << sig3 << OP_0;1362CScript complete12 = CScript() << OP_0 << sig1 << sig2;1363CScript complete13 = CScript() << OP_0 << sig1 << sig3;1364CScript complete23 = CScript() << OP_0 << sig2 << sig3;1365SignatureData partial1_sigs;1366partial1_sigs.signatures.emplace(keys[0].GetPubKey().GetID(), SigPair(keys[0].GetPubKey(), sig1));1367SignatureData partial2_sigs;1368partial2_sigs.signatures.emplace(keys[1].GetPubKey().GetID(), SigPair(keys[1].GetPubKey(), sig2));1369SignatureData partial3_sigs;1370partial3_sigs.signatures.emplace(keys[2].GetPubKey().GetID(), SigPair(keys[2].GetPubKey(), sig3));1372combined = CombineSignatures(txFrom.vout[0], txTo, partial1_sigs, partial1_sigs);1373BOOST_CHECK(combined.scriptSig == partial1a);1374combined = CombineSignatures(txFrom.vout[0], txTo, partial1_sigs, partial2_sigs);1375BOOST_CHECK(combined.scriptSig == complete12);1376combined = CombineSignatures(txFrom.vout[0], txTo, partial2_sigs, partial1_sigs);1377BOOST_CHECK(combined.scriptSig == complete12);1378combined = CombineSignatures(txFrom.vout[0], txTo, partial1_sigs, partial2_sigs);1379BOOST_CHECK(combined.scriptSig == complete12);1380combined = CombineSignatures(txFrom.vout[0], txTo, partial3_sigs, partial1_sigs);1381BOOST_CHECK(combined.scriptSig == complete13);1382combined = CombineSignatures(txFrom.vout[0], txTo, partial2_sigs, partial3_sigs);1383BOOST_CHECK(combined.scriptSig == complete23);1384combined = CombineSignatures(txFrom.vout[0], txTo, partial3_sigs, partial2_sigs);1385BOOST_CHECK(combined.scriptSig == complete23);1386combined = CombineSignatures(txFrom.vout[0], txTo, partial3_sigs, partial3_sigs);1387BOOST_CHECK(combined.scriptSig == partial3c);1388}1390/**1391* Reproduction of an exception incorrectly raised when parsing a public key inside a TapMiniscript.1392*/1393BOOST_AUTO_TEST_CASE(sign_invalid_miniscript)1394{1395FillableSigningProvider keystore;1396SignatureData sig_data;1397CMutableTransaction prev, curr;1399// Create a Taproot output which contains a leaf in which a non-32 bytes push is used where a public key is expected1400// by the Miniscript parser. This offending Script was found by the RPC fuzzer.1401const auto invalid_pubkey{"173d36c8c9c9c9ffffffffffff0200000000021e1e37373721361818181818181e1e1e1e19000000000000000000b19292929292926b006c9b9b9292"_hex_u8};1402TaprootBuilder builder;1403builder.Add(0, {invalid_pubkey}, 0xc0);1404builder.Finalize(XOnlyPubKey::NUMS_H);1405prev.vout.emplace_back(0, GetScriptForDestination(builder.GetOutput()));1406curr.vin.emplace_back(COutPoint{prev.GetHash(), 0});1407sig_data.tr_spenddata = builder.GetSpendData();1409// SignSignature can fail but it shouldn't raise an exception (nor crash).1410BOOST_CHECK(!SignSignature(keystore, CTransaction(prev), curr, 0, SIGHASH_ALL, sig_data));1411}1413/* P2A input should be considered signed. */1414BOOST_AUTO_TEST_CASE(sign_paytoanchor)1415{1416FillableSigningProvider keystore;1417SignatureData sig_data;1418CMutableTransaction prev, curr;1419prev.vout.emplace_back(0, GetScriptForDestination(PayToAnchor{}));1421curr.vin.emplace_back(COutPoint{prev.GetHash(), 0});1423BOOST_CHECK(SignSignature(keystore, CTransaction(prev), curr, 0, SIGHASH_ALL, sig_data));1424}1426BOOST_AUTO_TEST_CASE(script_standard_push)1427{1428ScriptError err;1429for (int i=0; i<67000; i++) {1430CScript script;1431script << i;1432BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push.");1433BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, nullptr, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Number " << i << " push is not minimal data.");1434BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));1435}1437for (unsigned int i=0; i<=MAX_SCRIPT_ELEMENT_SIZE; i++) {1438std::vector<unsigned char> data(i, '\111');1439CScript script;1440script << data;1441BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push.");1442BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, nullptr, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Length " << i << " push is not minimal data.");1443BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));1444}1445}1447BOOST_AUTO_TEST_CASE(script_IsPushOnly_on_invalid_scripts)1448{1449// IsPushOnly returns false when given a script containing only pushes that1450// are invalid due to truncation. IsPushOnly() is consensus critical1451// because P2SH evaluation uses it, although this specific behavior should1452// not be consensus critical as the P2SH evaluation would fail first due to1453// the invalid push. Still, it doesn't hurt to test it explicitly.1454static const unsigned char direct[] = { 1 };1455BOOST_CHECK(!CScript(direct, direct+sizeof(direct)).IsPushOnly());1456}1458BOOST_AUTO_TEST_CASE(script_CheckMinimalPush_boundary)1459{1460// Test the boundary at exactly 65535 bytes: must use OP_PUSHDATA2, not OP_PUSHDATA4.1461std::vector<unsigned char> data(65535, '\x42');1462BOOST_CHECK(CheckMinimalPush(data, OP_PUSHDATA2));1463BOOST_CHECK(!CheckMinimalPush(data, OP_PUSHDATA4));1464}1466BOOST_AUTO_TEST_CASE(script_GetScriptAsm)1467{1468BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2, true));1469BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY, true));1470BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2));1471BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY));1473std::string derSig("304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090");1474std::string pubKey("03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2");1475std::vector<unsigned char> vchPubKey = ToByteVector(ParseHex(pubKey));1477BOOST_CHECK_EQUAL(derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey, true));1478BOOST_CHECK_EQUAL(derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey, true));1479BOOST_CHECK_EQUAL(derSig + "[ALL] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "01")) << vchPubKey, true));1480BOOST_CHECK_EQUAL(derSig + "[NONE] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "02")) << vchPubKey, true));1481BOOST_CHECK_EQUAL(derSig + "[SINGLE] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "03")) << vchPubKey, true));1482BOOST_CHECK_EQUAL(derSig + "[ALL|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "81")) << vchPubKey, true));1483BOOST_CHECK_EQUAL(derSig + "[NONE|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "82")) << vchPubKey, true));1484BOOST_CHECK_EQUAL(derSig + "[SINGLE|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey, true));1486BOOST_CHECK_EQUAL(derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey));1487BOOST_CHECK_EQUAL(derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey));1488BOOST_CHECK_EQUAL(derSig + "01 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "01")) << vchPubKey));1489BOOST_CHECK_EQUAL(derSig + "02 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "02")) << vchPubKey));1490BOOST_CHECK_EQUAL(derSig + "03 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "03")) << vchPubKey));1491BOOST_CHECK_EQUAL(derSig + "81 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "81")) << vchPubKey));1492BOOST_CHECK_EQUAL(derSig + "82 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "82")) << vchPubKey));1493BOOST_CHECK_EQUAL(derSig + "83 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey));1494}1496template <typename T>1497CScript ToScript(const T& byte_container)1498{1499auto span{MakeUCharSpan(byte_container)};1500return {span.begin(), span.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.