コード例 #1
0
 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 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)
コード例 #3
0
 def sign_and_insert_remote_sig(self, tx: PartialTransaction, remote_pubkey, remote_signature, pubkey, privkey):
     assert type(remote_pubkey) is bytes
     assert len(remote_pubkey) == 33
     assert type(remote_signature) is str
     assert type(pubkey) is bytes
     assert type(privkey) is bytes
     assert len(pubkey) == 33
     assert len(privkey) == 33
     tx.sign({bh2u(pubkey): (privkey[:-1], True)})
     tx.add_signature_to_txin(txin_idx=0, signing_pubkey=remote_pubkey.hex(), sig=remote_signature + "01")
コード例 #4
0
ファイル: tx_dialog.py プロジェクト: cryptobuks1/electrum-nix
 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
コード例 #5
0
ファイル: trezor.py プロジェクト: huazhouwang/electrum
 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()}
     if not self.client:
         raise Exception("client is None")
     xpub = keystore.xpub
     derivation = keystore.get_derivation_prefix()
     if not self.force_pair_with_xpub(self.client, xpub, derivation):
         raise Exception("Can't Pair With You Device When Sign tx")
     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, _ = self.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)
     raise Exception("sign success")
コード例 #6
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():
            if address:
                return TxOutputType(
                    amount=txout.value,
                    script_type=OutputScriptType.PAYTOADDRESS,
                    address=address,
                )
            else:
                return TxOutputType(
                    amount=txout.value,
                    script_type=OutputScriptType.PAYTOOPRETURN,
                    op_return_data=
                    trezor_validate_op_return_output_and_get_data(txout),
                )

        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
コード例 #7
0
    def tx_outputs(self, tx: PartialTransaction, *,
                   keystore: 'KeepKey_KeyStore'):
        def create_output_by_derivation():
            script_type = self.get_keepkey_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 = self.types.TxOutputType(multisig=multisig,
                                                   amount=txout.value,
                                                   address_n=full_path,
                                                   script_type=script_type)
            return txoutputtype

        def create_output_by_address():
            txoutputtype = self.types.TxOutputType()
            txoutputtype.amount = txout.value
            if address:
                txoutputtype.script_type = self.types.PAYTOADDRESS
                txoutputtype.address = address
            else:
                txoutputtype.script_type = self.types.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
                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
コード例 #8
0
 def on_otp(self, tx: PartialTransaction, otp):
     if not otp:
         self.logger.info("sign_transaction: no auth code")
         return
     otp = int(otp)
     long_user_id, short_id = self.get_user_id()
     raw_tx = serialize_tx_in_legacy_format(tx, wallet=self)
     try:
         r = server.sign(short_id, raw_tx, otp)
     except TrustedCoinException as e:
         if e.status_code == 400:  # invalid OTP
             raise UserFacingException(_('Invalid one-time password.')) from e
         else:
             raise
     if r:
         received_raw_tx = r.get('transaction')
         received_tx = Transaction(received_raw_tx)
         tx.combine_with_other_psbt(received_tx)
     self.logger.info(f"twofactor: is complete {tx.is_complete()}")
     # reset billing_info
     self.billing_info = None
     self.plugin.start_request_thread(self)
コード例 #9
0
ファイル: tx_dialog.py プロジェクト: cryptobuks1/electrum-nix
 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()
コード例 #10
0
ファイル: coldcard.py プロジェクト: yo5eff/electrum-ecc
    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)
コード例 #11
0
ファイル: bitbox02.py プロジェクト: sysbot/electrum
    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
コード例 #12
0
ファイル: bitbox02.py プロジェクト: sysbot/electrum
    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 = bitbox02.btc.BTC
        if constants.net.TESTNET:
            coin = bitbox02.btc.TBTC

        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 == "p2wsh":
            if type(wallet) is Multisig_Wallet:
                tx_script_type = self.btc_multisig_config(coin, full_path, wallet)
            else:
                raise Exception("Can only use 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,
                    )
                )

        if type(wallet) is Standard_Wallet:
            keypath_account = full_path[:3]
        elif type(wallet) is Multisig_Wallet:
            keypath_account = full_path[:4]
        else:
            raise Exception(
                "BitBox02 does not support this wallet type: {}".format(type(wallet))
            )

        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)
