commit acbe67fd1f4d3bd0755707ee90b97295b5d7ff99
parent 62201b37f59b8c10828958d2326e48f068d98449
Author: ThomasV <thomasv@electrum.org>
Date: Wed, 23 Dec 2015 10:54:31 +0100
separation between RPC and non-RPC commands.
Diffstat:
3 files changed, 126 insertions(+), 111 deletions(-)
diff --git a/electrum b/electrum
@@ -107,9 +107,74 @@ def init_gui(config, network, plugins):
return gui
+def run_non_RPC(config):
+ cmdname = config.get('cmd')
+
+ storage = WalletStorage(config.get_wallet_path())
+ if storage.file_exists:
+ sys.exit("Error: Remove the existing wallet first!")
+
+ def password_dialog():
+ return prompt_password("Password (hit return if you do not wish to encrypt your wallet):")
+
+ if cmdname == 'restore':
+ text = config.get('text')
+ password = password_dialog() if Wallet.is_seed(text) or Wallet.is_xprv(text) or Wallet.is_private_key(text) else None
+ try:
+ wallet = Wallet.from_text(text, password, storage)
+ except BaseException as e:
+ sys.exit(str(e))
+ if not config.get('offline'):
+ network = Network(config)
+ network.start()
+ wallet.start_threads(network)
+ print_msg("Recovering wallet...")
+ wallet.synchronize()
+ wallet.wait_until_synchronized()
+ 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."
+ print_msg(msg)
+
+ elif cmdname == 'create':
+ password = password_dialog()
+ wallet = Wallet(storage)
+ seed = wallet.make_seed()
+ wallet.add_seed(seed, password)
+ wallet.create_master_keys(password)
+ wallet.create_main_account(password)
+ wallet.synchronize()
+ print_msg("Your wallet generation seed is:\n\"%s\"" % seed)
+ print_msg("Please keep it in a safe place; if you lose it, you will not be able to restore your wallet.")
+
+ elif cmdname == 'deseed':
+ if not wallet.seed:
+ print_msg("Error: This wallet has no seed")
+ else:
+ ns = wallet.storage.path + '.seedless'
+ print_msg("Warning: you are going to create a seedless wallet'\nIt will be saved in '%s'" % ns)
+ if raw_input("Are you sure you want to continue? (y/n) ") in ['y', 'Y', 'yes']:
+ wallet.storage.path = ns
+ wallet.seed = ''
+ wallet.storage.put('seed', '')
+ wallet.use_encryption = False
+ wallet.storage.put('use_encryption', wallet.use_encryption)
+ for k in wallet.imported_keys.keys():
+ wallet.imported_keys[k] = ''
+ wallet.storage.put('imported_keys', wallet.imported_keys)
+ print_msg("Done.")
+ else:
+ print_msg("Action canceled.")
+ wallet.storage.write()
+ sys.exit(0)
+
+ wallet.storage.write()
+ print_msg("Wallet saved in '%s'" % wallet.storage.path)
+ sys.exit(0)
-def init_cmdline(config):
+def init_cmdline(config_options):
+ config = SimpleConfig(config_options)
cmdname = config.get('cmd')
cmd = known_commands[cmdname]
@@ -130,58 +195,11 @@ def init_cmdline(config):
# instanciate wallet for command-line
storage = WalletStorage(config.get_wallet_path())
- if cmd.name in ['create', 'restore']:
- if storage.file_exists:
- sys.exit("Error: Remove the existing wallet first!")
-
- def password_dialog():
- return prompt_password("Password (hit return if you do not wish to encrypt your wallet):")
-
- if cmd.name == 'restore':
- text = config.get('text')
- password = password_dialog() if Wallet.is_seed(text) or Wallet.is_xprv(text) or Wallet.is_private_key(text) else None
- try:
- wallet = Wallet.from_text(text, password, storage)
- except BaseException as e:
- sys.exit(str(e))
- if not config.get('offline'):
- network = Network(config)
- network.start()
- wallet.start_threads(network)
- print_msg("Recovering wallet...")
- wallet.synchronize()
- wallet.wait_until_synchronized()
- 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."
- print_msg(msg)
-
- else:
- password = password_dialog()
- wallet = Wallet(storage)
- seed = wallet.make_seed()
- wallet.add_seed(seed, password)
- wallet.create_master_keys(password)
- wallet.create_main_account(password)
- wallet.synchronize()
- print_msg("Your wallet generation seed is:\n\"%s\"" % seed)
- print_msg("Please keep it in a safe place; if you lose it, you will not be able to restore your wallet.")
-
- wallet.storage.write()
- print_msg("Wallet saved in '%s'" % wallet.storage.path)
- sys.exit(0)
-
if cmd.requires_wallet and not storage.file_exists:
print_msg("Error: Wallet file not found.")
print_msg("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option")
sys.exit(0)
- # create wallet instance
- wallet = Wallet(storage) if cmd.requires_wallet else None
-
- # notify plugins
- always_hook('cmdline_load_wallet', wallet)
-
# important warning
if cmd.name in ['getprivatekeys']:
print_stderr("WARNING: ALL your private keys are secret.")
@@ -189,7 +207,7 @@ def init_cmdline(config):
print_stderr("In particular, DO NOT use 'redeem private key' services proposed by third parties.")
# commands needing password
- if cmd.requires_password and wallet.use_encryption:
+ if cmd.requires_password and storage.get('use_encryption'):
if config.get('password'):
password = config.get('password')
else:
@@ -197,57 +215,48 @@ def init_cmdline(config):
if not password:
print_msg("Error: Password required")
sys.exit(1)
- # check password
- try:
- seed = wallet.check_password(password)
- except InvalidPassword:
- print_msg("Error: This password does not decode this wallet.")
- sys.exit(1)
else:
password = None
- # run the command
- if cmd.name == 'deseed':
- if not wallet.seed:
- print_msg("Error: This wallet has no seed")
- else:
- ns = wallet.storage.path + '.seedless'
- print_msg("Warning: you are going to create a seedless wallet'\nIt will be saved in '%s'" % ns)
- if raw_input("Are you sure you want to continue? (y/n) ") in ['y', 'Y', 'yes']:
- wallet.storage.path = ns
- wallet.seed = ''
- wallet.storage.put('seed', '')
- wallet.use_encryption = False
- wallet.storage.put('use_encryption', wallet.use_encryption)
- for k in wallet.imported_keys.keys():
- wallet.imported_keys[k] = ''
- wallet.storage.put('imported_keys', wallet.imported_keys)
- print_msg("Done.")
- else:
- print_msg("Action canceled.")
- wallet.storage.write()
- sys.exit(0)
+ config_options['password'] = password
- elif cmd.name == 'password':
+ if cmd.name == 'password':
new_password = prompt_password('New password:')
- wallet.update_password(password, new_password)
- wallet.storage.write()
- sys.exit(0)
+ config_options['new_password'] = new_password
- return cmd, password, wallet
+ return cmd, password
-def run_offline_command(config, cmd, wallet, password):
+def run_offline_command(config, config_options):
+ cmdname = config.get('cmd')
+ cmd = known_commands[cmdname]
+ storage = WalletStorage(config.get_wallet_path())
+ wallet = Wallet(storage) if cmd.requires_wallet else None
+ # check password
+ if cmd.requires_password and storage.get('use_encryption'):
+ password = config_options.get('password')
+ try:
+ seed = wallet.check_password(password)
+ except InvalidPassword:
+ print_msg("Error: This password does not decode this wallet.")
+ sys.exit(1)
+ if cmd.requires_network:
+ print_stderr("Warning: running command offline")
+ # notify plugins
+ always_hook('cmdline_load_wallet', wallet)
# arguments passed to function
args = map(lambda x: config.get(x), cmd.params)
# decode json arguments
args = map(json_decode, args)
# options
args += map(lambda x: config.get(x), cmd.options)
- cmd_runner = Commands(config, wallet, None)
- cmd_runner.password = password
+ cmd_runner = Commands(config, wallet, None,
+ password=config_options.get('password'),
+ new_password=config_options.get('new_password'))
func = getattr(cmd_runner, cmd.name)
result = func(*args)
+ # save wallet
+ wallet.storage.write()
return result
@@ -317,18 +326,21 @@ if __name__ == '__main__':
gui_name = config.get('gui', 'qt') if cmd_name == 'gui' else 'cmdline'
plugins = Plugins(config, is_bundle or is_local or is_android, gui_name)
- # run command offline
+ # run non-RPC commands separately
+ if cmd_name in ['create', 'restore', 'deseed']:
+ run_non_RPC(config)
+ sys.exit(0)
+
+ # check if a daemon is running
+ server = get_daemon(config)
+
+ # if no daemon is running, run the command offline
if cmd_name not in ['gui', 'daemon']:
- cmd, password, wallet = init_cmdline(config)
- if not (cmd.requires_network or cmd.requires_wallet) or config.get('offline'):
- result = run_offline_command(config, cmd, wallet, password)
+ init_cmdline(config_options)
+ if server is None: #not (cmd.requires_network or cmd.requires_wallet) or config.get('offline'):
+ result = run_offline_command(config, config_options)
print_msg(json_encode(result))
- wallet.storage.write()
sys.exit(0)
- else:
- config_options['password'] = password
-
- server = get_daemon(config)
# daemon is running
if server is not None:
diff --git a/lib/commands.py b/lib/commands.py
@@ -74,21 +74,22 @@ def command(s):
class Commands:
- def __init__(self, config, wallet, network, callback = None):
+ def __init__(self, config, wallet, network, callback = None, password=None, new_password=None):
self.config = config
self.wallet = wallet
self.network = network
self._callback = callback
- self.password = None
+ self._password = password
+ self.new_password = new_password
self.contacts = contacts.Contacts(self.config)
def _run(self, method, args, password_getter):
cmd = known_commands[method]
if cmd.requires_password and self.wallet.use_encryption:
- self.password = apply(password_getter,())
+ self._password = apply(password_getter,())
f = getattr(self, method)
result = f(*args)
- self.password = None
+ self._password = None
if self._callback:
apply(self._callback, ())
return result
@@ -120,7 +121,9 @@ class Commands:
@command('wp')
def password(self):
"""Change wallet password. """
- raise BaseException('Not a JSON-RPC command')
+ self.wallet.update_password(self._password, self.new_password)
+ self.wallet.storage.write()
+ return {'password':self.wallet.use_encryption}
@command('')
def getconfig(self, key):
@@ -200,7 +203,7 @@ class Commands:
outputs = map(lambda x: ('address', x[0], int(COIN*x[1])), outputs.items())
tx = Transaction.from_io(tx_inputs, outputs)
if not unsigned:
- self.wallet.sign_transaction(tx, self.password)
+ self.wallet.sign_transaction(tx, self._password)
return tx.as_dict()
@command('wp')
@@ -212,7 +215,7 @@ class Commands:
pubkey = bitcoin.public_key_from_private_key(privkey)
t.sign({pubkey:privkey})
else:
- self.wallet.sign_transaction(t, self.password)
+ self.wallet.sign_transaction(t, self._password)
return t.as_dict()
@command('')
@@ -250,7 +253,7 @@ class Commands:
"""Get private keys of addresses. You may pass a single wallet address, or a list of wallet addresses."""
is_list = type(address) is list
domain = address if is_list else [address]
- out = [self.wallet.get_private_key(address, self.password) for address in domain]
+ out = [self.wallet.get_private_key(address, self._password) for address in domain]
return out if is_list else out[0]
@command('w')
@@ -334,19 +337,19 @@ class Commands:
@command('wp')
def getmasterprivate(self):
"""Get master private key. Return your wallet\'s master private key"""
- return str(self.wallet.get_master_private_key(self.wallet.root_name, self.password))
+ return str(self.wallet.get_master_private_key(self.wallet.root_name, self._password))
@command('wp')
def getseed(self):
"""Get seed phrase. Print the generation seed of your wallet."""
- s = self.wallet.get_mnemonic(self.password)
+ s = self.wallet.get_mnemonic(self._password)
return s.encode('utf8')
@command('wp')
def importprivkey(self, privkey):
"""Import a private key. """
try:
- addr = self.wallet.import_key(privkey, self.password)
+ addr = self.wallet.import_key(privkey, self._password)
out = "Keypair imported: " + addr
except Exception as e:
out = "Error: " + str(e)
@@ -377,7 +380,7 @@ class Commands:
def signmessage(self, address, message):
"""Sign a message with a key. Use quotes if your message contains
whitespaces"""
- sig = self.wallet.sign_message(address, message, self.password)
+ sig = self.wallet.sign_message(address, message, self._password)
return base64.b64encode(sig)
@command('')
@@ -415,7 +418,7 @@ class Commands:
tx = self.wallet.make_unsigned_transaction(coins, final_outputs, self.config, fee, change_addr)
str(tx) #this serializes
if not unsigned:
- self.wallet.sign_transaction(tx, self.password)
+ self.wallet.sign_transaction(tx, self._password)
return tx
@command('wpn')
@@ -522,7 +525,7 @@ class Commands:
@command('wp')
def decrypt(self, pubkey, encrypted):
"""Decrypt a message encrypted with a public key."""
- return self.wallet.decrypt_message(pubkey, encrypted, self.password)
+ return self.wallet.decrypt_message(pubkey, encrypted, self._password)
def _format_request(self, out):
pr_str = {
@@ -587,7 +590,7 @@ class Commands:
if not alias:
raise BaseException('No alias in your configuration')
alias_addr = self.contacts.resolve(alias)['address']
- self.wallet.sign_payment_request(address, alias, alias_addr, self.password)
+ self.wallet.sign_payment_request(address, alias, alias_addr, self._password)
@command('w')
def rmrequest(self, address):
diff --git a/lib/daemon.py b/lib/daemon.py
@@ -135,7 +135,6 @@ class Daemon(DaemonThread):
return wallet
def run_cmdline(self, config_options):
- password = config_options.get('password')
config = SimpleConfig(config_options)
cmdname = config.get('cmd')
cmd = known_commands[cmdname]
@@ -146,8 +145,9 @@ class Daemon(DaemonThread):
args = map(json_decode, args)
# options
args += map(lambda x: config.get(x), cmd.options)
- cmd_runner = Commands(config, wallet, self.network)
- cmd_runner.password = password
+ cmd_runner = Commands(config, wallet, self.network,
+ password=config_options.get('password'),
+ new_password=config_options.get('new_password'))
func = getattr(cmd_runner, cmd.name)
result = func(*args)
return result