Skip to content

Commit 7db5dbe

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

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.
@@ -5007,7 +5029,7 @@ pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
50075029
is_v2_established: bool,
50085030
/// Info about an in-progress, pending splice (if any), on the pre-splice channel
50095031
#[cfg(splicing)]
5010-
pending_splice: Option<PendingSplice>,
5032+
pending_splice_pre: Option<PendingSplice>,
50115033
}
50125034

50135035
#[cfg(any(test, fuzzing))]
@@ -8540,7 +8562,7 @@ impl<SP: Deref> FundedChannel<SP> where
85408562
) -> Result<msgs::SpliceInit, APIError> {
85418563
// Check if a splice has been initiated already.
85428564
// Note: only a single outstanding splice is supported (per spec)
8543-
if let Some(splice_info) = &self.pending_splice {
8565+
if let Some(splice_info) = &self.pending_splice_pre {
85448566
return Err(APIError::APIMisuseError { err: format!(
85458567
"Channel {} cannot be spliced, as it has already a splice pending (contribution {})",
85468568
self.context.channel_id(), splice_info.our_funding_contribution
@@ -8576,8 +8598,20 @@ impl<SP: Deref> FundedChannel<SP> where
85768598
self.context.channel_id(), err,
85778599
)})?;
85788600

8579-
self.pending_splice = Some(PendingSplice {
8601+
// convert inputs
8602+
let mut funding_inputs = Vec::new();
8603+
for (tx_in, tx, _w) in our_funding_inputs.into_iter() {
8604+
let tx16 = TransactionU16LenLimited::new(tx.clone()).map_err(
8605+
|e| APIError::APIMisuseError { err: format!("Too large transaction, {:?}", e)}
8606+
)?;
8607+
funding_inputs.push((tx_in.clone(), tx16));
8608+
}
8609+
8610+
self.pending_splice_pre = Some(PendingSplice {
85808611
our_funding_contribution: our_funding_contribution_satoshis,
8612+
funding_feerate_per_kw,
8613+
locktime,
8614+
our_funding_inputs: funding_inputs,
85818615
});
85828616

85838617
let msg = self.get_splice_init(our_funding_contribution_satoshis, funding_feerate_per_kw, locktime);
@@ -8604,13 +8638,13 @@ impl<SP: Deref> FundedChannel<SP> where
86048638

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

86128646
// Check if a splice has been initiated already.
8613-
if let Some(splice_info) = &self.pending_splice {
8647+
if let Some(splice_info) = &self.pending_splice_pre {
86148648
return Err(ChannelError::Warn(format!(
86158649
"Channel has already a splice pending, contribution {}", splice_info.our_funding_contribution,
86168650
)));
@@ -8639,7 +8673,8 @@ impl<SP: Deref> FundedChannel<SP> where
86398673
// TODO(splicing): Once splice acceptor can contribute, add reserve pre-check, similar to the one in `splice_ack`.
86408674

86418675
// TODO(splicing): Store msg.funding_pubkey
8642-
// TODO(splicing): Apply start of splice (splice_start)
8676+
// Apply start of splice change in the state
8677+
self.splice_start(false, logger);
86438678

86448679
// TODO(splicing): The exisiting pubkey is reused, but a new one should be generated. See #3542.
86458680
// Note that channel_keys_id is supposed NOT to change
@@ -8650,22 +8685,55 @@ impl<SP: Deref> FundedChannel<SP> where
86508685
require_confirmed_inputs: None,
86518686
};
86528687
// TODO(splicing): start interactive funding negotiation
8688+
// let _msg = self.begin_interactive_funding_tx_construction(signer_provider, entropy_source, holder_node_id)
8689+
// .map_err(|err| ChannelError::Warn(format!("Failed to start interactive transaction construction, {:?}", err)))?;
8690+
86538691
Ok(splice_ack_msg)
86548692
}
86558693

86568694
/// Handle splice_ack
86578695
#[cfg(splicing)]
8658-
pub fn splice_ack(&mut self, _msg: &msgs::SpliceAck) -> Result<(), ChannelError> {
8696+
pub fn splice_ack<L: Deref>(&mut self, msg: &msgs::SpliceAck, logger: &L) -> Result<(), ChannelError> where L::Target: Logger {
86598697
// check if splice is pending
8660-
if self.pending_splice.is_none() {
8698+
let pending_splice = if let Some(pending_splice) = &self.pending_splice_pre {
8699+
pending_splice
8700+
} else {
86618701
return Err(ChannelError::Warn(format!("Channel is not in pending splice")));
86628702
};
86638703

8704+
8705+
let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
8706+
let our_funding_contribution = pending_splice.our_funding_contribution;
8707+
8708+
let pre_channel_value = self.funding.get_value_satoshis();
8709+
let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution_satoshis);
8710+
let post_balance = PendingSplice::add_checked(self.funding.value_to_self_msat, our_funding_contribution);
8711+
86648712
// TODO(splicing): Pre-check for reserve requirement
86658713
// (Note: It should also be checked later at tx_complete)
8714+
8715+
// Apply start of splice change in the state
8716+
self.splice_start(true, logger);
8717+
8718+
// TODO(splicing): start interactive funding negotiation
8719+
// let tx_msg_opt = self.begin_interactive_funding_tx_construction(signer_provider, entropy_source, holder_node_id)
8720+
// .map_err(|err| ChannelError::Warn(format!("V2 channel rejected due to sender error, {:?}", err)))?;
8721+
// Ok(tx_msg_opt)
86668722
Ok(())
86678723
}
86688724

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

86718739
/// Queues up an outbound HTLC to send by placing it in the holding cell. You should call
@@ -9586,7 +9654,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
95869654
is_v2_established: false,
95879655
holder_commitment_point,
95889656
#[cfg(splicing)]
9589-
pending_splice: None,
9657+
pending_splice_pre: None,
95909658
};
95919659

95929660
let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some()
@@ -9863,7 +9931,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
98639931
is_v2_established: false,
98649932
holder_commitment_point,
98659933
#[cfg(splicing)]
9866-
pending_splice: None,
9934+
pending_splice_pre: None,
98679935
};
98689936
let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some()
98699937
|| channel.context.signer_pending_channel_ready;
@@ -11227,7 +11295,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1122711295
is_v2_established,
1122811296
holder_commitment_point,
1122911297
#[cfg(splicing)]
11230-
pending_splice: None,
11298+
pending_splice_pre: None,
1123111299
})
1123211300
}
1123311301
}
@@ -13157,4 +13225,69 @@ mod tests {
1315713225
);
1315813226
}
1315913227
}
13228+
13229+
#[cfg(all(test, splicing))]
13230+
fn get_pre_and_post(pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64) -> (u64, u64) {
13231+
use crate::ln::channel::PendingSplice;
13232+
13233+
let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution);
13234+
(pre_channel_value, post_channel_value)
13235+
}
13236+
13237+
#[cfg(all(test, splicing))]
13238+
#[test]
13239+
fn test_splice_compute_post_value() {
13240+
{
13241+
// increase, small amounts
13242+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 6_000, 0);
13243+
assert_eq!(pre_channel_value, 9_000);
13244+
assert_eq!(post_channel_value, 15_000);
13245+
}
13246+
{
13247+
// increase, small amounts
13248+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 4_000, 2_000);
13249+
assert_eq!(pre_channel_value, 9_000);
13250+
assert_eq!(post_channel_value, 15_000);
13251+
}
13252+
{
13253+
// increase, small amounts
13254+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 0, 6_000);
13255+
assert_eq!(pre_channel_value, 9_000);
13256+
assert_eq!(post_channel_value, 15_000);
13257+
}
13258+
{
13259+
// decrease, small amounts
13260+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -6_000, 0);
13261+
assert_eq!(pre_channel_value, 15_000);
13262+
assert_eq!(post_channel_value, 9_000);
13263+
}
13264+
{
13265+
// decrease, small amounts
13266+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -4_000, -2_000);
13267+
assert_eq!(pre_channel_value, 15_000);
13268+
assert_eq!(post_channel_value, 9_000);
13269+
}
13270+
{
13271+
// increase and decrease
13272+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, 4_000, -2_000);
13273+
assert_eq!(pre_channel_value, 15_000);
13274+
assert_eq!(post_channel_value, 17_000);
13275+
}
13276+
let base2: u64 = 2;
13277+
let huge63i3 = (base2.pow(63) - 3) as i64;
13278+
assert_eq!(huge63i3, 9223372036854775805);
13279+
assert_eq!(-huge63i3, -9223372036854775805);
13280+
{
13281+
// increase, large amount
13282+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, 3);
13283+
assert_eq!(pre_channel_value, 9_000);
13284+
assert_eq!(post_channel_value, 9223372036854784807);
13285+
}
13286+
{
13287+
// increase, large amounts
13288+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, huge63i3);
13289+
assert_eq!(pre_channel_value, 9_000);
13290+
assert_eq!(post_channel_value, 9223372036854784807);
13291+
}
13292+
}
1316013293
}

lightning/src/ln/channelmanager.rs

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

0 commit comments

Comments
 (0)