diff --git a/server/src/api/mod.rs b/server/src/api/mod.rs index c1079f2..e7561fd 100644 --- a/server/src/api/mod.rs +++ b/server/src/api/mod.rs @@ -10,3 +10,4 @@ pub(crate) mod list_payments; pub(crate) mod onchain_receive; pub(crate) mod onchain_send; pub(crate) mod open_channel; +pub(crate) mod update_channel_config; diff --git a/server/src/api/update_channel_config.rs b/server/src/api/update_channel_config.rs new file mode 100644 index 0000000..1f8cec2 --- /dev/null +++ b/server/src/api/update_channel_config.rs @@ -0,0 +1,75 @@ +use ldk_node::bitcoin::secp256k1::PublicKey; +use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; +use ldk_node::{Node, UserChannelId}; +use protos::channel_config::MaxDustHtlcExposure; +use protos::{UpdateChannelConfigRequest, UpdateChannelConfigResponse}; +use std::str::FromStr; +use std::sync::Arc; + +pub(crate) const UPDATE_CHANNEL_CONFIG_PATH: &str = "UpdateChannelConfig"; + +pub(crate) fn handle_update_channel_config_request( + node: Arc, request: UpdateChannelConfigRequest, +) -> Result { + let user_channel_id: u128 = + request.user_channel_id.parse().map_err(|_| ldk_node::NodeError::InvalidChannelId)?; + + //FIXME: Use ldk/ldk-node's partial config update api. + let current_config = node + .list_channels() + .into_iter() + .find(|c| c.user_channel_id.0 == user_channel_id) + .ok_or_else(|| ldk_node::NodeError::InvalidChannelId)? + .config; + + let updated_channel_config = + build_updated_channel_config(current_config, request.channel_config.unwrap()); + + let counterparty_node_id = PublicKey::from_str(&request.counterparty_node_id) + .map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; + node.update_channel_config( + &UserChannelId(user_channel_id), + counterparty_node_id, + updated_channel_config, + ) + .map_err(ldk_node::NodeError::from)?; + + Ok(UpdateChannelConfigResponse {}) +} + +fn build_updated_channel_config( + current_config: ChannelConfig, proto_channel_config: protos::ChannelConfig, +) -> ChannelConfig { + let max_dust_htlc_exposure = proto_channel_config + .max_dust_htlc_exposure + .map(|max_dust_htlc_exposure| match max_dust_htlc_exposure { + MaxDustHtlcExposure::FixedLimitMsat(limit_msat) => { + MaxDustHTLCExposure::FixedLimit { limit_msat } + }, + MaxDustHtlcExposure::FeeRateMultiplier(multiplier) => { + MaxDustHTLCExposure::FeeRateMultiplier { multiplier } + }, + }) + .unwrap_or(current_config.max_dust_htlc_exposure); + + let cltv_expiry_delta = proto_channel_config + .cltv_expiry_delta.map(|c| u16::try_from(c).unwrap()) + .unwrap_or(current_config.cltv_expiry_delta); + + ChannelConfig { + forwarding_fee_proportional_millionths: proto_channel_config + .forwarding_fee_proportional_millionths + .unwrap_or(current_config.forwarding_fee_proportional_millionths), + forwarding_fee_base_msat: proto_channel_config + .forwarding_fee_base_msat + .unwrap_or(current_config.forwarding_fee_base_msat), + cltv_expiry_delta, + max_dust_htlc_exposure, + force_close_avoidance_max_fee_satoshis: proto_channel_config + .force_close_avoidance_max_fee_satoshis + .unwrap_or(current_config.force_close_avoidance_max_fee_satoshis), + accept_underpaying_htlcs: proto_channel_config + .accept_underpaying_htlcs + .unwrap_or(current_config.accept_underpaying_htlcs), + } +} diff --git a/server/src/service.rs b/server/src/service.rs index 510131d..b8fb525 100644 --- a/server/src/service.rs +++ b/server/src/service.rs @@ -25,6 +25,9 @@ use crate::api::list_payments::{handle_list_payments_request, LIST_PAYMENTS_PATH use crate::api::onchain_receive::{handle_onchain_receive_request, ONCHAIN_RECEIVE_PATH}; use crate::api::onchain_send::{handle_onchain_send_request, ONCHAIN_SEND_PATH}; use crate::api::open_channel::{handle_open_channel, OPEN_CHANNEL_PATH}; +use crate::api::update_channel_config::{ + handle_update_channel_config_request, UPDATE_CHANNEL_CONFIG_PATH, +}; #[derive(Clone)] pub struct NodeService { @@ -62,6 +65,9 @@ impl Service> for NodeService { OPEN_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_open_channel)), CLOSE_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_close_channel_request)), LIST_CHANNELS_PATH => Box::pin(handle_request(node, req, handle_list_channels_request)), + UPDATE_CHANNEL_CONFIG_PATH => { + Box::pin(handle_request(node, req, handle_update_channel_config_request)) + }, GET_PAYMENT_DETAILS_PATH => { Box::pin(handle_request(node, req, handle_get_payment_details_request)) },