示例#1
0
    def start_new_window(self, path, uri):
        '''Raises the window for the wallet if it is open.  Otherwise
        opens the wallet and creates a new window for it'''
        try:
            wallet = self.daemon.load_wallet(path, None)
        except BaseException as e:
            traceback.print_exc(file=sys.stdout)
            d = QMessageBox(QMessageBox.Warning, _('Error'),
                            _('Cannot load wallet') + ' (1):\n' + str(e))
            d.exec_()
            return
        if not wallet:
            storage = WalletStorage(path, manual_upgrades=True)
            wizard = InstallWizard(self.config, self.app, self.plugins,
                                   storage)
            try:
                wallet = wizard.run_and_get_wallet(self.daemon.get_wallet)
            except UserCancelled:
                pass
            except GoBack as e:
                print_error('[start_new_window] Exception caught (GoBack)', e)
            except (WalletFileException, BitcoinException) as e:
                traceback.print_exc(file=sys.stderr)
                d = QMessageBox(QMessageBox.Warning, _('Error'),
                                _('Cannot load wallet') + ' (2):\n' + str(e))
                d.exec_()
                return
            finally:
                wizard.terminate()
            if not wallet:
                return

            if not self.daemon.get_wallet(wallet.storage.path):
                # wallet was not in memory
                wallet.start_threads(self.daemon.network)
                self.daemon.add_wallet(wallet)
        try:
            for w in self.windows:
                if w.wallet.storage.path == wallet.storage.path:
                    w.bring_to_top()
                    return
            w = self.create_window_for_wallet(wallet)
        except BaseException as e:
            traceback.print_exc(file=sys.stdout)
            d = QMessageBox(
                QMessageBox.Warning, _('Error'),
                _('Cannot create window for wallet') + ':\n' + str(e))
            d.exec_()
            return
        if uri:
            w.pay_to_URI(uri)
        w.bring_to_top()
        w.setWindowState(w.windowState() & ~QtCore.Qt.WindowMinimized
                         | QtCore.Qt.WindowActive)

        # this will activate the window
        w.activateWindow()
        return w
示例#2
0
 def give_error(self, message, clear_client=False):
     print_error(message)
     if not self.signing:
         self.handler.show_error(message)
     else:
         self.signing = False
     if clear_client:
         self.client = None
     raise Exception(message)
 def hid_send_encrypt(self, msg):
     reply = ""
     try:
         secret = Hash(self.password)
         msg = EncodeAES(secret, msg)
         reply = self.hid_send_plain(msg)
         if 'ciphertext' in reply:
             reply = DecodeAES(secret, ''.join(reply["ciphertext"]))
             reply = to_string(reply, 'utf8')
             reply = json.loads(reply)
         if 'error' in reply:
             self.password = None
     except Exception as e:
         print_error('Exception caught ' + str(e))
     return reply
 def use_tor_proxy(self, use_it):
     if not use_it:
         self.proxy_cb.setChecked(False)
     else:
         socks5_mode_index = self.proxy_mode.findText('SOCKS5')
         if socks5_mode_index == -1:
             print_error("[network_dialog] can't find proxy_mode 'SOCKS5'")
             return
         self.proxy_mode.setCurrentIndex(socks5_mode_index)
         self.proxy_host.setText("127.0.0.1")
         self.proxy_port.setText(str(self.tor_proxy[1]))
         self.proxy_user.setText("")
         self.proxy_password.setText("")
         self.tor_cb.setChecked(True)
         self.proxy_cb.setChecked(True)
     self.check_disable_proxy(use_it)
     self.set_proxy()
 def hid_send_plain(self, msg):
     reply = ""
     try:
         serial_number = self.dbb_hid.get_serial_number_string()
         if "v2.0." in serial_number or "v1." in serial_number:
             hidBufSize = 4096
             self.dbb_hid.write('\0' + msg + '\0' * (hidBufSize - len(msg)))
             r = bytearray()
             while len(r) < hidBufSize:
                 r += bytearray(self.dbb_hid.read(hidBufSize))
         else:
             self.hid_send_frame(msg)
             r = self.hid_read_frame()
         r = r.rstrip(b' \t\r\n\0')
         r = r.replace(b"\0", b'')
         r = to_string(r, 'utf8')
         reply = json.loads(r)
     except Exception as e:
         print_error('Exception caught ' + str(e))
     return reply
