Skip to content

Commit 7fbca89

Browse files
committed
Add OutboundV2Channel struct
1 parent b54396e commit 7fbca89

File tree

1 file changed

+162
-35
lines changed

1 file changed

+162
-35
lines changed

lightning/src/ln/channel.rs

Lines changed: 162 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1848,7 +1848,10 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
18481848
current_chain_height: u32,
18491849
outbound_scid_alias: u64,
18501850
temporary_channel_id: Option<ChannelId>,
1851-
channel_type: ChannelTypeFeatures,
1851+
holder_selected_channel_reserve_satoshis: u64,
1852+
channel_keys_id: [u8; 32],
1853+
holder_signer: <SP::Target as SignerProvider>::EcdsaSigner,
1854+
pubkeys: ChannelPublicKeys,
18521855
) -> Result<ChannelContext<SP>, APIError>
18531856
where
18541857
ES::Target: EntropySource,
@@ -1859,9 +1862,6 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
18591862
let channel_value_satoshis = funding_satoshis;
18601863

18611864
let holder_selected_contest_delay = config.channel_handshake_config.our_to_self_delay;
1862-
let channel_keys_id = signer_provider.generate_channel_keys_id(false, channel_value_satoshis, user_id);
1863-
let holder_signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id);
1864-
let pubkeys = holder_signer.pubkeys().clone();
18651865

18661866
if !their_features.supports_wumbo() && channel_value_satoshis > MAX_FUNDING_SATOSHIS_NO_WUMBO {
18671867
return Err(APIError::APIMisuseError{err: format!("funding_value must not exceed {}, it was {}", MAX_FUNDING_SATOSHIS_NO_WUMBO, channel_value_satoshis)});
@@ -1876,13 +1876,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
18761876
if holder_selected_contest_delay < BREAKDOWN_TIMEOUT {
18771877
return Err(APIError::APIMisuseError {err: format!("Configured with an unreasonable our_to_self_delay ({}) putting user funds at risks", holder_selected_contest_delay)});
18781878
}
1879-
let holder_selected_channel_reserve_satoshis = get_holder_selected_channel_reserve_satoshis(channel_value_satoshis, config);
1880-
if holder_selected_channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
1881-
// Protocol level safety check in place, although it should never happen because
1882-
// of `MIN_THEIR_CHAN_RESERVE_SATOSHIS`
1883-
return Err(APIError::APIMisuseError { err: format!("Holder selected channel reserve below implemention limit dust_limit_satoshis {}", holder_selected_channel_reserve_satoshis) });
1884-
}
18851879

1880+
let channel_type = get_initial_channel_type(&config, their_features);
18861881
debug_assert!(channel_type.is_subset(&channelmanager::provided_channel_type_features(&config)));
18871882

