From df82d9c017ecf6a61f2ba43a03e0c12bd389f184 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Thu, 20 Aug 2020 17:38:45 +0200 Subject: [PATCH] bip39 scan: follow-up prev - use logger - allow qt dialog to be GC-ed - (trivial) add typing; minor formatting --- electrum/base_wizard.py | 4 ++-- electrum/bip39_recovery.py | 17 +++++++++++++---- electrum/gui/qt/bip39_recovery_dialog.py | 13 +++++++++++-- electrum/gui/qt/installwizard.py | 15 ++++++++++++--- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/electrum/base_wizard.py b/electrum/base_wizard.py index f5d12bef6..fa643873f 100644 --- a/electrum/base_wizard.py +++ b/electrum/base_wizard.py @@ -404,7 +404,7 @@ class BaseWizard(Logger): else: raise Exception('unknown purpose: %s' % purpose) - def derivation_and_script_type_dialog(self, f, get_account_xpub=None): + def derivation_and_script_type_dialog(self, f, *, get_account_xpub=None): message1 = _('Choose the type of addresses in your wallet.') message2 = ' '.join([ _('You can override the suggested derivation path.'), @@ -516,7 +516,7 @@ class BaseWizard(Logger): account_node = root_node.subkey_at_private_derivation(account_path) account_xpub = account_node.to_xpub() return account_xpub - self.derivation_and_script_type_dialog(f, get_account_xpub) + self.derivation_and_script_type_dialog(f, get_account_xpub=get_account_xpub) def create_keystore(self, seed, passphrase): k = keystore.from_seed(seed, passphrase, self.wallet_type == 'multisig') diff --git a/electrum/bip39_recovery.py b/electrum/bip39_recovery.py index 42bfdc581..b0cd2f902 100644 --- a/electrum/bip39_recovery.py +++ b/electrum/bip39_recovery.py @@ -2,6 +2,8 @@ # Distributed under the MIT software license, see the accompanying # file LICENCE or http://www.opensource.org/licenses/mit-license.php +from typing import TYPE_CHECKING + from aiorpcx import TaskGroup from . import bitcoin @@ -10,7 +12,11 @@ from .bip32 import BIP32_PRIME, BIP32Node from .bip32 import convert_bip32_path_to_list_of_uint32 as bip32_str_to_ints from .bip32 import convert_bip32_intpath_to_strpath as bip32_ints_to_str -async def account_discovery(network, get_account_xpub): +if TYPE_CHECKING: + from .network import Network + + +async def account_discovery(network: 'Network', get_account_xpub): async with TaskGroup() as group: account_scan_tasks = [] for wallet_format in BIP39_WALLET_FORMATS: @@ -21,13 +27,14 @@ async def account_discovery(network, get_account_xpub): active_accounts.extend(task.result()) return active_accounts -async def scan_for_active_accounts(network, get_account_xpub, wallet_format): + +async def scan_for_active_accounts(network: 'Network', get_account_xpub, wallet_format): active_accounts = [] account_path = bip32_str_to_ints(wallet_format["derivation_path"]) while True: account_xpub = get_account_xpub(account_path) account_node = BIP32Node.from_xkey(account_xpub) - has_history = await account_has_history(network, account_node, wallet_format["script_type"]); + has_history = await account_has_history(network, account_node, wallet_format["script_type"]) if has_history: account = format_account(wallet_format, account_path) active_accounts.append(account) @@ -36,7 +43,8 @@ async def scan_for_active_accounts(network, get_account_xpub, wallet_format): account_path[-1] = account_path[-1] + 1 return active_accounts -async def account_has_history(network, account_node, script_type): + +async def account_has_history(network: 'Network', account_node: BIP32Node, script_type: str) -> bool: gap_limit = 20 async with TaskGroup() as group: get_history_tasks = [] @@ -54,6 +62,7 @@ async def account_has_history(network, account_node, script_type): return True return False + def format_account(wallet_format, account_path): description = wallet_format["description"] if wallet_format["iterate_accounts"]: diff --git a/electrum/gui/qt/bip39_recovery_dialog.py b/electrum/gui/qt/bip39_recovery_dialog.py index 11b658ec7..cf8cfd1eb 100644 --- a/electrum/gui/qt/bip39_recovery_dialog.py +++ b/electrum/gui/qt/bip39_recovery_dialog.py @@ -8,9 +8,14 @@ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QGridLayout, QLabel, QListWidg from electrum.i18n import _ from electrum.network import Network from electrum.bip39_recovery import account_discovery +from electrum.logging import get_logger from .util import WindowModalDialog, MessageBoxMixin, TaskThread, Buttons, CancelButton, OkButton + +_logger = get_logger(__name__) + + class Bip39RecoveryDialog(WindowModalDialog): def __init__(self, parent: QWidget, get_account_xpub, on_account_select): self.get_account_xpub = get_account_xpub @@ -25,11 +30,15 @@ class Bip39RecoveryDialog(WindowModalDialog): self.ok_button.clicked.connect(self.on_ok_button_click) self.ok_button.setEnabled(False) vbox.addLayout(Buttons(CancelButton(self), self.ok_button)) + self.finished.connect(self.on_finished) self.show() self.thread = TaskThread(self) self.thread.finished.connect(self.deleteLater) # see #3956 self.thread.add(self.recovery, self.on_recovery_success, None, self.on_recovery_error) + def on_finished(self): + self.thread.stop() + def on_ok_button_click(self): item = self.list.currentItem() account = item.data(Qt.UserRole) @@ -54,10 +63,10 @@ class Bip39RecoveryDialog(WindowModalDialog): self.list.clicked.connect(lambda: self.ok_button.setEnabled(True)) self.content.addWidget(self.list) - def on_recovery_error(self, error): + def on_recovery_error(self, exc_info): self.clear_content() self.content.addWidget(QLabel(_('Error: Account discovery failed.'))) - print(error) + _logger.error(f"recovery error", exc_info=exc_info) def clear_content(self): for i in reversed(range(self.content.count())): diff --git a/electrum/gui/qt/installwizard.py b/electrum/gui/qt/installwizard.py index 02f33207f..bd3ac4b4a 100644 --- a/electrum/gui/qt/installwizard.py +++ b/electrum/gui/qt/installwizard.py @@ -604,9 +604,18 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard): return clayout.selected_index() @wizard_dialog - def derivation_and_script_type_gui_specific_dialog(self, title: str, message1: str, choices: List[Tuple[str, str, str]], - message2: str, test_text: Callable[[str], int], - run_next, default_choice_idx: int=0, get_account_xpub=None) -> Tuple[str, str]: + def derivation_and_script_type_gui_specific_dialog( + self, + *, + title: str, + message1: str, + choices: List[Tuple[str, str, str]], + message2: str, + test_text: Callable[[str], int], + run_next, + default_choice_idx: int = 0, + get_account_xpub=None + ) -> Tuple[str, str]: vbox = QVBoxLayout() if get_account_xpub: