Skip to content

Commit f7ec55a

Browse files
committed
Add InboundV2Channel struct
1 parent db6e1fa commit f7ec55a

File tree

1 file changed

+208
-5
lines changed

1 file changed

+208
-5
lines changed

lightning/src/ln/channel.rs

Lines changed: 208 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2849,6 +2849,20 @@ pub(crate) fn get_legacy_default_holder_selected_channel_reserve_satoshis(channe
28492849
cmp::min(channel_value_satoshis, cmp::max(q, 1000))
28502850
}
28512851

2852+
/// Returns a minimum channel reserve value each party needs to maintain, fixed in the spec to a
2853+
/// default of 1% of the total channel value.
2854+
///
2855+
/// Guaranteed to return a value no larger than channel_value_satoshis
2856+
///
2857+
/// This is used both for outbound and inbound channels and has lower bound
2858+
/// of `dust_limit_satoshis`.
2859+
fn get_v2_channel_reserve_satoshis(channel_value_satoshis: u64, dust_limit_satoshis: u64) -> u64 {
2860+
let channel_reserve_proportional_millionths = 10_000; // Fixed at 1% in spec.
2861+
let calculated_reserve =
2862+
channel_value_satoshis.saturating_mul(channel_reserve_proportional_millionths) / 1_000_000;
2863+
cmp::min(channel_value_satoshis, cmp::max(calculated_reserve, dust_limit_satoshis))
2864+
}
2865+
28522866
// Get the fee cost in SATS of a commitment tx with a given number of HTLC outputs.
28532867
// Note that num_htlcs should not include dust HTLCs.
28542868
#[inline]
@@ -2882,6 +2896,8 @@ pub(super) struct DualFundingChannelContext {
28822896
// Counterparty designates channel data owned by the another channel participant entity.
28832897
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
28842898
pub context: ChannelContext<SP>,
2899+
#[cfg(dual_funding)]
2900+
pub dual_funding_channel_context: Option<DualFundingChannelContext>,
28852901
}
28862902

28872903
#[cfg(any(test, fuzzing))]
@@ -7190,7 +7206,11 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
71907206

71917207
log_info!(logger, "Received funding_signed from peer for channel {}", &self.context.channel_id());
71927208

7193-
let mut channel = Channel { context: self.context };
7209+
let mut channel = Channel {
7210+
context: self.context,
7211+
#[cfg(dual_funding)]
7212+
dual_funding_channel_context: None,
7213+
};
71947214