コード例 #13
0
def serialize_tx_in_legacy_format(tx: PartialTransaction, *, wallet: Multisig_Wallet) -> str:
    assert isinstance(tx, PartialTransaction)

    # copy tx so we don't mutate the input arg
    # monkey-patch method of tx instance to change serialization
    tx = copy.deepcopy(tx)

    def get_siglist(txin: 'PartialTxInput', *, estimate_size=False):
        if txin.is_coinbase_input():
            return [], []
        if estimate_size:
            try:
                pubkey_size = len(txin.pubkeys[0])
            except IndexError:
                pubkey_size = 33  # guess it is compressed
            num_pubkeys = max(1, len(txin.pubkeys))
            pk_list = ["00" * pubkey_size] * num_pubkeys
            # we assume that signature will be 0x48 bytes long
            num_sig = max(txin.num_sig, num_pubkeys)
            sig_list = [ "00" * 0x48 ] * num_sig
        else:
            pk_list = ["" for pk in txin.pubkeys]
            for ks in wallet.get_keystores():
                my_pubkey, full_path = ks.find_my_pubkey_in_txinout(txin)
                x_pubkey = get_xpubkey(ks, full_path[-2], full_path[-1])
                pubkey_index = txin.pubkeys.index(my_pubkey)
                pk_list[pubkey_index] = x_pubkey
            assert all(pk_list)
            sig_list = [txin.part_sigs.get(pubkey, NO_SIGNATURE).hex() for pubkey in txin.pubkeys]
        return pk_list, sig_list

    def input_script(self, txin: PartialTxInput, *, estimate_size=False) -> str:
        assert estimate_size is False
        pubkeys, sig_list = get_siglist(txin, estimate_size=estimate_size)
        script = ''.join(push_script(x) for x in sig_list)
        if txin.script_type == 'p2sh':
            # put op_0 before script
            script = '00' + script
            redeem_script = multisig_script(pubkeys, txin.num_sig)
            script += push_script(redeem_script)
            return script
        elif txin.script_type == 'p2wsh':
            return ''
        raise Exception(f"unexpected type {txin.script_type}")
    tx.input_script = input_script.__get__(tx, PartialTransaction)

    def serialize_witness(self, txin: PartialTxInput, *, estimate_size=False):
        assert estimate_size is False
        if txin.witness is not None:
            return txin.witness.hex()
        if txin.is_coinbase_input():
            return ''
        assert isinstance(txin, PartialTxInput)
        if not self.is_segwit_input(txin):
            return '00'
        pubkeys, sig_list = get_siglist(txin, estimate_size=estimate_size)
        if txin.script_type == 'p2wsh':
            witness_script = multisig_script(pubkeys, txin.num_sig)
            witness = construct_witness([0] + sig_list + [witness_script])
        else:
            raise Exception(f"unexpected type {txin.script_type}")
        if txin.is_complete() or estimate_size:
            partial_format_witness_prefix = ''
        else:
            input_value = int_to_hex(txin.value_sats(), 8)
            witness_version = int_to_hex(0, 2)
            partial_format_witness_prefix = var_int(0xffffffff) + input_value + witness_version
        return partial_format_witness_prefix + witness
    tx.serialize_witness = serialize_witness.__get__(tx, PartialTransaction)

    buf = ELECTRUM_PARTIAL_TXN_HEADER_MAGIC.hex()
    buf += PARTIAL_FORMAT_VERSION.hex()
    buf += tx.serialize_to_network()
    return buf
