Skip to content

Commit 5c68d10

Browse files
committed
Add OutboundV2Channel struct
1 parent 2f1fcb7 commit 5c68d10

File tree

1 file changed

+158
-35
lines changed

1 file changed

+158
-35
lines changed

lightning/src/ln/channel.rs

Lines changed: 158 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,7 +1616,10 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
16161616
current_chain_height: u32,
16171617
outbound_scid_alias: u64,
16181618
temporary_channel_id: ChannelId,
1619-
channel_type: ChannelTypeFeatures,
1619+
holder_selected_channel_reserve_satoshis: u64,
1620+
channel_keys_id: [u8; 32],
1621+
holder_signer: <SP::Target as SignerProvider>::EcdsaSigner,
1622+
pubkeys: ChannelPublicKeys,
16201623
) -> Result<ChannelContext<SP>, APIError>
16211624
where
16221625
ES::Target: EntropySource,
@@ -1627,9 +1630,6 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
16271630
let channel_value_satoshis = funding_satoshis;
16281631

16291632
let holder_selected_contest_delay = config.channel_handshake_config.our_to_self_delay;
1630-
let channel_keys_id = signer_provider.generate_channel_keys_id(false, channel_value_satoshis, user_id);
1631-
let holder_signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id);
1632-
let pubkeys = holder_signer.pubkeys().clone();
16331633

16341634
if !their_features.supports_wumbo() && channel_value_satoshis > MAX_FUNDING_SATOSHIS_NO_WUMBO {
16351635
return Err(APIError::APIMisuseError{err: format!("funding_value must not exceed {}, it was {}", MAX_FUNDING_SATOSHIS_NO_WUMBO, channel_value_satoshis)});
@@ -1644,13 +1644,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
16441644
if holder_selected_contest_delay < BREAKDOWN_TIMEOUT {
16451645
return Err(APIError::APIMisuseError {err: format!("Configured with an unreasonable our_to_self_delay ({}) putting user funds at risks", holder_selected_contest_delay)});
16461646
}
1647-
let holder_selected_channel_reserve_satoshis = get_holder_selected_channel_reserve_satoshis(channel_value_satoshis, config);
1648-
if holder_selected_channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
1649-
// Protocol level safety check in place, although it should never happen because
1650-
// of `MIN_THEIR_CHAN_RESERVE_SATOSHIS`
1651-
return Err(APIError::APIMisuseError { err: format!("Holder selected channel reserve below implemention limit dust_limit_satoshis {}", holder_selected_channel_reserve_satoshis) });
1652-
}
16531647

1648+
let channel_type = get_initial_channel_type(&config, their_features);
16541649
debug_assert!(channel_type.is_subset(&channelmanager::provided_channel_type_features(&config)));
16551650

16561651
let (commitment_conf_target, anchor_outputs_value_msat) = if channel_type.supports_anchors_zero_fee_htlc_tx() {
@@ -1706,6 +1701,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
17061701
channel_state: ChannelState::NegotiatingFunding(NegotiatingFundingFlags::OUR_INIT_SENT),
17071702
announcement_sigs_state: AnnouncementSigsState::NotSent,
17081703
secp_ctx,
1704+
// We'll add our counterparty's `funding_satoshis` when we receive `accept_channel2`.
17091705
channel_value_satoshis,
17101706

17111707
latest_monitor_update_id: 0,
@@ -1739,6 +1735,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
17391735
signer_pending_commitment_update: false,
17401736
signer_pending_funding: false,
17411737

1738+
// We'll add our counterparty's `funding_satoshis` to these max commitment output assertions
1739+
// when we receive `accept_channel2`.
17421740
#[cfg(debug_assertions)]
17431741
holder_max_commitment_tx_output: Mutex::new((channel_value_satoshis * 1000 - push_msat, push_msat)),
17441742
#[cfg(debug_assertions)]
@@ -1759,6 +1757,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
17591757
counterparty_dust_limit_satoshis: 0,
17601758
holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
17611759
counterparty_max_htlc_value_in_flight_msat: 0,
1760+
// We'll adjust this to include our counterparty's `funding_satoshis` when we
1761+
// receive `accept_channel2`.
17621762
holder_max_htlc_value_in_flight_msat: get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &config.channel_handshake_config),
17631763
counterparty_selected_channel_reserve_satoshis: None, // Filled in in accept_channel
17641764
holder_selected_channel_reserve_satoshis,
@@ -6704,7 +6704,17 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
67046704
F::Target: FeeEstimator
67056705
{
67066706
let temporary_channel_id = temporary_channel_id.unwrap_or_else(|| ChannelId::temporary_from_entropy_source(entropy_source));
6707-
let channel_type = Self::get_initial_channel_type(&config, their_features);
6707+
6708+
let holder_selected_channel_reserve_satoshis = get_holder_selected_channel_reserve_satoshis(channel_value_satoshis, config);
6709+
if holder_selected_channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
6710+
// Protocol level safety check in place, although it should never happen because
6711+
// of `MIN_THEIR_CHAN_RESERVE_SATOSHIS`
6712+
return Err(APIError::APIMisuseError { err: format!("Holder selected channel reserve below implemention limit dust_limit_satoshis {}", holder_selected_channel_reserve_satoshis) });
6713+
}
6714+
6715+
let channel_keys_id = signer_provider.generate_channel_keys_id(false, channel_value_satoshis, user_id);
6716+
let holder_signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id);
6717+
let pubkeys = holder_signer.pubkeys().clone();
67086718

