Repository: bitcoin/bitcoin
File: test/functional/test_framework/script_util.py (Python)

Code before:
    p2shscript = CScript([OP_0, sha256(script)])
    return script_to_p2sh_script(p2shscript)


def output_key_to_p2tr_script(key):
    assert len(key) == 32
    return program_to_witness_script(1, key)


def check_key(key):
    if isinstance(key, str):
        key = bytes.fromhex(key)  # Assuming this is hex string
    if isinstance(key, bytes) and (len(key) == 33 or len(key) == 65):
        return key
    assert False


def check_script(script):
    if isinstance(script, str):
        script = bytes.fromhex(script)  # Assuming this is hex string
    if isinstance(script, bytes) or isinstance(script, CScript):
        return script
    assert False


def valid_witness_malleate_tx(wallet, node):
    """
    Creates a valid witness malleation transaction:
    - Parent transaction with a script supporting 2 branches
    - 2 child transactions with the same txid but different wtxids
    """
    hashlock = hash160(b'Preimage')
    witness_script = CScript([OP_IF, OP_HASH160, hashlock, OP_EQUAL, OP_ELSE, OP_TRUE, OP_ENDIF])
    witness_program = sha256(witness_script)
    script_pubkey = CScript([OP_0, witness_program])

    # Create parent transaction with a script supporting 2 branches
    parent = wallet.send_to(from_node=node, scriptPubKey=script_pubkey, amount=int(9.99998 * COIN), fee=1000)

    # Create 2 valid children that differ only in witness data.
    # 1. Create a new transaction with witness solving first branch
    child_witness_script = CScript([OP_TRUE])
    child_witness_program = sha256(child_witness_script)
    child_script_pubkey = CScript([OP_0, child_witness_program])
    child_one = CTransaction()

    child_one.vin.append(CTxIn(COutPoint(int(parent['txid'], 16), parent['sent_vout']), b""))
    child_one.vout.append(CTxOut(int(9.99996 * COIN), child_script_pubkey))
    child_one.wit.vtxinwit.append(CTxInWitness())
    child_one.wit.vtxinwit[0].scriptWitness.stack = [b'Preimage', b'\x01', witness_script]
    # 2. Create another identical transaction with witness solving second branch

Review comment (suggestion):
d1a2e27: it would be nice to have a more general interface where we can pass the parent + child amount and fees.

cc @vasild - you might be interested in this too. I hadn't considered passing both wallet and node as arguments to the function in #32385. there are other functions in util.py which do this too - ex: `create_lots_of_big_transactions`

Code after:
    key = check_key(key)
    return program_to_witness_script(0, hash160(key))


def script_to_p2sh_p2wsh_script(script):
    script = check_script(script)
    p2shscript = CScript([OP_0, sha256(script)])
    return script_to_p2sh_script(p2shscript)

def bulk_vout(tx, target_vsize):
    if target_vsize < tx.get_vsize():
        raise RuntimeError(f"target_vsize {target_vsize} is less than transaction virtual size {tx.get_vsize()}")
    # determine number of needed padding bytes
    dummy_vbytes = target_vsize - tx.get_vsize()
    # compensate for the increase of the compact-size encoded script length
    # (note that the length encoding of the unpadded output script needs one byte)
    dummy_vbytes -= len(ser_compact_size(dummy_vbytes)) - 1
    tx.vout[-1].scriptPubKey = CScript([OP_RETURN] + [OP_1] * dummy_vbytes)
    assert_equal(tx.get_vsize(), target_vsize)

def output_key_to_p2tr_script(key):
    assert len(key) == 32
    return program_to_witness_script(1, key)


def check_key(key):
    if isinstance(key, str):
        key = bytes.fromhex(key)  # Assuming this is hex string
    if isinstance(key, bytes) and (len(key) == 33 or len(key) == 65):
        return key
    assert False


def check_script(script):
    if isinstance(script, str):
        script = bytes.fromhex(script)  # Assuming this is hex string
    if isinstance(script, bytes) or isinstance(script, CScript):
        return script
    assert False


def build_malleated_tx_package(*, parent: CTransaction, rebalance_parent_output_amount, child_amount):
    """
    Returns a transaction package with valid witness:
    - Parent transaction whose last output contains a script that has two spending conditions
    - Two malleated child transactions with same txid but different wtxids because of different witnesses

    Args:
        parent: Transaction with modifiable outputs. Either unsigned (sign after
        calling this function) or anyone-can-spend (e.g., MiniWallet's OP_TRUE).
    """