Skip to content

Commit ce203f2

Browse files
committed
Support accepting splice-out
When a counterparty sends splice_init with a negative contribution, they are requesting to remove funds from a channel. Remove conditions guarding against this and check that they have enough channel balance to cover the removed funds.
1 parent 3245ebf commit ce203f2

File tree

1 file changed

+53
-21
lines changed

1 file changed

+53
-21
lines changed

lightning/src/ln/channel.rs

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10826,35 +10826,31 @@ where
1082610826
)));
1082710827
}
1082810828

10829+
debug_assert_eq!(our_funding_contribution, SignedAmount::ZERO);
10830+
1082910831
// TODO(splicing): Move this check once user-provided contributions are supported for
1083010832
// counterparty-initiated splices.
1083110833
if our_funding_contribution > SignedAmount::MAX_MONEY {
1083210834
return Err(ChannelError::WarnAndDisconnect(format!(
10833-
"Channel {} cannot be spliced; our contribution exceeds total bitcoin supply: {}",
10835+
"Channel {} cannot be spliced in; our {} contribution exceeds the total bitcoin supply",
1083410836
self.context.channel_id(),
1083510837
our_funding_contribution,
1083610838
)));
1083710839
}
1083810840

10839-
let their_funding_contribution = SignedAmount::from_sat(msg.funding_contribution_satoshis);
10840-
if their_funding_contribution > SignedAmount::MAX_MONEY {
10841+
if our_funding_contribution < -SignedAmount::MAX_MONEY {
1084110842
return Err(ChannelError::WarnAndDisconnect(format!(
10842-
"Channel {} cannot be spliced; their contribution exceeds total bitcoin supply: {}",
10843+
"Channel {} cannot be spliced out; our {} contribution exhausts the total bitcoin supply",
1084310844
self.context.channel_id(),
10844-
their_funding_contribution,
10845-
)));
10846-
}
10847-
10848-
debug_assert_eq!(our_funding_contribution, SignedAmount::ZERO);
10849-
if their_funding_contribution < SignedAmount::ZERO {
10850-
return Err(ChannelError::WarnAndDisconnect(format!(
10851-
"Splice-out not supported, only splice in, contribution is {} ({} + {})",
10852-
their_funding_contribution + our_funding_contribution,
10853-
their_funding_contribution,
1085410845
our_funding_contribution,
1085510846
)));
1085610847
}
1085710848

10849+
let their_funding_contribution = SignedAmount::from_sat(msg.funding_contribution_satoshis);
10850+
self.validate_splice_contribution(their_funding_contribution)?;
10851+
10852+
// TODO(splicing): Check that channel balance does not go below the channel reserve
10853+
1085810854
let splice_funding = FundingScope::for_splice(
1085910855
&self.funding,
1086010856
&self.context,
@@ -10874,6 +10870,45 @@ where
1087410870
Ok(splice_funding)
1087510871
}
1087610872

10873+
#[cfg(splicing)]
10874+
fn validate_splice_contribution(
10875+
&self, their_funding_contribution: SignedAmount,
10876+
) -> Result<(), ChannelError> {
10877+
if their_funding_contribution > SignedAmount::MAX_MONEY {
10878+
return Err(ChannelError::WarnAndDisconnect(format!(
10879+
"Channel {} cannot be spliced in; their {} contribution exceeds the total bitcoin supply",
10880+
self.context.channel_id(),
10881+
their_funding_contribution,
10882+
)));
10883+
}
10884+
10885+
if their_funding_contribution < -SignedAmount::MAX_MONEY {
10886+
return Err(ChannelError::WarnAndDisconnect(format!(
10887+
"Channel {} cannot be spliced out; their {} contribution exhausts the total bitcoin supply",
10888+
self.context.channel_id(),
10889+
their_funding_contribution,
10890+
)));
10891+
}
10892+
10893+
let their_channel_balance = Amount::from_sat(self.funding.get_value_satoshis())
10894+
- Amount::from_sat(self.funding.get_value_to_self_msat() / 1000);
10895+
let post_channel_balance = AddSigned::checked_add_signed(
10896+
their_channel_balance.to_sat(),
10897+
their_funding_contribution.to_sat(),
10898+
);
10899+
10900+
if post_channel_balance.is_none() {
10901+
return Err(ChannelError::WarnAndDisconnect(format!(
10902+
"Channel {} cannot be spliced out; their {} contribution exhausts their channel balance: {}",
10903+
self.context.channel_id(),
10904+
their_funding_contribution,
10905+
their_channel_balance,
10906+
)));
10907+
}
10908+
10909+
Ok(())
10910+
}
10911+
1087710912
/// See also [`validate_splice_init`]
1087810913
#[cfg(splicing)]
1087910914
pub(crate) fn splice_init<ES: Deref, L: Deref>(
@@ -10987,13 +11022,7 @@ where
1098711022
debug_assert!(our_funding_contribution <= SignedAmount::MAX_MONEY);
1098811023

1098911024
let their_funding_contribution = SignedAmount::from_sat(msg.funding_contribution_satoshis);
10990-
if their_funding_contribution > SignedAmount::MAX_MONEY {
10991-
return Err(ChannelError::Warn(format!(
10992-
"Channel {} cannot be spliced; their contribution exceeds total bitcoin supply: {}",
10993-
self.context.channel_id(),
10994-
their_funding_contribution,
10995-
)));
10996-
}
11025+
self.validate_splice_contribution(their_funding_contribution)?;
1099711026

1099811027
let splice_funding = FundingScope::for_splice(
1099911028
&self.funding,
@@ -11031,6 +11060,9 @@ where
1103111060
let tx_msg_opt = interactive_tx_constructor.take_initiator_first_message();
1103211061

1103311062
debug_assert!(self.interactive_tx_signing_session.is_none());
11063+
11064+
let pending_splice =
11065+
self.pending_splice.as_mut().expect("pending_splice should still be set");
1103411066
pending_splice.funding_negotiation = Some(FundingNegotiation::ConstructingTransaction(
1103511067
splice_funding,
1103611068
interactive_tx_constructor,

0 commit comments

Comments
 (0)