示例#1
0
    def sign_transaction(self, tx, password):
        if tx.is_complete():
            return
        client = self.get_client()
        self.signing = True
        inputs = []
        inputsPaths = []
        pubKeys = []
        chipInputs = []
        redeemScripts = []
        signatures = []
        preparedTrustedInputs = []
        changePath = ""
        changeAmount = None
        output = None
        outputAmount = None
        p2shTransaction = 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

            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])
                    hwAddress = "%s" % (self.get_derivation()[2:])

                    # Jackhammer Fix
                    for idx in s:
                        hwAddress += "/%d" % (idx)

                    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(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:
            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):
                    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)
                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]))

            # Sign all inputs
            inputIndex = 0
            rawTx = tx.serialize()
            self.get_client().enableAlternate2fa(False)
            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,
                    sighashType=tx.nHashType())
                inputSignature[0] = 0x30  # force for 1.4.9+
                signatures.append(inputSignature)
                inputIndex = inputIndex + 1
        except UserWarning:
            self.handler.show_error(_('Cancelled by user'))
            return
        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()
        self.signing = False
示例#2
0
    def sign_transaction(self, tx, password):
        self.print_error('sign_transaction(): tx: ' + str(tx))  #debugSatochip

        client = self.get_client()

        # outputs
        txOutputs = ''.join(tx.serialize_output(o) for o in tx.outputs())
        hashOutputs = bh2u(Hash(bfh(txOutputs)))
        txOutputs = var_int(len(tx.outputs())) + txOutputs
        self.print_error('sign_transaction(): hashOutputs= ',
                         hashOutputs)  #debugSatochip
        self.print_error('sign_transaction(): outputs= ',
                         txOutputs)  #debugSatochip

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

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

            pubkeys, x_pubkeys = tx.get_sorted_pubkeys(txin)
            for j, x_pubkey in enumerate(x_pubkeys):
                self.print_error('sign_transaction(): forforloop: j=',
                                 j)  #debugSatochip
                if tx.is_txin_complete(txin):
                    break

                if x_pubkey in derivations:
                    signingPos = j
                    s = derivations.get(x_pubkey)
                    address_path = "%s/%d/%d" % (self.get_derivation()[2:],
                                                 s[0], s[1])

                    # get corresponing extended key
                    (depth, bytepath) = bip32path2bytes(address_path)
                    (key, chaincode
                     ) = client.cc.card_bip32_get_extendedkey(bytepath)

                    # parse tx
                    pre_tx_hex = tx.serialize_preimage(i)
                    pre_tx = bytes.fromhex(
                        pre_tx_hex)  # hex representation => converted to bytes
                    pre_hash = Hash(bfh(pre_tx_hex))
                    pre_hash_hex = pre_hash.hex()
                    self.print_error('sign_transaction(): pre_tx_hex=',
                                     pre_tx_hex)  #debugSatochip
                    self.print_error('sign_transaction(): pre_hash=',
                                     pre_hash_hex)  #debugSatochip
                    (response, sw1, sw2) = client.cc.card_parse_transaction(
                        pre_tx, True
                    )  # use 'True' since BCH use BIP143 as in Segwit...
                    #print_error('[satochip] sign_transaction(): response= '+str(response)) #debugSatochip
                    (tx_hash, needs_2fa
                     ) = client.parser.parse_parse_transaction(response)
                    # tx_hash should be equal to pre_hash_hex
                    self.print_error('sign_transaction(): tx_hash=',
                                     bytes(tx_hash).hex())  #debugSatochip
                    #todo: assert()

                    # sign tx
                    keynbr = 0xFF  #for extended key
                    if needs_2fa:
                        # format & encrypt msg
                        import json
                        coin_type = 145  #see https://github.com/satoshilabs/slips/blob/master/slip-0044.md
                        test_net = networks.net.TESTNET
                        msg = {
                            'action': "sign_tx",
                            'tx': pre_tx_hex,
                            'ct': coin_type,
                            'sw': True,
                            'tn': test_net,
                            'txo': txOutputs,
                            'ty': txin['type']
                        }
                        msg = json.dumps(msg)
                        (id_2FA,
                         msg_out) = client.cc.card_crypt_transaction_2FA(
                             msg, True)
                        d = {}
                        d['msg_encrypt'] = msg_out
                        d['id_2FA'] = id_2FA
                        # self.print_error("encrypted message: "+msg_out)
                        self.print_error("id_2FA:", id_2FA)

                        #do challenge-response with 2FA device...
                        client.handler.show_message(
                            '2FA request sent! Approve or reject request on your second device.'
                        )
                        run_hook('do_challenge_response', d)
                        # decrypt and parse reply to extract challenge response
                        try:
                            reply_encrypt = None  # init it in case of exc below
                            reply_encrypt = d['reply_encrypt']
                        except Exception as e:
                            # Note: give_error here will raise again.. :/
                            self.give_error(
                                "No response received from 2FA.\nPlease ensure that the Satochip-2FA plugin is enabled in Tools>Optional Features",
                                True)
                            break
                        if reply_encrypt is None:
                            #todo: abort tx
                            break
                        reply_decrypt = client.cc.card_crypt_transaction_2FA(
                            reply_encrypt, False)
                        self.print_error("challenge:response=", reply_decrypt)
                        reply_decrypt = reply_decrypt.split(":")
                        rep_pre_hash_hex = reply_decrypt[0][0:64]
                        if rep_pre_hash_hex != pre_hash_hex:
                            #todo: abort tx or retry?
                            self.print_error("Abort transaction: tx mismatch:",
                                             rep_pre_hash_hex, "!=",
                                             pre_hash_hex)
                            break
                        chalresponse = reply_decrypt[1]
                        if chalresponse == "00" * 20:
                            #todo: abort tx?
                            self.print_error(
                                "Abort transaction: rejected by 2FA!")
                            break
                        chalresponse = list(bytes.fromhex(chalresponse))
                    else:
                        chalresponse = None
                    (tx_sig, sw1, sw2) = client.cc.card_sign_transaction(
                        keynbr, tx_hash, chalresponse)
                    self.print_error('sign_transaction(): sig=',
                                     bytes(tx_sig).hex())  #debugSatochip
                    #todo: check sw1sw2 for error (0x9c0b if wrong challenge-response)
                    # enforce low-S signature (BIP 62)
                    tx_sig = bytearray(tx_sig)
                    r, s = get_r_and_s_from_der_sig(tx_sig)
                    if s > CURVE_ORDER // 2:
                        s = CURVE_ORDER - s
                    tx_sig = der_sig_from_r_and_s(r, s)
                    #update tx with signature
                    tx_sig = tx_sig.hex() + '41'
                    #tx.add_signature_to_txin(i,j,tx_sig)
                    txin['signatures'][j] = tx_sig
                    break
            else:
                self.give_error("No matching x_key for sign_transaction"
                                )  # should never happen

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

        # 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

            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}".format(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(addr)
            txOutput += var_int(len(script)//2)
            txOutput += script
        txOutput = bfh(txOutput)

        # Recognize outputs
        # - only one output and one change is authorized (for hw.1 and nano)
        # - at most one output can bypass confirmation (~change) (for all)
        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")
            has_change = False
            any_output_on_change_branch = is_any_tx_output_on_change_branch(tx)
            for _type, address, amount in tx.outputs():
                if self.get_client_electrum().is_hw1():
                    if not _type == TYPE_ADDRESS:
                        self.give_error(_("Only address outputs are supported by {}").format(self.hw_type))
                else:
                    if not _type in [TYPE_ADDRESS, TYPE_SCRIPT]:
                        self.give_error(_("Only address and script outputs are supported by {}").format(self.hw_type))
                    if _type == TYPE_SCRIPT and not address.script[0] == OpCodes.OP_RETURN:
                        self.give_error(_("Only OP_RETURN script outputs are supported by {}").format(self.hw_type))
                info = tx.output_info.get(address)
                if (info is not None) and len(tx.outputs()) > 1 \
                        and not has_change:
                    index, xpubs, m = info
                    on_change_branch = index[0] == 1
                    # prioritise hiding outputs on the 'change' branch from user
                    # because no more than one change address allowed
                    if on_change_branch == any_output_on_change_branch:
                        changePath = self.get_derivation()[2:] + "/{:d}/{:d}".format(*index)
                        has_change = True
                    else:
                        output = address
                else:
                    output = address

        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)
                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]))

            # Sign all inputs
            inputIndex = 0
            self.get_client().enableAlternate2fa(False)
            cashaddr = Address.FMT_UI == Address.FMT_CASHADDR
            if cashaddr and self.get_client_electrum().supports_cashaddr():
                self.get_client().startUntrustedTransaction(True, inputIndex, chipInputs,
                                                            redeemScripts[inputIndex], cashAddr=True)
            else:
                self.get_client().startUntrustedTransaction(True, inputIndex,
                                                            chipInputs, redeemScripts[inputIndex])
            # 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(tx.serialize(True)))
            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()
                self.handler.show_message(_("Confirmed. Signing Transaction..."))
            while inputIndex < len(inputs):
                singleInput = [ chipInputs[inputIndex] ]
                if cashaddr and self.get_client_electrum().supports_cashaddr():
                    self.get_client().startUntrustedTransaction(False, 0, singleInput,
                                                            redeemScripts[inputIndex], cashAddr=True)
                else:
                    self.get_client().startUntrustedTransaction(False, 0,
                                                            singleInput, redeemScripts[inputIndex])
                inputSignature = self.get_client().untrustedHashSign(inputsPaths[inputIndex], pin, lockTime=tx.locktime, sighashType=tx.nHashType())
                inputSignature[0] = 0x30 # force for 1.4.9+
                signatures.append(inputSignature)
                inputIndex = inputIndex + 1
        except UserWarning:
            self.handler.show_error(_('Cancelled by user'))
            return
        except BTChipException as e:
            if e.sw in (0x6985, 0x6d00):  # cancelled by user
                return
            elif e.sw == 0x6982:
                raise  # pin lock. decorator will catch it
            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()
