# # basic_psbt.py - yet another PSBT parser/serializer but used only for test cases. # # - history: taken from coldcard-firmware/testing/psbt.py # - trying to minimize electrum code in here, and generally, dependancies. # import io import struct from base64 import b64decode from binascii import a2b_hex, b2a_hex from struct import pack, unpack from electrum.transaction import Transaction # BIP-174 (aka PSBT) defined values # PSBT_GLOBAL_UNSIGNED_TX = (0) PSBT_GLOBAL_XPUB = (1) PSBT_IN_NON_WITNESS_UTXO = (0) PSBT_IN_WITNESS_UTXO = (1) PSBT_IN_PARTIAL_SIG = (2) PSBT_IN_SIGHASH_TYPE = (3) PSBT_IN_REDEEM_SCRIPT = (4) PSBT_IN_WITNESS_SCRIPT = (5) PSBT_IN_BIP32_DERIVATION = (6) PSBT_IN_FINAL_SCRIPTSIG = (7) PSBT_IN_FINAL_SCRIPTWITNESS = (8) PSBT_OUT_REDEEM_SCRIPT = (0) PSBT_OUT_WITNESS_SCRIPT = (1) PSBT_OUT_BIP32_DERIVATION = (2) # Serialization/deserialization tools def ser_compact_size(l): r = b"" if l < 253: r = struct.pack("B", l) elif l < 0x10000: r = struct.pack(" val=(path) self.xpubs.append( (key, val) ) else: raise ValueError('unknown global key type: 0x%02x' % kt) assert self.txn, 'missing reqd section' self.inputs = [BasicPSBTInput(fd, idx) for idx in range(num_ins)] self.outputs = [BasicPSBTOutput(fd, idx) for idx in range(num_outs)] sep = fd.read(1) assert sep == b'' return self def serialize(self, fd): def wr(ktype, val, key=b''): fd.write(ser_compact_size(1 + len(key))) fd.write(bytes([ktype]) + key) fd.write(ser_compact_size(len(val))) fd.write(val) fd.write(b'psbt\xff') wr(PSBT_GLOBAL_UNSIGNED_TX, self.txn) for k,v in self.xpubs: wr(PSBT_GLOBAL_XPUB, v, key=k) # sep fd.write(b'\0') for idx, inp in enumerate(self.inputs): inp.serialize(fd, idx) for idx, outp in enumerate(self.outputs): outp.serialize(fd, idx) def as_bytes(self): with io.BytesIO() as fd: self.serialize(fd) return fd.getvalue() # EOF