@@ -2239,19 +2239,26 @@ impl FundingScope {
22392239 self.short_channel_id
22402240 }
22412241
2242- /// Construct FundingScope for a splicing channel
2242+ /// Constructs a ` FundingScope` for splicing a channel.
22432243 #[cfg(splicing)]
2244- pub fn for_splice<SP: Deref>(
2244+ fn for_splice<SP: Deref>(
22452245 prev_funding: &Self, context: &ChannelContext<SP>, our_funding_contribution_sats: i64,
2246- post_channel_value: u64 , counterparty_funding_pubkey: PublicKey,
2246+ their_funding_contribution_sats: i64 , counterparty_funding_pubkey: PublicKey,
22472247 ) -> Result<Self, ChannelError>
22482248 where
22492249 SP::Target: SignerProvider,
22502250 {
2251- let post_value_to_self_msat_signed = (prev_funding.value_to_self_msat as i64)
2252- .saturating_add(our_funding_contribution_sats * 1000);
2253- debug_assert!(post_value_to_self_msat_signed >= 0);
2254- let post_value_to_self_msat = post_value_to_self_msat_signed as u64;
2251+ let post_channel_value = prev_funding.compute_post_splice_value(
2252+ our_funding_contribution_sats,
2253+ their_funding_contribution_sats,
2254+ );
2255+
2256+ let post_value_to_self_msat = AddSigned::checked_add_signed(
2257+ prev_funding.value_to_self_msat,
2258+ our_funding_contribution_sats * 1000,
2259+ );
2260+ debug_assert!(post_value_to_self_msat.is_some());
2261+ let post_value_to_self_msat = post_value_to_self_msat.unwrap();
22552262
22562263 // Rotate the pubkeys using the prev_funding_txid as a tweak
22572264 let prev_funding_txid = prev_funding.get_funding_txid();
@@ -2283,6 +2290,7 @@ impl FundingScope {
22832290 ));
22842291 let holder_selected_channel_reserve_satoshis =
22852292 get_v2_channel_reserve_satoshis(post_channel_value, MIN_CHAN_DUST_LIMIT_SATOSHIS);
2293+
22862294 Ok(Self {
22872295 channel_transaction_parameters: post_channel_transaction_parameters,
22882296 value_to_self_msat: post_value_to_self_msat,
@@ -2310,6 +2318,17 @@ impl FundingScope {
23102318 })
23112319 }
23122320
2321+ /// Compute the post-splice channel value from each counterparty's contributions.
2322+ #[cfg(splicing)]
2323+ pub(super) fn compute_post_splice_value(
2324+ &self, our_funding_contribution: i64, their_funding_contribution: i64,
2325+ ) -> u64 {
2326+ AddSigned::saturating_add_signed(
2327+ self.get_value_satoshis(),
2328+ our_funding_contribution.saturating_add(their_funding_contribution),
2329+ )
2330+ }
2331+
23132332 /// Returns a `SharedOwnedInput` for using this `FundingScope` as the input to a new splice.
23142333 #[cfg(splicing)]
23152334 fn to_splice_funding_input(&self) -> SharedOwnedInput {
@@ -2332,6 +2351,30 @@ impl FundingScope {
23322351 }
23332352}
23342353
2354+ // TODO: Remove once MSRV is at least 1.66
2355+ trait AddSigned {
2356+ fn checked_add_signed(self, rhs: i64) -> Option<u64>;
2357+ fn saturating_add_signed(self, rhs: i64) -> u64;
2358+ }
2359+
2360+ impl AddSigned for u64 {
2361+ fn checked_add_signed(self, rhs: i64) -> Option<u64> {
2362+ if rhs >= 0 {
2363+ self.checked_add(rhs as u64)
2364+ } else {
2365+ self.checked_sub(rhs.abs() as u64)
2366+ }
2367+ }
2368+
2369+ fn saturating_add_signed(self, rhs: i64) -> u64 {
2370+ if rhs >= 0 {
2371+ self.saturating_add(rhs as u64)
2372+ } else {
2373+ self.saturating_sub(rhs.abs() as u64)
2374+ }
2375+ }
2376+ }
2377+
23352378/// Info about a pending splice
23362379#[cfg(splicing)]
23372380struct PendingSplice {
@@ -2420,28 +2463,6 @@ impl<'a> From<&'a Transaction> for ConfirmedTransaction<'a> {
24202463 }
24212464}
24222465
2423- #[cfg(splicing)]
2424- impl PendingSplice {
2425- #[inline]
2426- fn add_checked(base: u64, delta: i64) -> u64 {
2427- if delta >= 0 {
2428- base.saturating_add(delta as u64)
2429- } else {
2430- base.saturating_sub(delta.abs() as u64)
2431- }
2432- }
2433-
2434- /// Compute the post-splice channel value from the pre-splice values and the peer contributions
2435- pub fn compute_post_value(
2436- pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64,
2437- ) -> u64 {
2438- Self::add_checked(
2439- pre_channel_value,
2440- our_funding_contribution.saturating_add(their_funding_contribution),
2441- )
2442- }
2443- }
2444-
24452466/// Contains everything about the channel including state, and various flags.
24462467pub(super) struct ChannelContext<SP: Deref>
24472468where
@@ -10399,39 +10420,26 @@ where
1039910420 received_funding_txid: None,
1040010421 });
1040110422
10402- let msg = self.get_splice_init(
10403- our_funding_contribution_satoshis,
10404- funding_feerate_per_kw,
10405- locktime,
10406- );
10407- Ok(msg)
10408- }
10409-
10410- /// Get the splice message that can be sent during splice initiation.
10411- #[cfg(splicing)]
10412- fn get_splice_init(
10413- &self, our_funding_contribution_satoshis: i64, funding_feerate_per_kw: u32, locktime: u32,
10414- ) -> msgs::SpliceInit {
1041510423 // Rotate the pubkeys using the prev_funding_txid as a tweak
1041610424 let prev_funding_txid = self.funding.get_funding_txid();
1041710425 let funding_pubkey = self.context.holder_pubkeys(prev_funding_txid).funding_pubkey;
1041810426
10419- msgs::SpliceInit {
10427+ Ok( msgs::SpliceInit {
1042010428 channel_id: self.context.channel_id,
1042110429 funding_contribution_satoshis: our_funding_contribution_satoshis,
1042210430 funding_feerate_per_kw,
1042310431 locktime,
1042410432 funding_pubkey,
1042510433 require_confirmed_inputs: None,
10426- }
10434+ })
1042710435 }
1042810436
1042910437 /// Checks during handling splice_init
1043010438 #[cfg(splicing)]
10431- pub fn validate_splice_init(&self, msg: &msgs::SpliceInit) -> Result<(), ChannelError> {
10439+ pub fn validate_splice_init(
10440+ &self, msg: &msgs::SpliceInit, our_funding_contribution_satoshis: i64,
10441+ ) -> Result<FundingScope, ChannelError> {
1043210442 let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
10433- // TODO(splicing): Currently not possible to contribute on the splicing-acceptor side
10434- let our_funding_contribution_satoshis = 0i64;
1043510443
1043610444 // TODO(splicing): Add check that we are the quiescence acceptor
1043710445
@@ -10462,25 +10470,23 @@ where
1046210470 )));
1046310471 }
1046410472
10473+ let splice_funding = FundingScope::for_splice(
10474+ &self.funding,
10475+ &self.context,
10476+ our_funding_contribution_satoshis,
10477+ their_funding_contribution_satoshis,
10478+ msg.funding_pubkey,
10479+ )?;
10480+
1046510481 // TODO(splicing): Once splice acceptor can contribute, check that inputs are sufficient,
1046610482 // similarly to the check in `splice_channel`.
1046710483
1046810484 // Note on channel reserve requirement pre-check: as the splice acceptor does not contribute,
1046910485 // it can't go below reserve, therefore no pre-check is done here.
1047010486
10471- let pre_channel_value = self.funding.value_to_self_msat;
10472- let _post_channel_value = PendingSplice::compute_post_value(
10473- pre_channel_value,
10474- their_funding_contribution_satoshis,
10475- our_funding_contribution_satoshis,
10476- );
10477- let _post_balance = PendingSplice::add_checked(
10478- self.funding.value_to_self_msat,
10479- our_funding_contribution_satoshis,
10480- );
10481- // TODO: Early check for reserve requirement
10487+ // TODO(splicing): Early check for reserve requirement
1048210488
10483- Ok(() )
10489+ Ok(splice_funding )
1048410490 }
1048510491
1048610492 /// See also [`validate_splice_init`]
@@ -10493,27 +10499,17 @@ where
1049310499 ES::Target: EntropySource,
1049410500 L::Target: Logger,
1049510501 {
10496- let _res = self.validate_splice_init(msg)?;
10502+ let splice_funding = self.validate_splice_init(msg, our_funding_contribution_satoshis )?;
1049710503
10498- let pre_channel_value = self.funding.get_value_satoshis();
10499- let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
10500-
10501- let post_channel_value = PendingSplice::compute_post_value(
10502- pre_channel_value,
10503- our_funding_contribution_satoshis,
10504- their_funding_contribution_satoshis,
10504+ log_info!(
10505+ logger,
10506+ "Starting splice funding negotiation for channel {} after receiving splice_init; new channel value: {} sats (old: {} sats)",
10507+ self.context.channel_id,
10508+ splice_funding.get_value_satoshis(),
10509+ self.funding.get_value_satoshis(),
1050510510 );
1050610511
10507- let splice_funding = FundingScope::for_splice(
10508- &self.funding,
10509- &self.context,
10510- our_funding_contribution_satoshis,
10511- post_channel_value,
10512- msg.funding_pubkey,
10513- )?;
10514-
10515- let prev_funding_input = self.funding.to_splice_funding_input();
10516-
10512+ let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
1051710513 let funding_negotiation_context = FundingNegotiationContext {
1051810514 is_initiator: false,
1051910515 our_funding_contribution_satoshis,
@@ -10523,11 +10519,7 @@ where
1052310519 our_funding_inputs: Vec::new(),
1052410520 };
1052510521
10526- log_info!(logger, "Splicing process started after splice_init, new channel value {}, old {}, outgoing {}, channel_id {}",
10527- post_channel_value, pre_channel_value, false, self.context.channel_id);
10528-
10529- let splice_ack_msg = self.get_splice_ack(our_funding_contribution_satoshis);
10530-
10522+ let prev_funding_input = self.funding.to_splice_funding_input();
1053110523 let mut interactive_tx_constructor = funding_negotiation_context
1053210524 .into_interactive_tx_constructor(
1053310525 &self.context,
@@ -10611,36 +10603,26 @@ where
1061110603 funding_negotiation_context.our_funding_contribution_satoshis;
1061210604 let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
1061310605
10614- // TODO(splicing): Pre-check for reserve requirement
10615- // (Note: It should also be checked later at tx_complete)
10616- let pre_channel_value = self.funding.get_value_satoshis();
10617- let post_channel_value = PendingSplice::compute_post_value(
10618- pre_channel_value,
10619- our_funding_contribution_satoshis,
10620- their_funding_contribution_satoshis,
10621- );
10622- let _post_balance = PendingSplice::add_checked(
10623- self.funding.value_to_self_msat,
10624- our_funding_contribution_satoshis,
10625- );
10626-
10627- // TODO(splicing): Pre-check for reserve requirement
10628- // (Note: It should also be checked later at tx_complete)
10629-
1063010606 let splice_funding = FundingScope::for_splice(
1063110607 &self.funding,
1063210608 &self.context,
1063310609 our_funding_contribution_satoshis,
10634- post_channel_value ,
10610+ their_funding_contribution_satoshis ,
1063510611 msg.funding_pubkey,
1063610612 )?;
1063710613
10638- let prev_funding_input = self.funding.to_splice_funding_input();
10614+ // TODO(splicing): Pre-check for reserve requirement
10615+ // (Note: It should also be checked later at tx_complete)
1063910616
10640- log_info!(logger, "Splicing process started after splice_ack, new channel value {}, old {}, outgoing {}, channel_id {}",
10641- post_channel_value, pre_channel_value, true, self.context.channel_id);
10617+ log_info!(
10618+ logger,
10619+ "Starting splice funding negotiation for channel {} after receiving splice_ack; new channel value: {} sats (old: {} sats)",
10620+ self.context.channel_id,
10621+ splice_funding.get_value_satoshis(),
10622+ self.funding.get_value_satoshis(),
10623+ );
1064210624
10643- // Start interactive funding negotiation, with the previous funding transaction as an extra shared input
10625+ let prev_funding_input = self. funding.to_splice_funding_input();
1064410626 let mut interactive_tx_constructor = funding_negotiation_context
1064510627 .into_interactive_tx_constructor(
1064610628 &self.context,
@@ -13654,6 +13636,7 @@ mod tests {
1365413636 use crate::chain::BestBlock;
1365513637 use crate::ln::chan_utils::{
1365613638 self, commit_tx_fee_sat, htlc_success_tx_weight, htlc_timeout_tx_weight,
13639+ ChannelTransactionParameters,
1365713640 };
1365813641 use crate::ln::channel::{
1365913642 AwaitingChannelReadyFlags, ChannelState, FundedChannel, HTLCCandidate, HTLCInitiator,
@@ -13673,6 +13656,7 @@ mod tests {
1367313656 use crate::prelude::*;
1367413657 use crate::routing::router::{Path, RouteHop};
1367513658 use crate::sign::{ChannelSigner, EntropySource, InMemorySigner, SignerProvider};
13659+ use crate::sync::Mutex;
1367613660 #[cfg(ldk_test_vectors)]
1367713661 use crate::types::features::ChannelTypeFeatures;
1367813662 use crate::types::features::{ChannelFeatures, NodeFeatures};
@@ -15464,19 +15448,40 @@ mod tests {
1546415448 fn get_pre_and_post(
1546515449 pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64,
1546615450 ) -> (u64, u64) {
15467- use crate::ln::channel::PendingSplice ;
15451+ use crate::ln::channel::FundingScope ;
1546815452
15469- let post_channel_value = PendingSplice::compute_post_value(
15470- pre_channel_value,
15471- our_funding_contribution,
15472- their_funding_contribution,
15473- );
15453+ let funding = FundingScope {
15454+ value_to_self_msat: 0,
15455+ counterparty_selected_channel_reserve_satoshis: None,
15456+ holder_selected_channel_reserve_satoshis: 0,
15457+
15458+ #[cfg(debug_assertions)]
15459+ holder_max_commitment_tx_output: Mutex::new((0, 0)),
15460+ #[cfg(debug_assertions)]
15461+ counterparty_max_commitment_tx_output: Mutex::new((0, 0)),
15462+
15463+ #[cfg(any(test, fuzzing))]
15464+ next_local_commitment_tx_fee_info_cached: Mutex::new(None),
15465+ #[cfg(any(test, fuzzing))]
15466+ next_remote_commitment_tx_fee_info_cached: Mutex::new(None),
15467+
15468+ channel_transaction_parameters: ChannelTransactionParameters::test_dummy(
15469+ pre_channel_value,
15470+ ),
15471+ funding_transaction: None,
15472+ funding_tx_confirmed_in: None,
15473+ funding_tx_confirmation_height: 0,
15474+ short_channel_id: None,
15475+ minimum_depth_override: None,
15476+ };
15477+ let post_channel_value =
15478+ funding.compute_post_splice_value(our_funding_contribution, their_funding_contribution);
1547415479 (pre_channel_value, post_channel_value)
1547515480 }
1547615481
1547715482 #[cfg(splicing)]
1547815483 #[test]
15479- fn test_splice_compute_post_value () {
15484+ fn test_compute_post_splice_value () {
1548015485 {
1548115486 // increase, small amounts
1548215487 let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 6_000, 0);
0 commit comments