18881883
let (commitment_conf_target, anchor_outputs_value_msat) = if channel_type.supports_anchors_zero_fee_htlc_tx() {
@@ -1939,6 +1934,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
19391934
channel_state: ChannelState::NegotiatingFunding(NegotiatingFundingFlags::OUR_INIT_SENT),
19401935
announcement_sigs_state: AnnouncementSigsState::NotSent,
19411936
secp_ctx,
1937+
// We'll add our counterparty's `funding_satoshis` when we receive `accept_channel2`.
19421938
channel_value_satoshis,
19431939

19441940
latest_monitor_update_id: 0,
@@ -1972,6 +1968,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
19721968
signer_pending_commitment_update: false,
19731969
signer_pending_funding: false,
19741970

1971+
// We'll add our counterparty's `funding_satoshis` to these max commitment output assertions
1972+
// when we receive `accept_channel2`.
19751973
#[cfg(debug_assertions)]
19761974
holder_max_commitment_tx_output: Mutex::new((channel_value_satoshis * 1000 - push_msat, push_msat)),
19771975
#[cfg(debug_assertions)]
@@ -1992,6 +1990,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
19921990
counterparty_dust_limit_satoshis: 0,
19931991
holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
19941992
counterparty_max_htlc_value_in_flight_msat: 0,
1993+
// We'll adjust this to include our counterparty's `funding_satoshis` when we
1994+
// receive `accept_channel2`.
19951995
holder_max_htlc_value_in_flight_msat: get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &config.channel_handshake_config),
19961996
counterparty_selected_channel_reserve_satoshis: None, // Filled in in accept_channel
19971997
holder_selected_channel_reserve_satoshis,
@@ -3415,6 +3415,7 @@ pub(crate) fn get_legacy_default_holder_selected_channel_reserve_satoshis(channe
34153415
///
34163416
/// This is used both for outbound and inbound channels and has lower bound
34173417
/// of `dust_limit_satoshis`.
3418+
#[cfg(dual_funding)]
34183419
fn get_v2_channel_reserve_satoshis(channel_value_satoshis: u64, dust_limit_satoshis: u64) -> u64 {
34193420
// Fixed at 1% of channel value by spec.
34203421
let (q, _) = channel_value_satoshis.overflowing_div(100);
@@ -7165,7 +7166,17 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
71657166
where ES::Target: EntropySource,
71667167
F::Target: FeeEstimator
71677168
{
7168-
let channel_type = Self::get_initial_channel_type(&config, their_features);
7169+
let holder_selected_channel_reserve_satoshis = get_holder_selected_channel_reserve_satoshis(channel_value_satoshis, config);
7170+
if holder_selected_channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
7171+
// Protocol level safety check in place, although it should never happen because
7172+
// of `MIN_THEIR_CHAN_RESERVE_SATOSHIS`
7173+
return Err(APIError::APIMisuseError { err: format!("Holder selected channel reserve below \
7174+
implemention limit dust_limit_satoshis {}", holder_selected_channel_reserve_satoshis) });
7175+
}
7176+
7177+
let channel_keys_id = signer_provider.generate_channel_keys_id(false, channel_value_satoshis, user_id);
7178+
let holder_signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id);
7179+
let pubkeys = holder_signer.pubkeys().clone();
71697180

71707181
let chan = Self {
71717182
context: ChannelContext::new_for_outbound_channel(
@@ -7181,7 +7192,10 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
71817192
current_chain_height,
71827193
outbound_scid_alias,
71837194
temporary_channel_id,
7184-
channel_type,
7195+
holder_selected_channel_reserve_satoshis,
7196+
channel_keys_id,
7197+
holder_signer,
7198+
pubkeys,
71857199
)?,
71867200
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 }
71877201
};
@@ -7279,29 +7293,6 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
72797293
Ok(funding_created)
72807294
}
72817295

7282-
fn get_initial_channel_type(config: &UserConfig, their_features: &InitFeatures) -> ChannelTypeFeatures {
7283-
// The default channel type (ie the first one we try) depends on whether the channel is
7284-
// public - if it is, we just go with `only_static_remotekey` as it's the only option
7285-
// available. If it's private, we first try `scid_privacy` as it provides better privacy
7286-
// with no other changes, and fall back to `only_static_remotekey`.
7287-
let mut ret = ChannelTypeFeatures::only_static_remote_key();
7288-
if !config.channel_handshake_config.announced_channel &&
7289-
config.channel_handshake_config.negotiate_scid_privacy &&
7290-
their_features.supports_scid_privacy() {
7291-
ret.set_scid_privacy_required();
7292-
}
7293-
7294-
// Optionally, if the user would like to negotiate the `anchors_zero_fee_htlc_tx` option, we
7295-
// set it now. If they don't understand it, we'll fall back to our default of
7296-
// `only_static_remotekey`.
7297-
if config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx &&
7298-
their_features.supports_anchors_zero_fee_htlc_tx() {
7299-
ret.set_anchors_zero_fee_htlc_tx_required();
7300-
}
7301-
7302-
ret
7303-
}
7304-
73057296
/// If we receive an error message, it may only be a rejection of the channel type we tried,
73067297
/// not of our ability to open any channel at all. Thus, on error, we should first call this
73077298
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
@@ -7913,6 +7904,117 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
79137904
}
79147905
}
79157906

