@@ -2477,6 +2477,28 @@ impl<'a> From<&'a Transaction> for ConfirmedTransaction<'a> {
2477
2477
}
2478
2478
}
2479
2479
2480
+ #[cfg(splicing)]
2481
+ impl PendingSplice {
2482
+ #[inline]
2483
+ fn add_checked(base: u64, delta: i64) -> u64 {
2484
+ if delta >= 0 {
2485
+ base.saturating_add(delta as u64)
2486
+ } else {
2487
+ base.saturating_sub(delta.abs() as u64)
2488
+ }
2489
+ }
2490
+
2491
+ // /// Compute the post-splice channel value from the pre-splice values and the peer contributions
2492
+ // pub fn compute_post_splice_value(
2493
+ // pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64,
2494
+ // ) -> u64 {
2495
+ // Self::add_checked(
2496
+ // pre_channel_value,
2497
+ // our_funding_contribution.saturating_add(their_funding_contribution),
2498
+ // )
2499
+ // }
2500
+ }
2501
+
2480
2502
/// Contains everything about the channel including state, and various flags.
2481
2503
pub(super) struct ChannelContext<SP: Deref>
2482
2504
where
@@ -5056,6 +5078,71 @@ where
5056
5078
}
5057
5079
}
5058
5080
5081
+ /// Check that post-splicing balance meets reserve requirements, but only if it met it pre-splice as well
5082
+ #[cfg(splicing)]
5083
+ pub fn check_splice_balance_meets_v2_reserve_requirement_noerr(
5084
+ pre_balance: u64, post_balance: u64, pre_channel_value: u64, post_channel_value: u64,
5085
+ dust_limit: u64,
5086
+ ) -> Result<(), u64> {
5087
+ if post_balance == 0 {
5088
+ // 0 balance is fine
5089
+ return Ok(());
5090
+ }
5091
+ let post_channel_reserve = get_v2_channel_reserve_satoshis(post_channel_value, dust_limit);
5092
+ if post_balance >= post_channel_reserve {
5093
+ return Ok(());
5094
+ }
5095
+ // post is not OK, check pre
5096
+ if pre_balance == 0 {
5097
+ // pre OK, post not -> not
5098
+ return Err(post_channel_reserve);
5099
+ }
5100
+ let pre_channel_reserve = get_v2_channel_reserve_satoshis(pre_channel_value, dust_limit);
5101
+ if pre_balance >= pre_channel_reserve {
5102
+ // pre OK, post not -> not
5103
+ return Err(post_channel_reserve);
5104
+ }
5105
+ // post not OK, but so was pre -> OK
5106
+ Ok(())
5107
+ }
5108
+
5109
+ /// Check that balances meet the channel reserve requirements or violates them (below reserve).
5110
+ /// The channel value is an input as opposed to using from the FundingScope, so that this can be used in case of splicing
5111
+ /// to check with new channel value (before being committed to it).
5112
+ #[cfg(splicing)]
5113
+ pub fn check_splice_balances_meet_v2_reserve_requirements(
5114
+ &self, self_balance_pre: u64, self_balance_post: u64, counterparty_balance_pre: u64,
5115
+ counterparty_balance_post: u64, channel_value_pre: u64, channel_value_post: u64,
5116
+ ) -> Result<(), ChannelError> {
5117
+ let is_ok_self = Self::check_splice_balance_meets_v2_reserve_requirement_noerr(
5118
+ self_balance_pre,
5119
+ self_balance_post,
5120
+ channel_value_pre,
5121
+ channel_value_post,
5122
+ self.holder_dust_limit_satoshis,
5123
+ );
5124
+ if let Err(channel_reserve_self) = is_ok_self {
5125
+ return Err(ChannelError::Warn(format!(
5126
+ "Balance below reserve, mandated by holder, {} vs {}",
5127
+ self_balance_post, channel_reserve_self,
5128
+ )));
5129
+ }
5130
+ let is_ok_cp = Self::check_splice_balance_meets_v2_reserve_requirement_noerr(
5131
+ counterparty_balance_pre,
5132
+ counterparty_balance_post,
5133
+ channel_value_pre,
5134
+ channel_value_post,
5135
+ self.counterparty_dust_limit_satoshis,
5136
+ );
5137
+ if let Err(channel_reserve_cp) = is_ok_cp {
5138
+ return Err(ChannelError::Warn(format!(
5139
+ "Balance below reserve mandated by counterparty, {} vs {}",
5140
+ counterparty_balance_post, channel_reserve_cp,
5141
+ )));
5142
+ }
5143
+ Ok(())
5144
+ }
5145
+
5059
5146
/// Get the commitment tx fee for the local's (i.e. our) next commitment transaction based on the
5060
5147
/// number of pending HTLCs that are on track to be in our next commitment tx.
5061
5148
///
@@ -10882,8 +10969,28 @@ where
10882
10969
msg.funding_pubkey,
10883
10970
)?;
10884
10971
10885
- // TODO(splicing): Pre-check for reserve requirement
10972
+ // Pre-check for reserve requirement
10886
10973
// (Note: It should also be checked later at tx_complete)
10974
+ let pre_channel_value = self.funding.get_value_satoshis();
10975
+ let post_channel_value = self.funding.compute_post_splice_value(
10976
+ our_funding_contribution_satoshis,
10977
+ their_funding_contribution_satoshis,
10978
+ );
10979
+ let pre_balance_self = self.funding.value_to_self_msat;
10980
+ let post_balance_self =
10981
+ PendingSplice::add_checked(pre_balance_self, our_funding_contribution_satoshis);
10982
+ let pre_balance_counterparty = pre_channel_value.saturating_sub(pre_balance_self);
10983
+ let post_balance_counterparty = post_channel_value.saturating_sub(post_balance_self);
10984
+ // Pre-check for reserve requirement
10985
+ // This will also be checked later at tx_complete
10986
+ let _res = self.context.check_splice_balances_meet_v2_reserve_requirements(
10987
+ pre_balance_self,
10988
+ post_balance_self,
10989
+ pre_balance_counterparty,
10990
+ post_balance_counterparty,
10991
+ pre_channel_value,
10992
+ post_channel_value,
10993
+ )?;
10887
10994
10888
10995
log_info!(
10889
10996
logger,
0 commit comments