Skip to content

Commit b94b182

Browse files
committed
Allow setting a ChannelConfig for LSPS2 JIT channels
When acting as an LSPS2 service, we'd previously always reuse the node-wide configuration for the JIT channels we open towards clients, while hard-coding their forwarding fees to zero. Here, we add an optional channel_config field to LSPS2ServiceConfig that allows configuring the JIT channels separately from regular channels. If unset, we retain the previous behavior, i.e., zero forwarding fees, as we're compensated via the channel opening fee. This resolves the TODO to revisit the hard-coded zero-fee decision. This change was developed with the assistance of AI tooling (Claude Code).
1 parent dc4fa49 commit b94b182

2 files changed

Lines changed: 44 additions & 6 deletions

File tree

src/liquidity/service/lsps2.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use lightning_liquidity::lsps2::msgs::LSPS2RawOpeningFeeParams;
2222
use lightning_liquidity::lsps2::service::LSPS2ServiceConfig as LdkLSPS2ServiceConfig;
2323
use lightning_types::payment::PaymentHash;
2424

25+
use crate::config::ChannelConfig;
2526
use crate::logger::{log_error, LdkLogger};
2627
use crate::types::{ChannelManager, KeysManager, LiquidityManager, PeerManager, Wallet};
2728
use crate::{total_anchor_channels_reserve_sats, Config};
@@ -106,6 +107,15 @@ pub struct LSPS2ServiceConfig {
106107
///
107108
/// [`Node::open_0reserve_channel`]: crate::Node::open_0reserve_channel
108109
pub disable_client_reserve: bool,
110+
/// The channel config we'll apply to the JIT channels we open to clients, allowing to
111+
/// configure them separately from regular channels.
112+
///
113+
/// If set, the given config is used without modification. Note that this means any
114+
/// forwarding fees configured here are charged in addition to the channel opening fee.
115+
///
116+
/// If set to `None`, we'll reuse the node-wide config, but override the forwarding fees
117+
/// to be zero, as we're already compensated via the channel opening fee.
118+
pub channel_config: Option<ChannelConfig>,
109119
}
110120

111121
impl<L: Deref> LSPS2ServiceLiquiditySource<L>
@@ -487,11 +497,17 @@ where
487497
debug_assert!(!config.channel_handshake_config.announce_for_forwarding);
488498
debug_assert!(config.accept_forwards_to_priv_channels);
489499

490-
// We set the forwarding fee to 0 for now as we're getting paid by the channel fee.
491-
//
492-
// TODO: revisit this decision eventually.
493-
config.channel_config.forwarding_fee_base_msat = 0;
494-
config.channel_config.forwarding_fee_proportional_millionths = 0;
500+
match service_config.channel_config {
501+
Some(channel_config) => {
502+
config.channel_config = channel_config.into();
503+
},
504+
None => {
505+
// By default we set the forwarding fees to 0 as we're getting paid by the
506+
// channel opening fee.
507+
config.channel_config.forwarding_fee_base_msat = 0;
508+
config.channel_config.forwarding_fee_proportional_millionths = 0;
509+
},
510+
}
495511

496512
let result = if service_config.disable_client_reserve {
497513
self.channel_manager.create_channel_to_trusted_peer_0reserve(

tests/integration_tests_rust.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ use common::{
2929
};
3030
use electrsd::corepc_node::{self, Node as BitcoinD};
3131
use electrsd::ElectrsD;
32-
use ldk_node::config::{AsyncPaymentsRole, EsploraSyncConfig, DEFAULT_FULL_SCAN_STOP_GAP};
32+
use ldk_node::config::{
33+
AsyncPaymentsRole, ChannelConfig, EsploraSyncConfig, DEFAULT_FULL_SCAN_STOP_GAP,
34+
};
3335
use ldk_node::entropy::NodeEntropy;
3436
use ldk_node::liquidity::LSPS2ServiceConfig;
3537
use ldk_node::payment::{
@@ -2787,6 +2789,13 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) {
27872789
// Setup three nodes: service, client, and payer
27882790
let channel_opening_fee_ppm = 10_000;
27892791
let channel_over_provisioning_ppm = 100_000;
2792+
2793+
let jit_channel_config = ChannelConfig {
2794+
forwarding_fee_proportional_millionths: 0,
2795+
forwarding_fee_base_msat: 0,
2796+
force_close_avoidance_max_fee_satoshis: 1337,
2797+
..Default::default()
2798+
};
27902799
let lsps2_service_config = LSPS2ServiceConfig {
27912800
require_token: None,
27922801
advertise_service: false,
@@ -2799,6 +2808,7 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) {
27992808
max_client_to_self_delay: 1024,
28002809
client_trusts_lsp,
28012810
disable_client_reserve: false,
2811+
channel_config: Some(jit_channel_config),
28022812
};
28032813

28042814
let service_config = random_config(true);
@@ -2890,6 +2900,14 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) {
28902900
let channel_value_sats = client_node.list_channels().first().unwrap().channel_value_sats;
28912901
assert_eq!(channel_value_sats, expected_channel_size_sat);
28922902

2903+
let jit_channel = service_node
2904+
.list_channels()
2905+
.into_iter()
2906+
.find(|c| c.counterparty.node_id == client_node.node_id())
2907+
.unwrap();
2908+
assert_eq!(jit_channel.config.force_close_avoidance_max_fee_satoshis, 1337);
2909+
assert_eq!(jit_channel.config.forwarding_fee_base_msat, 0);
2910+
28932911
println!("Generating regular invoice!");
28942912
let invoice_description =
28952913
Bolt11InvoiceDescription::Direct(Description::new(String::from("asdf")).unwrap()).into();
@@ -3118,6 +3136,7 @@ async fn lsps2_client_trusts_lsp() {
31183136
max_client_to_self_delay: 1024,
31193137
client_trusts_lsp: true,
31203138
disable_client_reserve: false,
3139+
channel_config: None,
31213140
};
31223141

31233142
let service_config = random_config(true);
@@ -3293,6 +3312,7 @@ async fn lsps2_lsp_trusts_client_but_client_does_not_claim() {
32933312
max_client_to_self_delay: 1024,
32943313
client_trusts_lsp: false,
32953314
disable_client_reserve: false,
3315+
channel_config: None,
32963316
};
32973317

32983318
let service_config = random_config(true);
@@ -4092,6 +4112,7 @@ async fn do_lsps2_multi_lsp_picks_cheapest(reverse_order: bool) {
40924112
max_client_to_self_delay: 1024,
40934113
client_trusts_lsp: true,
40944114
disable_client_reserve: false,
4115+
channel_config: None,
40954116
};
40964117
let cheap_node_config = random_config(true);
40974118
setup_builder!(cheap_builder, cheap_node_config.node_config);
@@ -4115,6 +4136,7 @@ async fn do_lsps2_multi_lsp_picks_cheapest(reverse_order: bool) {
41154136
max_client_to_self_delay: 1024,
41164137
client_trusts_lsp: true,
41174138
disable_client_reserve: false,
4139+
channel_config: None,
41184140
};
41194141
let expensive_node_config = random_config(true);
41204142
setup_builder!(expensive_builder, expensive_node_config.node_config);

0 commit comments

Comments
 (0)