mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
add some type hints
mostly related to hw wallets
This commit is contained in:
parent
770ae6d878
commit
88307357ec
5 changed files with 39 additions and 26 deletions
|
@ -34,7 +34,7 @@ from . import bitcoin
|
||||||
from . import keystore
|
from . import keystore
|
||||||
from . import mnemonic
|
from . import mnemonic
|
||||||
from .bip32 import is_bip32_derivation, xpub_type, normalize_bip32_derivation, BIP32Node
|
from .bip32 import is_bip32_derivation, xpub_type, normalize_bip32_derivation, BIP32Node
|
||||||
from .keystore import bip44_derivation, purpose48_derivation
|
from .keystore import bip44_derivation, purpose48_derivation, Hardware_KeyStore
|
||||||
from .wallet import (Imported_Wallet, Standard_Wallet, Multisig_Wallet,
|
from .wallet import (Imported_Wallet, Standard_Wallet, Multisig_Wallet,
|
||||||
wallet_types, Wallet, Abstract_Wallet)
|
wallet_types, Wallet, Abstract_Wallet)
|
||||||
from .storage import (WalletStorage, StorageEncryptionVersion,
|
from .storage import (WalletStorage, StorageEncryptionVersion,
|
||||||
|
@ -47,7 +47,7 @@ from .logging import Logger
|
||||||
from .plugins.hw_wallet.plugin import OutdatedHwFirmwareException, HW_PluginBase
|
from .plugins.hw_wallet.plugin import OutdatedHwFirmwareException, HW_PluginBase
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .plugin import DeviceInfo
|
from .plugin import DeviceInfo, BasePlugin
|
||||||
|
|
||||||
|
|
||||||
# hardware device setup purpose
|
# hardware device setup purpose
|
||||||
|
@ -84,7 +84,7 @@ class BaseWizard(Logger):
|
||||||
self.data = {}
|
self.data = {}
|
||||||
self.pw_args = None # type: Optional[WizardWalletPasswordSetting]
|
self.pw_args = None # type: Optional[WizardWalletPasswordSetting]
|
||||||
self._stack = [] # type: List[WizardStackItem]
|
self._stack = [] # type: List[WizardStackItem]
|
||||||
self.plugin = None
|
self.plugin = None # type: Optional[BasePlugin]
|
||||||
self.keystores = []
|
self.keystores = []
|
||||||
self.is_kivy = config.get('gui') == 'kivy'
|
self.is_kivy = config.get('gui') == 'kivy'
|
||||||
self.seed_type = None
|
self.seed_type = None
|
||||||
|
@ -532,9 +532,9 @@ class BaseWizard(Logger):
|
||||||
encrypt_keystore = any(k.may_have_password() for k in self.keystores)
|
encrypt_keystore = any(k.may_have_password() for k in self.keystores)
|
||||||
# note: the following condition ("if") is duplicated logic from
|
# note: the following condition ("if") is duplicated logic from
|
||||||
# wallet.get_available_storage_encryption_version()
|
# wallet.get_available_storage_encryption_version()
|
||||||
if self.wallet_type == 'standard' and isinstance(self.keystores[0], keystore.Hardware_KeyStore):
|
if self.wallet_type == 'standard' and isinstance(self.keystores[0], Hardware_KeyStore):
|
||||||
# offer encrypting with a pw derived from the hw device
|
# offer encrypting with a pw derived from the hw device
|
||||||
k = self.keystores[0]
|
k = self.keystores[0] # type: Hardware_KeyStore
|
||||||
try:
|
try:
|
||||||
k.handler = self.plugin.create_handler(self)
|
k.handler = self.plugin.create_handler(self)
|
||||||
password = k.get_password_for_storage_encryption()
|
password = k.get_password_for_storage_encryption()
|
||||||
|
|
|
@ -44,23 +44,25 @@ from .plugin import run_hook
|
||||||
from .logging import Logger
|
from .logging import Logger
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
from .gui.qt.util import TaskThread
|
||||||
from .transaction import Transaction, PartialTransaction, PartialTxInput, PartialTxOutput
|
from .transaction import Transaction, PartialTransaction, PartialTxInput, PartialTxOutput
|
||||||
from .plugins.hw_wallet import HW_PluginBase, HardwareClientBase
|
from .plugins.hw_wallet import HW_PluginBase, HardwareClientBase
|
||||||
|
|
||||||
|
|
||||||
class KeyStore(Logger):
|
class KeyStore(Logger):
|
||||||
|
type: str
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Logger.__init__(self)
|
Logger.__init__(self)
|
||||||
self.is_requesting_to_be_rewritten_to_wallet_file = False # type: bool
|
self.is_requesting_to_be_rewritten_to_wallet_file = False # type: bool
|
||||||
|
|
||||||
def has_seed(self):
|
def has_seed(self) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def is_watching_only(self):
|
def is_watching_only(self) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def can_import(self):
|
def can_import(self) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_type_text(self) -> str:
|
def get_type_text(self) -> str:
|
||||||
|
@ -85,12 +87,12 @@ class KeyStore(Logger):
|
||||||
keypairs[pubkey.hex()] = derivation
|
keypairs[pubkey.hex()] = derivation
|
||||||
return keypairs
|
return keypairs
|
||||||
|
|
||||||
def can_sign(self, tx):
|
def can_sign(self, tx) -> bool:
|
||||||
if self.is_watching_only():
|
if self.is_watching_only():
|
||||||
return False
|
return False
|
||||||
return bool(self.get_tx_derivations(tx))
|
return bool(self.get_tx_derivations(tx))
|
||||||
|
|
||||||
def ready_to_sign(self):
|
def ready_to_sign(self) -> bool:
|
||||||
return not self.is_watching_only()
|
return not self.is_watching_only()
|
||||||
|
|
||||||
def dump(self) -> dict:
|
def dump(self) -> dict:
|
||||||
|
@ -629,6 +631,7 @@ class Hardware_KeyStore(KeyStore, Xpub):
|
||||||
hw_type: str
|
hw_type: str
|
||||||
device: str
|
device: str
|
||||||
plugin: 'HW_PluginBase'
|
plugin: 'HW_PluginBase'
|
||||||
|
thread: Optional['TaskThread'] = None
|
||||||
|
|
||||||
type = 'hardware'
|
type = 'hardware'
|
||||||
|
|
||||||
|
@ -684,7 +687,7 @@ class Hardware_KeyStore(KeyStore, Xpub):
|
||||||
assert not self.has_seed()
|
assert not self.has_seed()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_password_for_storage_encryption(self):
|
def get_password_for_storage_encryption(self) -> str:
|
||||||
from .storage import get_derivation_used_for_hw_device_encryption
|
from .storage import get_derivation_used_for_hw_device_encryption
|
||||||
client = self.plugin.get_client(self)
|
client = self.plugin.get_client(self)
|
||||||
derivation = get_derivation_used_for_hw_device_encryption()
|
derivation = get_derivation_used_for_hw_device_encryption()
|
||||||
|
@ -692,7 +695,7 @@ class Hardware_KeyStore(KeyStore, Xpub):
|
||||||
password = self.get_pubkey_from_xpub(xpub, ())
|
password = self.get_pubkey_from_xpub(xpub, ())
|
||||||
return password
|
return password
|
||||||
|
|
||||||
def has_usable_connection_with_device(self):
|
def has_usable_connection_with_device(self) -> bool:
|
||||||
if not hasattr(self, 'plugin'):
|
if not hasattr(self, 'plugin'):
|
||||||
return False
|
return False
|
||||||
client = self.plugin.get_client(self, force_pair=False)
|
client = self.plugin.get_client(self, force_pair=False)
|
||||||
|
|
|
@ -352,7 +352,7 @@ class DeviceMgr(ThreadJob):
|
||||||
ThreadJob.__init__(self)
|
ThreadJob.__init__(self)
|
||||||
# Keyed by xpub. The value is the device id
|
# Keyed by xpub. The value is the device id
|
||||||
# has been paired, and None otherwise.
|
# has been paired, and None otherwise.
|
||||||
self.xpub_ids = {}
|
self.xpub_ids = {} # type: Dict[str, str]
|
||||||
# A list of clients. The key is the client, the value is
|
# A list of clients. The key is the client, the value is
|
||||||
# a (path, id_) pair.
|
# a (path, id_) pair.
|
||||||
self.clients = {} # type: Dict[HardwareClientBase, Tuple[Union[str, bytes], str]]
|
self.clients = {} # type: Dict[HardwareClientBase, Tuple[Union[str, bytes], str]]
|
||||||
|
|
|
@ -40,6 +40,7 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
class HW_PluginBase(BasePlugin):
|
class HW_PluginBase(BasePlugin):
|
||||||
keystore_class: Type['Hardware_KeyStore']
|
keystore_class: Type['Hardware_KeyStore']
|
||||||
|
libraries_available: bool
|
||||||
|
|
||||||
minimum_library = (0, )
|
minimum_library = (0, )
|
||||||
|
|
||||||
|
@ -211,7 +212,7 @@ def get_xpubs_and_der_suffixes_from_txinout(tx: PartialTransaction,
|
||||||
def only_hook_if_libraries_available(func):
|
def only_hook_if_libraries_available(func):
|
||||||
# note: this decorator must wrap @hook, not the other way around,
|
# note: this decorator must wrap @hook, not the other way around,
|
||||||
# as 'hook' uses the name of the function it wraps
|
# as 'hook' uses the name of the function it wraps
|
||||||
def wrapper(self, *args, **kwargs):
|
def wrapper(self: 'HW_PluginBase', *args, **kwargs):
|
||||||
if not self.libraries_available: return None
|
if not self.libraries_available: return None
|
||||||
return func(self, *args, **kwargs)
|
return func(self, *args, **kwargs)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
import threading
|
import threading
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from typing import TYPE_CHECKING, Union, Optional, Callable, Any
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, pyqtSignal
|
from PyQt5.QtCore import QObject, pyqtSignal
|
||||||
from PyQt5.QtWidgets import QVBoxLayout, QLineEdit, QHBoxLayout, QLabel
|
from PyQt5.QtWidgets import QVBoxLayout, QLineEdit, QHBoxLayout, QLabel
|
||||||
|
@ -33,12 +34,18 @@ from PyQt5.QtWidgets import QVBoxLayout, QLineEdit, QHBoxLayout, QLabel
|
||||||
from electrum.gui.qt.password_dialog import PasswordLayout, PW_PASSPHRASE
|
from electrum.gui.qt.password_dialog import PasswordLayout, PW_PASSPHRASE
|
||||||
from electrum.gui.qt.util import (read_QIcon, WWLabel, OkButton, WindowModalDialog,
|
from electrum.gui.qt.util import (read_QIcon, WWLabel, OkButton, WindowModalDialog,
|
||||||
Buttons, CancelButton, TaskThread, char_width_in_lineedit)
|
Buttons, CancelButton, TaskThread, char_width_in_lineedit)
|
||||||
|
from electrum.gui.qt.main_window import StatusBarButton, ElectrumWindow
|
||||||
|
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.logging import Logger
|
from electrum.logging import Logger
|
||||||
from electrum.util import parse_URI, InvalidBitcoinURI
|
from electrum.util import parse_URI, InvalidBitcoinURI, UserCancelled
|
||||||
|
from electrum.plugin import hook, DeviceUnpairableError
|
||||||
|
|
||||||
from .plugin import OutdatedHwFirmwareException
|
from .plugin import OutdatedHwFirmwareException, HW_PluginBase
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from electrum.wallet import Abstract_Wallet
|
||||||
|
from electrum.keystore import Hardware_KeyStore
|
||||||
|
|
||||||
|
|
||||||
# The trickiest thing about this handler was getting windows properly
|
# The trickiest thing about this handler was getting windows properly
|
||||||
|
@ -190,15 +197,10 @@ class QtHandlerBase(QObject, Logger):
|
||||||
self.done.set()
|
self.done.set()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from electrum.plugin import hook
|
|
||||||
from electrum.util import UserCancelled
|
|
||||||
from electrum.gui.qt.main_window import StatusBarButton
|
|
||||||
|
|
||||||
class QtPluginBase(object):
|
class QtPluginBase(object):
|
||||||
|
|
||||||
@hook
|
@hook
|
||||||
def load_wallet(self, wallet, window):
|
def load_wallet(self: Union['QtPluginBase', HW_PluginBase], wallet: 'Abstract_Wallet', window: ElectrumWindow):
|
||||||
for keystore in wallet.get_keystores():
|
for keystore in wallet.get_keystores():
|
||||||
if not isinstance(keystore, self.keystore_class):
|
if not isinstance(keystore, self.keystore_class):
|
||||||
continue
|
continue
|
||||||
|
@ -220,7 +222,8 @@ class QtPluginBase(object):
|
||||||
# Trigger a pairing
|
# Trigger a pairing
|
||||||
keystore.thread.add(partial(self.get_client, keystore))
|
keystore.thread.add(partial(self.get_client, keystore))
|
||||||
|
|
||||||
def on_task_thread_error(self, window, keystore, exc_info):
|
def on_task_thread_error(self: Union['QtPluginBase', HW_PluginBase], window: ElectrumWindow,
|
||||||
|
keystore: 'Hardware_KeyStore', exc_info):
|
||||||
e = exc_info[1]
|
e = exc_info[1]
|
||||||
if isinstance(e, OutdatedHwFirmwareException):
|
if isinstance(e, OutdatedHwFirmwareException):
|
||||||
if window.question(e.text_ignore_old_fw_and_continue(), title=_("Outdated device firmware")):
|
if window.question(e.text_ignore_old_fw_and_continue(), title=_("Outdated device firmware")):
|
||||||
|
@ -236,7 +239,8 @@ class QtPluginBase(object):
|
||||||
else:
|
else:
|
||||||
window.on_error(exc_info)
|
window.on_error(exc_info)
|
||||||
|
|
||||||
def choose_device(self, window, keystore):
|
def choose_device(self: Union['QtPluginBase', HW_PluginBase], window: ElectrumWindow,
|
||||||
|
keystore: 'Hardware_KeyStore') -> Optional[str]:
|
||||||
'''This dialog box should be usable even if the user has
|
'''This dialog box should be usable even if the user has
|
||||||
forgotten their PIN or it is in bootloader mode.'''
|
forgotten their PIN or it is in bootloader mode.'''
|
||||||
device_id = self.device_manager().xpub_id(keystore.xpub)
|
device_id = self.device_manager().xpub_id(keystore.xpub)
|
||||||
|
@ -248,10 +252,12 @@ class QtPluginBase(object):
|
||||||
device_id = info.device.id_
|
device_id = info.device.id_
|
||||||
return device_id
|
return device_id
|
||||||
|
|
||||||
def show_settings_dialog(self, window, keystore):
|
def show_settings_dialog(self, window: ElectrumWindow, keystore: 'Hardware_KeyStore') -> None:
|
||||||
device_id = self.choose_device(window, keystore)
|
device_id = self.choose_device(window, keystore)
|
||||||
|
|
||||||
def add_show_address_on_hw_device_button_for_receive_addr(self, wallet, keystore, main_window):
|
def add_show_address_on_hw_device_button_for_receive_addr(self, wallet: 'Abstract_Wallet',
|
||||||
|
keystore: 'Hardware_KeyStore',
|
||||||
|
main_window: ElectrumWindow):
|
||||||
plugin = keystore.plugin
|
plugin = keystore.plugin
|
||||||
receive_address_e = main_window.receive_address_e
|
receive_address_e = main_window.receive_address_e
|
||||||
|
|
||||||
|
@ -267,3 +273,6 @@ class QtPluginBase(object):
|
||||||
keystore.thread.add(partial(plugin.show_address, wallet, addr, keystore))
|
keystore.thread.add(partial(plugin.show_address, wallet, addr, keystore))
|
||||||
dev_name = f"{plugin.device} ({keystore.label})"
|
dev_name = f"{plugin.device} ({keystore.label})"
|
||||||
receive_address_e.addButton("eye1.png", show_address, _("Show on {}").format(dev_name))
|
receive_address_e.addButton("eye1.png", show_address, _("Show on {}").format(dev_name))
|
||||||
|
|
||||||
|
def create_handler(self, window: ElectrumWindow) -> 'QtHandlerBase':
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
Loading…
Add table
Reference in a new issue