diff --git a/electrum/base_wizard.py b/electrum/base_wizard.py index c377efdfe..764cd30e1 100644 --- a/electrum/base_wizard.py +++ b/electrum/base_wizard.py @@ -199,7 +199,7 @@ class BaseWizard(object): self.choice_dialog(title=title, message=message, choices=choices, run_next=self.run) def import_addresses_or_keys(self): - v = lambda x: keystore.is_address_list(x) or keystore.is_private_key_list(x) + v = lambda x: keystore.is_address_list(x) or keystore.is_private_key_list(x, raise_on_error=True) title = _("Import Bitcoin Addresses") message = _("Enter a list of Bitcoin addresses (this will create a watching-only wallet), or a list of private keys.") self.add_xpub_dialog(title=title, message=message, run_next=self.on_import, diff --git a/electrum/bitcoin.py b/electrum/bitcoin.py index 39f943152..d39c45bc6 100644 --- a/electrum/bitcoin.py +++ b/electrum/bitcoin.py @@ -615,11 +615,13 @@ def is_address(addr: str, *, net=None) -> bool: or is_b58_address(addr, net=net) -def is_private_key(key: str) -> bool: +def is_private_key(key: str, *, raise_on_error=False) -> bool: try: - k = deserialize_privkey(key) - return k is not False - except: + deserialize_privkey(key) + return True + except BaseException as e: + if raise_on_error: + raise return False diff --git a/electrum/gui/kivy/uix/dialogs/installwizard.py b/electrum/gui/kivy/uix/dialogs/installwizard.py index 98223e070..3a577b0e1 100644 --- a/electrum/gui/kivy/uix/dialogs/installwizard.py +++ b/electrum/gui/kivy/uix/dialogs/installwizard.py @@ -899,7 +899,12 @@ class AddXpubDialog(WizardDialog): def __init__(self, wizard, **kwargs): WizardDialog.__init__(self, wizard, **kwargs) - self.is_valid = kwargs['is_valid'] + def is_valid(x): + try: + return kwargs['is_valid'](x) + except: + return False + self.is_valid = is_valid self.title = kwargs['title'] self.message = kwargs['message'] self.allow_multi = kwargs.get('allow_multi', False) diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index 5a462d951..0df098381 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -2669,14 +2669,22 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): if bitcoin.is_address(addr): return addr - def get_pk(): + def get_pk(*, raise_on_error=False): text = str(keys_e.toPlainText()) - return keystore.get_private_keys(text) + return keystore.get_private_keys(text, raise_on_error=raise_on_error) - f = lambda: button.setEnabled(get_address() is not None and get_pk() is not None) + def on_edit(): + valid_privkeys = False + try: + valid_privkeys = get_pk(raise_on_error=True) is not None + except Exception as e: + button.setToolTip(f'{_("Error")}: {str(e)}') + else: + button.setToolTip('') + button.setEnabled(get_address() is not None and valid_privkeys) on_address = lambda text: address_e.setStyleSheet((ColorScheme.DEFAULT if get_address() else ColorScheme.RED).as_stylesheet()) - keys_e.textChanged.connect(f) - address_e.textChanged.connect(f) + keys_e.textChanged.connect(on_edit) + address_e.textChanged.connect(on_edit) address_e.textChanged.connect(on_address) on_address(str(address_e.text())) if not d.exec_(): diff --git a/electrum/gui/qt/seed_dialog.py b/electrum/gui/qt/seed_dialog.py index 4b8b6f133..f2b559fa8 100644 --- a/electrum/gui/qt/seed_dialog.py +++ b/electrum/gui/qt/seed_dialog.py @@ -198,8 +198,14 @@ class KeysLayout(QVBoxLayout): return self.text_e.text() def on_edit(self): - b = self.is_valid(self.get_text()) - self.parent.next_button.setEnabled(b) + valid = False + try: + valid = self.is_valid(self.get_text()) + except Exception as e: + self.parent.next_button.setToolTip(f'{_("Error")}: {str(e)}') + else: + self.parent.next_button.setToolTip('') + self.parent.next_button.setEnabled(valid) class SeedDialog(WindowModalDialog): diff --git a/electrum/keystore.py b/electrum/keystore.py index 641f45dcb..b6e6320c6 100644 --- a/electrum/keystore.py +++ b/electrum/keystore.py @@ -752,19 +752,21 @@ def is_address_list(text): return bool(parts) and all(bitcoin.is_address(x) for x in parts) -def get_private_keys(text, *, allow_spaces_inside_key=True): +def get_private_keys(text, *, allow_spaces_inside_key=True, raise_on_error=False): if allow_spaces_inside_key: # see #1612 parts = text.split('\n') parts = map(lambda x: ''.join(x.split()), parts) parts = list(filter(bool, parts)) else: parts = text.split() - if bool(parts) and all(bitcoin.is_private_key(x) for x in parts): + if bool(parts) and all(bitcoin.is_private_key(x, raise_on_error=raise_on_error) for x in parts): return parts -def is_private_key_list(text, *, allow_spaces_inside_key=True): - return bool(get_private_keys(text, allow_spaces_inside_key=allow_spaces_inside_key)) +def is_private_key_list(text, *, allow_spaces_inside_key=True, raise_on_error=False): + return bool(get_private_keys(text, + allow_spaces_inside_key=allow_spaces_inside_key, + raise_on_error=raise_on_error)) is_mpk = lambda x: is_old_mpk(x) or is_xpub(x) diff --git a/electrum/wallet.py b/electrum/wallet.py index 74c3b4237..e01b3cfbe 100644 --- a/electrum/wallet.py +++ b/electrum/wallet.py @@ -1472,8 +1472,8 @@ class Imported_Wallet(Simple_Wallet): for key in keys: try: txin_type, pubkey = self.keystore.import_privkey(key, password) - except Exception: - bad_keys.append((key, _('invalid private key'))) + except Exception as e: + bad_keys.append((key, _('invalid private key') + f': {e}')) continue if txin_type not in ('p2pkh', 'p2wpkh', 'p2wpkh-p2sh'): bad_keys.append((key, _('not implemented type') + f': {txin_type}'))