commit 4b1d8353040513f6a3e371b7385711eb9f146a70
parent 01dac92e19481690e31b06632c1b1833468cee0b
Author: SomberNight <somber.night@protonmail.com>
Date: Thu, 9 Apr 2020 18:00:35 +0200
wizard hww: scan devices fewer times and move away from GUI thread
Diffstat:
9 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/electrum/base_wizard.py b/electrum/base_wizard.py
@@ -348,7 +348,7 @@ class BaseWizard(Logger):
assert isinstance(self.plugin, HW_PluginBase)
devmgr = self.plugins.device_manager
try:
- self.plugin.setup_device(device_info, self, purpose)
+ client = self.plugin.setup_device(device_info, self, purpose)
except OSError as e:
self.show_error(_('We encountered an error while connecting to your device:')
+ '\n' + str(e) + '\n'
@@ -376,19 +376,18 @@ class BaseWizard(Logger):
self.show_error(str(e))
self.choose_hw_device(purpose, storage=storage)
return
+
if purpose == HWD_SETUP_NEW_WALLET:
def f(derivation, script_type):
derivation = normalize_bip32_derivation(derivation)
self.run('on_hw_derivation', name, device_info, derivation, script_type)
self.derivation_and_script_type_dialog(f)
elif purpose == HWD_SETUP_DECRYPT_WALLET:
- client = devmgr.client_by_id(device_info.device.id_)
password = client.get_password_for_storage_encryption()
try:
storage.decrypt(password)
except InvalidPassword:
# try to clear session so that user can type another passphrase
- client = devmgr.client_by_id(device_info.device.id_)
if hasattr(client, 'clear_session'): # FIXME not all hw wallet plugins have this
client.clear_session()
raise
@@ -435,7 +434,7 @@ class BaseWizard(Logger):
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_)
+ client = devmgr.client_by_id(device_info.device.id_, scan_now=False)
if not client: raise Exception("failed to find client for device id")
root_fingerprint = client.request_root_fingerprint_from_device()
label = client.label() # use this as device_info.label might be outdated!
diff --git a/electrum/plugin.py b/electrum/plugin.py
@@ -401,7 +401,7 @@ class DeviceMgr(ThreadJob):
def create_client(self, device: 'Device', handler: Optional['HardwareHandlerBase'],
plugin: 'HW_PluginBase') -> Optional['HardwareClientBase']:
# Get from cache first
- client = self.client_lookup(device.id_)
+ client = self._client_by_id(device.id_)
if client:
return client
client = plugin.create_client(device, handler)
@@ -437,7 +437,7 @@ class DeviceMgr(ThreadJob):
self._close_client(id_)
def _close_client(self, id_):
- client = self.client_lookup(id_)
+ client = self._client_by_id(id_)
self.clients.pop(client, None)
if client:
client.close()
@@ -446,19 +446,20 @@ class DeviceMgr(ThreadJob):
with self.lock:
self.xpub_ids[xpub] = id_
- def client_lookup(self, id_) -> Optional['HardwareClientBase']:
+ def _client_by_id(self, id_) -> Optional['HardwareClientBase']:
with self.lock:
for client, (path, client_id) in self.clients.items():
if client_id == id_:
return client
return None
- def client_by_id(self, id_) -> Optional['HardwareClientBase']:
+ def client_by_id(self, id_, *, scan_now: bool = True) -> Optional['HardwareClientBase']:
'''Returns a client for the device ID if one is registered. If
a device is wiped or in bootloader mode pairing is impossible;
in such cases we communicate by device ID and not wallet.'''
- self.scan_devices()
- return self.client_lookup(id_)
+ if scan_now:
+ self.scan_devices()
+ return self._client_by_id(id_)
@with_scan_lock
def client_for_keystore(self, plugin: 'HW_PluginBase', handler: Optional['HardwareHandlerBase'],
@@ -495,7 +496,7 @@ class DeviceMgr(ThreadJob):
def client_by_xpub(self, plugin: 'HW_PluginBase', xpub, handler: 'HardwareHandlerBase',
devices: Sequence['Device']) -> Optional['HardwareClientBase']:
_id = self.xpub_id(xpub)
- client = self.client_lookup(_id)
+ client = self._client_by_id(_id)
if client:
# An unpaired client might have another wallet's handler
# from a prior scan. Replace to fix dialog parenting.
@@ -511,7 +512,7 @@ class DeviceMgr(ThreadJob):
# The wallet has not been previously paired, so let the user
# choose an unpaired device and compare its first address.
xtype = bip32.xpub_type(xpub)
- client = self.client_lookup(info.device.id_)
+ client = self._client_by_id(info.device.id_)
if client and client.is_pairable():
# See comment above for same code
client.handler = handler
diff --git a/electrum/plugins/coldcard/coldcard.py b/electrum/plugins/coldcard/coldcard.py
@@ -524,6 +524,7 @@ class ColdcardPlugin(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)
+ return client
def get_xpub(self, device_id, derivation, xtype, wizard):
# this seems to be part of the pairing process only, not during normal ops?
diff --git a/electrum/plugins/digitalbitbox/digitalbitbox.py b/electrum/plugins/digitalbitbox/digitalbitbox.py
@@ -705,6 +705,7 @@ class DigitalBitboxPlugin(HW_PluginBase):
client.setupRunning = True
wizard.run_task_without_blocking_gui(
task=lambda: client.get_xpub("m/44'/0'", 'standard'))
+ return client
def is_mobile_paired(self):
diff --git a/electrum/plugins/hw_wallet/plugin.py b/electrum/plugins/hw_wallet/plugin.py
@@ -25,6 +25,7 @@
# SOFTWARE.
from typing import TYPE_CHECKING, Dict, List, Union, Tuple, Sequence, Optional, Type
+from functools import partial
from electrum.plugin import BasePlugin, hook, Device, DeviceMgr, DeviceInfo
from electrum.i18n import _
@@ -67,14 +68,15 @@ class HW_PluginBase(BasePlugin):
def scan_and_create_client_for_device(self, *, device_id: str, wizard: 'BaseWizard') -> 'HardwareClientBase':
devmgr = self.device_manager()
- client = devmgr.client_by_id(device_id)
+ client = wizard.run_task_without_blocking_gui(
+ task=partial(devmgr.client_by_id, device_id))
if client is None:
raise UserFacingException(_('Failed to create a client for this device.') + '\n' +
_('Make sure it is in the correct state.'))
client.handler = self.create_handler(wizard)
return client
- def setup_device(self, device_info: DeviceInfo, wizard: 'BaseWizard', purpose):
+ def setup_device(self, device_info: DeviceInfo, wizard: 'BaseWizard', purpose) -> 'HardwareClientBase':
"""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.
diff --git a/electrum/plugins/keepkey/keepkey.py b/electrum/plugins/keepkey/keepkey.py
@@ -283,6 +283,7 @@ class KeepKeyPlugin(HW_PluginBase):
wizard.run_task_without_blocking_gui(
task=lambda: client.get_xpub("m", 'standard'))
client.used()
+ return client
def get_xpub(self, device_id, derivation, xtype, wizard):
if xtype not in self.SUPPORTED_XTYPES:
diff --git a/electrum/plugins/ledger/ledger.py b/electrum/plugins/ledger/ledger.py
@@ -610,6 +610,7 @@ class LedgerPlugin(HW_PluginBase):
client = self.scan_and_create_client_for_device(device_id=device_id, wizard=wizard)
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
+ return client
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
@@ -257,6 +257,7 @@ class SafeTPlugin(HW_PluginBase):
wizard.run_task_without_blocking_gui(
task=lambda: client.get_xpub("m", 'standard'))
client.used()
+ return client
def get_xpub(self, device_id, derivation, xtype, wizard):
if xtype not in self.SUPPORTED_XTYPES:
diff --git a/electrum/plugins/trezor/trezor.py b/electrum/plugins/trezor/trezor.py
@@ -288,6 +288,7 @@ class TrezorPlugin(HW_PluginBase):
wizard.run_task_without_blocking_gui(
task=lambda: client.get_xpub('m', 'standard', creating=is_creating_wallet))
client.used()
+ return client
def get_xpub(self, device_id, derivation, xtype, wizard):
if xtype not in self.SUPPORTED_XTYPES: