Skip to content

Commit e12a412

Browse files
committed
Add OutboundV2Channel struct
1 parent 730ff48 commit e12a412

File tree

1 file changed

+160
-35
lines changed

1 file changed

+160
-35
lines changed

lightning/src/ln/channel.rs

Lines changed: 160 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,7 +1596,10 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
15961596
current_chain_height: u32,
15971597
outbound_scid_alias: u64,
15981598
temporary_channel_id: Option<ChannelId>,
1599-
channel_type: ChannelTypeFeatures,
1599+
holder_selected_channel_reserve_satoshis: u64,
1600+
channel_keys_id: [u8; 32],
1601+
holder_signer: <SP::Target as SignerProvider>::EcdsaSigner,
1602+
pubkeys: ChannelPublicKeys,
16001603
) -> Result<ChannelContext<SP>, APIError>
16011604
where
16021605
ES::Target: EntropySource,
@@ -1607,9 +1610,6 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
16071610
let channel_value_satoshis = funding_satoshis;
16081611

16091612
let holder_selected_contest_delay = config.channel_handshake_config.our_to_self_delay;
1610-
let channel_keys_id = signer_provider.generate_channel_keys_id(false, channel_value_satoshis, user_id);
1611-
let holder_signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id);
1612-
let pubkeys = holder_signer.pubkeys().clone();
16131613

16141614
if !their_features.supports_wumbo() && channel_value_satoshis > MAX_FUNDING_SATOSHIS_NO_WUMBO {
16151615
return Err(APIError::APIMisuseError{err: format!("funding_value must not exceed {}, it was {}", MAX_FUNDING_SATOSHIS_NO_WUMBO, channel_value_satoshis)});
@@ -1624,13 +1624,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
16241624
if holder_selected_contest_delay < BREAKDOWN_TIMEOUT {
16251625
return Err(APIError::APIMisuseError {err: format!("Configured with an unreasonable our_to_self_delay ({}) putting user funds at risks", holder_selected_contest_delay)});
16261626
}
1627-
let holder_selected_channel_reserve_satoshis = get_holder_selected_channel_reserve_satoshis(channel_value_satoshis, config);
1628-
if holder_selected_channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
1629-
// Protocol level safety check in place, although it should never happen because
1630-
// of `MIN_THEIR_CHAN_RESERVE_SATOSHIS`
1631-
return Err(APIError::APIMisuseError { err: format!("Holder selected channel reserve below implemention limit dust_limit_satoshis {}", holder_selected_channel_reserve_satoshis) });
1632-
}
16331627

1628+
let channel_type = get_initial_channel_type(&config, their_features);
16341629
debug_assert!(channel_type.is_subset(&channelmanager::provided_channel_type_features(&config)));
16351630

