Skip to content

Commit 97d9d51

Browse files
carlaKCTheBlueMatt
andcommitted
ln+util: add test option to enable negotiation of zero fee channels
To allow testing along the way in this PR, turn on negotiation of zero fee channels. Co-authored-by: Matt Corallo <[email protected]>
1 parent 5fffe77 commit 97d9d51

File tree

4 files changed

+133
-10
lines changed

4 files changed

+133
-10
lines changed

lightning-types/src/features.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,15 @@ impl ChannelTypeFeatures {
10241024
<sealed::ChannelTypeContext as sealed::AnchorsZeroFeeHtlcTx>::set_required_bit(&mut ret);
10251025
ret
10261026
}
1027+
1028+
/// Constructs a ChannelTypeFeatures with zero fee commitment anchors support.
1029+
pub fn anchors_zero_fee_commitments() -> Self {
1030+
let mut ret = Self::empty();
1031+
<sealed::ChannelTypeContext as sealed::AnchorZeroFeeCommitments>::set_required_bit(
1032+
&mut ret,
1033+
);
1034+
ret
1035+
}
10271036
}
10281037

10291038
impl<T: sealed::Context> Features<T> {

lightning/src/ln/channel.rs

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4902,20 +4902,35 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
49024902
let channel_type = &funding.channel_transaction_parameters.channel_type_features;
49034903
let mut eligible_features = their_features.clone();
49044904

4905-
if channel_type.supports_anchors_zero_fee_htlc_tx() {
4905+
if channel_type.supports_anchor_zero_fee_commitments() {
4906+
eligible_features.clear_anchor_zero_fee_commitments();
4907+
assert!(!eligible_features.supports_anchor_zero_fee_commitments());
4908+
} else if channel_type.supports_anchors_zero_fee_htlc_tx() {
4909+
eligible_features.clear_anchor_zero_fee_commitments();
49064910
eligible_features.clear_anchors_zero_fee_htlc_tx();
4911+
assert!(!eligible_features.supports_anchor_zero_fee_commitments());
49074912
assert!(!eligible_features.supports_anchors_nonzero_fee_htlc_tx());
49084913
assert!(!eligible_features.supports_anchors_zero_fee_htlc_tx());
49094914
} else if channel_type.supports_scid_privacy() {
49104915
eligible_features.clear_scid_privacy();
49114916
eligible_features.clear_anchors_zero_fee_htlc_tx();
4917+
eligible_features.clear_anchor_zero_fee_commitments();
49124918
assert!(!eligible_features.supports_scid_privacy());
49134919
assert!(!eligible_features.supports_anchors_nonzero_fee_htlc_tx());
49144920
assert!(!eligible_features.supports_anchors_zero_fee_htlc_tx());
4921+
assert!(!eligible_features.supports_anchor_zero_fee_commitments());
49154922
}
49164923

49174924
let next_channel_type = get_initial_channel_type(user_config, &eligible_features);
49184925

4926+
// Note that we can't get `anchor_zero_fee_commitments` type here, which requires zero
4927+
// fees, because we downgrade from this channel type first. If there were a superior
4928+
// channel type that downgrades to `anchor_zero_fee_commitments`, we'd need to handle
4929+
// fee setting differently here. If we proceeded to open a `anchor_zero_fee_commitments`
4930+
// channel with non-zero fees, we could produce a non-standard commitment transaction that
4931+
// puts us at risk of losing funds. We would expect our peer to reject such a channel
4932+
// open, but we don't want to rely on their validation.
4933+
assert!(!next_channel_type.supports_anchor_zero_fee_commitments());
49194934
let conf_target = if next_channel_type.supports_anchors_zero_fee_htlc_tx() {
49204935
ConfirmationTarget::AnchorChannelFee
49214936
} else {
@@ -10101,8 +10116,9 @@ pub(super) fn channel_type_from_open_channel(
1010110116

1010210117
// We only support the channel types defined by the `ChannelManager` in
1010310118
// `provided_channel_type_features`. The channel type must always support
10104-
// `static_remote_key`.
10105-
if !channel_type.requires_static_remote_key() {
10119+
// `static_remote_key`, either implicitly with `option_zero_fee_commitments`
10120+
// or explicitly.
10121+
if !channel_type.requires_static_remote_key() && !channel_type.requires_anchor_zero_fee_commitments() {
1010610122
return Err(ChannelError::close("Channel Type was not understood - we require static remote key".to_owned()));
1010710123
}
1010810124
// Make sure we support all of the features behind the channel type.
@@ -10689,10 +10705,21 @@ fn get_initial_channel_type(config: &UserConfig, their_features: &InitFeatures)
1068910705
ret.set_scid_privacy_required();
1069010706
}
1069110707

10692-
// Optionally, if the user would like to negotiate the `anchors_zero_fee_htlc_tx` option, we
10693-
// set it now. If they don't understand it, we'll fall back to our default of
10694-
// `only_static_remotekey`.
10695-
if config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx &&
10708+
// Optionally, if the user would like to negotiate `option_zero_fee_commitments` we set it now.
10709+
// If they don't understand it (or we don't want it), we check the same conditions for
10710+
// `option_anchors_zero_fee_htlc_tx`. The counterparty can still refuse the channel and we'll
10711+
// try to fall back (all the way to `only_static_remotekey`).
10712+
#[cfg(not(test))]
10713+
let negotiate_zero_fee_commitments = false;
10714+
10715+
#[cfg(test)]
10716+
let negotiate_zero_fee_commitments = config.channel_handshake_config.negotiate_anchor_zero_fee_commitments;
10717+
10718+
if negotiate_zero_fee_commitments && their_features.supports_anchor_zero_fee_commitments() {
10719+
ret.set_anchor_zero_fee_commitments_required();
10720+
// `option_static_remote_key` is assumed by `option_zero_fee_commitments`.
10721+
ret.clear_static_remote_key();
10722+
} else if config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx &&
1069610723
their_features.supports_anchors_zero_fee_htlc_tx() {
1069710724
ret.set_anchors_zero_fee_htlc_tx_required();
1069810725
}

lightning/src/ln/channelmanager.rs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13005,6 +13005,12 @@ pub fn provided_init_features(config: &UserConfig) -> InitFeatures {
1300513005
// quiescent-dependent protocols (e.g., splicing).
1300613006
#[cfg(any(test, fuzzing))]
1300713007
features.set_quiescence_optional();
13008+
13009+
#[cfg(test)]
13010+
if config.channel_handshake_config.negotiate_anchor_zero_fee_commitments {
13011+
features.set_anchor_zero_fee_commitments_optional();
13012+
}
13013+
1300813014
features
1300913015
}
1301013016

@@ -16371,29 +16377,71 @@ mod tests {
1637116377

1637216378
#[test]
1637316379
fn test_scid_privacy_downgrade() {
16374-
// Tests downgrade from `anchors_zero_fee_htlc_tx` with `option_scid_alias` when the
16380+
// Tests downgrade from `anchors_zero_fee_commitments` with `option_scid_alias` when the
1637516381
// remote node advertises the features but does not accept the channel, asserting that
1637616382
// `option_scid_alias` is the last feature to be downgraded.
1637716383
let mut initiator_cfg = test_default_channel_config();
16384+
initiator_cfg.channel_handshake_config.negotiate_anchor_zero_fee_commitments = true;
1637816385
initiator_cfg.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
1637916386
initiator_cfg.channel_handshake_config.negotiate_scid_privacy = true;
1638016387
initiator_cfg.channel_handshake_config.announce_for_forwarding = false;
1638116388

1638216389
let mut receiver_cfg = test_default_channel_config();
16390+
receiver_cfg.channel_handshake_config.negotiate_anchor_zero_fee_commitments = true;
1638316391
receiver_cfg.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
1638416392
receiver_cfg.channel_handshake_config.negotiate_scid_privacy = true;
1638516393
receiver_cfg.manually_accept_inbound_channels = true;
1638616394

16387-
let mut start_type = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies();
16395+
let mut start_type = ChannelTypeFeatures::anchors_zero_fee_commitments();
1638816396
start_type.set_scid_privacy_required();
16397+
let mut with_anchors = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies();
16398+
with_anchors.set_scid_privacy_required();
1638916399
let mut with_scid_privacy = ChannelTypeFeatures::only_static_remote_key();
1639016400
with_scid_privacy.set_scid_privacy_required();
1639116401
let static_remote = ChannelTypeFeatures::only_static_remote_key();
16392-
let downgrade_types = vec![with_scid_privacy, static_remote];
16402+
let downgrade_types = vec![with_anchors, with_scid_privacy, static_remote];
16403+
16404+
do_test_channel_type_downgrade(initiator_cfg, receiver_cfg, start_type, downgrade_types);
16405+
}
16406+
16407+
#[test]
16408+
fn test_zero_fee_commitments_downgrade() {
16409+
// Tests that the local node will retry without zero fee commitments in the case where the
16410+
// remote node supports the feature but does not accept it.
16411+
let mut initiator_cfg = test_default_channel_config();
16412+
initiator_cfg.channel_handshake_config.negotiate_anchor_zero_fee_commitments = true;
16413+
initiator_cfg.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
16414+
16415+
let mut receiver_cfg = test_default_channel_config();
16416+
receiver_cfg.channel_handshake_config.negotiate_anchor_zero_fee_commitments = true;
16417+
receiver_cfg.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
16418+
receiver_cfg.manually_accept_inbound_channels = true;
1639316419

16420+
let start_type = ChannelTypeFeatures::anchors_zero_fee_commitments();
16421+
let downgrade_types = vec![
16422+
ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(),
16423+
ChannelTypeFeatures::only_static_remote_key(),
16424+
];
1639416425
do_test_channel_type_downgrade(initiator_cfg, receiver_cfg, start_type, downgrade_types);
1639516426
}
1639616427

16428+
#[test]
16429+
fn test_zero_fee_commitments_downgrade_to_static_remote() {
16430+
// Tests that the local node will retry with static remote key when zero fee commitments
16431+
// are supported (but not accepted), but not legacy anchors.
16432+
let mut initiator_cfg = test_default_channel_config();
16433+
initiator_cfg.channel_handshake_config.negotiate_anchor_zero_fee_commitments = true;
16434+
initiator_cfg.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
16435+
16436+
let mut receiver_cfg = test_default_channel_config();
16437+
receiver_cfg.channel_handshake_config.negotiate_anchor_zero_fee_commitments = true;
16438+
receiver_cfg.manually_accept_inbound_channels = true;
16439+
16440+
let start_type = ChannelTypeFeatures::anchors_zero_fee_commitments();
16441+
let end_type = ChannelTypeFeatures::only_static_remote_key();
16442+
do_test_channel_type_downgrade(initiator_cfg, receiver_cfg, start_type, vec![end_type]);
16443+
}
16444+
1639716445
#[rustfmt::skip]
1639816446
fn do_test_channel_type_downgrade(initiator_cfg: UserConfig, acceptor_cfg: UserConfig,
1639916447
start_type: ChannelTypeFeatures, downgrade_types: Vec<ChannelTypeFeatures>) {

lightning/src/util/config.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,41 @@ pub struct ChannelHandshakeConfig {
183183
/// [`DecodeError::InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
184184
pub negotiate_anchors_zero_fee_htlc_tx: bool,
185185

186+
/// If set, we attempt to negotiate the `zero_fee_commitments` option for all future channels.
187+
///
188+
/// These channels operate very similarly to the `anchors_zero_fee_htlc` channels but rely on
189+
/// [TRUC] to assign zero fee to the commitment transactions themselves, avoiding many protocol
190+
/// edge-cases involving fee updates and greatly simplifying the concept of your "balance" in
191+
/// lightning.
192+
///
193+
/// Like `anchors_zero_fee_htlc` channels, this feature requires having a reserve of onchain
194+
/// funds readily available to bump transactions in the event of a channel force close to avoid
195+
/// the possibility of losing funds.
196+
///
197+
/// Note that if you wish accept inbound channels with anchor outputs, you must enable
198+
/// [`UserConfig::manually_accept_inbound_channels`] and manually accept them with
199+
/// [`ChannelManager::accept_inbound_channel`]. This is done to give you the chance to check
200+
/// whether your reserve of onchain funds is enough to cover the fees for all existing and new
201+
/// channels featuring anchor outputs in the event of a force close.
202+
///
203+
/// If this option is set, channels may be created that will not be readable by LDK versions
204+
/// prior to 0.2, causing [`ChannelManager`]'s read method to return a
205+
/// [`DecodeError::InvalidValue`].
206+
///
207+
/// Note that setting this to true does *not* prevent us from opening channels with
208+
/// counterparties that do not support the `zero_fee_commitments` option; we will simply fall
209+
/// back to a `anchors_zero_fee_htlc` (if [`Self::negotiate_anchors_zero_fee_htlc_tx`]
210+
/// is set) or `static_remote_key` channel.
211+
///
212+
/// Default value: `false` (This value is likely to change to `true` in the future.)
213+
///
214+
/// [TRUC]: (https://bitcoinops.org/en/topics/version-3-transaction-relay/)
215+
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
216+
/// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel
217+
/// [`DecodeError::InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
218+
#[cfg(test)]
219+
pub negotiate_anchor_zero_fee_commitments: bool,
220+
186221
/// The maximum number of HTLCs in-flight from our counterparty towards us at the same time.
187222
///
188223
/// Increasing the value can help improve liquidity and stability in
@@ -212,6 +247,8 @@ impl Default for ChannelHandshakeConfig {
212247
commit_upfront_shutdown_pubkey: true,
213248
their_channel_reserve_proportional_millionths: 10_000,
214249
negotiate_anchors_zero_fee_htlc_tx: false,
250+
#[cfg(test)]
251+
negotiate_anchor_zero_fee_commitments: false,
215252
our_max_accepted_htlcs: 50,
216253
}
217254
}
@@ -233,6 +270,8 @@ impl Readable for ChannelHandshakeConfig {
233270
commit_upfront_shutdown_pubkey: Readable::read(reader)?,
234271
their_channel_reserve_proportional_millionths: Readable::read(reader)?,
235272
negotiate_anchors_zero_fee_htlc_tx: Readable::read(reader)?,
273+
#[cfg(test)]
274+
negotiate_anchor_zero_fee_commitments: Readable::read(reader)?,
236275
our_max_accepted_htlcs: Readable::read(reader)?,
237276
})
238277
}

0 commit comments

Comments
 (0)