Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1#!/usr/bin/env python32# Copyright (c) 2019-present The Bitcoin Core developers3# Distributed under the MIT software license, see the accompanying4# file COPYING or http://www.opensource.org/licenses/mit-license.php.5"""Useful Script constants and utils."""6import unittest8from copy import deepcopy10from test_framework.messages import (11COutPoint,12CTransaction,13CTxIn,14CTxInWitness,15CTxOut,16ser_compact_size,17sha256,18)19from test_framework.script import (20CScript,21OP_0,22OP_1,23OP_15,24OP_16,25OP_CHECKMULTISIG,26OP_CHECKSIG,27OP_DUP,28OP_ELSE,29OP_ENDIF,30OP_EQUAL,31OP_EQUALVERIFY,32OP_HASH160,33OP_IF,34OP_RETURN,35OP_TRUE,36hash160,37)39from test_framework.util import (40assert_greater_than_or_equal,41assert_equal,42)44# Maximum number of potentially executed legacy signature operations in validating a transaction.45MAX_STD_LEGACY_SIGOPS = 2_50047# Maximum number of sigops per standard P2SH redeemScript.48MAX_STD_P2SH_SIGOPS = 1550# To prevent a "tx-size-small" policy rule error, a transaction has to have a51# non-witness size of at least 65 bytes (MIN_STANDARD_TX_NONWITNESS_SIZE in52# src/policy/policy.h). Considering a Tx with the smallest possible single53# 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 bytes57# Blank Input: 32 [PrevTxHash] + 4 [Index] + 1 [scriptSigLen] + 4 [SeqNo] = 41 bytes58# Output: 8 [Amount] + 1 [scriptPubKeyLen] = 9 bytes59#60# Hence, the scriptPubKey of the single output has to have a size of at61# least 5 bytes.62MIN_STANDARD_TX_NONWITNESS_SIZE = 6563MIN_PADDING = MIN_STANDARD_TX_NONWITNESS_SIZE - 10 - 41 - 964assert_equal(MIN_PADDING, 5)66# This script cannot be spent, allowing dust output values under67# standardness checks68DUMMY_MIN_OP_RETURN_SCRIPT = CScript([OP_RETURN] + ([OP_0] * (MIN_PADDING - 1)))69assert_equal(len(DUMMY_MIN_OP_RETURN_SCRIPT), MIN_PADDING)71PAY_TO_ANCHOR = CScript([OP_1, bytes.fromhex("4e73")])72ANCHOR_ADDRESS = "bcrt1pfeesnyr2tx"74def key_to_p2pk_script(key):75key = check_key(key)76return CScript([key, OP_CHECKSIG])79def keys_to_multisig_script(keys, *, k=None):80n = len(keys)81if k is None: # n-of-n multisig by default82k = n83assert k <= n84checked_keys = [check_key(key) for key in keys]85return CScript([k] + checked_keys + [n, OP_CHECKMULTISIG])88def keyhash_to_p2pkh_script(hash):89assert_equal(len(hash), 20)90return CScript([OP_DUP, OP_HASH160, hash, OP_EQUALVERIFY, OP_CHECKSIG])93def scripthash_to_p2sh_script(hash):94assert_equal(len(hash), 20)95return CScript([OP_HASH160, hash, OP_EQUAL])98def key_to_p2pkh_script(key):99key = check_key(key)100return keyhash_to_p2pkh_script(hash160(key))103def script_to_p2sh_script(script):104script = check_script(script)105return scripthash_to_p2sh_script(hash160(script))108def key_to_p2sh_p2wpkh_script(key):109key = check_key(key)110p2shscript = CScript([OP_0, hash160(key)])111return script_to_p2sh_script(p2shscript)114def program_to_witness_script(version, program):115if isinstance(program, str):116program = bytes.fromhex(program)117assert 0 <= version <= 16118assert 2 <= len(program) <= 40119assert version > 0 or len(program) in [20, 32]120return CScript([version, program])123def script_to_p2wsh_script(script):124script = check_script(script)125return program_to_witness_script(0, sha256(script))128def key_to_p2wpkh_script(key):129key = check_key(key)130return program_to_witness_script(0, hash160(key))133def script_to_p2sh_p2wsh_script(script):134script = check_script(script)135p2shscript = CScript([OP_0, sha256(script)])136return script_to_p2sh_script(p2shscript)138def bulk_vout(tx, target_vsize):139if target_vsize < tx.get_vsize():140raise RuntimeError(f"target_vsize {target_vsize} is less than transaction virtual size {tx.get_vsize()}")141# determine number of needed padding bytes142dummy_vbytes = target_vsize - tx.get_vsize()143# compensate for the increase of the compact-size encoded script length144# (note that the length encoding of the unpadded output script needs one byte)145dummy_vbytes -= len(ser_compact_size(dummy_vbytes)) - 1146tx.vout[-1].scriptPubKey = CScript([OP_RETURN] + [OP_1] * dummy_vbytes)147assert_equal(tx.get_vsize(), target_vsize)149def output_key_to_p2tr_script(key):150assert_equal(len(key), 32)151return program_to_witness_script(1, key)154def check_key(key):155if isinstance(key, str):156key = bytes.fromhex(key) # Assuming this is hex string157if isinstance(key, bytes) and (len(key) == 33 or len(key) == 65):158return key159assert False162def check_script(script):163if isinstance(script, str):164script = bytes.fromhex(script) # Assuming this is hex string165if isinstance(script, bytes) or isinstance(script, CScript):166return script167assert False170def build_malleated_tx_package(*, parent: CTransaction, rebalance_parent_output_amount, child_amount):171"""172Returns a transaction package with valid witness:173- Parent transaction whose last output contains a script that has two spending conditions174- Two malleated child transactions with same txid but different wtxids because of different witnesses176Args:177parent: Transaction with modifiable outputs. Either unsigned (sign after178calling this function) or anyone-can-spend (e.g., MiniWallet's OP_TRUE).179"""180hashlock = hash160(b'Preimage')181witness_script = CScript([OP_IF, OP_HASH160, hashlock, OP_EQUAL, OP_ELSE, OP_TRUE, OP_ENDIF])182witness_program = sha256(witness_script)183script_pubkey = CScript([OP_0, witness_program])185# Append to the transaction the vout containing the script supporting 2 spending conditions186assert_greater_than_or_equal(len(parent.vout), 1)187last_output = parent.vout[len(parent.vout) - 1]188assert_greater_than_or_equal(last_output.nValue, rebalance_parent_output_amount)189last_output.nValue -= rebalance_parent_output_amount190parent.vout.append(CTxOut(rebalance_parent_output_amount, script_pubkey))193# Create 2 valid children that differ only in witness data.194# 1. Create a new transaction with witness solving first branch195child_witness_script = CScript([OP_TRUE])196child_witness_program = sha256(child_witness_script)197child_script_pubkey = CScript([OP_0, child_witness_program])198child_one = CTransaction()200child_one.vin.append(CTxIn(COutPoint(int(parent.txid_hex, 16), len(parent.vout) - 1), b""))201child_one.vout.append(CTxOut(child_amount, child_script_pubkey))202child_one.wit.vtxinwit.append(CTxInWitness())203child_one.wit.vtxinwit[0].scriptWitness.stack = [b'Preimage', b'\x01', witness_script]204# 2. Create another identical transaction with witness solving second branch205child_two = deepcopy(child_one)206child_two.wit.vtxinwit[0].scriptWitness.stack = [b'', witness_script]207return parent, child_one, child_two210class TestFrameworkScriptUtil(unittest.TestCase):211def test_multisig(self):212fake_pubkey = bytes([0]*33)213# check correct encoding of P2MS script with n,k <= 16214normal_ms_script = keys_to_multisig_script([fake_pubkey]*16, k=15)215self.assertEqual(len(normal_ms_script), 1 + 16*34 + 1 + 1)216self.assertTrue(normal_ms_script.startswith(bytes([OP_15])))217self.assertTrue(normal_ms_script.endswith(bytes([OP_16, OP_CHECKMULTISIG])))219# check correct encoding of P2MS script with n,k > 16220max_ms_script = keys_to_multisig_script([fake_pubkey]*20, k=19)221self.assertEqual(len(max_ms_script), 2 + 20*34 + 2 + 1)222self.assertTrue(max_ms_script.startswith(bytes([1, 19]))) # using OP_PUSH1223self.assertTrue(max_ms_script.endswith(bytes([1, 20, OP_CHECKMULTISIG])))
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.