16361631
let (commitment_conf_target, anchor_outputs_value_msat) = if channel_type.supports_anchors_zero_fee_htlc_tx() {
@@ -1687,6 +1682,7 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
16871682
channel_state: ChannelState::NegotiatingFunding(NegotiatingFundingFlags::OUR_INIT_SENT),
16881683
announcement_sigs_state: AnnouncementSigsState::NotSent,
16891684
secp_ctx,
1685+
// We'll add our counterparty's `funding_satoshis` when we receive `accept_channel2`.
16901686
channel_value_satoshis,
16911687

16921688
latest_monitor_update_id: 0,
@@ -1720,6 +1716,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
17201716
signer_pending_commitment_update: false,
17211717
signer_pending_funding: false,
17221718

1719+
// We'll add our counterparty's `funding_satoshis` to these max commitment output assertions
1720+
// when we receive `accept_channel2`.
17231721
#[cfg(debug_assertions)]
17241722
holder_max_commitment_tx_output: Mutex::new((channel_value_satoshis * 1000 - push_msat, push_msat)),
17251723
#[cfg(debug_assertions)]
@@ -1740,6 +1738,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
17401738
counterparty_dust_limit_satoshis: 0,
17411739
holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
17421740
counterparty_max_htlc_value_in_flight_msat: 0,
1741+
// We'll adjust this to include our counterparty's `funding_satoshis` when we
1742+
// receive `accept_channel2`.
17431743
holder_max_htlc_value_in_flight_msat: get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis, &config.channel_handshake_config),
17441744
counterparty_selected_channel_reserve_satoshis: None, // Filled in in accept_channel
17451745
holder_selected_channel_reserve_satoshis,
@@ -3072,6 +3072,7 @@ pub(crate) fn get_legacy_default_holder_selected_channel_reserve_satoshis(channe
30723072
///
30733073
/// This is used both for outbound and inbound channels and has lower bound
30743074
/// of `dust_limit_satoshis`.
3075+
#[cfg(dual_funding)]
30753076
fn get_v2_channel_reserve_satoshis(channel_value_satoshis: u64, dust_limit_satoshis: u64) -> u64 {
30763077
let channel_reserve_proportional_millionths = 10_000; // Fixed at 1% in spec.
30773078
let calculated_reserve =
@@ -6804,7 +6805,17 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
68046805
where ES::Target: EntropySource,
68056806
F::Target: FeeEstimator
68066807
{
6807-
let channel_type = Self::get_initial_channel_type(&config, their_features);
6808+
let holder_selected_channel_reserve_satoshis = get_holder_selected_channel_reserve_satoshis(channel_value_satoshis, config);
6809+
if holder_selected_channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
6810+
// Protocol level safety check in place, although it should never happen because
6811+
// of `MIN_THEIR_CHAN_RESERVE_SATOSHIS`
6812+
return Err(APIError::APIMisuseError { err: format!("Holder selected channel reserve below \
6813+
implemention limit dust_limit_satoshis {}", holder_selected_channel_reserve_satoshis) });
6814+
}
6815+
6816+
let channel_keys_id = signer_provider.generate_channel_keys_id(false, channel_value_satoshis, user_id);
6817+
let holder_signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id);
6818+
let pubkeys = holder_signer.pubkeys().clone();
68086819

68096820
let chan = Self {
68106821
context: ChannelContext::new_for_outbound_channel(
@@ -6820,7 +6831,10 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
68206831
current_chain_height,
68216832
outbound_scid_alias,
68226833
temporary_channel_id,
6823-
channel_type,
6834+
holder_selected_channel_reserve_satoshis,
6835+
channel_keys_id,
6836+
holder_signer,
6837+
pubkeys,
68246838
)?,
68256839
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 }
68266840
};
@@ -6918,29 +6932,6 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
69186932
Ok(funding_created)
69196933
}
69206934

6921-
fn get_initial_channel_type(config: &UserConfig, their_features: &InitFeatures) -> ChannelTypeFeatures {
6922-
// The default channel type (ie the first one we try) depends on whether the channel is
6923-
// public - if it is, we just go with `only_static_remotekey` as it's the only option
6924-
// available. If it's private, we first try `scid_privacy` as it provides better privacy
6925-
// with no other changes, and fall back to `only_static_remotekey`.
6926-
let mut ret = ChannelTypeFeatures::only_static_remote_key();
6927-
if !config.channel_handshake_config.announced_channel &&
6928-
config.channel_handshake_config.negotiate_scid_privacy &&
6929-
their_features.supports_scid_privacy() {
6930-
ret.set_scid_privacy_required();
6931-
}
6932-
6933-
// Optionally, if the user would like to negotiate the `anchors_zero_fee_htlc_tx` option, we
6934-
// set it now. If they don't understand it, we'll fall back to our default of
6935-
// `only_static_remotekey`.
6936-
if config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx &&
6937-
their_features.supports_anchors_zero_fee_htlc_tx() {
6938-
ret.set_anchors_zero_fee_htlc_tx_required();
6939-
}
6940-
6941-
ret
6942-
}
6943-
69446935
/// If we receive an error message, it may only be a rejection of the channel type we tried,
69456936
/// not of our ability to open any channel at all. Thus, on error, we should first call this
69466937
/// and see if we get a new `OpenChannel` message, otherwise the channel is failed.
@@ -7574,6 +7565,115 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
75747565
}
75757566
}
75767567

