예제 #1
0
class ElectrumGui:
    def __init__(self, config, daemon, plugins):
        colorama.init()
        self.config = config
        self.network = network = daemon.network
        if config.get('tor_auto_on', True):
            if network:
                proxy_modifiable = config.is_modifiable('proxy')
                if not proxy_modifiable or not network.detect_tor_proxy():
                    print(network.TOR_WARN_MSG_TXT)
                    c = ''
                    while c != 'y':
                        c = input("Continue without Tor (y/n)?")
                        if c == 'n':
                            exit()
        storage = WalletStorage(config.get_wallet_path())
        if not storage.file_exists:
            print("Wallet not found. try 'electrum-dash create'")
            exit()
        if storage.is_encrypted():
            password = getpass.getpass('Password:'******'Can not open unfinished multisig wallet')
            exit()

        if getattr(storage, 'backup_message', None):
            print(f'{storage.backup_message}\n')
            input('Press Enter to continue...')

        self.done = 0
        self.last_balance = ""

        console_stderr_handler.setLevel(logging.CRITICAL)

        self.str_recipient = ""
        self.str_description = ""
        self.str_amount = ""
        self.str_fee = ""

        self.wallet = Wallet(db, storage, config=config)
        self.wallet.start_network(self.network)
        self.contacts = self.wallet.contacts

        util.register_callback(self.on_network,
                               ['wallet_updated', 'network_updated', 'banner'])
        self.commands = [_("[h] - displays this help text"), \
                         _("[i] - display transaction history"), \
                         _("[o] - enter payment order"), \
                         _("[p] - print stored payment order"), \
                         _("[s] - send stored payment order"), \
                         _("[r] - show own receipt addresses"), \
                         _("[c] - display contacts"), \
                         _("[b] - print server banner"), \
                         _("[M] - start PrivateSend mixing"),
                         _("[S] - stop PrivateSend mixing"),
                         _("[l][f][a] - print PrivateSend log (filtered/all)"),
                         _("[q] - quit") ]
        self.num_commands = len(self.commands)

    def on_network(self, event, *args):
        if event in ['wallet_updated', 'network_updated']:
            self.updated()
        elif event == 'banner':
            self.print_banner()

    def main_command(self):
        self.print_balance()
        c = input("enter command: ")
        if c == "h": self.print_commands()
        elif c == "i": self.print_history()
        elif c == "o": self.enter_order()
        elif c == "p": self.print_order()
        elif c == "s": self.send_order()
        elif c == "r": self.print_addresses()
        elif c == "c": self.print_contacts()
        elif c == "b": self.print_banner()
        elif c == "n": self.network_dialog()
        elif c == "e": self.settings_dialog()
        elif c == "M": self.start_mixing()
        elif c == "S": self.stop_mixing()
        elif c.startswith('l'): self.privatesend_log(c)
        elif c == "q": self.done = 1
        else: self.print_commands()

    def updated(self):
        s = self.get_balance()
        if s != self.last_balance:
            print(s)
        self.last_balance = s
        return True

    def print_commands(self):
        self.print_list(self.commands, "Available commands")

    def print_history(self):
        messages = []

        def_dip2 = not self.wallet.psman.unsupported
        show_dip2 = self.config.get('show_dip2_tx_type', def_dip2)
        if show_dip2:
            width = [20, 18, 22, 14, 14]
            wdelta = (80 - sum(width) - 5) // 3
            format_str = ("%" + "%d" % width[0] + "s" + "%" + "%d" % width[1] +
                          "s" + "%" + "%d" % (width[2] + wdelta) + "s" + "%" +
                          "%d" % (width[3] + wdelta) + "s" + "%" + "%d" %
                          (width[4] + wdelta) + "s")
        else:
            width = [20, 40, 14, 14]
            wdelta = (80 - sum(width) - 4) // 3
            format_str = ("%" + "%d" % width[0] + "s" + "%" + "%d" %
                          (width[1] + wdelta) + "s" + "%" + "%d" %
                          (width[2] + wdelta) + "s" + "%" + "%d" %
                          (width[3] + wdelta) + "s")
        for hist_item in reversed(self.wallet.get_history(config=self.config)):
            if hist_item.tx_mined_status.conf:
                timestamp = hist_item.tx_mined_status.timestamp
                try:
                    dttm = datetime.fromtimestamp(timestamp)
                    time_str = dttm.isoformat(' ')[:-3]
                except Exception:
                    time_str = "unknown"
            elif hist_item.islock:
                dttm = datetime.fromtimestamp(hist_item.islock)
                time_str = dttm.isoformat(' ')[:-3]
            else:
                time_str = 'unconfirmed'

            label = self.wallet.get_label_for_txid(hist_item.txid)
            if show_dip2:
                tx_type = hist_item.tx_type
                tx_type_name = SPEC_TX_NAMES.get(tx_type, str(tx_type))
                msg = format_str % (
                    time_str, tx_type_name, label,
                    format_satoshis(hist_item.delta, whitespaces=True),
                    format_satoshis(hist_item.balance, whitespaces=True))
            else:
                msg = format_str % (
                    time_str, label,
                    format_satoshis(hist_item.delta, whitespaces=True),
                    format_satoshis(hist_item.balance, whitespaces=True))
            messages.append(msg)
        if show_dip2:
            self.print_list(
                messages[::-1],
                format_str % (_("Date"), 'Type', _("Description"), _("Amount"),
                              _("Balance")))
        else:
            self.print_list(
                messages[::-1], format_str %
                (_("Date"), _("Description"), _("Amount"), _("Balance")))

    def print_balance(self):
        print(self.get_balance())

    def get_balance(self):
        if self.wallet.network.is_connected():
            if not self.wallet.up_to_date:
                msg = _("Synchronizing...")
            else:
                c, u, x = self.wallet.get_balance()
                msg = _("Balance") + ": %f  " % (Decimal(c) / COIN)
                if u:
                    msg += "  [%f unconfirmed]" % (Decimal(u) / COIN)
                if x:
                    msg += "  [%f unmatured]" % (Decimal(x) / COIN)
        else:
            msg = _("Not connected")

        return (msg)

    def print_contacts(self):
        messages = map(lambda x: "%20s   %45s " % (x[0], x[1][1]),
                       self.contacts.items())
        self.print_list(messages, "%19s  %25s " % ("Key", "Value"))

    def print_addresses(self):
        w = self.wallet
        addrs = w.get_addresses() + w.psman.get_addresses()
        messages = map(
            lambda addr: "%30s    %30s       " %
            (addr, self.wallet.get_label(addr)), addrs)
        self.print_list(messages, "%19s  %25s " % ("Address", "Label"))

    def print_order(self):
        print("send order to " + self.str_recipient + ", amount: " + self.str_amount \
              + "\nfee: " + self.str_fee + ", desc: " + self.str_description)

    def enter_order(self):
        self.str_recipient = input("Pay to: ")
        self.str_description = input("Description : ")
        self.str_amount = input("Amount: ")
        self.str_fee = input("Fee: ")

    def send_order(self):
        self.do_send()

    def print_banner(self):
        for i, x in enumerate(self.wallet.network.banner.split('\n')):
            print(x)

    def print_list(self, lst, firstline):
        lst = list(lst)
        self.maxpos = len(lst)
        if not self.maxpos: return
        print(firstline)
        for i in range(self.maxpos):
            msg = lst[i] if i < len(lst) else ""
            print(msg)

    def main(self):
        while self.done == 0:
            self.main_command()

    def do_send(self):
        if not is_address(self.str_recipient):
            print(_('Invalid Dash address'))
            return
        try:
            amount = int(Decimal(self.str_amount) * COIN)
        except Exception:
            print(_('Invalid Amount'))
            return
        try:
            fee = int(Decimal(self.str_fee) * COIN)
        except Exception:
            print(_('Invalid Fee'))
            return

        if self.wallet.has_password():
            password = self.password_dialog()
            if not password:
                return
        else:
            password = None

        c = ""
        while c != "y":
            c = input("ok to send (y/n)?")
            if c == "n": return

        try:
            tx = self.wallet.mktx(outputs=[
                PartialTxOutput.from_address_and_value(self.str_recipient,
                                                       amount)
            ],
                                  password=password,
                                  fee=fee)
        except Exception as e:
            print(repr(e))
            return

        if self.str_description:
            self.wallet.set_label(tx.txid(), self.str_description)

        print(_("Please wait..."))
        try:
            coro = self.wallet.psman.broadcast_transaction(tx)
            self.network.run_from_another_thread(coro)
        except TxBroadcastError as e:
            msg = e.get_message_for_gui()
            print(msg)
        except BestEffortRequestFailed as e:
            msg = repr(e)
            print(msg)
        else:
            print(_('Payment sent.'))
            #self.do_clear()
            #self.update_contacts_tab()

    def network_dialog(self):
        print(
            "use 'electrum-dash setconfig server/proxy' to change your network settings"
        )
        return True

    def settings_dialog(self):
        print("use 'electrum-dash setconfig' to change your settings")
        return True

    def start_mixing(self):
        if self.wallet.has_password():
            password = self.password_dialog()
            if not password:
                return
        else:
            password = None
        self.wallet.psman.start_mixing(password)
        return True

    def stop_mixing(self):
        self.wallet.psman.stop_mixing()

    def privatesend_log(self, cmd):
        try:
            cmd = cmd.lower()
            subcmds = cmd[1:].split()
            print_filtered = True if 'f' in subcmds else False
            print_tail = True if 'a' not in subcmds else False
            log_handler = self.wallet.psman.log_handler
            p_from = log_handler.tail - 20 if print_tail else log_handler.head
            p_from = max(p_from, log_handler.head)
            for i in range(p_from, log_handler.tail):
                log_line = ''
                log_record = log_handler.log.get(i, None)
                if log_record:
                    created = time.localtime(log_record.created)
                    created = time.strftime('%x %X', created)
                    log_line = f'{created} {log_record.msg}'
                    if print_filtered:
                        log_line = filter_log_line(log_line)
                    if log_record.subcat == PSLogSubCat.WflDone:
                        log_line = f'{Fore.BLUE}{log_line}{Style.RESET_ALL}'
                    elif log_record.subcat == PSLogSubCat.WflOk:
                        log_line = f'{Fore.GREEN}{log_line}{Style.RESET_ALL}'
                    elif log_record.subcat == PSLogSubCat.WflErr:
                        log_line = f'{Fore.RED}{log_line}{Style.RESET_ALL}'
                print(log_line)
        except:
            import traceback
            traceback.print_exc()

    def password_dialog(self):
        return getpass.getpass()

#   XXX unused

    def run_receive_tab(self, c):
        #if c == 10:
        #    out = self.run_popup('Address', ["Edit label", "Freeze", "Prioritize"])
        return

    def run_contacts_tab(self, c):
        pass