Browse Source

bip39 scan: follow-up prev

- use logger
- allow qt dialog to be GC-ed
- (trivial) add typing; minor formatting
bip39-recovery
SomberNight 4 years ago
parent
commit
df82d9c017
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 4
      electrum/base_wizard.py
  2. 17
      electrum/bip39_recovery.py
  3. 13
      electrum/gui/qt/bip39_recovery_dialog.py
  4. 15
      electrum/gui/qt/installwizard.py

4
electrum/base_wizard.py

@ -404,7 +404,7 @@ class BaseWizard(Logger):
else: else:
raise Exception('unknown purpose: %s' % purpose) raise Exception('unknown purpose: %s' % purpose)
def derivation_and_script_type_dialog(self, f, get_account_xpub=None): def derivation_and_script_type_dialog(self, f, *, get_account_xpub=None):
message1 = _('Choose the type of addresses in your wallet.') message1 = _('Choose the type of addresses in your wallet.')
message2 = ' '.join([ message2 = ' '.join([
_('You can override the suggested derivation path.'), _('You can override the suggested derivation path.'),
@ -516,7 +516,7 @@ class BaseWizard(Logger):
account_node = root_node.subkey_at_private_derivation(account_path) account_node = root_node.subkey_at_private_derivation(account_path)
account_xpub = account_node.to_xpub() account_xpub = account_node.to_xpub()
return account_xpub return account_xpub
self.derivation_and_script_type_dialog(f, get_account_xpub) self.derivation_and_script_type_dialog(f, get_account_xpub=get_account_xpub)
def create_keystore(self, seed, passphrase): def create_keystore(self, seed, passphrase):
k = keystore.from_seed(seed, passphrase, self.wallet_type == 'multisig') k = keystore.from_seed(seed, passphrase, self.wallet_type == 'multisig')

17
electrum/bip39_recovery.py

@ -2,6 +2,8 @@
# Distributed under the MIT software license, see the accompanying # Distributed under the MIT software license, see the accompanying
# file LICENCE or http://www.opensource.org/licenses/mit-license.php # file LICENCE or http://www.opensource.org/licenses/mit-license.php
from typing import TYPE_CHECKING
from aiorpcx import TaskGroup from aiorpcx import TaskGroup
from . import bitcoin from . import bitcoin
@ -10,7 +12,11 @@ from .bip32 import BIP32_PRIME, BIP32Node
from .bip32 import convert_bip32_path_to_list_of_uint32 as bip32_str_to_ints from .bip32 import convert_bip32_path_to_list_of_uint32 as bip32_str_to_ints
from .bip32 import convert_bip32_intpath_to_strpath as bip32_ints_to_str from .bip32 import convert_bip32_intpath_to_strpath as bip32_ints_to_str
async def account_discovery(network, get_account_xpub): if TYPE_CHECKING:
from .network import Network
async def account_discovery(network: 'Network', get_account_xpub):
async with TaskGroup() as group: async with TaskGroup() as group:
account_scan_tasks = [] account_scan_tasks = []
for wallet_format in BIP39_WALLET_FORMATS: for wallet_format in BIP39_WALLET_FORMATS:
@ -21,13 +27,14 @@ async def account_discovery(network, get_account_xpub):
active_accounts.extend(task.result()) active_accounts.extend(task.result())
return active_accounts return active_accounts
async def scan_for_active_accounts(network, get_account_xpub, wallet_format):
async def scan_for_active_accounts(network: 'Network', get_account_xpub, wallet_format):
active_accounts = [] active_accounts = []
account_path = bip32_str_to_ints(wallet_format["derivation_path"]) account_path = bip32_str_to_ints(wallet_format["derivation_path"])
while True: while True:
account_xpub = get_account_xpub(account_path) account_xpub = get_account_xpub(account_path)
account_node = BIP32Node.from_xkey(account_xpub) account_node = BIP32Node.from_xkey(account_xpub)
has_history = await account_has_history(network, account_node, wallet_format["script_type"]); has_history = await account_has_history(network, account_node, wallet_format["script_type"])
if has_history: if has_history:
account = format_account(wallet_format, account_path) account = format_account(wallet_format, account_path)
active_accounts.append(account) active_accounts.append(account)
@ -36,7 +43,8 @@ async def scan_for_active_accounts(network, get_account_xpub, wallet_format):
account_path[-1] = account_path[-1] + 1 account_path[-1] = account_path[-1] + 1
return active_accounts return active_accounts
async def account_has_history(network, account_node, script_type):
async def account_has_history(network: 'Network', account_node: BIP32Node, script_type: str) -> bool:
gap_limit = 20 gap_limit = 20
async with TaskGroup() as group: async with TaskGroup() as group:
get_history_tasks = [] get_history_tasks = []
@ -54,6 +62,7 @@ async def account_has_history(network, account_node, script_type):
return True return True
return False return False
def format_account(wallet_format, account_path): def format_account(wallet_format, account_path):
description = wallet_format["description"] description = wallet_format["description"]
if wallet_format["iterate_accounts"]: if wallet_format["iterate_accounts"]:

13
electrum/gui/qt/bip39_recovery_dialog.py

@ -8,9 +8,14 @@ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QGridLayout, QLabel, QListWidg
from electrum.i18n import _ from electrum.i18n import _
from electrum.network import Network from electrum.network import Network
from electrum.bip39_recovery import account_discovery from electrum.bip39_recovery import account_discovery
from electrum.logging import get_logger
from .util import WindowModalDialog, MessageBoxMixin, TaskThread, Buttons, CancelButton, OkButton from .util import WindowModalDialog, MessageBoxMixin, TaskThread, Buttons, CancelButton, OkButton
_logger = get_logger(__name__)
class Bip39RecoveryDialog(WindowModalDialog): class Bip39RecoveryDialog(WindowModalDialog):
def __init__(self, parent: QWidget, get_account_xpub, on_account_select): def __init__(self, parent: QWidget, get_account_xpub, on_account_select):
self.get_account_xpub = get_account_xpub self.get_account_xpub = get_account_xpub
@ -25,11 +30,15 @@ class Bip39RecoveryDialog(WindowModalDialog):
self.ok_button.clicked.connect(self.on_ok_button_click) self.ok_button.clicked.connect(self.on_ok_button_click)
self.ok_button.setEnabled(False) self.ok_button.setEnabled(False)
vbox.addLayout(Buttons(CancelButton(self), self.ok_button)) vbox.addLayout(Buttons(CancelButton(self), self.ok_button))
self.finished.connect(self.on_finished)
self.show() self.show()
self.thread = TaskThread(self) self.thread = TaskThread(self)
self.thread.finished.connect(self.deleteLater) # see #3956 self.thread.finished.connect(self.deleteLater) # see #3956
self.thread.add(self.recovery, self.on_recovery_success, None, self.on_recovery_error) self.thread.add(self.recovery, self.on_recovery_success, None, self.on_recovery_error)
def on_finished(self):
self.thread.stop()
def on_ok_button_click(self): def on_ok_button_click(self):
item = self.list.currentItem() item = self.list.currentItem()
account = item.data(Qt.UserRole) account = item.data(Qt.UserRole)
@ -54,10 +63,10 @@ class Bip39RecoveryDialog(WindowModalDialog):
self.list.clicked.connect(lambda: self.ok_button.setEnabled(True)) self.list.clicked.connect(lambda: self.ok_button.setEnabled(True))
self.content.addWidget(self.list) self.content.addWidget(self.list)
def on_recovery_error(self, error): def on_recovery_error(self, exc_info):
self.clear_content() self.clear_content()
self.content.addWidget(QLabel(_('Error: Account discovery failed.'))) self.content.addWidget(QLabel(_('Error: Account discovery failed.')))
print(error) _logger.error(f"recovery error", exc_info=exc_info)
def clear_content(self): def clear_content(self):
for i in reversed(range(self.content.count())): for i in reversed(range(self.content.count())):

15
electrum/gui/qt/installwizard.py

@ -604,9 +604,18 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
return clayout.selected_index() return clayout.selected_index()
@wizard_dialog @wizard_dialog
def derivation_and_script_type_gui_specific_dialog(self, title: str, message1: str, choices: List[Tuple[str, str, str]], def derivation_and_script_type_gui_specific_dialog(
message2: str, test_text: Callable[[str], int], self,
run_next, default_choice_idx: int=0, get_account_xpub=None) -> Tuple[str, str]: *,
title: str,
message1: str,
choices: List[Tuple[str, str, str]],
message2: str,
test_text: Callable[[str], int],
run_next,
default_choice_idx: int = 0,
get_account_xpub=None
) -> Tuple[str, str]:
vbox = QVBoxLayout() vbox = QVBoxLayout()
if get_account_xpub: if get_account_xpub:

Loading…
Cancel
Save