mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-09-01 17:55:20 +00:00
coldcard: follow-up prev
This commit is contained in:
parent
c77fe6aafd
commit
47c3ac6f1b
4 changed files with 22 additions and 40 deletions
|
@ -4,7 +4,8 @@
|
||||||
# - history: taken from coldcard-firmware/testing/psbt.py
|
# - history: taken from coldcard-firmware/testing/psbt.py
|
||||||
# - trying to minimize electrum code in here, and generally, dependancies.
|
# - trying to minimize electrum code in here, and generally, dependancies.
|
||||||
#
|
#
|
||||||
import io, struct
|
import io
|
||||||
|
import struct
|
||||||
from base64 import b64decode
|
from base64 import b64decode
|
||||||
from binascii import a2b_hex, b2a_hex
|
from binascii import a2b_hex, b2a_hex
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
#
|
#
|
||||||
# build_psbt.py - create a PSBT from (unsigned) transaction and keystore data.
|
# build_psbt.py - create a PSBT from (unsigned) transaction and keystore data.
|
||||||
#
|
#
|
||||||
import io, struct
|
import io
|
||||||
from base64 import b64decode
|
import struct
|
||||||
from binascii import a2b_hex, b2a_hex
|
from binascii import a2b_hex, b2a_hex
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
|
|
||||||
from electrum.transaction import (Transaction, multisig_script, parse_redeemScript_multisig,
|
from electrum.transaction import (Transaction, multisig_script, parse_redeemScript_multisig,
|
||||||
NotRecognizedRedeemScript)
|
NotRecognizedRedeemScript)
|
||||||
|
|
||||||
from electrum.logging import get_logger
|
from electrum.logging import get_logger
|
||||||
from electrum.wallet import Standard_Wallet, Multisig_Wallet, Wallet
|
from electrum.wallet import Standard_Wallet, Multisig_Wallet, Abstract_Wallet
|
||||||
from electrum.keystore import xpubkey_to_pubkey, Xpub
|
from electrum.keystore import xpubkey_to_pubkey, Xpub
|
||||||
from electrum.util import bfh, bh2u
|
from electrum.util import bfh, bh2u
|
||||||
from electrum.crypto import hash_160, sha256
|
from electrum.crypto import hash_160, sha256
|
||||||
from electrum.bitcoin import DecodeBase58Check
|
from electrum.bitcoin import DecodeBase58Check
|
||||||
|
from electrum.i18n import _
|
||||||
|
|
||||||
from .basic_psbt import (
|
from .basic_psbt import (
|
||||||
PSBT_GLOBAL_UNSIGNED_TX, PSBT_GLOBAL_XPUB, PSBT_IN_NON_WITNESS_UTXO, PSBT_IN_WITNESS_UTXO,
|
PSBT_GLOBAL_UNSIGNED_TX, PSBT_GLOBAL_XPUB, PSBT_IN_NON_WITNESS_UTXO, PSBT_IN_WITNESS_UTXO,
|
||||||
|
@ -23,12 +24,6 @@ from .basic_psbt import (
|
||||||
PSBT_OUT_REDEEM_SCRIPT, PSBT_OUT_WITNESS_SCRIPT)
|
PSBT_OUT_REDEEM_SCRIPT, PSBT_OUT_WITNESS_SCRIPT)
|
||||||
from .basic_psbt import BasicPSBT
|
from .basic_psbt import BasicPSBT
|
||||||
|
|
||||||
from electrum.logging import get_logger
|
|
||||||
from electrum.wallet import Standard_Wallet, Multisig_Wallet, Wallet
|
|
||||||
from electrum.util import bfh, bh2u
|
|
||||||
from electrum.crypto import hash_160
|
|
||||||
from electrum.bitcoin import DecodeBase58Check
|
|
||||||
|
|
||||||
|
|
||||||
_logger = get_logger(__name__)
|
_logger = get_logger(__name__)
|
||||||
|
|
||||||
|
@ -131,7 +126,7 @@ def my_var_int(l):
|
||||||
else:
|
else:
|
||||||
return pack("<BQ", 255, l)
|
return pack("<BQ", 255, l)
|
||||||
|
|
||||||
def build_psbt(tx: Transaction, wallet: Wallet):
|
def build_psbt(tx: Transaction, wallet: Abstract_Wallet):
|
||||||
# Render a PSBT file, for possible upload to Coldcard.
|
# Render a PSBT file, for possible upload to Coldcard.
|
||||||
#
|
#
|
||||||
# TODO this should be part of Wallet object, or maybe Transaction?
|
# TODO this should be part of Wallet object, or maybe Transaction?
|
||||||
|
@ -178,15 +173,14 @@ def build_psbt(tx: Transaction, wallet: Wallet):
|
||||||
for o in tx.outputs():
|
for o in tx.outputs():
|
||||||
if o.address in tx.output_info:
|
if o.address in tx.output_info:
|
||||||
# this address "is_mine" but might not be change (if I send funds to myself)
|
# this address "is_mine" but might not be change (if I send funds to myself)
|
||||||
chg_path = tx.output_info.get(o.address).address_index
|
output_info = tx.output_info.get(o.address)
|
||||||
|
if not output_info.is_change:
|
||||||
if chg_path[0] != 1 or len(chg_path) != 2:
|
|
||||||
# not change.
|
|
||||||
continue
|
continue
|
||||||
|
chg_path = output_info.address_index
|
||||||
|
assert chg_path[0] == 1 and len(chg_path) == 2, f"unexpected change path: {chg_path}"
|
||||||
pubkey = ks.derive_pubkey(True, chg_path[1])
|
pubkey = ks.derive_pubkey(True, chg_path[1])
|
||||||
subkeys[bfh(pubkey)] = ks_prefix + pack('<II', *chg_path)
|
subkeys[bfh(pubkey)] = ks_prefix + pack('<II', *chg_path)
|
||||||
|
|
||||||
for txin in inputs:
|
for txin in inputs:
|
||||||
assert txin['type'] != 'coinbase', _("Coinbase not supported")
|
assert txin['type'] != 'coinbase', _("Coinbase not supported")
|
||||||
|
|
||||||
|
@ -246,7 +240,7 @@ def build_psbt(tx: Transaction, wallet: Wallet):
|
||||||
# always need a redeem script for multisig
|
# always need a redeem script for multisig
|
||||||
scr = Transaction.get_preimage_script(txin)
|
scr = Transaction.get_preimage_script(txin)
|
||||||
|
|
||||||
if 'p2wsh' in txin['type']:
|
if Transaction.is_segwit_input(txin):
|
||||||
# needed for both p2wsh-p2sh and p2wsh
|
# needed for both p2wsh-p2sh and p2wsh
|
||||||
write_kv(PSBT_IN_WITNESS_SCRIPT, bfh(scr))
|
write_kv(PSBT_IN_WITNESS_SCRIPT, bfh(scr))
|
||||||
else:
|
else:
|
||||||
|
@ -275,8 +269,9 @@ def build_psbt(tx: Transaction, wallet: Wallet):
|
||||||
|
|
||||||
if txin['type'] == 'p2wpkh-p2sh':
|
if txin['type'] == 'p2wpkh-p2sh':
|
||||||
assert len(pubkeys) == 1, 'can be only one redeem script per input'
|
assert len(pubkeys) == 1, 'can be only one redeem script per input'
|
||||||
pa = hash_160(k)
|
pa = hash_160(pubkey)
|
||||||
write_kv(PSBT_OUT_REDEEM_SCRIPT, b'\x00\x14'+pa)
|
assert len(pa) == 20
|
||||||
|
write_kv(PSBT_IN_REDEEM_SCRIPT, b'\x00\x14'+pa)
|
||||||
|
|
||||||
# optional? insert (partial) signatures that we already have
|
# optional? insert (partial) signatures that we already have
|
||||||
if sigs and sigs[pk_pos]:
|
if sigs and sigs[pk_pos]:
|
||||||
|
@ -291,10 +286,7 @@ def build_psbt(tx: Transaction, wallet: Wallet):
|
||||||
if o.address in tx.output_info:
|
if o.address in tx.output_info:
|
||||||
# this address "is_mine" but might not be change (if I send funds to myself)
|
# this address "is_mine" but might not be change (if I send funds to myself)
|
||||||
output_info = tx.output_info.get(o.address)
|
output_info = tx.output_info.get(o.address)
|
||||||
chg_path, master_xpubs = output_info.address_index, output_info.sorted_xpubs
|
if output_info.is_change:
|
||||||
|
|
||||||
if chg_path[0] == 1 and len(chg_path) == 2:
|
|
||||||
# it is a change output (based on our standard derivation path)
|
|
||||||
pubkeys = [bfh(i) for i in wallet.get_public_keys(o.address)]
|
pubkeys = [bfh(i) for i in wallet.get_public_keys(o.address)]
|
||||||
|
|
||||||
# Add redeem/witness script?
|
# Add redeem/witness script?
|
||||||
|
@ -331,7 +323,7 @@ def build_psbt(tx: Transaction, wallet: Wallet):
|
||||||
return tx.raw_psbt
|
return tx.raw_psbt
|
||||||
|
|
||||||
|
|
||||||
def recover_tx_from_psbt(first: BasicPSBT, wallet: Wallet) -> Transaction:
|
def recover_tx_from_psbt(first: BasicPSBT, wallet: Abstract_Wallet) -> Transaction:
|
||||||
# Take a PSBT object and re-construct the Electrum transaction object.
|
# Take a PSBT object and re-construct the Electrum transaction object.
|
||||||
# - does not include signatures, see merge_sigs_from_psbt
|
# - does not include signatures, see merge_sigs_from_psbt
|
||||||
# - any PSBT in the group could be used for this purpose; all must share tx details
|
# - any PSBT in the group could be used for this purpose; all must share tx details
|
||||||
|
|
|
@ -11,12 +11,10 @@ from electrum.i18n import _
|
||||||
from electrum.plugin import Device, hook
|
from electrum.plugin import Device, hook
|
||||||
from electrum.keystore import Hardware_KeyStore
|
from electrum.keystore import Hardware_KeyStore
|
||||||
from electrum.transaction import Transaction, multisig_script
|
from electrum.transaction import Transaction, multisig_script
|
||||||
from electrum.wallet import Standard_Wallet, Multisig_Wallet, Wallet
|
from electrum.wallet import Standard_Wallet, Multisig_Wallet
|
||||||
from electrum.crypto import hash_160
|
|
||||||
from electrum.util import bfh, bh2u, versiontuple, UserFacingException
|
from electrum.util import bfh, bh2u, versiontuple, UserFacingException
|
||||||
from electrum.base_wizard import ScriptTypeNotSupported
|
from electrum.base_wizard import ScriptTypeNotSupported
|
||||||
from electrum.logging import get_logger
|
from electrum.logging import get_logger
|
||||||
from electrum.bitcoin import DecodeBase58Check
|
|
||||||
|
|
||||||
from ..hw_wallet import HW_PluginBase
|
from ..hw_wallet import HW_PluginBase
|
||||||
from ..hw_wallet.plugin import LibraryFoundButUnusable, only_hook_if_libraries_available
|
from ..hw_wallet.plugin import LibraryFoundButUnusable, only_hook_if_libraries_available
|
||||||
|
@ -34,10 +32,6 @@ try:
|
||||||
from ckcc.protocol import CCProtoError, CCUserRefused, CCBusyError
|
from ckcc.protocol import CCProtoError, CCUserRefused, CCBusyError
|
||||||
from ckcc.constants import (MAX_MSG_LEN, MAX_BLK_LEN, MSG_SIGNING_MAX_LENGTH, MAX_TXN_LEN,
|
from ckcc.constants import (MAX_MSG_LEN, MAX_BLK_LEN, MSG_SIGNING_MAX_LENGTH, MAX_TXN_LEN,
|
||||||
AF_CLASSIC, AF_P2SH, AF_P2WPKH, AF_P2WSH, AF_P2WPKH_P2SH, AF_P2WSH_P2SH)
|
AF_CLASSIC, AF_P2SH, AF_P2WPKH, AF_P2WSH, AF_P2WPKH_P2SH, AF_P2WSH_P2SH)
|
||||||
#from ckcc.constants import (
|
|
||||||
#PSBT_GLOBAL_UNSIGNED_TX, PSBT_GLOBAL_XPUB, PSBT_IN_NON_WITNESS_UTXO, PSBT_IN_WITNESS_UTXO,
|
|
||||||
#PSBT_IN_SIGHASH_TYPE, PSBT_IN_REDEEM_SCRIPT, PSBT_IN_WITNESS_SCRIPT,
|
|
||||||
#PSBT_IN_BIP32_DERIVATION, PSBT_OUT_BIP32_DERIVATION, PSBT_OUT_REDEEM_SCRIPT)
|
|
||||||
|
|
||||||
from ckcc.client import ColdcardDevice, COINKITE_VID, CKCC_PID, CKCC_SIMULATOR_PATH
|
from ckcc.client import ColdcardDevice, COINKITE_VID, CKCC_PID, CKCC_SIMULATOR_PATH
|
||||||
|
|
||||||
|
@ -388,12 +382,6 @@ class Coldcard_KeyStore(Hardware_KeyStore):
|
||||||
|
|
||||||
client = self.get_client()
|
client = self.get_client()
|
||||||
|
|
||||||
if 0:
|
|
||||||
from pprint import pprint
|
|
||||||
for n,i in enumerate(tx.inputs()):
|
|
||||||
print('[%d]: ' % n, end='')
|
|
||||||
pprint(i)
|
|
||||||
|
|
||||||
assert client.dev.master_fingerprint == self.ckcc_xfp
|
assert client.dev.master_fingerprint == self.ckcc_xfp
|
||||||
|
|
||||||
# makes PSBT required
|
# makes PSBT required
|
||||||
|
|
|
@ -265,4 +265,5 @@ class QtPluginBase(object):
|
||||||
else:
|
else:
|
||||||
addr = uri.get('address')
|
addr = uri.get('address')
|
||||||
keystore.thread.add(partial(plugin.show_address, wallet, addr, keystore))
|
keystore.thread.add(partial(plugin.show_address, wallet, addr, keystore))
|
||||||
receive_address_e.addButton("eye1.png", show_address, _("Show on {}").format(keystore.label))
|
dev_name = f"{plugin.device} ({keystore.label})"
|
||||||
|
receive_address_e.addButton("eye1.png", show_address, _("Show on {}").format(dev_name))
|
||||||
|
|
Loading…
Add table
Reference in a new issue