Skip to content

Commit a8a5b2d

Browse files
committed
gui: warn about old channel backups on wallet startup
Implement a mechanism to show one-time warnings to the user on startup of the wallet to inform them about critical changes. Use this mechanism to inform them about the changed lightning channel backup scheme.
1 parent c85a191 commit a8a5b2d

6 files changed

Lines changed: 91 additions & 1 deletion

File tree

electrum/gui/qml/components/main.qml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,28 @@ ApplicationWindow
698698
}
699699
}
700700

701+
function showStartupWarnings() {
702+
if (!Daemon.currentWallet)
703+
return
704+
let warnings = Daemon.currentWallet.startupWarnings
705+
// show the warnings one after another, as the dialogs are not modal
706+
function showWarning(i) {
707+
if (i >= warnings.length)
708+
return
709+
let dialog = app.messageDialog.createObject(app, {
710+
title: warnings[i].title,
711+
iconSource: Qt.resolvedUrl('../../icons/warning.png'),
712+
text: warnings[i].message
713+
})
714+
dialog.closed.connect(function() {
715+
showWarning(i + 1)
716+
})
717+
dialog.open()
718+
Daemon.currentWallet.acknowledgeWarning(warnings[i].key)
719+
}
720+
showWarning(0)
721+
}
722+
701723
Connections {
702724
target: Daemon
703725
function onWalletRequiresPassword(name, path) {
@@ -734,6 +756,7 @@ ApplicationWindow
734756
}
735757
function onWalletLoaded() {
736758
app._loadingWalletContext = null // either biometric auth or manual auth was successful
759+
showStartupWarnings()
737760
}
738761
}
739762

electrum/gui/qml/qewallet.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,18 @@ def lightningNumPeers(self):
528528
return self.wallet.lnworker.lnpeermgr.num_peers()
529529
return 0
530530

531+
@pyqtProperty('QVariantList', notify=dataChanged)
532+
def startupWarnings(self):
533+
return [{
534+
'key': warning.key,
535+
'title': warning.title,
536+
'message': warning.message,
537+
} for warning in self.wallet.get_startup_warnings()]
538+
539+
@pyqtSlot(str)
540+
def acknowledgeWarning(self, key: str):
541+
self.wallet.acknowledge_warning(key)
542+
531543
@pyqtSlot()
532544
def enableLightning(self):
533545
self.wallet.init_lightning(password=self.password)

electrum/gui/qt/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ def _create_window_for_wallet(self, wallet):
331331
self.build_tray_menu()
332332
w.warn_if_testnet()
333333
w.warn_if_watching_only()
334+
w.show_startup_warnings()
334335
return w
335336

336337
def count_wizards_in_progress(func):

electrum/gui/qt/main_window.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,11 @@ def on_cb(_x):
681681
if cb_checked:
682682
self.config.DONT_SHOW_TESTNET_WARNING = True
683683

684+
def show_startup_warnings(self):
685+
for warning in self.wallet.get_startup_warnings():
686+
self.show_warning(warning.message, title=warning.title)
687+
self.wallet.acknowledge_warning(warning.key)
688+
684689
def open_wallet(self):
685690
try:
686691
wallet_folder = self.get_wallet_folder()

electrum/lnworker.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595

9696
if TYPE_CHECKING:
9797
from .network import Network
98-
from .wallet import Abstract_Wallet
98+
from .wallet import Abstract_Wallet, WalletWarning
9999
from .channel_db import ChannelDB
100100
from .simple_config import SimpleConfig
101101

@@ -1123,6 +1123,33 @@ def has_anchor_channels(self) -> bool:
11231123
return any(chan.has_anchors() and not chan.is_closed()
11241124
for chan in self.channels.values())
11251125

1126+
def get_lightning_startup_warnings(self) -> Sequence['WalletWarning']:
1127+
from .wallet import WalletWarning
1128+
warnings = []
1129+
if not self.has_deterministic_node_id() and self.has_anchor_channels():
1130+
# backups exported before we started storing the payment_basepoint privkey
1131+
# (backup v3) cannot sweep the to_remote output of an anchor channel
1132+
warnings.append(WalletWarning(
1133+
key='ln_outdated_channel_backups',
1134+
title=_('Outdated channel backups'),
1135+
message=''.join([
1136+
_("The Lightning channels of this wallet cannot be recovered from seed."), ' ',
1137+
_("Channel backups that were exported with an older version of Electrum "
1138+
"cannot be used to request a force close of these channels."), '\n\n',
1139+
_("Please export new channel backups and store them in a safe place."),
1140+
])))
1141+
if any(not cb.can_sweep_their_ctx_to_remote() for cb in self.channel_backups.values()):
1142+
warnings.append(WalletWarning(
1143+
key='ln_unusable_channel_backups',
1144+
title=_('Unusable channel backups'),
1145+
message=''.join([
1146+
_("This wallet contains channel backups that cannot be used to request a force close, "
1147+
"because they were exported with an older version of Electrum."), ' ',
1148+
_("Please import new backups, exported by the wallet these channels belong to."), '\n\n',
1149+
_("If you have lost access to that wallet, please open an issue on GitHub."),
1150+
])))
1151+
return warnings
1152+
11261153
@property
11271154
def features(self) -> 'LnFeatures':
11281155
return self.lnpeermgr.features

electrum/wallet.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,12 @@ class TxWalletDetails(NamedTuple):
379379
is_related_to_wallet: bool
380380

381381

382+
class WalletWarning(NamedTuple):
383+
key: str # stable identifier, used to remember that the user has seen this warning
384+
title: str
385+
message: str
386+
387+
382388
@dataclass(kw_only=True, slots=True, frozen=True)
383389
class PiechartBalance:
384390
confirmed: int # confirmed and matured and NOT frozen
@@ -517,6 +523,22 @@ def save_backup(self, backup_dir):
517523
new_db.write()
518524
return new_path
519525

526+
def get_startup_warnings(self) -> Sequence[WalletWarning]:
527+
"""Warnings that should be shown to the user once, when the wallet is opened in a GUI."""
528+
warnings = [] # type: List[WalletWarning]
529+
if self.lnworker:
530+
warnings += self.lnworker.get_lightning_startup_warnings()
531+
acknowledged = self.db.get('acknowledged_warnings', [])
532+
return [warning for warning in warnings if warning.key not in acknowledged]
533+
534+
def acknowledge_warning(self, key: str) -> None:
535+
"""Remember that the user has seen this warning, so that it is not shown again."""
536+
acknowledged = self.db.get('acknowledged_warnings', [])
537+
if key in acknowledged:
538+
return
539+
self.db.put('acknowledged_warnings', list(acknowledged) + [key])
540+
self.save_db()
541+
520542
def has_lightning(self) -> bool:
521543
return bool(self.lnworker)
522544

0 commit comments

Comments
 (0)