From 371f55a0f922cf57196ae3d8d7c2fabc7a9f0f08 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Wed, 1 Apr 2020 21:05:19 +0200 Subject: [PATCH] hww: fix some threading issues in wizard fixes #3377 related: #6064 (passphrase dialog not rendered correctly) --- electrum/base_wizard.py | 8 ++++++++ electrum/gui/qt/installwizard.py | 20 +++++++++++++++++++ .../plugins/digitalbitbox/digitalbitbox.py | 3 ++- electrum/plugins/hw_wallet/plugin.py | 2 ++ electrum/plugins/keepkey/keepkey.py | 3 ++- electrum/plugins/ledger/ledger.py | 3 ++- electrum/plugins/safe_t/safe_t.py | 3 ++- electrum/plugins/trezor/trezor.py | 3 ++- 8 files changed, 40 insertions(+), 5 deletions(-) diff --git a/electrum/base_wizard.py b/electrum/base_wizard.py index a80638483..a6f898ec4 100644 --- a/electrum/base_wizard.py +++ b/electrum/base_wizard.py @@ -158,6 +158,13 @@ class BaseWizard(Logger): exc = e self.waiting_dialog(do_upgrade, _('Upgrading wallet format...'), on_finished=on_finished) + def run_task_without_blocking_gui(self, task, *, msg: str = None) -> Any: + """Perform a task in a thread without blocking the GUI. + Returns the result of 'task', or raises the same exception. + This method blocks until 'task' is finished. + """ + raise NotImplementedError() + def load_2fa(self): self.data['wallet_type'] = '2fa' self.data['use_trustedcoin'] = True @@ -421,6 +428,7 @@ class BaseWizard(Logger): def on_hw_derivation(self, name, device_info: 'DeviceInfo', derivation, xtype): from .keystore import hardware_keystore devmgr = self.plugins.device_manager + assert isinstance(self.plugin, HW_PluginBase) try: xpub = self.plugin.get_xpub(device_info.device.id_, derivation, xtype, self) client = devmgr.client_by_id(device_info.device.id_) diff --git a/electrum/gui/qt/installwizard.py b/electrum/gui/qt/installwizard.py index 3d139a0cc..e791ac296 100644 --- a/electrum/gui/qt/installwizard.py +++ b/electrum/gui/qt/installwizard.py @@ -529,6 +529,26 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard): if on_finished: on_finished() + def run_task_without_blocking_gui(self, task, *, msg=None): + assert self.gui_thread == threading.current_thread(), 'must be called from GUI thread' + if msg is None: + msg = _("Please wait...") + + exc = None # type: Optional[Exception] + res = None + def task_wrapper(): + nonlocal exc + nonlocal res + try: + task() + except Exception as e: + exc = e + self.waiting_dialog(task_wrapper, msg=msg) + if exc is None: + return res + else: + raise exc + @wizard_dialog def choice_dialog(self, title, message, choices, run_next): c_values = [x[0] for x in choices] diff --git a/electrum/plugins/digitalbitbox/digitalbitbox.py b/electrum/plugins/digitalbitbox/digitalbitbox.py index c801460fa..bf8294254 100644 --- a/electrum/plugins/digitalbitbox/digitalbitbox.py +++ b/electrum/plugins/digitalbitbox/digitalbitbox.py @@ -707,7 +707,8 @@ class DigitalBitboxPlugin(HW_PluginBase): client = self.scan_and_create_client_for_device(device_id=device_id, wizard=wizard) if purpose == HWD_SETUP_NEW_WALLET: client.setupRunning = True - client.get_xpub("m/44'/0'", 'standard') + wizard.run_task_without_blocking_gui( + task=lambda: client.get_xpub("m/44'/0'", 'standard')) def is_mobile_paired(self): diff --git a/electrum/plugins/hw_wallet/plugin.py b/electrum/plugins/hw_wallet/plugin.py index 14a2a846a..f1e28c6eb 100644 --- a/electrum/plugins/hw_wallet/plugin.py +++ b/electrum/plugins/hw_wallet/plugin.py @@ -78,6 +78,8 @@ class HW_PluginBase(BasePlugin): """Called when creating a new wallet or when using the device to decrypt an existing wallet. Select the device to use. If the device is uninitialized, go through the initialization process. + + Runs in GUI thread. """ raise NotImplementedError() diff --git a/electrum/plugins/keepkey/keepkey.py b/electrum/plugins/keepkey/keepkey.py index 07ff0889d..3c76ef09a 100644 --- a/electrum/plugins/keepkey/keepkey.py +++ b/electrum/plugins/keepkey/keepkey.py @@ -279,7 +279,8 @@ class KeepKeyPlugin(HW_PluginBase): client = self.scan_and_create_client_for_device(device_id=device_id, wizard=wizard) if not device_info.initialized: self.initialize_device(device_id, wizard, client.handler) - client.get_xpub('m', 'standard') + wizard.run_task_without_blocking_gui( + task=lambda: client.get_xpub("m", 'standard')) client.used() def get_xpub(self, device_id, derivation, xtype, wizard): diff --git a/electrum/plugins/ledger/ledger.py b/electrum/plugins/ledger/ledger.py index 79d8638f3..8e0040f5a 100644 --- a/electrum/plugins/ledger/ledger.py +++ b/electrum/plugins/ledger/ledger.py @@ -591,7 +591,8 @@ class LedgerPlugin(HW_PluginBase): def setup_device(self, device_info, wizard, purpose): device_id = device_info.device.id_ client = self.scan_and_create_client_for_device(device_id=device_id, wizard=wizard) - client.get_xpub("m/44'/0'", 'standard') # TODO replace by direct derivation once Nano S > 1.1 + wizard.run_task_without_blocking_gui( + task=lambda: client.get_xpub("m/44'/0'", 'standard')) # TODO replace by direct derivation once Nano S > 1.1 def get_xpub(self, device_id, derivation, xtype, wizard): if xtype not in self.SUPPORTED_XTYPES: diff --git a/electrum/plugins/safe_t/safe_t.py b/electrum/plugins/safe_t/safe_t.py index 6d4711f05..4bf6381e2 100644 --- a/electrum/plugins/safe_t/safe_t.py +++ b/electrum/plugins/safe_t/safe_t.py @@ -253,7 +253,8 @@ class SafeTPlugin(HW_PluginBase): client = self.scan_and_create_client_for_device(device_id=device_id, wizard=wizard) if not device_info.initialized: self.initialize_device(device_id, wizard, client.handler) - client.get_xpub('m', 'standard') + wizard.run_task_without_blocking_gui( + task=lambda: client.get_xpub("m", 'standard')) client.used() def get_xpub(self, device_id, derivation, xtype, wizard): diff --git a/electrum/plugins/trezor/trezor.py b/electrum/plugins/trezor/trezor.py index 2c49e621c..f32cc5227 100644 --- a/electrum/plugins/trezor/trezor.py +++ b/electrum/plugins/trezor/trezor.py @@ -280,7 +280,8 @@ class TrezorPlugin(HW_PluginBase): if not device_info.initialized: self.initialize_device(device_id, wizard, client.handler) is_creating_wallet = purpose == HWD_SETUP_NEW_WALLET - client.get_xpub('m', 'standard', creating=is_creating_wallet) + wizard.run_task_without_blocking_gui( + task=lambda: client.get_xpub('m', 'standard', creating=is_creating_wallet)) client.used() def get_xpub(self, device_id, derivation, xtype, wizard):