Skip to content

Commit 2cb9ea8

Browse files
committed
New splice_channel() for initiating splicing, handle splice_init and splice_ack messages, but fail afterwards
1 parent d9c20be commit 2cb9ea8

File tree

1 file changed

+139
-11
lines changed

1 file changed

+139
-11
lines changed

lightning/src/ln/channel.rs

+139-11
Original file line numberDiff line numberDiff line change
@@ -1522,7 +1522,7 @@ impl<SP: Deref> Channel<SP> where
15221522
holder_commitment_point,
15231523
is_v2_established: true,
15241524
#[cfg(splicing)]
1525-
pending_splice: None,
1525+
pending_splice_pre: None,
15261526
};
15271527
let res = funded_channel.commitment_signed_initial_v2(msg, best_block, signer_provider, logger)
15281528
.map(|monitor| (Some(monitor), None))
@@ -1736,6 +1736,23 @@ struct PendingSplice {
17361736
pub our_funding_contribution: i64,
17371737
}
17381738

1739+
#[cfg(splicing)]
1740+
impl PendingSplice {
1741+
#[inline]
1742+
fn add_checked(base: u64, delta: i64) -> u64 {
1743+
if delta >= 0 {
1744+
base.saturating_add(delta as u64)
1745+
} else {
1746+
base.saturating_sub(delta.abs() as u64)
1747+
}
1748+
}
1749+
1750+
/// Compute the post-splice channel value from the pre-splice values and the peer contributions
1751+
pub fn compute_post_value(pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64) -> u64 {
1752+
Self::add_checked(pre_channel_value, our_funding_contribution.saturating_add(their_funding_contribution))
1753+
}
1754+
}
1755+
17391756
/// Contains everything about the channel including state, and various flags.
17401757
pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
17411758
config: LegacyChannelConfig,
@@ -4299,6 +4316,33 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
42994316
}
43004317
}
43014318

4319+
/// Check that a balance value meets the channel reserve requirements or violates them (below reserve).
4320+
/// The channel value is an input as opposed to using from self, so that this can be used in case of splicing
4321+
/// to checks with new channel value (before being comitted to it).
4322+
#[cfg(splicing)]
4323+
pub fn check_balance_meets_v2_reserve_requirements(&self, balance: u64, channel_value: u64) -> Result<(), ChannelError> {
4324+
if balance == 0 {
4325+
return Ok(());
4326+
}
4327+
let holder_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
4328+
channel_value, self.holder_dust_limit_satoshis);
4329+
if balance < holder_selected_channel_reserve_satoshis {
4330+
return Err(ChannelError::Warn(format!(
4331+
"Balance below reserve mandated by holder, {} vs {}",
4332+
balance, holder_selected_channel_reserve_satoshis,
4333+
)));
4334+
}
4335+
let counterparty_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
4336+
channel_value, self.counterparty_dust_limit_satoshis);
4337+
if balance < counterparty_selected_channel_reserve_satoshis {
4338+
return Err(ChannelError::Warn(format!(
4339+
"Balance below reserve mandated by counterparty, {} vs {}",
4340+
balance, counterparty_selected_channel_reserve_satoshis,
4341+
)));
4342+
}
4343+
Ok(())
4344+
}
4345+
43024346
/// Get the commitment tx fee for the local's (i.e. our) next commitment transaction based on the
43034347
/// number of pending HTLCs that are on track to be in our next commitment tx.
43044348
///
@@ -4951,7 +4995,7 @@ pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
49514995
is_v2_established: bool,
49524996
/// Info about an in-progress, pending splice (if any), on the pre-splice channel
49534997
#[cfg(splicing)]
4954-
pending_splice: Option<PendingSplice>,
4998+
pending_splice_pre: Option<PendingSplice>,
49554999
}
49565000