7907+
// A not-yet-funded outbound (from holder) channel using V2 channel establishment.
7908+
#[cfg(dual_funding)]
7909+
pub(super) struct OutboundV2Channel<SP: Deref> where SP::Target: SignerProvider {
7910+
pub context: ChannelContext<SP>,
7911+
pub unfunded_context: UnfundedChannelContext,
7912+
#[cfg(dual_funding)]
7913+
pub dual_funding_context: DualFundingChannelContext,
7914+
}
7915+
7916+
#[cfg(dual_funding)]
7917+
impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
7918+
pub fn new<ES: Deref, F: Deref>(
7919+
fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
7920+
counterparty_node_id: PublicKey, their_features: &InitFeatures, funding_satoshis: u64,
7921+
user_id: u128, config: &UserConfig, current_chain_height: u32, outbound_scid_alias: u64,
7922+
funding_confirmation_target: ConfirmationTarget,
7923+
) -> Result<OutboundV2Channel<SP>, APIError>
7924+
where ES::Target: EntropySource,
7925+
F::Target: FeeEstimator,
7926+
{
7927+
let channel_keys_id = signer_provider.generate_channel_keys_id(false, funding_satoshis, user_id);
7928+
let holder_signer = signer_provider.derive_channel_signer(funding_satoshis, channel_keys_id);
7929+
let pubkeys = holder_signer.pubkeys().clone();
7930+
7931+
let temporary_channel_id = Some(ChannelId::temporary_v2_from_revocation_basepoint(&pubkeys.revocation_basepoint));
7932+
7933+
let holder_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
7934+
funding_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS);
7935+
7936+
let funding_feerate_sat_per_1000_weight = fee_estimator.bounded_sat_per_1000_weight(funding_confirmation_target);
7937+
let funding_tx_locktime = current_chain_height;
7938+
7939+
let chan = Self {
7940+
context: ChannelContext::new_for_outbound_channel(
7941+
fee_estimator,
7942+
entropy_source,
7943+
signer_provider,
7944+
counterparty_node_id,
7945+
their_features,
7946+
funding_satoshis,
7947+
0,
7948+
user_id,
7949+
config,
7950+
current_chain_height,
7951+
outbound_scid_alias,
7952+
temporary_channel_id,
7953+
holder_selected_channel_reserve_satoshis,
7954+
channel_keys_id,
7955+
holder_signer,
7956+
pubkeys,
7957+
)?,
7958+
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 },
7959+
dual_funding_context: DualFundingChannelContext {
7960+
our_funding_satoshis: funding_satoshis,
7961+
their_funding_satoshis: 0,
7962+
funding_tx_locktime,
7963+
funding_feerate_sat_per_1000_weight,
7964+
}
7965+
};
7966+
Ok(chan)
7967+
}
7968+
7969+
pub fn get_open_channel_v2(&self, chain_hash: ChainHash) -> msgs::OpenChannelV2 {
7970+
if self.context.have_received_message() {
7971+
debug_assert!(false, "Cannot generate an open_channel2 after we've moved forward");
7972+
}
7973+
7974+
if self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
7975+
debug_assert!(false, "Tried to send an open_channel2 for a channel that has already advanced");
7976+
}
7977+
7978+
let first_per_commitment_point = self.context.holder_signer.as_ref()
7979+
.get_per_commitment_point(self.context.cur_holder_commitment_transaction_number,
7980+
&self.context.secp_ctx);
7981+
let second_per_commitment_point = self.context.holder_signer.as_ref()
7982+
.get_per_commitment_point(self.context.cur_holder_commitment_transaction_number - 1,
7983+
&self.context.secp_ctx);
7984+
let keys = self.context.get_holder_pubkeys();
7985+
7986+
msgs::OpenChannelV2 {
7987+
common_fields: msgs::CommonOpenChannelFields {
7988+
chain_hash,
7989+
temporary_channel_id: self.context.temporary_channel_id.unwrap(),
7990+
funding_satoshis: self.context.channel_value_satoshis,
7991+
dust_limit_satoshis: self.context.holder_dust_limit_satoshis,
7992+
max_htlc_value_in_flight_msat: self.context.holder_max_htlc_value_in_flight_msat,
7993+
htlc_minimum_msat: self.context.holder_htlc_minimum_msat,
7994+
commitment_feerate_sat_per_1000_weight: self.context.feerate_per_kw,
7995+
to_self_delay: self.context.get_holder_selected_contest_delay(),
7996+
max_accepted_htlcs: self.context.holder_max_accepted_htlcs,
7997+
funding_pubkey: keys.funding_pubkey,
7998+
revocation_basepoint: keys.revocation_basepoint.to_public_key(),
7999+
payment_basepoint: keys.payment_point,
8000+
delayed_payment_basepoint: keys.delayed_payment_basepoint.to_public_key(),
8001+
htlc_basepoint: keys.htlc_basepoint.to_public_key(),
8002+
first_per_commitment_point,
8003+
channel_flags: if self.context.config.announced_channel {1} else {0},
8004+
shutdown_scriptpubkey: Some(match &self.context.shutdown_scriptpubkey {
8005+
Some(script) => script.clone().into_inner(),
8006+
None => Builder::new().into_script(),
8007+
}),
8008+
channel_type: Some(self.context.channel_type.clone()),
8009+
},
8010+
funding_feerate_sat_per_1000_weight: self.context.feerate_per_kw,
8011+
second_per_commitment_point,
8012+
locktime: self.dual_funding_context.funding_tx_locktime,
8013+
require_confirmed_inputs: None,
8014+
}
8015+
}
8016+
}
8017+
79168018
// A not-yet-funded inbound (from counterparty) channel using V2 channel establishment.
79178019
#[cfg(dual_funding)]
79188020
pub(super) struct InboundV2Channel<SP: Deref> where SP::Target: SignerProvider {
@@ -8067,6 +8169,31 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
80678169
}
80688170
}
80698171

