# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Creating fake transactions. Not simple. # import pytest, struct from ckcc_protocol.protocol import MAX_TXN_LEN from psbt import BasicPSBT, BasicPSBTInput, BasicPSBTOutput from io import BytesIO from helpers import fake_dest_addr, make_change_addr, hash160, taptweak from base58 import decode_base58 from bip32 import BIP32Node from constants import ADDR_STYLES, simulator_fixed_tprv, SIGHASH_MAP from serialize import uint256_from_str from ctransaction import CTransaction, COutPoint, CTxIn, CTxOut @pytest.fixture def fake_txn(dev, pytestconfig): # make various size txn's ... completely fake and pointless values # - but has UTXO's to match needs # - input total = num_inputs * 1BTC def doit(num_ins, num_outs, master_xpub=None, subpath="0/%d", fee=10000, invals=None, outvals=None, segwit_in=False, wrapped=False, outstyles=['p2pkh'], psbt_hacker=None, change_outputs=[], capture_scripts=None, add_xpub=None, op_return=None, taproot_in=False, psbt_v2=None, input_amount=1E8, unknown_out_script=None, lock_time=0, sequences=None, sighashes=None, dupe_ins=[], p2pk_in=False): psbt = BasicPSBT() if psbt_v2 is None: # anything passed directly to this function overrides # pytest flag --psbt2 - only care about pytest flag # if psbt_v2 is not specified (None) psbt_v2 = pytestconfig.getoption('psbt2') if psbt_v2: psbt.version = 2 psbt.txn_version = 2 psbt.input_count = num_ins psbt.output_count = num_outs if lock_time: psbt.fallback_locktime = lock_time txn = CTransaction() txn.nLockTime = lock_time txn.nVersion = 2 master_xpub = master_xpub or dev.master_xpub or simulator_fixed_tprv # we have a key; use it to provide "plausible" value inputs mk = BIP32Node.from_wallet_key(master_xpub) xfp = mk.fingerprint() psbt.inputs = [BasicPSBTInput(idx=i) for i in range(num_ins)] psbt.outputs = [BasicPSBTOutput(idx=i) for i in range(num_outs)] for i in range(num_ins): # make a fake txn to supply each of the inputs # - each input is 1BTC # addr where the fake money will be stored. if subpath is None: subkey = mk sec = mk.sec() bytes_path = b"" else: subkey = mk.subkey_for_path(subpath % i) if p2pk_in: assert not segwit_in and not taproot_in and not wrapped assert p2pk_in in (True, 'compressed', 'uncompressed') sec = subkey.sec(compressed=(p2pk_in != 'uncompressed')) else: sec = subkey.sec() assert len(sec) == 33, "expect compressed" assert subpath[0:2] == '0/' # TODO does not respect subpath parameter bytes_path = struct.pack(' OP_CHECKSIG scr = bytes([len(sec)]) + sec + b'\xac' elif segwit_in: # p2wpkh scr = bytes([0x00, 0x14]) + subkey.hash160() if wrapped: # p2sh-p2wpkh psbt.inputs[i].redeem_script = scr scr = bytes([0xa9, 0x14]) + hash160(scr) + bytes([0x87]) elif taproot_in: psbt.inputs[i].taproot_bip32_paths[sec[1:]] = b"\x00" + xfp + struct.pack('