From 120faa480e427472bad95b65cb75a485e93feec6 Mon Sep 17 00:00:00 2001 From: ThomasV Date: Sun, 29 Oct 2023 16:08:35 +0100 Subject: [PATCH] If trampoline is enabled, do not add non-trampoline nodes to invoices Rationale: The sender should not assume that they share the same list of hardcoded trampolines as the receiver. --- electrum/gui/messages.py | 3 +-- electrum/gui/qt/channels_list.py | 15 +++++++++------ electrum/lnchannel.py | 2 ++ electrum/lnworker.py | 2 ++ electrum/trampoline.py | 2 +- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/electrum/gui/messages.py b/electrum/gui/messages.py index 2cf20d650..407b2ed3e 100644 --- a/electrum/gui/messages.py +++ b/electrum/gui/messages.py @@ -41,7 +41,6 @@ MSG_CAPITAL_GAINS = _( ) MSG_NON_TRAMPOLINE_CHANNEL_FROZEN_WITHOUT_GOSSIP = _( -"""Trampoline routing is enabled, but this channel is with a non-trampoline node. -This channel may still be used for receiving, but it is frozen for sending. +"""This channel is with a non-trampoline node; it cannot be used if trampoline is enabled. If you want to keep using this channel, you need to disable trampoline routing in your preferences.""" ) diff --git a/electrum/gui/qt/channels_list.py b/electrum/gui/qt/channels_list.py index ead1260b8..1a85045cb 100644 --- a/electrum/gui/qt/channels_list.py +++ b/electrum/gui/qt/channels_list.py @@ -193,9 +193,12 @@ class ChannelsList(MyTreeView): return self.network.run_from_another_thread(coro) WaitingDialog(self, 'please wait..', task, self.on_request_sent, self.on_failure) - def freeze_channel_for_sending(self, chan, b): + def set_frozen(self, chan, *, for_sending, value): if not self.lnworker.uses_trampoline() or self.lnworker.is_trampoline_peer(chan.node_id): - chan.set_frozen_for_sending(b) + if for_sending: + chan.set_frozen_for_sending(value) + else: + chan.set_frozen_for_receiving(value) else: msg = messages.MSG_NON_TRAMPOLINE_CHANNEL_FROZEN_WITHOUT_GOSSIP self.main_window.show_warning(msg, title=_('Channel is frozen for sending')) @@ -258,13 +261,13 @@ class ChannelsList(MyTreeView): if not chan.is_backup() and not chan.is_closed(): fm = menu.addMenu(_("Freeze")) if not chan.is_frozen_for_sending(): - fm.addAction(_("Freeze for sending"), lambda: self.freeze_channel_for_sending(chan, True)) + fm.addAction(_("Freeze for sending"), lambda: self.set_frozen(chan, for_sending=True, value=True)) else: - fm.addAction(_("Unfreeze for sending"), lambda: self.freeze_channel_for_sending(chan, False)) + fm.addAction(_("Unfreeze for sending"), lambda: self.set_frozen(chan, for_sending=True, value=False)) if not chan.is_frozen_for_receiving(): - fm.addAction(_("Freeze for receiving"), lambda: chan.set_frozen_for_receiving(True)) + fm.addAction(_("Freeze for receiving"), lambda: self.set_frozen(chan, for_sending=False, value=True)) else: - fm.addAction(_("Unfreeze for receiving"), lambda: chan.set_frozen_for_receiving(False)) + fm.addAction(_("Unfreeze for receiving"), lambda: self.set_frozen(chan, for_sending=False, value=False)) if close_opts := chan.get_close_options(): cm = menu.addMenu(_("Close")) if ChanCloseOption.COOP_CLOSE in close_opts: diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py index bf627df53..a1b6e2a07 100644 --- a/electrum/lnchannel.py +++ b/electrum/lnchannel.py @@ -921,6 +921,8 @@ class Channel(AbstractChannel): util.trigger_callback('channel', self.lnworker.wallet, self) def is_frozen_for_receiving(self) -> bool: + if self.lnworker and self.lnworker.uses_trampoline() and not self.lnworker.is_trampoline_peer(self.node_id): + return True return self.storage.get('frozen_for_receiving', False) def set_frozen_for_receiving(self, b: bool) -> None: diff --git a/electrum/lnworker.py b/electrum/lnworker.py index 7c13fb234..bbc9e378e 100644 --- a/electrum/lnworker.py +++ b/electrum/lnworker.py @@ -2068,6 +2068,8 @@ class LNWallet(LNWorker): routing_hints = self.calc_routing_hints_for_invoice(amount_msat, channels=channels) self.logger.info(f"creating bolt11 invoice with routing_hints: {routing_hints}") invoice_features = self.features.for_invoice() + if not self.uses_trampoline(): + invoice_features &= ~ LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM payment_secret = self.get_payment_secret(payment_hash) amount_btc = amount_msat/Decimal(COIN*1000) if amount_msat else None if expiry == 0: diff --git a/electrum/trampoline.py b/electrum/trampoline.py index 73226bdbd..542667948 100644 --- a/electrum/trampoline.py +++ b/electrum/trampoline.py @@ -143,7 +143,7 @@ def is_legacy_relay(invoice_features, r_tags) -> Tuple[bool, Set[bytes]]: # endpoints connected to T1 and T2, and sender only has send-capacity with T1, while # recipient only has recv-capacity with T2. singlehop_r_tags = [x for x in r_tags if len(x) == 1] - invoice_trampolines = [x[0][0] for x in singlehop_r_tags if is_hardcoded_trampoline(x[0][0])] + invoice_trampolines = [x[0][0] for x in singlehop_r_tags] invoice_trampolines = set(invoice_trampolines) if invoice_trampolines: return False, invoice_trampolines