diff --git a/electrum/gui/messages.py b/electrum/gui/messages.py index 66b9c13ee..24875995d 100644 --- a/electrum/gui/messages.py +++ b/electrum/gui/messages.py @@ -52,6 +52,13 @@ MSG_HELP_TRAMPOLINE = _( Downloading the network gossip uses quite some bandwidth and storage, and is not recommended on mobile devices. If you use trampoline, you can only open channels with trampoline nodes.""" ) +MSG_LEGACY_ADD_TRAMPOLINE = _( +"""When paying a non-trampoline invoice, add an extra trampoline to the route, in order to improve your privacy. + +This will result in longer routes; it might increase your fees and decrease the success rate of your payments. +""" +) + MGS_CONFLICTING_BACKUP_INSTANCE = _( """Another instance of this wallet (same seed) has an open channel with the same remote node. If you create this channel, you will not be able to use both wallets at the same time. diff --git a/electrum/gui/qt/settings_dialog.py b/electrum/gui/qt/settings_dialog.py index 99b491ba4..46c05ae3b 100644 --- a/electrum/gui/qt/settings_dialog.py +++ b/electrum/gui/qt/settings_dialog.py @@ -130,6 +130,14 @@ class SettingsDialog(QDialog, QtEventListener): util.trigger_callback('channels_updated', self.wallet) trampoline_cb.stateChanged.connect(on_trampoline_checked) + help_legacy_add_trampoline = messages.MSG_LEGACY_ADD_TRAMPOLINE + legacy_add_trampoline_cb = QCheckBox(_("Add extra trampoline to legacy payments")) + legacy_add_trampoline_cb.setToolTip(messages.to_rtf(help_legacy_add_trampoline)) + legacy_add_trampoline_cb.setChecked(self.config.LIGHTNING_LEGACY_ADD_TRAMPOLINE) + def on_legacy_add_trampoline_checked(b): + self.config.LIGHTNING_LEGACY_ADD_TRAMPOLINE = bool(b) + legacy_add_trampoline_cb.stateChanged.connect(on_legacy_add_trampoline_checked) + help_remote_wt = ' '.join([ _("A watchtower is a daemon that watches your channels and prevents the other party from stealing funds by broadcasting an old state."), _("If you have private a watchtower, enter its URL here."), @@ -372,6 +380,7 @@ class SettingsDialog(QDialog, QtEventListener): units_widgets.append((thousandsep_cb, None)) lightning_widgets = [] lightning_widgets.append((trampoline_cb, None)) + lightning_widgets.append((legacy_add_trampoline_cb, None)) lightning_widgets.append((remote_wt_cb, self.watchtower_url_e)) fiat_widgets = [] fiat_widgets.append((QLabel(_('Fiat currency')), ccy_combo)) diff --git a/electrum/lnworker.py b/electrum/lnworker.py index e07a92cc6..295245c4a 100644 --- a/electrum/lnworker.py +++ b/electrum/lnworker.py @@ -657,17 +657,18 @@ class LNGossip(LNWorker): class PaySession(Logger): def __init__( - self, - *, - payment_hash: bytes, - payment_secret: bytes, - initial_trampoline_fee_level: int, - invoice_features: int, - r_tags, - min_cltv_expiry: int, - amount_to_pay: int, # total payment amount final receiver will get - invoice_pubkey: bytes, - uses_trampoline: bool, # whether sender uses trampoline or gossip + self, + *, + payment_hash: bytes, + payment_secret: bytes, + initial_trampoline_fee_level: int, + invoice_features: int, + r_tags, + min_cltv_expiry: int, + amount_to_pay: int, # total payment amount final receiver will get + invoice_pubkey: bytes, + uses_trampoline: bool, # whether sender uses trampoline or gossip + use_two_trampolines: bool, # whether legacy payments will try to use two trampolines ): assert payment_hash assert payment_secret @@ -688,7 +689,7 @@ class PaySession(Logger): self.uses_trampoline = uses_trampoline self.trampoline_fee_level = initial_trampoline_fee_level self.failed_trampoline_routes = [] - self.use_two_trampolines = True + self.use_two_trampolines = use_two_trampolines self._sent_buckets = dict() # psecret_bucket -> (amount_sent, amount_failed) self._amount_inflight = 0 # what we sent in htlcs (that receiver gets, without fees) @@ -1432,6 +1433,7 @@ class LNWallet(LNWorker): amount_to_pay=amount_to_pay, invoice_pubkey=node_pubkey, uses_trampoline=self.uses_trampoline(), + use_two_trampolines=self.config.LIGHTNING_LEGACY_ADD_TRAMPOLINE, ) self.logs[payment_hash.hex()] = log = [] # TODO incl payment_secret in key (re trampoline forwarding) diff --git a/electrum/simple_config.py b/electrum/simple_config.py index 971324f3c..bad6c5bf7 100644 --- a/electrum/simple_config.py +++ b/electrum/simple_config.py @@ -863,6 +863,7 @@ class SimpleConfig(Logger): LIGHTNING_ALLOW_INSTANT_SWAPS = ConfigVar('allow_instant_swaps', default=False, type_=bool) LIGHTNING_TO_SELF_DELAY_CSV = ConfigVar('lightning_to_self_delay', default=7 * 144, type_=int) LIGHTNING_MAX_FUNDING_SAT = ConfigVar('lightning_max_funding_sat', default=LN_MAX_FUNDING_SAT_LEGACY, type_=int) + LIGHTNING_LEGACY_ADD_TRAMPOLINE = ConfigVar('lightning_legacy_add_trampoline', default=False, type_=bool) EXPERIMENTAL_LN_FORWARD_PAYMENTS = ConfigVar('lightning_forward_payments', default=False, type_=bool) EXPERIMENTAL_LN_FORWARD_TRAMPOLINE_PAYMENTS = ConfigVar('lightning_forward_trampoline_payments', default=False, type_=bool) diff --git a/electrum/tests/test_lnpeer.py b/electrum/tests/test_lnpeer.py index c9ed07fbd..37f5ccceb 100644 --- a/electrum/tests/test_lnpeer.py +++ b/electrum/tests/test_lnpeer.py @@ -242,6 +242,7 @@ class MockLNWallet(Logger, EventListener, NetworkRetryManager[LNPeerAddr]): amount_to_pay=amount_msat, invoice_pubkey=decoded_invoice.pubkey.serialize(), uses_trampoline=False, + use_two_trampolines=False, ) paysession.use_two_trampolines = False payment_key = decoded_invoice.paymenthash + decoded_invoice.payment_secret