コード例 #14
0
ファイル: elec-p2wsh-hodl.py プロジェクト: brianddk/reddit
witness_script = compile(
    [expiry, 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', pubkey, 'OP_CHECKSIG'])
script_hash = b2x(sha256(x(witness_script)))
hodl_address = bech32_encode(script_hash)
prevout = TxOutpoint(txid=txid, out_idx=vout)
txin = PartialTxInput(prevout=prevout)
txin._trusted_value_sats = sats
txin.nsequence = sequence
txin.script_sig = x(compile([]))  # empty script (important!)
txin.witness_script = x(witness_script)

# Build the Transaction Output
txout = PartialTxOutput.from_address_and_value(address, sats_less_fees)

# Build and sign the transaction
tx = PartialTransaction.from_io([txin], [txout], locktime=locktime)
tx.version = 1
txin_index = 0
sig = tx.sign_txin(txin_index, privkey)

# Prepend number of elements in script per the spec.
script = [sig, witness_script]
size = bytes([len(script)])
txin.witness = size + x(compile(script))

# Get the serialized txn and compute txid
txn = tx.serialize()

# Display results
print("PayTo:", hodl_address)
print("wif:", wif)
コード例 #15
0
ファイル: elec-p2sh-hodl.py プロジェクト: brianddk/reddit
 def __init__(self):
     PartialTransaction.__init__(self)
コード例 #16
0
ファイル: plugin.py プロジェクト: GlobalBoost/electrum
def is_any_tx_output_on_change_branch(tx: PartialTransaction) -> bool:
    return any([txout.is_change for txout in tx.outputs()])
コード例 #17
0
    def __init__(
        self,
        *,
        main_window: 'ElectrumWindow',
        tx: PartialTransaction,
        txid: str,
        title: str,
        help_text: str,
    ):
        WindowModalDialog.__init__(self, main_window, title=title)
        self.window = main_window
        self.wallet = main_window.wallet
        self.tx = tx
        assert txid
        self.txid = txid

        fee = tx.get_fee()
        assert fee is not None
        tx_size = tx.estimated_size()
        old_fee_rate = fee / tx_size  # sat/vbyte
        vbox = QVBoxLayout(self)
        vbox.addWidget(WWLabel(help_text))

        ok_button = OkButton(self)
        self.adv_button = QPushButton(_("Show advanced settings"))
        warning_label = WWLabel('\n')
        warning_label.setStyleSheet(ColorScheme.RED.as_stylesheet())
        self.feerate_e = FeerateEdit(lambda: 0)
        self.feerate_e.setAmount(max(old_fee_rate * 1.5, old_fee_rate + 1))

        def on_feerate():
            fee_rate = self.feerate_e.get_amount()
            warning_text = '\n'
            if fee_rate is not None:
                try:
                    new_tx = self.rbf_func(fee_rate)
                except Exception as e:
                    new_tx = None
                    warning_text = str(e).replace('\n', ' ')
            else:
                new_tx = None
            ok_button.setEnabled(new_tx is not None)
            warning_label.setText(warning_text)

        self.feerate_e.textChanged.connect(on_feerate)

        def on_slider(dyn, pos, fee_rate):
            fee_slider.activate()
            if fee_rate is not None:
                self.feerate_e.setAmount(fee_rate / 1000)

        fee_slider = FeeSlider(self.window, self.window.config, on_slider)
        fee_combo = FeeComboBox(fee_slider)
        fee_slider.deactivate()
        self.feerate_e.textEdited.connect(fee_slider.deactivate)

        grid = QGridLayout()
        grid.addWidget(QLabel(_('Current Fee') + ':'), 0, 0)
        grid.addWidget(
            QLabel(
                self.window.format_amount(fee) + ' ' +
                self.window.base_unit()), 0, 1)
        grid.addWidget(QLabel(_('Current Fee rate') + ':'), 1, 0)
        grid.addWidget(
            QLabel(self.window.format_fee_rate(1000 * old_fee_rate)), 1, 1)
        grid.addWidget(QLabel(_('New Fee rate') + ':'), 2, 0)
        grid.addWidget(self.feerate_e, 2, 1)
        grid.addWidget(fee_slider, 3, 1)
        grid.addWidget(fee_combo, 3, 2)
        vbox.addLayout(grid)
        self._add_advanced_options_cont(vbox)
        vbox.addWidget(warning_label)

        btns_hbox = QHBoxLayout()
        btns_hbox.addWidget(self.adv_button)
        btns_hbox.addStretch(1)
        btns_hbox.addWidget(CancelButton(self))
        btns_hbox.addWidget(ok_button)
        vbox.addLayout(btns_hbox)