示例#6
0
 def update_status(self, b):
     print_error('trezor status', b)
    def sign_transaction(self, tx, password):
        if tx.is_complete():
            return

        try:
            p2pkhTransaction = True
            derivations = self.get_tx_derivations(tx)
            inputhasharray = []
            hasharray = []
            pubkeyarray = []

            # Build hasharray from inputs
            for i, txin in enumerate(tx.inputs()):
                if txin['type'] == 'coinbase':
                    self.give_error(
                        "Coinbase not supported")  # should never happen

                if txin['type'] != 'p2pkh':
                    p2pkhTransaction = False

                for x_pubkey in txin['x_pubkeys']:
                    if x_pubkey in derivations:
                        index = derivations.get(x_pubkey)
                        inputPath = "%s/%d/%d" % (self.get_derivation(),
                                                  index[0], index[1])
                        inputHash = Hash(
                            binascii.unhexlify(tx.serialize_preimage(i)))
                        hasharray_i = {
                            'hash': to_hexstr(inputHash),
                            'keypath': inputPath
                        }
                        hasharray.append(hasharray_i)
                        inputhasharray.append(inputHash)
                        break
                else:
                    self.give_error("No matching x_key for sign_transaction"
                                    )  # should never happen

            # Build pubkeyarray from outputs
            for _type, address, amount in tx.outputs():
                assert _type == TYPE_ADDRESS
                info = tx.output_info.get(address)
                if info is not None:
                    index, xpubs, m = info
                    changePath = self.get_derivation() + "/%d/%d" % index
                    changePubkey = self.derive_pubkey(index[0], index[1])
                    pubkeyarray_i = {
                        'pubkey': changePubkey,
                        'keypath': changePath
                    }
                    pubkeyarray.append(pubkeyarray_i)

            # Special serialization of the unsigned transaction for
            # the mobile verification app.
            # At the moment, verification only works for p2pkh transactions.
            if p2pkhTransaction:

                class CustomTXSerialization(Transaction):
                    @classmethod
                    def input_script(self, txin, estimate_size=False):
                        if txin['type'] == 'p2pkh':
                            return Transaction.get_preimage_script(txin)
                        if txin['type'] == 'p2sh':
                            # Multisig verification has partial support, but is disabled. This is the
                            # expected serialization though, so we leave it here until we activate it.
                            return '00' + push_script(
                                Transaction.get_preimage_script(txin))
                        raise Exception("unsupported type %s" % txin['type'])

                tx_dbb_serialized = CustomTXSerialization(
                    tx.serialize()).serialize()
            else:
                # We only need this for the signing echo / verification.
                tx_dbb_serialized = None

            # Build sign command
            dbb_signatures = []
            steps = math.ceil(1.0 * len(hasharray) / self.maxInputs)
            for step in range(int(steps)):
                hashes = hasharray[step * self.maxInputs:(step + 1) *
                                   self.maxInputs]

                msg = {
                    "sign": {
                        "data": hashes,
                        "checkpub": pubkeyarray,
                    },
                }
                if tx_dbb_serialized is not None:
                    msg["sign"]["meta"] = to_hexstr(Hash(tx_dbb_serialized))
                msg = json.dumps(msg).encode('ascii')
                dbb_client = self.plugin.get_client(self)

                if not dbb_client.is_paired():
                    raise Exception("Could not sign transaction.")

                reply = dbb_client.hid_send_encrypt(msg)
                if 'error' in reply:
                    raise Exception(reply['error']['message'])

                if 'echo' not in reply:
                    raise Exception("Could not sign transaction.")

                if self.plugin.is_mobile_paired(
                ) and tx_dbb_serialized is not None:
                    reply['tx'] = tx_dbb_serialized
                    self.plugin.comserver_post_notification(reply)

                if steps > 1:
                    self.handler.show_message(
                        _("Signing large transaction. Please be patient ...") +
                        "\n\n" +
                        _("To continue, touch the Digital Bitbox's blinking light for 3 seconds."
                          ) + " " +
                        _("(Touch {} of {})").format((step + 1), steps) +
                        "\n\n" +
                        _("To cancel, briefly touch the blinking light or wait for the timeout."
                          ) + "\n\n")
                else:
                    self.handler.show_message(
                        _("Signing transaction...") + "\n\n" +
                        _("To continue, touch the Digital Bitbox's blinking light for 3 seconds."
                          ) + "\n\n" +
                        _("To cancel, briefly touch the blinking light or wait for the timeout."
                          ))

                # Send twice, first returns an echo for smart verification
                reply = dbb_client.hid_send_encrypt(msg)
                self.handler.finished()

                if 'error' in reply:
                    if reply["error"].get('code') in (600, 601):
                        # aborted via LED short touch or timeout
                        raise UserCancelled()
                    raise Exception(reply['error']['message'])

                if 'sign' not in reply:
                    raise Exception("Could not sign transaction.")

                dbb_signatures.extend(reply['sign'])

            # Fill signatures
            if len(dbb_signatures) != len(tx.inputs()):
                raise Exception("Incorrect number of transactions signed."
                                )  # Should never occur
            for i, txin in enumerate(tx.inputs()):
                num = txin['num_sig']
                for pubkey in txin['pubkeys']:
                    signatures = list(filter(None, txin['signatures']))
                    if len(signatures) == num:
                        break  # txin is complete
                    ii = txin['pubkeys'].index(pubkey)
                    signed = dbb_signatures[i]
                    if 'recid' in signed:
                        # firmware > v2.1.1
                        recid = int(signed['recid'], 16)
                        s = binascii.unhexlify(signed['sig'])
                        h = inputhasharray[i]
                        pk = MyVerifyingKey.from_signature(s,
                                                           recid,
                                                           h,
                                                           curve=SECP256k1)
                        pk = to_hexstr(point_to_ser(pk.pubkey.point, True))
                    elif 'pubkey' in signed:
                        # firmware <= v2.1.1
                        pk = signed['pubkey']
                    if pk != pubkey:
                        continue
                    sig_r = int(signed['sig'][:64], 16)
                    sig_s = int(signed['sig'][64:], 16)
                    sig = sigencode_der(sig_r, sig_s,
                                        generator_secp256k1.order())
                    txin['signatures'][ii] = to_hexstr(sig) + '01'
                    tx._inputs[i] = txin
        except UserCancelled:
            raise
        except BaseException as e:
            self.give_error(e, True)
        else:
            print_error("Transaction is_complete", tx.is_complete())
            tx.raw = tx.serialize()
