diff --git a/mutiny-core/src/ldkstorage.rs b/mutiny-core/src/ldkstorage.rs index 778376e86..22585f540 100644 --- a/mutiny-core/src/ldkstorage.rs +++ b/mutiny-core/src/ldkstorage.rs @@ -197,6 +197,7 @@ impl MutinyNodePersister { pub(crate) async fn read_channel_manager( &self, network: Network, + accept_underpaying_htlcs: bool, chain_monitor: Arc>, mutiny_chain: Arc>, fee_estimator: Arc>, @@ -215,6 +216,7 @@ impl MutinyNodePersister { let bytes = FromHex::from_hex(&hex)?; let res = Self::parse_channel_manager( bytes, + accept_underpaying_htlcs, chain_monitor, mutiny_chain, fee_estimator, @@ -234,6 +236,7 @@ impl MutinyNodePersister { Self::create_new_channel_manager( network, + accept_underpaying_htlcs, chain_monitor, mutiny_chain, fee_estimator, @@ -250,6 +253,7 @@ impl MutinyNodePersister { let bytes = self.read_value(CHANNEL_MANAGER_KEY)?; Self::parse_channel_manager( bytes, + accept_underpaying_htlcs, chain_monitor, mutiny_chain, fee_estimator, @@ -265,6 +269,7 @@ impl MutinyNodePersister { #[allow(clippy::too_many_arguments)] fn parse_channel_manager( bytes: Vec, + accept_underpaying_htlcs: bool, chain_monitor: Arc>, mutiny_chain: Arc>, fee_estimator: Arc>, @@ -286,7 +291,7 @@ impl MutinyNodePersister { mutiny_chain, router, mutiny_logger, - default_user_config(), + default_user_config(accept_underpaying_htlcs), channel_monitor_mut_references, ); let mut readable_kv_value = Cursor::new(bytes); @@ -307,6 +312,7 @@ impl MutinyNodePersister { #[allow(clippy::too_many_arguments)] pub(crate) async fn create_new_channel_manager( network: Network, + accept_underpaying_htlcs: bool, chain_monitor: Arc>, mutiny_chain: Arc>, fee_estimator: Arc>, @@ -344,7 +350,7 @@ impl MutinyNodePersister { keys_manager.clone(), keys_manager.clone(), keys_manager, - default_user_config(), + default_user_config(accept_underpaying_htlcs), chain_params, utils::now().as_secs() as u32, ); @@ -978,6 +984,7 @@ mod test { let read = persister .read_channel_manager( network, + false, chain_monitor.clone(), chain.clone(), fees.clone(), @@ -1001,6 +1008,7 @@ mod test { let read = persister .read_channel_manager( network, + false, chain_monitor, chain.clone(), fees.clone(), diff --git a/mutiny-core/src/lsp/mod.rs b/mutiny-core/src/lsp/mod.rs index df66a2c55..db6bca2ce 100644 --- a/mutiny-core/src/lsp/mod.rs +++ b/mutiny-core/src/lsp/mod.rs @@ -35,6 +35,13 @@ impl LspConfig { token, }) } + + pub fn accept_underpaying_htlcs(&self) -> bool { + match self { + LspConfig::VoltageFlow(_) => false, + LspConfig::Lsps(_) => true, + } + } } pub fn deserialize_lsp_config<'de, D>(deserializer: D) -> Result, D::Error> @@ -128,6 +135,13 @@ impl AnyLsp { )?; Ok(Self::Lsps(lsps_client)) } + + pub fn accept_underpaying_htlcs(&self) -> bool { + match self { + AnyLsp::VoltageFlow(_) => false, + AnyLsp::Lsps(_) => true, + } + } } #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] diff --git a/mutiny-core/src/node.rs b/mutiny-core/src/node.rs index 5dd05a248..8e2798703 100644 --- a/mutiny-core/src/node.rs +++ b/mutiny-core/src/node.rs @@ -385,10 +385,31 @@ impl NodeBuilder { scoring_params(), )); + log_info!(logger, "creating lsp client"); + let lsp_config: Option = match node_index.lsp { + None => { + log_info!(logger, "no lsp saved, using configured one if present"); + self.lsp_config + } + Some(ref lsp) => { + if self.lsp_config.as_ref() == Some(lsp) { + log_info!(logger, "lsp config matches saved lsp config"); + self.lsp_config + } else { + log_info!(logger, "lsp config does not match saved lsp config"); + None + } + } + }; + // init channel manager + let accept_underpaying_htlcs = lsp_config + .as_ref() + .is_some_and(|l| l.accept_underpaying_htlcs()); let mut read_channel_manager = persister .read_channel_manager( network, + accept_underpaying_htlcs, chain_monitor.clone(), chain.clone(), fee_estimator.clone(), @@ -403,53 +424,6 @@ impl NodeBuilder { let channel_manager: Arc> = Arc::new(read_channel_manager.channel_manager); - // Check all existing channels against default configs. - // If we have default config changes, those should apply - // to all existing and new channels. - let default_config = default_user_config().channel_config; - for channel in channel_manager.list_channels() { - // unwrap is safe after LDK.0.0.109 - if channel.config.unwrap() != default_config { - match channel_manager.update_channel_config( - &channel.counterparty.node_id, - &[channel.channel_id], - &default_config, - ) { - Ok(_) => { - log_debug!( - logger, - "changed default config for channel: {}", - channel.channel_id.to_hex() - ) - } - Err(e) => { - log_error!( - logger, - "error changing default config for channel: {} - {e:?}", - channel.channel_id.to_hex() - ) - } - }; - } - } - - log_info!(logger, "creating lsp client"); - let lsp_config: Option = match node_index.lsp { - None => { - log_info!(logger, "no lsp saved, using configured one if present"); - self.lsp_config - } - Some(ref lsp) => { - if self.lsp_config.as_ref() == Some(lsp) { - log_info!(logger, "lsp config matches saved lsp config"); - self.lsp_config - } else { - log_info!(logger, "lsp config does not match saved lsp config"); - None - } - } - }; - let stop = Arc::new(AtomicBool::new(false)); let (lsp_client, liquidity) = match lsp_config { @@ -621,6 +595,36 @@ impl NodeBuilder { } } + // Check all existing channels against default configs. + // If we have default config changes, those should apply + // to all existing and new channels. + let default_config = default_user_config(accept_underpaying_htlcs).channel_config; + for channel in channel_manager.list_channels() { + // unwrap is safe after LDK.0.0.109 + if channel.config.unwrap() != default_config { + match channel_manager.update_channel_config( + &channel.counterparty.node_id, + &[channel.channel_id], + &default_config, + ) { + Ok(_) => { + log_debug!( + logger, + "changed default config for channel: {}", + channel.channel_id.to_hex() + ) + } + Err(e) => { + log_error!( + logger, + "error changing default config for channel: {} - {e:?}", + channel.channel_id.to_hex() + ) + } + }; + } + } + let background_persister = persister.clone(); let background_event_handler = event_handler.clone(); let background_processor_logger = logger.clone(); @@ -1693,7 +1697,11 @@ impl Node { fee_rate: Option, user_channel_id: Option, ) -> Result { - let mut config = default_user_config(); + let accept_underpaying_htlcs = self + .lsp_client + .as_ref() + .is_some_and(|l| l.accept_underpaying_htlcs()); + let mut config = default_user_config(accept_underpaying_htlcs); // if we are opening channel to LSP, turn off SCID alias until CLN is updated // LSP protects all invoice information anyways, so no UTXO leakage @@ -1797,7 +1805,11 @@ impl Node { // channel size is the total value of the utxos minus the fee let channel_value_satoshis = utxo_value - expected_fee; - let mut config = default_user_config(); + let accept_underpaying_htlcs = self + .lsp_client + .as_ref() + .is_some_and(|l| l.accept_underpaying_htlcs()); + let mut config = default_user_config(accept_underpaying_htlcs); // if we are opening channel to LSP, turn off SCID alias until CLN is updated // LSP protects all invoice information anyways, so no UTXO leakage if let Some(lsp) = self.lsp_client.clone() { @@ -2158,7 +2170,7 @@ pub(crate) fn split_peer_connection_string( Ok((pubkey, peer_addr_str.to_string())) } -pub(crate) fn default_user_config() -> UserConfig { +pub(crate) fn default_user_config(accept_underpaying_htlcs: bool) -> UserConfig { UserConfig { channel_handshake_limits: ChannelHandshakeLimits { // lnd's max to_self_delay is 2016, so we want to be compatible. @@ -2183,7 +2195,7 @@ pub(crate) fn default_user_config() -> UserConfig { max_dust_htlc_exposure: MaxDustHTLCExposure::FixedLimitMsat( 21_000_000 * 100_000_000 * 1_000, ), - accept_underpaying_htlcs: true, + accept_underpaying_htlcs, ..Default::default() }, ..Default::default()