diff --git a/src/builder.rs b/src/builder.rs index f0f38783f..5a6aae272 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -2238,6 +2238,7 @@ fn build_with_store_internal( let connection_manager = Arc::new(ConnectionManager::new( Arc::clone(&peer_manager), + config.disable_peer_networking, config.tor_config.clone(), Arc::clone(&keys_manager), Arc::clone(&logger), diff --git a/src/config.rs b/src/config.rs index a409b9e48..7c0c9fd16 100644 --- a/src/config.rs +++ b/src/config.rs @@ -179,6 +179,7 @@ pub(crate) const LIQUIDITY_DISCOVERY_RETRY_MAX_DELAY: Duration = Duration::from_ /// |----------------------------------------|--------------------------------------| /// | `storage_dir_path` | /tmp/ldk_node/ | /// | `network` | Bitcoin | +/// | `disable_peer_networking` | false | /// | `listening_addresses` | None | /// | `announcement_addresses` | None | /// | `node_alias` | None | @@ -199,6 +200,12 @@ pub struct Config { pub storage_dir_path: String, /// The used Bitcoin network. pub network: Network, + /// Whether Lightning peer networking is disabled. + /// + /// If enabled, the node won't listen for incoming peer connections, reconnect to persisted + /// peers, or initiate new peer connections. Chain synchronization and on-chain transaction + /// broadcasting remain enabled. + pub disable_peer_networking: bool, /// The addresses on which the node will listen for incoming connections. /// /// **Note**: We will only allow opening and accepting public channels if the `node_alias` and the @@ -271,6 +278,7 @@ impl Default for Config { Self { storage_dir_path: DEFAULT_STORAGE_DIR_PATH.to_string(), network: DEFAULT_NETWORK, + disable_peer_networking: false, listening_addresses: None, announcement_addresses: None, trusted_peers_0conf: Vec::new(), @@ -886,6 +894,11 @@ mod tests { assert_eq!(ElectrumSyncConfig::default().full_scan_stop_gap, DEFAULT_FULL_SCAN_STOP_GAP); } + #[test] + fn peer_networking_is_enabled_by_default() { + assert!(!Config::default().disable_peer_networking); + } + #[test] fn full_scan_stop_gap_is_clamped_to_valid_range() { assert_eq!(clamp_full_scan_stop_gap(MIN_FULL_SCAN_STOP_GAP), MIN_FULL_SCAN_STOP_GAP); diff --git a/src/connection.rs b/src/connection.rs index ccb6f9846..c353bf87f 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -57,6 +57,7 @@ where { pending_connections: PendingConnections, peer_manager: Arc, + disable_peer_networking: bool, tor_proxy_config: Option, keys_manager: Arc, logger: L, @@ -67,12 +68,19 @@ where L::Target: LdkLogger, { pub(crate) fn new( - peer_manager: Arc, tor_proxy_config: Option, - keys_manager: Arc, logger: L, + peer_manager: Arc, disable_peer_networking: bool, + tor_proxy_config: Option, keys_manager: Arc, logger: L, ) -> Self { let pending_connections = Mutex::new(HashMap::new()); - Self { pending_connections, peer_manager, tor_proxy_config, keys_manager, logger } + Self { + pending_connections, + peer_manager, + disable_peer_networking, + tor_proxy_config, + keys_manager, + logger, + } } pub(crate) async fn connect_peer_if_necessary( @@ -92,6 +100,11 @@ where pub(crate) async fn do_connect_peer( &self, node_id: PublicKey, addr: SocketAddress, ) -> Result<(), Error> { + if self.disable_peer_networking { + log_debug!(self.logger, "Peer networking is disabled."); + return Err(Error::ConnectionFailed); + } + // If another task is already connecting, subscribe to its result instead of starting a // duplicate attempt. if let Some(pending_connection_ready_receiver) = diff --git a/src/lib.rs b/src/lib.rs index 18152b3a7..f7cea26f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,9 +27,9 @@ //! # { //! use std::str::FromStr; //! +//! use ldk_node::bip39::Mnemonic; //! use ldk_node::bitcoin::secp256k1::PublicKey; //! use ldk_node::bitcoin::Network; -//! use ldk_node::bip39::Mnemonic; //! use ldk_node::entropy::NodeEntropy; //! use ldk_node::lightning::ln::msgs::SocketAddress; //! use ldk_node::lightning_invoice::Bolt11Invoice; @@ -426,7 +426,9 @@ impl Node { ); } - if let Some(listening_addresses) = &self.config.listening_addresses { + if self.config.disable_peer_networking { + log_info!(self.logger, "Lightning peer networking is disabled."); + } else if let Some(listening_addresses) = &self.config.listening_addresses { // Setup networking let peer_manager_connection_handler = Arc::clone(&self.peer_manager); let listening_logger = Arc::clone(&self.logger); @@ -520,17 +522,18 @@ impl Node { } } - // Regularly reconnect to persisted peers. - let connect_cm = Arc::clone(&self.connection_manager); - let connect_pm = Arc::clone(&self.peer_manager); - let connect_logger = Arc::clone(&self.logger); - let connect_peer_store = Arc::clone(&self.peer_store); - let mut stop_connect = self.stop_sender.subscribe(); - self.runtime.spawn_cancellable_background_task(async move { - let mut interval = tokio::time::interval(PEER_RECONNECTION_INTERVAL); - interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); - loop { - tokio::select! { + if !self.config.disable_peer_networking { + // Regularly reconnect to persisted peers. + let connect_cm = Arc::clone(&self.connection_manager); + let connect_pm = Arc::clone(&self.peer_manager); + let connect_logger = Arc::clone(&self.logger); + let connect_peer_store = Arc::clone(&self.peer_store); + let mut stop_connect = self.stop_sender.subscribe(); + self.runtime.spawn_cancellable_background_task(async move { + let mut interval = tokio::time::interval(PEER_RECONNECTION_INTERVAL); + interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); + loop { + tokio::select! { _ = stop_connect.changed() => { log_debug!( connect_logger, @@ -549,12 +552,13 @@ impl Node { let _ = connect_cm.do_connect_peer( peer_info.node_id, peer_info.address.clone(), - ).await; + ).await; } } + } } - } - }); + }); + } // Regularly broadcast node announcements. let bcast_cm = Arc::clone(&self.channel_manager); @@ -565,7 +569,7 @@ impl Node { let bcast_node_metrics = Arc::clone(&self.node_metrics); let mut stop_bcast = self.stop_sender.subscribe(); let node_alias = self.config.node_alias.clone(); - if may_announce_channel(&self.config).is_ok() { + if !self.config.disable_peer_networking && may_announce_channel(&self.config).is_ok() { self.runtime.spawn_cancellable_background_task(async move { // We check every 30 secs whether our last broadcast is NODE_ANN_BCAST_INTERVAL away. #[cfg(not(test))]