Browse Source

wizard hww: scan devices fewer times and move away from GUI thread

hard-fail-on-bad-server-string
SomberNight 5 years ago
parent
commit
4b1d835304
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 7
      electrum/base_wizard.py
  2. 15
      electrum/plugin.py
  3. 1
      electrum/plugins/coldcard/coldcard.py
  4. 1
      electrum/plugins/digitalbitbox/digitalbitbox.py
  5. 6
      electrum/plugins/hw_wallet/plugin.py
  6. 1
      electrum/plugins/keepkey/keepkey.py
  7. 1
      electrum/plugins/ledger/ledger.py
  8. 1
      electrum/plugins/safe_t/safe_t.py
  9. 1
      electrum/plugins/trezor/trezor.py

7
electrum/base_wizard.py

@ -348,7 +348,7 @@ class BaseWizard(Logger):
assert isinstance(self.plugin, HW_PluginBase) assert isinstance(self.plugin, HW_PluginBase)
devmgr = self.plugins.device_manager devmgr = self.plugins.device_manager
try: try:
self.plugin.setup_device(device_info, self, purpose) client = self.plugin.setup_device(device_info, self, purpose)
except OSError as e: except OSError as e:
self.show_error(_('We encountered an error while connecting to your device:') self.show_error(_('We encountered an error while connecting to your device:')
+ '\n' + str(e) + '\n' + '\n' + str(e) + '\n'
@ -376,19 +376,18 @@ class BaseWizard(Logger):
self.show_error(str(e)) self.show_error(str(e))
self.choose_hw_device(purpose, storage=storage) self.choose_hw_device(purpose, storage=storage)
return return
if purpose == HWD_SETUP_NEW_WALLET: if purpose == HWD_SETUP_NEW_WALLET:
def f(derivation, script_type): def f(derivation, script_type):
derivation = normalize_bip32_derivation(derivation) derivation = normalize_bip32_derivation(derivation)
self.run('on_hw_derivation', name, device_info, derivation, script_type) self.run('on_hw_derivation', name, device_info, derivation, script_type)
self.derivation_and_script_type_dialog(f) self.derivation_and_script_type_dialog(f)
elif purpose == HWD_SETUP_DECRYPT_WALLET: elif purpose == HWD_SETUP_DECRYPT_WALLET:
client = devmgr.client_by_id(device_info.device.id_)
password = client.get_password_for_storage_encryption() password = client.get_password_for_storage_encryption()
try: try:
storage.decrypt(password) storage.decrypt(password)
except InvalidPassword: except InvalidPassword:
# try to clear session so that user can type another passphrase # 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 if hasattr(client, 'clear_session'): # FIXME not all hw wallet plugins have this
client.clear_session() client.clear_session()
raise raise
@ -435,7 +434,7 @@ class BaseWizard(Logger):
assert isinstance(self.plugin, HW_PluginBase) assert isinstance(self.plugin, HW_PluginBase)
try: try:
xpub = self.plugin.get_xpub(device_info.device.id_, derivation, xtype, self) 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") if not client: raise Exception("failed to find client for device id")
root_fingerprint = client.request_root_fingerprint_from_device() root_fingerprint = client.request_root_fingerprint_from_device()
label = client.label() # use this as device_info.label might be outdated! label = client.label() # use this as device_info.label might be outdated!

15
electrum/plugin.py

@ -401,7 +401,7 @@ class DeviceMgr(ThreadJob):
def create_client(self, device: 'Device', handler: Optional['HardwareHandlerBase'], def create_client(self, device: 'Device', handler: Optional['HardwareHandlerBase'],
plugin: 'HW_PluginBase') -> Optional['HardwareClientBase']: plugin: 'HW_PluginBase') -> Optional['HardwareClientBase']:
# Get from cache first # Get from cache first
client = self.client_lookup(device.id_) client = self._client_by_id(device.id_)
if client: if client:
return client return client
client = plugin.create_client(device, handler) client = plugin.create_client(device, handler)
@ -437,7 +437,7 @@ class DeviceMgr(ThreadJob):
self._close_client(id_) self._close_client(id_)
def _close_client(self, id_): def _close_client(self, id_):
client = self.client_lookup(id_) client = self._client_by_id(id_)
self.clients.pop(client, None) self.clients.pop(client, None)
if client: if client:
client.close() client.close()
@ -446,19 +446,20 @@ class DeviceMgr(ThreadJob):
with self.lock: with self.lock:
self.xpub_ids[xpub] = id_ self.xpub_ids[xpub] = id_
def client_lookup(self, id_) -> Optional['HardwareClientBase']: def _client_by_id(self, id_) -> Optional['HardwareClientBase']:
with self.lock: with self.lock:
for client, (path, client_id) in self.clients.items(): for client, (path, client_id) in self.clients.items():
if client_id == id_: if client_id == id_:
return client return client
return None 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 '''Returns a client for the device ID if one is registered. If
a device is wiped or in bootloader mode pairing is impossible; a device is wiped or in bootloader mode pairing is impossible;
in such cases we communicate by device ID and not wallet.''' in such cases we communicate by device ID and not wallet.'''
if scan_now:
self.scan_devices() self.scan_devices()
return self.client_lookup(id_) return self._client_by_id(id_)
@with_scan_lock @with_scan_lock
def client_for_keystore(self, plugin: 'HW_PluginBase', handler: Optional['HardwareHandlerBase'], 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', def client_by_xpub(self, plugin: 'HW_PluginBase', xpub, handler: 'HardwareHandlerBase',
devices: Sequence['Device']) -> Optional['HardwareClientBase']: devices: Sequence['Device']) -> Optional['HardwareClientBase']:
_id = self.xpub_id(xpub) _id = self.xpub_id(xpub)
client = self.client_lookup(_id) client = self._client_by_id(_id)
if client: if client:
# An unpaired client might have another wallet's handler # An unpaired client might have another wallet's handler
# from a prior scan. Replace to fix dialog parenting. # 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 # The wallet has not been previously paired, so let the user
# choose an unpaired device and compare its first address. # choose an unpaired device and compare its first address.
xtype = bip32.xpub_type(xpub) 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(): if client and client.is_pairable():
# See comment above for same code # See comment above for same code
client.handler = handler client.handler = handler

1
electrum/plugins/coldcard/coldcard.py

@ -524,6 +524,7 @@ class ColdcardPlugin(HW_PluginBase):
def setup_device(self, device_info, wizard, purpose): def setup_device(self, device_info, wizard, purpose):
device_id = device_info.device.id_ device_id = device_info.device.id_
client = self.scan_and_create_client_for_device(device_id=device_id, wizard=wizard) 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): def get_xpub(self, device_id, derivation, xtype, wizard):
# this seems to be part of the pairing process only, not during normal ops? # this seems to be part of the pairing process only, not during normal ops?

1
electrum/plugins/digitalbitbox/digitalbitbox.py

@ -705,6 +705,7 @@ class DigitalBitboxPlugin(HW_PluginBase):
client.setupRunning = True client.setupRunning = True
wizard.run_task_without_blocking_gui( wizard.run_task_without_blocking_gui(
task=lambda: client.get_xpub("m/44'/0'", 'standard')) task=lambda: client.get_xpub("m/44'/0'", 'standard'))
return client
def is_mobile_paired(self): def is_mobile_paired(self):

6
electrum/plugins/hw_wallet/plugin.py

@ -25,6 +25,7 @@
# SOFTWARE. # SOFTWARE.
from typing import TYPE_CHECKING, Dict, List, Union, Tuple, Sequence, Optional, Type 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.plugin import BasePlugin, hook, Device, DeviceMgr, DeviceInfo
from electrum.i18n import _ 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': def scan_and_create_client_for_device(self, *, device_id: str, wizard: 'BaseWizard') -> 'HardwareClientBase':
devmgr = self.device_manager() 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: if client is None:
raise UserFacingException(_('Failed to create a client for this device.') + '\n' + raise UserFacingException(_('Failed to create a client for this device.') + '\n' +
_('Make sure it is in the correct state.')) _('Make sure it is in the correct state.'))
client.handler = self.create_handler(wizard) client.handler = self.create_handler(wizard)
return client 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 """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 an existing wallet. Select the device to use. If the device is
uninitialized, go through the initialization process. uninitialized, go through the initialization process.

1
electrum/plugins/keepkey/keepkey.py

@ -283,6 +283,7 @@ class KeepKeyPlugin(HW_PluginBase):
wizard.run_task_without_blocking_gui( wizard.run_task_without_blocking_gui(
task=lambda: client.get_xpub("m", 'standard')) task=lambda: client.get_xpub("m", 'standard'))
client.used() client.used()
return client
def get_xpub(self, device_id, derivation, xtype, wizard): def get_xpub(self, device_id, derivation, xtype, wizard):
if xtype not in self.SUPPORTED_XTYPES: if xtype not in self.SUPPORTED_XTYPES:

1
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) client = self.scan_and_create_client_for_device(device_id=device_id, wizard=wizard)
wizard.run_task_without_blocking_gui( 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 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): def get_xpub(self, device_id, derivation, xtype, wizard):
if xtype not in self.SUPPORTED_XTYPES: if xtype not in self.SUPPORTED_XTYPES:

1
electrum/plugins/safe_t/safe_t.py

@ -257,6 +257,7 @@ class SafeTPlugin(HW_PluginBase):
wizard.run_task_without_blocking_gui( wizard.run_task_without_blocking_gui(
task=lambda: client.get_xpub("m", 'standard')) task=lambda: client.get_xpub("m", 'standard'))
client.used() client.used()
return client
def get_xpub(self, device_id, derivation, xtype, wizard): def get_xpub(self, device_id, derivation, xtype, wizard):
if xtype not in self.SUPPORTED_XTYPES: if xtype not in self.SUPPORTED_XTYPES:

1
electrum/plugins/trezor/trezor.py

@ -288,6 +288,7 @@ class TrezorPlugin(HW_PluginBase):
wizard.run_task_without_blocking_gui( wizard.run_task_without_blocking_gui(
task=lambda: client.get_xpub('m', 'standard', creating=is_creating_wallet)) task=lambda: client.get_xpub('m', 'standard', creating=is_creating_wallet))
client.used() client.used()
return client
def get_xpub(self, device_id, derivation, xtype, wizard): def get_xpub(self, device_id, derivation, xtype, wizard):
if xtype not in self.SUPPORTED_XTYPES: if xtype not in self.SUPPORTED_XTYPES:

Loading…
Cancel
Save