Auto-reconnect Lightning peers and document service management#1
Merged
refined-element merged 4 commits intoApr 29, 2026
Merged
Conversation
The Lightning node had no way to keep critical peer connections alive after a TCP drop — once a peer disconnected, channels became unusable until the user manually called ln_connect again. This is the same gap that left an LN channel offline after a recent reboot even though both nodes were healthy. Add a persistent_peers config field on LightningConfig listing peers the node should keep connected (pubkey@host:port). On startup, after the LDK background processor is running, spawn a reconnector that ticks every 60s, walks the peer list, and dials any persistent peer not currently in peer_manager().list_peers(). Hostnames are resolved on each tick so DHCP/DNS changes on the LAN don't permanently break reconnection. Also document service management since users without an AI assistant need to know how to start and stop the node: - README gains a Stop section (Ctrl+C, RPC stop, kill, dashboard Settings page) and Auto-Start sections for macOS launchd and Linux systemd. - A template launchd plist lands in config/com.bitcoinwolfe.node.plist with placeholder paths for the user to fill in. The plist uses KeepAlive with SuccessfulExit=false so launchd restarts the node on crashes but respects intentional shutdowns. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR adds a Lightning “persistent peers” feature to automatically re-establish configured LN peer connections, and expands the README with service-management guidance (launchd/systemd) plus a launchd plist template.
Changes:
- Add
[lightning].persistent_peersconfig and default it to empty. - Spawn a periodic Lightning peer reconnector task that dials configured peers not currently connected.
- Add service-management documentation (stop + auto-start) and include a macOS launchd plist template.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| crates/wolfe-types/src/config.rs | Adds persistent_peers to LightningConfig and defaults it. |
| crates/wolfe-node/src/main.rs | Implements the periodic LN peer reconnector and adds parse_ln_peer. |
| config/com.bitcoinwolfe.node.plist | Adds a launchd template for running the node as a macOS user service. |
| README.md | Documents stop methods and auto-start setup for macOS (launchd) and Linux (systemd). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Handle SIGTERM alongside SIGINT/Ctrl+C so kill, systemctl stop, and launchctl unload all exit through the same graceful shutdown path. - Resolve persistent peer hostnames with tokio::net::lookup_host to keep blocking DNS off the runtime workers. - Validate persistent_peers pubkeys once at startup; invalid entries are logged once and skipped instead of warning every 60s. - Move the launchd plist log path out of data/ so a fresh install doesn't fail before the binary creates that directory. - README: document SIGTERM as a graceful stop, correct LaunchAgents to run on login (not boot) with a LaunchDaemons pointer, and add TimeoutStopSec=30 to the systemd example so Lightning state can persist. - Update the persistent_peers doc comment to reflect the ongoing reconnect behavior. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Threads a `picture` field through NostrConfig and the NostrBridge so it shows up in the published kind-0 metadata event. Invalid URLs are warned once and skipped rather than failing the whole metadata publish. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cargo fmt --check on the prior commits flagged two long error!() calls and clippy was hitting too_many_arguments after the picture field was added to NostrBridge::new (8 args, default threshold is 7). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
persistent_peersconfig in[lightning]. A reconnector ticks every 60s and dials any listed peer that's not currently connected. Solves the "LN channel goes dark after a reboot or transient TCP drop" problem.config/com.bitcoinwolfe.node.plist.Why
The Lightning node had no mechanism to keep critical peer connections alive after a disconnect. If LDK lost the TCP connection to a counterparty, the channels stayed open on-chain but became
is_usable: falseuntil a manualln_connect. This was hit in practice after an OS update reboot — the channel partner's address wasn't stored anywhere, so reconnection required AI assistance to look up the IP.The reconnector fixes the reconnection loop. The README/launchd docs fix the bootstrap loop.
Implementation
Reconnector (
crates/wolfe-node/src/main.rs):peer_manager().list_peers()into aHashSet<PublicKey>, then iterate config peers and dial any not in the set.ToSocketAddrs) so DHCP/DNS churn on the LAN doesn't permanently break reconnection.debug!(silent retries) since the next tick will try again; only invalid config entries warn.parse_ln_peerhelper splitspubkey@host:portinto(PublicKey, SocketAddr).Config (
crates/wolfe-types/src/config.rs):persistent_peers: Vec<String>toLightningConfigwith sensible default (empty).Service management:
config/com.bitcoinwolfe.node.plist: Template plist with__WOLFE_BINARY__/__WOLFE_DIR__placeholders.KeepAlivewithSuccessfulExit=falsemeans launchd restarts on crashes but respects intentionalstop.ThrottleInterval=10prevents tight crash loops.stop,kill, dashboard Settings page — all converge on the same graceful shutdown path.launchctl load) and Linux (systemctl enable).Test plan
cargo build --release -p wolfe-node— clean buildcargo clippy --release -p wolfe-node -p wolfe-types -- -D warnings— cleanpersistent_peers = ["02acb60b...@host:9735"], observedpersistent Lightning peer reconnector startedlog, killed peer connection, watched it reconnect on the next tick. Lightning info reportednum_peers: 1and channels becameis_usable: trueautomatically.~/Library/LaunchAgents/, starts on login, restarts on crash, respects RPCstop.🤖 Generated with Claude Code