Trampoline routing.
- trampoline is enabled by default in config, to prevent download of `gossip_db`.
(if disabled, `gossip_db` will be downloaded, regardless of the existence of channels)
- if trampoline is enabled:
- the wallet can only open channels with trampoline nodes
- already-existing channels with non-trampoline nodes are frozen for sending.
- there are two types of trampoline payments: legacy and end-to-end (e2e).
- we decide to perform legacy or e2e based on the invoice:
- we use trampoline_routing_opt in features to detect Eclair and Phoenix invoices
- we use trampoline_routing_hints to detect Electrum invoices
- when trying a legacy payment, we add a second trampoline to the path to preserve privacy.
(we fall back to a single trampoline if the payment fails for all trampolines)
- the trampoline list is hardcoded, it will remain so until `trampoline_routing_opt` feature flag is in INIT.
- there are currently only two nodes in the hardcoded list, it would be nice to have more.
- similar to Phoenix, we find the fee/cltv by trial-and-error.
- if there is a second trampoline in the path, we use the same fee for both.
- the final spec should add fee info in error messages, so we will be able to fine-tune fees
This commit is contained in:
@@ -145,6 +145,17 @@ class ChannelsList(MyTreeView):
|
||||
self.main_window.show_message('success')
|
||||
WaitingDialog(self, 'please wait..', task, on_success, self.on_failure)
|
||||
|
||||
def freeze_channel_for_sending(self, chan, b):
|
||||
if self.lnworker.channel_db or self.lnworker.is_trampoline_peer(chan.node_id):
|
||||
chan.set_frozen_for_sending(b)
|
||||
else:
|
||||
msg = ' '.join([
|
||||
_("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."),
|
||||
_("If you want to keep using this channel, you need to disable trampoline routing in your preferences."),
|
||||
])
|
||||
self.main_window.show_warning(msg, title=_('Channel is frozen for sending'))
|
||||
|
||||
def create_menu(self, position):
|
||||
menu = QMenu()
|
||||
menu.setSeparatorsCollapsible(True) # consecutive separators are merged together
|
||||
@@ -177,9 +188,9 @@ class ChannelsList(MyTreeView):
|
||||
channel_id.hex(), title=_("Long Channel ID")))
|
||||
if not chan.is_closed():
|
||||
if not chan.is_frozen_for_sending():
|
||||
menu.addAction(_("Freeze (for sending)"), lambda: chan.set_frozen_for_sending(True))
|
||||
menu.addAction(_("Freeze (for sending)"), lambda: self.freeze_channel_for_sending(chan, True))
|
||||
else:
|
||||
menu.addAction(_("Unfreeze (for sending)"), lambda: chan.set_frozen_for_sending(False))
|
||||
menu.addAction(_("Unfreeze (for sending)"), lambda: self.freeze_channel_for_sending(chan, False))
|
||||
if not chan.is_frozen_for_receiving():
|
||||
menu.addAction(_("Freeze (for receiving)"), lambda: chan.set_frozen_for_receiving(True))
|
||||
else:
|
||||
@@ -359,7 +370,7 @@ class ChannelsList(MyTreeView):
|
||||
suggest_button = QPushButton(d, text=_('Suggest Peer'))
|
||||
def on_suggest():
|
||||
self.parent.wallet.network.start_gossip()
|
||||
nodeid = bh2u(lnworker.lnrater.suggest_peer() or b'')
|
||||
nodeid = bh2u(lnworker.suggest_peer() or b'')
|
||||
if not nodeid:
|
||||
remote_nodeid.setText("")
|
||||
remote_nodeid.setPlaceholderText(
|
||||
|
||||
@@ -742,7 +742,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
||||
tools_menu.addAction(_("Electrum preferences"), self.settings_dialog)
|
||||
|
||||
tools_menu.addAction(_("&Network"), self.gui_object.show_network_dialog).setEnabled(bool(self.network))
|
||||
tools_menu.addAction(_("&Lightning Network"), self.gui_object.show_lightning_dialog).setEnabled(bool(self.wallet.has_lightning() and self.network))
|
||||
tools_menu.addAction(_("&Lightning Gossip"), self.gui_object.show_lightning_dialog).setEnabled(bool(self.wallet.has_lightning() and self.network))
|
||||
tools_menu.addAction(_("Local &Watchtower"), self.gui_object.show_watchtower_dialog).setEnabled(bool(self.network and self.network.local_watchtower))
|
||||
tools_menu.addAction(_("&Plugins"), self.plugins_dialog)
|
||||
tools_menu.addSeparator()
|
||||
@@ -2205,8 +2205,8 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
||||
self.seed_button = StatusBarButton(read_QIcon("seed.png"), _("Seed"), self.show_seed_dialog )
|
||||
sb.addPermanentWidget(self.seed_button)
|
||||
self.lightning_button = None
|
||||
if self.wallet.has_lightning() and self.network:
|
||||
self.lightning_button = StatusBarButton(read_QIcon("lightning_disconnected.png"), _("Lightning Network"), self.gui_object.show_lightning_dialog)
|
||||
if self.wallet.has_lightning():
|
||||
self.lightning_button = StatusBarButton(read_QIcon("lightning.png"), _("Lightning Network"), self.gui_object.show_lightning_dialog)
|
||||
self.update_lightning_icon()
|
||||
sb.addPermanentWidget(self.lightning_button)
|
||||
self.status_button = None
|
||||
@@ -2247,10 +2247,10 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
||||
if self.lightning_button is None:
|
||||
return
|
||||
if self.network.lngossip is None:
|
||||
self.lightning_button.setVisible(False)
|
||||
return
|
||||
|
||||
# display colorful lightning icon to signal connection
|
||||
self.lightning_button.setIcon(read_QIcon("lightning.png"))
|
||||
self.lightning_button.setVisible(True)
|
||||
|
||||
cur, total, progress_percent = self.network.lngossip.get_sync_progress_estimate()
|
||||
# self.logger.debug(f"updating lngossip sync progress estimate: cur={cur}, total={total}")
|
||||
|
||||
@@ -130,6 +130,24 @@ class SettingsDialog(WindowModalDialog):
|
||||
# lightning
|
||||
lightning_widgets = []
|
||||
|
||||
help_gossip = _("""If this option is enabled, Electrum will download the network
|
||||
channels graph and compute payment path locally, instead of using trampoline payments. """)
|
||||
gossip_cb = QCheckBox(_("Download network graph"))
|
||||
gossip_cb.setToolTip(help_gossip)
|
||||
gossip_cb.setChecked(bool(self.config.get('use_gossip', False)))
|
||||
def on_gossip_checked(x):
|
||||
use_gossip = bool(x)
|
||||
self.config.set_key('use_gossip', use_gossip)
|
||||
if use_gossip:
|
||||
self.window.network.start_gossip()
|
||||
else:
|
||||
self.window.network.stop_gossip()
|
||||
util.trigger_callback('ln_gossip_sync_progress')
|
||||
# FIXME: update all wallet windows
|
||||
util.trigger_callback('channels_updated', self.wallet)
|
||||
gossip_cb.stateChanged.connect(on_gossip_checked)
|
||||
lightning_widgets.append((gossip_cb, None))
|
||||
|
||||
help_local_wt = _("""If this option is checked, Electrum will
|
||||
run a local watchtower and protect your channels even if your wallet is not
|
||||
open. For this to work, your computer needs to be online regularly.""")
|
||||
|
||||
Reference in New Issue
Block a user