Skip to content

Commit a9df01c

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

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
@@ -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))
@@ -1727,8 +1727,30 @@ impl FundingScope {
17271727

17281728
/// Info about a pending splice, used in the pre-splice channel
17291729
#[cfg(splicing)]
1730+
#[derive(Clone)]
17301731
struct PendingSplice {
17311732
pub our_funding_contribution: i64,
1733+
pub funding_feerate_per_kw: u32,
1734+
pub locktime: u32,
1735+
/// The funding inputs that we plan to contributing to the splice.
1736+
pub our_funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>,
1737+
}
1738+
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+
}
17321754
}
17331755

17341756
/// Contains everything about the channel including state, and various flags.
@@ -4981,7 +5003,7 @@ pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
49815003
is_v2_established: bool,
49825004
/// Info about an in-progress, pending splice (if any), on the pre-splice channel
49835005
#[cfg(splicing)]
4984-
pending_splice: Option<PendingSplice>,
5006+
pending_splice_pre: Option<PendingSplice>,
49855007
}
49865008

49875009
#[cfg(any(test, fuzzing))]
@@ -8516,7 +8538,7 @@ impl<SP: Deref> FundedChannel<SP> where
85168538
) -> Result<msgs::SpliceInit, APIError> {
85178539
// Check if a splice has been initiated already.
85188540
// Note: only a single outstanding splice is supported (per spec)
8519-
if let Some(splice_info) = &self.pending_splice {
8541+
if let Some(splice_info) = &self.pending_splice_pre {
85208542
return Err(APIError::APIMisuseError { err: format!(
85218543
"Channel {} cannot be spliced, as it has already a splice pending (contribution {})",
85228544
self.context.channel_id(), splice_info.our_funding_contribution
@@ -8552,8 +8574,20 @@ impl<SP: Deref> FundedChannel<SP> where
85528574
self.context.channel_id(), err,
85538575
)})?;
85548576

8555-
self.pending_splice = Some(PendingSplice {
8577+
// convert inputs
8578+
let mut funding_inputs = Vec::new();
8579+
for (tx_in, tx, _w) in our_funding_inputs.into_iter() {
8580+
let tx16 = TransactionU16LenLimited::new(tx.clone()).map_err(
8581+
|e| APIError::APIMisuseError { err: format!("Too large transaction, {:?}", e)}
8582+
)?;
8583+
funding_inputs.push((tx_in.clone(), tx16));
8584+
}
8585+
8586+
self.pending_splice_pre = Some(PendingSplice {
85568587
our_funding_contribution: our_funding_contribution_satoshis,
8588+
funding_feerate_per_kw,
8589+
locktime,
8590+
our_funding_inputs: funding_inputs,
85578591
});
85588592

85598593
let msg = self.get_splice_init(our_funding_contribution_satoshis, funding_feerate_per_kw, locktime);
@@ -8580,13 +8614,13 @@ impl<SP: Deref> FundedChannel<SP> where
85808614

85818615
/// Handle splice_init
85828616
#[cfg(splicing)]
8583-
pub fn splice_init(&mut self, msg: &msgs::SpliceInit) -> Result<msgs::SpliceAck, ChannelError> {
8617+
pub fn splice_init<L: Deref>(&mut self, msg: &msgs::SpliceInit, logger: &L) -> Result<msgs::SpliceAck, ChannelError> where L::Target: Logger {
85848618
let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
85858619
// TODO(splicing): Currently not possible to contribute on the splicing-acceptor side
85868620
let our_funding_contribution_satoshis = 0i64;
85878621

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

86178651
// TODO(splicing): Store msg.funding_pubkey
8618-
// TODO(splicing): Apply start of splice (splice_start)
8652+
// Apply start of splice change in the state
8653+
self.splice_start(false, logger);
86198654

86208655
// TODO(splicing): The exisiting pubkey is reused, but a new one should be generated. See #3542.
86218656
// Note that channel_keys_id is supposed NOT to change
@@ -8626,22 +8661,55 @@ impl<SP: Deref> FundedChannel<SP> where
86268661
require_confirmed_inputs: None,
86278662
};
86288663
// TODO(splicing): start interactive funding negotiation
8664+
// let _msg = self.begin_interactive_funding_tx_construction(signer_provider, entropy_source, holder_node_id)
8665+
// .map_err(|err| ChannelError::Warn(format!("Failed to start interactive transaction construction, {:?}", err)))?;
8666+
86298667
Ok(splice_ack_msg)
86308668
}
86318669

86328670
/// Handle splice_ack
86338671
#[cfg(splicing)]
8634-
pub fn splice_ack(&mut self, _msg: &msgs::SpliceAck) -> Result<(), ChannelError> {
8672+
pub fn splice_ack<L: Deref>(&mut self, msg: &msgs::SpliceAck, logger: &L) -> Result<(), ChannelError> where L::Target: Logger {
86358673
// check if splice is pending
8636-
if self.pending_splice.is_none() {
8674+
let pending_splice = if let Some(pending_splice) = &self.pending_splice_pre {
8675+
pending_splice
8676+
} else {
86378677
return Err(ChannelError::Warn(format!("Channel is not in pending splice")));
86388678
};
86398679

8680+
8681+
let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
8682+
let our_funding_contribution = pending_splice.our_funding_contribution;
8683+
8684+
let pre_channel_value = self.funding.get_value_satoshis();
8685+
let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution_satoshis);
8686+
let post_balance = PendingSplice::add_checked(self.funding.value_to_self_msat, our_funding_contribution);
8687+
86408688
// TODO(splicing): Pre-check for reserve requirement
86418689
// (Note: It should also be checked later at tx_complete)
8690+
8691+
// Apply start of splice change in the state
8692+
self.splice_start(true, logger);
8693+
8694+
// TODO(splicing): start interactive funding negotiation
8695+
// let tx_msg_opt = self.begin_interactive_funding_tx_construction(signer_provider, entropy_source, holder_node_id)
8696+
// .map_err(|err| ChannelError::Warn(format!("V2 channel rejected due to sender error, {:?}", err)))?;
8697+
// Ok(tx_msg_opt)
86428698
Ok(())
86438699
}
86448700

8701+
/// Splice process starting; update state, log, etc.
8702+
#[cfg(splicing)]
8703+
pub(crate) fn splice_start<L: Deref>(&mut self, is_outgoing: bool, logger: &L) where L::Target: Logger {
8704+
// Set state, by this point splice_init/splice_ack handshake is complete
8705+
// TODO(splicing)
8706+
// self.channel_state = ChannelState::NegotiatingFunding(
8707+
// NegotiatingFundingFlags::OUR_INIT_SENT | NegotiatingFundingFlags::THEIR_INIT_SENT
8708+
// );
8709+
log_info!(logger, "Splicing process started, old channel value {}, outgoing {}, channel_id {}",
8710+
self.funding.get_value_satoshis(), is_outgoing, self.context.channel_id);
8711+
}
8712+
86458713
// Send stuff to our remote peers:
86468714

86478715
/// Queues up an outbound HTLC to send by placing it in the holding cell. You should call
@@ -9565,7 +9633,7 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
95659633
is_v2_established: false,
95669634
holder_commitment_point,
95679635
#[cfg(splicing)]
9568-
pending_splice: None,
9636+
pending_splice_pre: None,
95699637
};
95709638

95719639
let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some()
@@ -9841,7 +9909,7 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
98419909
is_v2_established: false,
98429910
holder_commitment_point,
98439911
#[cfg(splicing)]
9844-
pending_splice: None,
9912+
pending_splice_pre: None,
98459913
};
98469914
let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some()
98479915
|| channel.context.signer_pending_channel_ready;
@@ -11224,7 +11292,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1122411292
is_v2_established,
1122511293
holder_commitment_point,
1122611294
#[cfg(splicing)]
11227-
pending_splice: None,
11295+
pending_splice_pre: None,
1122811296
})
1122911297
}
1123011298
}
@@ -13146,4 +13214,69 @@ mod tests {
1314613214
);
1314713215
}
1314813216
}
13217+
13218+
#[cfg(all(test, splicing))]
13219+
fn get_pre_and_post(pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64) -> (u64, u64) {
13220+
use crate::ln::channel::PendingSplice;
13221+
13222+
let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution);
13223+
(pre_channel_value, post_channel_value)
13224+
}
13225+
13226+
#[cfg(all(test, splicing))]
13227+
#[test]
13228+
fn test_splice_compute_post_value() {
13229+
{
13230+
// increase, small amounts
13231+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 6_000, 0);
13232+
assert_eq!(pre_channel_value, 9_000);
13233+
assert_eq!(post_channel_value, 15_000);
13234+
}
13235+
{
13236+
// increase, small amounts
13237+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 4_000, 2_000);
13238+
assert_eq!(pre_channel_value, 9_000);
13239+
assert_eq!(post_channel_value, 15_000);
13240+
}
13241+
{
13242+
// increase, small amounts
13243+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 0, 6_000);
13244+
assert_eq!(pre_channel_value, 9_000);
13245+
assert_eq!(post_channel_value, 15_000);
13246+
}
13247+
{
13248+
// decrease, small amounts
13249+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -6_000, 0);
13250+
assert_eq!(pre_channel_value, 15_000);
13251+
assert_eq!(post_channel_value, 9_000);
13252+
}
13253+
{
13254+
// decrease, small amounts
13255+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -4_000, -2_000);
13256+
assert_eq!(pre_channel_value, 15_000);
13257+
assert_eq!(post_channel_value, 9_000);
13258+
}
13259+
{
13260+
// increase and decrease
13261+
let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, 4_000, -2_000);
13262+
assert_eq!(pre_channel_value, 15_000);
13263+
assert_eq!(post_channel_value, 17_000);
13264+
}
13265+
let base2: u64 = 2;
13266+
let huge63i3 = (base2.pow(63) - 3) as i64;
13267+
assert_eq!(huge63i3, 9223372036854775805);
13268+
assert_eq!(-huge63i3, -9223372036854775805);
13269+
{
13270+
// increase, large amount
13271+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, 3);
13272+
assert_eq!(pre_channel_value, 9_000);
13273+
assert_eq!(post_channel_value, 9223372036854784807);
13274+
}
13275+
{
13276+
// increase, large amounts
13277+
let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, huge63i3);
13278+
assert_eq!(pre_channel_value, 9_000);
13279+
assert_eq!(post_channel_value, 9223372036854784807);
13280+
}
13281+
}
1314913282
}

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)