mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
commands/wallet: separate out 'create' and 'restore' core parts
so that they are easier to use from python scripts
This commit is contained in:
parent
b2128af958
commit
ae80f143e7
2 changed files with 99 additions and 67 deletions
|
@ -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):
|
||||
|
|
|
@ -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}
|
||||
|
|
Loading…
Add table
Reference in a new issue