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

Code before:

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
    """
    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])

    # Append to the transaction the vout containing the script supporting 2 spending conditions
    assert_greater_than_or_equal(len(parent.vout), 1)
    last_output = parent.vout[len(parent.vout) - 1]
    assert_greater_than_or_equal(last_output.nValue, rebalance_parent_output_amount)
    last_output.nValue -= rebalance_parent_output_amount
    parent.vout.append(CTxOut(rebalance_parent_output_amount, script_pubkey))


    # 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_hex, 16), len(parent.vout) - 1), b""))
    child_one.vout.append(CTxOut(child_amount, child_script_pubkey))
    child_one.wit.vtxinwit.append(CTxInWitness())

Review comment (suggestion):
30ea9047: maybe also useful to mention the kind of parent we're expecting to be passed into `build_malleated_tx_package`. something like:
Expects parent with anyone-can-spend inputs (ex: MiniWallet's OP_TRUE) to allow output modification.

we could also remove `wallet.sign_tx(siblings_parent)` in p2p_private_broadcast.py since signing doesn't really do anything - just adds `OP_TRUE` again in the witness.

Code after:

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).
    """
    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])

    # Append to the transaction the vout containing the script supporting 2 spending conditions
    assert_greater_than_or_equal(len(parent.vout), 1)
    last_output = parent.vout[len(parent.vout) - 1]
    assert_greater_than_or_equal(last_output.nValue, rebalance_parent_output_amount)
    last_output.nValue -= rebalance_parent_output_amount
    parent.vout.append(CTxOut(rebalance_parent_output_amount, script_pubkey))


    # 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()