script_util.py raw

   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_equal(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_equal(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_equal(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_equal(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_equal(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])))
 224