@@ -11,7 +11,6 @@ use bitcoin::amount::Amount;
1111use bitcoin::constants::ChainHash;
1212use bitcoin::script::{Script, ScriptBuf, Builder, WScriptHash};
1313use bitcoin::transaction::{Transaction, TxIn};
14- use bitcoin::sighash;
1514use bitcoin::sighash::EcdsaSighashType;
1615use bitcoin::consensus::encode;
1716use bitcoin::absolute::LockTime;
@@ -25,7 +24,7 @@ use bitcoin::hash_types::{Txid, BlockHash};
2524use bitcoin::secp256k1::constants::PUBLIC_KEY_SIZE;
2625use bitcoin::secp256k1::{PublicKey,SecretKey};
2726use bitcoin::secp256k1::{Secp256k1,ecdsa::Signature};
28- use bitcoin::secp256k1;
27+ use bitcoin::{ secp256k1, sighash} ;
2928
3029use crate::ln::types::ChannelId;
3130use crate::types::payment::{PaymentPreimage, PaymentHash};
@@ -1427,6 +1426,30 @@ impl UnfundedChannelContext {
14271426 }
14281427}
14291428
1429+ /// Info about a pending splice, used in the pre-splice channel
1430+ #[cfg(splicing)]
1431+ #[derive(Clone)]
1432+ struct PendingSplice {
1433+ pub our_funding_contribution: i64,
1434+ }
1435+
1436+ #[cfg(splicing)]
1437+ impl PendingSplice {
1438+ #[inline]
1439+ fn add_checked(base: u64, delta: i64) -> u64 {
1440+ if delta >= 0 {
1441+ base.saturating_add(delta as u64)
1442+ } else {
1443+ base.saturating_sub(delta.abs() as u64)
1444+ }
1445+ }
1446+
1447+ /// Compute the post-splice channel value from the pre-splice values and the peer contributions
1448+ pub fn compute_post_value(pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64) -> u64 {
1449+ Self::add_checked(pre_channel_value, our_funding_contribution.saturating_add(their_funding_contribution))
1450+ }
1451+ }
1452+
14301453/// Contains everything about the channel including state, and various flags.
14311454pub(super) struct ChannelContext<SP: Deref> where SP::Target: SignerProvider {
14321455 config: LegacyChannelConfig,
@@ -3828,6 +3851,33 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
38283851 (context.holder_selected_channel_reserve_satoshis, context.counterparty_selected_channel_reserve_satoshis)
38293852 }
38303853
3854+ /// Check that a balance value meets the channel reserve requirements or violates them (below reserve).
3855+ /// The channel value is an input as opposed to using from self, so that this can be used in case of splicing
3856+ /// to checks with new channel value (before being comitted to it).
3857+ #[cfg(splicing)]
3858+ pub fn check_balance_meets_reserve_requirements(&self, balance: u64, channel_value: u64) -> Result<(), ChannelError> {
3859+ if balance == 0 {
3860+ return Ok(());
3861+ }
3862+ let holder_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
3863+ channel_value, self.holder_dust_limit_satoshis);
3864+ if balance < holder_selected_channel_reserve_satoshis {
3865+ return Err(ChannelError::Warn(format!(
3866+ "Balance below reserve mandated by holder, {} vs {}",
3867+ balance, holder_selected_channel_reserve_satoshis,
3868+ )));
3869+ }
3870+ let counterparty_selected_channel_reserve_satoshis = get_v2_channel_reserve_satoshis(
3871+ channel_value, self.counterparty_dust_limit_satoshis);
3872+ if balance < counterparty_selected_channel_reserve_satoshis {
3873+ return Err(ChannelError::Warn(format!(
3874+ "Balance below reserve mandated by counterparty, {} vs {}",
3875+ balance, counterparty_selected_channel_reserve_satoshis,
3876+ )));
3877+ }
3878+ Ok(())
3879+ }
3880+
38313881 /// Get the commitment tx fee for the local's (i.e. our) next commitment transaction based on the
38323882 /// number of pending HTLCs that are on track to be in our next commitment tx.
38333883 ///
@@ -4290,6 +4340,38 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
42904340 self.channel_transaction_parameters = channel_transaction_parameters;
42914341 self.get_initial_counterparty_commitment_signature(logger)
42924342 }
4343+
4344+ /// Get the splice message that can be sent during splice initiation.
4345+ #[cfg(splicing)]
4346+ pub fn get_splice_init(&self, our_funding_contribution_satoshis: i64,
4347+ funding_feerate_perkw: u32, locktime: u32,
4348+ ) -> msgs::SpliceInit {
4349+ // Reuse the existing funding pubkey, in spite of the channel value changing
4350+ // (though at this point we don't know the new value yet, due tue the optional counterparty contribution)
4351+ // Note that channel_keys_id is supposed NOT to change
4352+ let funding_pubkey = self.get_holder_pubkeys().funding_pubkey.clone();
4353+ msgs::SpliceInit {
4354+ channel_id: self.channel_id,
4355+ funding_contribution_satoshis: our_funding_contribution_satoshis,
4356+ funding_feerate_perkw,
4357+ locktime,
4358+ funding_pubkey,
4359+ require_confirmed_inputs: None,
4360+ }
4361+ }
4362+
4363+ /// Get the splice_ack message that can be sent in response to splice initiation.
4364+ #[cfg(splicing)]
4365+ pub fn get_splice_ack(&self, our_funding_contribution_satoshis: i64) -> msgs::SpliceAck {
4366+ // Reuse the existing funding pubkey, in spite of the channel value changing
4367+ let funding_pubkey = self.get_holder_pubkeys().funding_pubkey;
4368+ msgs::SpliceAck {
4369+ channel_id: self.channel_id,
4370+ funding_contribution_satoshis: our_funding_contribution_satoshis,
4371+ funding_pubkey,
4372+ require_confirmed_inputs: None,
4373+ }
4374+ }
42934375}
42944376
42954377// Internal utility functions for channels
@@ -4414,6 +4496,9 @@ pub(super) struct FundedChannel<SP: Deref> where SP::Target: SignerProvider {
44144496 pub context: ChannelContext<SP>,
44154497 pub interactive_tx_signing_session: Option<InteractiveTxSigningSession>,
44164498 holder_commitment_point: HolderCommitmentPoint,
4499+ /// Info about an in-progress, pending splice (if any), on the pre-splice channel
4500+ #[cfg(splicing)]
4501+ pending_splice_pre: Option<PendingSplice>,
44174502}
44184503
44194504#[cfg(any(test, fuzzing))]
@@ -8028,6 +8113,135 @@ impl<SP: Deref> FundedChannel<SP> where
80288113 }
80298114 }
80308115
8116+ /// Initiate splicing
8117+ #[cfg(splicing)]
8118+ pub fn splice_channel(&mut self, our_funding_contribution_satoshis: i64,
8119+ our_funding_inputs: Vec<(TxIn, Transaction)>, funding_feerate_perkw: u32, locktime: u32,
8120+ ) -> Result<msgs::SpliceInit, ChannelError> {
8121+ // Check if a splice has been initiated already.
8122+ // Note: this could be handled more nicely, and support multiple outstanding splice's, the incoming splice_ack matters anyways.
8123+ if let Some(splice_info) = &self.pending_splice_pre {
8124+ return Err(ChannelError::Warn(format!(
8125+ "Channel has already a splice pending, contribution {}", splice_info.our_funding_contribution
8126+ )));
8127+ }
8128+
8129+ if !matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
8130+ return Err(ChannelError::Warn(format!("Cannot initiate splicing, as channel is not Ready")));
8131+ }
8132+
8133+ let pre_channel_value = self.context.get_value_satoshis();
8134+ // Sanity check: capacity cannot decrease below 0
8135+ if (pre_channel_value as i64).saturating_add(our_funding_contribution_satoshis) < 0 {
8136+ return Err(ChannelError::Warn(format!(
8137+ "Post-splicing channel value cannot be negative. It was {} + {}",
8138+ pre_channel_value, our_funding_contribution_satoshis
8139+ )));
8140+ }
8141+
8142+ if our_funding_contribution_satoshis < 0 {
8143+ return Err(ChannelError::Warn(format!(
8144+ "TODO(splicing): Splice-out not supported, only splice in, contribution {}",
8145+ our_funding_contribution_satoshis,
8146+ )));
8147+ }
8148+
8149+ // Note: post-splice channel value is not yet known at this point, counterpary contribution is not known
8150+ // (Cannot test for miminum required post-splice channel value)
8151+
8152+ // Check that inputs are sufficient to cover our contribution
8153+ let sum_input: i64 = our_funding_inputs.into_iter().map(
8154+ |(txin, tx)| tx.output.get(txin.previous_output.vout as usize).map(|tx| tx.value.to_sat() as i64).unwrap_or(0)
8155+ ).sum();
8156+ if sum_input < our_funding_contribution_satoshis {
8157+ return Err(ChannelError::Warn(format!(
8158+ "Provided inputs are insufficient for our contribution, {} {}",
8159+ sum_input, our_funding_contribution_satoshis,
8160+ )));
8161+ }
8162+
8163+ self.pending_splice_pre = Some(PendingSplice {
8164+ our_funding_contribution: our_funding_contribution_satoshis,
8165+ });
8166+
8167+ let msg = self.context.get_splice_init(our_funding_contribution_satoshis, funding_feerate_perkw, locktime);
8168+ Ok(msg)
8169+ }
8170+
8171+ /// Handle splice_init
8172+ #[cfg(splicing)]
8173+ pub fn splice_init(&mut self, msg: &msgs::SpliceInit) -> Result<msgs::SpliceAck, ChannelError> {
8174+ let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
8175+ // TODO(splicing): Currently not possible to contribute on the splicing-acceptor side
8176+ let our_funding_contribution_satoshis = 0i64;
8177+
8178+ // Check if a splice has been initiated already.
8179+ // Note: this could be handled more nicely, and support multiple outstanding splice's, the incoming splice_ack matters anyways.
8180+ if let Some(splice_info) = &self.pending_splice_pre {
8181+ return Err(ChannelError::Warn(format!(
8182+ "Channel has already a splice pending, contribution {}", splice_info.our_funding_contribution,
8183+ )));
8184+ }
8185+
8186+ if !matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
8187+ return Err(ChannelError::Warn(format!("Splicing requested on a channel that is not Ready")));
8188+ }
8189+
8190+ let pre_channel_value = self.context.get_value_satoshis();
8191+ // Sanity check: capacity cannot decrease below 0
8192+ if (pre_channel_value as i64)
8193+ .saturating_add(their_funding_contribution_satoshis)
8194+ .saturating_add(our_funding_contribution_satoshis) < 0
8195+ {
8196+ return Err(ChannelError::Warn(format!(
8197+ "Post-splicing channel value cannot be negative. It was {} + {} + {}",
8198+ pre_channel_value, their_funding_contribution_satoshis, our_funding_contribution_satoshis,
8199+ )));
8200+ }
8201+
8202+ if their_funding_contribution_satoshis.saturating_add(our_funding_contribution_satoshis) < 0 {
8203+ return Err(ChannelError::Warn(format!(
8204+ "Splice-out not supported, only splice in, relative {} + {}",
8205+ their_funding_contribution_satoshis, our_funding_contribution_satoshis,
8206+ )));
8207+ }
8208+
8209+ let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, their_funding_contribution_satoshis, our_funding_contribution_satoshis);
8210+ let post_balance = PendingSplice::add_checked(self.context.value_to_self_msat, our_funding_contribution_satoshis);
8211+ // Early check for reserve requirement, assuming maximum balance of full channel value
8212+ // This will also be checked later at tx_complete
8213+ let _res = self.context.check_balance_meets_reserve_requirements(post_balance, post_channel_value)?;
8214+
8215+ // TODO(splicing): Store msg.funding_pubkey
8216+ // TODO(splicing): Apply start of splice (splice_start)
8217+
8218+ let splice_ack_msg = self.context.get_splice_ack(our_funding_contribution_satoshis);
8219+ // TODO(splicing): start interactive funding negotiation
8220+ Ok(splice_ack_msg)
8221+ }
8222+
8223+ /// Handle splice_ack
8224+ #[cfg(splicing)]
8225+ pub fn splice_ack(&mut self, msg: &msgs::SpliceAck) -> Result<(), ChannelError> {
8226+ let their_funding_contribution_satoshis = msg.funding_contribution_satoshis;
8227+
8228+ // check if splice is pending
8229+ let pending_splice = if let Some(pending_splice) = &self.pending_splice_pre {
8230+ pending_splice
8231+ } else {
8232+ return Err(ChannelError::Warn(format!("Channel is not in pending splice")));
8233+ };
8234+
8235+ let our_funding_contribution = pending_splice.our_funding_contribution;
8236+
8237+ let pre_channel_value = self.context.get_value_satoshis();
8238+ let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution_satoshis);
8239+ let post_balance = PendingSplice::add_checked(self.context.value_to_self_msat, our_funding_contribution);
8240+ // Early check for reserve requirement, assuming maximum balance of full channel value
8241+ // This will also be checked later at tx_complete
8242+ let _res = self.context.check_balance_meets_reserve_requirements(post_balance, post_channel_value)?;
8243+ Ok(())
8244+ }
80318245
80328246 // Send stuff to our remote peers:
80338247
@@ -8722,6 +8936,8 @@ impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {
87228936 context: self.context,
87238937 interactive_tx_signing_session: None,
87248938 holder_commitment_point,
8939+ #[cfg(splicing)]
8940+ pending_splice_pre: None,
87258941 };
87268942
87278943 let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some()
@@ -8987,6 +9203,8 @@ impl<SP: Deref> InboundV1Channel<SP> where SP::Target: SignerProvider {
89879203 context: self.context,
89889204 interactive_tx_signing_session: None,
89899205 holder_commitment_point,
9206+ #[cfg(splicing)]
9207+ pending_splice_pre: None,
89909208 };
89919209 let need_channel_ready = channel.check_get_channel_ready(0, logger).is_some()
89929210 || channel.context.signer_pending_channel_ready;
@@ -9348,6 +9566,8 @@ impl<SP: Deref> PendingV2Channel<SP> where SP::Target: SignerProvider {
93489566 context: self.context,
93499567 interactive_tx_signing_session: Some(signing_session),
93509568 holder_commitment_point,
9569+ #[cfg(splicing)]
9570+ pending_splice_pre: None,
93519571 };
93529572
93539573 Ok(channel)
@@ -10428,6 +10648,8 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
1042810648 },
1042910649 interactive_tx_signing_session: None,
1043010650 holder_commitment_point,
10651+ #[cfg(splicing)]
10652+ pending_splice_pre: None,
1043110653 })
1043210654 }
1043310655}
@@ -12210,4 +12432,69 @@ mod tests {
1221012432 assert_eq!(node_a_chan.context.channel_state, ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::THEIR_CHANNEL_READY));
1221112433 assert!(node_a_chan.check_get_channel_ready(0, &&logger).is_some());
1221212434 }
12435+
12436+ #[cfg(all(test, splicing))]
12437+ fn get_pre_and_post(pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64) -> (u64, u64) {
12438+ use crate::ln::channel::PendingSplice;
12439+
12440+ let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution);
12441+ (pre_channel_value, post_channel_value)
12442+ }
12443+
12444+ #[cfg(all(test, splicing))]
12445+ #[test]
12446+ fn test_splice_compute_post_value() {
12447+ {
12448+ // increase, small amounts
12449+ let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 6_000, 0);
12450+ assert_eq!(pre_channel_value, 9_000);
12451+ assert_eq!(post_channel_value, 15_000);
12452+ }
12453+ {
12454+ // increase, small amounts
12455+ let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 4_000, 2_000);
12456+ assert_eq!(pre_channel_value, 9_000);
12457+ assert_eq!(post_channel_value, 15_000);
12458+ }
12459+ {
12460+ // increase, small amounts
12461+ let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, 0, 6_000);
12462+ assert_eq!(pre_channel_value, 9_000);
12463+ assert_eq!(post_channel_value, 15_000);
12464+ }
12465+ {
12466+ // decrease, small amounts
12467+ let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -6_000, 0);
12468+ assert_eq!(pre_channel_value, 15_000);
12469+ assert_eq!(post_channel_value, 9_000);
12470+ }
12471+ {
12472+ // decrease, small amounts
12473+ let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, -4_000, -2_000);
12474+ assert_eq!(pre_channel_value, 15_000);
12475+ assert_eq!(post_channel_value, 9_000);
12476+ }
12477+ {
12478+ // increase and decrease
12479+ let (pre_channel_value, post_channel_value) = get_pre_and_post(15_000, 4_000, -2_000);
12480+ assert_eq!(pre_channel_value, 15_000);
12481+ assert_eq!(post_channel_value, 17_000);
12482+ }
12483+ let base2: u64 = 2;
12484+ let huge63i3 = (base2.pow(63) - 3) as i64;
12485+ assert_eq!(huge63i3, 9223372036854775805);
12486+ assert_eq!(-huge63i3, -9223372036854775805);
12487+ {
12488+ // increase, large amount
12489+ let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, 3);
12490+ assert_eq!(pre_channel_value, 9_000);
12491+ assert_eq!(post_channel_value, 9223372036854784807);
12492+ }
12493+ {
12494+ // increase, large amounts
12495+ let (pre_channel_value, post_channel_value) = get_pre_and_post(9_000, huge63i3, huge63i3);
12496+ assert_eq!(pre_channel_value, 9_000);
12497+ assert_eq!(post_channel_value, 9223372036854784807);
12498+ }
12499+ }
1221312500}
0 commit comments