示例#8
0
import platform

from electrum_zclassic.plugins import BasePlugin, hook
from electrum_zclassic_gui.qt.util import WaitingDialog, EnterButton, WindowModalDialog
from electrum_zclassic.util import print_msg, print_error
from electrum_zclassic.i18n import _

from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import (QComboBox, QGridLayout, QLabel, QPushButton)

try:
    import amodem.audio
    import amodem.main
    import amodem.config
    print_error('Audio MODEM is available.')
    amodem.log.addHandler(amodem.logging.StreamHandler(sys.stderr))
    amodem.log.setLevel(amodem.logging.INFO)
except ImportError:
    amodem = None
    print_error('Audio MODEM is not found.')


class Plugin(BasePlugin):

    def __init__(self, parent, config, name):
        BasePlugin.__init__(self, parent, config, name)
        if self.is_available():
            self.modem_config = amodem.config.slowest()
            self.library_name = {
                'Linux': 'libportaudio.so'
示例#9
0
    def check_tx_slp(wallet,
                     tx,
                     *,
                     coins_to_burn=None,
                     require_tx_in_wallet=True):

        # Step 1) Double check all input transactions have been added to wallet._slp_txo
        if require_tx_in_wallet:
            for txo in tx.inputs():
                addr = txo['address']
                prev_out = txo['prevout_hash']
                prev_n = txo['prevout_n']
                with wallet.lock:
                    try:
                        input_tx = wallet.transactions[prev_out]
                    except KeyError:
                        raise Exception(
                            'Wallet has not downloaded this transaction')
                    else:
                        try:
                            slp_msg = slp.SlpMessage.parseSlpOutputScript(
                                input_tx.outputs()[0][1])
                        except SlpInvalidOutputMessage:
                            pass
                        except SlpUnsupportedSlpTokenType:
                            raise UnsupportedSlpTokenType('Transaction contains an unsupported SLP' \
                                                            + ' input type')
                        else:
                            if slp_msg.transaction_type == 'SEND':
                                if prev_n >= len(
                                        slp_msg.
                                        op_return_fields['token_output']):
                                    continue
                            elif slp_msg.transaction_type in [
                                    'GENESIS', 'MINT'
                            ]:
                                if slp_msg.op_return_fields['mint_baton_vout'] and \
                                        prev_n not in [1, slp_msg.op_return_fields['mint_baton_vout']]:
                                    continue
                                elif not slp_msg.op_return_fields[
                                        'mint_baton_vout'] and prev_n != 1:
                                    continue
                                elif slp_msg.transaction_type == 'MINT' and \
                                        prev_n == 1 and \
                                        slp_msg.op_return_fields['additional_token_quantity'] == 0:
                                    continue
                            try:
                                with wallet.lock:
                                    assert wallet._slp_txo[addr][prev_out][
                                        prev_n]
                            except (KeyError, AssertionError):
                                raise SlpMissingInputRecord('Transaction contains an SLP input that is' \
                                                                + ' unknown to this wallet (missing from slp_txo).')

        # Step 2) Get SLP metadata in current transaction
        try:
            slp_msg = slp.SlpMessage.parseSlpOutputScript(tx.outputs()[0][1])
        except SlpParsingError:
            slp_msg = None

        # Step 3a) If non-SLP check for SLP inputs (only allow
        #          spending slp inputs specified in 'coins_to_burn')
        if not slp_msg:
            for txo in tx.inputs():
                addr = txo['address']
                prev_out = txo['prevout_hash']
                prev_n = txo['prevout_n']
                slp_txo = None
                with wallet.lock:
                    try:
                        slp_txo = wallet._slp_txo[addr][prev_out][prev_n]
                    except KeyError:
                        pass
                if slp_txo:
                    is_burn_allowed = False
                    if coins_to_burn:
                        for c in coins_to_burn:
                            if c['prevout_hash'] == prev_out and c[
                                    'prevout_n'] == prev_n:
                                is_burn_allowed = True
                                c['is_in_txn'] = True

                    if not is_burn_allowed:
                        print_error("SLP check failed for non-SLP transaction" \
                                        + " which contains SLP inputs.")
                        raise NonSlpTransactionHasSlpInputs(
                            'Non-SLP transaction contains unspecified SLP inputs.'
                        )

            # Check that all coins within 'coins_to_burn' are included in burn transaction
            if coins_to_burn:
                for coin in coins_to_burn:
                    try:
                        if coin['is_in_txn']:
                            continue
                    except KeyError:
                        raise MissingCoinToBeBurned('Transaction is missing SLP required inputs that were' \
                                                        + ' for this burn transaction.')

        # Step 3b) If SLP, check quantities and token id of inputs match output requirements
        elif slp_msg:
            if slp_msg.transaction_type == 'SEND':
                tid = slp_msg.op_return_fields['token_id_hex']
                # raise an Exception if:
                #   - [X] input quantity is greater than output quanitity (except if 'coins_to_burn')
                #   - [X] input quantity is less than output quanitity
                #   - [X] slp input does not match tokenId
                #   - [X] make sure outpoint is provided for every slp output and is P2PKH or P2SH
                #   - [ ] the proper token type is not respected in the output op_return message
                slp_outputs = slp_msg.op_return_fields['token_output']
                input_slp_qty = 0
                for txo in tx.inputs():
                    addr = txo['address']
                    prev_out = txo['prevout_hash']
                    prev_n = txo['prevout_n']
                    with wallet.lock:
                        try:
                            slp_input = wallet._slp_txo[addr][prev_out][prev_n]
                        except KeyError:
                            pass
                        else:
                            input_slp_qty += slp_input['qty']
                            if slp_input['token_id'] != tid:
                                print_error("SLP check failed for SEND due to incorrect" \
                                                + " tokenId in txn input")
                                raise SlpWrongTokenID('Transaction contains SLP inputs' \
                                                        + ' with incorrect token id.')

                if input_slp_qty < sum(slp_outputs):
                    print_error(
                        "SLP check failed for SEND due to insufficient SLP inputs"
                    )
                    raise SlpInputsTooLow(
                        'Transaction SLP outputs exceed SLP inputs')
                elif not coins_to_burn and input_slp_qty > sum(slp_outputs):
                    print_error(
                        "SLP check failed for SEND due to SLP inputs too high")
                    raise SlpInputsTooHigh(
                        'Transaction SLP inputs exceed SLP outputs.')

                for i, out in enumerate(
                        slp_msg.op_return_fields['token_output']):
                    try:
                        out = tx.outputs()[i]
                    except IndexError:
                        print_error("Transaction is missing vout for MINT operation" \
                                        + " token receiver")
                        raise MissingTokenReceiverOutpoint('Transaction is missing' \
                                                                + ' a required SLP output.')
                    else:
                        if i == 0:
                            assert out[0] == 2
                        elif out[1].kind not in [
                                Address.ADDR_P2PKH, Address.ADDR_P2SH
                        ]:
                            print_error(
                                "Transaction token receiver vout is not P2PKH or P2SH"
                            )
                            raise BadSlpOutpointType('Tranaction SLP output must be p2pkh' \
                                                        + ' or p2sh output type.')
            elif slp_msg.transaction_type == 'MINT':
                tid = slp_msg.op_return_fields['token_id_hex']
                # raise an Exception if:
                #   - [X] Any non-baton SLP input is found
                #   - [X] Baton has wrong token ID
                #   - [ ] Minting transaction is being made from NFT child type baton
                for txo in tx.inputs():
                    addr = txo['address']
                    prev_out = txo['prevout_hash']
                    prev_n = txo['prevout_n']
                    with wallet.lock:
                        try:
                            slp_input = wallet._slp_txo[addr][prev_out][prev_n]
                        except KeyError:
                            pass
                        else:
                            if slp_input['qty'] != 'MINT_BATON':
                                print_error(
                                    "Non-baton SLP input found in MINT")
                                raise SlpNonMintInput(
                                    'MINT transaction contains non-baton SLP input.'
                                )
                            if slp_input['token_id'] != tid:
                                print_error("SLP check failed for MINT due to incorrect" \
                                                + " tokenId in baton")
                                raise SlpWrongTokenID('MINT transaction contains baton with incorrect' \
                                                        + ' token id.')
            elif slp_msg.transaction_type == 'GENESIS':
                # raise an Exception if:
                #   - [ ] NFT Child has quantity that is !== 1
                #   - [ ] Allow 0x01 or 0x81 qty == 0
                #   - [ ] NFT Child has minting baton vout specified
                #   - [ ] NFT Child does not grant exception for burning a coin in vin=0
                #   - [ ] NFT Child does not have a valid Type 0x81 coin in vin=0
                for txo in tx.inputs():
                    addr = txo['address']
                    prev_out = txo['prevout_hash']
                    prev_n = txo['prevout_n']
                    with wallet.lock:
                        try:
                            slp_input = wallet._slp_txo[addr][prev_out][prev_n]
                        except KeyError:
                            pass
                        else:
                            is_burn_allowed = False
                            if coins_to_burn:
                                for c in coins_to_burn:
                                    if c['prevout_hash'] == prev_out and c[
                                            'prevout_n'] == prev_n:
                                        is_burn_allowed = True
                                        c['is_in_txn'] = True

                            if not is_burn_allowed:
                                print_error("SLP check failed for SLP GENESIS transaction" \
                                                                + " which contains SLP inputs.")
                                raise NonSlpTransactionHasSlpInputs(
                                    'Genesis transaction contains unspecified SLP inputs.'
                                )

            if slp_msg.transaction_type in ['GENESIS', 'MINT']:
                # raise an Exception if:
                #   - [X] New baton outpoint is not P2PKH or P2SH type for Genesis or Mint
                #   - [X] Mint receiver has outpoint and is p2pkh or p2sh
                if slp_msg.op_return_fields['mint_baton_vout']:
                    try:
                        out = tx.outputs()[
                            slp_msg.op_return_fields['mint_baton_vout']]
                    except IndexError:
                        print_error(
                            "Transaction is missing baton vout for MINT operation"
                        )
                        raise MissingMintBatonOutpoint('Transaction is missing baton' \
                                                            + ' vout for MINT operation')
                    else:
                        if out[1].kind not in [
                                Address.ADDR_P2PKH, Address.ADDR_P2SH
                        ]:
                            print_error(
                                "Transaction baton receiver vout is not P2PKH or P2SH"
                            )
                            raise BadSlpOutpointType('Transaction baton receiver vout is not P2PKH' \
                                                        + ' or P2SH output type')

                    try:
                        out = tx.outputs()[1]
                    except IndexError:
                        print_error(
                            "Transaction is missing vout for MINT operation token receiver"
                        )
                        raise MissingTokenReceiverOutpoint('Transaction is missing vout for MINT' \
                                                                + ' operation token receiver')
                    else:
                        if out[1].kind not in [
                                Address.ADDR_P2PKH, Address.ADDR_P2SH
                        ]:
                            print_error(
                                "Transaction token receiver vout is not P2PKH or P2SH"
                            )
                            raise BadSlpOutpointType('Transaction token receiver vout is not P2PKH' \
                                                        + ' or P2SH output type')

        # return True if this check passes
        print_error("Final SLP check passed")
        return True
        '''