electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

bip39_recovery_dialog.py (2977B)


      1 # Copyright (C) 2020 The Electrum developers
      2 # Distributed under the MIT software license, see the accompanying
      3 # file LICENCE or http://www.opensource.org/licenses/mit-license.php
      4 
      5 from PyQt5.QtCore import Qt
      6 from PyQt5.QtWidgets import QWidget, QVBoxLayout, QGridLayout, QLabel, QListWidget, QListWidgetItem
      7 
      8 from electrum.i18n import _
      9 from electrum.network import Network
     10 from electrum.bip39_recovery import account_discovery
     11 from electrum.logging import get_logger
     12 
     13 from .util import WindowModalDialog, MessageBoxMixin, TaskThread, Buttons, CancelButton, OkButton
     14 
     15 
     16 _logger = get_logger(__name__)
     17 
     18 
     19 class Bip39RecoveryDialog(WindowModalDialog):
     20     def __init__(self, parent: QWidget, get_account_xpub, on_account_select):
     21         self.get_account_xpub = get_account_xpub
     22         self.on_account_select = on_account_select
     23         WindowModalDialog.__init__(self, parent, _('BIP39 Recovery'))
     24         self.setMinimumWidth(400)
     25         vbox = QVBoxLayout(self)
     26         self.content = QVBoxLayout()
     27         self.content.addWidget(QLabel(_('Scanning common paths for existing accounts...')))
     28         vbox.addLayout(self.content)
     29         self.ok_button = OkButton(self)
     30         self.ok_button.clicked.connect(self.on_ok_button_click)
     31         self.ok_button.setEnabled(False)
     32         vbox.addLayout(Buttons(CancelButton(self), self.ok_button))
     33         self.finished.connect(self.on_finished)
     34         self.show()
     35         self.thread = TaskThread(self)
     36         self.thread.finished.connect(self.deleteLater) # see #3956
     37         self.thread.add(self.recovery, self.on_recovery_success, None, self.on_recovery_error)
     38 
     39     def on_finished(self):
     40         self.thread.stop()
     41 
     42     def on_ok_button_click(self):
     43         item = self.list.currentItem()
     44         account = item.data(Qt.UserRole)
     45         self.on_account_select(account)
     46 
     47     def recovery(self):
     48         network = Network.get_instance()
     49         coroutine = account_discovery(network, self.get_account_xpub)
     50         return network.run_from_another_thread(coroutine)
     51 
     52     def on_recovery_success(self, accounts):
     53         self.clear_content()
     54         if len(accounts) == 0:
     55             self.content.addWidget(QLabel(_('No existing accounts found.')))
     56             return
     57         self.content.addWidget(QLabel(_('Choose an account to restore.')))
     58         self.list = QListWidget()
     59         for account in accounts:
     60             item = QListWidgetItem(account['description'])
     61             item.setData(Qt.UserRole, account)
     62             self.list.addItem(item)
     63         self.list.clicked.connect(lambda: self.ok_button.setEnabled(True))
     64         self.content.addWidget(self.list)
     65 
     66     def on_recovery_error(self, exc_info):
     67         self.clear_content()
     68         self.content.addWidget(QLabel(_('Error: Account discovery failed.')))
     69         _logger.error(f"recovery error", exc_info=exc_info)
     70 
     71     def clear_content(self):
     72         for i in reversed(range(self.content.count())):
     73             self.content.itemAt(i).widget().setParent(None)