/ test / functional / test_framework / script_util.py
script_util.py
  1  #!/usr/bin/env python3
  2  # Copyright (c) 2019-present The Bitcoin Core developers
  3  # Distributed under the MIT software license, see the accompanying
  4  # file COPYING or http://www.opensource.org/licenses/mit-license.php.
  5  """Useful Script constants and utils."""
  6  import unittest
  7  
  8  from copy import deepcopy
  9  
 10  from test_framework.messages import (
 11      COutPoint,
 12      CTransaction,
 13      CTxIn,
 14      CTxInWitness,
 15      CTxOut,
 16      ser_compact_size,
 17      sha256,
 18  )
 19  from test_framework.script import (
 20      CScript,
 21      OP_0,
 22      OP_1,
 23      OP_15,
 24      OP_16,
 25      OP_CHECKMULTISIG,
 26      OP_CHECKSIG,
 27      OP_DUP,
 28      OP_ELSE,
 29      OP_ENDIF,
 30      OP_EQUAL,
 31      OP_EQUALVERIFY,
 32      OP_HASH160,
 33      OP_IF,
 34      OP_RETURN,
 35      OP_TRUE,
 36      hash160,
 37  )
 38  
 39  from test_framework.util import (
 40      assert_greater_than_or_equal,
 41      assert_equal,
 42  )
 43  
 44  # Maximum number of potentially executed legacy signature operations in validating a transaction.
 45  MAX_STD_LEGACY_SIGOPS = 2_500
 46  
 47  # Maximum number of sigops per standard P2SH redeemScript.
 48  MAX_STD_P2SH_SIGOPS = 15
 49  
 50  # To prevent a "tx-size-small" policy rule error, a transaction has to have a
 51  # non-witness size of at least 65 bytes (MIN_STANDARD_TX_NONWITNESS_SIZE in
 52  # src/policy/policy.h). Considering a Tx with the smallest possible single
 53  # input (blank, empty scriptSig), and with an output omitting the scriptPubKey,
 54  # we get to a minimum size of 60 bytes:
 55  #
 56  # Tx Skeleton: 4 [Version] + 1 [InCount] + 1 [OutCount] + 4 [LockTime] = 10 bytes
 57  # Blank Input: 32 [PrevTxHash] + 4 [Index] + 1 [scriptSigLen] + 4 [SeqNo] = 41 bytes
 58  # Output:      8 [Amount] + 1 [scriptPubKeyLen] = 9 bytes
 59  #
 60  # Hence, the scriptPubKey of the single output has to have a size of at
 61  # least 5 bytes.
 62  MIN_STANDARD_TX_NONWITNESS_SIZE = 65
 63  MIN_PADDING = MIN_STANDARD_TX_NONWITNESS_SIZE - 10 - 41 - 9
 64  assert MIN_PADDING == 5
 65  
 66  # This script cannot be spent, allowing dust output values under
 67  # standardness checks
 68  DUMMY_MIN_OP_RETURN_SCRIPT = CScript([OP_RETURN] + ([OP_0] * (MIN_PADDING - 1)))
 69  assert len(DUMMY_MIN_OP_RETURN_SCRIPT) == MIN_PADDING
 70  
 71  PAY_TO_ANCHOR = CScript([OP_1, bytes.fromhex("4e73")])
 72  ANCHOR_ADDRESS = "bcrt1pfeesnyr2tx"
 73  
 74  def key_to_p2pk_script(key):
 75      key = check_key(key)
 76      return CScript([key, OP_CHECKSIG])
 77  
 78  
 79  def keys_to_multisig_script(keys, *, k=None):
 80      n = len(keys)
 81      if k is None:  # n-of-n multisig by default
 82          k = n
 83      assert k <= n
 84      checked_keys = [check_key(key) for key in keys]
 85      return CScript([k] + checked_keys + [n, OP_CHECKMULTISIG])
 86  
 87  
 88  def keyhash_to_p2pkh_script(hash):
 89      assert len(hash) == 20
 90      return CScript([OP_DUP, OP_HASH160, hash, OP_EQUALVERIFY, OP_CHECKSIG])
 91  
 92  
 93  def scripthash_to_p2sh_script(hash):
 94      assert len(hash) == 20
 95      return CScript([OP_HASH160, hash, OP_EQUAL])
 96  
 97  
 98  def key_to_p2pkh_script(key):
 99      key = check_key(key)