71957215
let need_channel_ready = channel.check_get_channel_ready(0).is_some();
71967216
channel.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
@@ -7220,7 +7240,23 @@ pub(super) fn channel_type_from_open_channel(
72207240
msg: &msgs::OpenChannel, their_features: &InitFeatures,
72217241
our_supported_features: &ChannelTypeFeatures
72227242
) -> Result<ChannelTypeFeatures, ChannelError> {
7223-
if let Some(channel_type) = &msg.channel_type {
7243+
channel_type_from_type_and_flags(&msg.channel_type, msg.channel_flags, their_features, our_supported_features)
7244+
}
7245+
7246+
/// Fetches the [`ChannelTypeFeatures`] that will be used for a channel built from a given
7247+
/// [`msgs::OpenChannelV2`].
7248+
#[cfg(dual_funding)]
7249+
pub(super) fn channel_type_from_open_channel_v2(
7250+
msg: &msgs::OpenChannelV2, their_features: &InitFeatures,
7251+
our_supported_features: &ChannelTypeFeatures
7252+
) -> Result<ChannelTypeFeatures, ChannelError> {
7253+
channel_type_from_type_and_flags(&msg.channel_type, msg.channel_flags, their_features, our_supported_features)
7254+
}
7255+
7256+
fn channel_type_from_type_and_flags(msg_channel_type: &Option<ChannelTypeFeatures>,
7257+
msg_channel_flags: u8, their_features: &InitFeatures, our_supported_features: &ChannelTypeFeatures
7258+
) -> Result<ChannelTypeFeatures, ChannelError> {
7259+
if let Some(channel_type) = &msg_channel_type {
72247260
if channel_type.supports_any_optional_bits() {
72257261
return Err(ChannelError::Close("Channel Type field contained optional bits - this is not allowed".to_owned()));
72267262
}
@@ -7235,7 +7271,7 @@ pub(super) fn channel_type_from_open_channel(
72357271
if !channel_type.is_subset(our_supported_features) {
72367272
return Err(ChannelError::Close("Channel Type contains unsupported features".to_owned()));
72377273
}
7238-
let announced_channel = if (msg.channel_flags & 1) == 1 { true } else { false };
7274+
let announced_channel = if (msg_channel_flags & 1) == 1 { true } else { false };
72397275
if channel_type.requires_scid_privacy() && announced_channel {
72407276
return Err(ChannelError::Close("SCID Alias/Privacy Channel Type cannot be set on a public channel".to_owned()));
72417277
}
@@ -7486,6 +7522,8 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
74867522
// `ChannelMonitor`.
74877523
let mut channel = Channel {
74887524
context: self.context,
7525+
#[cfg(dual_funding)]
7526+
dual_funding_channel_context: None,
74897527
};
74907528
let need_channel_ready = channel.check_get_channel_ready(0).is_some();
74917529
channel.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
@@ -7494,6 +7532,165 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
74947532
}
74957533
}
74967534

7535+
// A not-yet-funded inbound (from counterparty) channel using V2 channel establishment.
7536+
#[cfg(dual_funding)]
7537+
pub(super) struct InboundV2Channel<SP: Deref> where SP::Target: SignerProvider {
7538+
pub context: ChannelContext<SP>,
7539+
pub unfunded_context: UnfundedChannelContext,
7540+
pub dual_funding_context: DualFundingChannelContext,
7541+
}
7542+
7543+
#[cfg(dual_funding)]
7544+
impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
7545+
/// Creates a new dual-funded channel from a remote side's request for one.
7546+
/// Assumes chain_hash has already been checked and corresponds with what we expect!
7547+
pub fn new<ES: Deref, F: Deref, L: Deref>(
7548+
fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
7549+
counterparty_node_id: PublicKey, our_supported_features: &ChannelTypeFeatures,
7550+
their_features: &InitFeatures, msg: &msgs::OpenChannelV2, funding_satoshis: u64, user_id: u128,
7551+
config: &UserConfig, current_chain_height: u32, logger: &L,
7552+
) -> Result<InboundV2Channel<SP>, ChannelError>
7553+
where ES::Target: EntropySource,
7554+
F::Target: FeeEstimator,
7555+
L::Target: Logger,
7556+
{
7557+
// TODO(dual_funding): Fix this
7558+
let channel_value_satoshis = funding_satoshis * 1000 + msg.funding_satoshis;
7559+
let counterparty_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
7560+
channel_value_satoshis, msg.dust_limit_satoshis);
7561+
let holder_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
7562+
channel_value_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS);
7563+
7564+
// First check the channel type is known, failing before we do anything else if we don't
7565+
// support this channel type.
7566+
let channel_type = channel_type_from_open_channel_v2(msg, their_features, our_supported_features)?;
7567+
7568+
let counterparty_pubkeys = ChannelPublicKeys {
7569+
funding_pubkey: msg.funding_pubkey,
7570+
revocation_basepoint: RevocationBasepoint(msg.revocation_basepoint),
7571+
payment_point: msg.payment_basepoint,
7572+
delayed_payment_basepoint: DelayedPaymentBasepoint(msg.delayed_payment_basepoint),
7573+
htlc_basepoint: HtlcBasepoint(msg.htlc_basepoint)
7574+
};
7575+
7576+
let mut context = ChannelContext::new_for_inbound_channel(
7577+
fee_estimator,
7578+
entropy_source,
7579+
signer_provider,
7580+
counterparty_node_id,
7581+
their_features,
7582+
user_id,
7583+
config,
7584+
current_chain_height,
7585+
logger,
7586+
false,
7587+
7588+
funding_satoshis,
7589+
7590+
counterparty_pubkeys,
7591+
msg.channel_flags,
7592+
channel_type,
7593+
msg.funding_satoshis,
7594+
msg.to_self_delay,
7595+
holder_selected_channel_reserve_satoshis,
7596+
counterparty_selected_channel_reserve_satoshis,
7597+
0 /* push_msat not used in dual-funding */,
7598+
msg.dust_limit_satoshis,
7599+
msg.htlc_minimum_msat,
7600+
msg.commitment_feerate_sat_per_1000_weight,
7601+
msg.max_accepted_htlcs,
7602+
msg.shutdown_scriptpubkey.clone(),
7603+
msg.max_htlc_value_in_flight_msat,
7604+
msg.temporary_channel_id,
7605+
msg.first_per_commitment_point,
7606+
)?;
7607+
let channel_id = ChannelId::v2_from_revocation_basepoints(
7608+
&context.get_holder_pubkeys().revocation_basepoint,
7609+
&context.get_counterparty_pubkeys().revocation_basepoint);
7610+
context.channel_id = channel_id;
7611+
7612+
let chan = Self {
7613+
context,
7614+
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 },
7615+
dual_funding_context: DualFundingChannelContext {
7616+
our_funding_satoshis: funding_satoshis,
7617+
their_funding_satoshis: msg.funding_satoshis,
7618+
funding_tx_locktime: msg.locktime,
7619+
funding_feerate_sat_per_1000_weight: msg.funding_feerate_sat_per_1000_weight,
7620+
}
7621+
};
7622+
7623+
Ok(chan)
7624+
}
7625+
7626+
/// Marks an inbound channel as accepted and generates a [`msgs::AcceptChannelV2`] message which
7627+
/// should be sent back to the counterparty node.
7628+
///
7629+
/// [`msgs::AcceptChannelV2`]: crate::ln::msgs::AcceptChannelV2
7630+
pub fn accept_inbound_dual_funded_channel(&mut self) -> msgs::AcceptChannelV2 {
7631+
if self.context.is_outbound() {
7632+
panic!("Tried to send accept_channel for an outbound channel?");
7633+
}
7634+
if !matches!(
7635+
self.context.channel_state, ChannelState::NegotiatingFunding(flags)
7636+
if flags == (NegotiatingFundingFlags::OUR_INIT_SENT | NegotiatingFundingFlags::THEIR_INIT_SENT)
7637+
) {
7638+
panic!("Tried to send accept_channel2 after channel had moved forward");
7639+
}
7640+
if self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
7641+
panic!("Tried to send an accept_channel2 for a channel that has already advanced");
7642+
}
7643+
7644+
self.generate_accept_channel_v2_message()
7645+
}
7646+
7647+
/// This function is used to explicitly generate a [`msgs::AcceptChannel`] message for an
7648+
/// inbound channel. If the intention is to accept an inbound channel, use
7649+
/// [`InboundV1Channel::accept_inbound_channel`] instead.
7650+
///
7651+
/// [`msgs::AcceptChannelV2`]: crate::ln::msgs::AcceptChannelV2
7652+
fn generate_accept_channel_v2_message(&self) -> msgs::AcceptChannelV2 {
7653+
let first_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(
7654+
self.context.cur_holder_commitment_transaction_number, &self.context.secp_ctx);
7655+
let second_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(
7656+
self.context.cur_holder_commitment_transaction_number - 1, &self.context.secp_ctx);
7657+
let keys = self.context.get_holder_pubkeys();
7658+
7659+
msgs::AcceptChannelV2 {
7660+
temporary_channel_id: self.context.temporary_channel_id.unwrap(),
7661+
funding_satoshis: self.dual_funding_context.our_funding_satoshis,
7662+
dust_limit_satoshis: self.context.holder_dust_limit_satoshis,
7663+
max_htlc_value_in_flight_msat: self.context.holder_max_htlc_value_in_flight_msat,
7664+
htlc_minimum_msat: self.context.holder_htlc_minimum_msat,
7665+
minimum_depth: self.context.minimum_depth.unwrap(),
7666+
to_self_delay: self.context.get_holder_selected_contest_delay(),
7667+
max_accepted_htlcs: self.context.holder_max_accepted_htlcs,
7668+
funding_pubkey: keys.funding_pubkey,
7669+
revocation_basepoint: keys.revocation_basepoint.to_public_key(),
7670+
payment_basepoint: keys.payment_point,
7671+
delayed_payment_basepoint: keys.delayed_payment_basepoint.to_public_key(),
7672+
htlc_basepoint: keys.htlc_basepoint.to_public_key(),
7673+
first_per_commitment_point,
7674+
second_per_commitment_point,
7675+
shutdown_scriptpubkey: Some(match &self.context.shutdown_scriptpubkey {
7676+
Some(script) => script.clone().into_inner(),
7677+
None => Builder::new().into_script(),
7678+
}),
7679+
channel_type: Some(self.context.channel_type.clone()),
7680+
require_confirmed_inputs: None,
7681+
}
7682+
}
7683+
7684+
/// Enables the possibility for tests to extract a [`msgs::AcceptChannelV2`] message for an
7685+
/// inbound channel without accepting it.
7686+
///
7687+
/// [`msgs::AcceptChannelV2`]: crate::ln::msgs::AcceptChannelV2
7688+
#[cfg(test)]
7689+
pub fn get_accept_channel_v2_message(&self) -> msgs::AcceptChannelV2 {
7690+
self.generate_accept_channel_v2_message()
7691+
}
7692+
}
7693+
74977694
const SERIALIZATION_VERSION: u8 = 3;
74987695
const MIN_SERIALIZATION_VERSION: u8 = 3;
74997696

@@ -8429,7 +8626,9 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
84298626
channel_keys_id,
84308627

84318628
blocked_monitor_updates: blocked_monitor_updates.unwrap(),
8432-
}
8629+
},
8630+
#[cfg(dual_funding)]
8631+
dual_funding_channel_context: None,
84338632
})
84348633
}
84358634
}
@@ -8992,7 +9191,11 @@ mod tests {
89929191
let config = UserConfig::default();
89939192
let features = channelmanager::provided_init_features(&config);
89949193
let outbound_chan = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, node_b_node_id, &features, 10000000, 100000, 42, &config, 0, 42, None).unwrap();
8995-
let mut chan = Channel { context: outbound_chan.context };
9194+
let mut chan = Channel {
9195+
context: outbound_chan.context,
9196+
#[cfg(dual_funding)]
9197+
dual_funding_channel_context: None,
9198+
};
89969199

89979200
let dummy_htlc_source = HTLCSource::OutboundRoute {
89989201
path: Path {

0 commit comments

Comments
 (0)