From 9e225d12698f617f986a866f62c6b0039a333872 Mon Sep 17 00:00:00 2001 From: ThomasV Date: Sat, 31 May 2025 11:45:57 +0200 Subject: [PATCH] Replace config GUI_LAST_WALLET with CURRENT_WALLET - CURRENT_WALLET is set when a single wallet is loaded in memory, and it remains set after Electrum stops running. - If several wallets are loaded at the same time, CURRENT_WALLET is unset, and RPCs must specify the wallet explicitly (using --wallet for the CLI) - The fallback to 'default_wallet' essentially only applies when creating a new wallet file --- electrum/commands.py | 3 ++- electrum/daemon.py | 9 ++++++++- electrum/gui/qml/qedaemon.py | 2 +- electrum/gui/qt/__init__.py | 5 +---- electrum/gui/stdio.py | 2 +- electrum/gui/text.py | 4 ++-- electrum/simple_config.py | 34 ++++++++++------------------------ run_electrum | 21 ++++++++++++++------- tests/regtest/regtest.sh | 2 +- 9 files changed, 40 insertions(+), 42 deletions(-) diff --git a/electrum/commands.py b/electrum/commands.py index ae7fb98b7..111d0cf0c 100644 --- a/electrum/commands.py +++ b/electrum/commands.py @@ -246,7 +246,7 @@ class Commands(Logger): 'connected': self.network.is_connected(), 'auto_connect': net_params.auto_connect, 'version': ELECTRUM_VERSION, - 'default_wallet': self.config.get_wallet_path(), + 'current_wallet': self.config.get_wallet_path(use_fallback=False), 'fee_estimates': self.network.fee_estimates.get_data() } return response @@ -278,6 +278,7 @@ class Commands(Logger): if wallet is None: raise UserFacingException('could not load wallet') run_hook('load_wallet', wallet, None) + return wallet_path @command('n') async def close_wallet(self, wallet_path=None): diff --git a/electrum/daemon.py b/electrum/daemon.py index 86425d50b..253756879 100644 --- a/electrum/daemon.py +++ b/electrum/daemon.py @@ -342,7 +342,7 @@ class CommandsServer(AuthenticatedServer): if config_options.get(SimpleConfig.NETWORK_OFFLINE.key()) and not self.config.NETWORK_OFFLINE: raise UserFacingException( "error: current GUI is running online, so it cannot open a new wallet offline.") - path = config_options.get('wallet_path') or self.config.get_wallet_path(use_gui_last_wallet=True) + path = config_options.get('wallet_path') or self.config.get_wallet_path() self.daemon.gui_object.new_window(path, config_options.get('url')) return True else: @@ -477,9 +477,15 @@ class Daemon(Logger): coro = wallet.lnworker.lnwatcher.trigger_callbacks(requires_synchronizer=False) asyncio.run_coroutine_threadsafe(coro, self.asyncio_loop) self.add_wallet(wallet) + self.update_current_wallet() self.update_recently_opened_wallets(path) return wallet + def update_current_wallet(self): + if not self._wallets: + return + self.config.CURRENT_WALLET = list(self._wallets.keys())[0] if len(self._wallets) == 1 else None + @staticmethod @profiler def _load_wallet( @@ -540,6 +546,7 @@ class Daemon(Logger): wallet = self._wallets.pop(wallet_key, None) if not wallet: return False + self.update_current_wallet() await wallet.stop() return True diff --git a/electrum/gui/qml/qedaemon.py b/electrum/gui/qml/qedaemon.py index 5791f31de..238deaa44 100644 --- a/electrum/gui/qml/qedaemon.py +++ b/electrum/gui/qml/qedaemon.py @@ -178,7 +178,7 @@ class QEDaemon(AuthMixin, QObject): if path is None: self._path = self.daemon.config.get('wallet_path') # command line -w option if self._path is None: - self._path = self.daemon.config.GUI_LAST_WALLET + self._path = self.daemon.config.CURRENT_WALLET else: self._path = path if self._path is None: diff --git a/electrum/gui/qt/__init__.py b/electrum/gui/qt/__init__.py index 5907ded6f..4d12cfcba 100644 --- a/electrum/gui/qt/__init__.py +++ b/electrum/gui/qt/__init__.py @@ -488,9 +488,6 @@ class ElectrumGui(BaseElectrumGui, Logger): if window in self.windows: self.windows.remove(window) self.build_tray_menu() - # save wallet path of last open window - if not self.windows: - self.config.save_last_wallet(window.wallet) run_hook('on_close_window', window) if window.should_stop_wallet_on_close: self.daemon.stop_wallet(window.wallet.storage.path) @@ -555,7 +552,7 @@ class ElectrumGui(BaseElectrumGui, Logger): return # start wizard to select/create wallet self.timer.start() - path = self.config.get_wallet_path(use_gui_last_wallet=True) + path = self.config.get_wallet_path() try: if not self.start_new_window(path, self.config.get('url'), app_is_starting=True): return diff --git a/electrum/gui/stdio.py b/electrum/gui/stdio.py index 1871c726e..6b188e4d9 100644 --- a/electrum/gui/stdio.py +++ b/electrum/gui/stdio.py @@ -26,7 +26,7 @@ class ElectrumGui(BaseElectrumGui, EventListener): def __init__(self, *, config, daemon, plugins): BaseElectrumGui.__init__(self, config=config, daemon=daemon, plugins=plugins) self.network = daemon.network - storage = WalletStorage(config.get_wallet_path(use_gui_last_wallet=True)) + storage = WalletStorage(config.get_wallet_path()) if not storage.file_exists(): print("Wallet not found. try 'electrum create'") exit() diff --git a/electrum/gui/text.py b/electrum/gui/text.py index 4b4932567..52b388970 100644 --- a/electrum/gui/text.py +++ b/electrum/gui/text.py @@ -62,7 +62,7 @@ class ElectrumGui(BaseElectrumGui, EventListener): def __init__(self, *, config: 'SimpleConfig', daemon: 'Daemon', plugins: 'Plugins'): BaseElectrumGui.__init__(self, config=config, daemon=daemon, plugins=plugins) self.network = daemon.network - storage = WalletStorage(config.get_wallet_path(use_gui_last_wallet=True)) + storage = WalletStorage(config.get_wallet_path()) password = None if not storage.file_exists(): print("Wallet not found. try 'electrum create'") @@ -70,7 +70,7 @@ class ElectrumGui(BaseElectrumGui, EventListener): if storage.is_encrypted(): password = getpass.getpass('Password:', stream=None) del storage - self.wallet = self.daemon.load_wallet(config.get_wallet_path(use_gui_last_wallet=True), password) + self.wallet = self.daemon.load_wallet(config.get_wallet_path(), password) self.contacts = self.wallet.contacts locale.setlocale(locale.LC_ALL, '') diff --git a/electrum/simple_config.py b/electrum/simple_config.py index a20eb350b..5b7d975b5 100644 --- a/electrum/simple_config.py +++ b/electrum/simple_config.py @@ -458,27 +458,18 @@ class SimpleConfig(Logger): else: return self.WALLET_BACKUP_DIRECTORY - def get_wallet_path(self, *, use_gui_last_wallet=False): - """Set the path of the wallet.""" - + def get_wallet_path(self, *, use_fallback=True) -> Optional[str]: + """Returns the wallet path.""" # command line -w option if self.get('wallet_path'): return os.path.join(self.get('cwd', ''), self.get('wallet_path')) - - if use_gui_last_wallet: - path = self.GUI_LAST_WALLET - if path and os.path.exists(path): - return path - - new_path = self.get_fallback_wallet_path() - - # TODO: this can be removed by now - # default path in pre 1.9 versions - old_path = os.path.join(self.path, "electrum.dat") - if os.path.exists(old_path) and not os.path.exists(new_path): - os.rename(old_path, new_path) - - return new_path + # current wallet + path = self.CURRENT_WALLET + if path and os.path.exists(path): + return path + if use_fallback: + return self.get_fallback_wallet_path() + return def get_datadir_wallet_path(self): util.assert_datadir_available(self.path) @@ -496,11 +487,6 @@ class SimpleConfig(Logger): def get_session_timeout(self): return self.HWD_SESSION_TIMEOUT - def save_last_wallet(self, wallet): - if self.get('wallet_path') is None: - path = wallet.storage.path - self.GUI_LAST_WALLET = path - def get_video_device(self): device = self.VIDEO_DEVICE_PATH if device == 'default': @@ -762,7 +748,7 @@ Warning: setting this to too low will result in lots of payment failures."""), RPC_SOCKET_FILEPATH = ConfigVar('rpcsockpath', default=None, type_=str) GUI_NAME = ConfigVar('gui', default='qt', type_=str) - GUI_LAST_WALLET = ConfigVar('gui_last_wallet', default=None, type_=str) + CURRENT_WALLET = ConfigVar('current_wallet', default=None, type_=str) GUI_QT_COLOR_THEME = ConfigVar( 'qt_gui_color_theme', default='default', type_=str, diff --git a/run_electrum b/run_electrum index 008ff5815..b04fc0d8a 100755 --- a/run_electrum +++ b/run_electrum @@ -138,8 +138,12 @@ def init_cmdline(config_options, wallet_path, *, rpcserver: bool, config: 'Simpl if cmdname in ['payto', 'paytomany'] and config.get('broadcast'): cmd.requires_network = True + if cmd.requires_wallet and not wallet_path: + print_msg("wallet path not provided.") + sys_exit(1) + # instantiate wallet for command-line - storage = WalletStorage(wallet_path) + storage = WalletStorage(wallet_path) if wallet_path else None if cmd.requires_wallet and not storage.file_exists(): print_msg("Error: Wallet file not found.") @@ -215,14 +219,14 @@ def get_password_for_hw_device_encrypted_storage(plugins: 'Plugins') -> str: sys.exit(0) -async def run_offline_command(config, config_options, plugins: 'Plugins'): +async def run_offline_command(config, config_options, wallet_path, plugins: 'Plugins'): cmdname = config.get('cmd') cmd = known_commands[cmdname] password = config_options.get('password') if 'wallet_path' in cmd.options and config_options.get('wallet_path') is None: - config_options['wallet_path'] = config.get_wallet_path() + config_options['wallet_path'] = wallet_path if cmd.requires_wallet: - storage = WalletStorage(config.get_wallet_path()) + storage = WalletStorage(wallet_path) if storage.is_encrypted(): if storage.is_encrypted_with_hw_device(): password = get_password_for_hw_device_encrypted_storage(plugins) @@ -512,7 +516,6 @@ def handle_cmd(*, cmdname: str, config: 'SimpleConfig', config_options: dict): sys_exit(1) elif cmdname == 'daemon': - configure_logging(config) fd = daemon.get_file_descriptor(config) if fd is not None: @@ -528,7 +531,11 @@ def handle_cmd(*, cmdname: str, config: 'SimpleConfig', config_options: dict): # command line configure_logging(config, log_to_file=False) # don't spam logfiles for each client-side RPC, but support "-v" cmd = known_commands[cmdname] - wallet_path = config.get_wallet_path() + use_fallback = (cmdname in ['create', 'restore', 'load_wallet']) + wallet_path = config.get_wallet_path(use_fallback=use_fallback) + if cmd.requires_wallet and not wallet_path: + print_stderr('wallet path not provided') + sys_exit(1) if not config.NETWORK_OFFLINE: init_cmdline(config_options, wallet_path, rpcserver=True, config=config) timeout = config.CLI_TIMEOUT @@ -568,7 +575,7 @@ def handle_cmd(*, cmdname: str, config: 'SimpleConfig', config_options: dict): sys_exit(1) init_cmdline(config_options, wallet_path, rpcserver=False, config=config) plugins = Plugins(config, 'cmdline') - coro = run_offline_command(config, config_options, plugins) + coro = run_offline_command(config, config_options, wallet_path, plugins) fut = asyncio.run_coroutine_threadsafe(coro, loop) try: try: diff --git a/tests/regtest/regtest.sh b/tests/regtest/regtest.sh index f85ffc172..c8a53bf83 100755 --- a/tests/regtest/regtest.sh +++ b/tests/regtest/regtest.sh @@ -112,7 +112,7 @@ if [[ $1 == "init" ]]; then $agent setconfig --offline test_force_disable_mpp True echo "funding $2" # note: changing the funding amount affects all tests, as they rely on "wait_for_balance" - $bitcoin_cli sendtoaddress $($agent getunusedaddress -o) 1 + $bitcoin_cli sendtoaddress $($agent getunusedaddress -o -w "/tmp/$2/regtest/wallets/default_wallet") 1 fi if [[ $1 == "setconfig" ]]; then