# Buggy code
def sign_transaction(self, tx, password):
    if tx.is_complete():
        return
    client = self.get_client()
    inputs = []
    inputsPaths = []
    pubKeys = []
    chipInputs = []
    redeemScripts = []
    signatures = []
    preparedTrustedInputs = []
    changePath = ""
    changeAmount = None
    output = None
    outputAmount = None
    p2shTransaction = False
    segwitTransaction = False
    pin = ""
    self.get_client()  # prompt for the PIN before displaying the dialog if necessary

    # Fetch inputs of the transaction to sign
    derivations = self.get_tx_derivations(tx)
    for txin in tx.inputs():
        if txin["type"] == "coinbase":
            self.give_error("Coinbase not supported")  # should never happen

        if txin["type"] in ["p2sh"]:
            p2shTransaction = True

        if txin["type"] in ["p2wpkh-p2sh", "p2wsh-p2sh"]:
            if not self.get_client_electrum().supports_segwit():
                self.give_error(MSG_NEEDS_FW_UPDATE_SEGWIT)
            segwitTransaction = True

        if txin["type"] in ["p2wpkh", "p2wsh"]:
            if not self.get_client_electrum().supports_native_segwit():
                self.give_error(MSG_NEEDS_FW_UPDATE_SEGWIT)
            segwitTransaction = True

        pubkeys, x_pubkeys = tx.get_sorted_pubkeys(txin)
        for i, x_pubkey in enumerate(x_pubkeys):
            if x_pubkey in derivations:
                signingPos = i
                s = derivations.get(x_pubkey)
                hwAddress = "%s/%d/%d" % (self.get_derivation()[2:], s[0], s[1])
                break
        else:
            self.give_error(
                "No matching x_key for sign_transaction"
            )  # should never happen

        redeemScript = Transaction.get_preimage_script(txin)
        inputs.append(
            [
                txin["prev_tx"].raw,
                txin["prevout_n"],
                redeemScript,
                txin["prevout_hash"],
                signingPos,
                txin.get("sequence", 0xFFFFFFFF - 1),
            ]
        )
        inputsPaths.append(hwAddress)
        pubKeys.append(pubkeys)

    # Sanity check
    if p2shTransaction:
        for txin in tx.inputs():
            if txin["type"] != "p2sh":
                self.give_error(
                    "P2SH / regular input mixed in same transaction not supported"
                )  # should never happen

    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 = bfh(txOutput)

    # Recognize outputs - only one output and one change is authorized
    if not p2shTransaction:
        if not self.get_client_electrum().supports_multi_output():
            if len(tx.outputs()) > 2:
                self.give_error("Transaction with more than 2 outputs not supported")
        for _type, address, amount in tx.outputs():
            assert _type == TYPE_ADDRESS
            info = tx.output_info.get(address)
            if (
                (info is not None) and len(tx.outputs()) > 1 and info[0][0] == 1
            ):  # "is on 'change' branch"
                index, xpubs, m = info
                changePath = self.get_derivation()[2:] + "/%d/%d" % index
                changeAmount = amount
            else:
                output = address
                outputAmount = amount

    self.handler.show_message(_("Confirm Transaction on your Ledger device..."))
    try:
        # Get trusted inputs from the original transactions
        for utxo in inputs:
            sequence = int_to_hex(utxo[5], 4)
            if segwitTransaction:
                txtmp = bitcoinTransaction(bfh(utxo[0]))
                tmp = bfh(utxo[3])[::-1]
                tmp += bfh(int_to_hex(utxo[1], 4))
                tmp += txtmp.outputs[utxo[1]].amount
                chipInputs.append({"value": tmp, "witness": True, "sequence": sequence})
                redeemScripts.append(bfh(utxo[2]))
            elif not p2shTransaction:
                txtmp = bitcoinTransaction(bfh(utxo[0]))
                trustedInput = self.get_client().getTrustedInput(txtmp, utxo[1])
                trustedInput["sequence"] = sequence
                chipInputs.append(trustedInput)
                redeemScripts.append(txtmp.outputs[utxo[1]].script)
            else:
                tmp = bfh(utxo[3])[::-1]
                tmp += bfh(int_to_hex(utxo[1], 4))
                chipInputs.append({"value": tmp, "sequence": sequence})
                redeemScripts.append(bfh(utxo[2]))

        # Sign all inputs
        firstTransaction = True
        inputIndex = 0
        rawTx = tx.serialize()
        self.get_client().enableAlternate2fa(False)
        if segwitTransaction:
            self.get_client().startUntrustedTransaction(
                True, inputIndex, chipInputs, redeemScripts[inputIndex]
            )
            outputData = self.get_client().finalizeInputFull(txOutput)
            outputData["outputData"] = txOutput
            transactionOutput = outputData["outputData"]
            if outputData["confirmationNeeded"]:
                outputData["address"] = output
                self.handler.finished()
                pin = self.handler.get_auth(
                    outputData
                )  # does the authenticate dialog and returns pin
                if not pin:
                    raise UserWarning()
                if pin != "paired":
                    self.handler.show_message(_("Confirmed. Signing Transaction..."))
            while inputIndex < len(inputs):
                singleInput = [chipInputs[inputIndex]]
                self.get_client().startUntrustedTransaction(
                    False, 0, singleInput, redeemScripts[inputIndex]
                )
                inputSignature = self.get_client().untrustedHashSign(
                    inputsPaths[inputIndex], pin, lockTime=tx.locktime
                )
                inputSignature[0] = 0x30  # force for 1.4.9+
                signatures.append(inputSignature)
                inputIndex = inputIndex + 1
        else:
            while inputIndex < len(inputs):
                self.get_client().startUntrustedTransaction(
                    firstTransaction, inputIndex, chipInputs, redeemScripts[inputIndex]
                )
                outputData = self.get_client().finalizeInputFull(txOutput)
                outputData["outputData"] = txOutput
                if firstTransaction:
                    transactionOutput = outputData["outputData"]
                if outputData["confirmationNeeded"]:
                    outputData["address"] = output
                    self.handler.finished()
                    pin = self.handler.get_auth(
                        outputData
                    )  # does the authenticate dialog and returns pin
                    if not pin:
                        raise UserWarning()
                    if pin != "paired":
                        self.handler.show_message(
                            _("Confirmed. Signing Transaction...")
                        )
                else:
                    # Sign input with the provided PIN
                    inputSignature = self.get_client().untrustedHashSign(
                        inputsPaths[inputIndex], pin, lockTime=tx.locktime
                    )
                    inputSignature[0] = 0x30  # force for 1.4.9+
                    signatures.append(inputSignature)
                    inputIndex = inputIndex + 1
                if pin != "paired":
                    firstTransaction = False
    except UserWarning:
        self.handler.show_error(_("Cancelled by user"))
        return
    except BTChipException as e:
        if e.sw == 0x6985:  # cancelled by user
            return
        else:
            traceback.print_exc(file=sys.stderr)
            self.give_error(e, True)
    except BaseException as e:
        traceback.print_exc(file=sys.stdout)
        self.give_error(e, True)
    finally:
        self.handler.finished()

    for i, txin in enumerate(tx.inputs()):
        signingPos = inputs[i][4]
        txin["signatures"][signingPos] = bh2u(signatures[i])
    tx.raw = tx.serialize()