7568+
// A not-yet-funded outbound (from holder) channel using V2 channel establishment.
7569+
#[cfg(dual_funding)]
7570+
pub(super) struct OutboundV2Channel<SP: Deref> where SP::Target: SignerProvider {
7571+
pub context: ChannelContext<SP>,
7572+
pub unfunded_context: UnfundedChannelContext,
7573+
#[cfg(dual_funding)]
7574+
pub dual_funding_context: DualFundingChannelContext,
7575+
}
7576+
7577+
#[cfg(dual_funding)]
7578+
impl<SP: Deref> OutboundV2Channel<SP> where SP::Target: SignerProvider {
7579+
pub fn new<ES: Deref, F: Deref>(
7580+
fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
7581+
counterparty_node_id: PublicKey, their_features: &InitFeatures, funding_satoshis: u64,
7582+
user_id: u128, config: &UserConfig, current_chain_height: u32, outbound_scid_alias: u64,
7583+
funding_confirmation_target: ConfirmationTarget,
7584+
) -> Result<OutboundV2Channel<SP>, APIError>
7585+
where ES::Target: EntropySource,
7586+
F::Target: FeeEstimator,
7587+
{
7588+
let channel_keys_id = signer_provider.generate_channel_keys_id(false, funding_satoshis, user_id);
7589+
let holder_signer = signer_provider.derive_channel_signer(funding_satoshis, channel_keys_id);
7590+
let pubkeys = holder_signer.pubkeys().clone();
7591+
7592+
let temporary_channel_id = Some(ChannelId::temporary_v2_from_revocation_basepoint(&pubkeys.revocation_basepoint));
7593+
7594+
let holder_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
7595+
funding_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS);
7596+
7597+
let funding_feerate_sat_per_1000_weight = fee_estimator.bounded_sat_per_1000_weight(funding_confirmation_target);
7598+
let funding_tx_locktime = current_chain_height;
7599+
7600+
let chan = Self {
7601+
context: ChannelContext::new_for_outbound_channel(
7602+
fee_estimator,
7603+
entropy_source,
7604+
signer_provider,
7605+
counterparty_node_id,
7606+
their_features,
7607+
funding_satoshis,
7608+
0,
7609+
user_id,
7610+
config,
7611+
current_chain_height,
7612+
outbound_scid_alias,
7613+
temporary_channel_id,
7614+
holder_selected_channel_reserve_satoshis,
7615+
channel_keys_id,
7616+
holder_signer,
7617+
pubkeys,
7618+
)?,
7619+
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 },
7620+
dual_funding_context: DualFundingChannelContext {
7621+
our_funding_satoshis: funding_satoshis,
7622+
their_funding_satoshis: 0,
7623+
funding_tx_locktime,
7624+
funding_feerate_sat_per_1000_weight,
7625+
}
7626+
};
7627+
Ok(chan)
7628+
}
7629+
7630+
pub fn get_open_channel_v2(&self, chain_hash: ChainHash) -> msgs::OpenChannelV2 {
7631+
if self.context.have_received_message() {
7632+
panic!("Cannot generate an open_channel2 after we've moved forward");
7633+
}
7634+
7635+
if self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
7636+
panic!("Tried to send an open_channel2 for a channel that has already advanced");
7637+
}
7638+
7639+
let first_per_commitment_point = self.context.holder_signer.as_ref()
7640+
.get_per_commitment_point(self.context.cur_holder_commitment_transaction_number,
7641+
&self.context.secp_ctx);
7642+
let second_per_commitment_point = self.context.holder_signer.as_ref()
7643+
.get_per_commitment_point(self.context.cur_holder_commitment_transaction_number - 1,
7644+
&self.context.secp_ctx);
7645+
let keys = self.context.get_holder_pubkeys();
7646+
7647+
msgs::OpenChannelV2 {
7648+
chain_hash,
7649+
temporary_channel_id: self.context.temporary_channel_id.unwrap(),
7650+
funding_satoshis: self.context.channel_value_satoshis,
7651+
dust_limit_satoshis: self.context.holder_dust_limit_satoshis,
7652+
max_htlc_value_in_flight_msat: self.context.holder_max_htlc_value_in_flight_msat,
7653+
htlc_minimum_msat: self.context.holder_htlc_minimum_msat,
7654+
funding_feerate_sat_per_1000_weight: self.context.feerate_per_kw,
7655+
commitment_feerate_sat_per_1000_weight: self.context.feerate_per_kw,
7656+
to_self_delay: self.context.get_holder_selected_contest_delay(),
7657+
max_accepted_htlcs: self.context.holder_max_accepted_htlcs,
7658+
funding_pubkey: keys.funding_pubkey,
7659+
revocation_basepoint: keys.revocation_basepoint.to_public_key(),
7660+
payment_basepoint: keys.payment_point,
7661+
delayed_payment_basepoint: keys.delayed_payment_basepoint.to_public_key(),
7662+
htlc_basepoint: keys.htlc_basepoint.to_public_key(),
7663+
first_per_commitment_point,
7664+
second_per_commitment_point,
7665+
channel_flags: if self.context.config.announced_channel {1} else {0},
7666+
shutdown_scriptpubkey: Some(match &self.context.shutdown_scriptpubkey {
7667+
Some(script) => script.clone().into_inner(),
7668+
None => Builder::new().into_script(),
7669+
}),
7670+
channel_type: Some(self.context.channel_type.clone()),
7671+
locktime: self.dual_funding_context.funding_tx_locktime,
7672+
require_confirmed_inputs: None,
7673+
}
7674+
}
7675+
}
7676+
75777677
// A not-yet-funded inbound (from counterparty) channel using V2 channel establishment.
75787678
#[cfg(dual_funding)]
75797679
pub(super) struct InboundV2Channel<SP: Deref> where SP::Target: SignerProvider {
@@ -7733,6 +7833,31 @@ impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
77337833
}
77347834
}
77357835

