/ test / functional / test_framework / blocktools.py
blocktools.py
  1  #!/usr/bin/env python3
  2  # Copyright (c) 2015-2022 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  """Utilities for manipulating blocks and transactions."""
  6  
  7  import struct
  8  import time
  9  import unittest
 10  
 11  from .address import (
 12      address_to_scriptpubkey,
 13      key_to_p2sh_p2wpkh,
 14      key_to_p2wpkh,
 15      script_to_p2sh_p2wsh,
 16      script_to_p2wsh,
 17  )
 18  from .messages import (
 19      CBlock,
 20      COIN,
 21      COutPoint,
 22      CTransaction,
 23      CTxIn,
 24      CTxInWitness,
 25      CTxOut,
 26      SEQUENCE_FINAL,
 27      hash256,
 28      ser_uint256,
 29      tx_from_hex,
 30      uint256_from_str,
 31  )
 32  from .script import (
 33      CScript,
 34      CScriptNum,
 35      CScriptOp,
 36      OP_1,
 37      OP_RETURN,
 38      OP_TRUE,
 39  )
 40  from .script_util import (
 41      key_to_p2pk_script,
 42      key_to_p2wpkh_script,
 43      keys_to_multisig_script,
 44      script_to_p2wsh_script,
 45  )
 46  from .util import assert_equal
 47  
 48  WITNESS_SCALE_FACTOR = 4
 49  MAX_BLOCK_SIGOPS = 20000
 50  MAX_BLOCK_SIGOPS_WEIGHT = MAX_BLOCK_SIGOPS * WITNESS_SCALE_FACTOR
 51  
 52  # Genesis block time (regtest)
 53  TIME_GENESIS_BLOCK = 1296688602
 54  
 55  MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60
 56  
 57  # Coinbase transaction outputs can only be spent after this number of new blocks (network rule)
 58  COINBASE_MATURITY = 100
 59  
 60  # From BIP141
 61  WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed"
 62  
 63  NORMAL_GBT_REQUEST_PARAMS = {"rules": ["segwit"]}
 64  VERSIONBITS_LAST_OLD_BLOCK_VERSION = 4
 65  MIN_BLOCKS_TO_KEEP = 288
 66  
 67  
 68  def create_block(hashprev=None, coinbase=None, ntime=None, *, version=None, tmpl=None, txlist=None):
 69      """Create a block (with regtest difficulty)."""
 70      block = CBlock()
 71      if tmpl is None:
 72          tmpl = {}
 73      block.nVersion = version or tmpl.get('version') or VERSIONBITS_LAST_OLD_BLOCK_VERSION
 74      block.nTime = ntime or tmpl.get('curtime') or int(time.time() + 600)
 75      block.hashPrevBlock = hashprev or int(tmpl['previousblockhash'], 0x10)
 76      if tmpl and not tmpl.get('bits') is None:
 77          block.nBits = struct.unpack('>I', bytes.fromhex(tmpl['bits']))[0]
 78      else:
 79          block.nBits = 0x207fffff  # difficulty retargeting is disabled in REGTEST chainparams
 80      if coinbase is None:
 81          coinbase = create_coinbase(height=tmpl['height'])
 82      block.vtx.append(coinbase)
 83      if txlist:
 84          for tx in txlist:
 85              if not hasattr(tx, 'calc_sha256'):
 86                  tx = tx_from_hex(tx)
 87              block.vtx.append(tx)
 88      block.hashMerkleRoot = block.calc_merkle_root()
 89      block.calc_sha256()
 90      return block
 91  
 92  def get_witness_script(witness_root, witness_nonce):
 93      witness_commitment = uint256_from_str(hash256(ser_uint256(witness_root) + ser_uint256(witness_nonce)))
 94      output_data = WITNESS_COMMITMENT_HEADER + ser_uint256(witness_commitment)
 95      return CScript([OP_RETURN, output_data])
 96  
 97  def add_witness_commitment(block, nonce=0):
 98      """Add a witness commitment to the block's coinbase transaction.
 99  
100      According to BIP141, blocks with witness rules active must commit to the
101      hash of all in-block transactions including witness."""
102      # First calculate the merkle root of the block's
103      # transactions, with witnesses.
104      witness_nonce = nonce
105      witness_root = block.calc_witness_merkle_root()
106      # witness_nonce should go to coinbase witness.
107      block.vtx[0].wit.vtxinwit = [CTxInWitness()]
108      block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(witness_nonce)]
109  
110      # witness commitment is the last OP_RETURN output in coinbase
111      block.vtx[0].vout.append(CTxOut(0, get_witness_script(witness_root, witness_nonce)))
112      block.vtx[0].rehash()
113      block.hashMerkleRoot = block.calc_merkle_root()
114      block.rehash()
115  
116  
117  def script_BIP34_coinbase_height(height):
118      if height <= 16:
119          res = CScriptOp.encode_op_n(height)
120          # Append dummy to increase scriptSig size above 2 (see bad-cb-length consensus rule)
121          return CScript([res, OP_1])
122      return CScript([CScriptNum(height)])
123  
124  
125  def create_coinbase(height, pubkey=None, *, script_pubkey=None, extra_output_script=None, fees=0, nValue=50):
126      """Create a coinbase transaction.
127  
128      If pubkey is passed in, the coinbase output will be a P2PK output;
129      otherwise an anyone-can-spend output.
130  
131      If extra_output_script is given, make a 0-value output to that
132      script. This is useful to pad block weight/sigops as needed. """
133      coinbase = CTransaction()
134      coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff), script_BIP34_coinbase_height(height), SEQUENCE_FINAL))
135      coinbaseoutput = CTxOut()
136      coinbaseoutput.nValue = nValue * COIN
137      if nValue == 50:
138          halvings = int(height / 150)  # regtest
139          coinbaseoutput.nValue >>= halvings
140          coinbaseoutput.nValue += fees
141      if pubkey is not None:
142          coinbaseoutput.scriptPubKey = key_to_p2pk_script(pubkey)
143      elif script_pubkey is not None:
144          coinbaseoutput.scriptPubKey = script_pubkey
145      else:
146          coinbaseoutput.scriptPubKey = CScript([OP_TRUE])
147      coinbase.vout = [coinbaseoutput]
148      if extra_output_script is not None:
149          coinbaseoutput2 = CTxOut()
150          coinbaseoutput2.nValue = 0
151          coinbaseoutput2.scriptPubKey = extra_output_script
152          coinbase.vout.append(coinbaseoutput2)
153      coinbase.calc_sha256()
154      return coinbase
155  
156  def create_tx_with_script(prevtx, n, script_sig=b"", *, amount, script_pub_key=CScript()):
157      """Return one-input, one-output transaction object
158         spending the prevtx's n-th output with the given amount.
159  
160         Can optionally pass scriptPubKey and scriptSig, default is anyone-can-spend output.
161      """
162      tx = CTransaction()
163      assert n < len(prevtx.vout)
164      tx.vin.append(CTxIn(COutPoint(prevtx.sha256, n), script_sig, SEQUENCE_FINAL))
165      tx.vout.append(CTxOut(amount, script_pub_key))
166      tx.calc_sha256()
167      return tx
168  
169  def get_legacy_sigopcount_block(block, accurate=True):
170      count = 0
171      for tx in block.vtx:
172          count += get_legacy_sigopcount_tx(tx, accurate)
173      return count
174  
175  def get_legacy_sigopcount_tx(tx, accurate=True):
176      count = 0
177      for i in tx.vout:
178          count += i.scriptPubKey.GetSigOpCount(accurate)
179      for j in tx.vin:
180          # scriptSig might be of type bytes, so convert to CScript for the moment
181          count += CScript(j.scriptSig).GetSigOpCount(accurate)
182      return count
183  
184  def witness_script(use_p2wsh, pubkey):
185      """Create a scriptPubKey for a pay-to-witness TxOut.
186  
187      This is either a P2WPKH output for the given pubkey, or a P2WSH output of a
188      1-of-1 multisig for the given pubkey. Returns the hex encoding of the
189      scriptPubKey."""
190      if not use_p2wsh:
191          # P2WPKH instead
192          pkscript = key_to_p2wpkh_script(pubkey)
193      else:
194          # 1-of-1 multisig
195          witness_script = keys_to_multisig_script([pubkey])
196          pkscript = script_to_p2wsh_script(witness_script)
197      return pkscript.hex()
198  
199  def create_witness_tx(node, use_p2wsh, utxo, pubkey, encode_p2sh, amount):
200      """Return a transaction (in hex) that spends the given utxo to a segwit output.
201  
202      Optionally wrap the segwit output using P2SH."""
203      if use_p2wsh:
204          program = keys_to_multisig_script([pubkey])
205          addr = script_to_p2sh_p2wsh(program) if encode_p2sh else script_to_p2wsh(program)
206      else:
207          addr = key_to_p2sh_p2wpkh(pubkey) if encode_p2sh else key_to_p2wpkh(pubkey)
208      if not encode_p2sh:
209          assert_equal(address_to_scriptpubkey(addr).hex(), witness_script(use_p2wsh, pubkey))
210      return node.createrawtransaction([utxo], {addr: amount})
211  
212  def send_to_witness(use_p2wsh, node, utxo, pubkey, encode_p2sh, amount, sign=True, insert_redeem_script=""):
213      """Create a transaction spending a given utxo to a segwit output.
214  
215      The output corresponds to the given pubkey: use_p2wsh determines whether to
216      use P2WPKH or P2WSH; encode_p2sh determines whether to wrap in P2SH.
217      sign=True will have the given node sign the transaction.
218      insert_redeem_script will be added to the scriptSig, if given."""
219      tx_to_witness = create_witness_tx(node, use_p2wsh, utxo, pubkey, encode_p2sh, amount)
220      if (sign):
221          signed = node.signrawtransactionwithwallet(tx_to_witness)
222          assert "errors" not in signed or len(["errors"]) == 0
223          return node.sendrawtransaction(signed["hex"])
224      else:
225          if (insert_redeem_script):
226              tx = tx_from_hex(tx_to_witness)
227              tx.vin[0].scriptSig += CScript([bytes.fromhex(insert_redeem_script)])
228              tx_to_witness = tx.serialize().hex()
229  
230      return node.sendrawtransaction(tx_to_witness)
231  
232  class TestFrameworkBlockTools(unittest.TestCase):
233      def test_create_coinbase(self):
234          height = 20
235          coinbase_tx = create_coinbase(height=height)
236          assert_equal(CScriptNum.decode(coinbase_tx.vin[0].scriptSig), height)