# Traceback (btchip.btchipException.BTChipException)
[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

# Fixed code
def sign_transaction(self, tx, password):
    if tx.is_complete():
        return
    client = self.get_client()
    inputs = []
    inputsPaths = []
    pubKeys = []
    chipInputs = []
    redeemScripts = []
    signatures = []
    preparedTrustedInputs = []
    changePath = ""
    changeAmount = None
    output = None
    outputAmount = None
    p2shTransaction = False
    segwitTransaction = False
    pin = ""
    self.get_client()  # prompt for the PIN before displaying the dialog if necessary

    # Fetch inputs of the transaction to sign
    derivations = self.get_tx_derivations(tx)
    for txin in tx.inputs():
        if txin["type"] == "coinbase":
            self.give_error("Coinbase not supported")  # should never happen

        if txin["type"] in ["p2sh"]:
            p2shTransaction = True

        if txin["type"] in ["p2wpkh-p2sh", "p2wsh-p2sh"]:
            if not self.get_client_electrum().supports_segwit():
                self.give_error(MSG_NEEDS_FW_UPDATE_SEGWIT)
            segwitTransaction = True

        if txin["type"] in ["p2wpkh", "p2wsh"]:
            if not self.get_client_electrum().supports_native_segwit():
                self.give_error(MSG_NEEDS_FW_UPDATE_SEGWIT)
            segwitTransaction = True

        pubkeys, x_pubkeys = tx.get_sorted_pubkeys(txin)
        for i, x_pubkey in enumerate(x_pubkeys):
            if x_pubkey in derivations:
                signingPos = i
                s = derivations.get(x_pubkey)
                hwAddress = "%s/%d/%d" % (self.get_derivation()[2:], s[0], s[1])
                break
        else:
            self.give_error(
                "No matching x_key for sign_transaction"
            )  # should never happen

        redeemScript = Transaction.get_preimage_script(txin)
        inputs.append(
            [
                txin["prev_tx"].raw,
                txin["prevout_n"],
                redeemScript,
                txin["prevout_hash"],
                signingPos,
                txin.get("sequence", 0xFFFFFFFF - 1),
            ]
        )
        inputsPaths.append(hwAddress)
        pubKeys.append(pubkeys)

    # Sanity check
    if p2shTransaction:
        for txin in tx.inputs():
            if txin["type"] != "p2sh":
                self.give_error(
                    "P2SH / regular input mixed in same transaction not supported"
                )  # should never happen

    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 = bfh(txOutput)

    # Recognize outputs - only one output and one change is authorized
    if not p2shTransaction:
        if not self.get_client_electrum().supports_multi_output():
            if len(tx.outputs()) > 2:
                self.give_error("Transaction with more than 2 outputs not supported")
        for _type, address, amount in tx.outputs():
            assert _type == TYPE_ADDRESS
            info = tx.output_info.get(address)
            if (
                (info is not None) and len(tx.outputs()) > 1 and info[0][0] == 1
            ):  # "is on 'change' branch"
                index, xpubs, m = info
                changePath = self.get_derivation()[2:] + "/%d/%d" % index
                changeAmount = amount
            else:
                output = address
                outputAmount = amount

    self.handler.show_message(_("Confirm Transaction on your Ledger device..."))
    try:
        # Get trusted inputs from the original transactions
        for utxo in inputs:
            sequence = int_to_hex(utxo[5], 4)
            if segwitTransaction:
                txtmp = bitcoinTransaction(bfh(utxo[0]))
                tmp = bfh(utxo[3])[::-1]
                tmp += bfh(int_to_hex(utxo[1], 4))
                tmp += txtmp.outputs[utxo[1]].amount
                chipInputs.append({"value": tmp, "witness": True, "sequence": sequence})
                redeemScripts.append(bfh(utxo[2]))
            elif not p2shTransaction:
                txtmp = bitcoinTransaction(bfh(utxo[0]))
                trustedInput = self.get_client().getTrustedInput(txtmp, utxo[1])
                trustedInput["sequence"] = sequence
                chipInputs.append(trustedInput)
                redeemScripts.append(txtmp.outputs[utxo[1]].script)
            else:
                tmp = bfh(utxo[3])[::-1]
                tmp += bfh(int_to_hex(utxo[1], 4))
                chipInputs.append({"value": tmp, "sequence": sequence})
                redeemScripts.append(bfh(utxo[2]))

        # Sign all inputs
        firstTransaction = True
        inputIndex = 0
        rawTx = tx.serialize()
        self.get_client().enableAlternate2fa(False)
        if segwitTransaction:
            self.get_client().startUntrustedTransaction(
                True, inputIndex, chipInputs, redeemScripts[inputIndex]
            )
            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"]:
                outputData["address"] = output
                self.handler.finished()
                pin = self.handler.get_auth(
                    outputData
                )  # does the authenticate dialog and returns pin
                if not pin:
                    raise UserWarning()
                if pin != "paired":
                    self.handler.show_message(_("Confirmed. Signing Transaction..."))
            while inputIndex < len(inputs):
                singleInput = [chipInputs[inputIndex]]
                self.get_client().startUntrustedTransaction(
                    False, 0, singleInput, redeemScripts[inputIndex]
                )
                inputSignature = self.get_client().untrustedHashSign(
                    inputsPaths[inputIndex], pin, lockTime=tx.locktime
                )
                inputSignature[0] = 0x30  # force for 1.4.9+
                signatures.append(inputSignature)
                inputIndex = inputIndex + 1
        else:
            while inputIndex < len(inputs):
                self.get_client().startUntrustedTransaction(
                    firstTransaction, inputIndex, chipInputs, redeemScripts[inputIndex]
                )
                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"]
                if outputData["confirmationNeeded"]:
                    outputData["address"] = output
                    self.handler.finished()
                    pin = self.handler.get_auth(
                        outputData
                    )  # does the authenticate dialog and returns pin
                    if not pin:
                        raise UserWarning()
                    if pin != "paired":
                        self.handler.show_message(
                            _("Confirmed. Signing Transaction...")
                        )
                else:
                    # Sign input with the provided PIN
                    inputSignature = self.get_client().untrustedHashSign(
                        inputsPaths[inputIndex], pin, lockTime=tx.locktime
                    )
                    inputSignature[0] = 0x30  # force for 1.4.9+
                    signatures.append(inputSignature)
                    inputIndex = inputIndex + 1
                if pin != "paired":
                    firstTransaction = False
    except UserWarning:
        self.handler.show_error(_("Cancelled by user"))
        return
    except BTChipException as e:
        if e.sw == 0x6985:  # cancelled by user
            return
        else:
            traceback.print_exc(file=sys.stderr)
            self.give_error(e, True)
    except BaseException as e:
        traceback.print_exc(file=sys.stdout)
        self.give_error(e, True)
    finally:
        self.handler.finished()

    for i, txin in enumerate(tx.inputs()):
        signingPos = inputs[i][4]
        txin["signatures"][signingPos] = bh2u(signatures[i])
    tx.raw = tx.serialize()