Skip to content

Commit 48a70a8

Browse files
committed
Expose channel_reserve_satoshis via ChannelParameters
Add `channel_reserve_satoshis: Option<u64>` to `ChannelParameters` so users can access the counterparty's channel reserve when handling the `OpenChannelRequest` event. For V1 channels (`open_channel`), this returns `Some(value)` with the explicit reserve from the message. For V2 channels (`open_channel2`), this returns `None` because the reserve is calculated as `max(1% of total_channel_value, dust_limit)` per spec, where total_channel_value includes both parties' funding. Since the acceptor's contribution is unknown at `OpenChannelRequest` time, the final reserve cannot be determined. Move `channel_parameters()` from `CommonOpenChannelFields` to separate implementations on `OpenChannel` and `OpenChannelV2` to handle the V1/V2 difference correctly. Fixes #3909
1 parent 9e91b2e commit 48a70a8

3 files changed

Lines changed: 102 additions & 15 deletions

File tree

lightning/src/ln/channel_open_tests.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1750,6 +1750,75 @@ pub fn test_invalid_funding_tx() {
17501750
mine_transaction(&nodes[1], &spend_tx);
17511751
}
17521752

1753+
#[xtest(feature = "_externalize_tests")]
1754+
pub fn test_open_channel_request_channel_reserve_satoshis() {
1755+
// Test that the `channel_reserve_satoshis` field is correctly populated in the
1756+
// `OpenChannelRequest` event's `params` field for V1 channels.
1757+
let mut manually_accept_conf = UserConfig::default();
1758+
manually_accept_conf.manually_accept_inbound_channels = true;
1759+
1760+
let chanmon_cfgs = create_chanmon_cfgs(2);
1761+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
1762+
let node_chanmgrs =
1763+
create_node_chanmgrs(2, &node_cfgs, &[None, Some(manually_accept_conf.clone())]);
1764+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
1765+
1766+
let node_a_id = nodes[0].node.get_our_node_id();
1767+
let node_b_id = nodes[1].node.get_our_node_id();
1768+
1769+
// Create channel with 100,000 sats
1770+
nodes[0]
1771+
.node
1772+
.create_channel(node_b_id, 100_000, 10_001, 42, None, Some(manually_accept_conf))
1773+
.unwrap();
1774+
let open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, node_b_id);
1775+
1776+
// The channel_reserve_satoshis in the open_channel message is set by the opener
1777+
let expected_reserve = open_channel_msg.channel_reserve_satoshis;
1778+
1779+
nodes[1].node.handle_open_channel(node_a_id, &open_channel_msg);
1780+
1781+
// Verify the OpenChannelRequest event contains the correct channel_reserve_satoshis
1782+
let events = nodes[1].node.get_and_clear_pending_events();
1783+
assert_eq!(events.len(), 1);
1784+
match &events[0] {
1785+
Event::OpenChannelRequest { temporary_channel_id, params, .. } => {
1786+
// For V1 channels, channel_reserve_satoshis should be Some with the value from the message
1787+
assert_eq!(
1788+
params.channel_reserve_satoshis,
1789+
Some(expected_reserve),
1790+
"channel_reserve_satoshis in OpenChannelRequest params should match the open_channel message"
1791+
);
1792+
1793+
// Verify other params fields are also correctly populated
1794+
assert_eq!(
1795+
params.dust_limit_satoshis,
1796+
open_channel_msg.common_fields.dust_limit_satoshis
1797+
);
1798+
assert_eq!(
1799+
params.max_htlc_value_in_flight_msat,
1800+
open_channel_msg.common_fields.max_htlc_value_in_flight_msat
1801+
);
1802+
assert_eq!(params.htlc_minimum_msat, open_channel_msg.common_fields.htlc_minimum_msat);
1803+
assert_eq!(params.to_self_delay, open_channel_msg.common_fields.to_self_delay);
1804+
assert_eq!(
1805+
params.max_accepted_htlcs,
1806+
open_channel_msg.common_fields.max_accepted_htlcs
1807+
);
1808+
1809+
// Accept the channel to clean up
1810+
nodes[1]
1811+
.node
1812+
.accept_inbound_channel(temporary_channel_id, &node_a_id, 0, None)
1813+
.unwrap();
1814+
},
1815+
_ => panic!("Expected OpenChannelRequest event"),
1816+
}
1817+
1818+
// Clear the SendAcceptChannel message event generated by accepting the channel
1819+
nodes[1].node.get_and_clear_pending_msg_events();
1820+
}
1821+
17531822
#[xtest(feature = "_externalize_tests")]
17541823
pub fn test_coinbase_funding_tx() {
17551824
// Miners are able to fund channels directly from coinbase transactions, however

lightning/src/ln/channelmanager.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1682,6 +1682,25 @@ pub(super) enum OpenChannelMessageRef<'a> {
16821682
V2(&'a msgs::OpenChannelV2),
16831683
}
16841684

1685+
impl<'a> OpenChannelMessageRef<'a> {
1686+
pub(super) fn channel_parameters(&self) -> msgs::ChannelParameters {
1687+
let (common_fields, channel_reserve_satoshis) = match self {
1688+
Self::V1(msg) => (&msg.common_fields, Some(msg.channel_reserve_satoshis)),
1689+
Self::V2(msg) => (&msg.common_fields, None),
1690+
};
1691+
msgs::ChannelParameters {
1692+
dust_limit_satoshis: common_fields.dust_limit_satoshis,
1693+
max_htlc_value_in_flight_msat: common_fields.max_htlc_value_in_flight_msat,
1694+
htlc_minimum_msat: common_fields.htlc_minimum_msat,
1695+
commitment_feerate_sat_per_1000_weight: common_fields
1696+
.commitment_feerate_sat_per_1000_weight,
1697+
to_self_delay: common_fields.to_self_delay,
1698+
max_accepted_htlcs: common_fields.max_accepted_htlcs,
1699+
channel_reserve_satoshis,
1700+
}
1701+
}
1702+
}
1703+
16851704
/// A not-yet-accepted inbound (from counterparty) channel. Once
16861705
/// accepted, the parameters will be used to construct a channel.
16871706
pub(super) struct InboundChannelRequest {
@@ -10716,7 +10735,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1071610735
},
1071710736
channel_type,
1071810737
is_announced,
10719-
params: common_fields.channel_parameters(),
10738+
params: msg.channel_parameters(),
1072010739
}, None));
1072110740
peer_state.inbound_channel_request_by_id.insert(channel_id, InboundChannelRequest {
1072210741
open_channel_msg: match msg {

lightning/src/ln/msgs.rs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -244,20 +244,6 @@ pub struct CommonOpenChannelFields {
244244
pub channel_type: Option<ChannelTypeFeatures>,
245245
}
246246

247-
impl CommonOpenChannelFields {
248-
/// The [`ChannelParameters`] for this channel.
249-
pub fn channel_parameters(&self) -> ChannelParameters {
250-
ChannelParameters {
251-
dust_limit_satoshis: self.dust_limit_satoshis,
252-
max_htlc_value_in_flight_msat: self.max_htlc_value_in_flight_msat,
253-
htlc_minimum_msat: self.htlc_minimum_msat,
254-
commitment_feerate_sat_per_1000_weight: self.commitment_feerate_sat_per_1000_weight,
255-
to_self_delay: self.to_self_delay,
256-
max_accepted_htlcs: self.max_accepted_htlcs,
257-
}
258-
}
259-
}
260-
261247
/// A subset of [`CommonOpenChannelFields`], containing various parameters which are set by the
262248
/// channel initiator and which are not part of the channel funding transaction.
263249
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
@@ -277,6 +263,19 @@ pub struct ChannelParameters {
277263
pub to_self_delay: u16,
278264
/// The maximum number of pending HTLCs towards the channel initiator.
279265
pub max_accepted_htlcs: u16,
266+
/// The minimum value unencumbered by HTLCs for the counterparty to keep in the channel.
267+
///
268+
/// For V1 channels (`open_channel`), this is the explicit `channel_reserve_satoshis` value
269+
/// from the counterparty.
270+
///
271+
/// For V2 channels (`open_channel2`), this is `None` at the time of [`Event::OpenChannelRequest`]
272+
/// because the channel reserve is calculated as `max(1% of total_channel_value, dust_limit_satoshis)`
273+
/// per the spec, where `total_channel_value` includes both the initiator's and acceptor's funding
274+
/// contributions. Since the acceptor's contribution is not yet known when the event is generated,
275+
/// the final reserve value cannot be determined at that point.
276+
///
277+
/// [`Event::OpenChannelRequest`]: crate::events::Event::OpenChannelRequest
278+
pub channel_reserve_satoshis: Option<u64>,
280279
}
281280

282281
/// An [`open_channel`] message to be sent to or received from a peer.

0 commit comments

Comments
 (0)