2013-09-11 13:43:37 +02:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
#
|
|
|
|
|
# Electrum - lightweight Bitcoin client
|
|
|
|
|
# Copyright (C) 2012 thomasv@gitorious
|
|
|
|
|
#
|
2016-02-23 11:36:42 +01:00
|
|
|
# Permission is hereby granted, free of charge, to any person
|
|
|
|
|
# obtaining a copy of this software and associated documentation files
|
|
|
|
|
# (the "Software"), to deal in the Software without restriction,
|
|
|
|
|
# including without limitation the rights to use, copy, modify, merge,
|
|
|
|
|
# publish, distribute, sublicense, and/or sell copies of the Software,
|
|
|
|
|
# and to permit persons to whom the Software is furnished to do so,
|
|
|
|
|
# subject to the following conditions:
|
2013-09-11 13:43:37 +02:00
|
|
|
#
|
2016-02-23 11:36:42 +01:00
|
|
|
# The above copyright notice and this permission notice shall be
|
|
|
|
|
# included in all copies or substantial portions of the Software.
|
2013-09-11 13:43:37 +02:00
|
|
|
#
|
2016-02-23 11:36:42 +01:00
|
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
|
|
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
|
|
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
|
# SOFTWARE.
|
2013-09-11 13:43:37 +02:00
|
|
|
|
2019-02-11 20:21:24 +01:00
|
|
|
import os
|
2014-08-06 13:15:53 +02:00
|
|
|
import signal
|
2017-11-12 22:54:04 -06:00
|
|
|
import sys
|
2018-11-14 22:39:49 +01:00
|
|
|
import threading
|
2022-06-30 20:27:03 +02:00
|
|
|
from typing import Optional, TYPE_CHECKING, List, Sequence
|
2017-11-12 22:54:04 -06:00
|
|
|
|
2013-09-11 13:43:37 +02:00
|
|
|
try:
|
2024-09-05 16:20:01 +00:00
|
|
|
import PyQt6
|
|
|
|
|
import PyQt6.QtGui
|
2022-04-11 16:53:25 +02:00
|
|
|
except Exception as e:
|
2023-09-24 02:31:25 +00:00
|
|
|
from electrum import GuiImportError
|
2022-04-11 16:53:25 +02:00
|
|
|
raise GuiImportError(
|
2024-09-05 16:20:01 +00:00
|
|
|
"Error: Could not import PyQt6. On Linux systems, "
|
|
|
|
|
"you may try 'sudo apt-get install python3-pyqt6'") from e
|
2013-09-11 13:43:37 +02:00
|
|
|
|
2024-09-05 16:20:01 +00:00
|
|
|
from PyQt6.QtGui import QGuiApplication
|
|
|
|
|
from PyQt6.QtWidgets import QApplication, QSystemTrayIcon, QWidget, QMenu, QMessageBox, QDialog
|
|
|
|
|
from PyQt6.QtCore import QObject, pyqtSignal, QTimer, Qt
|
2024-10-07 12:55:36 +02:00
|
|
|
|
2024-09-05 16:20:01 +00:00
|
|
|
import PyQt6.QtCore as QtCore
|
2013-09-11 13:43:37 +02:00
|
|
|
|
2022-03-21 15:50:28 +01:00
|
|
|
try:
|
|
|
|
|
# Preload QtMultimedia at app start, if available.
|
|
|
|
|
# We use QtMultimedia on some platforms for camera-handling, and
|
2024-09-05 16:20:01 +00:00
|
|
|
# lazy-loading it later led to some crashes. Maybe due to bugs in PyQt. (see #7725)
|
|
|
|
|
from PyQt6.QtMultimedia import QMediaDevices; del QMediaDevices
|
2022-03-21 15:50:28 +01:00
|
|
|
except ImportError as e:
|
|
|
|
|
pass # failure is ok; it is an optional dependency.
|
|
|
|
|
|
2024-09-17 15:57:43 +00:00
|
|
|
if sys.platform == "linux" and os.environ.get("APPIMAGE"):
|
|
|
|
|
# For AppImage, we default to xcb qt backend, for better support of older system.
|
|
|
|
|
# qt6 normally defaults to QT_QPA_PLATFORM=wayland instead of QT_QPA_PLATFORM=xcb.
|
|
|
|
|
# However, the wayland QPA plugin requires libwayland-client0>=1.19, which is too new
|
|
|
|
|
# for debian 11 or ubuntu 20.04. So instead, we default to the X11 integration (and not wayland).
|
|
|
|
|
# see https://bugreports.qt.io/browse/QTBUG-114635
|
|
|
|
|
os.environ.setdefault("QT_QPA_PLATFORM", "xcb")
|
|
|
|
|
|
2014-09-08 11:02:55 +02:00
|
|
|
from electrum.i18n import _, set_language
|
2018-07-11 17:38:47 +02:00
|
|
|
from electrum.plugin import run_hook
|
qt init: on exc, let crash reporter appear instead of silently dying
related: https://github.com/spesmilo/electrum/issues/7390
```
20210706T091826.513398Z | ERROR | __main__ | daemon.run_gui errored
Traceback (most recent call last):
File "run_electrum", line 407, in handle_cmd
File "electrum\daemon.py", line 584, in run_gui
File "electrum\gui\qt\__init__.py", line 414, in main
File "electrum\gui\qt\__init__.py", line 291, in wrapper
File "electrum\gui\qt\__init__.py", line 316, in start_new_window
File "electrum\gui\qt\__init__.py", line 361, in _start_wizard_to_select_or_create_wallet
File "electrum\wallet_db.py", line 73, in __init__
File "electrum\wallet_db.py", line 106, in load_data
File "electrum\util.py", line 412, in <lambda>
File "electrum\util.py", line 408, in do_profile
File "electrum\wallet_db.py", line 175, in upgrade
File "electrum\wallet_db.py", line 540, in _convert_version_24
ValueError: too many values to unpack (expected 2)
```
2021-07-07 19:19:43 +02:00
|
|
|
from electrum.util import (UserCancelled, profiler, send_exception_to_crash_reporter,
|
2025-01-23 12:58:28 +01:00
|
|
|
WalletFileException, get_new_wallet_name, InvalidPassword)
|
2019-03-04 02:08:23 +01:00
|
|
|
from electrum.wallet import Wallet, Abstract_Wallet
|
2025-01-23 12:58:28 +01:00
|
|
|
from electrum.wallet_db import WalletRequiresSplit, WalletRequiresUpgrade, WalletUnfinished
|
2019-04-26 18:52:26 +02:00
|
|
|
from electrum.logging import Logger
|
2021-11-05 20:21:50 +01:00
|
|
|
from electrum.gui import BaseElectrumGui
|
2023-05-24 17:41:44 +00:00
|
|
|
from electrum.simple_config import SimpleConfig
|
2023-09-24 02:31:25 +00:00
|
|
|
from electrum.wizard import WizardViewState
|
|
|
|
|
from electrum.keystore import load_keystore
|
2024-10-08 00:04:20 +02:00
|
|
|
from electrum.bip32 import is_xprv
|
2017-01-22 21:25:24 +03:00
|
|
|
|
2024-10-07 12:55:36 +02:00
|
|
|
from electrum.gui.common_qt.i18n import ElectrumTranslator
|
|
|
|
|
|
2023-08-28 11:50:24 +02:00
|
|
|
from .util import read_QIcon, ColorScheme, custom_message_box, MessageBoxMixin, WWLabel
|
2017-01-22 21:25:24 +03:00
|
|
|
from .main_window import ElectrumWindow
|
2017-03-15 12:13:20 +01:00
|
|
|
from .network_dialog import NetworkDialog
|
2019-05-05 02:14:07 +02:00
|
|
|
from .stylesheet_patcher import patch_qt_stylesheet
|
2019-05-07 09:10:23 +02:00
|
|
|
from .lightning_dialog import LightningDialog
|
qt init: on exc, let crash reporter appear instead of silently dying
related: https://github.com/spesmilo/electrum/issues/7390
```
20210706T091826.513398Z | ERROR | __main__ | daemon.run_gui errored
Traceback (most recent call last):
File "run_electrum", line 407, in handle_cmd
File "electrum\daemon.py", line 584, in run_gui
File "electrum\gui\qt\__init__.py", line 414, in main
File "electrum\gui\qt\__init__.py", line 291, in wrapper
File "electrum\gui\qt\__init__.py", line 316, in start_new_window
File "electrum\gui\qt\__init__.py", line 361, in _start_wizard_to_select_or_create_wallet
File "electrum\wallet_db.py", line 73, in __init__
File "electrum\wallet_db.py", line 106, in load_data
File "electrum\util.py", line 412, in <lambda>
File "electrum\util.py", line 408, in do_profile
File "electrum\wallet_db.py", line 175, in upgrade
File "electrum\wallet_db.py", line 540, in _convert_version_24
ValueError: too many values to unpack (expected 2)
```
2021-07-07 19:19:43 +02:00
|
|
|
from .exception_window import Exception_Hook
|
2023-09-24 02:31:25 +00:00
|
|
|
from .wizard.server_connect import QEServerConnectWizard
|
|
|
|
|
from .wizard.wallet import QENewWalletWizard
|
2013-09-11 13:43:37 +02:00
|
|
|
|
2019-09-09 22:19:36 +02:00
|
|
|
if TYPE_CHECKING:
|
|
|
|
|
from electrum.daemon import Daemon
|
|
|
|
|
from electrum.plugin import Plugins
|
|
|
|
|
|
2013-09-11 13:43:37 +02:00
|
|
|
|
|
|
|
|
class OpenFileEventFilter(QObject):
|
2022-06-30 20:27:03 +02:00
|
|
|
def __init__(self, windows: Sequence[ElectrumWindow]):
|
2013-09-11 13:43:37 +02:00
|
|
|
self.windows = windows
|
|
|
|
|
super(OpenFileEventFilter, self).__init__()
|
|
|
|
|
|
|
|
|
|
def eventFilter(self, obj, event):
|
2024-09-05 16:20:01 +00:00
|
|
|
if event.type() == QtCore.QEvent.Type.FileOpen:
|
2013-09-11 13:43:37 +02:00
|
|
|
if len(self.windows) >= 1:
|
2023-03-19 13:32:43 +01:00
|
|
|
self.windows[0].set_payment_identifier(event.url().toString())
|
2013-09-11 13:43:37 +02:00
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
2017-09-23 05:54:38 +02:00
|
|
|
class QElectrumApplication(QApplication):
|
|
|
|
|
new_window_signal = pyqtSignal(str, object)
|
2021-11-05 17:24:03 +01:00
|
|
|
quit_signal = pyqtSignal()
|
2022-04-29 16:56:19 +02:00
|
|
|
refresh_tabs_signal = pyqtSignal()
|
|
|
|
|
refresh_amount_edits_signal = pyqtSignal()
|
|
|
|
|
update_status_signal = pyqtSignal()
|
|
|
|
|
update_fiat_signal = pyqtSignal()
|
|
|
|
|
alias_received_signal = pyqtSignal()
|
2017-09-23 05:54:38 +02:00
|
|
|
|
|
|
|
|
|
2021-11-05 20:21:50 +01:00
|
|
|
class ElectrumGui(BaseElectrumGui, Logger):
|
2013-09-11 13:43:37 +02:00
|
|
|
|
2021-04-03 19:17:32 +02:00
|
|
|
network_dialog: Optional['NetworkDialog']
|
|
|
|
|
lightning_dialog: Optional['LightningDialog']
|
|
|
|
|
|
2018-11-16 14:39:22 +01:00
|
|
|
@profiler
|
2021-11-05 20:21:50 +01:00
|
|
|
def __init__(self, *, config: 'SimpleConfig', daemon: 'Daemon', plugins: 'Plugins'):
|
|
|
|
|
BaseElectrumGui.__init__(self, config=config, daemon=daemon, plugins=plugins)
|
2019-04-26 18:52:26 +02:00
|
|
|
Logger.__init__(self)
|
2020-05-14 18:49:18 +02:00
|
|
|
self.logger.info(f"Qt GUI starting up... Qt={QtCore.QT_VERSION_STR}, PyQt={QtCore.PYQT_VERSION_STR}")
|
2015-11-13 23:11:43 +09:00
|
|
|
# Uncomment this call to verify objects are being properly
|
|
|
|
|
# GC-ed when windows are closed
|
|
|
|
|
#network.add_jobs([DebugMem([Abstract_Wallet, SPV, Synchronizer,
|
|
|
|
|
# ElectrumWindow], interval=5)])
|
2018-01-13 16:03:40 +00:00
|
|
|
if hasattr(QtCore.Qt, "AA_ShareOpenGLContexts"):
|
|
|
|
|
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts)
|
2018-02-08 17:33:57 +01:00
|
|
|
if hasattr(QGuiApplication, 'setDesktopFileName'):
|
|
|
|
|
QGuiApplication.setDesktopFileName('electrum.desktop')
|
2024-09-09 16:34:43 +00:00
|
|
|
QGuiApplication.setApplicationName("Electrum")
|
2018-12-08 04:07:46 +01:00
|
|
|
self.gui_thread = threading.current_thread()
|
2020-05-25 17:31:13 +02:00
|
|
|
self.windows = [] # type: List[ElectrumWindow]
|
2013-09-11 13:43:37 +02:00
|
|
|
self.efilter = OpenFileEventFilter(self.windows)
|
2017-09-23 05:54:38 +02:00
|
|
|
self.app = QElectrumApplication(sys.argv)
|
2013-09-11 13:43:37 +02:00
|
|
|
self.app.installEventFilter(self.efilter)
|
2019-02-04 18:07:14 +01:00
|
|
|
self.app.setWindowIcon(read_QIcon("electrum.png"))
|
2024-10-07 12:55:36 +02:00
|
|
|
self.translator = ElectrumTranslator()
|
|
|
|
|
self.app.installTranslator(self.translator)
|
2021-04-03 19:17:32 +02:00
|
|
|
self._cleaned_up = False
|
2018-12-12 00:53:55 +02:00
|
|
|
# timer
|
|
|
|
|
self.timer = QTimer(self.app)
|
|
|
|
|
self.timer.setSingleShot(False)
|
|
|
|
|
self.timer.setInterval(500) # msec
|
|
|
|
|
|
2019-05-07 09:10:23 +02:00
|
|
|
self.network_dialog = None
|
|
|
|
|
self.lightning_dialog = None
|
2018-11-14 22:39:49 +01:00
|
|
|
self._num_wizards_in_progress = 0
|
|
|
|
|
self._num_wizards_lock = threading.Lock()
|
2023-05-24 17:41:44 +00:00
|
|
|
self.dark_icon = self.config.GUI_QT_DARK_TRAY_ICON
|
2024-09-05 16:20:01 +00:00
|
|
|
self.tray = None # type: Optional[QSystemTrayIcon]
|
2021-04-03 05:42:32 +02:00
|
|
|
self._init_tray()
|
|
|
|
|
self.app.new_window_signal.connect(self.start_new_window)
|
2024-09-05 16:20:01 +00:00
|
|
|
self.app.quit_signal.connect(self.app.quit, Qt.ConnectionType.QueuedConnection)
|
2022-02-18 18:08:38 +01:00
|
|
|
# maybe set dark theme
|
|
|
|
|
self._default_qtstylesheet = self.app.styleSheet()
|
|
|
|
|
self.reload_app_stylesheet()
|
|
|
|
|
|
2023-08-01 18:02:46 +02:00
|
|
|
# always load 2fa
|
2023-11-29 12:13:34 +01:00
|
|
|
self.plugins.load_internal_plugin('trustedcoin')
|
2023-08-01 18:02:46 +02:00
|
|
|
|
2021-04-03 05:42:32 +02:00
|
|
|
run_hook('init_qt', self)
|
|
|
|
|
|
|
|
|
|
def _init_tray(self):
|
2015-09-02 11:45:05 +09:00
|
|
|
self.tray = QSystemTrayIcon(self.tray_icon(), None)
|
|
|
|
|
self.tray.setToolTip('Electrum')
|
|
|
|
|
self.tray.activated.connect(self.tray_activated)
|
|
|
|
|
self.build_tray_menu()
|
|
|
|
|
self.tray.show()
|
2018-06-25 16:45:56 +02:00
|
|
|
|
2022-02-18 18:08:38 +01:00
|
|
|
def reload_app_stylesheet(self):
|
2022-02-18 22:17:44 +01:00
|
|
|
"""Set the Qt stylesheet and custom colors according to the user-selected
|
|
|
|
|
light/dark theme.
|
|
|
|
|
TODO this can ~almost be used to change the theme at runtime (without app restart),
|
|
|
|
|
except for util.ColorScheme... widgets already created with colors set using
|
|
|
|
|
ColorSchemeItem.as_stylesheet() and similar will not get recolored.
|
|
|
|
|
See e.g.
|
|
|
|
|
- in Coins tab, the color for "frozen" UTXOs, or
|
|
|
|
|
- in TxDialog, the receiving/change address colors
|
|
|
|
|
"""
|
2023-05-24 17:41:44 +00:00
|
|
|
use_dark_theme = self.config.GUI_QT_COLOR_THEME == 'dark'
|
2018-06-25 16:45:56 +02:00
|
|
|
if use_dark_theme:
|
|
|
|
|
try:
|
|
|
|
|
import qdarkstyle
|
2024-09-16 16:02:08 +00:00
|
|
|
self.app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt6())
|
2018-06-25 16:45:56 +02:00
|
|
|
except BaseException as e:
|
|
|
|
|
use_dark_theme = False
|
2019-04-26 18:52:26 +02:00
|
|
|
self.logger.warning(f'Error setting dark theme: {repr(e)}')
|
2022-02-18 18:08:38 +01:00
|
|
|
else:
|
|
|
|
|
self.app.setStyleSheet(self._default_qtstylesheet)
|
2019-05-05 02:14:07 +02:00
|
|
|
# Apply any necessary stylesheet patches
|
|
|
|
|
patch_qt_stylesheet(use_dark_theme=use_dark_theme)
|
2018-06-25 16:45:56 +02:00
|
|
|
# Even if we ourselves don't set the dark theme,
|
|
|
|
|
# the OS/window manager/etc might set *a dark theme*.
|
|
|
|
|
# Hence, try to choose colors accordingly:
|
|
|
|
|
ColorScheme.update_from_widget(QWidget(), force_dark=use_dark_theme)
|
2015-08-26 17:44:19 +02:00
|
|
|
|
2014-04-25 11:22:16 +02:00
|
|
|
def build_tray_menu(self):
|
2021-04-03 05:42:32 +02:00
|
|
|
if not self.tray:
|
|
|
|
|
return
|
2015-09-02 11:45:05 +09:00
|
|
|
# Avoid immediate GC of old menu when window closed via its action
|
2017-10-12 12:25:39 -04:00
|
|
|
if self.tray.contextMenu() is None:
|
|
|
|
|
m = QMenu()
|
|
|
|
|
self.tray.setContextMenu(m)
|
|
|
|
|
else:
|
|
|
|
|
m = self.tray.contextMenu()
|
|
|
|
|
m.clear()
|
2019-11-23 11:02:31 +01:00
|
|
|
network = self.daemon.network
|
2024-10-11 18:48:49 +00:00
|
|
|
if network:
|
|
|
|
|
m.addAction(_("Network"), self.show_network_dialog)
|
2020-01-09 18:21:48 +01:00
|
|
|
if network and network.lngossip:
|
2019-11-23 11:02:31 +01:00
|
|
|
m.addAction(_("Lightning Network"), self.show_lightning_dialog)
|
2015-09-02 11:45:05 +09:00
|
|
|
for window in self.windows:
|
2019-01-30 17:24:43 +01:00
|
|
|
name = window.wallet.basename()
|
|
|
|
|
submenu = m.addMenu(name)
|
2015-09-02 11:45:05 +09:00
|
|
|
submenu.addAction(_("Show/Hide"), window.show_or_hide)
|
|
|
|
|
submenu.addAction(_("Close"), window.close)
|
2014-04-25 11:22:16 +02:00
|
|
|
m.addAction(_("Dark/Light"), self.toggle_tray_icon)
|
|
|
|
|
m.addSeparator()
|
2021-04-04 01:05:23 +02:00
|
|
|
m.addAction(_("Exit Electrum"), self.app.quit)
|
2014-04-25 11:22:16 +02:00
|
|
|
|
2015-09-02 11:45:05 +09:00
|
|
|
def tray_icon(self):
|
|
|
|
|
if self.dark_icon:
|
2019-02-01 19:01:21 +01:00
|
|
|
return read_QIcon('electrum_dark_icon.png')
|
2015-09-02 11:45:05 +09:00
|
|
|
else:
|
2019-02-01 19:01:21 +01:00
|
|
|
return read_QIcon('electrum_light_icon.png')
|
2015-09-02 11:45:05 +09:00
|
|
|
|
2014-04-25 11:22:16 +02:00
|
|
|
def toggle_tray_icon(self):
|
2021-04-03 05:42:32 +02:00
|
|
|
if not self.tray:
|
|
|
|
|
return
|
2014-04-25 11:22:16 +02:00
|
|
|
self.dark_icon = not self.dark_icon
|
2023-05-24 17:41:44 +00:00
|
|
|
self.config.GUI_QT_DARK_TRAY_ICON = self.dark_icon
|
2015-09-02 11:45:05 +09:00
|
|
|
self.tray.setIcon(self.tray_icon())
|
2014-04-25 11:22:16 +02:00
|
|
|
|
|
|
|
|
def tray_activated(self, reason):
|
2024-09-05 16:20:01 +00:00
|
|
|
if reason == QSystemTrayIcon.ActivationReason.DoubleClick:
|
2015-09-02 11:45:05 +09:00
|
|
|
if all([w.is_hidden() for w in self.windows]):
|
|
|
|
|
for w in self.windows:
|
|
|
|
|
w.bring_to_top()
|
2014-04-25 11:22:16 +02:00
|
|
|
else:
|
2015-09-02 11:45:05 +09:00
|
|
|
for w in self.windows:
|
|
|
|
|
w.hide()
|
2014-04-25 11:22:16 +02:00
|
|
|
|
2021-04-03 19:17:32 +02:00
|
|
|
def _cleanup_before_exit(self):
|
|
|
|
|
if self._cleaned_up:
|
|
|
|
|
return
|
|
|
|
|
self._cleaned_up = True
|
|
|
|
|
self.app.new_window_signal.disconnect()
|
2024-07-09 14:26:24 +00:00
|
|
|
self.app.removeEventFilter(self.efilter)
|
2021-04-03 19:17:32 +02:00
|
|
|
self.efilter = None
|
|
|
|
|
# If there are still some open windows, try to clean them up.
|
|
|
|
|
for window in list(self.windows):
|
2015-09-02 11:45:05 +09:00
|
|
|
window.close()
|
2021-04-03 19:17:32 +02:00
|
|
|
window.clean_up()
|
2019-05-07 09:10:23 +02:00
|
|
|
if self.network_dialog:
|
|
|
|
|
self.network_dialog.close()
|
2021-04-03 19:17:32 +02:00
|
|
|
self.network_dialog.clean_up()
|
|
|
|
|
self.network_dialog = None
|
2019-05-07 09:10:23 +02:00
|
|
|
if self.lightning_dialog:
|
|
|
|
|
self.lightning_dialog.close()
|
2021-04-03 19:17:32 +02:00
|
|
|
self.lightning_dialog = None
|
|
|
|
|
# Shut down the timer cleanly
|
|
|
|
|
self.timer.stop()
|
|
|
|
|
self.timer = None
|
|
|
|
|
# clipboard persistence. see http://www.mail-archive.com/pyqt@riverbankcomputing.com/msg17328.html
|
2024-09-05 16:20:01 +00:00
|
|
|
event = QtCore.QEvent(QtCore.QEvent.Type.Clipboard)
|
2021-04-03 19:17:32 +02:00
|
|
|
self.app.sendEvent(self.app.clipboard(), event)
|
|
|
|
|
if self.tray:
|
|
|
|
|
self.tray.hide()
|
|
|
|
|
self.tray.deleteLater()
|
|
|
|
|
self.tray = None
|
|
|
|
|
|
2021-04-04 00:49:25 +02:00
|
|
|
def _maybe_quit_if_no_windows_open(self) -> None:
|
|
|
|
|
"""Check if there are any open windows and decide whether we should quit."""
|
|
|
|
|
# keep daemon running after close
|
|
|
|
|
if self.config.get('daemon'):
|
|
|
|
|
return
|
|
|
|
|
# check if a wizard is in progress
|
|
|
|
|
with self._num_wizards_lock:
|
|
|
|
|
if self._num_wizards_in_progress > 0 or len(self.windows) > 0:
|
|
|
|
|
return
|
|
|
|
|
self.app.quit()
|
|
|
|
|
|
2015-09-03 11:27:33 +02:00
|
|
|
def new_window(self, path, uri=None):
|
2015-09-02 20:34:40 +09:00
|
|
|
# Use a signal as can be called from daemon thread
|
2017-09-23 05:54:38 +02:00
|
|
|
self.app.new_window_signal.emit(path, uri)
|
2015-09-01 12:16:07 +02:00
|
|
|
|
2019-05-07 09:10:23 +02:00
|
|
|
def show_lightning_dialog(self):
|
2020-10-08 06:36:02 +02:00
|
|
|
if not self.daemon.network.has_channel_db():
|
2020-03-06 11:23:26 +01:00
|
|
|
return
|
2019-05-07 09:10:23 +02:00
|
|
|
if not self.lightning_dialog:
|
|
|
|
|
self.lightning_dialog = LightningDialog(self)
|
|
|
|
|
self.lightning_dialog.bring_to_top()
|
2019-10-12 14:30:52 +02:00
|
|
|
|
2019-11-23 11:02:31 +01:00
|
|
|
def show_network_dialog(self):
|
2019-05-07 09:10:23 +02:00
|
|
|
if self.network_dialog:
|
2022-06-16 12:05:05 +02:00
|
|
|
self.network_dialog.on_event_network_updated()
|
2019-05-07 09:10:23 +02:00
|
|
|
self.network_dialog.show()
|
|
|
|
|
self.network_dialog.raise_()
|
2017-07-08 15:23:00 +02:00
|
|
|
return
|
2021-04-03 19:17:32 +02:00
|
|
|
self.network_dialog = NetworkDialog(
|
|
|
|
|
network=self.daemon.network,
|
2022-06-16 12:05:05 +02:00
|
|
|
config=self.config)
|
2019-05-07 09:10:23 +02:00
|
|
|
self.network_dialog.show()
|
2017-07-08 15:23:00 +02:00
|
|
|
|
2019-03-04 02:08:23 +01:00
|
|
|
def _create_window_for_wallet(self, wallet):
|
2015-12-31 12:02:16 +09:00
|
|
|
w = ElectrumWindow(self, wallet)
|
|
|
|
|
self.windows.append(w)
|
|
|
|
|
self.build_tray_menu()
|
2019-04-28 06:31:01 +02:00
|
|
|
w.warn_if_testnet()
|
2018-12-04 11:52:31 +01:00
|
|
|
w.warn_if_watching_only()
|
2024-12-19 19:57:57 +01:00
|
|
|
w.require_full_encryption()
|
2015-12-31 12:02:16 +09:00
|
|
|
return w
|
|
|
|
|
|
2018-11-14 22:39:49 +01:00
|
|
|
def count_wizards_in_progress(func):
|
|
|
|
|
def wrapper(self: 'ElectrumGui', *args, **kwargs):
|
|
|
|
|
with self._num_wizards_lock:
|
|
|
|
|
self._num_wizards_in_progress += 1
|
|
|
|
|
try:
|
|
|
|
|
return func(self, *args, **kwargs)
|
|
|
|
|
finally:
|
|
|
|
|
with self._num_wizards_lock:
|
|
|
|
|
self._num_wizards_in_progress -= 1
|
2021-04-04 00:49:25 +02:00
|
|
|
self._maybe_quit_if_no_windows_open()
|
2018-11-14 22:39:49 +01:00
|
|
|
return wrapper
|
|
|
|
|
|
|
|
|
|
@count_wizards_in_progress
|
qt gui: more resilient startup: catch more exceptions, better fallback
fixes https://github.com/spesmilo/electrum/issues/7447
Consider this trace for 4.2.0:
```
Traceback (most recent call last):
File "electrum/gui/qt/__init__.py", line 332, in start_new_window
File "electrum/gui/qt/__init__.py", line 363, in _start_wizard_to_select_or_create_wallet
File "electrum/gui/qt/installwizard.py", line 302, in select_storage
File "electrum/util.py", line 504, in get_new_wallet_name
PermissionError: [Errno 1] Operation not permitted: '/Users/admin/Documents/Peach/MS'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "electrum/gui/qt/__init__.py", line 426, in main
File "electrum/gui/qt/__init__.py", line 307, in wrapper
File "electrum/gui/qt/__init__.py", line 349, in start_new_window
File "electrum/util.py", line 504, in get_new_wallet_name
PermissionError: [Errno 1] Operation not permitted: '/Users/admin/Documents/Peach/MS'
```
Note that `get_new_wallet_name` (os.listdir) can raise OSError,
and we were calling that on the main entrypoint codepath without exception-handling.
We were also calling it in the fallback codepath without exception-handling.
i.e. the GUI errored out on every startup for affected users, and without CLI usage
it was not possible to recover.
2022-03-23 03:58:33 +01:00
|
|
|
def start_new_window(
|
|
|
|
|
self,
|
|
|
|
|
path,
|
|
|
|
|
uri: Optional[str],
|
|
|
|
|
*,
|
|
|
|
|
app_is_starting: bool = False,
|
|
|
|
|
force_wizard: bool = False,
|
|
|
|
|
) -> Optional[ElectrumWindow]:
|
qt gui: more resilient startup
Example log:
app tries to auto-open to wallet "test_segwit_2", which has too new db version,
then user manually tries to open wallet "test_segwit_3" instead,
which opens okay but - immediately after - the process shuts down (due to line 383 -> line 458).
```
$ ./run_electrum -v --testnet -o
0.59 | I | simple_config.SimpleConfig | electrum directory /home/user/.electrum/testnet
0.59 | I | logging | Electrum version: 4.3.4 - https://electrum.org - https://github.com/spesmilo/electrum
0.59 | I | logging | Python version: 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0]. On platform: Linux-5.15.0-58-generic-x86_64-with-glibc2.35
0.59 | I | logging | Logging to file: /home/user/.electrum/testnet/logs/electrum_log_20230202T151759Z_220451.log
0.59 | I | logging | Log filters: verbosity '*', verbosity_shortcuts ''
0.59 | I | p/plugin.Plugins | registering hardware bitbox02: ('hardware', 'bitbox02', 'BitBox02')
0.59 | I | p/plugin.Plugins | registering hardware coldcard: ('hardware', 'coldcard', 'Coldcard Wallet')
0.59 | I | p/plugin.Plugins | registering hardware digitalbitbox: ('hardware', 'digitalbitbox', 'Digital Bitbox wallet')
0.60 | I | p/plugin.Plugins | registering hardware jade: ('hardware', 'jade', 'Jade wallet')
0.60 | I | p/plugin.Plugins | registering hardware keepkey: ('hardware', 'keepkey', 'KeepKey wallet')
0.60 | I | p/plugin.Plugins | registering hardware ledger: ('hardware', 'ledger', 'Ledger wallet')
1.74 | I | p/plugin.Plugins | loaded payserver
1.74 | I | p/plugin.Plugins | registering hardware safe_t: ('hardware', 'safe_t', 'Safe-T mini wallet')
1.74 | I | p/plugin.Plugins | registering hardware trezor: ('hardware', 'trezor', 'Trezor wallet')
1.74 | I | p/plugin.Plugins | registering wallet type ('2fa', 'trustedcoin')
1.74 | D | util.profiler | Plugins.__init__ 1.1522 sec
1.74 | I | exchange_rate.FxThread | using exchange CoinGecko
1.75 | D | util.profiler | Daemon.__init__ 0.0033 sec
1.75 | I | daemon.Daemon | starting taskgroup.
1.75 | I | daemon.Daemon | launching GUI: qt
1.75 | I | gui.qt.ElectrumGui | Qt GUI starting up... Qt=5.15.3, PyQt=5.15.6
1.75 | I | daemon.CommandsServer | now running and listening. socktype=unix, addr=/home/user/.electrum/testnet/daemon_rpc_socket
Warning: Ignoring XDG_SESSION_TYPE=wayland on Gnome. Use QT_QPA_PLATFORM=wayland to run on Wayland anyway.
2.04 | D | util.profiler | ElectrumGui.__init__ 0.2865 sec
2.04 | I | storage.WalletStorage | wallet path /home/user/.electrum/testnet/wallets/test_segwit_2
2.13 | I | storage.WalletStorage | wallet path /home/user/.electrum/testnet/wallets/test_segwit_2
5.24 | E | gui.qt.ElectrumGui |
Traceback (most recent call last):
File "/home/user/wspace/electrum/electrum/gui/qt/__init__.py", line 354, in start_new_window
wallet = self._start_wizard_to_select_or_create_wallet(path)
File "/home/user/wspace/electrum/electrum/gui/qt/__init__.py", line 401, in _start_wizard_to_select_or_create_wallet
db = WalletDB(storage.read(), manual_upgrades=False)
File "/home/user/wspace/electrum/electrum/wallet_db.py", line 72, in __init__
self.load_data(raw)
File "/home/user/wspace/electrum/electrum/wallet_db.py", line 102, in load_data
if not self.requires_upgrade():
File "/home/user/wspace/electrum/electrum/wallet_db.py", line 153, in requires_upgrade
return self.get_seed_version() < FINAL_SEED_VERSION
File "/home/user/wspace/electrum/electrum/json_db.py", line 44, in wrapper
return func(self, *args, **kwargs)
File "/home/user/wspace/electrum/electrum/wallet_db.py", line 1035, in get_seed_version
raise WalletFileException('This version of Electrum is too old to open this wallet.\n'
electrum.util.WalletFileException: This version of Electrum is too old to open this wallet.
(highest supported storage version: 50, version of this file: 51)
5.35 | I | storage.WalletStorage | wallet path /home/user/.electrum/testnet/wallets/wallet_20
7.90 | I | storage.WalletStorage | wallet path /home/user/.electrum/testnet/wallets/test_segwit_3
8.48 | D | util.profiler | WalletDB._load_transactions 0.0517 sec
8.48 | D | util.profiler | AddressSynchronizer.load_local_history 0.0005 sec
8.48 | D | util.profiler | AddressSynchronizer.check_history 0.0005 sec
8.70 | D | util.profiler | AddressList.update 0.0000 sec
9.00 | D | util.profiler | Deterministic_Wallet.try_detecting_internal_addresses_corruption 0.0223 sec
9.01 | D | util.profiler | ElectrumWindow.load_wallet 0.0808 sec
9.01 | I | daemon.Daemon | stop() entered. initiating shutdown
9.01 | I | gui.qt.ElectrumGui | closing GUI
9.01 | I | daemon.Daemon | stopping all wallets
9.04 | I | storage.WalletStorage | saved /home/user/.electrum/testnet/wallets/test_segwit_3
9.04 | D | util.profiler | WalletDB._write 0.0265 sec
9.04 | I | daemon.Daemon | stopping network and taskgroup
9.04 | I | daemon.Daemon | taskgroup stopped.
9.04 | I | daemon.Daemon | removing lockfile
9.04 | I | daemon.Daemon | stopped
9.08 | I | p/plugin.Plugins | stopped
QThread: Destroyed while thread is still running
Aborted (core dumped)
```
2023-02-02 15:25:15 +00:00
|
|
|
"""Raises the window for the wallet if it is open.
|
|
|
|
|
Otherwise, opens the wallet and creates a new window for it.
|
|
|
|
|
Warning: the returned window might be for a completely different wallet
|
|
|
|
|
than the provided path, as we allow user interaction to change the path.
|
|
|
|
|
"""
|
2019-03-04 02:08:23 +01:00
|
|
|
wallet = None
|
qt gui: more resilient startup: catch more exceptions, better fallback
fixes https://github.com/spesmilo/electrum/issues/7447
Consider this trace for 4.2.0:
```
Traceback (most recent call last):
File "electrum/gui/qt/__init__.py", line 332, in start_new_window
File "electrum/gui/qt/__init__.py", line 363, in _start_wizard_to_select_or_create_wallet
File "electrum/gui/qt/installwizard.py", line 302, in select_storage
File "electrum/util.py", line 504, in get_new_wallet_name
PermissionError: [Errno 1] Operation not permitted: '/Users/admin/Documents/Peach/MS'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "electrum/gui/qt/__init__.py", line 426, in main
File "electrum/gui/qt/__init__.py", line 307, in wrapper
File "electrum/gui/qt/__init__.py", line 349, in start_new_window
File "electrum/util.py", line 504, in get_new_wallet_name
PermissionError: [Errno 1] Operation not permitted: '/Users/admin/Documents/Peach/MS'
```
Note that `get_new_wallet_name` (os.listdir) can raise OSError,
and we were calling that on the main entrypoint codepath without exception-handling.
We were also calling it in the fallback codepath without exception-handling.
i.e. the GUI errored out on every startup for affected users, and without CLI usage
it was not possible to recover.
2022-03-23 03:58:33 +01:00
|
|
|
# Try to open with daemon first. If this succeeds, there won't be a wizard at all
|
|
|
|
|
# (the wallet main window will appear directly).
|
|
|
|
|
if not force_wizard:
|
|
|
|
|
try:
|
|
|
|
|
wallet = self.daemon.load_wallet(path, None)
|
2023-10-14 10:13:27 +02:00
|
|
|
except FileNotFoundError:
|
|
|
|
|
pass # open with wizard below
|
2023-10-10 16:57:44 +02:00
|
|
|
except InvalidPassword:
|
|
|
|
|
pass # open with wizard below
|
|
|
|
|
except WalletRequiresSplit:
|
|
|
|
|
pass # open with wizard below
|
|
|
|
|
except WalletRequiresUpgrade:
|
|
|
|
|
pass # open with wizard below
|
2024-01-15 17:06:44 +01:00
|
|
|
except WalletUnfinished:
|
|
|
|
|
pass # open with wizard below
|
qt gui: more resilient startup: catch more exceptions, better fallback
fixes https://github.com/spesmilo/electrum/issues/7447
Consider this trace for 4.2.0:
```
Traceback (most recent call last):
File "electrum/gui/qt/__init__.py", line 332, in start_new_window
File "electrum/gui/qt/__init__.py", line 363, in _start_wizard_to_select_or_create_wallet
File "electrum/gui/qt/installwizard.py", line 302, in select_storage
File "electrum/util.py", line 504, in get_new_wallet_name
PermissionError: [Errno 1] Operation not permitted: '/Users/admin/Documents/Peach/MS'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "electrum/gui/qt/__init__.py", line 426, in main
File "electrum/gui/qt/__init__.py", line 307, in wrapper
File "electrum/gui/qt/__init__.py", line 349, in start_new_window
File "electrum/util.py", line 504, in get_new_wallet_name
PermissionError: [Errno 1] Operation not permitted: '/Users/admin/Documents/Peach/MS'
```
Note that `get_new_wallet_name` (os.listdir) can raise OSError,
and we were calling that on the main entrypoint codepath without exception-handling.
We were also calling it in the fallback codepath without exception-handling.
i.e. the GUI errored out on every startup for affected users, and without CLI usage
it was not possible to recover.
2022-03-23 03:58:33 +01:00
|
|
|
except Exception as e:
|
|
|
|
|
self.logger.exception('')
|
wallet_db version 52: break non-homogeneous multisig wallets
- case 1: in version 4.4.1, 4.4.2, the qml GUI wizard allowed creating multisig wallets with an old_mpk as cosigner.
- case 2: in version 4.4.0, 4.4.1, 4.4.2, the qml GUI wizard allowed creating multisig wallets with mixed xpub/Ypub/Zpub.
The corresponding missing input validation was a bug in the wizard, it was unintended behaviour. Validation was added in d2cf21fc2bcf79f07b7e41178cd3e4ca9e3d9f68. Note however that there might be users who created such wallet files.
Re case 1 wallet files: there is no version of Electrum that allows spending from such a wallet. Coins received at addresses are not burned, however it is technically challenging to spend them. (unless the multisig can spend without needing the old_mpk cosigner in the quorum).
Re case 2 wallet files: it is possible to create a corresponding spending wallet for such a multisig, however it is a bit tricky. The script type for the addresses in such a heterogeneous xpub wallet is based on the xpub_type of the first keystore. So e.g. given a wallet file [Yprv1, Zpub2] it will have sh(wsh()) scripts, and the cosigner should create a wallet file [Ypub1, Zprv2] (same order).
Technically case 2 wallet files could be "fixed" automatically by converting the xpub types as part of a wallet_db upgrade. However if the wallet files also contain seeds, those cannot be converted ("standard" vs "segwit" electrum seed).
Case 1 wallet files are not possible to "fix" automatically as the cosigner using the old_mpk is not bip32 based.
It is unclear if there are *any* users out there affected by this. I suspect for case 1 it is very likely there are none (not many people have pre-2.0 electrum seeds which were never supported as part of a multisig who would also now try to create a multisig using them); for case 2 however there might be.
This commit breaks both case 1 and case 2 wallets: these wallet files can no longer be opened in new Electrum, an error message is shown and the crash reporter opens. If any potential users opt to send crash reports, at least we will know they exist and can help them recover.
2023-05-11 13:48:54 +00:00
|
|
|
err_text = str(e) if isinstance(e, WalletFileException) else repr(e)
|
2024-09-05 16:20:01 +00:00
|
|
|
custom_message_box(icon=QMessageBox.Icon.Warning,
|
qt gui: more resilient startup: catch more exceptions, better fallback
fixes https://github.com/spesmilo/electrum/issues/7447
Consider this trace for 4.2.0:
```
Traceback (most recent call last):
File "electrum/gui/qt/__init__.py", line 332, in start_new_window
File "electrum/gui/qt/__init__.py", line 363, in _start_wizard_to_select_or_create_wallet
File "electrum/gui/qt/installwizard.py", line 302, in select_storage
File "electrum/util.py", line 504, in get_new_wallet_name
PermissionError: [Errno 1] Operation not permitted: '/Users/admin/Documents/Peach/MS'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "electrum/gui/qt/__init__.py", line 426, in main
File "electrum/gui/qt/__init__.py", line 307, in wrapper
File "electrum/gui/qt/__init__.py", line 349, in start_new_window
File "electrum/util.py", line 504, in get_new_wallet_name
PermissionError: [Errno 1] Operation not permitted: '/Users/admin/Documents/Peach/MS'
```
Note that `get_new_wallet_name` (os.listdir) can raise OSError,
and we were calling that on the main entrypoint codepath without exception-handling.
We were also calling it in the fallback codepath without exception-handling.
i.e. the GUI errored out on every startup for affected users, and without CLI usage
it was not possible to recover.
2022-03-23 03:58:33 +01:00
|
|
|
parent=None,
|
|
|
|
|
title=_('Error'),
|
wallet_db version 52: break non-homogeneous multisig wallets
- case 1: in version 4.4.1, 4.4.2, the qml GUI wizard allowed creating multisig wallets with an old_mpk as cosigner.
- case 2: in version 4.4.0, 4.4.1, 4.4.2, the qml GUI wizard allowed creating multisig wallets with mixed xpub/Ypub/Zpub.
The corresponding missing input validation was a bug in the wizard, it was unintended behaviour. Validation was added in d2cf21fc2bcf79f07b7e41178cd3e4ca9e3d9f68. Note however that there might be users who created such wallet files.
Re case 1 wallet files: there is no version of Electrum that allows spending from such a wallet. Coins received at addresses are not burned, however it is technically challenging to spend them. (unless the multisig can spend without needing the old_mpk cosigner in the quorum).
Re case 2 wallet files: it is possible to create a corresponding spending wallet for such a multisig, however it is a bit tricky. The script type for the addresses in such a heterogeneous xpub wallet is based on the xpub_type of the first keystore. So e.g. given a wallet file [Yprv1, Zpub2] it will have sh(wsh()) scripts, and the cosigner should create a wallet file [Ypub1, Zprv2] (same order).
Technically case 2 wallet files could be "fixed" automatically by converting the xpub types as part of a wallet_db upgrade. However if the wallet files also contain seeds, those cannot be converted ("standard" vs "segwit" electrum seed).
Case 1 wallet files are not possible to "fix" automatically as the cosigner using the old_mpk is not bip32 based.
It is unclear if there are *any* users out there affected by this. I suspect for case 1 it is very likely there are none (not many people have pre-2.0 electrum seeds which were never supported as part of a multisig who would also now try to create a multisig using them); for case 2 however there might be.
This commit breaks both case 1 and case 2 wallets: these wallet files can no longer be opened in new Electrum, an error message is shown and the crash reporter opens. If any potential users opt to send crash reports, at least we will know they exist and can help them recover.
2023-05-11 13:48:54 +00:00
|
|
|
text=_('Cannot load wallet') + ' (1):\n' + err_text)
|
|
|
|
|
if isinstance(e, WalletFileException) and e.should_report_crash:
|
|
|
|
|
send_exception_to_crash_reporter(e)
|
qt gui: more resilient startup: catch more exceptions, better fallback
fixes https://github.com/spesmilo/electrum/issues/7447
Consider this trace for 4.2.0:
```
Traceback (most recent call last):
File "electrum/gui/qt/__init__.py", line 332, in start_new_window
File "electrum/gui/qt/__init__.py", line 363, in _start_wizard_to_select_or_create_wallet
File "electrum/gui/qt/installwizard.py", line 302, in select_storage
File "electrum/util.py", line 504, in get_new_wallet_name
PermissionError: [Errno 1] Operation not permitted: '/Users/admin/Documents/Peach/MS'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "electrum/gui/qt/__init__.py", line 426, in main
File "electrum/gui/qt/__init__.py", line 307, in wrapper
File "electrum/gui/qt/__init__.py", line 349, in start_new_window
File "electrum/util.py", line 504, in get_new_wallet_name
PermissionError: [Errno 1] Operation not permitted: '/Users/admin/Documents/Peach/MS'
```
Note that `get_new_wallet_name` (os.listdir) can raise OSError,
and we were calling that on the main entrypoint codepath without exception-handling.
We were also calling it in the fallback codepath without exception-handling.
i.e. the GUI errored out on every startup for affected users, and without CLI usage
it was not possible to recover.
2022-03-23 03:58:33 +01:00
|
|
|
# if app is starting, still let wizard appear
|
|
|
|
|
if not app_is_starting:
|
|
|
|
|
return
|
|
|
|
|
# Open a wizard window. This lets the user e.g. enter a password, or select
|
|
|
|
|
# a different wallet.
|
2018-03-14 23:46:23 -06:00
|
|
|
try:
|
qt init: make sure wallet file parsing errors are shown in gui
Some exceptions were just killing the gui silently and not even logged.
E.g.:
```
E | gui.qt.ElectrumGui | error loading wallet (or creating window for it)
Traceback (most recent call last):
File "/opt/electrum/electrum/gui/qt/__init__.py", line 433, in main
if not self.start_new_window(path, self.config.get('url'), app_is_starting=True):
File "/opt/electrum/electrum/gui/qt/__init__.py", line 307, in wrapper
return func(self, *args, **kwargs)
File "/opt/electrum/electrum/gui/qt/__init__.py", line 332, in start_new_window
wallet = self._start_wizard_to_select_or_create_wallet(path)
File "/opt/electrum/electrum/gui/qt/__init__.py", line 377, in _start_wizard_to_select_or_create_wallet
db = WalletDB(storage.read(), manual_upgrades=False)
File "/opt/electrum/electrum/wallet_db.py", line 73, in __init__
self.load_data(raw)
File "/opt/electrum/electrum/wallet_db.py", line 104, in load_data
self._after_upgrade_tasks()
File "/opt/electrum/electrum/wallet_db.py", line 202, in _after_upgrade_tasks
self._load_transactions()
File "/opt/electrum/electrum/util.py", line 439, in <lambda>
return lambda *args, **kw_args: do_profile(args, kw_args)
File "/opt/electrum/electrum/util.py", line 435, in do_profile
o = func(*args, **kw_args)
File "/opt/electrum/electrum/wallet_db.py", line 1310, in _load_transactions
self.data = StoredDict(self.data, self, [])
File "/opt/electrum/electrum/json_db.py", line 79, in __init__
self.__setitem__(k, v)
File "/opt/electrum/electrum/json_db.py", line 44, in wrapper
return func(self, *args, **kwargs)
File "/opt/electrum/electrum/json_db.py", line 97, in __setitem__
v = self.db._convert_dict(self.path, key, v)
File "/opt/electrum/electrum/wallet_db.py", line 1361, in _convert_dict
v = dict((k, SwapData(**x)) for k, x in v.items())
```
2022-03-15 14:23:30 +01:00
|
|
|
if not wallet:
|
|
|
|
|
wallet = self._start_wizard_to_select_or_create_wallet(path)
|
|
|
|
|
if not wallet:
|
|
|
|
|
return
|
|
|
|
|
# create or raise window
|
2019-03-04 02:20:34 +01:00
|
|
|
for window in self.windows:
|
|
|
|
|
if window.wallet.storage.path == wallet.storage.path:
|
2018-10-25 00:18:14 +02:00
|
|
|
break
|
|
|
|
|
else:
|
2019-03-04 02:20:34 +01:00
|
|
|
window = self._create_window_for_wallet(wallet)
|
2024-12-19 19:57:57 +01:00
|
|
|
except UserCancelled:
|
|
|
|
|
return
|
2021-04-03 01:47:44 +02:00
|
|
|
except Exception as e:
|
2019-04-26 18:52:26 +02:00
|
|
|
self.logger.exception('')
|
wallet_db version 52: break non-homogeneous multisig wallets
- case 1: in version 4.4.1, 4.4.2, the qml GUI wizard allowed creating multisig wallets with an old_mpk as cosigner.
- case 2: in version 4.4.0, 4.4.1, 4.4.2, the qml GUI wizard allowed creating multisig wallets with mixed xpub/Ypub/Zpub.
The corresponding missing input validation was a bug in the wizard, it was unintended behaviour. Validation was added in d2cf21fc2bcf79f07b7e41178cd3e4ca9e3d9f68. Note however that there might be users who created such wallet files.
Re case 1 wallet files: there is no version of Electrum that allows spending from such a wallet. Coins received at addresses are not burned, however it is technically challenging to spend them. (unless the multisig can spend without needing the old_mpk cosigner in the quorum).
Re case 2 wallet files: it is possible to create a corresponding spending wallet for such a multisig, however it is a bit tricky. The script type for the addresses in such a heterogeneous xpub wallet is based on the xpub_type of the first keystore. So e.g. given a wallet file [Yprv1, Zpub2] it will have sh(wsh()) scripts, and the cosigner should create a wallet file [Ypub1, Zprv2] (same order).
Technically case 2 wallet files could be "fixed" automatically by converting the xpub types as part of a wallet_db upgrade. However if the wallet files also contain seeds, those cannot be converted ("standard" vs "segwit" electrum seed).
Case 1 wallet files are not possible to "fix" automatically as the cosigner using the old_mpk is not bip32 based.
It is unclear if there are *any* users out there affected by this. I suspect for case 1 it is very likely there are none (not many people have pre-2.0 electrum seeds which were never supported as part of a multisig who would also now try to create a multisig using them); for case 2 however there might be.
This commit breaks both case 1 and case 2 wallets: these wallet files can no longer be opened in new Electrum, an error message is shown and the crash reporter opens. If any potential users opt to send crash reports, at least we will know they exist and can help them recover.
2023-05-11 13:48:54 +00:00
|
|
|
err_text = str(e) if isinstance(e, WalletFileException) else repr(e)
|
2024-09-05 16:20:01 +00:00
|
|
|
custom_message_box(icon=QMessageBox.Icon.Warning,
|
2019-05-13 23:59:29 +02:00
|
|
|
parent=None,
|
|
|
|
|
title=_('Error'),
|
wallet_db version 52: break non-homogeneous multisig wallets
- case 1: in version 4.4.1, 4.4.2, the qml GUI wizard allowed creating multisig wallets with an old_mpk as cosigner.
- case 2: in version 4.4.0, 4.4.1, 4.4.2, the qml GUI wizard allowed creating multisig wallets with mixed xpub/Ypub/Zpub.
The corresponding missing input validation was a bug in the wizard, it was unintended behaviour. Validation was added in d2cf21fc2bcf79f07b7e41178cd3e4ca9e3d9f68. Note however that there might be users who created such wallet files.
Re case 1 wallet files: there is no version of Electrum that allows spending from such a wallet. Coins received at addresses are not burned, however it is technically challenging to spend them. (unless the multisig can spend without needing the old_mpk cosigner in the quorum).
Re case 2 wallet files: it is possible to create a corresponding spending wallet for such a multisig, however it is a bit tricky. The script type for the addresses in such a heterogeneous xpub wallet is based on the xpub_type of the first keystore. So e.g. given a wallet file [Yprv1, Zpub2] it will have sh(wsh()) scripts, and the cosigner should create a wallet file [Ypub1, Zprv2] (same order).
Technically case 2 wallet files could be "fixed" automatically by converting the xpub types as part of a wallet_db upgrade. However if the wallet files also contain seeds, those cannot be converted ("standard" vs "segwit" electrum seed).
Case 1 wallet files are not possible to "fix" automatically as the cosigner using the old_mpk is not bip32 based.
It is unclear if there are *any* users out there affected by this. I suspect for case 1 it is very likely there are none (not many people have pre-2.0 electrum seeds which were never supported as part of a multisig who would also now try to create a multisig using them); for case 2 however there might be.
This commit breaks both case 1 and case 2 wallets: these wallet files can no longer be opened in new Electrum, an error message is shown and the crash reporter opens. If any potential users opt to send crash reports, at least we will know they exist and can help them recover.
2023-05-11 13:48:54 +00:00
|
|
|
text=_('Cannot load wallet') + '(2) :\n' + err_text)
|
|
|
|
|
if isinstance(e, WalletFileException) and e.should_report_crash:
|
|
|
|
|
send_exception_to_crash_reporter(e)
|
2018-12-11 21:29:23 +01:00
|
|
|
if app_is_starting:
|
qt gui: more resilient startup: catch more exceptions, better fallback
fixes https://github.com/spesmilo/electrum/issues/7447
Consider this trace for 4.2.0:
```
Traceback (most recent call last):
File "electrum/gui/qt/__init__.py", line 332, in start_new_window
File "electrum/gui/qt/__init__.py", line 363, in _start_wizard_to_select_or_create_wallet
File "electrum/gui/qt/installwizard.py", line 302, in select_storage
File "electrum/util.py", line 504, in get_new_wallet_name
PermissionError: [Errno 1] Operation not permitted: '/Users/admin/Documents/Peach/MS'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "electrum/gui/qt/__init__.py", line 426, in main
File "electrum/gui/qt/__init__.py", line 307, in wrapper
File "electrum/gui/qt/__init__.py", line 349, in start_new_window
File "electrum/util.py", line 504, in get_new_wallet_name
PermissionError: [Errno 1] Operation not permitted: '/Users/admin/Documents/Peach/MS'
```
Note that `get_new_wallet_name` (os.listdir) can raise OSError,
and we were calling that on the main entrypoint codepath without exception-handling.
We were also calling it in the fallback codepath without exception-handling.
i.e. the GUI errored out on every startup for affected users, and without CLI usage
it was not possible to recover.
2022-03-23 03:58:33 +01:00
|
|
|
# If we raise in this context, there are no more fallbacks, we will shut down.
|
|
|
|
|
# Worst case scenario, we might have gotten here without user interaction,
|
|
|
|
|
# in which case, if we raise now without user interaction, the same sequence of
|
|
|
|
|
# events is likely to repeat when the user restarts the process.
|
|
|
|
|
# So we play it safe: clear path, clear uri, force a wizard to appear.
|
|
|
|
|
try:
|
|
|
|
|
wallet_dir = os.path.dirname(path)
|
|
|
|
|
filename = get_new_wallet_name(wallet_dir)
|
|
|
|
|
except OSError:
|
|
|
|
|
path = self.config.get_fallback_wallet_path()
|
|
|
|
|
else:
|
|
|
|
|
path = os.path.join(wallet_dir, filename)
|
qt gui: more resilient startup
Example log:
app tries to auto-open to wallet "test_segwit_2", which has too new db version,
then user manually tries to open wallet "test_segwit_3" instead,
which opens okay but - immediately after - the process shuts down (due to line 383 -> line 458).
```
$ ./run_electrum -v --testnet -o
0.59 | I | simple_config.SimpleConfig | electrum directory /home/user/.electrum/testnet
0.59 | I | logging | Electrum version: 4.3.4 - https://electrum.org - https://github.com/spesmilo/electrum
0.59 | I | logging | Python version: 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0]. On platform: Linux-5.15.0-58-generic-x86_64-with-glibc2.35
0.59 | I | logging | Logging to file: /home/user/.electrum/testnet/logs/electrum_log_20230202T151759Z_220451.log
0.59 | I | logging | Log filters: verbosity '*', verbosity_shortcuts ''
0.59 | I | p/plugin.Plugins | registering hardware bitbox02: ('hardware', 'bitbox02', 'BitBox02')
0.59 | I | p/plugin.Plugins | registering hardware coldcard: ('hardware', 'coldcard', 'Coldcard Wallet')
0.59 | I | p/plugin.Plugins | registering hardware digitalbitbox: ('hardware', 'digitalbitbox', 'Digital Bitbox wallet')
0.60 | I | p/plugin.Plugins | registering hardware jade: ('hardware', 'jade', 'Jade wallet')
0.60 | I | p/plugin.Plugins | registering hardware keepkey: ('hardware', 'keepkey', 'KeepKey wallet')
0.60 | I | p/plugin.Plugins | registering hardware ledger: ('hardware', 'ledger', 'Ledger wallet')
1.74 | I | p/plugin.Plugins | loaded payserver
1.74 | I | p/plugin.Plugins | registering hardware safe_t: ('hardware', 'safe_t', 'Safe-T mini wallet')
1.74 | I | p/plugin.Plugins | registering hardware trezor: ('hardware', 'trezor', 'Trezor wallet')
1.74 | I | p/plugin.Plugins | registering wallet type ('2fa', 'trustedcoin')
1.74 | D | util.profiler | Plugins.__init__ 1.1522 sec
1.74 | I | exchange_rate.FxThread | using exchange CoinGecko
1.75 | D | util.profiler | Daemon.__init__ 0.0033 sec
1.75 | I | daemon.Daemon | starting taskgroup.
1.75 | I | daemon.Daemon | launching GUI: qt
1.75 | I | gui.qt.ElectrumGui | Qt GUI starting up... Qt=5.15.3, PyQt=5.15.6
1.75 | I | daemon.CommandsServer | now running and listening. socktype=unix, addr=/home/user/.electrum/testnet/daemon_rpc_socket
Warning: Ignoring XDG_SESSION_TYPE=wayland on Gnome. Use QT_QPA_PLATFORM=wayland to run on Wayland anyway.
2.04 | D | util.profiler | ElectrumGui.__init__ 0.2865 sec
2.04 | I | storage.WalletStorage | wallet path /home/user/.electrum/testnet/wallets/test_segwit_2
2.13 | I | storage.WalletStorage | wallet path /home/user/.electrum/testnet/wallets/test_segwit_2
5.24 | E | gui.qt.ElectrumGui |
Traceback (most recent call last):
File "/home/user/wspace/electrum/electrum/gui/qt/__init__.py", line 354, in start_new_window
wallet = self._start_wizard_to_select_or_create_wallet(path)
File "/home/user/wspace/electrum/electrum/gui/qt/__init__.py", line 401, in _start_wizard_to_select_or_create_wallet
db = WalletDB(storage.read(), manual_upgrades=False)
File "/home/user/wspace/electrum/electrum/wallet_db.py", line 72, in __init__
self.load_data(raw)
File "/home/user/wspace/electrum/electrum/wallet_db.py", line 102, in load_data
if not self.requires_upgrade():
File "/home/user/wspace/electrum/electrum/wallet_db.py", line 153, in requires_upgrade
return self.get_seed_version() < FINAL_SEED_VERSION
File "/home/user/wspace/electrum/electrum/json_db.py", line 44, in wrapper
return func(self, *args, **kwargs)
File "/home/user/wspace/electrum/electrum/wallet_db.py", line 1035, in get_seed_version
raise WalletFileException('This version of Electrum is too old to open this wallet.\n'
electrum.util.WalletFileException: This version of Electrum is too old to open this wallet.
(highest supported storage version: 50, version of this file: 51)
5.35 | I | storage.WalletStorage | wallet path /home/user/.electrum/testnet/wallets/wallet_20
7.90 | I | storage.WalletStorage | wallet path /home/user/.electrum/testnet/wallets/test_segwit_3
8.48 | D | util.profiler | WalletDB._load_transactions 0.0517 sec
8.48 | D | util.profiler | AddressSynchronizer.load_local_history 0.0005 sec
8.48 | D | util.profiler | AddressSynchronizer.check_history 0.0005 sec
8.70 | D | util.profiler | AddressList.update 0.0000 sec
9.00 | D | util.profiler | Deterministic_Wallet.try_detecting_internal_addresses_corruption 0.0223 sec
9.01 | D | util.profiler | ElectrumWindow.load_wallet 0.0808 sec
9.01 | I | daemon.Daemon | stop() entered. initiating shutdown
9.01 | I | gui.qt.ElectrumGui | closing GUI
9.01 | I | daemon.Daemon | stopping all wallets
9.04 | I | storage.WalletStorage | saved /home/user/.electrum/testnet/wallets/test_segwit_3
9.04 | D | util.profiler | WalletDB._write 0.0265 sec
9.04 | I | daemon.Daemon | stopping network and taskgroup
9.04 | I | daemon.Daemon | taskgroup stopped.
9.04 | I | daemon.Daemon | removing lockfile
9.04 | I | daemon.Daemon | stopped
9.08 | I | p/plugin.Plugins | stopped
QThread: Destroyed while thread is still running
Aborted (core dumped)
```
2023-02-02 15:25:15 +00:00
|
|
|
return self.start_new_window(path, uri=None, force_wizard=True)
|
2018-03-14 23:46:23 -06:00
|
|
|
return
|
2019-03-04 02:20:34 +01:00
|
|
|
window.bring_to_top()
|
2024-09-05 16:20:01 +00:00
|
|
|
window.setWindowState(window.windowState() & ~Qt.WindowState.WindowMinimized | Qt.WindowState.WindowActive)
|
2019-03-04 02:20:34 +01:00
|
|
|
window.activateWindow()
|
2022-08-16 15:27:13 +00:00
|
|
|
if uri:
|
2023-07-07 20:48:29 +02:00
|
|
|
window.show_send_tab()
|
2023-03-19 13:32:43 +01:00
|
|
|
window.send_tab.set_payment_identifier(uri)
|
2019-03-04 02:20:34 +01:00
|
|
|
return window
|
2014-04-25 11:22:16 +02:00
|
|
|
|
2019-03-04 02:08:23 +01:00
|
|
|
def _start_wizard_to_select_or_create_wallet(self, path) -> Optional[Abstract_Wallet]:
|
2023-08-28 11:50:24 +02:00
|
|
|
wizard = QENewWalletWizard(self.config, self.app, self.plugins, self.daemon, path)
|
|
|
|
|
result = wizard.exec()
|
2023-08-16 23:09:29 +02:00
|
|
|
# TODO: use dialog.open() instead to avoid new event loop spawn?
|
2023-12-01 15:31:50 +00:00
|
|
|
self.logger.info(f'wizard dialog exec result={result}')
|
2024-09-05 16:20:01 +00:00
|
|
|
if result == QDialog.DialogCode.Rejected:
|
2023-12-01 15:31:50 +00:00
|
|
|
self.logger.info('wizard dialog cancelled by user')
|
2023-08-16 23:09:29 +02:00
|
|
|
return
|
|
|
|
|
|
2023-08-28 11:50:24 +02:00
|
|
|
d = wizard.get_wizard_data()
|
2023-08-16 23:09:29 +02:00
|
|
|
|
|
|
|
|
if d['wallet_is_open']:
|
2024-04-24 13:16:12 +02:00
|
|
|
wallet_path = self.daemon._wallet_key_from_path(d['wallet_name'])
|
2023-08-16 23:09:29 +02:00
|
|
|
for window in self.windows:
|
2024-04-24 13:16:12 +02:00
|
|
|
if window.wallet.storage.path == wallet_path:
|
2023-08-16 23:09:29 +02:00
|
|
|
return window.wallet
|
|
|
|
|
raise Exception('found by wizard but not here?!')
|
|
|
|
|
|
|
|
|
|
if not d['wallet_exists']:
|
|
|
|
|
self.logger.info('about to create wallet')
|
2023-08-28 11:50:24 +02:00
|
|
|
wizard.create_storage()
|
2020-02-04 12:45:31 +01:00
|
|
|
if d['wallet_type'] == '2fa' and 'x3' not in d:
|
2023-08-28 16:22:37 +02:00
|
|
|
return
|
2023-08-28 11:50:24 +02:00
|
|
|
wallet_file = wizard.path
|
2023-08-16 23:09:29 +02:00
|
|
|
else:
|
|
|
|
|
wallet_file = d['wallet_name']
|
|
|
|
|
|
2023-08-18 15:13:33 +02:00
|
|
|
try:
|
2023-10-10 16:57:44 +02:00
|
|
|
wallet = self.daemon.load_wallet(wallet_file, d['password'], upgrade=True)
|
|
|
|
|
return wallet
|
2023-08-18 15:13:33 +02:00
|
|
|
except WalletRequiresSplit as e:
|
2023-10-10 16:57:44 +02:00
|
|
|
wizard.run_split(wallet_file, e._split_data)
|
|
|
|
|
return
|
|
|
|
|
except WalletUnfinished as e:
|
2023-08-28 13:48:39 +02:00
|
|
|
# wallet creation is not complete, 2fa online phase
|
2023-10-10 16:57:44 +02:00
|
|
|
db = e._wallet_db
|
|
|
|
|
action = db.get_action()
|
2023-08-28 13:48:39 +02:00
|
|
|
assert action[1] == 'accept_terms_of_use', 'only support for resuming trustedcoin split setup'
|
2020-02-04 12:45:31 +01:00
|
|
|
k1 = load_keystore(db, 'x1')
|
2023-08-28 16:22:37 +02:00
|
|
|
if 'password' in d and d['password']:
|
|
|
|
|
xprv = k1.get_master_private_key(d['password'])
|
|
|
|
|
else:
|
2020-02-04 12:45:31 +01:00
|
|
|
xprv = db.get('x1')['xprv']
|
2024-10-08 00:04:20 +02:00
|
|
|
if not is_xprv(xprv):
|
|
|
|
|
xprv = k1
|
trustedcoin: fix qt wizard two-part-wallet-creation, online phase
```
25.30 | E | gui.qt.exception_window.Exception_Hook | exception caught by crash reporter
Traceback (most recent call last):
File "/home/user/wspace/electrum/electrum/gui/qt/__init__.py", line 439, in _start_wizard_to_select_or_create_wallet
wallet = self.daemon.load_wallet(wallet_file, d['password'], upgrade=True)
File "/home/user/wspace/electrum/electrum/daemon.py", line 481, in func_wrapper
return func(self, *args, **kwargs)
File "/home/user/wspace/electrum/electrum/daemon.py", line 491, in load_wallet
wallet = self._load_wallet(path, password, upgrade=upgrade, config=self.config)
File "/home/user/wspace/electrum/electrum/util.py", line 481, in do_profile
o = func(*args, **kw_args)
File "/home/user/wspace/electrum/electrum/daemon.py", line 516, in _load_wallet
raise WalletUnfinished(db)
electrum.wallet_db.WalletUnfinished: <electrum.wallet_db.WalletDB object at 0x7f11db3a7ca0>
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/user/wspace/electrum/electrum/gui/qt/wizard/wizard.py", line 203, in on_next_button_clicked
if self.is_finalized(wd):
File "/home/user/wspace/electrum/electrum/gui/qt/wizard/wallet.py", line 178, in is_finalized
if not wizard_data['wallet_exists'] or wizard_data['wallet_is_open']:
KeyError: 'wallet_exists'
```
2024-01-05 15:34:20 +00:00
|
|
|
_wiz_data_updates = {
|
2024-05-28 15:04:22 +00:00
|
|
|
'wallet_name': wallet_file,
|
2023-08-28 16:22:37 +02:00
|
|
|
'xprv1': xprv,
|
2020-02-04 12:45:31 +01:00
|
|
|
'xpub1': db.get('x1')['xpub'],
|
|
|
|
|
'xpub2': db.get('x2')['xpub'],
|
2023-08-28 13:48:39 +02:00
|
|
|
}
|
trustedcoin: fix qt wizard two-part-wallet-creation, online phase
```
25.30 | E | gui.qt.exception_window.Exception_Hook | exception caught by crash reporter
Traceback (most recent call last):
File "/home/user/wspace/electrum/electrum/gui/qt/__init__.py", line 439, in _start_wizard_to_select_or_create_wallet
wallet = self.daemon.load_wallet(wallet_file, d['password'], upgrade=True)
File "/home/user/wspace/electrum/electrum/daemon.py", line 481, in func_wrapper
return func(self, *args, **kwargs)
File "/home/user/wspace/electrum/electrum/daemon.py", line 491, in load_wallet
wallet = self._load_wallet(path, password, upgrade=upgrade, config=self.config)
File "/home/user/wspace/electrum/electrum/util.py", line 481, in do_profile
o = func(*args, **kw_args)
File "/home/user/wspace/electrum/electrum/daemon.py", line 516, in _load_wallet
raise WalletUnfinished(db)
electrum.wallet_db.WalletUnfinished: <electrum.wallet_db.WalletDB object at 0x7f11db3a7ca0>
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/user/wspace/electrum/electrum/gui/qt/wizard/wizard.py", line 203, in on_next_button_clicked
if self.is_finalized(wd):
File "/home/user/wspace/electrum/electrum/gui/qt/wizard/wallet.py", line 178, in is_finalized
if not wizard_data['wallet_exists'] or wizard_data['wallet_is_open']:
KeyError: 'wallet_exists'
```
2024-01-05 15:34:20 +00:00
|
|
|
data = {**d, **_wiz_data_updates}
|
2023-08-28 13:48:39 +02:00
|
|
|
wizard = QENewWalletWizard(self.config, self.app, self.plugins, self.daemon, path,
|
2023-12-08 11:56:11 +01:00
|
|
|
start_viewstate=WizardViewState('trustedcoin_tos', data, {}))
|
2023-08-28 13:48:39 +02:00
|
|
|
result = wizard.exec()
|
2024-09-05 16:20:01 +00:00
|
|
|
if result == QDialog.DialogCode.Rejected:
|
2023-12-01 15:31:50 +00:00
|
|
|
self.logger.info('wizard dialog cancelled by user')
|
2023-08-28 13:48:39 +02:00
|
|
|
return
|
2020-02-04 12:45:31 +01:00
|
|
|
db.put('x3', wizard.get_wizard_data()['x3'])
|
2023-08-28 13:48:39 +02:00
|
|
|
db.write()
|
2023-08-16 23:09:29 +02:00
|
|
|
|
2023-08-24 16:55:32 +02:00
|
|
|
wallet = Wallet(db, config=self.config)
|
2023-08-16 23:09:29 +02:00
|
|
|
wallet.start_network(self.daemon.network)
|
|
|
|
|
self.daemon.add_wallet(wallet)
|
|
|
|
|
return wallet
|
|
|
|
|
|
2019-05-14 17:04:03 +02:00
|
|
|
def close_window(self, window: ElectrumWindow):
|
2018-08-30 14:35:01 +00:00
|
|
|
if window in self.windows:
|
2021-04-03 01:44:42 +02:00
|
|
|
self.windows.remove(window)
|
2015-09-02 11:45:05 +09:00
|
|
|
self.build_tray_menu()
|
2015-12-05 16:53:56 +01:00
|
|
|
# save wallet path of last open window
|
2016-03-08 11:10:04 +01:00
|
|
|
if not self.windows:
|
|
|
|
|
self.config.save_last_wallet(window.wallet)
|
2016-01-12 20:19:21 +09:00
|
|
|
run_hook('on_close_window', window)
|
2018-09-13 16:25:56 +02:00
|
|
|
self.daemon.stop_wallet(window.wallet.storage.path)
|
2014-04-25 11:22:16 +02:00
|
|
|
|
2016-10-14 14:05:24 +02:00
|
|
|
def init_network(self):
|
2023-03-29 22:09:46 +00:00
|
|
|
"""Start the network, including showing a first-start network dialog if config does not exist."""
|
2016-10-14 14:05:24 +02:00
|
|
|
if self.daemon.network:
|
2023-03-29 22:09:46 +00:00
|
|
|
# first-start network-setup
|
2023-05-24 17:41:44 +00:00
|
|
|
if not self.config.cv.NETWORK_AUTO_CONNECT.is_set():
|
2023-08-16 23:09:29 +02:00
|
|
|
dialog = QEServerConnectWizard(self.config, self.app, self.plugins, self.daemon)
|
2023-12-12 17:16:07 +01:00
|
|
|
result = dialog.exec()
|
2024-09-05 16:20:01 +00:00
|
|
|
if result == QDialog.DialogCode.Rejected:
|
2023-12-12 17:16:07 +01:00
|
|
|
self.logger.info('network wizard dialog cancelled by user')
|
|
|
|
|
raise UserCancelled()
|
|
|
|
|
|
2023-03-29 22:09:46 +00:00
|
|
|
# start network
|
|
|
|
|
self.daemon.start_network()
|
2016-10-14 14:05:24 +02:00
|
|
|
|
2015-08-26 17:44:19 +02:00
|
|
|
def main(self):
|
2021-04-06 18:27:28 +02:00
|
|
|
# setup Ctrl-C handling and tear-down code first, so that user can easily exit whenever
|
|
|
|
|
self.app.setQuitOnLastWindowClosed(False) # so _we_ can decide whether to quit
|
|
|
|
|
self.app.lastWindowClosed.connect(self._maybe_quit_if_no_windows_open)
|
|
|
|
|
self.app.aboutToQuit.connect(self._cleanup_before_exit)
|
|
|
|
|
signal.signal(signal.SIGINT, lambda *args: self.app.quit())
|
qt init: on exc, let crash reporter appear instead of silently dying
related: https://github.com/spesmilo/electrum/issues/7390
```
20210706T091826.513398Z | ERROR | __main__ | daemon.run_gui errored
Traceback (most recent call last):
File "run_electrum", line 407, in handle_cmd
File "electrum\daemon.py", line 584, in run_gui
File "electrum\gui\qt\__init__.py", line 414, in main
File "electrum\gui\qt\__init__.py", line 291, in wrapper
File "electrum\gui\qt\__init__.py", line 316, in start_new_window
File "electrum\gui\qt\__init__.py", line 361, in _start_wizard_to_select_or_create_wallet
File "electrum\wallet_db.py", line 73, in __init__
File "electrum\wallet_db.py", line 106, in load_data
File "electrum\util.py", line 412, in <lambda>
File "electrum\util.py", line 408, in do_profile
File "electrum\wallet_db.py", line 175, in upgrade
File "electrum\wallet_db.py", line 540, in _convert_version_24
ValueError: too many values to unpack (expected 2)
```
2021-07-07 19:19:43 +02:00
|
|
|
# hook for crash reporter
|
|
|
|
|
Exception_Hook.maybe_setup(config=self.config)
|
2023-03-29 22:09:46 +00:00
|
|
|
# start network, and maybe show first-start network-setup
|
2016-10-14 14:05:24 +02:00
|
|
|
try:
|
|
|
|
|
self.init_network()
|
2016-10-24 14:57:02 +02:00
|
|
|
except UserCancelled:
|
|
|
|
|
return
|
2021-04-03 01:47:44 +02:00
|
|
|
except Exception as e:
|
2019-04-26 18:52:26 +02:00
|
|
|
self.logger.exception('')
|
2016-10-14 14:05:24 +02:00
|
|
|
return
|
2021-04-06 18:27:28 +02:00
|
|
|
# start wizard to select/create wallet
|
2015-08-26 17:44:19 +02:00
|
|
|
self.timer.start()
|
2019-09-10 17:10:52 +02:00
|
|
|
path = self.config.get_wallet_path(use_gui_last_wallet=True)
|
qt init: on exc, let crash reporter appear instead of silently dying
related: https://github.com/spesmilo/electrum/issues/7390
```
20210706T091826.513398Z | ERROR | __main__ | daemon.run_gui errored
Traceback (most recent call last):
File "run_electrum", line 407, in handle_cmd
File "electrum\daemon.py", line 584, in run_gui
File "electrum\gui\qt\__init__.py", line 414, in main
File "electrum\gui\qt\__init__.py", line 291, in wrapper
File "electrum\gui\qt\__init__.py", line 316, in start_new_window
File "electrum\gui\qt\__init__.py", line 361, in _start_wizard_to_select_or_create_wallet
File "electrum\wallet_db.py", line 73, in __init__
File "electrum\wallet_db.py", line 106, in load_data
File "electrum\util.py", line 412, in <lambda>
File "electrum\util.py", line 408, in do_profile
File "electrum\wallet_db.py", line 175, in upgrade
File "electrum\wallet_db.py", line 540, in _convert_version_24
ValueError: too many values to unpack (expected 2)
```
2021-07-07 19:19:43 +02:00
|
|
|
try:
|
|
|
|
|
if not self.start_new_window(path, self.config.get('url'), app_is_starting=True):
|
|
|
|
|
return
|
|
|
|
|
except Exception as e:
|
|
|
|
|
self.logger.error("error loading wallet (or creating window for it)")
|
|
|
|
|
send_exception_to_crash_reporter(e)
|
|
|
|
|
# Let Qt event loop start properly so that crash reporter window can appear.
|
|
|
|
|
# We will shutdown when the user closes that window, via lastWindowClosed signal.
|
2015-08-26 17:44:19 +02:00
|
|
|
# main loop
|
qt init: on exc, let crash reporter appear instead of silently dying
related: https://github.com/spesmilo/electrum/issues/7390
```
20210706T091826.513398Z | ERROR | __main__ | daemon.run_gui errored
Traceback (most recent call last):
File "run_electrum", line 407, in handle_cmd
File "electrum\daemon.py", line 584, in run_gui
File "electrum\gui\qt\__init__.py", line 414, in main
File "electrum\gui\qt\__init__.py", line 291, in wrapper
File "electrum\gui\qt\__init__.py", line 316, in start_new_window
File "electrum\gui\qt\__init__.py", line 361, in _start_wizard_to_select_or_create_wallet
File "electrum\wallet_db.py", line 73, in __init__
File "electrum\wallet_db.py", line 106, in load_data
File "electrum\util.py", line 412, in <lambda>
File "electrum\util.py", line 408, in do_profile
File "electrum\wallet_db.py", line 175, in upgrade
File "electrum\wallet_db.py", line 540, in _convert_version_24
ValueError: too many values to unpack (expected 2)
```
2021-07-07 19:19:43 +02:00
|
|
|
self.logger.info("starting Qt main loop")
|
2024-09-05 16:20:01 +00:00
|
|
|
self.app.exec()
|
qt init: on exc, let crash reporter appear instead of silently dying
related: https://github.com/spesmilo/electrum/issues/7390
```
20210706T091826.513398Z | ERROR | __main__ | daemon.run_gui errored
Traceback (most recent call last):
File "run_electrum", line 407, in handle_cmd
File "electrum\daemon.py", line 584, in run_gui
File "electrum\gui\qt\__init__.py", line 414, in main
File "electrum\gui\qt\__init__.py", line 291, in wrapper
File "electrum\gui\qt\__init__.py", line 316, in start_new_window
File "electrum\gui\qt\__init__.py", line 361, in _start_wizard_to_select_or_create_wallet
File "electrum\wallet_db.py", line 73, in __init__
File "electrum\wallet_db.py", line 106, in load_data
File "electrum\util.py", line 412, in <lambda>
File "electrum\util.py", line 408, in do_profile
File "electrum\wallet_db.py", line 175, in upgrade
File "electrum\wallet_db.py", line 540, in _convert_version_24
ValueError: too many values to unpack (expected 2)
```
2021-07-07 19:19:43 +02:00
|
|
|
# on some platforms the exec_ call may not return, so use _cleanup_before_exit
|
2018-09-13 16:25:56 +02:00
|
|
|
|
|
|
|
|
def stop(self):
|
2019-04-26 18:52:26 +02:00
|
|
|
self.logger.info('closing GUI')
|
2021-11-05 17:24:03 +01:00
|
|
|
self.app.quit_signal.emit()
|
commands: add "version_info" cmd
example:
```
$ ./run_electrum -o version_info
{
"aiohttp.version": "3.8.1",
"aiorpcx.version": "0.22.1",
"certifi.version": "2021.10.08",
"cryptodome.version": null,
"cryptography.path": "/home/user/.local/lib/python3.8/site-packages/cryptography",
"cryptography.version": "3.4.6",
"dnspython.version": "2.2.0",
"electrum.path": "/home/user/wspace/electrum/electrum",
"electrum.version": "4.2.1",
"hidapi.version": "0.11.0.post2",
"libsecp256k1.path": "/home/user/wspace/electrum/electrum/libsecp256k1.so.0",
"libusb.path": "libusb-1.0.so",
"libusb.version": "1.0.23.11397",
"libzbar.path": "/home/user/wspace/electrum/electrum/libzbar.so.0",
"pyaes.version": "1.3.0",
"pyqt.path": "/usr/lib/python3/dist-packages/PyQt5",
"pyqt.version": "5.14.1",
"qt.version": "5.12.8"
}
```
2022-04-11 17:05:26 +02:00
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def version_info(cls):
|
|
|
|
|
ret = {
|
|
|
|
|
"qt.version": QtCore.QT_VERSION_STR,
|
|
|
|
|
"pyqt.version": QtCore.PYQT_VERSION_STR,
|
|
|
|
|
}
|
2024-09-05 16:20:01 +00:00
|
|
|
if hasattr(PyQt6, "__path__"):
|
|
|
|
|
ret["pyqt.path"] = ", ".join(PyQt6.__path__ or [])
|
commands: add "version_info" cmd
example:
```
$ ./run_electrum -o version_info
{
"aiohttp.version": "3.8.1",
"aiorpcx.version": "0.22.1",
"certifi.version": "2021.10.08",
"cryptodome.version": null,
"cryptography.path": "/home/user/.local/lib/python3.8/site-packages/cryptography",
"cryptography.version": "3.4.6",
"dnspython.version": "2.2.0",
"electrum.path": "/home/user/wspace/electrum/electrum",
"electrum.version": "4.2.1",
"hidapi.version": "0.11.0.post2",
"libsecp256k1.path": "/home/user/wspace/electrum/electrum/libsecp256k1.so.0",
"libusb.path": "libusb-1.0.so",
"libusb.version": "1.0.23.11397",
"libzbar.path": "/home/user/wspace/electrum/electrum/libzbar.so.0",
"pyaes.version": "1.3.0",
"pyqt.path": "/usr/lib/python3/dist-packages/PyQt5",
"pyqt.version": "5.14.1",
"qt.version": "5.12.8"
}
```
2022-04-11 17:05:26 +02:00
|
|
|
return ret
|