Skip to content

Commit c9d30bc

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

File tree

2 files changed

+147
-14
lines changed

2 files changed

+147
-14
lines changed

lightning/src/ln/channel.rs

Lines changed: 145 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,7 +1519,7 @@ impl<SP: Deref> Channel<SP> where
15191519
holder_commitment_point,
15201520
is_v2_established: true,
15211521
#[cfg(splicing)]
1522-
pending_splice: None,
1522+
pending_splice_pre: None,
15231523
};
15241524
let res = funded_channel.commitment_signed_initial_v2(msg, best_block, signer_provider, logger)
15251525
.map(|monitor| (Some(monitor), None))
@@ -1724,8 +1724,30 @@ impl FundingScope {
17241724

17251725
/// Info about a pending splice, used in the pre-splice channel
17261726
#[cfg(splicing)]
1727+
#[derive(Clone)]
17271728
struct PendingSplice {
17281729
pub our_funding_contribution: i64,
1730+
pub funding_feerate_per_kw: u32,
1731+
pub locktime: u32,
1732+
/// The funding inputs that we plan to contributing to the splice.
1733+
pub our_funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
1734+
}
1735+
1736+
#[cfg(splicing)]
1737+
impl PendingSplice {
1738+
#[inline]
1739+
fn add_checked(base: u64, delta: i64) -> u64 {
1740+
if delta >= 0 {
1741+
base.saturating_add(delta as u64)
1742+
} else {
1743+
base.saturating_sub(delta.abs() as u64)
1744+
}
1745+
}
1746+
1747+
/// Compute the post-splice channel value from the pre-splice values and the peer contributions
1748+
pub fn compute_post_value(pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64) -> u64 {
1749+
Self::add_checked(pre_channel_value, our_funding_contribution.saturating_add(their_funding_contribution))
1750+
}
17291751
}
17301752

17311753
/// Contains everything about the channel including state, and various flags.
@@ -5003,7 +5025,7 @@ pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
50035025
is_v2_established: bool,
50045026
/// Info about an in-progress, pending splice (if any), on the pre-splice channel
50055027
#[cfg(splicing)]
5006-
pending_splice: Option<PendingSplice>,
5028+
pending_splice_pre: Option<PendingSplice>,
50075029
}
50085030

