Skip to content

Commit 2ee04b0

Browse files
committed
Add InboundV2Channel struct
1 parent 2e66dc5 commit 2ee04b0

File tree

1 file changed

+184
-3
lines changed

1 file changed

+184
-3
lines changed

lightning/src/ln/channel.rs

Lines changed: 184 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2860,6 +2860,20 @@ pub(crate) fn get_legacy_default_holder_selected_channel_reserve_satoshis(channe
28602860
cmp::min(channel_value_satoshis, cmp::max(q, 1000))
28612861
}
28622862

2863+
/// Returns a minimum channel reserve value each party needs to maintain, fixed in the spec to a
2864+
/// default of 1% of the total channel value.
2865+
///
2866+
/// Guaranteed to return a value no larger than channel_value_satoshis
2867+
///
2868+
/// This is used both for outbound and inbound channels and has lower bound
2869+
/// of `dust_limit_satoshis`.
2870+
fn get_v2_channel_reserve_satoshis(channel_value_satoshis: u64, dust_limit_satoshis: u64) -> u64 {
2871+
let channel_reserve_proportional_millionths = 10_000; // Fixed at 1% in spec.
2872+
let calculated_reserve =
2873+
channel_value_satoshis.saturating_mul(channel_reserve_proportional_millionths) / 1_000_000;
2874+
cmp::min(channel_value_satoshis, cmp::max(calculated_reserve, dust_limit_satoshis))
2875+
}
2876+
28632877
// Get the fee cost in SATS of a commitment tx with a given number of HTLC outputs.
28642878
// Note that num_htlcs should not include dust HTLCs.
28652879
#[inline]
@@ -2893,6 +2907,8 @@ pub(super) struct DualFundingChannelContext {
28932907
// Counterparty designates channel data owned by the another channel participant entity.
28942908
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
28952909
pub context: ChannelContext<SP>,
2910+
#[cfg(dual_funding)]
2911+
pub dual_funding_channel_context: Option<DualFundingChannelContext>,
28962912
}
28972913

28982914
#[cfg(any(test, fuzzing))]
@@ -7085,7 +7101,11 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
70857101

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

7088-
let mut channel = Channel { context: self.context };
7104+
let mut channel = Channel {
7105+
context: self.context,
7106+
#[cfg(dual_funding)]
7107+
dual_funding_channel_context: None,
7108+
};
70897109

70907110
let need_channel_ready = channel.check_get_channel_ready(0).is_some();
70917111
channel.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
@@ -7342,6 +7362,8 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
73427362
// `ChannelMonitor`.
73437363
let mut channel = Channel {
73447364
context: self.context,
7365+
#[cfg(dual_funding)]
7366+
dual_funding_channel_context: None,
73457367
};
73467368
let need_channel_ready = channel.check_get_channel_ready(0).is_some();
73477369
channel.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
@@ -7350,6 +7372,159 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
73507372
}
73517373
}
73527374

