Skip to content

Commit b2d48dc

Browse files
LarryRuaneluke-jr
authored andcommitted
QA: script_tests: Check GetScriptForTransactionInput and CScript::DataCarrierBytes
Github-Pull: bitcoin#28408 Rebased-From: abd19ad
1 parent 343513a commit b2d48dc

File tree

1 file changed

+256
-0
lines changed

1 file changed

+256
-0
lines changed

src/test/script_tests.cpp

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <common/system.h>
99
#include <core_io.h>
1010
#include <key.h>
11+
#include <policy/policy.h>
1112
#include <rpc/util.h>
1213
#include <script/script.h>
1314
#include <script/script_error.h>
@@ -1481,6 +1482,261 @@ BOOST_AUTO_TEST_CASE(script_HasValidOps)
14811482
BOOST_CHECK(!script.HasValidOps());
14821483
}
14831484

1485+
BOOST_AUTO_TEST_CASE(script_DataCarrierBytes)
1486+
{
1487+
using zeros = std::vector<unsigned char>;
1488+
1489+
// empty script
1490+
BOOST_CHECK_EQUAL(0, (CScript()).DatacarrierBytes());
1491+
// series of pushes are not data
1492+
BOOST_CHECK_EQUAL(0, (CScript() << OP_0 << OP_0 << OP_0).DatacarrierBytes());
1493+
// unspendable if first op is OP_RETURN, then length(1), zeros(11)
1494+
BOOST_CHECK_EQUAL(13, (CScript() << OP_RETURN << zeros(11)).DatacarrierBytes());
1495+
// invalid script (no data following PUSHDATA) makes it all data
1496+
BOOST_CHECK_EQUAL(2, (CScript() << OP_0 << OP_PUSHDATA4).DatacarrierBytes());
1497+
// no data here
1498+
BOOST_CHECK_EQUAL(0, (CScript() << OP_TRUE << OP_IF << OP_ENDIF).DatacarrierBytes());
1499+
// specific data pattern, entire script is data
1500+
BOOST_CHECK_EQUAL(4, (CScript() << OP_FALSE << OP_IF << OP_7 << OP_ENDIF).DatacarrierBytes());
1501+
// consecutive data
1502+
BOOST_CHECK_EQUAL(6, (CScript() << OP_FALSE << OP_IF << OP_ENDIF << OP_FALSE << OP_IF << OP_ENDIF).DatacarrierBytes());
1503+
// nested data (all is data)
1504+
BOOST_CHECK_EQUAL(6, (CScript() << OP_FALSE << OP_IF << OP_TRUE << OP_IF << OP_ENDIF << OP_ENDIF).DatacarrierBytes());
1505+
// pushing then immediately dropping is data: length(1), zero(11), OP_DROP
1506+
BOOST_CHECK_EQUAL(13, (CScript() << zeros(11) << OP_DROP).DatacarrierBytes());
1507+
}
1508+
1509+
BOOST_AUTO_TEST_CASE(script_GetScriptForTransactionInput)
1510+
{
1511+
using zeros = std::vector<unsigned char>;
1512+
1513+
{ // P2PK - no datacarrier bytes (tx_in doesn't matter)
1514+
CScript prev_script; // scriptPubKey
1515+
CTxIn tx_in;
1516+
prev_script = CScript() << zeros(65) << OP_CHECKSIG;
1517+
tx_in.scriptSig = CScript();
1518+
auto [ret_script, scale] = GetScriptForTransactionInput(prev_script, tx_in);
1519+
BOOST_CHECK(ret_script == tx_in.scriptSig);
1520+
BOOST_CHECK_EQUAL(scale, WITNESS_SCALE_FACTOR);
1521+
BOOST_CHECK_EQUAL(ret_script.DatacarrierBytes(), 0);
1522+
}
1523+
{ // P2PKH - no datacarrier bytes
1524+
CScript prev_script; // scriptPubKey
1525+
CTxIn tx_in;
1526+
prev_script = CScript() << OP_DUP << OP_HASH160 << zeros(20) << OP_EQUALVERIFY << OP_CHECKSIG;
1527+
// signature, pubkey
1528+
tx_in.scriptSig = CScript() << zeros(72) << zeros(33);
1529+
auto [ret_script, scale] = GetScriptForTransactionInput(prev_script, tx_in);
1530+
BOOST_CHECK(ret_script == tx_in.scriptSig);
1531+
BOOST_CHECK_EQUAL(scale, WITNESS_SCALE_FACTOR);
1532+
BOOST_CHECK_EQUAL(ret_script.DatacarrierBytes(), 0);
1533+
}
1534+
{ // P2SH - no datacarrier bytes
1535+
CScript prev_script; // scriptPubKey
1536+
CTxIn tx_in;
1537+
CScript redeem_script = CScript() << OP_DROP << OP_TRUE;
1538+
prev_script = CScript() << OP_HASH160 << zeros(20) << OP_EQUAL;
1539+
// signature, pubkey, redeem_script
1540+
tx_in.scriptSig = CScript() << OP_7 << std::vector<unsigned char>(redeem_script.begin(), redeem_script.end());
1541+
// this should return the redeem script
1542+
auto [ret_script, scale] = GetScriptForTransactionInput(prev_script, tx_in);
1543+
BOOST_CHECK(ret_script == redeem_script);
1544+
BOOST_CHECK_EQUAL(scale, WITNESS_SCALE_FACTOR);
1545+
BOOST_CHECK_EQUAL(ret_script.DatacarrierBytes(), 0);
1546+
}
1547+
{ // P2SH - with datacarrier bytes
1548+
CScript prev_script; // scriptPubKey
1549+
CTxIn tx_in;
1550+
// arbitrary amount of data (27 bytes)
1551+
CScript redeem_script = CScript() << OP_RETURN << zeros(27);
1552+
prev_script = CScript() << OP_HASH160 << zeros(20) << OP_EQUAL;
1553+
// signature, pubkey, redeem_script
1554+
tx_in.scriptSig = CScript() << OP_7 << std::vector<unsigned char>(redeem_script.begin(), redeem_script.end());
1555+
// this should return the redeem script
1556+
auto [ret_script, scale] = GetScriptForTransactionInput(prev_script, tx_in);
1557+
BOOST_CHECK(ret_script == redeem_script);
1558+
BOOST_CHECK_EQUAL(scale, WITNESS_SCALE_FACTOR);
1559+
// OP_RETURN(1), length(1), zeros(27) = 29
1560+
BOOST_CHECK_EQUAL(ret_script.DatacarrierBytes(), 29);
1561+
}
1562+
{ // P2WPKH - no datacarrier bytes
1563+
CScript prev_script; // scriptPubKey
1564+
CTxIn tx_in;
1565+
// P2WPKH is [OP_0, hash160(pubkey)]
1566+
prev_script = CScript() << OP_0 << zeros(20);
1567+
// segwit: empty scriptsig
1568+
tx_in.scriptSig = CScript();
1569+
tx_in.scriptWitness.stack.emplace_back(65); // signature
1570+
tx_in.scriptWitness.stack.emplace_back(33); // pubkey
1571+
// this should return the redeem script
1572+
auto [ret_script, scale] = GetScriptForTransactionInput(prev_script, tx_in);
1573+
// should have no script at all since it's wrapped P2WPKH
1574+
BOOST_CHECK(ret_script == CScript());
1575+
BOOST_CHECK_EQUAL(scale, 0);
1576+
BOOST_CHECK_EQUAL(ret_script.DatacarrierBytes(), 0);
1577+
}
1578+
{ // P2WSH - no datacarrier bytes
1579+
CScript prev_script; // scriptPubKey
1580+
CTxIn tx_in;
1581+
prev_script = CScript() << OP_0 << zeros(32);
1582+
// segwit: empty scriptsig
1583+
tx_in.scriptSig = CScript();
1584+
tx_in.scriptWitness.stack.emplace_back(65); // arbitrary value to satisfy redeem script
1585+
CScript redeem_script = CScript() << OP_0;
1586+
auto redeem_vec{std::vector<unsigned char>(redeem_script.begin(), redeem_script.end())};
1587+
tx_in.scriptWitness.stack.push_back(redeem_vec);
1588+
// this should return the redeem script
1589+
auto [ret_script, scale] = GetScriptForTransactionInput(prev_script, tx_in);
1590+
BOOST_CHECK(ret_script == redeem_script);
1591+
BOOST_CHECK_EQUAL(scale, 1);
1592+
BOOST_CHECK_EQUAL(ret_script.DatacarrierBytes(), 0);
1593+
}
1594+
{ // P2WSH - some datacarrier bytes
1595+
CScript prev_script; // scriptPubKey
1596+
CTxIn tx_in;
1597+
prev_script = CScript() << OP_0 << zeros(32);
1598+
// segwit: empty scriptsig
1599+
tx_in.scriptSig = CScript();
1600+
tx_in.scriptWitness.stack.emplace_back(65); // arbitrary value to satisfy redeem script
1601+
CScript redeem_script = CScript() << OP_FALSE << OP_IF << zeros(10) << OP_ENDIF;
1602+
auto redeem_vec{std::vector<unsigned char>(redeem_script.begin(), redeem_script.end())};
1603+
tx_in.scriptWitness.stack.push_back(redeem_vec);
1604+
// this should return the redeem script
1605+
auto [ret_script, scale] = GetScriptForTransactionInput(prev_script, tx_in);
1606+
BOOST_CHECK(ret_script == redeem_script);
1607+
BOOST_CHECK_EQUAL(scale, 1);
1608+
// OP_FALSE(1), OP_IF(1), length(1), zeros(10), OP_ENDIF(1)
1609+
BOOST_CHECK_EQUAL(ret_script.DatacarrierBytes(), 14);
1610+
}
1611+
{ // P2SH-P2WPKH - no datacarrier bytes
1612+
CScript prev_script; // scriptPubKey
1613+
CTxIn tx_in;
1614+
// P2WPKH is [OP_0, hash160(pubkey)]
1615+
CScript redeem_script = CScript() << OP_0 << zeros(20);
1616+
prev_script = CScript() << OP_HASH160 << zeros(20) << OP_EQUAL;
1617+
tx_in.scriptSig = CScript() << std::vector<unsigned char>(redeem_script.begin(), redeem_script.end());
1618+
// this should return the redeem script
1619+
auto [ret_script, scale] = GetScriptForTransactionInput(prev_script, tx_in);
1620+
// should have no script at all since it's wrapped P2WPKH
1621+
BOOST_CHECK(ret_script == CScript());
1622+
// data bytes in the witness get discounted (*1 instead of *4)
1623+
BOOST_CHECK_EQUAL(scale, 0);
1624+
BOOST_CHECK_EQUAL(ret_script.DatacarrierBytes(), 0);
1625+
}
1626+
{ // P2SH-P2WSH - no datacarrier bytes
1627+
CScript prev_script; // scriptPubKey
1628+
CTxIn tx_in;
1629+
// P2WSH is [OP_0, sha256(redeem_script)]
1630+
CScript redeem_script = CScript() << OP_0 << zeros(32);
1631+
prev_script = CScript() << OP_HASH160 << zeros(20) << OP_EQUAL;
1632+
tx_in.scriptSig = CScript() << std::vector<unsigned char>(redeem_script.begin(), redeem_script.end());
1633+
CScript witness_redeem_script = CScript() << OP_TRUE << OP_IF << zeros(10) << OP_ENDIF;
1634+
1635+
// in real life, one or more values (to satisfy the redeem script) would be pushed to the stack
1636+
CScript wit = CScript() << OP_7;
1637+
tx_in.scriptWitness.stack.emplace_back(wit.begin(), wit.end());
1638+
// and then finally the redeem script itself (as the last stack element)
1639+
auto redeem_vec{std::vector<unsigned char>(witness_redeem_script.begin(), witness_redeem_script.end())};
1640+
tx_in.scriptWitness.stack.push_back(redeem_vec);
1641+
1642+
// this should return the witness redeem script
1643+
auto [ret_script, scale] = GetScriptForTransactionInput(prev_script, tx_in);
1644+
// should have no script at all since it's wrapped P2WPKH
1645+
BOOST_CHECK(ret_script == witness_redeem_script);
1646+
// data bytes in the witness get discounted (*1 instead of *4)
1647+
BOOST_CHECK_EQUAL(scale, 1);
1648+
BOOST_CHECK_EQUAL(ret_script.DatacarrierBytes(), 0);
1649+
}
1650+
{ // P2SH-P2WSH - some datacarrier bytes
1651+
CScript prev_script; // scriptPubKey
1652+
CTxIn tx_in;
1653+
// P2WSH is [OP_0, sha256(redeem_script)]
1654+
CScript redeem_script = CScript() << OP_0 << zeros(32);
1655+
prev_script = CScript() << OP_HASH160 << zeros(20) << OP_EQUAL;
1656+
tx_in.scriptSig = CScript() << std::vector<unsigned char>(redeem_script.begin(), redeem_script.end());
1657+
CScript witness_redeem_script = CScript() << OP_FALSE << OP_IF << zeros(10) << OP_ENDIF;
1658+
1659+
// in real life, one or more values (to satisfy the redeem script) would be pushed to the stack
1660+
CScript wit = CScript() << OP_7;
1661+
tx_in.scriptWitness.stack.emplace_back(wit.begin(), wit.end());
1662+
// and then finally the redeem script itself (as the last stack element)
1663+
auto redeem_vec{std::vector<unsigned char>(witness_redeem_script.begin(), witness_redeem_script.end())};
1664+
tx_in.scriptWitness.stack.push_back(redeem_vec);
1665+
1666+
// this should return the witness redeem script
1667+
auto [ret_script, scale] = GetScriptForTransactionInput(prev_script, tx_in);
1668+
// should have no script at all since it's wrapped P2WPKH
1669+
BOOST_CHECK(ret_script == witness_redeem_script);
1670+
// data bytes in the witness get discounted (*1 instead of *4)
1671+
BOOST_CHECK_EQUAL(scale, 1);
1672+
// OP_FALSE(1), OP_IF(1), length(1), zeros(10), OP_ENDIF(1) = 14
1673+
BOOST_CHECK_EQUAL(ret_script.DatacarrierBytes(), 14);
1674+
}
1675+
{ // P2TR keypath - no datacarrier bytes
1676+
CScript prev_script; // scriptPubKey
1677+
CTxIn tx_in;
1678+
prev_script = CScript() << OP_1 << zeros(32);
1679+
// segwit: empty scriptsig
1680+
tx_in.scriptSig = CScript();
1681+
tx_in.scriptWitness.stack.emplace_back(65); // signature
1682+
auto [ret_script, scale] = GetScriptForTransactionInput(prev_script, tx_in);
1683+
BOOST_CHECK(ret_script == CScript());
1684+
BOOST_CHECK_EQUAL(scale, 0);
1685+
BOOST_CHECK_EQUAL(ret_script.DatacarrierBytes(), 0);
1686+
}
1687+
{ // P2TR keypath - annex but no script - no datacarrier bytes
1688+
CScript prev_script; // scriptPubKey
1689+
CTxIn tx_in;
1690+
prev_script = CScript() << OP_1 << zeros(32);
1691+
// segwit: empty scriptsig
1692+
tx_in.scriptSig = CScript();
1693+
tx_in.scriptWitness.stack.emplace_back(65); // signature
1694+
std::vector<unsigned char> annex{0x50, 0, 0};
1695+
tx_in.scriptWitness.stack.push_back(annex);
1696+
auto [ret_script, scale] = GetScriptForTransactionInput(prev_script, tx_in);
1697+
BOOST_CHECK(ret_script == CScript());
1698+
BOOST_CHECK_EQUAL(scale, 0);
1699+
BOOST_CHECK_EQUAL(ret_script.DatacarrierBytes(), 0);
1700+
}
1701+
{ // P2TR scriptpath - no datacarrier bytes
1702+
CScript prev_script; // scriptPubKey
1703+
CTxIn tx_in;
1704+
prev_script = CScript() << OP_1 << zeros(32);
1705+
// segwit: empty scriptsig
1706+
tx_in.scriptSig = CScript();
1707+
// stack: zero or more arbitrary values (script arguments); script; control block
1708+
// (here we have two arbitrary values)
1709+
tx_in.scriptWitness.stack.emplace_back(85); // arbitrary value
1710+
tx_in.scriptWitness.stack.emplace_back(10); // arbitrary value
1711+
CScript script = CScript() << OP_7 << OP_8;
1712+
auto script_vec{std::vector<unsigned char>(script.begin(), script.end())};
1713+
tx_in.scriptWitness.stack.push_back(script_vec);
1714+
tx_in.scriptWitness.stack.emplace_back(33); // control block
1715+
auto [ret_script, scale] = GetScriptForTransactionInput(prev_script, tx_in);
1716+
BOOST_CHECK(ret_script == script);
1717+
BOOST_CHECK_EQUAL(scale, 1);
1718+
BOOST_CHECK_EQUAL(ret_script.DatacarrierBytes(), 0);
1719+
}
1720+
{ // P2TR scriptpath - some datacarrier bytes
1721+
CScript prev_script; // scriptPubKey
1722+
CTxIn tx_in;
1723+
prev_script = CScript() << OP_1 << zeros(32);
1724+
// segwit: empty scriptsig
1725+
tx_in.scriptSig = CScript();
1726+
// stack: zero or more arbitrary values (script arguments); script; control block
1727+
// (here we have one arbitrary value)
1728+
tx_in.scriptWitness.stack.emplace_back(85); // arbitrary value
1729+
CScript script = CScript() << OP_RETURN << OP_7 << OP_8;
1730+
auto script_vec{std::vector<unsigned char>(script.begin(), script.end())};
1731+
tx_in.scriptWitness.stack.push_back(script_vec);
1732+
tx_in.scriptWitness.stack.emplace_back(33); // control block
1733+
auto [ret_script, scale] = GetScriptForTransactionInput(prev_script, tx_in);
1734+
BOOST_CHECK(ret_script == script);
1735+
BOOST_CHECK_EQUAL(scale, 1);
1736+
BOOST_CHECK_EQUAL(ret_script.DatacarrierBytes(), 3);
1737+
}
1738+
}
1739+
14841740
static CMutableTransaction TxFromHex(const std::string& str)
14851741
{
14861742
CMutableTransaction tx;

0 commit comments

Comments
 (0)