URI: 
       tcommands: make 'wallet'-mangling in decorator less obscure, and fixes - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 9baaf1afda3181cd511fda83c0be426a85c02abd
   DIR parent 21e637f5438e32dd0f6fdae17b0c908c5ab4d24b
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Thu, 14 May 2020 16:33:02 +0200
       
       commands: make 'wallet'-mangling in decorator less obscure, and fixes
       
       - some commands expect a 'wallet_path' arg, while others expect 'wallet'
       - 'wallet_path' in the end is supposed to be a str,
         'wallet' in the end is supposed to be an Optional[Abstract_Wallet]
       - initially, in the decorator, 'wallet' can be a str, in which case
         the decorator replaces it with an Abstract_Wallet (from the daemon)
       - Previously the decorator sometimes converted 'wallet_path' to 'wallet'.
         This was because when called from the CLI it was always given 'wallet_path' (and never 'wallet),
         while when called from JSON-RPC it was given either 'wallet' or 'wallet_path' (depending on command).
         Now, the CLI also behaves as JSON-RPC, and hence 'wallet_path' and 'wallet' are fully separate.
       - A bug is fixed where, when a command that only optionally takes a 'wallet' (such as gettransaction),
         was called from the JSON-RPC with the arg present, it raised; and when called from CLI with the arg present
         the arg was not actually passed to the command.
       - A bug is fixed where if one command calls another command (that both take a 'wallet'),
         it would raise (due to assuming 'wallet' is str and needs to be converted to Abstract_Wallet).
         This fixes #6154.
       
       -----
       
       $ ./run_electrum --testnet daemon -d
       $ ./run_electrum --testnet load_wallet -w ~/.electrum/testnet/wallets/default_wallet
       
       $ curl --data-binary '{"id":"curltext","jsonrpc":"2.0","method":"gettransaction","params":{"txid":"9f43ff71ea2594873e4e7d15e61254a3661ff2df1af76325c854d9aa199550ce"}}' http://user:pass@127.0.0.1:7777
       {"jsonrpc": "2.0", "result": "0200000001caaac6b5eb916e3067d0224f942fb331ce1dcfb4031cfb479e7941dcf95e409801000000fdfe0000483045022100e2a508bb78c2172eb03f081a342454ba1d24669e959700973b1a742a4fedd0c302203174e06feda265031cf9aa0364d4a4eafb71b0c0a62e76be7795cfbb307b677a01483045022100d0e14564838fac754395158741d64c73da2b86e7900dfdc6a63c7492b232ba130220778e7e7c21d94ebcd340057302aeff7e9a797a3aa3e0ac4884e9ff27339ea6e9014c69522102091f0b4d8ab30016a5d1c088249e02883fad8160f06fa53588ad8598650a3e6221035f2f8263bb3608d6cc4ee03bd4cb8d65c4d70af71049f05fbfee4978832a1fd22103fe42dab58718ea0413f7c8de693cdeee22ce19b1dc34c0bbdd7a48245465c5a253aefdffffff01cb9f0700000000001976a914c13fd6294d1be7b9410a5538f4b4ef10fc594ee788ac802c1800", "id": "curltext"}
       
       $ curl --data-binary '{"id":"curltext","jsonrpc":"2.0","method":"gettransaction","params":{"txid":"9f43ff71ea2594873e4e7d15e61254a3661ff2df1af76325c854d9aa199550ce", "wallet":"~/.electrum/testnet/wallets/default_wallet"}}' http://user:pass@127.0.0.1:7777
       {"jsonrpc": "2.0", "error": {"code": -32000, "message": "'str' object has no attribute 'db'"}, "id": "curltext"}
       
       Diffstat:
         M electrum/commands.py                |      36 +++++++++++++++++++++-----------
         M electrum/daemon.py                  |       6 ++++--
       
       2 files changed, 28 insertions(+), 14 deletions(-)
       ---
   DIR diff --git a/electrum/commands.py b/electrum/commands.py
       t@@ -106,6 +106,16 @@ class Command:
                    self.options = []
                    self.defaults = []
        
       +        # sanity checks
       +        if self.requires_password:
       +            assert self.requires_wallet
       +        for varname in ('wallet_path', 'wallet'):
       +            if varname in varnames:
       +                assert varname in self.options
       +        assert not ('wallet_path' in varnames and 'wallet' in varnames)
       +        if self.requires_wallet:
       +            assert 'wallet' in varnames
       +
        
        def command(s):
            def decorator(func):
       t@@ -119,18 +129,20 @@ def command(s):
                    password = kwargs.get('password')
                    daemon = cmd_runner.daemon
                    if daemon:
       -                if (cmd.requires_wallet or 'wallet_path' in cmd.options) and kwargs.get('wallet_path') is None:
       -                    # using JSON-RPC, sometimes the "wallet" kwarg needs to be used to specify a wallet
       -                    kwargs['wallet_path'] = kwargs.pop('wallet', None) or daemon.config.get_wallet_path()
       -                if cmd.requires_wallet:
       -                    wallet_path = kwargs.pop('wallet_path')
       -                    wallet = daemon.get_wallet(wallet_path)
       -                    if wallet is None:
       -                        raise Exception('wallet not loaded')
       -                    kwargs['wallet'] = wallet
       -            else:
       -                # we are offline. the wallet must have been passed if required
       -                wallet = kwargs.get('wallet')
       +                if 'wallet_path' in cmd.options and kwargs.get('wallet_path') is None:
       +                    kwargs['wallet_path'] = daemon.config.get_wallet_path()
       +                if cmd.requires_wallet and kwargs.get('wallet') is None:
       +                    kwargs['wallet'] = daemon.config.get_wallet_path()
       +                if 'wallet' in cmd.options:
       +                    wallet_path = kwargs.get('wallet', None)
       +                    if isinstance(wallet_path, str):
       +                        wallet = daemon.get_wallet(wallet_path)
       +                        if wallet is None:
       +                            raise Exception('wallet not loaded')
       +                        kwargs['wallet'] = wallet
       +            wallet = kwargs.get('wallet')  # type: Optional[Abstract_Wallet]
       +            if cmd.requires_wallet and not wallet:
       +                raise Exception('wallet not loaded')
                    if cmd.requires_password and password is None and wallet.has_password():
                        raise Exception('Password required')
                    return await func(*args, **kwargs)
   DIR diff --git a/electrum/daemon.py b/electrum/daemon.py
       t@@ -251,8 +251,10 @@ class CommandsServer(AuthenticatedServer):
                kwargs = {}
                for x in cmd.options:
                    kwargs[x] = config_options.get(x)
       -        if cmd.requires_wallet:
       +        if 'wallet_path' in cmd.options:
                    kwargs['wallet_path'] = config_options.get('wallet_path')
       +        elif 'wallet' in cmd.options:
       +            kwargs['wallet'] = config_options.get('wallet_path')
                func = getattr(self.cmd_runner, cmd.name)
                # fixme: not sure how to retrieve message in jsonrpcclient
                try:
       t@@ -477,7 +479,7 @@ class Daemon(Logger):
                path = standardize_path(path)
                self._wallets[path] = wallet
        
       -    def get_wallet(self, path: str) -> Abstract_Wallet:
       +    def get_wallet(self, path: str) -> Optional[Abstract_Wallet]:
                path = standardize_path(path)
                return self._wallets.get(path)