URI: 
       tseparation between RPC and non-RPC commands. - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit acbe67fd1f4d3bd0755707ee90b97295b5d7ff99
   DIR parent 62201b37f59b8c10828958d2326e48f068d98449
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Wed, 23 Dec 2015 10:54:31 +0100
       
       separation between RPC and non-RPC commands.
       
       Diffstat:
         M electrum                            |     198 ++++++++++++++++---------------
         M lib/commands.py                     |      33 +++++++++++++++++--------------
         M lib/daemon.py                       |       6 +++---
       
       3 files changed, 126 insertions(+), 111 deletions(-)
       ---
   DIR diff --git a/electrum b/electrum
       t@@ -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]
        
       t@@ -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.")
       t@@ -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:
       t@@ -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
        
        
       t@@ -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:
   DIR diff --git a/lib/commands.py b/lib/commands.py
       t@@ -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
       t@@ -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):
       t@@ -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')
       t@@ -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('')
       t@@ -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')
       t@@ -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)
       t@@ -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('')
       t@@ -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')
       t@@ -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 = {
       t@@ -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):
   DIR diff --git a/lib/daemon.py b/lib/daemon.py
       t@@ -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]
       t@@ -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