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-02-14 18:10:58 +01:00
|
|
|
import traceback
|
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
|
|
|
|
2022-04-11 16:53:25 +02:00
|
|
|
from electrum import GuiImportError
|
2013-09-11 13:43:37 +02:00
|
|
|
|
|
|
|
|
try:
|
2017-09-23 05:54:38 +02:00
|
|
|
import PyQt5
|
2022-04-11 17:37:10 +02:00
|
|
|
import PyQt5.QtGui
|
2022-04-11 16:53:25 +02:00
|
|
|
except Exception as e:
|
|
|
|
|
raise GuiImportError(
|
|
|
|
|
"Error: Could not import PyQt5 on Linux systems, "
|
|
|
|
|
"you may try 'sudo apt-get install python3-pyqt5'") from e
|
2013-09-11 13:43:37 +02:00
|
|
|
|
2019-02-11 20:21:24 +01:00
|
|
|
from PyQt5.QtGui import QGuiApplication
|
|
|
|
|
from PyQt5.QtWidgets import (QApplication, QSystemTrayIcon, QWidget, QMenu,
|
|
|
|
|
QMessageBox)
|
2021-06-25 15:48:22 +02:00
|
|
|
from PyQt5.QtCore import QObject, pyqtSignal, QTimer, Qt
|
2017-09-23 05:54:38 +02:00
|
|
|
import PyQt5.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
|
|
|
|
|
# lazy-loading it later led to some crashes. Maybe due to bugs in PyQt5. (see #7725)
|
|
|
|
|
from PyQt5.QtMultimedia import QCameraInfo; del QCameraInfo
|
|
|
|
|
except ImportError as e:
|
|
|
|
|
pass # failure is ok; it is an optional dependency.
|
|
|
|
|
|
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
|
2018-05-01 14:39:01 +02:00
|
|
|
from electrum.base_wizard import GoBack
|
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,
|
2018-12-11 21:29:23 +01:00
|
|
|
WalletFileException, BitcoinException, get_new_wallet_name)
|
2019-03-04 02:08:23 +01:00
|
|
|
from electrum.wallet import Wallet, Abstract_Wallet
|
2020-02-05 15:13:37 +01:00
|
|
|
from electrum.wallet_db import WalletDB
|
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
|
2017-01-22 21:25:24 +03:00
|
|
|
|
2019-03-04 02:08:23 +01:00
|
|
|
from .installwizard import InstallWizard, WalletAlreadyOpenInMemory
|
2021-06-25 15:48:22 +02:00
|
|
|
from .util import get_default_language, read_QIcon, ColorScheme, custom_message_box, MessageBoxMixin
|
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
|
2019-10-12 14:30:52 +02:00
|
|
|
from .watchtower_dialog import WatchtowerDialog
|
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
|
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.simple_config import SimpleConfig
|
|
|
|
|
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):
|
|
|
|
|
if event.type() == QtCore.QEvent.FileOpen:
|
|
|
|
|
if len(self.windows) >= 1:
|
2021-11-23 14:42:43 +01:00
|
|
|
self.windows[0].handle_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
|
|
|
|
|
|
|
|
|
2015-08-26 17:44:19 +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']
|
|
|
|
|
watchtower_dialog: Optional['WatchtowerDialog']
|
|
|
|
|
|
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'):
|
2018-09-19 13:07:19 +05:00
|
|
|
set_language(config.get('language', get_default_language()))
|
2021-11-05 20:21:50 +01:00
|
|
|
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')
|
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"))
|
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
|
2019-10-12 14:30:52 +02:00
|
|
|
self.watchtower_dialog = None
|
2018-11-14 22:39:49 +01:00
|
|
|
self._num_wizards_in_progress = 0
|
|
|
|
|
self._num_wizards_lock = threading.Lock()
|
2015-09-02 11:45:05 +09:00
|
|
|
self.dark_icon = self.config.get("dark_icon", False)
|
2021-04-03 05:42:32 +02:00
|
|
|
self.tray = None
|
|
|
|
|
self._init_tray()
|
|
|
|
|
self.app.new_window_signal.connect(self.start_new_window)
|
2021-11-05 17:24:03 +01:00
|
|
|
self.app.quit_signal.connect(self.app.quit, Qt.QueuedConnection)
|
2022-02-18 18:08:38 +01:00
|
|
|
# maybe set dark theme
|
|
|
|
|
self._default_qtstylesheet = self.app.styleSheet()
|
|
|
|
|
self.reload_app_stylesheet()
|
|
|
|
|
|
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
|
|
|
|
|
"""
|
2018-06-25 16:45:56 +02:00
|
|
|
use_dark_theme = self.config.get('qt_gui_color_theme', 'default') == 'dark'
|
|
|
|
|
if use_dark_theme:
|
|
|
|
|
try:
|
|
|
|
|
import qdarkstyle
|
|
|
|
|
self.app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
|
|
|
|
|
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
|
|
|
|
|
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)
|
2020-01-09 18:21:48 +01:00
|
|
|
if network and network.local_watchtower:
|
2019-11-23 11:02:31 +01:00
|
|
|
m.addAction(_("Local Watchtower"), self.show_watchtower_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
|
|
|
|
|
self.config.set_key("dark_icon", self.dark_icon, True)
|
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):
|
|
|
|
|
if reason == QSystemTrayIcon.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()
|
|
|
|
|
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
|
2019-10-12 14:30:52 +02:00
|
|
|
if self.watchtower_dialog:
|
|
|
|
|
self.watchtower_dialog.close()
|
2021-04-03 19:17:32 +02:00
|
|
|
self.watchtower_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
|
|
|
|
|
event = QtCore.QEvent(QtCore.QEvent.Clipboard)
|
|
|
|
|
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
|
|
|
|
|
|
|
|
def show_watchtower_dialog(self):
|
|
|
|
|
if not self.watchtower_dialog:
|
|
|
|
|
self.watchtower_dialog = WatchtowerDialog(self)
|
|
|
|
|
self.watchtower_dialog.bring_to_top()
|
2019-01-30 17:24:43 +01: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()
|
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)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
self.logger.exception('')
|
|
|
|
|
custom_message_box(icon=QMessageBox.Warning,
|
|
|
|
|
parent=None,
|
|
|
|
|
title=_('Error'),
|
|
|
|
|
text=_('Cannot load wallet') + ' (1):\n' + repr(e))
|
|
|
|
|
# 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)
|
2021-04-03 01:47:44 +02:00
|
|
|
except Exception as e:
|
2019-04-26 18:52:26 +02:00
|
|
|
self.logger.exception('')
|
2019-05-13 23:59:29 +02:00
|
|
|
custom_message_box(icon=QMessageBox.Warning,
|
|
|
|
|
parent=None,
|
|
|
|
|
title=_('Error'),
|
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
|
|
|
text=_('Cannot load wallet') + '(2) :\n' + repr(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()
|
|
|
|
|
window.setWindowState(window.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive)
|
|
|
|
|
window.activateWindow()
|
2022-08-16 15:27:13 +00:00
|
|
|
if uri:
|
|
|
|
|
window.handle_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]:
|
2020-04-01 18:42:06 +02:00
|
|
|
wizard = InstallWizard(self.config, self.app, self.plugins, gui_object=self)
|
2019-03-04 02:08:23 +01:00
|
|
|
try:
|
|
|
|
|
path, storage = wizard.select_storage(path, self.daemon.get_wallet)
|
|
|
|
|
# storage is None if file does not exist
|
|
|
|
|
if storage is None:
|
|
|
|
|
wizard.path = path # needed by trustedcoin plugin
|
|
|
|
|
wizard.run('new')
|
2020-02-05 15:13:37 +01:00
|
|
|
storage, db = wizard.create_storage(path)
|
2019-03-04 02:08:23 +01:00
|
|
|
else:
|
2020-02-05 15:13:37 +01:00
|
|
|
db = WalletDB(storage.read(), manual_upgrades=False)
|
|
|
|
|
wizard.run_upgrades(storage, db)
|
2019-03-04 02:08:23 +01:00
|
|
|
except (UserCancelled, GoBack):
|
|
|
|
|
return
|
|
|
|
|
except WalletAlreadyOpenInMemory as e:
|
|
|
|
|
return e.wallet
|
|
|
|
|
finally:
|
|
|
|
|
wizard.terminate()
|
|
|
|
|
# return if wallet creation is not complete
|
2020-02-05 15:13:37 +01:00
|
|
|
if storage is None or db.get_action():
|
2019-03-04 02:08:23 +01:00
|
|
|
return
|
2020-02-05 15:13:37 +01:00
|
|
|
wallet = Wallet(db, storage, config=self.config)
|
2019-03-04 02:08:23 +01: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):
|
|
|
|
|
# Show network dialog if config does not exist
|
|
|
|
|
if self.daemon.network:
|
|
|
|
|
if self.config.get('auto_connect') is None:
|
2020-04-01 18:42:06 +02:00
|
|
|
wizard = InstallWizard(self.config, self.app, self.plugins, gui_object=self)
|
2016-10-14 14:05:24 +02:00
|
|
|
wizard.init_network(self.daemon.network)
|
|
|
|
|
wizard.terminate()
|
|
|
|
|
|
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)
|
2021-04-06 18:27:28 +02:00
|
|
|
# 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
|
|
|
|
|
except GoBack:
|
|
|
|
|
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")
|
2013-09-11 13:43:37 +02: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,
|
|
|
|
|
}
|
|
|
|
|
if hasattr(PyQt5, "__path__"):
|
|
|
|
|
ret["pyqt.path"] = ", ".join(PyQt5.__path__ or [])
|
|
|
|
|
return ret
|