Skip to content

Commit abf06d9

Browse files
committed
New splice_channel() for initiating splicing, handle splice_init and splice_ack messages, but fail afterwards
1 parent 248c45a commit abf06d9

File tree

1 file changed

+139
-11
lines changed

1 file changed

+139
-11
lines changed

lightning/src/ln/channel.rs

Lines changed: 139 additions & 11 deletions
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))
@@ -1731,6 +1731,23 @@ struct PendingSplice {
17311731
pub our_funding_contribution: i64,
17321732
}
17331733

1734+
#[cfg(splicing)]
1735+
impl PendingSplice {
1736+
#[inline]
1737+
fn add_checked(base: u64, delta: i64) -> u64 {
1738+
if delta >= 0 {
1739+
base.saturating_add(delta as u64)
1740+
} else {
1741+
base.saturating_sub(delta.abs() as u64)
1742+
}
1743+
}
1744+
1745+
/// Compute the post-splice channel value from the pre-splice values and the peer contributions
1746+
pub fn compute_post_value(pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64) -> u64 {
1747+
Self::add_checked(pre_channel_value, our_funding_contribution.saturating_add(their_funding_contribution))
1748+
}
1749+
}
1750+
17341751
/// Contains everything about the channel including state, and various flags.
17351752
pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
17361753
config: LegacyChannelConfig,
@@ -4213,6 +4230,33 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
42134230
}
42144231
}
42154232

4233+
/// Check that a balance value meets the channel reserve requirements or violates them (below reserve).
4234+
/// The channel value is an input as opposed to using from self, so that this can be used in case of splicing
4235+
/// to checks with new channel value (before being comitted to it).
4236+
#[cfg(splicing)]
4237+
pub fn check_balance_meets_v2_reserve_requirements(&self, balance: u64, channel_value: u64) -> Result<(), ChannelError> {
4238+
if balance == 0 {
4239+
return Ok(());
4240+
}
4241+
let holder_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
4242+
channel_value, self.holder_dust_limit_satoshis);
4243+
if balance < holder_selected_channel_reserve_satoshis {
4244+
return Err(ChannelError::Warn(format!(
4245+
"Balance below reserve mandated by holder, {} vs {}",
4246+
balance, holder_selected_channel_reserve_satoshis,
4247+
)));
4248+
}
4249+
let counterparty_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
4250+
channel_value, self.counterparty_dust_limit_satoshis);
4251+
if balance < counterparty_selected_channel_reserve_satoshis {
4252+
return Err(ChannelError::Warn(format!(
4253+
"Balance below reserve mandated by counterparty, {} vs {}",
4254+
balance, counterparty_selected_channel_reserve_satoshis,
4255+
)));
4256+
}
4257+
Ok(())
4258+
}
4259+
42164260
/// Get the commitment tx fee for the local's (i.e. our) next commitment transaction based on the
42174261
/// number of pending HTLCs that are on track to be in our next commitment tx.
42184262
///
@@ -4860,7 +4904,7 @@ pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
48604904
is_v2_established: bool,
48614905
/// Info about an in-progress, pending splice (if any), on the pre-splice channel
48624906
#[cfg(splicing)]
4863-
pending_splice: Option<PendingSplice>,
4907+
pending_splice_pre: Option<PendingSplice>,
48644908
}
48654909

