Skip to content

Commit 3e9e537

Browse files
authored
Merge pull request #250 from tankyleo/2026-07-0fc-commitments
Expose zero-fee commitment channel configuration
2 parents 1e57b87 + 36df71e commit 3e9e537

4 files changed

Lines changed: 49 additions & 1 deletion

File tree

contrib/ldk-server-config.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ alias = "ldk_server" # Lightning node alias
88
#pathfinding_scores_source_url = "https://rapidsync.lightningdevkit.org/scoring/scorer.bin" # External pathfinding scores source (optional, defaults to this URL on mainnet; set to "" to disable)
99
#rgs_server_url = "https://rapidsync.lightningdevkit.org/snapshot/v2/" # Optional: RGS URL for rapid gossip sync
1010
#async_payments_role = "client" # Optional async payments role: "client" or "server"
11+
#enable_zero_fee_commitments = false # Enable zero-fee commitment channels (default: false)
1112

1213
# Background probing service (optional)
1314
# CAUTION: Probes send real HTLCs and can lock outbound liquidity until they time out.

docs/configuration.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,18 @@ on macOS).
5252

5353
Core node settings: which Bitcoin network to use, Lightning peer listening and announcement
5454
addresses, the gRPC bind address, node alias, optional Rapid Gossip Sync / pathfinding
55-
scores URLs, and the async payments role.
55+
scores URLs, the async payments role, and zero-fee commitment channels.
5656

5757
Set `async_payments_role = "client"` to ask peers to hold HTLCs where possible, allowing
5858
this node to go offline. Set `async_payments_role = "server"` to hold async payment HTLCs
5959
and onion messages for peers. The server role requires an announceable node configuration.
6060
Leave the field unset to disable async payments.
6161

62+
Set `enable_zero_fee_commitments = true` to prefer zero-fee commitment channels,
63+
falling back to other channel types supported by the peer. Enabling this setting requires a chain
64+
source that supports Bitcoin Core's `submitpackage` RPC, and relays TRUC, P2A, and ephemeral
65+
dust. The default is `false`.
66+
6267
### `[probing]`
6368

6469
Enables LDK Node's background probing service to train the payment scorer with current

