コード例 #1
0
ファイル: safe_t.py プロジェクト: mboyd1/electrum-dsv
 def sign_transaction(self, keystore, tx: PartialTransaction, prev_tx):
     self.prev_tx = prev_tx
     client = self.get_client(keystore)
     inputs = self.tx_inputs(tx, for_sig=True, keystore=keystore)
     outputs = self.tx_outputs(tx, keystore=keystore)
     signatures = client.sign_tx(self.get_coin_name(),
                                 inputs,
                                 outputs,
                                 lock_time=tx.locktime,
                                 version=tx.version)[0]
     signatures = [(bh2u(x) + '01') for x in signatures]
     tx.update_signatures(signatures)
コード例 #2
0
 def _add_info_to_tx_from_wallet_and_network(
         self, tx: PartialTransaction) -> bool:
     """Returns whether successful."""
     # note side-effect: tx is being mutated
     assert isinstance(tx, PartialTransaction)
     try:
         # note: this might download input utxos over network
         # FIXME network code in gui thread...
         tx.add_info_from_wallet(self.wallet, ignore_network_issues=False)
     except NetworkException as e:
         self.app.show_error(repr(e))
         return False
     return True
コード例 #3
0
 def sign_transaction(self, keystore, tx: PartialTransaction, prev_tx):
     prev_tx = {
         bfh(txhash): self.electrum_tx_to_txtype(tx)
         for txhash, tx in prev_tx.items()
     }
     client = self.get_client(keystore)
     inputs = self.tx_inputs(tx, for_sig=True, keystore=keystore)
     outputs = self.tx_outputs(tx, keystore=keystore)
     details = SignTx(lock_time=tx.locktime, version=tx.version)
     signatures, _ = client.sign_tx(self.get_coin_name(),
                                    inputs,
                                    outputs,
                                    details=details,
                                    prev_txes=prev_tx)
     signatures = [(bh2u(x) + '01') for x in signatures]
     tx.update_signatures(signatures)
コード例 #4
0
    def tx_outputs(self, tx: PartialTransaction, *,
                   keystore: 'TrezorKeyStore'):
        def create_output_by_derivation():
            script_type = self.get_trezor_output_script_type(txout.script_type)
            if len(txout.pubkeys) > 1:
                xpubs_and_deriv_suffixes = get_xpubs_and_der_suffixes_from_txinout(
                    tx, txout)
                multisig = self._make_multisig(txout.num_sig,
                                               xpubs_and_deriv_suffixes)
            else:
                multisig = None
            my_pubkey, full_path = keystore.find_my_pubkey_in_txinout(txout)
            assert full_path
            txoutputtype = TxOutputType(multisig=multisig,
                                        amount=txout.value,
                                        address_n=full_path,
                                        script_type=script_type)
            return txoutputtype

        def create_output_by_address():
            txoutputtype = TxOutputType()
            txoutputtype.amount = txout.value
            if address:
                txoutputtype.script_type = OutputScriptType.PAYTOADDRESS
                txoutputtype.address = address
            else:
                txoutputtype.script_type = OutputScriptType.PAYTOOPRETURN
                txoutputtype.op_return_data = trezor_validate_op_return_output_and_get_data(
                    txout)
            return txoutputtype

        outputs = []
        has_change = False
        any_output_on_change_branch = is_any_tx_output_on_change_branch(tx)

        for txout in tx.outputs():
            address = txout.address
            use_create_by_derivation = False

            if txout.is_mine and not has_change:
                # prioritise hiding outputs on the 'change' branch from user
                # because no more than one change address allowed
                # note: ^ restriction can be removed once we require fw
                # that has https://github.com/trezor/trezor-mcu/pull/306
                if txout.is_change == any_output_on_change_branch:
                    use_create_by_derivation = True
                    has_change = True

            if use_create_by_derivation:
                txoutputtype = create_output_by_derivation()
            else:
                txoutputtype = create_output_by_address()
            outputs.append(txoutputtype)

        return outputs
