From 1bd9b3a66aac28d2ff2c556370c26138bf23de09 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Wed, 4 Sep 2019 20:15:54 +0200 Subject: [PATCH] commands: fix "restore" cmd Previously commands did not run on the asyncio thread but now they do. "restore" was polling like "while 1: time.sleep()", blocking the event loop. Now "restore" does not sync the wallet; which is actually cleaner as previously this wallet would never get unloaded from the daemon (syncing forever). This is also symmetric with the "create" cmd which also does not try to sync with the network. However now it became difficult to write a script that restores a wallet and wants to wait until it gets synced. Workaround for now is to poll with "list_wallets" whether it's synced. We could create a new command that blocks until the loaded wallet gets synced. --- electrum/commands.py | 4 ++-- electrum/tests/test_wallet.py | 11 +++++------ electrum/wallet.py | 20 ++++++-------------- 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/electrum/commands.py b/electrum/commands.py index 07220feca..49d3db3e5 100644 --- a/electrum/commands.py +++ b/electrum/commands.py @@ -221,12 +221,12 @@ class Commands: or bitcoin private keys. If you want to be prompted for an argument, type '?' or ':' (concealed) """ + # TODO create a separate command that blocks until wallet is synced d = restore_wallet_from_text(text, path=self.config.get_wallet_path(), passphrase=passphrase, password=password, - encrypt_file=encrypt_file, - network=self.network) + encrypt_file=encrypt_file) return { 'path': d['wallet'].storage.path, 'msg': d['msg'], diff --git a/electrum/tests/test_wallet.py b/electrum/tests/test_wallet.py index b07f0fffb..b4f70bf69 100644 --- a/electrum/tests/test_wallet.py +++ b/electrum/tests/test_wallet.py @@ -170,7 +170,6 @@ class TestCreateRestoreWallet(WalletTestCase): encrypt_file = True d = restore_wallet_from_text(text, path=self.wallet_path, - network=None, passphrase=passphrase, password=password, encrypt_file=encrypt_file, @@ -183,28 +182,28 @@ class TestCreateRestoreWallet(WalletTestCase): def test_restore_wallet_from_text_xpub(self): text = 'zpub6nydoME6CFdJtMpzHW5BNoPz6i6XbeT9qfz72wsRqGdgGEYeivso6xjfw8cGcCyHwF7BNW4LDuHF35XrZsovBLWMF4qXSjmhTXYiHbWqGLt' - d = restore_wallet_from_text(text, path=self.wallet_path, network=None, gap_limit=1) + d = restore_wallet_from_text(text, path=self.wallet_path, gap_limit=1) wallet = d['wallet'] # type: Standard_Wallet self.assertEqual(text, wallet.keystore.get_master_public_key()) self.assertEqual('bc1q2ccr34wzep58d4239tl3x3734ttle92a8srmuw', wallet.get_receiving_addresses()[0]) def test_restore_wallet_from_text_xkey_that_is_also_a_valid_electrum_seed_by_chance(self): text = 'yprvAJBpuoF4FKpK92ofzQ7ge6VJMtorow3maAGPvPGj38ggr2xd1xCrC9ojUVEf9jhW5L9SPu6fU2U3o64cLrRQ83zaQGNa6YP3ajZS6hHNPXj' - d = restore_wallet_from_text(text, path=self.wallet_path, network=None, gap_limit=1) + d = restore_wallet_from_text(text, path=self.wallet_path, gap_limit=1) wallet = d['wallet'] # type: Standard_Wallet self.assertEqual(text, wallet.keystore.get_master_private_key(password=None)) self.assertEqual('3Pa4hfP3LFWqa2nfphYaF7PZfdJYNusAnp', wallet.get_receiving_addresses()[0]) def test_restore_wallet_from_text_xprv(self): text = 'zprvAZzHPqhCMt51fskXBUYB1fTFYgG3CBjJUT4WEZTpGw6hPSDWBPZYZARC5sE9xAcX8NeWvvucFws8vZxEa65RosKAhy7r5MsmKTxr3hmNmea' - d = restore_wallet_from_text(text, path=self.wallet_path, network=None, gap_limit=1) + d = restore_wallet_from_text(text, path=self.wallet_path, gap_limit=1) wallet = d['wallet'] # type: Standard_Wallet self.assertEqual(text, wallet.keystore.get_master_private_key(password=None)) self.assertEqual('bc1q2ccr34wzep58d4239tl3x3734ttle92a8srmuw', wallet.get_receiving_addresses()[0]) def test_restore_wallet_from_text_addresses(self): text = 'bc1q2ccr34wzep58d4239tl3x3734ttle92a8srmuw bc1qnp78h78vp92pwdwq5xvh8eprlga5q8gu66960c' - d = restore_wallet_from_text(text, path=self.wallet_path, network=None) + d = restore_wallet_from_text(text, path=self.wallet_path) wallet = d['wallet'] # type: Imported_Wallet self.assertEqual('bc1q2ccr34wzep58d4239tl3x3734ttle92a8srmuw', wallet.get_receiving_addresses()[0]) self.assertEqual(2, len(wallet.get_receiving_addresses())) @@ -214,7 +213,7 @@ class TestCreateRestoreWallet(WalletTestCase): def test_restore_wallet_from_text_privkeys(self): text = 'p2wpkh:L4jkdiXszG26SUYvwwJhzGwg37H2nLhrbip7u6crmgNeJysv5FHL p2wpkh:L24GxnN7NNUAfCXA6hFzB1jt59fYAAiFZMcLaJ2ZSawGpM3uqhb1' - d = restore_wallet_from_text(text, path=self.wallet_path, network=None) + d = restore_wallet_from_text(text, path=self.wallet_path) wallet = d['wallet'] # type: Imported_Wallet addr0 = wallet.get_receiving_addresses()[0] self.assertEqual('bc1q2ccr34wzep58d4239tl3x3734ttle92a8srmuw', addr0) diff --git a/electrum/wallet.py b/electrum/wallet.py index 012363fca..09d3c7205 100644 --- a/electrum/wallet.py +++ b/electrum/wallet.py @@ -2100,7 +2100,8 @@ class Wallet(object): raise WalletFileException("Unknown wallet type: " + str(wallet_type)) -def create_new_wallet(*, path, passphrase=None, password=None, encrypt_file=True, seed_type=None, gap_limit=None): +def create_new_wallet(*, path, passphrase=None, password=None, + encrypt_file=True, seed_type=None, gap_limit=None) -> dict: """Create a new wallet""" storage = WalletStorage(path) if storage.file_exists(): @@ -2121,9 +2122,9 @@ def create_new_wallet(*, path, passphrase=None, password=None, encrypt_file=True return {'seed': seed, 'wallet': wallet, 'msg': msg} -def restore_wallet_from_text(text, *, path, network=None, +def restore_wallet_from_text(text, *, path, passphrase=None, password=None, encrypt_file=True, - gap_limit=None): + gap_limit=None) -> dict: """Restore a wallet from text. Text can be a seed phrase, a master public key, a master private key, a list of bitcoin addresses or bitcoin private keys.""" @@ -2164,17 +2165,8 @@ def restore_wallet_from_text(text, *, path, network=None, assert not storage.file_exists(), "file was created too soon! plaintext keys might have been written to disk" wallet.update_password(old_pw=None, new_pw=password, encrypt_storage=encrypt_file) wallet.synchronize() - - if network: - wallet.start_network(network) - _logger.info("Recovering wallet...") - wallet.wait_until_synchronized() - wallet.stop_threads() - # note: we don't wait for SPV - msg = "Recovery successful" if wallet.is_found() else "Found no history for this wallet" - else: - msg = ("This wallet was restored offline. It may contain more addresses than displayed. " - "Start a daemon (not offline) to sync history.") + msg = ("This wallet was restored offline. It may contain more addresses than displayed. " + "Start a daemon and use load_wallet to sync its history.") wallet.storage.write() return {'wallet': wallet, 'msg': msg}