48664910
#[cfg(any(test, fuzzing))]
@@ -8395,7 +8439,7 @@ impl<SP: Deref> FundedChannel<SP> where
83958439
) -> Result<msgs::SpliceInit, APIError> {
83968440
// Check if a splice has been initiated already.
83978441
// Note: only a single outstanding splice is supported (per spec)
8398-
if let Some(splice_info) = &self.pending_splice {
8442+
if let Some(splice_info) = &self.pending_splice_pre {
83998443
return Err(APIError::APIMisuseError { err: format!(
84008444
"Channel {} cannot be spliced, as it has already a splice pending (contribution {})",
84018445
self.context.channel_id(), splice_info.our_funding_contribution
@@ -8431,7 +8475,7 @@ impl<SP: Deref> FundedChannel<SP> where
84318475
self.context.channel_id(), err,
84328476
)})?;
84338477

8434-
self.pending_splice = Some(PendingSplice {
8478+
self.pending_splice_pre = Some(PendingSplice {
84358479
our_funding_contribution: our_funding_contribution_satoshis,
84368480
});
84378481

@@ -8465,7 +8509,7 @@ impl<SP: Deref> FundedChannel<SP> where
84658509
let our_funding_contribution_satoshis = 0i64;
84668510

84678511
// Check if a splice has been initiated already.
8468-
if let Some(splice_info) = &self.pending_splice {
8512+
if let Some(splice_info) = &self.pending_splice_pre {
84698513
return Err(ChannelError::Warn(format!(
84708514
"Channel has already a splice pending, contribution {}", splice_info.our_funding_contribution,
84718515
)));
@@ -8491,7 +8535,13 @@ impl<SP: Deref> FundedChannel<SP> where
84918535

84928536
// Note on channel reserve requirement pre-check: as the splice acceptor does not contribute,
84938537
// it can't go below reserve, therefore no pre-check is done here.
8494-
// TODO(splicing): Once splice acceptor can contribute, add reserve pre-check, similar to the one in `splice_ack`.
8538+
8539+
let pre_channel_value = self.funding.value_to_self_msat;
8540+
let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, their_funding_contribution_satoshis, our_funding_contribution_satoshis);
8541+
let post_balance = PendingSplice::add_checked(self.funding.value_to_self_msat, our_funding_contribution_satoshis);
8542+
// Early check for reserve requirement, assuming maximum balance of full channel value
8543+
// This will also be checked later at tx_complete
8544+
let _res = self.context.check_balance_meets_v2_reserve_requirements(post_balance, post_channel_value)?;
84958545

84968546
// TODO(splicing): Store msg.funding_pubkey
84978547
// TODO(splicing): Apply start of splice (splice_start)
@@ -8510,14 +8560,27 @@ impl<SP: Deref> FundedChannel<SP> where
85108560

85118561
/// Handle splice_ack
85128562
#[cfg(splicing)]
8513-
pub fn splice_ack(&mut self, _msg: &msgs::SpliceAck) -> Result<(), ChannelError> {
8563+
pub fn splice_ack(&mut self, msg: &msgs::SpliceAck) -> Result<(), ChannelError> {
85148564
// check if splice is pending
8515-
if self.pending_splice.is_none() {
8565+
let pending_splice = if let Some(pending_splice) = &self.pending_splice_pre {
8566+
pending_splice
8567+
} else {
85168568
return Err(ChannelError::Warn(format!("Channel is not in pending splice")));
85178569
};
85188570

85198571
// TODO(splicing): Pre-check for reserve requirement
85208572
// (Note: It should also be checked later at tx_complete)
8573+
8574+
8575+
let our_funding_contribution = pending_splice.our_funding_contribution;
8576+
let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
8577+
8578+
let pre_channel_value = self.funding.get_value_satoshis();
8579+
let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution_satoshis);
8580+
let post_balance = PendingSplice::add_checked(self.funding.value_to_self_msat, our_funding_contribution);
8581+
// Early check for reserve requirement, assuming maximum balance of full channel value
8582+
// This will also be checked later at tx_complete
8583+
let _res = self.context.check_balance_meets_v2_reserve_requirements(post_balance, post_channel_value)?;
85218584
Ok(())
85228585
}
85238586

@@ -9444,7 +9507,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
94449507
is_v2_established: false,
94459508
holder_commitment_point,
94469509
#[cfg(splicing)]
9447-
pending_splice: None,
9510+
pending_splice_pre: None,
94489511
};
94499512

94509513
let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some()
@@ -9720,7 +9783,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
97209783
is_v2_established: false,
97219784
holder_commitment_point,
97229785
#[cfg(splicing)]
9723-
pending_splice: None,
9786+
pending_splice_pre: None,
97249787
};
97259788
let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some()
97269789
|| channel.context.signer_pending_channel_ready;
@@ -11101,7 +11164,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1110111164
is_v2_established,
1110211165
holder_commitment_point,
1110311166
#[cfg(splicing)]
11104-
pending_splice: None,
11167+
pending_splice_pre: None,
1110511168
})
1110611169
}
1110711170
}
@@ -13023,4 +13086,69 @@ mod tests {
1302313086
);
1302413087
}
1302513088
}
13089+
13090+
#[cfg(all(test, splicing))]
13091+
fn get_pre_and_post(pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64) -> (u64, u64) {
13092+
use crate::ln::channel::PendingSplice;
13093+
13094+
let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution);
13095+
(pre_channel_value, post_channel_value)
13096+
}
13097+
13098+
#[cfg(all(test, splicing))]
13099+
#[test]
13100+
fn test_splice_compute_post_value() {
13101+
{
13102+
// increase, small amounts
13103+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 6_000, 0);
13104+
assert_eq!(pre_channel_value, 9_000);
13105+
assert_eq!(post_channel_value, 15_000);
13106+
}
13107+
{
13108+
// increase, small amounts
13109+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 4_000, 2_000);
13110+
assert_eq!(pre_channel_value, 9_000);
13111+
assert_eq!(post_channel_value, 15_000);
13112+
}
13113+
{
13114+
// increase, small amounts
13115+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 0, 6_000);
13116+
assert_eq!(pre_channel_value, 9_000);
13117+
assert_eq!(post_channel_value, 15_000);
13118+
}
13119+
{
13120+
// decrease, small amounts
13121+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -6_000, 0);
13122+
assert_eq!(pre_channel_value, 15_000);
13123+
assert_eq!(post_channel_value, 9_000);
13124+
}
13125+
{
13126+
// decrease, small amounts
13127+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -4_000, -2_000);
13128+
assert_eq!(pre_channel_value, 15_000);
13129+
assert_eq!(post_channel_value, 9_000);
13130+
}
13131+
{
13132+
// increase and decrease
13133+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, 4_000, -2_000);
13134+
assert_eq!(pre_channel_value, 15_000);
13135+
assert_eq!(post_channel_value, 17_000);
13136+
}
13137+
let base2: u64 = 2;
13138+
let huge63i3 = (base2.pow(63) - 3) as i64;
13139+
assert_eq!(huge63i3, 9223372036854775805);
13140+
assert_eq!(-huge63i3, -9223372036854775805);
13141+
{
13142+
// increase, large amount
13143+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, 3);
13144+
assert_eq!(pre_channel_value, 9_000);
13145+
assert_eq!(post_channel_value, 9223372036854784807);
13146+
}
13147+
{
13148+
// increase, large amounts
13149+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, huge63i3);
13150+
assert_eq!(pre_channel_value, 9_000);
13151+
assert_eq!(post_channel_value, 9223372036854784807);
13152+
}
13153+
}
1302613154
}

0 commit comments

Comments
 (0)