示例#4
0
    def sign_transaction(self, tx, password, *, use_cache=False):
        if tx.is_complete():
            return
        inputs = []
        inputsPaths = []
        pubKeys = []
        chipInputs = []
        redeemScripts = []
        signatures = []
        changePath = ""
        output = None
        p2shTransaction = False
        pin = ""
        # prompt for the PIN before displaying the dialog if necessary
        client_ledger = self.get_client()
        client_electrum = self.get_client_electrum()
        assert client_electrum

        # 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

            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}".format(
                        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(addr)
            txOutput += var_int(len(script) // 2)
            txOutput += script
        txOutput = bfh(txOutput)

        if not client_electrum.supports_multi_output():
            if len(tx.outputs()) > 2:
                self.give_error(
                    _('Transaction with more than 2 outputs not supported by {}'
                      ).format(self.device))
        for o in tx.outputs():
            _type, address, amount = o
            if client_electrum.is_hw1():
                if not _type == TYPE_ADDRESS:
                    self.give_error(
                        _('Only address outputs are supported by {}').format(
                            self.device))
            else:
                if not _type in [TYPE_ADDRESS, TYPE_SCRIPT]:
                    self.give_error(
                        _('Only address and script outputs are supported by {}'
                          ).format(self.device))
                if _type == TYPE_SCRIPT:
                    try:
                        # Ledger has a maximum output size of 200 bytes:
                        # https://github.com/LedgerHQ/ledger-app-btc/commit/3a78dee9c0484821df58975803e40d58fbfc2c38#diff-c61ccd96a6d8b54d48f54a3bc4dfa7e2R26
                        # which gives us a maximum OP_RETURN payload size of
                        # 187 bytes. It also apparently has no limit on
                        # max_pushes, so we specify max_pushes=None so as
                        # to bypass that check.
                        validate_op_return_output_and_get_data(o,
                                                               max_size=187,
                                                               max_pushes=None)
                    except RuntimeError as e:
                        self.give_error('{}: {}'.format(self.device, str(e)))

        # - only one output and one change is authorized (for hw.1 and nano)
        # - at most one output can bypass confirmation (~change) (for all)
        if not p2shTransaction:
            if not client_electrum.supports_multi_output():
                if len(tx.outputs()) > 2:
                    self.give_error(
                        _('Transaction with more than 2 outputs not supported by {}'
                          ).format(self.device))
            has_change = False
            any_output_on_change_branch = is_any_tx_output_on_change_branch(tx)
            for _type, address, amount in tx.outputs():
                info = tx.output_info.get(address)
                if (info is not None) and len(tx.outputs()) > 1 \
                        and not has_change:
                    index, xpubs, m, script_type = info
                    on_change_branch = index[0] == 1
                    # prioritise hiding outputs on the 'change' branch from user
                    # because no more than one change address allowed
                    if on_change_branch == any_output_on_change_branch:
                        changePath = self.get_derivation(
                        )[2:] + "/{:d}/{:d}".format(*index)
                        has_change = True
                    else:
                        output = address
                else:
                    output = address

        try:
            # Get trusted inputs from the original transactions
            for input_idx, utxo in enumerate(inputs):
                self.handler.show_message(
                    _("Preparing transaction inputs...") +
                    f" (phase1, {input_idx}/{len(inputs)})")
                sequence = int_to_hex(utxo[5], 4)
                if not client_electrum.requires_trusted_inputs():
                    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]))
                else:
                    txtmp = bitcoinTransaction(bfh(utxo[0]))
                    trustedInput = client_ledger.getTrustedInput(
                        txtmp, utxo[1])
                    trustedInput['sequence'] = sequence
                    trustedInput['witness'] = True
                    chipInputs.append(trustedInput)
                    if p2shTransaction:
                        redeemScripts.append(bfh(utxo[2]))
                    else:
                        redeemScripts.append(txtmp.outputs[utxo[1]].script)

            self.handler.show_message(
                _("Confirm Transaction on your Ledger device..."))
            # Sign all inputs
            inputIndex = 0
            client_ledger.enableAlternate2fa(False)
            cashaddr = Address.FMT_UI == Address.FMT_CASHADDR_BCH
            if cashaddr and client_electrum.supports_cashaddr():
                client_ledger.startUntrustedTransaction(
                    True,
                    inputIndex,
                    chipInputs,
                    redeemScripts[inputIndex],
                    cashAddr=True)
            else:
                client_ledger.startUntrustedTransaction(
                    True, inputIndex, chipInputs, redeemScripts[inputIndex])
            # we don't set meaningful outputAddress, amount and fees
            # as we only care about the alternateEncoding==True branch
            outputData = client_ledger.finalizeInput(b'', 0, 0, changePath,
                                                     bfh(tx.serialize(True)))
            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()
                self.handler.show_message(
                    _('Confirmed. Signing Transaction...'))
            while inputIndex < len(inputs):
                self.handler.show_message(
                    _("Signing transaction...") +
                    f" (phase2, {inputIndex}/{len(inputs)})")
                singleInput = [chipInputs[inputIndex]]
                if cashaddr and client_electrum.supports_cashaddr():
                    client_ledger.startUntrustedTransaction(
                        False,
                        0,
                        singleInput,
                        redeemScripts[inputIndex],
                        cashAddr=True)
                else:
                    client_ledger.startUntrustedTransaction(
                        False, 0, singleInput, redeemScripts[inputIndex])
                inputSignature = client_ledger.untrustedHashSign(
                    inputsPaths[inputIndex],
                    pin,
                    lockTime=tx.locktime,
                    sighashType=0x41)
                inputSignature[0] = 0x30  # force for 1.4.9+
                signatures.append(inputSignature)
                inputIndex = inputIndex + 1
        except UserWarning:
            self.handler.show_error(_('Cancelled by user'))
            return
        except BTChipException as e:
            if e.sw in (0x6985, 0x6d00):  # cancelled by user
                return
            elif e.sw == 0x6982:
                raise  # pin lock. decorator will catch it
            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()
示例#5
0
def msg_magic(message: bytes) -> bytes:
    from electroncash.bitcoin import var_int
    length = bfh(var_int(len(message)))
    return b"\x18Bitcoin Signed Message:\n" + length + message