@@ -2860,6 +2860,20 @@ pub(crate) fn get_legacy_default_holder_selected_channel_reserve_satoshis(channe
2860
2860
cmp::min(channel_value_satoshis, cmp::max(q, 1000))
2861
2861
}
2862
2862
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
+
2863
2877
// Get the fee cost in SATS of a commitment tx with a given number of HTLC outputs.
2864
2878
// Note that num_htlcs should not include dust HTLCs.
2865
2879
#[inline]
@@ -2893,6 +2907,8 @@ pub(super) struct DualFundingChannelContext {
2893
2907
// Counterparty designates channel data owned by the another channel participant entity.
2894
2908
pub(super) struct Channel<SP: Deref> where SP::Target: SignerProvider {
2895
2909
pub context: ChannelContext<SP>,
2910
+ #[cfg(dual_funding)]
2911
+ pub dual_funding_channel_context: Option<DualFundingChannelContext>,
2896
2912
}
2897
2913
2898
2914
#[cfg(any(test, fuzzing))]
@@ -7085,7 +7101,11 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
7085
7101
7086
7102
log_info!(logger, "Received funding_signed from peer for channel {}", &self.context.channel_id());
7087
7103
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
+ };
7089
7109
7090
7110
let need_channel_ready = channel.check_get_channel_ready(0).is_some();
7091
7111
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 {
7342
7362
// `ChannelMonitor`.
7343
7363
let mut channel = Channel {
7344
7364
context: self.context,
7365
+ #[cfg(dual_funding)]
7366
+ dual_funding_channel_context: None,
7345
7367
};
7346
7368
let need_channel_ready = channel.check_get_channel_ready(0).is_some();
7347
7369
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 {
7350
7372
}
7351
7373
}
7352
7374
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
+
7353
7528
const SERIALIZATION_VERSION: u8 = 3;
7354
7529
const MIN_SERIALIZATION_VERSION: u8 = 3;
7355
7530
@@ -8251,7 +8426,9 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
8251
8426
channel_keys_id,
8252
8427
8253
8428
blocked_monitor_updates: blocked_monitor_updates.unwrap(),
8254
- }
8429
+ },
8430
+ #[cfg(dual_funding)]
8431
+ dual_funding_channel_context: None,
8255
8432
})
8256
8433
}
8257
8434
}
@@ -8812,7 +8989,11 @@ mod tests {
8812
8989
let config = UserConfig::default();
8813
8990
let features = channelmanager::provided_init_features(&config);
8814
8991
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
+ };
8816
8997
8817
8998
let dummy_htlc_source = HTLCSource::OutboundRoute {
8818
8999
path: Path {
0 commit comments