gossip: broadcast channel updates along with channel announcements
What changed, and why it matters
This change adjusts how Electrum broadcasts Lightning Network channel updates. Previously, a channel update was sent only once and only to the direct peer when a channel opened, and some peers (notably Eclair) appeared to ignore it. Now, channel updates are also broadcast periodically alongside channel announcements to all peers. This is a protocol compatibility/reliability improvement rather than a fix for a clear security vulnerability.
Review as a normal protocol correctness/reliability patch. No immediate security response appears warranted based on the diff alone, but verify that broadcasting channel updates does not leak private channel details and that the periodic gossip loop respects privacy settings for non-public channels.
Security signals we found
Change in network/gossip message propagation logic
Condition change from experimental forwarding flag to public-channel check
Commit message notes peer (Eclair) discards certain channel updates
Evidence from the diff
The patch modifies lnpeer.py to call maybe_send_channel_update() inside the periodic gossip broadcast loop (every 600 seconds) for public, open channels in GOOD state, and refactors maybe_mark_open() to use the same helper. The condition for sending the outgoing channel update at channel open changes from EXPERIMENTAL_LN_FORWARD_PAYMENTS + short_channel_id to chan.is_public(). A test is updated to mark channels as public (CF_ANNOUNCE_CHANNEL). The commit message frames this as fixing a gossip propagation issue where channel updates were only sent to the peer and could be discarded by Eclair.
Changed components
electrum/lnpeer.pytests/test_lnchannel.pyInspect captured patch +10 / −6
diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py
index f10d556..a13b29e 100644
--- a/electrum/lnpeer.py
+++ b/electrum/lnpeer.py
@@ -578,6 +578,7 @@ class Peer(Logger, EventListener):
for chan in public_channels:
if chan.is_open() and chan.peer_state == PeerState.GOOD:
self.maybe_send_channel_announcement(chan)
+ self.maybe_send_channel_update(chan)
await asyncio.sleep(600)
def _should_forward_gossip(self) -> bool:
@@ -1782,6 +1783,10 @@ class Peer(Logger, EventListener):
raw_msg = encode_msg(message_type, **payload)
self.transport.send_bytes(raw_msg)
+ def maybe_send_channel_update(self, chan: Channel):
+ chan_upd = chan.get_outgoing_gossip_channel_update()
+ self.transport.send_bytes(chan_upd)
+
def maybe_mark_open(self, chan: Channel):
if not chan.sent_channel_ready:
return
@@ -1806,13 +1811,12 @@ class Peer(Logger, EventListener):
if pending_channel_update:
chan.set_remote_update(pending_channel_update)
self.logger.info(f"CHANNEL OPENING COMPLETED ({chan.get_id_for_log()})")
- forwarding_enabled = self.network.config.EXPERIMENTAL_LN_FORWARD_PAYMENTS
- if forwarding_enabled and chan.short_channel_id:
+ if chan.is_public():
# send channel_update of outgoing edge to peer,
# so that channel can be used to receive payments
- self.logger.info(f"sending channel update for outgoing edge ({chan.get_id_for_log()})")
- chan_upd = chan.get_outgoing_gossip_channel_update()
- self.transport.send_bytes(chan_upd)
+ # Note: this is only useful for our unit tests. peers may discard
+ # channel updates if the channel has not been announced
+ self.maybe_send_channel_update(chan)
def maybe_send_announcement_signatures(self, chan: Channel, is_reply=False):
if not chan.is_public():
diff --git a/tests/test_lnchannel.py b/tests/test_lnchannel.py
index 2081dd7..7d74c54 100644
--- a/tests/test_lnchannel.py
+++ b/tests/test_lnchannel.py
@@ -104,7 +104,7 @@ def create_channel_state(
"remote_config": remote_config,
"local_config": local_config,
"constraints":lnpeer.ChannelConstraints(
- flags=0,
+ flags=lnchannel.CF_ANNOUNCE_CHANNEL,
capacity=funding_sat,
is_initiator=is_initiator,
funding_txn_minimum_depth=3,
Why this scored 26/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.