URI: 
       tledger plugin: parse xpubkey instead of using txin['derivation']; always use client.finalizeInputFull - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 5f038a4157b1c24c8fef5b7519640ca74be99dfe
   DIR parent 03c66bb5f966aa1f90faab052a826cc6cea5e889
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Thu, 22 Sep 2016 10:25:03 +0200
       
       ledger plugin: parse xpubkey instead of using txin['derivation']; always use client.finalizeInputFull
       
       Diffstat:
         M plugins/ledger/ledger.py            |      63 +++++++++++++++----------------
       
       1 file changed, 31 insertions(+), 32 deletions(-)
       ---
   DIR diff --git a/plugins/ledger/ledger.py b/plugins/ledger/ledger.py
       t@@ -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
        
       t@@ -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:
       t@@ -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
       t@@ -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']:
       t@@ -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()