100      return keyhash_to_p2pkh_script(hash160(key))
101  
102  
103  def script_to_p2sh_script(script):
104      script = check_script(script)
105      return scripthash_to_p2sh_script(hash160(script))
106  
107  
108  def key_to_p2sh_p2wpkh_script(key):
109      key = check_key(key)
110      p2shscript = CScript([OP_0, hash160(key)])
111      return script_to_p2sh_script(p2shscript)
112  
113  
114  def program_to_witness_script(version, program):
115      if isinstance(program, str):
116          program = bytes.fromhex(program)
117      assert 0 <= version <= 16
118      assert 2 <= len(program) <= 40
119      assert version > 0 or len(program) in [20, 32]
120      return CScript([version, program])
121  
122  
123  def script_to_p2wsh_script(script):
124      script = check_script(script)
125      return program_to_witness_script(0, sha256(script))
126  
127  
128  def key_to_p2wpkh_script(key):
129      key = check_key(key)
130      return program_to_witness_script(0, hash160(key))
131  
132  
133  def script_to_p2sh_p2wsh_script(script):
134      script = check_script(script)
135      p2shscript = CScript([OP_0, sha256(script)])
136      return script_to_p2sh_script(p2shscript)
137  
138  def bulk_vout(tx, target_vsize):
139      if target_vsize < tx.get_vsize():
140          raise RuntimeError(f"target_vsize {target_vsize} is less than transaction virtual size {tx.get_vsize()}")
141      # determine number of needed padding bytes
142      dummy_vbytes = target_vsize - tx.get_vsize()
143      # compensate for the increase of the compact-size encoded script length
144      # (note that the length encoding of the unpadded output script needs one byte)
145      dummy_vbytes -= len(ser_compact_size(dummy_vbytes)) - 1
146      tx.vout[-1].scriptPubKey = CScript([OP_RETURN] + [OP_1] * dummy_vbytes)
147      assert_equal(tx.get_vsize(), target_vsize)
148  
149  def output_key_to_p2tr_script(key):
150      assert len(key) == 32
151      return program_to_witness_script(1, key)
152  
153  
154  def check_key(key):
155      if isinstance(key, str):
156          key = bytes.fromhex(key)  # Assuming this is hex string
157      if isinstance(key, bytes) and (len(key) == 33 or len(key) == 65):
158          return key
159      assert False
160  
161  
162  def check_script(script):
163      if isinstance(script, str):
164          script = bytes.fromhex(script)  # Assuming this is hex string
165      if isinstance(script, bytes) or isinstance(script, CScript):
166          return script
167      assert False
168  
169  
170  def build_malleated_tx_package(*, parent: CTransaction, rebalance_parent_output_amount, child_amount):
171      """
172      Returns a transaction package with valid witness:
173      - Parent transaction whose last output contains a script that has two spending conditions
174      - Two malleated child transactions with same txid but different wtxids because of different witnesses
175  
176      Args:
177          parent: Transaction with modifiable outputs. Either unsigned (sign after
178          calling this function) or anyone-can-spend (e.g., MiniWallet's OP_TRUE).
179      """
180      hashlock = hash160(b'Preimage')
181      witness_script = CScript([OP_IF, OP_HASH160, hashlock, OP_EQUAL, OP_ELSE, OP_TRUE, OP_ENDIF])
182      witness_program = sha256(witness_script)
183      script_pubkey = CScript([OP_0, witness_program])
184  
185      # Append to the transaction the vout containing the script supporting 2 spending conditions
186      assert_greater_than_or_equal(len(parent.vout), 1)
187      last_output = parent.vout[len(parent.vout) - 1]
188      assert_greater_than_or_equal(last_output.nValue, rebalance_parent_output_amount)
189      last_output.nValue -= rebalance_parent_output_amount
190      parent.vout.append(CTxOut(rebalance_parent_output_amount, script_pubkey))
191  
192  
193      # Create 2 valid children that differ only in witness data.
194      # 1. Create a new transaction with witness solving first branch
195      child_witness_script = CScript([OP_TRUE])
196      child_witness_program = sha256(child_witness_script)
197      child_script_pubkey = CScript([OP_0, child_witness_program])
198      child_one = CTransaction()
199  
200      child_one.vin.append(CTxIn(COutPoint(int(parent.txid_hex, 16), len(parent.vout) - 1), b""))
201      child_one.vout.append(CTxOut(child_amount, child_script_pubkey))
202      child_one.wit.vtxinwit.append(CTxInWitness())
203      child_one.wit.vtxinwit[0].scriptWitness.stack = [b'Preimage', b'\x01', witness_script]
204      # 2. Create another identical transaction with witness solving second branch
205      child_two = deepcopy(child_one)
206      child_two.wit.vtxinwit[0].scriptWitness.stack = [b'', witness_script]
207      return parent, child_one, child_two
208  
209  
210  class TestFrameworkScriptUtil(unittest.TestCase):
211      def test_multisig(self):
212          fake_pubkey = bytes([0]*33)
213          # check correct encoding of P2MS script with n,k <= 16
214          normal_ms_script = keys_to_multisig_script([fake_pubkey]*16, k=15)
215          self.assertEqual(len(normal_ms_script), 1 + 16*34 + 1 + 1)
216          self.assertTrue(normal_ms_script.startswith(bytes([OP_15])))
217          self.assertTrue(normal_ms_script.endswith(bytes([OP_16, OP_CHECKMULTISIG])))
218  
219          # check correct encoding of P2MS script with n,k > 16
220          max_ms_script = keys_to_multisig_script([fake_pubkey]*20, k=19)
221          self.assertEqual(len(max_ms_script), 2 + 20*34 + 2 + 1)
222          self.assertTrue(max_ms_script.startswith(bytes([1, 19])))  # using OP_PUSH1
223          self.assertTrue(max_ms_script.endswith(bytes([1, 20, OP_CHECKMULTISIG])))