Repository: spesmilo/electrum
Issue: Ledger hw.1 can only create txn with single output

On git master 382f69edd9a27dd37744d4eac3d3c8164afc0ae4.

Trying to sign a transactions with a ledger hw.1 (firmware version 1.0.4, latest atm).
It only succeeds if the transactions has one output (no change either).
If there are three or more outputs, I get `Exception: Transaction with more than 2 outputs not supported` which is most likely expected.
However, if there are two outputs (i.e. there is change), I get `Invalid status 6a80`

<details>
 <summary>log</summary>

```
[DeviceMgr] getting client for keystore
[DeviceMgr] scanning devices...
=> b'e0c4000000'
<= b'01200100040110'9000
[DeviceMgr] end client for keystore
[DeviceMgr] getting client for keystore
[DeviceMgr] scanning devices...
=> b'e0c4000000'
<= b'01200100040110'9000
[DeviceMgr] end client for keystore
[DeviceMgr] getting client for keystore
[DeviceMgr] scanning devices...
=> b'e0c4000000'
<= b'01200100040110'9000
[DeviceMgr] end client for keystore
[DeviceMgr] getting client for keystore
[DeviceMgr] scanning devices...
=> b'e0c4000000'
<= b'01200100040110'9000
[DeviceMgr] end client for keystore
=> b'e042000009000000000100000001'
<= b''9000
=> b'e042800025e2b7908358705e9d941884b6710b4eae9062911e085918f3681677930f17a3f9000000006a'
<= b''9000
=> b'e04280006e473044022050830a4ddfda472ed7cd6fb475a25079bdca4e94796fba00cb7c6064fad0adb702205b555b533d1c5165182746a22ae863ced8675df700cc452e8ac1127452ab65b4012103ad26fb33dfbdfcf70d6d5a76918be8d06e324279cb638ded9103a7c893389e35fdffffff'
<= b''9000
=> b'e04280000103'
<= b''9000
=> b'e04280000920a107000000000019'
<= b''9000
=> b'e04280001976a9142ca45dbe0c0d7c1ceae80c8ff67ada77dbb87c5f88ac'
<= b''9000
=> b'e04280000920a107000000000017'
<= b''9000
=> b'e042800017a9148ae694d8ae72693a399c5bd203243e1ecb8ecfe387'
<= b''9000
=> b'e042800009fe330c000000000019'
<= b''9000
=> b'e04280001976a914e3486bdaacaf84d5613b01b93abd3bea549a8cba88ac'
<= b''9000
=> b'e042800004f8a91300'
<= b'3200d5f94c89caf0cd962a1c71c1c57386eb11ebdb2e54ea03abee15f9317062c150ea120000000020a1070000000000dc3d51a1355165f2'9000
[DeviceMgr] getting client for keystore
[DeviceMgr] scanning devices...
=> b'e0c4000000'
<= b'01200100040110'9000
[DeviceMgr] end client for keystore
=> b'e02601000101'
<= b''9000
[DeviceMgr] getting client for keystore
[DeviceMgr] scanning devices...
=> b'e0c4000000'
<= b'01200100040110'9000
[DeviceMgr] end client for keystore
=> b'e0440000050100000001'
<= b''9000
=> b'e04480003b01383200d5f94c89caf0cd962a1c71c1c57386eb11ebdb2e54ea03abee15f9317062c150ea120000000020a1070000000000dc3d51a1355165f219'
<= b''9000
=> b'e04480001d76a9142ca45dbe0c0d7c1ceae80c8ff67ada77dbb87c5f88acfdffffff'
<= b''9000
[DeviceMgr] getting client for keystore
[DeviceMgr] scanning devices...
=> b'e0c4000000'
<= b'01200100040110'9000
[DeviceMgr] end client for keystore
=> b'e04a80004502a0860100000000001976a9144a4a898a28213db81e3a86cba487e05d551a170088ac9e190600000000001976a914eb45bfaf226e14b366796c9510e177659526a4b888ac'
[Network] network: retrying connections
<= b''6a80
Traceback (most recent call last):
  File "/home/user/wspace/electrum/plugins/ledger/ledger.py", line 444, in sign_transaction
    outputData = self.get_client().finalizeInputFull(txOutput)
  File "/usr/local/lib/python3.6/site-packages/btchip/btchip.py", line 348, in finalizeInputFull
    response = self.dongle.exchange(bytearray(apdu))
  File "/usr/local/lib/python3.6/site-packages/btchip/btchipComm.py", line 127, in exchange
    raise BTChipException("Invalid status %04x" % sw, sw)
btchip.btchipException.BTChipException: Exception : Invalid status 6a80
Exception : Invalid status 6a80
Traceback (most recent call last):
  File "/home/user/wspace/electrum/plugins/ledger/ledger.py", line 444, in sign_transaction
    outputData = self.get_client().finalizeInputFull(txOutput)
  File "/usr/local/lib/python3.6/site-packages/btchip/btchip.py", line 348, in finalizeInputFull
    response = self.dongle.exchange(bytearray(apdu))
  File "/usr/local/lib/python3.6/site-packages/btchip/btchipComm.py", line 127, in exchange
    raise BTChipException("Invalid status %04x" % sw, sw)
btchip.btchipException.BTChipException: Exception : Invalid status 6a80

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/user/wspace/electrum/gui/qt/util.py", line 639, in run
    result = task.task()
  File "/home/user/wspace/electrum/lib/wallet.py", line 1465, in sign_transaction
    k.sign_transaction(tx, password)
  File "/home/user/wspace/electrum/plugins/ledger/ledger.py", line 244, in wrapper
    return func(self, *args, **kwargs)
  File "/home/user/wspace/electrum/plugins/ledger/ledger.py", line 472, in sign_transaction
    self.give_error(e, True)
  File "/home/user/wspace/electrum/plugins/ledger/ledger.py", line 237, in give_error
    raise Exception(message)
Exception: Exception : Invalid status 6a80
```
</details>

