@@ -1519,7 +1519,7 @@ impl<SP: Deref> Channel<SP> where
1519
1519
holder_commitment_point,
1520
1520
is_v2_established: true,
1521
1521
#[cfg(splicing)]
1522
- pending_splice : None,
1522
+ pending_splice_pre : None,
1523
1523
};
1524
1524
let res = funded_channel.commitment_signed_initial_v2(msg, best_block, signer_provider, logger)
1525
1525
.map(|monitor| (Some(monitor), None))
@@ -1728,6 +1728,23 @@ struct PendingSplice {
1728
1728
pub our_funding_contribution: i64,
1729
1729
}
1730
1730
1731
+ #[cfg(splicing)]
1732
+ impl PendingSplice {
1733
+ #[inline]
1734
+ fn add_checked(base: u64, delta: i64) -> u64 {
1735
+ if delta >= 0 {
1736
+ base.saturating_add(delta as u64)
1737
+ } else {
1738
+ base.saturating_sub(delta.abs() as u64)
1739
+ }
1740
+ }
1741
+
1742
+ /// Compute the post-splice channel value from the pre-splice values and the peer contributions
1743
+ pub fn compute_post_value(pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64) -> u64 {
1744
+ Self::add_checked(pre_channel_value, our_funding_contribution.saturating_add(their_funding_contribution))
1745
+ }
1746
+ }
1747
+
1731
1748
/// Contains everything about the channel including state, and various flags.
1732
1749
pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
1733
1750
config: LegacyChannelConfig,
@@ -4256,6 +4273,33 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
4256
4273
}
4257
4274
}
4258
4275
4276
+ /// Check that a balance value meets the channel reserve requirements or violates them (below reserve).
4277
+ /// The channel value is an input as opposed to using from self, so that this can be used in case of splicing
4278
+ /// to checks with new channel value (before being comitted to it).
4279
+ #[cfg(splicing)]
4280
+ pub fn check_balance_meets_reserve_requirements(&self, balance: u64, channel_value: u64) -> Result<(), ChannelError> {
4281
+ if balance == 0 {
4282
+ return Ok(());
4283
+ }
4284
+ let holder_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
4285
+ channel_value, self.holder_dust_limit_satoshis);
4286
+ if balance < holder_selected_channel_reserve_satoshis {
4287
+ return Err(ChannelError::Warn(format!(
4288
+ "Balance below reserve mandated by holder, {} vs {}",
4289
+ balance, holder_selected_channel_reserve_satoshis,
4290
+ )));
4291
+ }
4292
+ let counterparty_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
4293
+ channel_value, self.counterparty_dust_limit_satoshis);
4294
+ if balance < counterparty_selected_channel_reserve_satoshis {
4295
+ return Err(ChannelError::Warn(format!(
4296
+ "Balance below reserve mandated by counterparty, {} vs {}",
4297
+ balance, counterparty_selected_channel_reserve_satoshis,
4298
+ )));
4299
+ }
4300
+ Ok(())
4301
+ }
4302
+
4259
4303
/// Get the commitment tx fee for the local's (i.e. our) next commitment transaction based on the
4260
4304
/// number of pending HTLCs that are on track to be in our next commitment tx.
4261
4305
///
@@ -4902,7 +4946,7 @@ pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
4902
4946
is_v2_established: bool,
4903
4947
/// Info about an in-progress, pending splice (if any), on the pre-splice channel
4904
4948
#[cfg(splicing)]
4905
- pending_splice : Option<PendingSplice>,
4949
+ pending_splice_pre : Option<PendingSplice>,
4906
4950
}
4907
4951
4908
4952
#[cfg(any(test, fuzzing))]
@@ -8435,7 +8479,7 @@ impl<SP: Deref> FundedChannel<SP> where
8435
8479
) -> Result<msgs::SpliceInit, APIError> {
8436
8480
// Check if a splice has been initiated already.
8437
8481
// Note: only a single outstanding splice is supported (per spec)
8438
- if let Some(splice_info) = &self.pending_splice {
8482
+ if let Some(splice_info) = &self.pending_splice_pre {
8439
8483
return Err(APIError::APIMisuseError { err: format!(
8440
8484
"Channel {} cannot be spliced, as it has already a splice pending (contribution {})",
8441
8485
self.context.channel_id(), splice_info.our_funding_contribution
@@ -8471,7 +8515,7 @@ impl<SP: Deref> FundedChannel<SP> where
8471
8515
self.context.channel_id(), err,
8472
8516
)})?;
8473
8517
8474
- self.pending_splice = Some(PendingSplice {
8518
+ self.pending_splice_pre = Some(PendingSplice {
8475
8519
our_funding_contribution: our_funding_contribution_satoshis,
8476
8520
});
8477
8521
@@ -8505,7 +8549,7 @@ impl<SP: Deref> FundedChannel<SP> where
8505
8549
let our_funding_contribution_satoshis = 0i64;
8506
8550
8507
8551
// Check if a splice has been initiated already.
8508
- if let Some(splice_info) = &self.pending_splice {
8552
+ if let Some(splice_info) = &self.pending_splice_pre {
8509
8553
return Err(ChannelError::Warn(format!(
8510
8554
"Channel has already a splice pending, contribution {}", splice_info.our_funding_contribution,
8511
8555
)));
@@ -8531,7 +8575,13 @@ impl<SP: Deref> FundedChannel<SP> where
8531
8575
8532
8576
// Note on channel reserve requirement pre-check: as the splice acceptor does not contribute,
8533
8577
// it can't go below reserve, therefore no pre-check is done here.
8534
- // TODO(splicing): Once splice acceptor can contribute, add reserve pre-check, similar to the one in `splice_ack`.
8578
+
8579
+ let pre_channel_value = self.funding.value_to_self_msat;
8580
+ let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, their_funding_contribution_satoshis, our_funding_contribution_satoshis);
8581
+ let post_balance = PendingSplice::add_checked(self.funding.value_to_self_msat, our_funding_contribution_satoshis);
8582
+ // Early check for reserve requirement, assuming maximum balance of full channel value
8583
+ // This will also be checked later at tx_complete
8584
+ let _res = self.context.check_balance_meets_reserve_requirements(post_balance, post_channel_value)?;
8535
8585
8536
8586
// TODO(splicing): Store msg.funding_pubkey
8537
8587
// TODO(splicing): Apply start of splice (splice_start)
@@ -8550,14 +8600,27 @@ impl<SP: Deref> FundedChannel<SP> where
8550
8600
8551
8601
/// Handle splice_ack
8552
8602
#[cfg(splicing)]
8553
- pub fn splice_ack(&mut self, _msg : &msgs::SpliceAck) -> Result<(), ChannelError> {
8603
+ pub fn splice_ack(&mut self, msg : &msgs::SpliceAck) -> Result<(), ChannelError> {
8554
8604
// check if splice is pending
8555
- if self.pending_splice.is_none() {
8605
+ let pending_splice = if let Some(pending_splice) = &self.pending_splice_pre {
8606
+ pending_splice
8607
+ } else {
8556
8608
return Err(ChannelError::Warn(format!("Channel is not in pending splice")));
8557
8609
};
8558
8610
8559
8611
// TODO(splicing): Pre-check for reserve requirement
8560
8612
// (Note: It should also be checked later at tx_complete)
8613
+
8614
+
8615
+ let our_funding_contribution = pending_splice.our_funding_contribution;
8616
+ let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
8617
+
8618
+ let pre_channel_value = self.funding.get_value_satoshis();
8619
+ let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution_satoshis);
8620
+ let post_balance = PendingSplice::add_checked(self.funding.value_to_self_msat, our_funding_contribution);
8621
+ // Early check for reserve requirement, assuming maximum balance of full channel value
8622
+ // This will also be checked later at tx_complete
8623
+ let _res = self.context.check_balance_meets_reserve_requirements(post_balance, post_channel_value)?;
8561
8624
Ok(())
8562
8625
}
8563
8626
@@ -9481,7 +9544,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
9481
9544
is_v2_established: false,
9482
9545
holder_commitment_point,
9483
9546
#[cfg(splicing)]
9484
- pending_splice : None,
9547
+ pending_splice_pre : None,
9485
9548
};
9486
9549
9487
9550
let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some()
@@ -9758,7 +9821,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
9758
9821
is_v2_established: false,
9759
9822
holder_commitment_point,
9760
9823
#[cfg(splicing)]
9761
- pending_splice : None,
9824
+ pending_splice_pre : None,
9762
9825
};
9763
9826
let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some()
9764
9827
|| channel.context.signer_pending_channel_ready;
@@ -11120,7 +11183,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
11120
11183
is_v2_established,
11121
11184
holder_commitment_point,
11122
11185
#[cfg(splicing)]
11123
- pending_splice : None,
11186
+ pending_splice_pre : None,
11124
11187
})
11125
11188
}
11126
11189
}
@@ -13050,4 +13113,69 @@ mod tests {
13050
13113
);
13051
13114
}
13052
13115
}
13116
+
13117
+ #[cfg(all(test, splicing))]
13118
+ fn get_pre_and_post(pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64) -> (u64, u64) {
13119
+ use crate::ln::channel::PendingSplice;
13120
+
13121
+ let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution);
13122
+ (pre_channel_value, post_channel_value)
13123
+ }
13124
+
13125
+ #[cfg(all(test, splicing))]
13126
+ #[test]
13127
+ fn test_splice_compute_post_value() {
13128
+ {
13129
+ // increase, small amounts
13130
+ let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 6_000, 0);
13131
+ assert_eq!(pre_channel_value, 9_000);
13132
+ assert_eq!(post_channel_value, 15_000);
13133
+ }
13134
+ {
13135
+ // increase, small amounts
13136
+ let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 4_000, 2_000);
13137
+ assert_eq!(pre_channel_value, 9_000);
13138
+ assert_eq!(post_channel_value, 15_000);
13139
+ }
13140
+ {
13141
+ // increase, small amounts
13142
+ let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 0, 6_000);
13143
+ assert_eq!(pre_channel_value, 9_000);
13144
+ assert_eq!(post_channel_value, 15_000);
13145
+ }
13146
+ {
13147
+ // decrease, small amounts
13148
+ let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -6_000, 0);
13149
+ assert_eq!(pre_channel_value, 15_000);
13150
+ assert_eq!(post_channel_value, 9_000);
13151
+ }
13152
+ {
13153
+ // decrease, small amounts
13154
+ let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -4_000, -2_000);
13155
+ assert_eq!(pre_channel_value, 15_000);
13156
+ assert_eq!(post_channel_value, 9_000);
13157
+ }
13158
+ {
13159
+ // increase and decrease
13160
+ let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, 4_000, -2_000);
13161
+ assert_eq!(pre_channel_value, 15_000);
13162
+ assert_eq!(post_channel_value, 17_000);
13163
+ }
13164
+ let base2: u64 = 2;
13165
+ let huge63i3 = (base2.pow(63) - 3) as i64;
13166
+ assert_eq!(huge63i3, 9223372036854775805);
13167
+ assert_eq!(-huge63i3, -9223372036854775805);
13168
+ {
13169
+ // increase, large amount
13170
+ let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, 3);
13171
+ assert_eq!(pre_channel_value, 9_000);
13172
+ assert_eq!(post_channel_value, 9223372036854784807);
13173
+ }
13174
+ {
13175
+ // increase, large amounts
13176
+ let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, huge63i3);
13177
+ assert_eq!(pre_channel_value, 9_000);
13178
+ assert_eq!(post_channel_value, 9223372036854784807);
13179
+ }
13180
+ }
13053
13181
}
0 commit comments