コード例 #5
0
 def do_dscancel(self):
     from .dscancel_dialog import DSCancelDialog
     tx = self.tx
     txid = tx.txid()
     assert txid
     if not isinstance(tx, PartialTransaction):
         tx = PartialTransaction.from_tx(tx)
     if not self._add_info_to_tx_from_wallet_and_network(tx):
         return
     fee = tx.get_fee()
     assert fee is not None
     size = tx.estimated_size()
     cb = partial(self._do_dscancel, tx=tx)
     d = DSCancelDialog(self.app, fee, size, cb)
     d.open()
コード例 #6
0
    def sign_transaction(self, tx, password):
        # Upload PSBT for signing.
        # - we can also work offline (without paired device present)
        if tx.is_complete():
            return

        client = self.get_client()

        assert client.dev.master_fingerprint == self.get_xfp_int()

        raw_psbt = tx.serialize_as_bytes()

        try:
            try:
                self.handler.show_message("Authorize Transaction...")

                client.sign_transaction_start(raw_psbt)

                while 1:
                    # How to kill some time, without locking UI?
                    time.sleep(0.250)

                    resp = client.sign_transaction_poll()
                    if resp is not None:
                        break

                rlen, rsha = resp

                # download the resulting txn.
                raw_resp = client.download_file(rlen, rsha)

            finally:
                self.handler.finished()

        except (CCUserRefused, CCBusyError) as exc:
            self.logger.info(f'Did not sign: {exc}')
            self.handler.show_error(str(exc))
            return
        except BaseException as e:
            self.logger.exception('')
            self.give_error(e, True)
            return

        tx2 = PartialTransaction.from_raw_psbt(raw_resp)
        # apply partial signatures back into txn
        tx.combine_with_other_psbt(tx2)
コード例 #7
0
ファイル: bitbox02.py プロジェクト: mboyd1/electrum-dsv
    def sign_transaction(self, tx: PartialTransaction, password: str):
        if tx.is_complete():
            return
        client = self.get_client()
        assert isinstance(client, BitBox02Client)

        try:
            try:
                self.handler.show_message("Authorize Transaction...")
                client.sign_transaction(self, tx, self.handler.get_wallet())

            finally:
                self.handler.finished()

        except Exception as e:
            self.logger.exception("")
            self.give_error(e, True)
            return