50095031
#[cfg(any(test, fuzzing))]
@@ -8535,7 +8557,7 @@ impl<SP: Deref> FundedChannel<SP> where
85358557
) -> Result<msgs::SpliceInit, APIError> {
85368558
// Check if a splice has been initiated already.
85378559
// Note: only a single outstanding splice is supported (per spec)
8538-
if let Some(splice_info) = &self.pending_splice {
8560+
if let Some(splice_info) = &self.pending_splice_pre {
85398561
return Err(APIError::APIMisuseError { err: format!(
85408562
"Channel {} cannot be spliced, as it has already a splice pending (contribution {})",
85418563
self.context.channel_id(), splice_info.our_funding_contribution
@@ -8571,8 +8593,20 @@ impl<SP: Deref> FundedChannel<SP> where
85718593
self.context.channel_id(), err,
85728594
)})?;
85738595

8574-
self.pending_splice = Some(PendingSplice {
8596+
// convert inputs
8597+
let mut funding_inputs = Vec::new();
8598+
for (tx_in, tx, _w) in our_funding_inputs.into_iter() {
8599+
let tx16 = TransactionU16LenLimited::new(tx.clone()).map_err(
8600+
|e| APIError::APIMisuseError { err: format!("Too large transaction, {:?}", e)}
8601+
)?;
8602+
funding_inputs.push((tx_in.clone(), tx16));
8603+
}
8604+
8605+
self.pending_splice_pre = Some(PendingSplice {
85758606
our_funding_contribution: our_funding_contribution_satoshis,
8607+
funding_feerate_per_kw,
8608+
locktime,
8609+
our_funding_inputs: funding_inputs,
85768610
});
85778611

85788612
let msg = self.get_splice_init(our_funding_contribution_satoshis, funding_feerate_per_kw, locktime);
@@ -8599,13 +8633,13 @@ impl<SP: Deref> FundedChannel<SP> where
85998633

86008634
/// Handle splice_init
86018635
#[cfg(splicing)]
8602-
pub fn splice_init(&mut self, msg: &msgs::SpliceInit) -> Result<msgs::SpliceAck, ChannelError> {
8636+
pub fn splice_init<L: Deref>(&mut self, msg: &msgs::SpliceInit, logger: &L) -> Result<msgs::SpliceAck, ChannelError> where L::Target: Logger {
86038637
let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
86048638
// TODO(splicing): Currently not possible to contribute on the splicing-acceptor side
86058639
let our_funding_contribution_satoshis = 0i64;
86068640

86078641
// Check if a splice has been initiated already.
8608-
if let Some(splice_info) = &self.pending_splice {
8642+
if let Some(splice_info) = &self.pending_splice_pre {
86098643
return Err(ChannelError::Warn(format!(
86108644
"Channel has already a splice pending, contribution {}", splice_info.our_funding_contribution,
86118645
)));
@@ -8634,7 +8668,8 @@ impl<SP: Deref> FundedChannel<SP> where
86348668
// TODO(splicing): Once splice acceptor can contribute, add reserve pre-check, similar to the one in `splice_ack`.
86358669

86368670
// TODO(splicing): Store msg.funding_pubkey
8637-
// TODO(splicing): Apply start of splice (splice_start)
8671+
// Apply start of splice change in the state
8672+
self.splice_start(false, logger);
86388673

86398674
// TODO(splicing): The exisiting pubkey is reused, but a new one should be generated. See #3542.
86408675
// Note that channel_keys_id is supposed NOT to change
@@ -8645,22 +8680,55 @@ impl<SP: Deref> FundedChannel<SP> where
86458680
require_confirmed_inputs: None,
86468681
};
86478682
// TODO(splicing): start interactive funding negotiation
8683+
// let _msg = self.begin_interactive_funding_tx_construction(signer_provider, entropy_source, holder_node_id)
8684+
// .map_err(|err| ChannelError::Warn(format!("Failed to start interactive transaction construction, {:?}", err)))?;
8685+
86488686
Ok(splice_ack_msg)
86498687
}
86508688

86518689
/// Handle splice_ack
86528690
#[cfg(splicing)]
8653-
pub fn splice_ack(&mut self, _msg: &msgs::SpliceAck) -> Result<(), ChannelError> {
8691+
pub fn splice_ack<L: Deref>(&mut self, msg: &msgs::SpliceAck, logger: &L) -> Result<(), ChannelError> where L::Target: Logger {
86548692
// check if splice is pending
8655-
if self.pending_splice.is_none() {
8693+
let pending_splice = if let Some(pending_splice) = &self.pending_splice_pre {
8694+
pending_splice
8695+
} else {
86568696
return Err(ChannelError::Warn(format!("Channel is not in pending splice")));
86578697
};
86588698

8699+
8700+
let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
8701+
let our_funding_contribution = pending_splice.our_funding_contribution;
8702+
8703+
let pre_channel_value = self.funding.get_value_satoshis();
8704+
let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution_satoshis);
8705+
let post_balance = PendingSplice::add_checked(self.funding.value_to_self_msat, our_funding_contribution);
8706+
86598707
// TODO(splicing): Pre-check for reserve requirement
86608708
// (Note: It should also be checked later at tx_complete)
8709+
8710+
// Apply start of splice change in the state
8711+
self.splice_start(true, logger);
8712+
8713+
// TODO(splicing): start interactive funding negotiation
8714+
// let tx_msg_opt = self.begin_interactive_funding_tx_construction(signer_provider, entropy_source, holder_node_id)
8715+
// .map_err(|err| ChannelError::Warn(format!("V2 channel rejected due to sender error, {:?}", err)))?;
8716+
// Ok(tx_msg_opt)
86618717
Ok(())
86628718
}
86638719

8720+
/// Splice process starting; update state, log, etc.
8721+
#[cfg(splicing)]
8722+
pub(crate) fn splice_start<L: Deref>(&mut self, is_outgoing: bool, logger: &L) where L::Target: Logger {
8723+
// Set state, by this point splice_init/splice_ack handshake is complete
8724+
// TODO(splicing)
8725+
// self.channel_state = ChannelState::NegotiatingFunding(
8726+
// NegotiatingFundingFlags::OUR_INIT_SENT | NegotiatingFundingFlags::THEIR_INIT_SENT
8727+
// );
8728+
log_info!(logger, "Splicing process started, old channel value {}, outgoing {}, channel_id {}",
8729+
self.funding.get_value_satoshis(), is_outgoing, self.context.channel_id);
8730+
}
8731+
86648732
// Send stuff to our remote peers:
86658733

86668734
/// Queues up an outbound HTLC to send by placing it in the holding cell. You should call
@@ -9582,7 +9650,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
95829650
is_v2_established: false,
95839651
holder_commitment_point,
95849652
#[cfg(splicing)]
9585-
pending_splice: None,
9653+
pending_splice_pre: None,
95869654
};
95879655

95889656
let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some()
@@ -9858,7 +9926,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
98589926
is_v2_established: false,
98599927
holder_commitment_point,
98609928
#[cfg(splicing)]
9861-
pending_splice: None,
9929+
pending_splice_pre: None,
98629930
};
98639931
let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some()
98649932
|| channel.context.signer_pending_channel_ready;
@@ -11241,7 +11309,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1124111309
is_v2_established,
1124211310
holder_commitment_point,
1124311311
#[cfg(splicing)]
11244-
pending_splice: None,
11312+
pending_splice_pre: None,
1124511313
})
1124611314
}
1124711315
}
@@ -13172,4 +13240,69 @@ mod tests {
1317213240
);
1317313241
}
1317413242
}
13243+
13244+
#[cfg(all(test, splicing))]
13245+
fn get_pre_and_post(pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64) -> (u64, u64) {
13246+
use crate::ln::channel::PendingSplice;
13247+
13248+
let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution);
13249+
(pre_channel_value, post_channel_value)
13250+
}
13251+
13252+
#[cfg(all(test, splicing))]
13253+
#[test]
13254+
fn test_splice_compute_post_value() {
13255+
{
13256+
// increase, small amounts
13257+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 6_000, 0);
13258+
assert_eq!(pre_channel_value, 9_000);
13259+
assert_eq!(post_channel_value, 15_000);
13260+
}
13261+
{
13262+
// increase, small amounts
13263+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 4_000, 2_000);
13264+
assert_eq!(pre_channel_value, 9_000);
13265+
assert_eq!(post_channel_value, 15_000);
13266+
}
13267+
{
13268+
// increase, small amounts
13269+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 0, 6_000);
13270+
assert_eq!(pre_channel_value, 9_000);
13271+
assert_eq!(post_channel_value, 15_000);
13272+
}
13273+
{
13274+
// decrease, small amounts
13275+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -6_000, 0);
13276+
assert_eq!(pre_channel_value, 15_000);
13277+
assert_eq!(post_channel_value, 9_000);
13278+
}
13279+
{
13280+
// decrease, small amounts
13281+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -4_000, -2_000);
13282+
assert_eq!(pre_channel_value, 15_000);
13283+
assert_eq!(post_channel_value, 9_000);
13284+
}
13285+
{
13286+
// increase and decrease
13287+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, 4_000, -2_000);
13288+
assert_eq!(pre_channel_value, 15_000);
13289+
assert_eq!(post_channel_value, 17_000);
13290+
}
13291+
let base2: u64 = 2;
13292+
let huge63i3 = (base2.pow(63) - 3) as i64;
13293+
assert_eq!(huge63i3, 9223372036854775805);
13294+
assert_eq!(-huge63i3, -9223372036854775805);
13295+
{
13296+
// increase, large amount
13297+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, 3);
13298+
assert_eq!(pre_channel_value, 9_000);
13299+
assert_eq!(post_channel_value, 9223372036854784807);
13300+
}
13301+
{
13302+
// increase, large amounts
13303+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, huge63i3);
13304+
assert_eq!(pre_channel_value, 9_000);
13305+
assert_eq!(post_channel_value, 9223372036854784807);
13306+
}
13307+
}
1317513308
}

