ledger plugin: parse xpubkey instead of using txin['derivation']; always use client.finalizeInputFull

This commit is contained in:
ThomasV 2016-09-22 10:25:03 +02:00
parent 03c66bb5f9
commit 5f038a4157
1 changed files with 31 additions and 32 deletions

View File

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