コード例 #8
0
ファイル: bitbox02.py プロジェクト: mboyd1/electrum-dsv
    def sign_transaction(
        self,
        keystore: Hardware_KeyStore,
        tx: PartialTransaction,
        wallet: Deterministic_Wallet,
    ):
        if tx.is_complete():
            return

        if self.bitbox02_device is None:
            raise Exception(
                "Need to setup communication first before attempting any BitBox02 calls"
            )

        coin = self._get_coin()
        tx_script_type = None

        # Build BTCInputType list
        inputs = []
        for txin in tx.inputs():
            my_pubkey, full_path = keystore.find_my_pubkey_in_txinout(txin)

            if full_path is None:
                raise Exception(
                    "A wallet owned pubkey was not found in the transaction input to be signed"
                )

            prev_tx = txin.utxo
            if prev_tx is None:
                raise UserFacingException(_('Missing previous tx.'))

            prev_inputs: List[bitbox02.BTCPrevTxInputType] = []
            prev_outputs: List[bitbox02.BTCPrevTxOutputType] = []
            for prev_txin in prev_tx.inputs():
                prev_inputs.append({
                    "prev_out_hash":
                    prev_txin.prevout.txid[::-1],
                    "prev_out_index":
                    prev_txin.prevout.out_idx,
                    "signature_script":
                    prev_txin.script_sig,
                    "sequence":
                    prev_txin.nsequence,
                })
            for prev_txout in prev_tx.outputs():
                prev_outputs.append({
                    "value": prev_txout.value,
                    "pubkey_script": prev_txout.scriptpubkey,
                })

            inputs.append({
                "prev_out_hash": txin.prevout.txid[::-1],
                "prev_out_index": txin.prevout.out_idx,
                "prev_out_value": txin.value_sats(),
                "sequence": txin.nsequence,
                "keypath": full_path,
                "script_config_index": 0,
                "prev_tx": {
                    "version": prev_tx.version,
                    "locktime": prev_tx.locktime,
                    "inputs": prev_inputs,
                    "outputs": prev_outputs,
                },
            })

            if tx_script_type == None:
                tx_script_type = txin.script_type
            elif tx_script_type != txin.script_type:
                raise Exception("Cannot mix different input script types")

        if tx_script_type == "p2wpkh":
            tx_script_type = bitbox02.btc.BTCScriptConfig(
                simple_type=bitbox02.btc.BTCScriptConfig.P2WPKH)
        elif tx_script_type == "p2wpkh-p2sh":
            tx_script_type = bitbox02.btc.BTCScriptConfig(
                simple_type=bitbox02.btc.BTCScriptConfig.P2WPKH_P2SH)
        elif tx_script_type in ("p2wsh-p2sh", "p2wsh"):
            if type(wallet) is Multisig_Wallet:
                tx_script_type = self.btc_multisig_config(
                    coin, full_path, wallet, tx_script_type)
            else:
                raise Exception(
                    "Can only use p2wsh-p2sh or p2wsh with multisig wallets")
        else:
            raise UserFacingException(
                "invalid input script type: {} is not supported by the BitBox02"
                .format(tx_script_type))

        # Build BTCOutputType list
        outputs = []
        for txout in tx.outputs():
            assert txout.address
            # check for change
            if txout.is_change:
                my_pubkey, change_pubkey_path = keystore.find_my_pubkey_in_txinout(
                    txout)
                outputs.append(
                    bitbox02.BTCOutputInternal(
                        keypath=change_pubkey_path,
                        value=txout.value,
                        script_config_index=0,
                    ))
            else:
                addrtype, pubkey_hash = bitcoin.address_to_hash(txout.address)
                if addrtype == OnchainOutputType.P2PKH:
                    output_type = bitbox02.btc.P2PKH
                elif addrtype == OnchainOutputType.P2SH:
                    output_type = bitbox02.btc.P2SH
                elif addrtype == OnchainOutputType.WITVER0_P2WPKH:
                    output_type = bitbox02.btc.P2WPKH
                elif addrtype == OnchainOutputType.WITVER0_P2WSH:
                    output_type = bitbox02.btc.P2WSH
                else:
                    raise UserFacingException(
                        "Received unsupported output type during transaction signing: {} is not supported by the BitBox02"
                        .format(addrtype))
                outputs.append(
                    bitbox02.BTCOutputExternal(
                        output_type=output_type,
                        output_hash=pubkey_hash,
                        value=txout.value,
                    ))

        keypath_account = full_path[:-2]
        sigs = self.bitbox02_device.btc_sign(
            coin,
            [
                bitbox02.btc.BTCScriptConfigWithKeypath(
                    script_config=tx_script_type,
                    keypath=keypath_account,
                )
            ],
            inputs=inputs,
            outputs=outputs,
            locktime=tx.locktime,
            version=tx.version,
        )

        # Fill signatures
        if len(sigs) != len(tx.inputs()):
            raise Exception(
                "Incorrect number of inputs signed.")  # Should never occur
        signatures = [
            bh2u(ecc.der_sig_from_sig_string(x[1])) + "01" for x in sigs
        ]
        tx.update_signatures(signatures)
コード例 #9
0
ファイル: plugin.py プロジェクト: mboyd1/electrum-dsv
def is_any_tx_output_on_change_branch(tx: PartialTransaction) -> bool:
    return any([txout.is_change for txout in tx.outputs()])