67096719
let chan = Self {
67106720
context: ChannelContext::new_for_outbound_channel(
@@ -6720,7 +6730,10 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
67206730
current_chain_height,
67216731
outbound_scid_alias,
67226732
temporary_channel_id,
6723-
channel_type,
6733+
holder_selected_channel_reserve_satoshis,
6734+
channel_keys_id,
6735+
holder_signer,
6736+
pubkeys,
67246737
)?,
67256738
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 }
67266739
};
@@ -6813,29 +6826,6 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
68136826
Ok(funding_created)
68146827
}
68156828

6816-
fn get_initial_channel_type(config: &UserConfig, their_features: &InitFeatures) -> ChannelTypeFeatures {
6817-
// The default channel type (ie the first one we try) depends on whether the channel is
6818-
// public - if it is, we just go with `only_static_remotekey` as it's the only option
6819-
// available. If it's private, we first try `scid_privacy` as it provides better privacy
6820-
// with no other changes, and fall back to `only_static_remotekey`.
6821-
let mut ret = ChannelTypeFeatures::only_static_remote_key();
6822-
if !config.channel_handshake_config.announced_channel &&
6823-
config.channel_handshake_config.negotiate_scid_privacy &&
6824-
their_features.supports_scid_privacy() {
6825-
ret.set_scid_privacy_required();
6826-
}
6827-
6828-
// Optionally, if the user would like to negotiate the `anchors_zero_fee_htlc_tx` option, we
6829-
// set it now. If they don't understand it, we'll fall back to our default of
6830-
// `only_static_remotekey`.
6831-
if config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx &&
6832-
their_features.supports_anchors_zero_fee_htlc_tx() {
6833-
ret.set_anchors_zero_fee_htlc_tx_required();
6834-
}
6835-
6836-
ret
6837-
}
6838-
68396829
/// If we receive an error message, it may only be a rejection of the channel type we tried,
68406830
/// not of our ability to open any channel at all. Thus, on error, we should first call this
68416831
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
@@ -7414,6 +7404,114 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
74147404
}
74157405
}
74167406

