|
8 | 8 | #include <common/system.h>
|
9 | 9 | #include <core_io.h>
|
10 | 10 | #include <key.h>
|
| 11 | +#include <policy/policy.h> |
11 | 12 | #include <rpc/util.h>
|
12 | 13 | #include <script/script.h>
|
13 | 14 | #include <script/script_error.h>
|
@@ -1481,6 +1482,261 @@ BOOST_AUTO_TEST_CASE(script_HasValidOps)
|
1481 | 1482 | BOOST_CHECK(!script.HasValidOps());
|
1482 | 1483 | }
|
1483 | 1484 |
|
| 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 | + |
1484 | 1740 | static CMutableTransaction TxFromHex(const std::string& str)
|
1485 | 1741 | {
|
1486 | 1742 | CMutableTransaction tx;
|
|
0 commit comments