8172+
// Unfunded channel utilities
8173+
8174+
fn get_initial_channel_type(config: &UserConfig, their_features: &InitFeatures) -> ChannelTypeFeatures {
8175+
// The default channel type (ie the first one we try) depends on whether the channel is
8176+
// public - if it is, we just go with `only_static_remotekey` as it's the only option
8177+
// available. If it's private, we first try `scid_privacy` as it provides better privacy
8178+
// with no other changes, and fall back to `only_static_remotekey`.
8179+
let mut ret = ChannelTypeFeatures::only_static_remote_key();
8180+
if !config.channel_handshake_config.announced_channel &&
8181+
config.channel_handshake_config.negotiate_scid_privacy &&
8182+
their_features.supports_scid_privacy() {
8183+
ret.set_scid_privacy_required();
8184+
}
8185+
8186+
// Optionally, if the user would like to negotiate the `anchors_zero_fee_htlc_tx` option, we
8187+
// set it now. If they don't understand it, we'll fall back to our default of
8188+
// `only_static_remotekey`.
8189+
if config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx &&
8190+
their_features.supports_anchors_zero_fee_htlc_tx() {
8191+
ret.set_anchors_zero_fee_htlc_tx_required();
8192+
}
8193+
8194+
ret
8195+
}
8196+
80708197
const SERIALIZATION_VERSION: u8 = 3;
80718198
const MIN_SERIALIZATION_VERSION: u8 = 3;
80728199

0 commit comments

Comments
 (0)