@@ -2239,19 +2239,26 @@ impl FundingScope {
2239
2239
self.short_channel_id
2240
2240
}
2241
2241
2242
- /// Construct FundingScope for a splicing channel
2242
+ /// Constructs a ` FundingScope` for splicing a channel.
2243
2243
#[cfg(splicing)]
2244
- pub fn for_splice<SP: Deref>(
2244
+ fn for_splice<SP: Deref>(
2245
2245
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,
2247
2247
) -> Result<Self, ChannelError>
2248
2248
where
2249
2249
SP::Target: SignerProvider,
2250
2250
{
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();
2255
2262
2256
2263
// Rotate the pubkeys using the prev_funding_txid as a tweak
2257
2264
let prev_funding_txid = prev_funding.get_funding_txid();
@@ -2283,6 +2290,7 @@ impl FundingScope {
2283
2290
));
2284
2291
let holder_selected_channel_reserve_satoshis =
2285
2292
get_v2_channel_reserve_satoshis(post_channel_value, MIN_CHAN_DUST_LIMIT_SATOSHIS);
2293
+
2286
2294
Ok(Self {
2287
2295
channel_transaction_parameters: post_channel_transaction_parameters,
2288
2296
value_to_self_msat: post_value_to_self_msat,
@@ -2310,6 +2318,17 @@ impl FundingScope {
2310
2318
})
2311
2319
}
2312
2320
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
+
2313
2332
/// Returns a `SharedOwnedInput` for using this `FundingScope` as the input to a new splice.
2314
2333
#[cfg(splicing)]
2315
2334
fn to_splice_funding_input(&self) -> SharedOwnedInput {
@@ -2332,6 +2351,30 @@ impl FundingScope {
2332
2351
}
2333
2352
}
2334
2353
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
+
2335
2378
/// Info about a pending splice
2336
2379
#[cfg(splicing)]
2337
2380
struct PendingSplice {
@@ -2420,28 +2463,6 @@ impl<'a> From<&'a Transaction> for ConfirmedTransaction<'a> {
2420
2463
}
2421
2464
}
2422
2465
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
-
2445
2466
/// Contains everything about the channel including state, and various flags.
2446
2467
pub(super) struct ChannelContext<SP: Deref>
2447
2468
where
@@ -10399,39 +10420,26 @@ where
10399
10420
received_funding_txid: None,
10400
10421
});
10401
10422
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 {
10415
10423
// Rotate the pubkeys using the prev_funding_txid as a tweak
10416
10424
let prev_funding_txid = self.funding.get_funding_txid();
10417
10425
let funding_pubkey = self.context.holder_pubkeys(prev_funding_txid).funding_pubkey;
10418
10426
10419
- msgs::SpliceInit {
10427
+ Ok( msgs::SpliceInit {
10420
10428
channel_id: self.context.channel_id,
10421
10429
funding_contribution_satoshis: our_funding_contribution_satoshis,
10422
10430
funding_feerate_per_kw,
10423
10431
locktime,
10424
10432
funding_pubkey,
10425
10433
require_confirmed_inputs: None,
10426
- }
10434
+ })
10427
10435
}
10428
10436
10429
10437
/// Checks during handling splice_init
10430
10438
#[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> {
10432
10442
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;
10435
10443
10436
10444
// TODO(splicing): Add check that we are the quiescence acceptor
10437
10445
@@ -10462,25 +10470,23 @@ where
10462
10470
)));
10463
10471
}
10464
10472
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
+
10465
10481
// TODO(splicing): Once splice acceptor can contribute, check that inputs are sufficient,
10466
10482
// similarly to the check in `splice_channel`.
10467
10483
10468
10484
// Note on channel reserve requirement pre-check: as the splice acceptor does not contribute,
10469
10485
// it can't go below reserve, therefore no pre-check is done here.
10470
10486
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
10482
10488
10483
- Ok(() )
10489
+ Ok(splice_funding )
10484
10490
}
10485
10491
10486
10492
/// See also [`validate_splice_init`]
@@ -10493,27 +10499,17 @@ where
10493
10499
ES::Target: EntropySource,
10494
10500
L::Target: Logger,
10495
10501
{
10496
- let _res = self.validate_splice_init(msg)?;
10502
+ let splice_funding = self.validate_splice_init(msg, our_funding_contribution_satoshis )?;
10497
10503
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(),
10505
10510
);
10506
10511
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;
10517
10513
let funding_negotiation_context = FundingNegotiationContext {
10518
10514
is_initiator: false,
10519
10515
our_funding_contribution_satoshis,
@@ -10523,11 +10519,7 @@ where
10523
10519
our_funding_inputs: Vec::new(),
10524
10520
};
10525
10521
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();
10531
10523
let mut interactive_tx_constructor = funding_negotiation_context
10532
10524
.into_interactive_tx_constructor(
10533
10525
&self.context,
@@ -10611,36 +10603,26 @@ where
10611
10603
funding_negotiation_context.our_funding_contribution_satoshis;
10612
10604
let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
10613
10605
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
-
10630
10606
let splice_funding = FundingScope::for_splice(
10631
10607
&self.funding,
10632
10608
&self.context,
10633
10609
our_funding_contribution_satoshis,
10634
- post_channel_value ,
10610
+ their_funding_contribution_satoshis ,
10635
10611
msg.funding_pubkey,
10636
10612
)?;
10637
10613
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)
10639
10616
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
+ );
10642
10624
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();
10644
10626
let mut interactive_tx_constructor = funding_negotiation_context
10645
10627
.into_interactive_tx_constructor(
10646
10628
&self.context,
@@ -13654,6 +13636,7 @@ mod tests {
13654
13636
use crate::chain::BestBlock;
13655
13637
use crate::ln::chan_utils::{
13656
13638
self, commit_tx_fee_sat, htlc_success_tx_weight, htlc_timeout_tx_weight,
13639
+ ChannelTransactionParameters,
13657
13640
};
13658
13641
use crate::ln::channel::{
13659
13642
AwaitingChannelReadyFlags, ChannelState, FundedChannel, HTLCCandidate, HTLCInitiator,
@@ -13673,6 +13656,7 @@ mod tests {
13673
13656
use crate::prelude::*;
13674
13657
use crate::routing::router::{Path, RouteHop};
13675
13658
use crate::sign::{ChannelSigner, EntropySource, InMemorySigner, SignerProvider};
13659
+ use crate::sync::Mutex;
13676
13660
#[cfg(ldk_test_vectors)]
13677
13661
use crate::types::features::ChannelTypeFeatures;
13678
13662
use crate::types::features::{ChannelFeatures, NodeFeatures};
@@ -15464,19 +15448,40 @@ mod tests {
15464
15448
fn get_pre_and_post(
15465
15449
pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64,
15466
15450
) -> (u64, u64) {
15467
- use crate::ln::channel::PendingSplice ;
15451
+ use crate::ln::channel::FundingScope ;
15468
15452
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);
15474
15479
(pre_channel_value, post_channel_value)
15475
15480
}
15476
15481
15477
15482
#[cfg(splicing)]
15478
15483
#[test]
15479
- fn test_splice_compute_post_value () {
15484
+ fn test_compute_post_splice_value () {
15480
15485
{
15481
15486
// increase, small amounts
15482
15487
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 6_000, 0);
0 commit comments