This seems to be broken since https://github.com/spesmilo/electrum/commit/e4659327a136f18fde59e4a1f60f45f3e16f22d6

Changed files:
plugins/ledger/ledger.py

diff --git a/plugins/ledger/ledger.py b/plugins/ledger/ledger.py
index e6c42d155..598f92f1e 100644
--- a/plugins/ledger/ledger.py
+++ b/plugins/ledger/ledger.py
@@ -418,7 +418,12 @@ class Ledger_KeyStore(Hardware_KeyStore):
             if segwitTransaction:
                 self.get_client().startUntrustedTransaction(True, inputIndex,
                                                             chipInputs, redeemScripts[inputIndex])
-                outputData = self.get_client().finalizeInputFull(txOutput)
+                if changePath:
+                    # we don't set meaningful outputAddress, amount and fees
+                    # as we only care about the alternateEncoding==True branch
+                    outputData = self.get_client().finalizeInput(b'', 0, 0, changePath, bfh(rawTx))
+                else:
+                    outputData = self.get_client().finalizeInputFull(txOutput)
                 outputData['outputData'] = txOutput
                 transactionOutput = outputData['outputData']
                 if outputData['confirmationNeeded']:
@@ -441,7 +446,12 @@ class Ledger_KeyStore(Hardware_KeyStore):
                 while inputIndex < len(inputs):
                     self.get_client().startUntrustedTransaction(firstTransaction, inputIndex,
                                                             chipInputs, redeemScripts[inputIndex])
-                    outputData = self.get_client().finalizeInputFull(txOutput)
+                    if changePath:
+                        # we don't set meaningful outputAddress, amount and fees
+                        # as we only care about the alternateEncoding==True branch
+                        outputData = self.get_client().finalizeInput(b'', 0, 0, changePath, bfh(rawTx))
+                    else:
+                        outputData = self.get_client().finalizeInputFull(txOutput)
                     outputData['outputData'] = txOutput
                     if firstTransaction:
                         transactionOutput = outputData['outputData']