commit ae80f143e7b82914c2f830d369df99e700bb1ccc
parent b2128af9585978ade8eab9822665c7cf07167f3d
Author: SomberNight <somber.night@protonmail.com>
Date: Thu, 28 Feb 2019 20:12:24 +0100
commands/wallet: separate out 'create' and 'restore' core parts
so that they are easier to use from python scripts
Diffstat:
M | electrum/commands.py | | | 87 | +++++++++++++++++++------------------------------------------------------------ |
M | electrum/wallet.py | | | 79 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
2 files changed, 99 insertions(+), 67 deletions(-)
diff --git a/electrum/commands.py b/electrum/commands.py
@@ -46,7 +46,7 @@ from .paymentrequest import PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED
from .synchronizer import Notifier
from .storage import WalletStorage
from . import keystore
-from .wallet import Wallet, Imported_Wallet, Abstract_Wallet
+from .wallet import Wallet, Imported_Wallet, Abstract_Wallet, create_new_wallet, restore_wallet_from_text
from .address_synchronizer import TX_HEIGHT_LOCAL
from .mnemonic import Mnemonic
@@ -139,22 +139,16 @@ class Commands:
@command('')
def create(self, passphrase=None, password=None, encrypt_file=True, segwit=False):
"""Create a new wallet"""
- storage = WalletStorage(self.config.get_wallet_path())
- if storage.file_exists():
- raise Exception("Remove the existing wallet first!")
-
- seed_type = 'segwit' if segwit else 'standard'
- seed = Mnemonic('en').make_seed(seed_type)
- k = keystore.from_seed(seed, passphrase)
- storage.put('keystore', k.dump())
- storage.put('wallet_type', 'standard')
- wallet = Wallet(storage)
- wallet.update_password(old_pw=None, new_pw=password, encrypt_storage=encrypt_file)
- wallet.synchronize()
- msg = "Please keep your seed in a safe place; if you lose it, you will not be able to restore your wallet."
-
- wallet.storage.write()
- return {'seed': seed, 'path': wallet.storage.path, 'msg': msg}
+ d = create_new_wallet(path=self.config.get_wallet_path(),
+ passphrase=passphrase,
+ password=password,
+ encrypt_file=encrypt_file,
+ segwit=segwit)
+ return {
+ 'seed': d['seed'],
+ 'path': d['wallet'].storage.path,
+ 'msg': d['msg'],
+ }
@command('')
def restore(self, text, passphrase=None, password=None, encrypt_file=True):
@@ -162,55 +156,16 @@ class Commands:
public key, a master private key, a list of bitcoin addresses
or bitcoin private keys. If you want to be prompted for your
seed, type '?' or ':' (concealed) """
- storage = WalletStorage(self.config.get_wallet_path())
- if storage.file_exists():
- raise Exception("Remove the existing wallet first!")
-
- text = text.strip()
- if keystore.is_address_list(text):
- wallet = Imported_Wallet(storage)
- addresses = text.split()
- good_inputs, bad_inputs = wallet.import_addresses(addresses, write_to_disk=False)
- # FIXME tell user about bad_inputs
- if not good_inputs:
- raise Exception("None of the given addresses can be imported")
- elif keystore.is_private_key_list(text, allow_spaces_inside_key=False):
- k = keystore.Imported_KeyStore({})
- storage.put('keystore', k.dump())
- wallet = Imported_Wallet(storage)
- keys = keystore.get_private_keys(text)
- good_inputs, bad_inputs = wallet.import_private_keys(keys, None, write_to_disk=False)
- # FIXME tell user about bad_inputs
- if not good_inputs:
- raise Exception("None of the given privkeys can be imported")
- else:
- if keystore.is_seed(text):
- k = keystore.from_seed(text, passphrase)
- elif keystore.is_master_key(text):
- k = keystore.from_master_key(text)
- else:
- raise Exception("Seed or key not recognized")
- storage.put('keystore', k.dump())
- storage.put('wallet_type', 'standard')
- wallet = Wallet(storage)
-
- 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 self.network:
- wallet.start_network(self.network)
- print_error("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.")
-
- wallet.storage.write()
- return {'path': wallet.storage.path, 'msg': msg}
+ d = restore_wallet_from_text(text,
+ path=self.config.get_wallet_path(),
+ passphrase=passphrase,
+ password=password,
+ encrypt_file=encrypt_file,
+ network=self.network)
+ return {
+ 'path': d['wallet'].storage.path,
+ 'msg': d['msg'],
+ }
@command('wp')
def password(self, password=None, new_password=None):
diff --git a/electrum/wallet.py b/electrum/wallet.py
@@ -45,10 +45,11 @@ from .util import (NotEnoughFunds, PrintError, UserCancelled, profiler,
format_satoshis, format_fee_satoshis, NoDynamicFeeEstimates,
WalletFileException, BitcoinException,
InvalidPassword, format_time, timestamp_to_datetime, Satoshis,
- Fiat, bfh, bh2u, TxMinedInfo)
+ Fiat, bfh, bh2u, TxMinedInfo, print_error)
from .bitcoin import (COIN, TYPE_ADDRESS, is_address, address_to_script,
is_minikey, relayfee, dust_threshold)
from .crypto import sha256d
+from . import keystore
from .keystore import load_keystore, Hardware_KeyStore
from .util import multisig_type
from .storage import STO_EV_PLAINTEXT, STO_EV_USER_PW, STO_EV_XPUB_PW, WalletStorage
@@ -62,6 +63,7 @@ from .paymentrequest import (PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED,
from .contacts import Contacts
from .interface import RequestTimedOut
from .ecc_fast import is_using_fast_ecc
+from .mnemonic import Mnemonic
if TYPE_CHECKING:
from .network import Network
@@ -1848,3 +1850,78 @@ class Wallet(object):
if wallet_type in wallet_constructors:
return wallet_constructors[wallet_type]
raise WalletFileException("Unknown wallet type: " + str(wallet_type))
+
+
+def create_new_wallet(*, path, passphrase=None, password=None, encrypt_file=True, segwit=True):
+ """Create a new wallet"""
+ storage = WalletStorage(path)
+ if storage.file_exists():
+ raise Exception("Remove the existing wallet first!")
+
+ seed_type = 'segwit' if segwit else 'standard'
+ seed = Mnemonic('en').make_seed(seed_type)
+ k = keystore.from_seed(seed, passphrase)
+ storage.put('keystore', k.dump())
+ storage.put('wallet_type', 'standard')
+ wallet = Wallet(storage)
+ wallet.update_password(old_pw=None, new_pw=password, encrypt_storage=encrypt_file)
+ wallet.synchronize()
+ msg = "Please keep your seed in a safe place; if you lose it, you will not be able to restore your wallet."
+
+ wallet.storage.write()
+ return {'seed': seed, 'wallet': wallet, 'msg': msg}
+
+
+def restore_wallet_from_text(text, *, path, network, passphrase=None, password=None, encrypt_file=True):
+ """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."""
+ storage = WalletStorage(path)
+ if storage.file_exists():
+ raise Exception("Remove the existing wallet first!")
+
+ text = text.strip()
+ if keystore.is_address_list(text):
+ wallet = Imported_Wallet(storage)
+ addresses = text.split()
+ good_inputs, bad_inputs = wallet.import_addresses(addresses, write_to_disk=False)
+ # FIXME tell user about bad_inputs
+ if not good_inputs:
+ raise Exception("None of the given addresses can be imported")
+ elif keystore.is_private_key_list(text, allow_spaces_inside_key=False):
+ k = keystore.Imported_KeyStore({})
+ storage.put('keystore', k.dump())
+ wallet = Imported_Wallet(storage)
+ keys = keystore.get_private_keys(text)
+ good_inputs, bad_inputs = wallet.import_private_keys(keys, None, write_to_disk=False)
+ # FIXME tell user about bad_inputs
+ if not good_inputs:
+ raise Exception("None of the given privkeys can be imported")
+ else:
+ if keystore.is_seed(text):
+ k = keystore.from_seed(text, passphrase)
+ elif keystore.is_master_key(text):
+ k = keystore.from_master_key(text)
+ else:
+ raise Exception("Seed or key not recognized")
+ storage.put('keystore', k.dump())
+ storage.put('wallet_type', 'standard')
+ wallet = Wallet(storage)
+
+ 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)
+ print_error("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.")
+
+ wallet.storage.write()
+ return {'wallet': wallet, 'msg': msg}