lightning/src/ln/channelmanager.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9530,7 +9530,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
95309530
), msg.channel_id)),
95319531
hash_map::Entry::Occupied(mut chan_entry) => {
95329532
if let Some(chan) = chan_entry.get_mut().as_funded_mut() {
9533-
let splice_ack_msg = try_channel_entry!(self, peer_state, chan.splice_init(msg), chan_entry);
9533+
let splice_ack_msg = try_channel_entry!(self, peer_state, chan.splice_init(msg, &self.logger), chan_entry);
95349534
peer_state.pending_msg_events.push(MessageSendEvent::SendSpliceAck {
95359535
node_id: *counterparty_node_id,
95369536
msg: splice_ack_msg,
@@ -9569,7 +9569,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
95699569
), msg.channel_id)),
95709570
hash_map::Entry::Occupied(mut chan_entry) => {
95719571
if let Some(chan) = chan_entry.get_mut().as_funded_mut() {
9572-
try_channel_entry!(self, peer_state, chan.splice_ack(msg), chan_entry);
9572+
try_channel_entry!(self, peer_state, chan.splice_ack(msg, &self.logger), chan_entry);
95739573
} else {
95749574
return Err(MsgHandleErrInternal::send_err_msg_no_close("Channel is not funded, cannot splice".to_owned(), msg.channel_id));
95759575
}

0 commit comments

Comments
 (0)