7836+
// Unfunded channel utilities
7837+
7838+
fn get_initial_channel_type(config: &UserConfig, their_features: &InitFeatures) -> ChannelTypeFeatures {
7839+
// The default channel type (ie the first one we try) depends on whether the channel is
7840+
// public - if it is, we just go with `only_static_remotekey` as it's the only option
7841+
// available. If it's private, we first try `scid_privacy` as it provides better privacy
7842+
// with no other changes, and fall back to `only_static_remotekey`.
7843+
let mut ret = ChannelTypeFeatures::only_static_remote_key();
7844+
if !config.channel_handshake_config.announced_channel &&
7845+
config.channel_handshake_config.negotiate_scid_privacy &&
7846+
their_features.supports_scid_privacy() {
7847+
ret.set_scid_privacy_required();
7848+
}
7849+
7850+
// Optionally, if the user would like to negotiate the `anchors_zero_fee_htlc_tx` option, we
7851+
// set it now. If they don't understand it, we'll fall back to our default of
7852+
// `only_static_remotekey`.
7853+
if config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx &&
7854+
their_features.supports_anchors_zero_fee_htlc_tx() {
7855+
ret.set_anchors_zero_fee_htlc_tx_required();
7856+
}
7857+
7858+
ret
7859+
}
7860+
77367861
const SERIALIZATION_VERSION: u8 = 3;
77377862
const MIN_SERIALIZATION_VERSION: u8 = 3;
77387863

0 commit comments

Comments
 (0)