49575001
#[cfg(any(test, fuzzing))]
@@ -8487,7 +8531,7 @@ impl<SP: Deref> FundedChannel<SP> where
84878531
) -> Result<msgs::SpliceInit, APIError> {
84888532
// Check if a splice has been initiated already.
84898533
// Note: only a single outstanding splice is supported (per spec)
8490-
if let Some(splice_info) = &self.pending_splice {
8534+
if let Some(splice_info) = &self.pending_splice_pre {
84918535
return Err(APIError::APIMisuseError { err: format!(
84928536
"Channel {} cannot be spliced, as it has already a splice pending (contribution {})",
84938537
self.context.channel_id(), splice_info.our_funding_contribution
@@ -8523,7 +8567,7 @@ impl<SP: Deref> FundedChannel<SP> where
85238567
self.context.channel_id(), err,
85248568
)})?;
85258569

8526-
self.pending_splice = Some(PendingSplice {
8570+
self.pending_splice_pre = Some(PendingSplice {
85278571
our_funding_contribution: our_funding_contribution_satoshis,
85288572
});
85298573

@@ -8557,7 +8601,7 @@ impl<SP: Deref> FundedChannel<SP> where
85578601
let our_funding_contribution_satoshis = 0i64;
85588602

85598603
// Check if a splice has been initiated already.
8560-
if let Some(splice_info) = &self.pending_splice {
8604+
if let Some(splice_info) = &self.pending_splice_pre {
85618605
return Err(ChannelError::Warn(format!(
85628606
"Channel has already a splice pending, contribution {}", splice_info.our_funding_contribution,
85638607
)));
@@ -8583,7 +8627,13 @@ impl<SP: Deref> FundedChannel<SP> where
85838627

85848628
// Note on channel reserve requirement pre-check: as the splice acceptor does not contribute,
85858629
// it can't go below reserve, therefore no pre-check is done here.
8586-
// TODO(splicing): Once splice acceptor can contribute, add reserve pre-check, similar to the one in `splice_ack`.
8630+
8631+
let pre_channel_value = self.funding.value_to_self_msat;
8632+
let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, their_funding_contribution_satoshis, our_funding_contribution_satoshis);
8633+
let post_balance = PendingSplice::add_checked(self.funding.value_to_self_msat, our_funding_contribution_satoshis);
8634+
// Early check for reserve requirement, assuming maximum balance of full channel value
8635+
// This will also be checked later at tx_complete
8636+
let _res = self.context.check_balance_meets_v2_reserve_requirements(post_balance, post_channel_value)?;
85878637

85888638
// TODO(splicing): Store msg.funding_pubkey
85898639
// TODO(splicing): Apply start of splice (splice_start)
@@ -8602,14 +8652,27 @@ impl<SP: Deref> FundedChannel<SP> where
86028652

86038653
/// Handle splice_ack
86048654
#[cfg(splicing)]
8605-
pub fn splice_ack(&mut self, _msg: &msgs::SpliceAck) -> Result<(), ChannelError> {
8655+
pub fn splice_ack(&mut self, msg: &msgs::SpliceAck) -> Result<(), ChannelError> {
86068656
// check if splice is pending
8607-
if self.pending_splice.is_none() {
8657+
let pending_splice = if let Some(pending_splice) = &self.pending_splice_pre {
8658+
pending_splice
8659+
} else {
86088660
return Err(ChannelError::Warn(format!("Channel is not in pending splice")));
86098661
};
86108662

86118663
// TODO(splicing): Pre-check for reserve requirement
86128664
// (Note: It should also be checked later at tx_complete)
8665+
8666+
8667+
let our_funding_contribution = pending_splice.our_funding_contribution;
8668+
let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
8669+
8670+
let pre_channel_value = self.funding.get_value_satoshis();
8671+
let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution_satoshis);
8672+
let post_balance = PendingSplice::add_checked(self.funding.value_to_self_msat, our_funding_contribution);
8673+
// Early check for reserve requirement, assuming maximum balance of full channel value
8674+
// This will also be checked later at tx_complete
8675+
let _res = self.context.check_balance_meets_v2_reserve_requirements(post_balance, post_channel_value)?;
86138676
Ok(())
86148677
}
86158678

@@ -9536,7 +9599,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
95369599
is_v2_established: false,
95379600
holder_commitment_point,
95389601
#[cfg(splicing)]
9539-
pending_splice: None,
9602+
pending_splice_pre: None,
95409603
};
95419604

95429605
let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some()
@@ -9812,7 +9875,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
98129875
is_v2_established: false,
98139876
holder_commitment_point,
98149877
#[cfg(splicing)]
9815-
pending_splice: None,
9878+
pending_splice_pre: None,
98169879
};
98179880
let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some()
98189881
|| channel.context.signer_pending_channel_ready;
@@ -11196,7 +11259,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1119611259
is_v2_established,
1119711260
holder_commitment_point,
1119811261
#[cfg(splicing)]
11199-
pending_splice: None,
11262+
pending_splice_pre: None,
1120011263
})
1120111264
}
1120211265
}
@@ -13118,4 +13181,69 @@ mod tests {
1311813181
);
1311913182
}
1312013183
}
13184+
13185+
#[cfg(all(test, splicing))]
13186+
fn get_pre_and_post(pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64) -> (u64, u64) {
13187+
use crate::ln::channel::PendingSplice;
13188+
13189+
let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution);
13190+
(pre_channel_value, post_channel_value)
13191+
}
13192+
13193+
#[cfg(all(test, splicing))]
13194+
#[test]
13195+
fn test_splice_compute_post_value() {
13196+
{
13197+
// increase, small amounts
13198+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 6_000, 0);
13199+
assert_eq!(pre_channel_value, 9_000);
13200+
assert_eq!(post_channel_value, 15_000);
13201+
}
13202+
{
13203+
// increase, small amounts
13204+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 4_000, 2_000);
13205+
assert_eq!(pre_channel_value, 9_000);
13206+
assert_eq!(post_channel_value, 15_000);
13207+
}
13208+
{
13209+
// increase, small amounts
13210+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 0, 6_000);
13211+
assert_eq!(pre_channel_value, 9_000);
13212+
assert_eq!(post_channel_value, 15_000);
13213+
}
13214+
{
13215+
// decrease, small amounts
13216+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -6_000, 0);
13217+
assert_eq!(pre_channel_value, 15_000);
13218+
assert_eq!(post_channel_value, 9_000);
13219+
}
13220+
{
13221+
// decrease, small amounts
13222+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -4_000, -2_000);
13223+
assert_eq!(pre_channel_value, 15_000);
13224+
assert_eq!(post_channel_value, 9_000);
13225+
}
13226+
{
13227+
// increase and decrease
13228+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, 4_000, -2_000);
13229+
assert_eq!(pre_channel_value, 15_000);
13230+
assert_eq!(post_channel_value, 17_000);
13231+
}
13232+
let base2: u64 = 2;
13233+
let huge63i3 = (base2.pow(63) - 3) as i64;
13234+
assert_eq!(huge63i3, 9223372036854775805);
13235+
assert_eq!(-huge63i3, -9223372036854775805);
13236+
{
13237+
// increase, large amount
13238+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, 3);
13239+
assert_eq!(pre_channel_value, 9_000);
13240+
assert_eq!(post_channel_value, 9223372036854784807);
13241+
}
13242+
{
13243+
// increase, large amounts
13244+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, huge63i3);
13245+
assert_eq!(pre_channel_value, 9_000);
13246+
assert_eq!(post_channel_value, 9223372036854784807);
13247+
}
13248+
}
1312113249
}

0 commit comments

Comments
 (0)