Skip to content

Channel Establishment for V3 Channels #3792

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions lightning/src/ln/chan_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,13 @@ use crate::prelude::*;
/// 483 for non-zero-fee-commitment channels and 114 for zero-fee-commitment channels.
///
/// Actual maximums can be set equal to or below this value by each channel participant.
pub fn max_htlcs(_channel_type: &ChannelTypeFeatures) -> u16 {
483
pub fn max_htlcs(channel_type: &ChannelTypeFeatures) -> u16 {
if channel_type.supports_anchor_zero_fee_commitments() {
// TRUC restricts the size of our commitment transactions to 10K vB rather than 100K vB
114
} else {
483
}
}
/// The weight of a BIP141 witnessScript for a BOLT3's "offered HTLC output" on a commitment transaction, non-anchor variant.
pub const OFFERED_HTLC_SCRIPT_WEIGHT: usize = 133;
Expand Down
107 changes: 84 additions & 23 deletions lightning/src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3036,12 +3036,18 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
debug_assert!(!channel_type.supports_any_optional_bits());
debug_assert!(!channel_type.requires_unknown_bits_from(&channelmanager::provided_channel_type_features(&config)));

let (commitment_conf_target, anchor_outputs_value_msat) = if channel_type.supports_anchors_zero_fee_htlc_tx() {
(ConfirmationTarget::AnchorChannelFee, ANCHOR_OUTPUT_VALUE_SATOSHI * 2 * 1000)
} else {
(ConfirmationTarget::NonAnchorChannelFee, 0)
};
let commitment_feerate = fee_estimator.bounded_sat_per_1000_weight(commitment_conf_target);
let (commitment_feerate, anchor_outputs_value_msat) =
if channel_type.supports_anchor_zero_fee_commitments() {
(0, 0)
} else if channel_type.supports_anchors_zero_fee_htlc_tx() {
let feerate = fee_estimator
.bounded_sat_per_1000_weight(ConfirmationTarget::AnchorChannelFee);
(feerate, ANCHOR_OUTPUT_VALUE_SATOSHI * 2 * 1000)
} else {
let feerate = fee_estimator
.bounded_sat_per_1000_weight(ConfirmationTarget::NonAnchorChannelFee);
(feerate, 0)
};

let value_to_self_msat = channel_value_satoshis * 1000 - push_msat;
let commitment_tx_fee = commit_tx_fee_sat(commitment_feerate, MIN_AFFORDABLE_HTLC_COUNT, &channel_type) * 1000;
Expand Down Expand Up @@ -4860,7 +4866,16 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
// counterparty is advertising the feature, but rejecting channels proposing the feature for
// whatever reason.
let channel_type = &mut funding.channel_transaction_parameters.channel_type_features;
if channel_type.supports_anchors_zero_fee_htlc_tx() {
if channel_type.supports_anchor_zero_fee_commitments() {
channel_type.clear_anchor_zero_fee_commitments();
channel_type.set_anchors_zero_fee_htlc_tx_required();
channel_type.set_static_remote_key_required();

self.feerate_per_kw = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::AnchorChannelFee);
assert!(!channel_type.supports_anchor_zero_fee_commitments());
assert!(channel_type.supports_anchors_zero_fee_htlc_tx());
assert!(channel_type.supports_static_remote_key());
} else if channel_type.supports_anchors_zero_fee_htlc_tx() {
channel_type.clear_anchors_zero_fee_htlc_tx();
self.feerate_per_kw = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::NonAnchorChannelFee);
assert!(!channel_type.supports_anchors_nonzero_fee_htlc_tx());
Expand Down Expand Up @@ -5223,6 +5238,15 @@ impl<SP: Deref> FundedChannel<SP> where
feerate_per_kw: u32, cur_feerate_per_kw: Option<u32>, logger: &L
) -> Result<(), ChannelError> where F::Target: FeeEstimator, L::Target: Logger,
{
if channel_type.supports_anchor_zero_fee_commitments() {
if feerate_per_kw != 0 {
let err = "Zero Fee Channels must never attempt to use a fee".to_owned();
return Err(ChannelError::close(err));
} else {
return Ok(());
}
}

let lower_limit_conf_target = if channel_type.supports_anchors_zero_fee_htlc_tx() {
ConfirmationTarget::MinAllowedAnchorChannelRemoteFee
} else {
Expand Down Expand Up @@ -9906,8 +9930,9 @@ pub(super) fn channel_type_from_open_channel(

// We only support the channel types defined by the `ChannelManager` in
// `provided_channel_type_features`. The channel type must always support
// `static_remote_key`.
if !channel_type.requires_static_remote_key() {
// `static_remote_key`, except for `option_zero_fee_commitments` which
// assumes this feature.
if !channel_type.requires_static_remote_key() && !channel_type.requires_anchor_zero_fee_commitments(){
return Err(ChannelError::close("Channel Type was not understood - we require static remote key".to_owned()));
}
// Make sure we support all of the features behind the channel type.
Expand Down Expand Up @@ -10492,10 +10517,21 @@ fn get_initial_channel_type(config: &UserConfig, their_features: &InitFeatures)
ret.set_scid_privacy_required();
}

// Optionally, if the user would like to negotiate the `anchors_zero_fee_htlc_tx` option, we
// set it now. If they don't understand it, we'll fall back to our default of
// `only_static_remotekey`.
if config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx &&
// Optionally, if the user would like to negotiate `option_zero_fee_commitments` we set it now.
// If they don't understand it (or we don't want it), we check the same conditions for
// `option_anchors_zero_fee_htlc_tx`. The counterparty can still refuse the channel and we'll
// try to fall back (all the way to `only_static_remotekey`).
#[cfg(not(test))]
let negotiate_zero_fee_commitments = false;

#[cfg(test)]
let negotiate_zero_fee_commitments = config.channel_handshake_config.negotiate_anchor_zero_fee_commitments;

if negotiate_zero_fee_commitments && their_features.supports_anchor_zero_fee_commitments() {
ret.set_anchor_zero_fee_commitments_required();
// `option_static_remote_key` is assumed by `option_zero_fee_commitments`.
ret.clear_static_remote_key();
} else if config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx &&
their_features.supports_anchors_zero_fee_htlc_tx() {
ret.set_anchors_zero_fee_htlc_tx_required();
}
Expand Down Expand Up @@ -13104,6 +13140,30 @@ mod tests {
fn test_supports_anchors_zero_htlc_tx_fee() {
// Tests that if both sides support and negotiate `anchors_zero_fee_htlc_tx`, it is the
// resulting `channel_type`.
let mut config = UserConfig::default();
config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;

let mut expected_channel_type = ChannelTypeFeatures::empty();
expected_channel_type.set_static_remote_key_required();
expected_channel_type.set_anchors_zero_fee_htlc_tx_required();

do_test_supports_channel_type(config, expected_channel_type)
}

#[test]
fn test_supports_zero_fee_commitments() {
// Tests that if both sides support and negotiate `anchors_zero_fee_commitments`, it is
// the resulting `channel_type`.
let mut config = UserConfig::default();
config.channel_handshake_config.negotiate_anchor_zero_fee_commitments = true;

let mut expected_channel_type = ChannelTypeFeatures::empty();
expected_channel_type.set_anchor_zero_fee_commitments_required();

do_test_supports_channel_type(config, expected_channel_type)
}

fn do_test_supports_channel_type(config: UserConfig, expected_channel_type: ChannelTypeFeatures) {
let secp_ctx = Secp256k1::new();
let fee_estimator = LowerBoundedFeeEstimator::new(&TestFeeEstimator{fee_est: 15000});
let network = Network::Testnet;
Expand All @@ -13113,21 +13173,14 @@ mod tests {
let node_id_a = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[1; 32]).unwrap());
let node_id_b = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[2; 32]).unwrap());

let mut config = UserConfig::default();
config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;

// It is not enough for just the initiator to signal `option_anchors_zero_fee_htlc_tx`, both
// need to signal it.
// Assert that we don't get the target channel type when the receiving node does not signal
// support.
let channel_a = OutboundV1Channel::<&TestKeysInterface>::new(
&fee_estimator, &&keys_provider, &&keys_provider, node_id_b,
&channelmanager::provided_init_features(&UserConfig::default()), 10000000, 100000, 42,
&config, 0, 42, None, &logger
).unwrap();
assert!(!channel_a.funding.get_channel_type().supports_anchors_zero_fee_htlc_tx());

let mut expected_channel_type = ChannelTypeFeatures::empty();
expected_channel_type.set_static_remote_key_required();
expected_channel_type.set_anchors_zero_fee_htlc_tx_required();
assert!(channel_a.funding.get_channel_type() != &expected_channel_type);

let mut channel_a = OutboundV1Channel::<&TestKeysInterface>::new(
&fee_estimator, &&keys_provider, &&keys_provider, node_id_b,
Expand All @@ -13144,6 +13197,14 @@ mod tests {

assert_eq!(channel_a.funding.get_channel_type(), &expected_channel_type);
assert_eq!(channel_b.funding.get_channel_type(), &expected_channel_type);

if expected_channel_type.supports_anchor_zero_fee_commitments() {
assert_eq!(channel_a.context.feerate_per_kw, 0);
assert_eq!(channel_b.context.feerate_per_kw, 0);
} else {
assert_ne!(channel_a.context.feerate_per_kw, 0);
assert_ne!(channel_b.context.feerate_per_kw, 0);
}
}

#[test]
Expand Down
72 changes: 54 additions & 18 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8175,7 +8175,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
if channel_type.requires_zero_conf() {
return Err(MsgHandleErrInternal::send_err_msg_no_close("No zero confirmation channels accepted".to_owned(), common_fields.temporary_channel_id));
}
if channel_type.requires_anchors_zero_fee_htlc_tx() {
if channel_type.requires_anchors_zero_fee_htlc_tx() || channel_type.requires_anchor_zero_fee_commitments() {
return Err(MsgHandleErrInternal::send_err_msg_no_close("No channels with anchor outputs accepted".to_owned(), common_fields.temporary_channel_id));
}

Expand Down Expand Up @@ -12931,6 +12931,14 @@ pub fn provided_init_features(config: &UserConfig) -> InitFeatures {
// quiescent-dependent protocols (e.g., splicing).
#[cfg(any(test, fuzzing))]
features.set_quiescence_optional();

#[cfg(test)]
{
if config.channel_handshake_config.negotiate_anchor_zero_fee_commitments {
features.set_anchor_zero_fee_commitments_optional();
}
}

features
}

Expand Down Expand Up @@ -15026,6 +15034,7 @@ where
mod tests {
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
use bitcoin::secp256k1::ecdh::SharedSecret;
use lightning_types::features::ChannelTypeFeatures;
use core::sync::atomic::Ordering;
use crate::events::{Event, HTLCHandlingFailureType, ClosureReason};
use crate::ln::onion_utils::AttributionData;
Expand All @@ -15041,7 +15050,7 @@ mod tests {
use crate::util::errors::APIError;
use crate::util::ser::Writeable;
use crate::util::test_utils;
use crate::util::config::{ChannelConfig, ChannelConfigUpdate, ChannelHandshakeConfigUpdate};
use crate::util::config::{ChannelConfig, ChannelConfigUpdate, ChannelHandshakeConfigUpdate, UserConfig};
use crate::sign::EntropySource;

#[test]
Expand Down Expand Up @@ -16083,7 +16092,9 @@ mod tests {

#[test]
fn test_inbound_anchors_manual_acceptance() {
test_inbound_anchors_manual_acceptance_with_override(None);
let mut anchors_cfg = test_default_channel_config();
anchors_cfg.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
do_test_manual_inbound_accept_with_override(anchors_cfg, None);
}

#[test]
Expand All @@ -16100,7 +16111,10 @@ mod tests {
update_overrides: None,
};

let accept_message = test_inbound_anchors_manual_acceptance_with_override(Some(overrides));
let mut anchors_cfg = test_default_channel_config();
anchors_cfg.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;

let accept_message = do_test_manual_inbound_accept_with_override(anchors_cfg, Some(overrides));
assert_eq!(accept_message.common_fields.max_htlc_value_in_flight_msat, 5_000_000);
assert_eq!(accept_message.common_fields.htlc_minimum_msat, 1_000);
assert_eq!(accept_message.common_fields.minimum_depth, 2);
Expand All @@ -16109,19 +16123,23 @@ mod tests {
assert_eq!(accept_message.channel_reserve_satoshis, 2_000);
}

fn test_inbound_anchors_manual_acceptance_with_override(config_overrides: Option<ChannelConfigOverrides>) -> AcceptChannel {
// Tests that we properly limit inbound channels when we have the manual-channel-acceptance
// flag set and (sometimes) accept channels as 0conf.
let mut anchors_cfg = test_default_channel_config();
anchors_cfg.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
#[test]
fn test_inbound_zero_fee_commitments_acceptance() {
let mut zero_fee_cfg = test_default_channel_config();
zero_fee_cfg.channel_handshake_config.negotiate_anchor_zero_fee_commitments = true;
do_test_manual_inbound_accept_with_override(zero_fee_cfg, None);
}

let mut anchors_manual_accept_cfg = anchors_cfg.clone();
anchors_manual_accept_cfg.manually_accept_inbound_channels = true;
fn do_test_manual_inbound_accept_with_override(start_cfg: UserConfig,
config_overrides: Option<ChannelConfigOverrides>) -> AcceptChannel {

let mut mannual_accept_cfg = start_cfg.clone();
mannual_accept_cfg.manually_accept_inbound_channels = true;

let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs,
&[Some(anchors_cfg.clone()), Some(anchors_cfg.clone()), Some(anchors_manual_accept_cfg.clone())]);
&[Some(start_cfg.clone()), Some(start_cfg.clone()), Some(mannual_accept_cfg.clone())]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);

nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 42, None, None).unwrap();
Expand Down Expand Up @@ -16153,22 +16171,40 @@ mod tests {
}

#[test]
fn test_anchors_zero_fee_htlc_tx_fallback() {
fn test_anchors_zero_fee_htlc_tx_downgrade() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Congrats, you touched it, now you get to move it out of channelmanager into some other test-specific file that isn't 15000 lines of code 😂

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done this in a follow up in #3797 so that move + format can be reviewed separately.

// Tests that if both nodes support anchors, but the remote node does not want to accept
// anchor channels at the moment, an error it sent to the local node such that it can retry
// the channel without the anchors feature.
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let mut anchors_config = test_default_channel_config();
anchors_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
anchors_config.manually_accept_inbound_channels = true;
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(anchors_config.clone()), Some(anchors_config.clone())]);

do_test_channel_type_downgrade(anchors_config, |features| features.supports_anchors_zero_fee_htlc_tx())
}

#[test]
fn test_zero_fee_commitments_downgrade() {
// Tests that the local node will retry without zero fee commitments in the case where the
// remote node supports the feature but does not accept it.
let mut zero_fee_config = test_default_channel_config();
zero_fee_config.channel_handshake_config.negotiate_anchor_zero_fee_commitments = true;
zero_fee_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
zero_fee_config.manually_accept_inbound_channels = true;

do_test_channel_type_downgrade(zero_fee_config, |features| features.supports_anchor_zero_fee_commitments())
}

fn do_test_channel_type_downgrade<F>(user_cfg: UserConfig, start_type_set: F)
where F: Fn(&ChannelTypeFeatures) -> bool {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(user_cfg.clone()), Some(user_cfg.clone())]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let error_message = "Channel force-closed";

nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 0, None, None).unwrap();
let open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
assert!(open_channel_msg.common_fields.channel_type.as_ref().unwrap().supports_anchors_zero_fee_htlc_tx());
assert!(start_type_set(open_channel_msg.common_fields.channel_type.as_ref().unwrap()));

nodes[1].node.handle_open_channel(nodes[0].node.get_our_node_id(), &open_channel_msg);
let events = nodes[1].node.get_and_clear_pending_events();
Expand All @@ -16183,7 +16219,7 @@ mod tests {
nodes[0].node.handle_error(nodes[1].node.get_our_node_id(), &error_msg);

let open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
assert!(!open_channel_msg.common_fields.channel_type.unwrap().supports_anchors_zero_fee_htlc_tx());
assert!(!start_type_set(open_channel_msg.common_fields.channel_type.as_ref().unwrap()));

// Since nodes[1] should not have accepted the channel, it should
// not have generated any events.
Expand Down
Loading
Loading