ledger plugin: parse xpubkey instead of using txin['derivation']; always use client.finalizeInputFull
This commit is contained in:
parent
03c66bb5f9
commit
5f038a4157
|
@ -2,12 +2,14 @@ from binascii import hexlify
|
|||
from struct import pack, unpack
|
||||
import hashlib
|
||||
import time
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
import electrum
|
||||
from electrum.bitcoin import EncodeBase58Check, DecodeBase58Check, TYPE_ADDRESS, int_to_hex, var_int
|
||||
from electrum.i18n import _
|
||||
from electrum.plugins import BasePlugin, hook
|
||||
from electrum.keystore import Hardware_KeyStore
|
||||
from electrum.keystore import Hardware_KeyStore, parse_xpubkey
|
||||
from ..hw_wallet import HW_PluginBase
|
||||
from electrum.util import format_satoshis_plain, print_error
|
||||
|
||||
|
@ -257,43 +259,45 @@ class Ledger_KeyStore(Hardware_KeyStore):
|
|||
self.get_client() # prompt for the PIN before displaying the dialog if necessary
|
||||
rawTx = tx.serialize()
|
||||
# Fetch inputs of the transaction to sign
|
||||
for txinput in tx.inputs():
|
||||
if ('is_coinbase' in txinput and txinput['is_coinbase']):
|
||||
for txin in tx.inputs():
|
||||
if txin.get('is_coinbase'):
|
||||
self.give_error("Coinbase not supported") # should never happen
|
||||
redeemScript = None
|
||||
signingPos = -1
|
||||
hwAddress = "%s/%d/%d" % (self.get_derivation()[2:], txinput['derivation'][0], txinput['derivation'][1])
|
||||
if len(txinput['pubkeys']) > 1:
|
||||
p2shTransaction = True
|
||||
if 'redeemScript' in txinput:
|
||||
redeemScript = txinput['redeemScript']
|
||||
xpub, s = parse_xpubkey(txin['x_pubkeys'][0])
|
||||
hwAddress = "%s/%d/%d" % (self.get_derivation()[2:], s[0], s[1])
|
||||
|
||||
if len(txin['pubkeys']) > 1:
|
||||
p2shTransaction = True
|
||||
if 'redeemScript' in txin:
|
||||
redeemScript = txin['redeemScript']
|
||||
if p2shTransaction:
|
||||
chipPublicKey = compress_public_key(self.get_client().getWalletPublicKey(hwAddress)['publicKey'])
|
||||
for currentIndex, key in enumerate(txinput['pubkeys']):
|
||||
for currentIndex, key in enumerate(txin['pubkeys']):
|
||||
if chipPublicKey == key.decode('hex'):
|
||||
signingPos = currentIndex
|
||||
break
|
||||
if signingPos == -1:
|
||||
self.give_error("No matching key for multisignature input") # should never happen
|
||||
|
||||
inputs.append([ txinput['prev_tx'].raw,
|
||||
txinput['prevout_n'], redeemScript, txinput['prevout_hash'], signingPos ])
|
||||
inputs.append([txin['prev_tx'].raw, txin['prevout_n'], redeemScript, txin['prevout_hash'], signingPos ])
|
||||
inputsPaths.append(hwAddress)
|
||||
pubKeys.append(txinput['pubkeys'])
|
||||
|
||||
pubKeys.append(txin['pubkeys'])
|
||||
|
||||
# Sanity check
|
||||
if p2shTransaction:
|
||||
for txinput in tx.inputs():
|
||||
if len(txinput['pubkeys']) < 2:
|
||||
self.give_error("P2SH / regular input mixed in same transaction not supported") # should never happen
|
||||
txOutput = var_int(len(tx.outputs()))
|
||||
for output in tx.outputs():
|
||||
output_type, addr, amount = output
|
||||
txOutput += int_to_hex(amount, 8)
|
||||
script = tx.pay_script(output_type, addr)
|
||||
txOutput += var_int(len(script)/2)
|
||||
txOutput += script
|
||||
txOutput = txOutput.decode('hex')
|
||||
|
||||
txOutput = var_int(len(tx.outputs()))
|
||||
for txout in tx.outputs():
|
||||
output_type, addr, amount = txout
|
||||
txOutput += int_to_hex(amount, 8)
|
||||
script = tx.pay_script(output_type, addr)
|
||||
txOutput += var_int(len(script)/2)
|
||||
txOutput += script
|
||||
txOutput = txOutput.decode('hex')
|
||||
|
||||
# Recognize outputs - only one output and one change is authorized
|
||||
if not p2shTransaction:
|
||||
|
@ -306,11 +310,9 @@ class Ledger_KeyStore(Hardware_KeyStore):
|
|||
changePath = "%s/%d/%d" % (self.get_derivation()[2:], change, index)
|
||||
changeAmount = amount
|
||||
else:
|
||||
if output <> None: # should never happen
|
||||
self.give_error("Multiple outputs with no change not supported")
|
||||
output = address
|
||||
outputAmount = amount
|
||||
|
||||
|
||||
self.handler.show_message("Signing Transaction ...")
|
||||
try:
|
||||
# Get trusted inputs from the original transactions
|
||||
|
@ -330,13 +332,9 @@ class Ledger_KeyStore(Hardware_KeyStore):
|
|||
inputIndex = 0
|
||||
while inputIndex < len(inputs):
|
||||
self.get_client().startUntrustedTransaction(firstTransaction, inputIndex,
|
||||
chipInputs, redeemScripts[inputIndex])
|
||||
if not p2shTransaction:
|
||||
outputData = self.get_client().finalizeInput(output, format_satoshis_plain(outputAmount),
|
||||
format_satoshis_plain(tx.get_fee()), changePath, bytearray(rawTx.decode('hex')))
|
||||
else:
|
||||
outputData = self.get_client().finalizeInputFull(txOutput)
|
||||
outputData['outputData'] = txOutput
|
||||
chipInputs, redeemScripts[inputIndex])
|
||||
outputData = self.get_client().finalizeInputFull(txOutput)
|
||||
outputData['outputData'] = txOutput
|
||||
if firstTransaction:
|
||||
transactionOutput = outputData['outputData']
|
||||
if outputData['confirmationNeeded']:
|
||||
|
@ -378,7 +376,8 @@ class Ledger_KeyStore(Hardware_KeyStore):
|
|||
signatures.append(inputSignature)
|
||||
inputIndex = inputIndex + 1
|
||||
firstTransaction = False
|
||||
except Exception, e:
|
||||
except BaseException as e:
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
self.give_error(e, True)
|
||||
finally:
|
||||
self.handler.clear_dialog()
|
||||
|
|
Loading…
Reference in New Issue