7375+
// A not-yet-funded inbound (from counterparty) channel using V2 channel establishment.
7376+
#[cfg(dual_funding)]
7377+
pub(super) struct InboundV2Channel<SP: Deref> where SP::Target: SignerProvider {
7378+
pub context: ChannelContext<SP>,
7379+
pub unfunded_context: UnfundedChannelContext,
7380+
pub dual_funding_context: DualFundingChannelContext,
7381+
}
7382+
7383+
#[cfg(dual_funding)]
7384+
impl<SP: Deref> InboundV2Channel<SP> where SP::Target: SignerProvider {
7385+
/// Creates a new dual-funded channel from a remote side's request for one.
7386+
/// Assumes chain_hash has already been checked and corresponds with what we expect!
7387+
pub fn new<ES: Deref, F: Deref, L: Deref>(
7388+
fee_estimator: &LowerBoundedFeeEstimator<F>, entropy_source: &ES, signer_provider: &SP,
7389+
counterparty_node_id: PublicKey, our_supported_features: &ChannelTypeFeatures,
7390+
their_features: &InitFeatures, msg: &msgs::OpenChannelV2, funding_satoshis: u64, user_id: u128,
7391+
config: &UserConfig, current_chain_height: u32, logger: &L,
7392+
) -> Result<InboundV2Channel<SP>, ChannelError>
7393+
where ES::Target: EntropySource,
7394+
F::Target: FeeEstimator,
7395+
L::Target: Logger,
7396+
{
7397+
// TODO(dual_funding): Fix this
7398+
let channel_value_satoshis = funding_satoshis * 1000 + msg.funding_satoshis;
7399+
let counterparty_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
7400+
channel_value_satoshis, msg.dust_limit_satoshis);
7401+
let holder_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
7402+
channel_value_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS);
7403+
7404+
let counterparty_pubkeys = ChannelPublicKeys {
7405+
funding_pubkey: msg.funding_pubkey,
7406+
revocation_basepoint: RevocationBasepoint(msg.revocation_basepoint),
7407+
payment_point: msg.payment_basepoint,
7408+
delayed_payment_basepoint: DelayedPaymentBasepoint(msg.delayed_payment_basepoint),
7409+
htlc_basepoint: HtlcBasepoint(msg.htlc_basepoint)
7410+
};
7411+
7412+
let mut context = ChannelContext::new_for_inbound_channel(
7413+
fee_estimator,
7414+
entropy_source,
7415+
signer_provider,
7416+
counterparty_node_id,
7417+
our_supported_features,
7418+
their_features,
7419+
user_id,
7420+
config,
7421+
current_chain_height,
7422+
logger,
7423+
false,
7424+
7425+
funding_satoshis,
7426+
7427+
counterparty_pubkeys,
7428+
msg.channel_flags,
7429+
msg.channel_type.clone(),
7430+
msg.funding_satoshis,
7431+
msg.to_self_delay,
7432+
holder_selected_channel_reserve_satoshis,
7433+
counterparty_selected_channel_reserve_satoshis,
7434+
0 /* push_msat not used in dual-funding */,
7435+
msg.dust_limit_satoshis,
7436+
msg.htlc_minimum_msat,
7437+
msg.commitment_feerate_sat_per_1000_weight,
7438+
msg.max_accepted_htlcs,
7439+
msg.shutdown_scriptpubkey.clone(),
7440+
msg.max_htlc_value_in_flight_msat,
7441+
msg.temporary_channel_id,
7442+
msg.first_per_commitment_point,
7443+
)?;
7444+
let channel_id = ChannelId::v2_from_revocation_basepoints(
7445+
&context.get_holder_pubkeys().revocation_basepoint,
7446+
&context.get_counterparty_pubkeys().revocation_basepoint);
7447+
context.channel_id = channel_id;
7448+
7449+
let chan = Self {
7450+
context,
7451+
unfunded_context: UnfundedChannelContext { unfunded_channel_age_ticks: 0 },
7452+
dual_funding_context: DualFundingChannelContext {
7453+
our_funding_satoshis: funding_satoshis,
7454+
their_funding_satoshis: msg.funding_satoshis,
7455+
funding_tx_locktime: msg.locktime,
7456+
funding_feerate_sat_per_1000_weight: msg.funding_feerate_sat_per_1000_weight,
7457+
}
7458+
};
7459+
7460+
Ok(chan)
7461+
}
7462+
7463+
/// Marks an inbound channel as accepted and generates a [`msgs::AcceptChannelV2`] message which
7464+
/// should be sent back to the counterparty node.
7465+
///
7466+
/// [`msgs::AcceptChannelV2`]: crate::ln::msgs::AcceptChannelV2
7467+
pub fn accept_inbound_dual_funded_channel(&mut self) -> msgs::AcceptChannelV2 {
7468+
if self.context.is_outbound() {
7469+
panic!("Tried to send accept_channel2 for an outbound channel?");
7470+
}
7471+
if self.context.channel_state != (ChannelState::OurInitSent as u32) | (ChannelState::TheirInitSent as u32) {
7472+
panic!("Tried to send accept_channel2 after channel had moved forward");
7473+
}
7474+
if self.context.cur_holder_commitment_transaction_number != INITIAL_COMMITMENT_NUMBER {
7475+
panic!("Tried to send an accept_channel2 for a channel that has already advanced");
7476+
}
7477+
7478+
self.generate_accept_channel_v2_message()
7479+
}
7480+
7481+
/// This function is used to explicitly generate a [`msgs::AcceptChannel`] message for an
7482+
/// inbound channel. If the intention is to accept an inbound channel, use
7483+
/// [`InboundV1Channel::accept_inbound_channel`] instead.
7484+
///
7485+
/// [`msgs::AcceptChannelV2`]: crate::ln::msgs::AcceptChannelV2
7486+
fn generate_accept_channel_v2_message(&self) -> msgs::AcceptChannelV2 {
7487+
let first_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(
7488+
self.context.cur_holder_commitment_transaction_number, &self.context.secp_ctx);
7489+
let second_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point(
7490+
self.context.cur_holder_commitment_transaction_number - 1, &self.context.secp_ctx);
7491+
let keys = self.context.get_holder_pubkeys();
7492+
7493+
msgs::AcceptChannelV2 {
7494+
temporary_channel_id: self.context.temporary_channel_id.unwrap(),
7495+
funding_satoshis: self.dual_funding_context.our_funding_satoshis,
7496+
dust_limit_satoshis: self.context.holder_dust_limit_satoshis,
7497+
max_htlc_value_in_flight_msat: self.context.holder_max_htlc_value_in_flight_msat,
7498+
htlc_minimum_msat: self.context.holder_htlc_minimum_msat,
7499+
minimum_depth: self.context.minimum_depth.unwrap(),
7500+
to_self_delay: self.context.get_holder_selected_contest_delay(),
7501+
max_accepted_htlcs: self.context.holder_max_accepted_htlcs,
7502+
funding_pubkey: keys.funding_pubkey,
7503+
revocation_basepoint: keys.revocation_basepoint.to_public_key(),
7504+
payment_basepoint: keys.payment_point,
7505+
delayed_payment_basepoint: keys.delayed_payment_basepoint.to_public_key(),
7506+
htlc_basepoint: keys.htlc_basepoint.to_public_key(),
7507+
first_per_commitment_point,
7508+
second_per_commitment_point,
7509+
shutdown_scriptpubkey: Some(match &self.context.shutdown_scriptpubkey {
7510+
Some(script) => script.clone().into_inner(),
7511+
None => Builder::new().into_script(),
7512+
}),
7513+
channel_type: Some(self.context.channel_type.clone()),
7514+
require_confirmed_inputs: None,
7515+
}
7516+
}
7517+
7518+
/// Enables the possibility for tests to extract a [`msgs::AcceptChannelV2`] message for an
7519+
/// inbound channel without accepting it.
7520+
///
7521+
/// [`msgs::AcceptChannelV2`]: crate::ln::msgs::AcceptChannelV2
7522+
#[cfg(test)]
7523+
pub fn get_accept_channel_v2_message(&self) -> msgs::AcceptChannelV2 {
7524+
self.generate_accept_channel_v2_message()
7525+
}
7526+
}
7527+
73537528
const SERIALIZATION_VERSION: u8 = 3;
73547529
const MIN_SERIALIZATION_VERSION: u8 = 3;
73557530

@@ -8251,7 +8426,9 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
82518426
channel_keys_id,
82528427

82538428
blocked_monitor_updates: blocked_monitor_updates.unwrap(),
8254-
}
8429+
},
8430+
#[cfg(dual_funding)]
8431+
dual_funding_channel_context: None,
82558432
})
82568433
}
82578434
}
@@ -8812,7 +8989,11 @@ mod tests {
88128989
let config = UserConfig::default();
88138990
let features = channelmanager::provided_init_features(&config);
88148991
let outbound_chan = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, node_b_node_id, &features, 10000000, 100000, 42, &config, 0, 42, None).unwrap();
8815-
let mut chan = Channel { context: outbound_chan.context };
8992+
let mut chan = Channel {
8993+
context: outbound_chan.context,
8994+
#[cfg(dual_funding)]
8995+
dual_funding_channel_context: None,
8996+
};
88168997

88178998
let dummy_htlc_source = HTLCSource::OutboundRoute {
88188999
path: Path {

0 commit comments

Comments
 (0)