hw wallets: generalise 'minimum_library' for those that provide a version number
This commit is contained in:
@@ -240,7 +240,8 @@ class BaseWizard(object):
|
|||||||
u = devmgr.unpaired_device_infos(None, plugin, devices=scanned_devices)
|
u = devmgr.unpaired_device_infos(None, plugin, devices=scanned_devices)
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
devmgr.print_error('error getting device infos for {}: {}'.format(name, e))
|
devmgr.print_error('error getting device infos for {}: {}'.format(name, e))
|
||||||
debug_msg += ' {}:\n {}\n'.format(plugin.name, e)
|
indented_error_msg = ' '.join([''] + str(e).splitlines(keepends=True))
|
||||||
|
debug_msg += ' {}:\n{}\n'.format(plugin.name, indented_error_msg)
|
||||||
continue
|
continue
|
||||||
devices += list(map(lambda x: (name, x), u))
|
devices += list(map(lambda x: (name, x), u))
|
||||||
if not debug_msg:
|
if not debug_msg:
|
||||||
|
|||||||
@@ -457,7 +457,8 @@ class DeviceMgr(ThreadJob, PrintError):
|
|||||||
'''Returns a list of DeviceInfo objects: one for each connected,
|
'''Returns a list of DeviceInfo objects: one for each connected,
|
||||||
unpaired device accepted by the plugin.'''
|
unpaired device accepted by the plugin.'''
|
||||||
if not plugin.libraries_available:
|
if not plugin.libraries_available:
|
||||||
raise Exception('Missing libraries for {}'.format(plugin.name))
|
message = plugin.get_library_not_available_message()
|
||||||
|
raise Exception(message)
|
||||||
if devices is None:
|
if devices is None:
|
||||||
devices = self.scan_devices()
|
devices = self.scan_devices()
|
||||||
devices = [dev for dev in devices if not self.xpub_by_id(dev.id_)]
|
devices = [dev for dev in devices if not self.xpub_by_id(dev.id_)]
|
||||||
|
|||||||
@@ -585,8 +585,8 @@ class Coldcard_KeyStore(Hardware_KeyStore):
|
|||||||
|
|
||||||
|
|
||||||
class ColdcardPlugin(HW_PluginBase):
|
class ColdcardPlugin(HW_PluginBase):
|
||||||
libraries_available = requirements_ok
|
|
||||||
keystore_class = Coldcard_KeyStore
|
keystore_class = Coldcard_KeyStore
|
||||||
|
minimum_library = (0, 7, 2)
|
||||||
client = None
|
client = None
|
||||||
|
|
||||||
DEVICE_IDS = [
|
DEVICE_IDS = [
|
||||||
@@ -600,10 +600,19 @@ class ColdcardPlugin(HW_PluginBase):
|
|||||||
def __init__(self, parent, config, name):
|
def __init__(self, parent, config, name):
|
||||||
HW_PluginBase.__init__(self, parent, config, name)
|
HW_PluginBase.__init__(self, parent, config, name)
|
||||||
|
|
||||||
if self.libraries_available:
|
self.libraries_available = self.check_libraries_available() and requirements_ok
|
||||||
self.device_manager().register_devices(self.DEVICE_IDS)
|
if not self.libraries_available:
|
||||||
|
return
|
||||||
|
|
||||||
self.device_manager().register_enumerate_func(self.detect_simulator)
|
self.device_manager().register_devices(self.DEVICE_IDS)
|
||||||
|
self.device_manager().register_enumerate_func(self.detect_simulator)
|
||||||
|
|
||||||
|
def get_library_version(self):
|
||||||
|
import ckcc
|
||||||
|
try:
|
||||||
|
return ckcc.__version__
|
||||||
|
except AttributeError:
|
||||||
|
return 'unknown'
|
||||||
|
|
||||||
def detect_simulator(self):
|
def detect_simulator(self):
|
||||||
# if there is a simulator running on this machine,
|
# if there is a simulator running on this machine,
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
from electrum.plugin import BasePlugin, hook
|
from electrum.plugin import BasePlugin, hook
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.bitcoin import is_address, TYPE_SCRIPT
|
from electrum.bitcoin import is_address, TYPE_SCRIPT
|
||||||
from electrum.util import bfh
|
from electrum.util import bfh, versiontuple
|
||||||
from electrum.transaction import opcodes, TxOutput
|
from electrum.transaction import opcodes, TxOutput
|
||||||
|
|
||||||
|
|
||||||
@@ -38,6 +38,8 @@ class HW_PluginBase(BasePlugin):
|
|||||||
# libraries_available, libraries_URL, minimum_firmware,
|
# libraries_available, libraries_URL, minimum_firmware,
|
||||||
# wallet_class, ckd_public, types, HidTransport
|
# wallet_class, ckd_public, types, HidTransport
|
||||||
|
|
||||||
|
minimum_library = (0, )
|
||||||
|
|
||||||
def __init__(self, parent, config, name):
|
def __init__(self, parent, config, name):
|
||||||
BasePlugin.__init__(self, parent, config, name)
|
BasePlugin.__init__(self, parent, config, name)
|
||||||
self.device = self.keystore_class.device
|
self.device = self.keystore_class.device
|
||||||
@@ -78,6 +80,38 @@ class HW_PluginBase(BasePlugin):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def get_library_version(self) -> str:
|
||||||
|
"""Returns the version of the 3rd party python library
|
||||||
|
for the hw wallet. For example '0.9.0'
|
||||||
|
|
||||||
|
Returns 'unknown' if library is found but cannot determine version.
|
||||||
|
Raises 'ImportError' if library is not found.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def check_libraries_available(self) -> bool:
|
||||||
|
try:
|
||||||
|
library_version = self.get_library_version()
|
||||||
|
except ImportError:
|
||||||
|
return False
|
||||||
|
if library_version == 'unknown' or \
|
||||||
|
versiontuple(library_version) < self.minimum_library:
|
||||||
|
self.libraries_available_message = (
|
||||||
|
_("Library version for '{}' is too old.").format(self.name)
|
||||||
|
+ '\nInstalled: {}, Needed: {}'
|
||||||
|
.format(library_version, self.minimum_library))
|
||||||
|
self.print_stderr(self.libraries_available_message)
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_library_not_available_message(self) -> str:
|
||||||
|
if hasattr(self, 'libraries_available_message'):
|
||||||
|
message = self.libraries_available_message
|
||||||
|
else:
|
||||||
|
message = _("Missing libraries for {}.").format(self.name)
|
||||||
|
message += '\n' + _("Make sure you install it with python3")
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
def is_any_tx_output_on_change_branch(tx):
|
def is_any_tx_output_on_change_branch(tx):
|
||||||
if not hasattr(tx, 'output_info'):
|
if not hasattr(tx, 'output_info'):
|
||||||
|
|||||||
@@ -189,11 +189,7 @@ class QtPluginBase(object):
|
|||||||
if not isinstance(keystore, self.keystore_class):
|
if not isinstance(keystore, self.keystore_class):
|
||||||
continue
|
continue
|
||||||
if not self.libraries_available:
|
if not self.libraries_available:
|
||||||
if hasattr(self, 'libraries_available_message'):
|
message = keystore.plugin.get_library_not_available_message()
|
||||||
message = self.libraries_available_message + '\n'
|
|
||||||
else:
|
|
||||||
message = _("Cannot find python library for") + " '%s'.\n" % self.name
|
|
||||||
message += _("Make sure you install it with python3")
|
|
||||||
window.show_error(message)
|
window.show_error(message)
|
||||||
return
|
return
|
||||||
tooltip = self.device + '\n' + (keystore.label or 'unnamed')
|
tooltip = self.device + '\n' + (keystore.label or 'unnamed')
|
||||||
|
|||||||
@@ -82,25 +82,8 @@ class SafeTPlugin(HW_PluginBase):
|
|||||||
def __init__(self, parent, config, name):
|
def __init__(self, parent, config, name):
|
||||||
HW_PluginBase.__init__(self, parent, config, name)
|
HW_PluginBase.__init__(self, parent, config, name)
|
||||||
|
|
||||||
try:
|
self.libraries_available = self.check_libraries_available()
|
||||||
# Minimal test if python-safet is installed
|
if not self.libraries_available:
|
||||||
import safetlib
|
|
||||||
try:
|
|
||||||
library_version = safetlib.__version__
|
|
||||||
except AttributeError:
|
|
||||||
# python-safet only introduced __version__ in 0.1.0
|
|
||||||
library_version = 'unknown'
|
|
||||||
if library_version == 'unknown' or \
|
|
||||||
versiontuple(library_version) < self.minimum_library:
|
|
||||||
self.libraries_available_message = (
|
|
||||||
_("Library version for '{}' is too old.").format(name)
|
|
||||||
+ '\nInstalled: {}, Needed: {}'
|
|
||||||
.format(library_version, self.minimum_library))
|
|
||||||
self.print_stderr(self.libraries_available_message)
|
|
||||||
raise ImportError()
|
|
||||||
self.libraries_available = True
|
|
||||||
except ImportError:
|
|
||||||
self.libraries_available = False
|
|
||||||
return
|
return
|
||||||
|
|
||||||
from . import client
|
from . import client
|
||||||
@@ -113,6 +96,13 @@ class SafeTPlugin(HW_PluginBase):
|
|||||||
self.transport_handler = transport.SafeTTransport()
|
self.transport_handler = transport.SafeTTransport()
|
||||||
self.device_manager().register_enumerate_func(self.enumerate)
|
self.device_manager().register_enumerate_func(self.enumerate)
|
||||||
|
|
||||||
|
def get_library_version(self):
|
||||||
|
import safetlib
|
||||||
|
try:
|
||||||
|
return safetlib.__version__
|
||||||
|
except AttributeError:
|
||||||
|
return 'unknown'
|
||||||
|
|
||||||
def enumerate(self):
|
def enumerate(self):
|
||||||
devices = self.transport_handler.enumerate_devices()
|
devices = self.transport_handler.enumerate_devices()
|
||||||
return [Device(d.get_path(), -1, d.get_path(), 'Safe-T mini', 0) for d in devices]
|
return [Device(d.get_path(), -1, d.get_path(), 'Safe-T mini', 0) for d in devices]
|
||||||
|
|||||||
@@ -83,25 +83,8 @@ class TrezorPlugin(HW_PluginBase):
|
|||||||
def __init__(self, parent, config, name):
|
def __init__(self, parent, config, name):
|
||||||
HW_PluginBase.__init__(self, parent, config, name)
|
HW_PluginBase.__init__(self, parent, config, name)
|
||||||
|
|
||||||
try:
|
self.libraries_available = self.check_libraries_available()
|
||||||
# Minimal test if python-trezor is installed
|
if not self.libraries_available:
|
||||||
import trezorlib
|
|
||||||
try:
|
|
||||||
library_version = trezorlib.__version__
|
|
||||||
except AttributeError:
|
|
||||||
# python-trezor only introduced __version__ in 0.9.0
|
|
||||||
library_version = 'unknown'
|
|
||||||
if library_version == 'unknown' or \
|
|
||||||
versiontuple(library_version) < self.minimum_library:
|
|
||||||
self.libraries_available_message = (
|
|
||||||
_("Library version for '{}' is too old.").format(name)
|
|
||||||
+ '\nInstalled: {}, Needed: {}'
|
|
||||||
.format(library_version, self.minimum_library))
|
|
||||||
self.print_stderr(self.libraries_available_message)
|
|
||||||
raise ImportError()
|
|
||||||
self.libraries_available = True
|
|
||||||
except ImportError:
|
|
||||||
self.libraries_available = False
|
|
||||||
return
|
return
|
||||||
|
|
||||||
from . import client
|
from . import client
|
||||||
@@ -114,6 +97,13 @@ class TrezorPlugin(HW_PluginBase):
|
|||||||
self.transport_handler = transport.TrezorTransport()
|
self.transport_handler = transport.TrezorTransport()
|
||||||
self.device_manager().register_enumerate_func(self.enumerate)
|
self.device_manager().register_enumerate_func(self.enumerate)
|
||||||
|
|
||||||
|
def get_library_version(self):
|
||||||
|
import trezorlib
|
||||||
|
try:
|
||||||
|
return trezorlib.__version__
|
||||||
|
except AttributeError:
|
||||||
|
return 'unknown'
|
||||||
|
|
||||||
def enumerate(self):
|
def enumerate(self):
|
||||||
devices = self.transport_handler.enumerate_devices()
|
devices = self.transport_handler.enumerate_devices()
|
||||||
return [Device(d.get_path(), -1, d.get_path(), 'TREZOR', 0) for d in devices]
|
return [Device(d.get_path(), -1, d.get_path(), 'TREZOR', 0) for d in devices]
|
||||||
|
|||||||
Reference in New Issue
Block a user