cli: add_peer: make add_peer wait for connection
What changed, and why it matters
This commit fixes a command-line bug where the `add_peer` command would report success before actually confirming that a new Lightning peer connected. Previously, callers could be told the peer was added even if the connection later failed or timed out. The change makes the command wait for the peer handshake to complete and report a clear error if it does not.
Treat as a reliability/usability fix rather than a critical security patch. Users relying on `add_peer` in scripts or automated workflows should update so that failures are reported accurately. No immediate emergency response is warranted based on the diff alone.
Security signals we found
CLI command returned success before asynchronous peer initialization completed
Missing await on peer.initialized future allowed false-positive connection confirmations
Error handling now surfaces connection failures to the user instead of silently succeeding
Evidence from the diff
In electrum/commands.py, the add_peer CLI command previously awaited lnworker.add_peer() but did not await the resulting peer object’s initialized future. Because add_peer() returns as soon as the transport is opened, the command returned True before the Lightning P2P handshake finished. The patch captures the returned peer, waits up to LN_P2P_NETWORK_TIMEOUT seconds for peer.initialized, and raises a UserFacingException on cancellation or any other exception. A CancelledError import and LN_P2P_NETWORK_TIMEOUT import were added.
Changed components
electrum/commands.pyCLI `add_peer` commandLightning Network peer initializationInspect captured patch +8 / −1
diff --git a/electrum/commands.py b/electrum/commands.py
index 2b23121..8e350de 100644
--- a/electrum/commands.py
+++ b/electrum/commands.py
@@ -33,6 +33,7 @@ import binascii
import base64
import asyncio
import inspect
+from asyncio import CancelledError
from collections import defaultdict
from functools import wraps
from decimal import Decimal, InvalidOperation
@@ -44,6 +45,7 @@ import electrum_ecc as ecc
from . import util
from .lnmsg import OnionWireSerializer
+from .lnworker import LN_P2P_NETWORK_TIMEOUT
from .logging import Logger
from .onion_message import create_blinded_path, send_onion_message_to
from .submarine_swaps import NostrTransport
@@ -1684,7 +1686,12 @@ class Commands(Logger):
arg:int:timeout:Timeout in seconds (default=20)
"""
lnworker = self.network.lngossip if gossip else wallet.lnworker
- await lnworker.add_peer(connection_string)
+ peer = await lnworker.add_peer(connection_string)
+ try:
+ await util.wait_for2(peer.initialized, timeout=LN_P2P_NETWORK_TIMEOUT)
+ except (CancelledError, Exception) as e:
+ # FIXME often simply CancelledError and real cause (e.g. timeout) remains hidden
+ raise UserFacingException(f"Connection failed: {repr(e)}")
return True
@command('wnl')
Why this scored 20/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.