7407+
// A not-yet-funded outbound (from holder) channel using V2 channel establishment.
7408+
pub(super) struct OutboundV2Channel<SP: Deref> where SP::Target: SignerProvider {
7409+
pub context: ChannelContext<SP>,
7410+
pub unfunded_context: UnfundedChannelContext,
7411+
#[cfg(dual_funding)]
7412+
pub dual_funding_context: DualFundingChannelContext,
7413+
}
7414+
7415+
#[cfg(dual_funding)]
7416+
impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
7417+
pub fn new<ES: Deref, F: Deref>(
7418+
fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
7419+
counterparty_node_id: PublicKey, their_features: &InitFeatures, funding_satoshis: u64,
7420+
user_id: u128, config: &UserConfig, current_chain_height: u32, outbound_scid_alias: u64,
7421+
funding_confirmation_target: ConfirmationTarget,
7422+
) -> Result<OutboundV2Channel<SP>, APIError>
7423+
where ES::Target: EntropySource,
7424+
F::Target: FeeEstimator,
7425+
{
7426+
let channel_keys_id = signer_provider.generate_channel_keys_id(false, funding_satoshis, user_id);
7427+
let holder_signer = signer_provider.derive_channel_signer(funding_satoshis, channel_keys_id);
7428+
let pubkeys = holder_signer.pubkeys().clone();
7429+
7430+
let temporary_channel_id = ChannelId::temporary_v2_from_revocation_basepoint(&pubkeys.revocation_basepoint);
7431+
7432+
let holder_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
7433+
funding_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS);
7434+
7435+
let funding_feerate_sat_per_1000_weight = fee_estimator.bounded_sat_per_1000_weight(funding_confirmation_target);
7436+
let funding_tx_locktime = current_chain_height;
7437+
7438+
let chan = Self {
7439+
context: ChannelContext::new_for_outbound_channel(
7440+
fee_estimator,
7441+
entropy_source,
7442+
signer_provider,
7443+
counterparty_node_id,
7444+
their_features,
7445+
funding_satoshis,
7446+
0,
7447+
user_id,
7448+
config,
7449+
current_chain_height,
7450+
outbound_scid_alias,
7451+
temporary_channel_id,
7452+
holder_selected_channel_reserve_satoshis,
7453+
channel_keys_id,
7454+
holder_signer,
7455+
pubkeys,
7456+
)?,
7457+
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 },
7458+
dual_funding_context: DualFundingChannelContext {
7459+
our_funding_satoshis: funding_satoshis,
7460+
their_funding_satoshis: 0,
7461+
funding_tx_locktime,
7462+
funding_feerate_sat_per_1000_weight,
7463+
}
7464+
};
7465+
Ok(chan)
7466+
}
7467+
7468+
pub fn get_open_channel_v2(&self, chain_hash: ChainHash) -> msgs::OpenChannelV2 {
7469+
if self.context.channel_state != ChannelState::OurInitSent as u32 {
7470+
panic!("Cannot generate an open_channel2 after we've moved forward");
7471+
}
7472+
7473+
if self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
7474+
panic!("Tried to send an open_channel2 for a channel that has already advanced");
7475+
}
7476+
7477+
let first_per_commitment_point = self.context.holder_signer.as_ref()
7478+
.get_per_commitment_point(self.context.cur_holder_commitment_transaction_number,
7479+
&self.context.secp_ctx);
7480+
let second_per_commitment_point = self.context.holder_signer.as_ref()
7481+
.get_per_commitment_point(self.context.cur_holder_commitment_transaction_number - 1,
7482+
&self.context.secp_ctx);
7483+
let keys = self.context.get_holder_pubkeys();
7484+
7485+
msgs::OpenChannelV2 {
7486+
chain_hash,
7487+
temporary_channel_id: self.context.temporary_channel_id.unwrap(),
7488+
funding_satoshis: self.context.channel_value_satoshis,
7489+
dust_limit_satoshis: self.context.holder_dust_limit_satoshis,
7490+
max_htlc_value_in_flight_msat: self.context.holder_max_htlc_value_in_flight_msat,
7491+
htlc_minimum_msat: self.context.holder_htlc_minimum_msat,
7492+
funding_feerate_sat_per_1000_weight: self.context.feerate_per_kw,
7493+
commitment_feerate_sat_per_1000_weight: self.context.feerate_per_kw,
7494+
to_self_delay: self.context.get_holder_selected_contest_delay(),
7495+
max_accepted_htlcs: self.context.holder_max_accepted_htlcs,
7496+
funding_pubkey: keys.funding_pubkey,
7497+
revocation_basepoint: keys.revocation_basepoint.to_public_key(),
7498+
payment_basepoint: keys.payment_point,
7499+
delayed_payment_basepoint: keys.delayed_payment_basepoint.to_public_key(),
7500+
htlc_basepoint: keys.htlc_basepoint.to_public_key(),
7501+
first_per_commitment_point,
7502+
second_per_commitment_point,
7503+
channel_flags: if self.context.config.announced_channel {1} else {0},
7504+
shutdown_scriptpubkey: Some(match &self.context.shutdown_scriptpubkey {
7505+
Some(script) => script.clone().into_inner(),
7506+
None => Builder::new().into_script(),
7507+
}),
7508+
channel_type: Some(self.context.channel_type.clone()),
7509+
locktime: self.dual_funding_context.funding_tx_locktime,
7510+
require_confirmed_inputs: None,
7511+
}
7512+
}
7513+
}
7514+
74177515
// A not-yet-funded inbound (from counterparty) channel using V2 channel establishment.
74187516
#[cfg(dual_funding)]
74197517
pub(super) struct InboundV2Channel<SP: Deref> where SP::Target: SignerProvider {
@@ -7567,6 +7665,31 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
75677665
}
75687666
}
75697667

7668+
// Unfunded channel utilities
7669+
7670+
fn get_initial_channel_type(config: &UserConfig, their_features: &InitFeatures) -> ChannelTypeFeatures {
7671+
// The default channel type (ie the first one we try) depends on whether the channel is
7672+
// public - if it is, we just go with `only_static_remotekey` as it's the only option
7673+
// available. If it's private, we first try `scid_privacy` as it provides better privacy
7674+
// with no other changes, and fall back to `only_static_remotekey`.
7675+
let mut ret = ChannelTypeFeatures::only_static_remote_key();
7676+
if !config.channel_handshake_config.announced_channel &&
7677+
config.channel_handshake_config.negotiate_scid_privacy &&
7678+
their_features.supports_scid_privacy() {
7679+
ret.set_scid_privacy_required();
7680+
}
7681+
7682+
// Optionally, if the user would like to negotiate the `anchors_zero_fee_htlc_tx` option, we
7683+
// set it now. If they don't understand it, we'll fall back to our default of
7684+
// `only_static_remotekey`.
7685+
if config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx &&
7686+
their_features.supports_anchors_zero_fee_htlc_tx() {
7687+
ret.set_anchors_zero_fee_htlc_tx_required();
7688+
}
7689+
7690+
ret
7691+
}
7692+
75707693
const SERIALIZATION_VERSION: u8 = 3;
75717694
const MIN_SERIALIZATION_VERSION: u8 = 3;
75727695

0 commit comments

Comments
 (0)