ldk-server/src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ fn main() {
156156
ldk_node_config.announcement_addresses = config_file.announcement_addrs;
157157
ldk_node_config.network = config_file.network;
158158
ldk_node_config.hrn_config = config_file.hrn_config;
159+
ldk_node_config.anchor_channels_config.enable_zero_fee_commitments =
160+
config_file.enable_zero_fee_commitments;
159161

160162
let mut builder = Builder::from_config(ldk_node_config);
161163
builder.set_log_facade_logger();

ldk-server/src/util/config.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ pub struct Config {
7070
pub pathfinding_scores_source_url: Option<String>,
7171
pub probing_config: Option<ProbingConfig>,
7272
pub async_payments_role: Option<AsyncPaymentsRole>,
73+
pub enable_zero_fee_commitments: bool,
7374
pub metrics_enabled: bool,
7475
pub poll_metrics_interval: Option<u64>,
7576
pub metrics_username: Option<String>,
@@ -144,6 +145,7 @@ struct ConfigBuilder {
144145
pathfinding_scores_source_url: Option<String>,
145146
probing: Option<ProbingTomlConfig>,
146147
async_payments_role: Option<String>,
148+
enable_zero_fee_commitments: Option<bool>,
147149
metrics_enabled: Option<bool>,
148150
poll_metrics_interval: Option<u64>,
149151
metrics_username: Option<String>,
@@ -167,6 +169,8 @@ impl ConfigBuilder {
167169
node.pathfinding_scores_source_url.or(self.pathfinding_scores_source_url.clone());
168170
self.async_payments_role =
169171
node.async_payments_role.or(self.async_payments_role.clone());
172+
self.enable_zero_fee_commitments =
173+
node.enable_zero_fee_commitments.or(self.enable_zero_fee_commitments);
170174
self.rgs_server_url = node.rgs_server_url.or(self.rgs_server_url.clone());
171175
}
172176

@@ -286,6 +290,10 @@ impl ConfigBuilder {
286290
self.async_payments_role = Some(async_payments_role.clone());
287291
}
288292

293+
if let Some(enable_zero_fee_commitments) = args.node_enable_zero_fee_commitments {
294+
self.enable_zero_fee_commitments = Some(enable_zero_fee_commitments);
295+
}
296+
289297
if args.has_probing_options() {
290298
let probing = self.probing.get_or_insert_with(ProbingTomlConfig::default);
291299
if let Some(probing_strategy) = &args.probing_strategy {
@@ -595,6 +603,7 @@ impl ConfigBuilder {
595603
pathfinding_scores_source_url,
596604
probing_config,
597605
async_payments_role,
606+
enable_zero_fee_commitments: self.enable_zero_fee_commitments.unwrap_or(false),
598607
metrics_enabled,
599608
poll_metrics_interval,
600609
metrics_username,
@@ -633,6 +642,7 @@ struct NodeConfig {
633642
alias: Option<String>,
634643
pathfinding_scores_source_url: Option<String>,
635644
async_payments_role: Option<String>,
645+
enable_zero_fee_commitments: Option<bool>,
636646
rgs_server_url: Option<String>,
637647
}
638648

@@ -1110,6 +1120,13 @@ pub struct ArgsConfig {
11101120
)]
11111121
node_async_payments_role: Option<String>,
11121122

1123+
#[arg(
1124+
long,
1125+
env = "LDK_SERVER_NODE_ENABLE_ZERO_FEE_COMMITMENTS",
1126+
help = "Whether to enable zero-fee commitment channels. Defaults to false."
1127+
)]
1128+
node_enable_zero_fee_commitments: Option<bool>,
1129+
11131130
#[arg(
11141131
long,
11151132
env = "LDK_SERVER_PROBING_STRATEGY",
@@ -1289,6 +1306,7 @@ mod tests {
12891306
alias = "LDK Server"
12901307
rgs_server_url = "https://rapidsync.lightningdevkit.org/snapshot/v2/"
12911308
async_payments_role = "client"
1309+
enable_zero_fee_commitments = true
12921310
12931311
[tls]
12941312
cert_path = "/path/to/tls.crt"
@@ -1348,6 +1366,7 @@ mod tests {
13481366
node_alias: Some(String::from("LDK Server CLI")),
13491367
pathfinding_scores_source_url: Some(String::from("https://example.com/")),
13501368
node_async_payments_role: Some(String::from("server")),
1369+
node_enable_zero_fee_commitments: Some(false),
13511370
probing_strategy: None,
13521371
probing_top_node_count: None,
13531372
probing_max_hops: None,
@@ -1383,6 +1402,7 @@ mod tests {
13831402
storage_dir_path: None,
13841403
pathfinding_scores_source_url: None,
13851404
node_async_payments_role: None,
1405+
node_enable_zero_fee_commitments: None,
13861406
probing_strategy: None,
13871407
probing_top_node_count: None,
13881408
probing_max_hops: None,
@@ -1497,6 +1517,7 @@ mod tests {
14971517
pathfinding_scores_source_url: None,
14981518
probing_config: None,
14991519
async_payments_role: Some(AsyncPaymentsRole::Client),
1520+
enable_zero_fee_commitments: true,
15001521
metrics_enabled: false,
15011522
poll_metrics_interval: None,
15021523
metrics_username: None,
@@ -1522,6 +1543,7 @@ mod tests {
15221543
assert_eq!(config.log_file_path, expected.log_file_path);
15231544
assert_eq!(config.pathfinding_scores_source_url, expected.pathfinding_scores_source_url);
15241545
assert!(matches!(config.async_payments_role, Some(AsyncPaymentsRole::Client)));
1546+
assert_eq!(config.enable_zero_fee_commitments, expected.enable_zero_fee_commitments);
15251547
assert_eq!(config.metrics_enabled, expected.metrics_enabled);
15261548
assert_eq!(config.tor_config, expected.tor_config);
15271549

@@ -1939,6 +1961,7 @@ mod tests {
19391961
pathfinding_scores_source_url: Some("https://example.com/".to_string()),
19401962
probing_config: None,
19411963
async_payments_role: Some(AsyncPaymentsRole::Server),
1964+
enable_zero_fee_commitments: false,
19421965
metrics_enabled: false,
19431966
poll_metrics_interval: None,
19441967
metrics_username: None,
@@ -1961,6 +1984,7 @@ mod tests {
19611984
assert!(config.lsps2_service_config.is_none());
19621985
assert_eq!(config.pathfinding_scores_source_url, expected.pathfinding_scores_source_url);
19631986
assert!(matches!(config.async_payments_role, Some(AsyncPaymentsRole::Server)));
1987+
assert_eq!(config.enable_zero_fee_commitments, expected.enable_zero_fee_commitments);
19641988
assert_eq!(config.metrics_enabled, expected.metrics_enabled);
19651989
assert_eq!(config.tor_config, expected.tor_config);
19661990
assert_eq!(config.log_max_size_bytes, expected.log_max_size_bytes);
@@ -2059,6 +2083,7 @@ mod tests {
20592083
pathfinding_scores_source_url: Some("https://example.com/".to_string()),
20602084
probing_config: None,
20612085
async_payments_role: Some(AsyncPaymentsRole::Server),
2086+
enable_zero_fee_commitments: false,
20622087
metrics_enabled: false,
20632088
poll_metrics_interval: None,
20642089
metrics_username: None,
@@ -2085,6 +2110,7 @@ mod tests {
20852110
assert_eq!(config.lsps2_service_config.is_some(), expected.lsps2_service_config.is_some());
20862111
assert_eq!(config.pathfinding_scores_source_url, expected.pathfinding_scores_source_url);
20872112
assert!(matches!(config.async_payments_role, Some(AsyncPaymentsRole::Server)));
2113+
assert_eq!(config.enable_zero_fee_commitments, expected.enable_zero_fee_commitments);
20882114
assert_eq!(config.metrics_enabled, expected.metrics_enabled);
20892115
assert_eq!(config.tor_config, expected.tor_config);
20902116
}
@@ -2490,6 +2516,20 @@ mod tests {
24902516
assert_eq!(args_config.probing_cooldown_secs, Some(1800));
24912517
}
24922518

2519+
#[test]
2520+
fn test_accepts_zero_fee_commitments_arg() {
2521+
for (value, expected) in [("true", true), ("false", false)] {
2522+
let args_config = ArgsConfig::try_parse_from([
2523+
"ldk-server",
2524+
"--node-enable-zero-fee-commitments",
2525+
value,
2526+
])
2527+
.unwrap();
2528+
2529+
assert_eq!(args_config.node_enable_zero_fee_commitments, Some(expected));
2530+
}
2531+
}
2532+
24932533
#[test]
24942534
fn test_probing_args_override_strategy_specific_file_options() {
24952535
let mut builder = ConfigBuilder {

0 commit comments

Comments
 (0)