From 3023e2f881a7fea6254804aeb64cd82c168742e9 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Thu, 4 Sep 2025 10:09:18 -0700 Subject: [PATCH 01/10] Don't process alternative funding confirmations duplicatively Otherwise we'll hit an assert that we do not already have an alternative funding confirmation when reprocessing the transaction. --- lightning/src/chain/channelmonitor.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index b34016befce..d0aa0eedf85 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -5164,6 +5164,10 @@ impl ChannelMonitorImpl { let txid = tx.compute_txid(); log_trace!(logger, "Transaction {} confirmed in block {}", txid , block_hash); // If a transaction has already been confirmed, ensure we don't bother processing it duplicatively. + if self.alternative_funding_confirmed.map(|(alternative_funding_txid, _)| alternative_funding_txid == txid).unwrap_or(false) { + log_debug!(logger, "Skipping redundant processing of funding-spend tx {} as it was previously confirmed", txid); + continue 'tx_iter; + } if Some(txid) == self.funding_spend_confirmed { log_debug!(logger, "Skipping redundant processing of funding-spend tx {} as it was previously confirmed", txid); continue 'tx_iter; From c40d1e8a76431909d812676bff820f1bef1367bc Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Thu, 4 Sep 2025 10:09:20 -0700 Subject: [PATCH 02/10] Update OnchainTxHandler channel parameters on renegotiated funding locked The `ChannelMonitor` now tracks its own set of channel parameters, but in the event they change after a splice, we want to ensure they are updated accordingly at the `OnchainTxHandler` level as well in case the user downgrades after a locked splice has already occurred. --- lightning/src/chain/channelmonitor.rs | 1 + lightning/src/chain/onchaintx.rs | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index d0aa0eedf85..863439b0b8d 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -4049,6 +4049,7 @@ impl ChannelMonitorImpl { mem::swap(&mut self.funding, &mut new_funding); self.onchain_tx_handler.update_after_renegotiated_funding_locked( + self.funding.channel_parameters.clone(), self.funding.current_holder_commitment_tx.clone(), self.funding.prev_holder_commitment_tx.clone(), ); diff --git a/lightning/src/chain/onchaintx.rs b/lightning/src/chain/onchaintx.rs index 4a35c7b7723..f7f9abf8ab7 100644 --- a/lightning/src/chain/onchaintx.rs +++ b/lightning/src/chain/onchaintx.rs @@ -1236,11 +1236,14 @@ impl OnchainTxHandler { self.prev_holder_commitment = Some(replace(&mut self.holder_commitment, tx)); } - /// Replaces the current/prev holder commitment transactions spending the currently confirmed - /// funding outpoint with those spending the new funding outpoint. + /// Replaces all the data pertaining to the currently locked funding transaction after a new + /// funding transaction has been renegotiated and locked. pub(crate) fn update_after_renegotiated_funding_locked( - &mut self, current: HolderCommitmentTransaction, prev: Option, + &mut self, channel_parameters: ChannelTransactionParameters, + current: HolderCommitmentTransaction, prev: Option, ) { + self.channel_value_satoshis = channel_parameters.channel_value_satoshis; + self.channel_transaction_parameters = channel_parameters; self.holder_commitment = current; self.prev_holder_commitment = prev; } From ea42df4c5dd88fcce7d99b7b52770e0ab41a790f Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Thu, 4 Sep 2025 10:09:21 -0700 Subject: [PATCH 03/10] Prune HTLC sources from pending funding scopes We only need to track the HTLC sources for the previous and current counterparty commitments. --- lightning/src/chain/channelmonitor.rs | 41 ++++++++++++++++----------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 863439b0b8d..9ff58ab7c4e 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -3399,26 +3399,35 @@ impl ChannelMonitorImpl { // Prune HTLCs from the previous counterparty commitment tx so we don't generate failure/fulfill // events for now-revoked/fulfilled HTLCs. - if let Some(txid) = self.funding.prev_counterparty_commitment_txid.take() { - if self.funding.current_counterparty_commitment_txid.unwrap() != txid { - let cur_claimables = self.funding.counterparty_claimable_outpoints.get( - &self.funding.current_counterparty_commitment_txid.unwrap()).unwrap(); - for (_, ref source_opt) in self.funding.counterparty_claimable_outpoints.get(&txid).unwrap() { - if let Some(source) = source_opt { - if !cur_claimables.iter() - .any(|(_, cur_source_opt)| cur_source_opt == source_opt) - { - self.counterparty_fulfilled_htlcs.remove(&SentHTLCId::from_source(source)); + let mut removed_fulfilled_htlcs = false; + let prune_htlc_sources = |funding: &mut FundingScope| { + if let Some(txid) = funding.prev_counterparty_commitment_txid.take() { + if funding.current_counterparty_commitment_txid.unwrap() != txid { + let cur_claimables = funding.counterparty_claimable_outpoints.get( + &funding.current_counterparty_commitment_txid.unwrap()).unwrap(); + // We only need to remove fulfilled HTLCs once for the first `FundingScope` we + // come across since all `FundingScope`s share the same set of HTLC sources. + if !removed_fulfilled_htlcs { + for (_, ref source_opt) in funding.counterparty_claimable_outpoints.get(&txid).unwrap() { + if let Some(source) = source_opt { + if !cur_claimables.iter() + .any(|(_, cur_source_opt)| cur_source_opt == source_opt) + { + self.counterparty_fulfilled_htlcs.remove(&SentHTLCId::from_source(source)); + } + } } + removed_fulfilled_htlcs = true; } + for &mut (_, ref mut source_opt) in funding.counterparty_claimable_outpoints.get_mut(&txid).unwrap() { + *source_opt = None; + } + } else { + assert!(cfg!(fuzzing), "Commitment txids are unique outside of fuzzing, where hashes can collide"); } - for &mut (_, ref mut source_opt) in self.funding.counterparty_claimable_outpoints.get_mut(&txid).unwrap() { - *source_opt = None; - } - } else { - assert!(cfg!(fuzzing), "Commitment txids are unique outside of fuzzing, where hashes can collide"); } - } + }; + core::iter::once(&mut self.funding).chain(&mut self.pending_funding).for_each(prune_htlc_sources); if !self.payment_preimages.is_empty() { let min_idx = self.get_min_seen_secret(); From d4bba8a054c68e69df2b2f7d045b881003c8229e Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Thu, 4 Sep 2025 10:09:21 -0700 Subject: [PATCH 04/10] Fail interactive-tx negotiation on abort This commit reworks all interactive transaction construction methods to mark the negotiation as failed upon a local/remote `TxAbort`, ensuring the `InteractiveTxConstructor` is consumed. Along the way, we refactor the handling of `tx_complete` such that we only have a single call into the `Channel` from the `ChannelManager`. --- lightning/src/ln/channel.rs | 248 ++++++++++++++++++++++++----- lightning/src/ln/channelmanager.rs | 168 +++++-------------- lightning/src/ln/interactivetxs.rs | 56 +------ lightning/src/ln/splicing_tests.rs | 8 +- 4 files changed, 252 insertions(+), 228 deletions(-) diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 1065803fe76..c14a571afb6 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -63,12 +63,11 @@ use crate::ln::funding::FundingTxInput; #[cfg(splicing)] use crate::ln::funding::SpliceContribution; #[cfg(splicing)] +use crate::ln::interactivetxs::calculate_change_output_value; use crate::ln::interactivetxs::{ - calculate_change_output_value, AbortReason, InteractiveTxMessageSend, -}; -use crate::ln::interactivetxs::{ - get_output_weight, InteractiveTxConstructor, InteractiveTxConstructorArgs, - InteractiveTxSigningSession, SharedOwnedInput, SharedOwnedOutput, TX_COMMON_FIELDS_WEIGHT, + get_output_weight, AbortReason, HandleTxCompleteValue, InteractiveTxConstructor, + InteractiveTxConstructorArgs, InteractiveTxMessageSend, InteractiveTxSigningSession, + SharedOwnedInput, SharedOwnedOutput, TX_COMMON_FIELDS_WEIGHT, }; use crate::ln::msgs; use crate::ln::msgs::{ClosingSigned, ClosingSignedFeeRange, DecodeError, OnionErrorPacket}; @@ -1597,14 +1596,6 @@ where } } - pub fn as_unfunded_v2_mut(&mut self) -> Option<&mut PendingV2Channel> { - if let ChannelPhase::UnfundedV2(channel) = &mut self.phase { - Some(channel) - } else { - None - } - } - #[rustfmt::skip] pub fn signer_maybe_unblocked( &mut self, chain_hash: ChainHash, logger: &L, @@ -1739,7 +1730,7 @@ where } } - pub fn interactive_tx_constructor_mut(&mut self) -> Option<&mut InteractiveTxConstructor> { + fn interactive_tx_constructor_mut(&mut self) -> Option<&mut InteractiveTxConstructor> { match &mut self.phase { ChannelPhase::UnfundedV2(chan) => chan.interactive_tx_constructor.as_mut(), #[cfg(splicing)] @@ -1748,6 +1739,195 @@ where } } + fn fail_interactive_tx_negotiation( + &mut self, reason: AbortReason, logger: &L, + ) -> msgs::TxAbort + where + L::Target: Logger, + { + let logger = WithChannelContext::from(logger, &self.context(), None); + log_info!(logger, "Failed interactive transaction negotiation: {reason}"); + + let _interactive_tx_constructor = match &mut self.phase { + ChannelPhase::Undefined => unreachable!(), + ChannelPhase::UnfundedOutboundV1(_) | ChannelPhase::UnfundedInboundV1(_) => None, + ChannelPhase::UnfundedV2(pending_v2_channel) => { + pending_v2_channel.interactive_tx_constructor.take() + }, + #[cfg(not(splicing))] + ChannelPhase::Funded(_) => unreachable!(), + #[cfg(splicing)] + ChannelPhase::Funded(funded_channel) => funded_channel + .pending_splice + .as_mut() + .and_then(|pending_splice| pending_splice.funding_negotiation.take()) + .and_then(|funding_negotiation| { + if let FundingNegotiation::ConstructingTransaction( + _, + interactive_tx_constructor, + ) = funding_negotiation + { + Some(interactive_tx_constructor) + } else { + None + } + }), + }; + + reason.into_tx_abort_msg(self.context().channel_id) + } + + pub fn tx_add_input( + &mut self, msg: &msgs::TxAddInput, logger: &L, + ) -> Result + where + L::Target: Logger, + { + match self.interactive_tx_constructor_mut() { + Some(interactive_tx_constructor) => interactive_tx_constructor.handle_tx_add_input(msg), + None => Err(AbortReason::InternalError( + "Received unexpected interactive transaction negotiation message", + )), + } + .map_err(|abort_reason| self.fail_interactive_tx_negotiation(abort_reason, logger)) + } + + pub fn tx_add_output( + &mut self, msg: &msgs::TxAddOutput, logger: &L, + ) -> Result + where + L::Target: Logger, + { + match self.interactive_tx_constructor_mut() { + Some(interactive_tx_constructor) => { + interactive_tx_constructor.handle_tx_add_output(msg) + }, + None => Err(AbortReason::InternalError( + "Received unexpected interactive transaction negotiation message", + )), + } + .map_err(|abort_reason| self.fail_interactive_tx_negotiation(abort_reason, logger)) + } + + pub fn tx_remove_input( + &mut self, msg: &msgs::TxRemoveInput, logger: &L, + ) -> Result + where + L::Target: Logger, + { + match self.interactive_tx_constructor_mut() { + Some(interactive_tx_constructor) => { + interactive_tx_constructor.handle_tx_remove_input(msg) + }, + None => Err(AbortReason::InternalError( + "Received unexpected interactive transaction negotiation message", + )), + } + .map_err(|abort_reason| self.fail_interactive_tx_negotiation(abort_reason, logger)) + } + + pub fn tx_remove_output( + &mut self, msg: &msgs::TxRemoveOutput, logger: &L, + ) -> Result + where + L::Target: Logger, + { + match self.interactive_tx_constructor_mut() { + Some(interactive_tx_constructor) => { + interactive_tx_constructor.handle_tx_remove_output(msg) + }, + None => Err(AbortReason::InternalError( + "Received unexpected interactive transaction negotiation message", + )), + } + .map_err(|abort_reason| self.fail_interactive_tx_negotiation(abort_reason, logger)) + } + + pub fn tx_complete( + &mut self, msg: &msgs::TxComplete, logger: &L, + ) -> Result<(Option, Option), msgs::TxAbort> + where + L::Target: Logger, + { + let tx_complete_action = match self.interactive_tx_constructor_mut() { + Some(interactive_tx_constructor) => interactive_tx_constructor.handle_tx_complete(msg), + None => Err(AbortReason::InternalError( + "Received unexpected interactive transaction negotiation message", + )), + } + .map_err(|abort_reason| self.fail_interactive_tx_negotiation(abort_reason, logger))?; + + let (interactive_tx_msg_send, negotiation_complete) = match tx_complete_action { + HandleTxCompleteValue::SendTxMessage(interactive_tx_msg_send) => { + (Some(interactive_tx_msg_send), false) + }, + HandleTxCompleteValue::SendTxComplete( + interactive_tx_msg_send, + negotiation_complete, + ) => (Some(interactive_tx_msg_send), negotiation_complete), + HandleTxCompleteValue::NegotiationComplete => (None, true), + }; + if !negotiation_complete { + return Ok((interactive_tx_msg_send, None)); + } + + let commitment_signed = self + .funding_tx_constructed(logger) + .map_err(|abort_reason| self.fail_interactive_tx_negotiation(abort_reason, logger))?; + Ok((interactive_tx_msg_send, Some(commitment_signed))) + } + + pub fn tx_abort( + &mut self, msg: &msgs::TxAbort, logger: &L, + ) -> Result, ChannelError> + where + L::Target: Logger, + { + // This checks for and resets the interactive negotiation state by `take()`ing it from the channel. + // The existence of the `tx_constructor` indicates that we have not moved into the signing + // phase for this interactively constructed transaction and hence we have not exchanged + // `tx_signatures`. Either way, we never close the channel upon receiving a `tx_abort`: + // https://github.com/lightning/bolts/blob/247e83d/02-peer-protocol.md?plain=1#L574-L576 + let should_ack = match &mut self.phase { + ChannelPhase::Undefined => unreachable!(), + ChannelPhase::UnfundedOutboundV1(_) | ChannelPhase::UnfundedInboundV1(_) => { + let err = "Got an unexpected tx_abort message: This is an unfunded channel created with V1 channel establishment"; + return Err(ChannelError::Warn(err.into())); + }, + ChannelPhase::UnfundedV2(pending_v2_channel) => { + pending_v2_channel.interactive_tx_constructor.take().is_some() + }, + #[cfg(not(splicing))] + ChannelPhase::Funded(_) => { + let err = "Got an unexpected tx_abort message: This is an funded channel and splicing is not supported"; + return Err(ChannelError::Warn(err.into())); + }, + #[cfg(splicing)] + ChannelPhase::Funded(funded_channel) => funded_channel + .pending_splice + .as_mut() + .and_then(|pending_splice| pending_splice.funding_negotiation.take()) + .is_some(), + }; + + // NOTE: Since at this point we have not sent a `tx_abort` message for this negotiation + // previously (tx_constructor was `Some`), we need to echo back a tx_abort message according + // to the spec: + // https://github.com/lightning/bolts/blob/247e83d/02-peer-protocol.md?plain=1#L560-L561 + // For rationale why we echo back `tx_abort`: + // https://github.com/lightning/bolts/blob/247e83d/02-peer-protocol.md?plain=1#L578-L580 + Ok(should_ack.then(|| { + let logger = WithChannelContext::from(logger, &self.context(), None); + let reason = + types::string::UntrustedString(String::from_utf8_lossy(&msg.data).to_string()); + log_info!(logger, "Counterparty failed interactive transaction negotiation: {reason}"); + msgs::TxAbort { + channel_id: msg.channel_id, + data: "Acknowledged tx_abort".to_string().into_bytes(), + } + })) + } + #[rustfmt::skip] pub fn funding_signed( &mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L @@ -1780,9 +1960,9 @@ where result.map(|monitor| (self.as_funded_mut().expect("Channel should be funded"), monitor)) } - pub fn funding_tx_constructed( + fn funding_tx_constructed( &mut self, logger: &L, - ) -> Result + ) -> Result where L::Target: Logger, { @@ -1837,17 +2017,15 @@ where } } - return Err(msgs::TxAbort { - channel_id: chan.context.channel_id(), - data: "Got a tx_complete message in an invalid state".to_owned().into_bytes(), - }); + return Err(AbortReason::InternalError( + "Got a tx_complete message in an invalid state", + )); }, _ => { debug_assert!(false); - return Err(msgs::TxAbort { - channel_id: self.context().channel_id(), - data: "Got a tx_complete message in an invalid phase".to_owned().into_bytes(), - }); + return Err(AbortReason::InternalError( + "Got a tx_complete message in an invalid phase", + )); }, } } @@ -5855,7 +6033,7 @@ where fn funding_tx_constructed( &mut self, funding: &mut FundingScope, signing_session: &mut InteractiveTxSigningSession, is_splice: bool, holder_commitment_transaction_number: u64, logger: &L - ) -> Result + ) -> Result where L::Target: Logger { @@ -5864,10 +6042,7 @@ where for (idx, outp) in signing_session.unsigned_tx().outputs().enumerate() { if outp.script_pubkey() == &expected_spk && outp.value() == funding.get_value_satoshis() { if output_index.is_some() { - return Err(msgs::TxAbort { - channel_id: self.channel_id(), - data: "Multiple outputs matched the expected script and value".to_owned().into_bytes(), - }); + return Err(AbortReason::DuplicateFundingOutput); } output_index = Some(idx as u16); } @@ -5875,10 +6050,7 @@ where let outpoint = if let Some(output_index) = output_index { OutPoint { txid: signing_session.unsigned_tx().compute_txid(), index: output_index } } else { - return Err(msgs::TxAbort { - channel_id: self.channel_id(), - data: "No output matched the funding script_pubkey".to_owned().into_bytes(), - }); + return Err(AbortReason::MissingFundingOutput); }; funding .channel_transaction_parameters.funding_outpoint = Some(outpoint); @@ -5892,10 +6064,7 @@ where self.counterparty_next_commitment_transaction_number, ); // TODO(splicing) Forced error, as the use case is not complete - return Err(msgs::TxAbort { - channel_id: self.channel_id(), - data: "Splicing not yet supported".to_owned().into_bytes(), - }); + return Err(AbortReason::InternalError("Splicing not yet supported")); } else { self.assert_no_commitment_advancement(holder_commitment_transaction_number, "initial commitment_signed"); } @@ -5906,10 +6075,7 @@ where // TODO(splicing): Support async signing None => { funding.channel_transaction_parameters.funding_outpoint = None; - return Err(msgs::TxAbort { - channel_id: self.channel_id(), - data: "Failed to get signature for commitment_signed".to_owned().into_bytes(), - }); + return Err(AbortReason::InternalError("Failed to compute commitment_signed signatures")); }, }; diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index dfc10e84a2a..90e6a309833 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -67,7 +67,7 @@ use crate::ln::channel_state::ChannelDetails; #[cfg(splicing)] use crate::ln::funding::SpliceContribution; use crate::ln::inbound_payment; -use crate::ln::interactivetxs::{HandleTxCompleteResult, InteractiveTxMessageSendResult}; +use crate::ln::interactivetxs::InteractiveTxMessageSend; use crate::ln::msgs; use crate::ln::msgs::{ BaseMessageHandler, ChannelMessageHandler, CommitmentUpdate, DecodeError, LightningError, @@ -9869,7 +9869,9 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ } } - fn internal_tx_msg) -> Option>( + fn internal_tx_msg< + HandleTxMsgFn: Fn(&mut Channel) -> Result, + >( &self, counterparty_node_id: &PublicKey, channel_id: ChannelId, tx_msg_handler: HandleTxMsgFn, ) -> Result<(), MsgHandleErrInternal> { @@ -9887,10 +9889,12 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ hash_map::Entry::Occupied(mut chan_entry) => { let channel = chan_entry.get_mut(); let msg_send_event = match tx_msg_handler(channel) { - Some(msg_send_event) => msg_send_event, - None => { - let err = ChannelError::Warn("Received unexpected interactive transaction negotiation message".to_owned()); - return Err(MsgHandleErrInternal::from_chan_no_close(err, channel_id)) + Ok(msg_send) => msg_send.into_msg_send_event(*counterparty_node_id), + Err(tx_abort) => { + MessageSendEvent::SendTxAbort { + node_id: *counterparty_node_id, + msg: tx_abort, + } }, }; peer_state.pending_msg_events.push(msg_send_event); @@ -9909,15 +9913,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ &self, counterparty_node_id: PublicKey, msg: &msgs::TxAddInput, ) -> Result<(), MsgHandleErrInternal> { self.internal_tx_msg(&counterparty_node_id, msg.channel_id, |channel: &mut Channel| { - Some( - InteractiveTxMessageSendResult( - channel - .interactive_tx_constructor_mut()? - .handle_tx_add_input(msg) - .map_err(|reason| reason.into_tx_abort_msg(msg.channel_id)), - ) - .into_msg_send_event(counterparty_node_id), - ) + channel.tx_add_input(msg, &self.logger) }) } @@ -9925,15 +9921,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ &self, counterparty_node_id: PublicKey, msg: &msgs::TxAddOutput, ) -> Result<(), MsgHandleErrInternal> { self.internal_tx_msg(&counterparty_node_id, msg.channel_id, |channel: &mut Channel| { - Some( - InteractiveTxMessageSendResult( - channel - .interactive_tx_constructor_mut()? - .handle_tx_add_output(msg) - .map_err(|reason| reason.into_tx_abort_msg(msg.channel_id)), - ) - .into_msg_send_event(counterparty_node_id), - ) + channel.tx_add_output(msg, &self.logger) }) } @@ -9941,15 +9929,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ &self, counterparty_node_id: PublicKey, msg: &msgs::TxRemoveInput, ) -> Result<(), MsgHandleErrInternal> { self.internal_tx_msg(&counterparty_node_id, msg.channel_id, |channel: &mut Channel| { - Some( - InteractiveTxMessageSendResult( - channel - .interactive_tx_constructor_mut()? - .handle_tx_remove_input(msg) - .map_err(|reason| reason.into_tx_abort_msg(msg.channel_id)), - ) - .into_msg_send_event(counterparty_node_id), - ) + channel.tx_remove_input(msg, &self.logger) }) } @@ -9957,15 +9937,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ &self, counterparty_node_id: PublicKey, msg: &msgs::TxRemoveOutput, ) -> Result<(), MsgHandleErrInternal> { self.internal_tx_msg(&counterparty_node_id, msg.channel_id, |channel: &mut Channel| { - Some( - InteractiveTxMessageSendResult( - channel - .interactive_tx_constructor_mut()? - .handle_tx_remove_output(msg) - .map_err(|reason| reason.into_tx_abort_msg(msg.channel_id)), - ) - .into_msg_send_event(counterparty_node_id), - ) + channel.tx_remove_output(msg, &self.logger) }) } @@ -9983,57 +9955,34 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ let peer_state = &mut *peer_state_lock; match peer_state.channel_by_id.entry(msg.channel_id) { hash_map::Entry::Occupied(mut chan_entry) => { - let (msg_send_event_opt, negotiation_complete) = match chan_entry.get_mut().interactive_tx_constructor_mut() { - Some(interactive_tx_constructor) => { - HandleTxCompleteResult( - interactive_tx_constructor - .handle_tx_complete(msg) - .map_err(|reason| reason.into_tx_abort_msg(msg.channel_id)), - ) - .into_msg_send_event(counterparty_node_id) + let chan = chan_entry.get_mut(); + match chan.tx_complete(msg, &self.logger) { + Ok((interactive_tx_msg_send, commitment_signed)) => { + if let Some(interactive_tx_msg_send) = interactive_tx_msg_send { + let msg_send_event = interactive_tx_msg_send.into_msg_send_event(counterparty_node_id); + peer_state.pending_msg_events.push(msg_send_event); + }; + if let Some(commitment_signed) = commitment_signed { + peer_state.pending_msg_events.push(MessageSendEvent::UpdateHTLCs { + node_id: counterparty_node_id, + channel_id: msg.channel_id, + updates: CommitmentUpdate { + commitment_signed: vec![commitment_signed], + update_add_htlcs: vec![], + update_fulfill_htlcs: vec![], + update_fail_htlcs: vec![], + update_fail_malformed_htlcs: vec![], + update_fee: None, + }, + }); + } }, - None => { - let err = ChannelError::Warn("Received unexpected tx_complete message".to_owned()); - return Err(MsgHandleErrInternal::from_chan_no_close(err, msg.channel_id)) + Err(tx_abort) => { + peer_state.pending_msg_events.push(MessageSendEvent::SendTxAbort { + node_id: counterparty_node_id, + msg: tx_abort, + }); }, - }; - if let Some(msg_send_event) = msg_send_event_opt { - peer_state.pending_msg_events.push(msg_send_event); - }; - if negotiation_complete { - let commitment_signed = match chan_entry - .get_mut() - .funding_tx_constructed(&self.logger) - { - Ok(commitment_signed) => commitment_signed, - Err(tx_abort) => { - if chan_entry.get().is_funded() { - peer_state.pending_msg_events.push(MessageSendEvent::SendTxAbort { - node_id: counterparty_node_id, - msg: tx_abort, - }); - return Ok(()); - } else { - let msg = String::from_utf8(tx_abort.data) - .expect("tx_abort data should contain valid UTF-8"); - let reason = ClosureReason::ProcessingError { err: msg.clone() }; - let err = ChannelError::Close((msg, reason)); - try_channel_entry!(self, peer_state, Err(err), chan_entry) - } - }, - }; - peer_state.pending_msg_events.push(MessageSendEvent::UpdateHTLCs { - node_id: counterparty_node_id, - channel_id: msg.channel_id, - updates: CommitmentUpdate { - commitment_signed: vec![commitment_signed], - update_add_htlcs: vec![], - update_fulfill_htlcs: vec![], - update_fail_htlcs: vec![], - update_fail_malformed_htlcs: vec![], - update_fee: None, - }, - }); } Ok(()) }, @@ -10105,41 +10054,8 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ let peer_state = &mut *peer_state_lock; match peer_state.channel_by_id.entry(msg.channel_id) { hash_map::Entry::Occupied(mut chan_entry) => { - let tx_constructor = match chan_entry.get_mut().as_unfunded_v2_mut() { - Some(chan) => &mut chan.interactive_tx_constructor, - None => if chan_entry.get().is_funded() { - // TODO(splicing)/TODO(RBF): We'll also be doing interactive tx construction - // for a "Channel::Funded" when we want to bump the fee on an interactively - // constructed funding tx or during splicing. For now we send an error as we would - // never ack an RBF attempt or a splice for now: - try_channel_entry!(self, peer_state, Err(ChannelError::Warn( - "Got an unexpected tx_abort message: After initial funding transaction is signed, \ - splicing and RBF attempts of interactive funding transactions are not supported yet so \ - we don't have any negotiation in progress".into(), - )), chan_entry) - } else { - try_channel_entry!(self, peer_state, Err(ChannelError::Warn( - "Got an unexpected tx_abort message: This is an unfunded channel created with V1 channel \ - establishment".into(), - )), chan_entry) - }, - }; - // This checks for and resets the interactive negotiation state by `take()`ing it from the channel. - // The existence of the `tx_constructor` indicates that we have not moved into the signing - // phase for this interactively constructed transaction and hence we have not exchanged - // `tx_signatures`. Either way, we never close the channel upon receiving a `tx_abort`: - // https://github.com/lightning/bolts/blob/247e83d/02-peer-protocol.md?plain=1#L574-L576 - if tx_constructor.take().is_some() { - let msg = msgs::TxAbort { - channel_id: msg.channel_id, - data: "Acknowledged tx_abort".to_string().into_bytes(), - }; - // NOTE: Since at this point we have not sent a `tx_abort` message for this negotiation - // previously (tx_constructor was `Some`), we need to echo back a tx_abort message according - // to the spec: - // https://github.com/lightning/bolts/blob/247e83d/02-peer-protocol.md?plain=1#L560-L561 - // For rationale why we echo back `tx_abort`: - // https://github.com/lightning/bolts/blob/247e83d/02-peer-protocol.md?plain=1#L578-L580 + let res = chan_entry.get_mut().tx_abort(msg, &self.logger); + if let Some(msg) = try_channel_entry!(self, peer_state, res, chan_entry) { peer_state.pending_msg_events.push(MessageSendEvent::SendTxAbort { node_id: *counterparty_node_id, msg, diff --git a/lightning/src/ln/interactivetxs.rs b/lightning/src/ln/interactivetxs.rs index ca468012e65..52127732f5f 100644 --- a/lightning/src/ln/interactivetxs.rs +++ b/lightning/src/ln/interactivetxs.rs @@ -89,7 +89,7 @@ impl SerialIdExt for SerialId { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub(crate) enum AbortReason { InvalidStateTransition, UnexpectedCounterpartyMessage, @@ -1852,23 +1852,6 @@ impl InteractiveTxMessageSend { } } -pub(super) struct InteractiveTxMessageSendResult( - pub Result, -); - -impl InteractiveTxMessageSendResult { - pub fn into_msg_send_event(self, counterparty_node_id: PublicKey) -> MessageSendEvent { - match self.0 { - Ok(interactive_tx_msg_send) => { - interactive_tx_msg_send.into_msg_send_event(counterparty_node_id) - }, - Err(tx_abort_msg) => { - MessageSendEvent::SendTxAbort { node_id: counterparty_node_id, msg: tx_abort_msg } - }, - } - } -} - // This macro executes a state machine transition based on a provided action. macro_rules! do_state_transition { ($self: ident, $transition: ident, $msg: expr) => {{ @@ -1901,43 +1884,6 @@ pub(super) enum HandleTxCompleteValue { NegotiationComplete, } -impl HandleTxCompleteValue { - pub fn into_msg_send_event( - self, counterparty_node_id: PublicKey, - ) -> (Option, bool) { - match self { - HandleTxCompleteValue::SendTxMessage(msg) => { - (Some(msg.into_msg_send_event(counterparty_node_id)), false) - }, - HandleTxCompleteValue::SendTxComplete(msg, negotiation_complete) => { - (Some(msg.into_msg_send_event(counterparty_node_id)), negotiation_complete) - }, - HandleTxCompleteValue::NegotiationComplete => (None, true), - } - } -} - -pub(super) struct HandleTxCompleteResult(pub Result); - -impl HandleTxCompleteResult { - pub fn into_msg_send_event( - self, counterparty_node_id: PublicKey, - ) -> (Option, bool) { - match self.0 { - Ok(interactive_tx_msg_send) => { - interactive_tx_msg_send.into_msg_send_event(counterparty_node_id) - }, - Err(tx_abort_msg) => ( - Some(MessageSendEvent::SendTxAbort { - node_id: counterparty_node_id, - msg: tx_abort_msg, - }), - false, - ), - } - } -} - pub(super) struct InteractiveTxConstructorArgs<'a, ES: Deref> where ES::Target: EntropySource, diff --git a/lightning/src/ln/splicing_tests.rs b/lightning/src/ln/splicing_tests.rs index b60903d4c71..bec2f4cad53 100644 --- a/lightning/src/ln/splicing_tests.rs +++ b/lightning/src/ln/splicing_tests.rs @@ -278,14 +278,10 @@ fn test_v1_splice_in() { .node .handle_tx_complete(acceptor_node.node.get_our_node_id(), &tx_complete_msg); let events = initiator_node.node.get_and_clear_pending_msg_events(); - assert_eq!(events.len(), 2); + assert_eq!(events.len(), 1); match events[0] { - MessageSendEvent::SendTxComplete { .. } => {}, - _ => panic!("Unexpected event {:?}", events[0]), - } - match events[1] { MessageSendEvent::SendTxAbort { .. } => {}, - _ => panic!("Unexpected event {:?}", events[1]), + _ => panic!("Unexpected event {:?}", events[0]), } // TODO(splicing): Continue with commitment flow, new tx confirmation, and shutdown From 33079be756d016bb6ad4102b3b2906966d24b18b Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Thu, 4 Sep 2025 10:09:22 -0700 Subject: [PATCH 05/10] Fix incorrect weight estimation for splice shared input The splice shared input weight should always be composed of the base input weight (prevout & sequence), an empty `script_sig` weight, and the multisig channel-type specific witness weight. --- lightning/src/ln/interactivetxs.rs | 9 +++++++-- lightning/src/ln/splicing_tests.rs | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lightning/src/ln/interactivetxs.rs b/lightning/src/ln/interactivetxs.rs index 52127732f5f..563a89466fe 100644 --- a/lightning/src/ln/interactivetxs.rs +++ b/lightning/src/ln/interactivetxs.rs @@ -1639,7 +1639,10 @@ impl InputOwned { fn estimate_input_weight(&self) -> Weight { match self { InputOwned::Single(single) => estimate_input_weight(&single.prev_output), - InputOwned::Shared(shared) => estimate_input_weight(&shared.prev_output), + // TODO(taproot): Needs to consider different weights based on channel type + InputOwned::Shared(_) => Weight::from_wu( + BASE_INPUT_WEIGHT + EMPTY_SCRIPT_SIG_WEIGHT + FUNDING_TRANSACTION_WITNESS_WEIGHT, + ), } } @@ -2156,6 +2159,8 @@ pub(super) fn calculate_change_output_value( weight = weight.saturating_add(TX_COMMON_FIELDS_WEIGHT); if is_splice { // TODO(taproot): Needs to consider different weights based on channel type + weight = weight.saturating_add(BASE_INPUT_WEIGHT); + weight = weight.saturating_add(EMPTY_SCRIPT_SIG_WEIGHT); weight = weight.saturating_add(FUNDING_TRANSACTION_WITNESS_WEIGHT); } } @@ -3147,7 +3152,7 @@ mod tests { // Provide and expect a shared input do_test_interactive_tx_constructor(TestSession { description: "Provide and expect a shared input", - inputs_a: generate_inputs(&[TestOutput::P2WPKH(50_000)]), + inputs_a: generate_inputs(&[TestOutput::P2WPKH(100_000)]), a_shared_input: Some(generate_shared_input(&prev_funding_tx_1, 0, 60_000)), shared_output_a: generate_funding_txout(108_000, 108_000), outputs_a: vec![], diff --git a/lightning/src/ln/splicing_tests.rs b/lightning/src/ln/splicing_tests.rs index bec2f4cad53..e822b8f7658 100644 --- a/lightning/src/ln/splicing_tests.rs +++ b/lightning/src/ln/splicing_tests.rs @@ -235,7 +235,7 @@ fn test_v1_splice_in() { assert_eq!(tx_add_output_msg.sats, post_splice_channel_value); } else { assert!(tx_add_output_msg.script.is_p2wpkh()); - assert_eq!(tx_add_output_msg.sats, 14146); // extra_splice_funding_input_sats - splice_in_sats + assert_eq!(tx_add_output_msg.sats, 13979); // extra_splice_funding_input_sats - splice_in_sats } let _res = acceptor_node From 4cc8d5a0d2ddc2e8cdbaeb654c8fe2d7446a8e92 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Thu, 4 Sep 2025 10:09:22 -0700 Subject: [PATCH 06/10] Detect splice out as local contribution Although a splice out doesn't include inputs to sign, users still need to call back with `funding_transaction_signed` to sign the shared splice input. --- lightning/src/ln/channelmanager.rs | 3 +-- lightning/src/ln/interactivetxs.rs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 90e6a309833..11f8d86c2e7 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -9034,8 +9034,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ .and_then(|_| channel.interactive_tx_signing_session.as_mut()) .filter(|signing_session| signing_session.holder_tx_signatures().is_none()) { - let local_inputs_count = signing_session.local_inputs_count(); - if local_inputs_count > 0 { + if signing_session.has_local_contribution() { let mut pending_events = self.pending_events.lock().unwrap(); let unsigned_transaction = signing_session.unsigned_tx().build_unsigned_tx(); let event_action = ( diff --git a/lightning/src/ln/interactivetxs.rs b/lightning/src/ln/interactivetxs.rs index 563a89466fe..d199b37edae 100644 --- a/lightning/src/ln/interactivetxs.rs +++ b/lightning/src/ln/interactivetxs.rs @@ -561,6 +561,24 @@ impl InteractiveTxSigningSession { .count() } + fn local_outputs_count(&self) -> usize { + self.unsigned_tx + .outputs + .iter() + .enumerate() + .filter(|(_, output)| { + !is_serial_id_valid_for_counterparty( + self.unsigned_tx.holder_is_initiator, + output.serial_id, + ) + }) + .count() + } + + pub fn has_local_contribution(&self) -> bool { + self.local_inputs_count() > 0 || self.local_outputs_count() > 0 + } + pub fn shared_input(&self) -> Option<&NegotiatedTxInput> { self.unsigned_tx .shared_input_index From 5c6b6370eebaeaa5f49415d280930d507dac5ab9 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Thu, 4 Sep 2025 10:09:24 -0700 Subject: [PATCH 07/10] Remove stale TODO for quiescence check on incoming splice_init --- lightning/src/ln/channel.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index c14a571afb6..9747be7c71a 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -11537,8 +11537,6 @@ where pub fn validate_splice_init( &self, msg: &msgs::SpliceInit, our_funding_contribution: SignedAmount, ) -> Result { - // TODO(splicing): Add check that we are the quiescence acceptor - if self.holder_commitment_point.current_point().is_none() { return Err(ChannelError::WarnAndDisconnect(format!( "Channel {} commitment point needs to be advanced once before spliced", @@ -11546,6 +11544,10 @@ where ))); } + if !self.context.channel_state.is_quiescent() { + return Err(ChannelError::WarnAndDisconnect("Quiescence needed to splice".to_owned())); + } + // Check if a splice has been initiated already. if self.pending_splice.is_some() { return Err(ChannelError::WarnAndDisconnect(format!( @@ -11686,10 +11688,6 @@ where ES::Target: EntropySource, L::Target: Logger, { - if !self.context.channel_state.is_quiescent() { - return Err(ChannelError::WarnAndDisconnect("Quiescence needed to splice".to_owned())); - } - let our_funding_contribution = SignedAmount::from_sat(our_funding_contribution_satoshis); let splice_funding = self.validate_splice_init(msg, our_funding_contribution)?; From bb0f5abf307141a2646f272858cc341b071bfb17 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Thu, 4 Sep 2025 10:09:23 -0700 Subject: [PATCH 08/10] Remove splicing rust cfg flag --- Cargo.toml | 1 - ci/ci-tests.sh | 2 - lightning-net-tokio/src/lib.rs | 3 - lightning/src/ln/channel.rs | 105 ++--------------------------- lightning/src/ln/channelmanager.rs | 17 ----- lightning/src/ln/funding.rs | 6 +- lightning/src/ln/mod.rs | 3 +- lightning/src/ln/msgs.rs | 3 - lightning/src/ln/peer_handler.rs | 6 -- lightning/src/ln/splicing_tests.rs | 2 +- lightning/src/ln/wire.rs | 12 ---- lightning/src/util/test_utils.rs | 3 - 12 files changed, 12 insertions(+), 151 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b89127b4f94..f9f7406339e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,6 @@ check-cfg = [ "cfg(ldk_test_vectors)", "cfg(taproot)", "cfg(require_route_graph_test)", - "cfg(splicing)", "cfg(simple_close)", "cfg(peer_storage)", ] diff --git a/ci/ci-tests.sh b/ci/ci-tests.sh index 1c8a53602c1..d2bd4facaee 100755 --- a/ci/ci-tests.sh +++ b/ci/ci-tests.sh @@ -151,8 +151,6 @@ fi echo -e "\n\nTest cfg-flag builds" RUSTFLAGS="--cfg=taproot" cargo test --verbose --color always -p lightning [ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean -RUSTFLAGS="--cfg=splicing" cargo test --verbose --color always -p lightning -[ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean RUSTFLAGS="--cfg=async_payments" cargo test --verbose --color always -p lightning [ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean RUSTFLAGS="--cfg=simple_close" cargo test --verbose --color always -p lightning diff --git a/lightning-net-tokio/src/lib.rs b/lightning-net-tokio/src/lib.rs index 1d1d3c4654b..f238a7da5fa 100644 --- a/lightning-net-tokio/src/lib.rs +++ b/lightning-net-tokio/src/lib.rs @@ -742,11 +742,8 @@ mod tests { fn handle_open_channel_v2(&self, _their_node_id: PublicKey, _msg: &OpenChannelV2) {} fn handle_accept_channel_v2(&self, _their_node_id: PublicKey, _msg: &AcceptChannelV2) {} fn handle_stfu(&self, _their_node_id: PublicKey, _msg: &Stfu) {} - #[cfg(splicing)] fn handle_splice_init(&self, _their_node_id: PublicKey, _msg: &SpliceInit) {} - #[cfg(splicing)] fn handle_splice_ack(&self, _their_node_id: PublicKey, _msg: &SpliceAck) {} - #[cfg(splicing)] fn handle_splice_locked(&self, _their_node_id: PublicKey, _msg: &SpliceLocked) {} fn handle_tx_add_input(&self, _their_node_id: PublicKey, _msg: &TxAddInput) {} fn handle_tx_add_output(&self, _their_node_id: PublicKey, _msg: &TxAddOutput) {} diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 9747be7c71a..5e8545c99ae 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -24,9 +24,7 @@ use bitcoin::hashes::Hash; use bitcoin::secp256k1::constants::PUBLIC_KEY_SIZE; use bitcoin::secp256k1::{ecdsa::Signature, Secp256k1}; use bitcoin::secp256k1::{PublicKey, SecretKey}; -use bitcoin::{secp256k1, sighash, TxIn}; -#[cfg(splicing)] -use bitcoin::{FeeRate, Sequence}; +use bitcoin::{secp256k1, sighash, FeeRate, Sequence, TxIn}; use crate::chain::chaininterface::{ fee_for_weight, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator, @@ -38,9 +36,7 @@ use crate::chain::channelmonitor::{ use crate::chain::transaction::{OutPoint, TransactionData}; use crate::chain::BestBlock; use crate::events::bump_transaction::{BASE_INPUT_WEIGHT, EMPTY_SCRIPT_SIG_WEIGHT}; -use crate::events::ClosureReason; -#[cfg(splicing)] -use crate::events::FundingInfo; +use crate::events::{ClosureReason, FundingInfo}; use crate::ln::chan_utils; use crate::ln::chan_utils::{ get_commitment_transaction_number_obscure_factor, max_htlcs, second_stage_tx_fees_sat, @@ -59,15 +55,11 @@ use crate::ln::channelmanager::{ RAACommitmentOrder, SentHTLCId, BREAKDOWN_TIMEOUT, MAX_LOCAL_BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, }; -use crate::ln::funding::FundingTxInput; -#[cfg(splicing)] -use crate::ln::funding::SpliceContribution; -#[cfg(splicing)] -use crate::ln::interactivetxs::calculate_change_output_value; +use crate::ln::funding::{FundingTxInput, SpliceContribution}; use crate::ln::interactivetxs::{ - get_output_weight, AbortReason, HandleTxCompleteValue, InteractiveTxConstructor, - InteractiveTxConstructorArgs, InteractiveTxMessageSend, InteractiveTxSigningSession, - SharedOwnedInput, SharedOwnedOutput, TX_COMMON_FIELDS_WEIGHT, + calculate_change_output_value, get_output_weight, AbortReason, HandleTxCompleteValue, + InteractiveTxConstructor, InteractiveTxConstructorArgs, InteractiveTxMessageSend, + InteractiveTxSigningSession, SharedOwnedInput, SharedOwnedOutput, TX_COMMON_FIELDS_WEIGHT, }; use crate::ln::msgs; use crate::ln::msgs::{ClosingSigned, ClosingSignedFeeRange, DecodeError, OnionErrorPacket}; @@ -76,7 +68,6 @@ use crate::ln::onion_utils::{ }; use crate::ln::script::{self, ShutdownScript}; use crate::ln::types::ChannelId; -#[cfg(splicing)] use crate::ln::LN_MAX_MSG_LEN; use crate::routing::gossip::NodeId; use crate::sign::ecdsa::EcdsaChannelSigner; @@ -1733,7 +1724,6 @@ where fn interactive_tx_constructor_mut(&mut self) -> Option<&mut InteractiveTxConstructor> { match &mut self.phase { ChannelPhase::UnfundedV2(chan) => chan.interactive_tx_constructor.as_mut(), - #[cfg(splicing)] ChannelPhase::Funded(chan) => chan.interactive_tx_constructor_mut(), _ => None, } @@ -1754,9 +1744,6 @@ where ChannelPhase::UnfundedV2(pending_v2_channel) => { pending_v2_channel.interactive_tx_constructor.take() }, - #[cfg(not(splicing))] - ChannelPhase::Funded(_) => unreachable!(), - #[cfg(splicing)] ChannelPhase::Funded(funded_channel) => funded_channel .pending_splice .as_mut() @@ -1897,12 +1884,6 @@ where ChannelPhase::UnfundedV2(pending_v2_channel) => { pending_v2_channel.interactive_tx_constructor.take().is_some() }, - #[cfg(not(splicing))] - ChannelPhase::Funded(_) => { - let err = "Got an unexpected tx_abort message: This is an funded channel and splicing is not supported"; - return Err(ChannelError::Warn(err.into())); - }, - #[cfg(splicing)] ChannelPhase::Funded(funded_channel) => funded_channel .pending_splice .as_mut() @@ -1986,7 +1967,6 @@ where return Ok(commitment_signed); }, - #[cfg(splicing)] ChannelPhase::Funded(chan) => { if let Some(pending_splice) = chan.pending_splice.as_mut() { if let Some(funding_negotiation) = pending_splice.funding_negotiation.take() { @@ -2061,7 +2041,6 @@ where context: chan.context, interactive_tx_signing_session: chan.interactive_tx_signing_session, holder_commitment_point, - #[cfg(splicing)] pending_splice: None, quiescent_action: None, }; @@ -2077,7 +2056,6 @@ where res }, ChannelPhase::Funded(mut funded_channel) => { - #[cfg(splicing)] let has_negotiated_pending_splice = funded_channel.pending_splice.as_ref() .and_then(|pending_splice| pending_splice.funding_negotiation.as_ref()) .filter(|funding_negotiation| { @@ -2085,7 +2063,6 @@ where }) .map(|funding_negotiation| funding_negotiation.as_funding().is_some()) .unwrap_or(false); - #[cfg(splicing)] let session_received_commitment_signed = funded_channel .interactive_tx_signing_session .as_ref() @@ -2093,7 +2070,6 @@ where // Not having a signing session implies they've already sent `splice_locked`, // which must always come after the initial commitment signed is sent. .unwrap_or(true); - #[cfg(splicing)] let res = if has_negotiated_pending_splice && !session_received_commitment_signed { funded_channel .splice_initial_commitment_signed(msg, logger) @@ -2103,10 +2079,6 @@ where .map(|monitor_update_opt| (None, monitor_update_opt)) }; - #[cfg(not(splicing))] - let res = funded_channel.commitment_signed(msg, logger) - .map(|monitor_update_opt| (None, monitor_update_opt)); - self.phase = ChannelPhase::Funded(funded_channel); res }, @@ -2391,7 +2363,6 @@ impl FundingScope { self.channel_transaction_parameters.make_funding_redeemscript() } - #[cfg(splicing)] fn holder_funding_pubkey(&self) -> &PublicKey { &self.get_holder_pubkeys().funding_pubkey } @@ -2433,7 +2404,6 @@ impl FundingScope { } /// Constructs a `FundingScope` for splicing a channel. - #[cfg(splicing)] fn for_splice( prev_funding: &Self, context: &ChannelContext, our_funding_contribution: SignedAmount, their_funding_contribution: SignedAmount, counterparty_funding_pubkey: PublicKey, @@ -2515,7 +2485,6 @@ impl FundingScope { } /// Compute the post-splice channel value from each counterparty's contributions. - #[cfg(splicing)] pub(super) fn compute_post_splice_value( &self, our_funding_contribution: i64, their_funding_contribution: i64, ) -> u64 { @@ -2526,7 +2495,6 @@ impl FundingScope { } /// Returns a `SharedOwnedInput` for using this `FundingScope` as the input to a new splice. - #[cfg(splicing)] fn to_splice_funding_input(&self) -> SharedOwnedInput { let funding_txo = self.get_funding_txo().expect("funding_txo should be set"); let input = TxIn { @@ -2556,13 +2524,11 @@ impl FundingScope { } // TODO: Remove once MSRV is at least 1.66 -#[cfg(splicing)] trait AddSigned { fn checked_add_signed(self, rhs: i64) -> Option; fn saturating_add_signed(self, rhs: i64) -> u64; } -#[cfg(splicing)] impl AddSigned for u64 { fn checked_add_signed(self, rhs: i64) -> Option { if rhs >= 0 { @@ -2582,7 +2548,6 @@ impl AddSigned for u64 { } /// Info about a pending splice -#[cfg(splicing)] struct PendingSplice { funding_negotiation: Option, @@ -2593,14 +2558,12 @@ struct PendingSplice { received_funding_txid: Option, } -#[cfg(splicing)] enum FundingNegotiation { AwaitingAck(FundingNegotiationContext), ConstructingTransaction(FundingScope, InteractiveTxConstructor), AwaitingSignatures(FundingScope), } -#[cfg(splicing)] impl FundingNegotiation { fn as_funding(&self) -> Option<&FundingScope> { match self { @@ -2611,7 +2574,6 @@ impl FundingNegotiation { } } -#[cfg(splicing)] impl PendingSplice { fn check_get_splice_locked( &mut self, context: &ChannelContext, funding: &FundingScope, height: u32, @@ -2671,7 +2633,6 @@ pub(crate) enum QuiescentAction { pub(crate) enum StfuResponse { Stfu(msgs::Stfu), - #[cfg_attr(not(splicing), allow(unused))] SpliceInit(msgs::SpliceInit), } @@ -4005,7 +3966,6 @@ where } /// Returns holder pubkeys to use for the channel. - #[cfg(splicing)] fn holder_pubkeys(&self, prev_funding_txid: Option) -> ChannelPublicKeys { match &self.holder_signer { ChannelSignerType::Ecdsa(ecdsa) => ecdsa.pubkeys(prev_funding_txid, &self.secp_ctx), @@ -6355,7 +6315,6 @@ fn get_v2_channel_reserve_satoshis(channel_value_satoshis: u64, dust_limit_satos cmp::min(channel_value_satoshis, cmp::max(q, dust_limit_satoshis)) } -#[cfg(splicing)] fn check_splice_contribution_sufficient( contribution: &SpliceContribution, is_initiator: bool, funding_feerate: FeeRate, ) -> Result { @@ -6434,7 +6393,6 @@ fn estimate_v2_funding_transaction_fee( /// the fees of the inputs, fees of the inputs weight, and for the initiator, /// the fees of the common fields as well as the output and extra input weights. /// Returns estimated (partial) fees as additional information -#[cfg(splicing)] #[rustfmt::skip] fn check_v2_funding_inputs_sufficient( contribution_amount: i64, funding_inputs: &[FundingTxInput], is_initiator: bool, @@ -6504,7 +6462,6 @@ pub(super) struct FundingNegotiationContext { impl FundingNegotiationContext { /// Prepare and start interactive transaction negotiation. /// If error occurs, it is caused by our side, not the counterparty. - #[cfg(splicing)] fn into_interactive_tx_constructor( self, context: &ChannelContext, funding: &FundingScope, signer_provider: &SP, entropy_source: &ES, holder_node_id: PublicKey, @@ -6614,7 +6571,6 @@ where pub interactive_tx_signing_session: Option, holder_commitment_point: HolderCommitmentPoint, /// Info about an in-progress, pending splice (if any), on the pre-splice channel - #[cfg(splicing)] pending_splice: Option, /// Once we become quiescent, if we're the initiator, there's some action we'll want to take. @@ -6624,7 +6580,6 @@ where quiescent_action: Option, } -#[cfg(splicing)] macro_rules! promote_splice_funding { ($self: expr, $funding: expr) => {{ let prev_funding_txid = $self.funding.get_funding_txid(); @@ -6733,7 +6688,6 @@ type BestBlockUpdatedRes = ( Option, ); -#[cfg(splicing)] pub struct SpliceFundingPromotion { pub funding_txo: OutPoint, pub monitor_update: Option, @@ -6754,7 +6708,6 @@ where self.context.force_shutdown(&self.funding, closure_reason) } - #[cfg(splicing)] fn interactive_tx_constructor_mut(&mut self) -> Option<&mut InteractiveTxConstructor> { self.pending_splice .as_mut() @@ -7543,7 +7496,6 @@ where /// Note that our `commitment_signed` send did not include a monitor update. This is due to: /// 1. Updates cannot be made since the state machine is paused until `tx_signatures`. /// 2. We're still able to abort negotiation until `tx_signatures`. - #[cfg(splicing)] pub fn splice_initial_commitment_signed( &mut self, msg: &msgs::CommitmentSigned, logger: &L, ) -> Result, ChannelError> @@ -8549,7 +8501,6 @@ where format!("Channel {} already received funding signatures", self.context.channel_id); return Err(APIError::APIMisuseError { err }); } - #[cfg(splicing)] if let Some(pending_splice) = self.pending_splice.as_ref() { if !pending_splice .funding_negotiation @@ -8602,7 +8553,6 @@ where } else { None }; - #[cfg(splicing)] debug_assert_eq!(self.pending_splice.is_some(), shared_input_signature.is_some()); let tx_signatures = msgs::TxSignatures { @@ -9415,7 +9365,6 @@ where // TODO(splicing): Add comment for spec requirements if next_funding.should_retransmit(msgs::NextFundingFlag::CommitmentSigned) { - #[cfg(splicing)] let funding = self .pending_splice .as_ref() @@ -9438,8 +9387,6 @@ where ) ) })?; - #[cfg(not(splicing))] - let funding = &self.funding; let commitment_signed = self.context.get_initial_commitment_signed_v2(&funding, logger) // TODO(splicing): Support async signing @@ -9563,7 +9510,6 @@ where // those splice transactions, for which it hasn't received `splice_locked` yet: // - MUST process `my_current_funding_locked` as if it was receiving `splice_locked` // for this `txid`. - #[cfg(splicing)] let inferred_splice_locked = msg.my_current_funding_locked.as_ref().and_then(|funding_locked| { self.pending_funding .iter() @@ -9579,8 +9525,6 @@ where splice_txid, }) }); - #[cfg(not(splicing))] - let inferred_splice_locked = None; if msg.next_local_commitment_number == next_counterparty_commitment_number { if required_revoke.is_some() || self.context.signer_pending_revoke_and_ack { @@ -10625,7 +10569,6 @@ where } /// Returns `Some` if a splice [`FundingScope`] was promoted. - #[cfg(splicing)] fn maybe_promote_splice_funding( &mut self, node_signer: &NS, chain_hash: ChainHash, user_config: &UserConfig, block_height: u32, logger: &L, @@ -10749,11 +10692,8 @@ where } } - #[cfg(splicing)] let mut confirmed_funding_index = None; - #[cfg(splicing)] let mut funding_already_confirmed = false; - #[cfg(splicing)] for (index, funding) in self.pending_funding.iter_mut().enumerate() { if self.context.check_for_funding_tx_confirmed( funding, block_hash, height, index_in_block, &mut confirmed_tx, logger, @@ -10769,7 +10709,6 @@ where } } - #[cfg(splicing)] if let Some(confirmed_funding_index) = confirmed_funding_index { let pending_splice = match self.pending_splice.as_mut() { Some(pending_splice) => pending_splice, @@ -10905,9 +10844,7 @@ where return Err(ClosureReason::FundingTimedOut); } - #[cfg(splicing)] let mut confirmed_funding_index = None; - #[cfg(splicing)] for (index, funding) in self.pending_funding.iter().enumerate() { if funding.funding_tx_confirmation_height != 0 { if confirmed_funding_index.is_some() { @@ -10919,7 +10856,6 @@ where } } - #[cfg(splicing)] if let Some(confirmed_funding_index) = confirmed_funding_index { let pending_splice = match self.pending_splice.as_mut() { Some(pending_splice) => pending_splice, @@ -11275,7 +11211,6 @@ where } } - #[cfg(splicing)] fn maybe_get_my_current_funding_locked(&self) -> Option { self.pending_splice .as_ref() @@ -11304,11 +11239,6 @@ where }) } - #[cfg(not(splicing))] - fn maybe_get_my_current_funding_locked(&self) -> Option { - None - } - /// May panic if called on a channel that wasn't immediately-previously /// self.remove_uncommitted_htlcs_and_mark_paused()'d #[rustfmt::skip] @@ -11369,7 +11299,6 @@ where /// Includes the witness weight for this input (e.g. P2WPKH_WITNESS_WEIGHT=109 for typical P2WPKH inputs). /// - `change_script`: an option change output script. If `None` and needed, one will be /// generated by `SignerProvider::get_destination_script`. - #[cfg(splicing)] pub fn splice_channel( &mut self, contribution: SpliceContribution, funding_feerate_per_kw: u32, locktime: u32, logger: &L, @@ -11478,7 +11407,6 @@ where .map_err(|e| APIError::APIMisuseError { err: e.to_owned() }) } - #[cfg(splicing)] fn send_splice_init( &mut self, instructions: SpliceInstructions, ) -> Result { @@ -11533,7 +11461,6 @@ where } /// Checks during handling splice_init - #[cfg(splicing)] pub fn validate_splice_init( &self, msg: &msgs::SpliceInit, our_funding_contribution: SignedAmount, ) -> Result { @@ -11589,7 +11516,6 @@ where )) } - #[cfg(splicing)] fn validate_splice_contributions( &self, our_funding_contribution: SignedAmount, their_funding_contribution: SignedAmount, ) -> Result<(), String> { @@ -11679,7 +11605,6 @@ where Ok(()) } - #[cfg(splicing)] pub(crate) fn splice_init( &mut self, msg: &msgs::SpliceInit, our_funding_contribution_satoshis: i64, signer_provider: &SP, entropy_source: &ES, holder_node_id: &PublicKey, logger: &L, @@ -11751,7 +11676,6 @@ where }) } - #[cfg(splicing)] pub(crate) fn splice_ack( &mut self, msg: &msgs::SpliceAck, signer_provider: &SP, entropy_source: &ES, holder_node_id: &PublicKey, logger: &L, @@ -11807,8 +11731,6 @@ where Ok(tx_msg_opt) } - /// Checks during handling splice_ack - #[cfg(splicing)] fn validate_splice_ack(&self, msg: &msgs::SpliceAck) -> Result { // TODO(splicing): Add check that we are the splice (quiescence) initiator @@ -11846,7 +11768,6 @@ where )) } - #[cfg(splicing)] fn get_holder_counterparty_balances_floor_incl_fee( &self, funding: &FundingScope, ) -> Result<(Amount, Amount), String> { @@ -11908,7 +11829,6 @@ where Ok((holder_balance_floor, counterparty_balance_floor)) } - #[cfg(splicing)] pub fn splice_locked( &mut self, msg: &msgs::SpliceLocked, node_signer: &NS, chain_hash: ChainHash, user_config: &UserConfig, block_height: u32, logger: &L, @@ -12543,7 +12463,6 @@ where ); } - #[cfg(any(splicing, test, fuzzing))] #[rustfmt::skip] pub fn propose_quiescence( &mut self, logger: &L, action: QuiescentAction, @@ -12694,7 +12613,6 @@ where )); }, Some(QuiescentAction::Splice(_instructions)) => { - #[cfg(splicing)] return self.send_splice_init(_instructions) .map(|splice_init| Some(StfuResponse::SpliceInit(splice_init))) .map_err(|e| ChannelError::WarnAndDisconnect(e.to_owned())); @@ -13077,7 +12995,6 @@ where context: self.context, interactive_tx_signing_session: None, holder_commitment_point, - #[cfg(splicing)] pending_splice: None, quiescent_action: None, }; @@ -13364,7 +13281,6 @@ where context: self.context, interactive_tx_signing_session: None, holder_commitment_point, - #[cfg(splicing)] pending_splice: None, quiescent_action: None, }; @@ -15052,7 +14968,6 @@ where }, interactive_tx_signing_session, holder_commitment_point, - #[cfg(splicing)] pending_splice: None, quiescent_action, }) @@ -15089,9 +15004,7 @@ mod tests { use crate::chain::chaininterface::LowerBoundedFeeEstimator; use crate::chain::transaction::OutPoint; use crate::chain::BestBlock; - #[cfg(splicing)] - use crate::ln::chan_utils::ChannelTransactionParameters; - use crate::ln::chan_utils::{self, commit_tx_fee_sat}; + use crate::ln::chan_utils::{self, commit_tx_fee_sat, ChannelTransactionParameters}; use crate::ln::channel::{ AwaitingChannelReadyFlags, ChannelState, FundedChannel, HTLCCandidate, HTLCInitiator, HTLCUpdateAwaitingACK, InboundHTLCOutput, InboundHTLCState, InboundV1Channel, @@ -15112,7 +15025,6 @@ mod tests { use crate::routing::router::{Path, RouteHop}; #[cfg(ldk_test_vectors)] use crate::sign::{ChannelSigner, EntropySource, InMemorySigner, SignerProvider}; - #[cfg(splicing)] use crate::sync::Mutex; #[cfg(ldk_test_vectors)] use crate::types::features::ChannelTypeFeatures; @@ -16903,7 +16815,6 @@ mod tests { FundingTxInput::new_p2wpkh(prevtx, 0).unwrap() } - #[cfg(splicing)] #[test] #[rustfmt::skip] fn test_check_v2_funding_inputs_sufficient() { @@ -16996,7 +16907,6 @@ mod tests { } } - #[cfg(splicing)] fn get_pre_and_post( pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64, ) -> (u64, u64) { @@ -17031,7 +16941,6 @@ mod tests { (pre_channel_value, post_channel_value) } - #[cfg(splicing)] #[test] fn test_compute_post_splice_value() { { diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 11f8d86c2e7..9a3a0366ae1 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -64,7 +64,6 @@ use crate::ln::channel::{ StfuResponse, UpdateFulfillCommitFetch, WithChannelContext, }; use crate::ln::channel_state::ChannelDetails; -#[cfg(splicing)] use crate::ln::funding::SpliceContribution; use crate::ln::inbound_payment; use crate::ln::interactivetxs::InteractiveTxMessageSend; @@ -4496,7 +4495,6 @@ where /// - `our_funding_inputs`: the funding inputs provided by us. If our contribution is positive, our funding inputs must cover at least that amount. /// Includes the witness weight for this input (e.g. P2WPKH_WITNESS_WEIGHT=109 for typical P2WPKH inputs). /// - `locktime`: Optional locktime for the new funding transaction. If None, set to the current block height. - #[cfg(splicing)] #[rustfmt::skip] pub fn splice_channel( &self, channel_id: &ChannelId, counterparty_node_id: &PublicKey, @@ -4516,8 +4514,6 @@ where res } - /// See [`splice_channel`] - #[cfg(splicing)] fn internal_splice_channel( &self, channel_id: &ChannelId, counterparty_node_id: &PublicKey, contribution: SpliceContribution, funding_feerate_per_kw: u32, locktime: Option, @@ -11047,9 +11043,6 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ self.internal_channel_ready(counterparty_node_id, &channel_ready_msg)?; } - #[cfg(not(splicing))] - let _ = inferred_splice_locked; - #[cfg(splicing)] if let Some(splice_locked) = inferred_splice_locked { self.internal_splice_locked(counterparty_node_id, &splice_locked)?; return Ok(NotifyOption::DoPersist); @@ -11059,7 +11052,6 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ } /// Handle incoming splice request, transition channel to splice-pending (unless some check fails). - #[cfg(splicing)] #[rustfmt::skip] fn internal_splice_init(&self, counterparty_node_id: &PublicKey, msg: &msgs::SpliceInit) -> Result<(), MsgHandleErrInternal> { let per_peer_state = self.per_peer_state.read().unwrap(); @@ -11100,7 +11092,6 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ } /// Handle incoming splice request ack, transition channel to splice-pending (unless some check fails). - #[cfg(splicing)] #[rustfmt::skip] fn internal_splice_ack(&self, counterparty_node_id: &PublicKey, msg: &msgs::SpliceAck) -> Result<(), MsgHandleErrInternal> { let per_peer_state = self.per_peer_state.read().unwrap(); @@ -11136,7 +11127,6 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ } } - #[cfg(splicing)] fn internal_splice_locked( &self, counterparty_node_id: &PublicKey, msg: &msgs::SpliceLocked, ) -> Result<(), MsgHandleErrInternal> { @@ -13384,7 +13374,6 @@ where pub(super) enum FundingConfirmedMessage { Establishment(msgs::ChannelReady), - #[cfg(splicing)] Splice(msgs::SpliceLocked, Option, Option, Vec), } @@ -13422,7 +13411,6 @@ where let mut failed_channels: Vec<(Result, _)> = Vec::new(); let mut timed_out_htlcs = Vec::new(); - #[cfg(splicing)] let mut to_process_monitor_update_actions = Vec::new(); { let per_peer_state = self.per_peer_state.read().unwrap(); @@ -13460,7 +13448,6 @@ where log_trace!(logger, "Sending channel_ready WITHOUT channel_update for {}", channel_id); } }, - #[cfg(splicing)] Some(FundingConfirmedMessage::Splice(splice_locked, funding_txo, monitor_update_opt, discarded_funding)) => { let counterparty_node_id = funded_channel.context.get_counterparty_node_id(); let channel_id = funded_channel.context.channel_id(); @@ -13591,7 +13578,6 @@ where } } - #[cfg(splicing)] for (counterparty_node_id, channel_id) in to_process_monitor_update_actions { self.channel_monitor_updated(&channel_id, None, &counterparty_node_id); } @@ -13865,7 +13851,6 @@ where }); } - #[cfg(splicing)] fn handle_splice_init(&self, counterparty_node_id: PublicKey, msg: &msgs::SpliceInit) { let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || { let res = self.internal_splice_init(&counterparty_node_id, msg); @@ -13879,7 +13864,6 @@ where }); } - #[cfg(splicing)] fn handle_splice_ack(&self, counterparty_node_id: PublicKey, msg: &msgs::SpliceAck) { let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || { let res = self.internal_splice_ack(&counterparty_node_id, msg); @@ -13893,7 +13877,6 @@ where }); } - #[cfg(splicing)] #[rustfmt::skip] fn handle_splice_locked(&self, counterparty_node_id: PublicKey, msg: &msgs::SpliceLocked) { let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || { diff --git a/lightning/src/ln/funding.rs b/lightning/src/ln/funding.rs index a87a3cb904e..b0b8cd4aa1c 100644 --- a/lightning/src/ln/funding.rs +++ b/lightning/src/ln/funding.rs @@ -9,15 +9,14 @@ //! Types pertaining to funding channels. -#[cfg(splicing)] use bitcoin::{Amount, ScriptBuf, SignedAmount, TxOut}; use bitcoin::{Script, Sequence, Transaction, Weight}; use crate::events::bump_transaction::{Utxo, EMPTY_SCRIPT_SIG_WEIGHT}; +use crate::prelude::Vec; use crate::sign::{P2TR_KEY_PATH_WITNESS_WEIGHT, P2WPKH_WITNESS_WEIGHT}; /// The components of a splice's funding transaction that are contributed by one party. -#[cfg(splicing)] pub enum SpliceContribution { /// When funds are added to a channel. SpliceIn { @@ -30,6 +29,8 @@ pub enum SpliceContribution { /// An optional change output script. This will be used if needed or, when not set, /// generated using [`SignerProvider::get_destination_script`]. + /// + /// [`SignerProvider::get_destination_script`]: crate::sign::SignerProvider::get_destination_script change_script: Option, }, /// When funds are removed from a channel. @@ -40,7 +41,6 @@ pub enum SpliceContribution { }, } -#[cfg(splicing)] impl SpliceContribution { pub(super) fn value(&self) -> SignedAmount { match self { diff --git a/lightning/src/ln/mod.rs b/lightning/src/ln/mod.rs index 07ef7238fbe..873618b9870 100644 --- a/lightning/src/ln/mod.rs +++ b/lightning/src/ln/mod.rs @@ -120,8 +120,7 @@ mod reorg_tests; #[cfg(test)] #[allow(unused_mut)] mod shutdown_tests; -#[cfg(all(test, splicing))] -#[allow(unused_mut)] +#[cfg(test)] mod splicing_tests; #[cfg(any(test, feature = "_externalize_tests"))] #[allow(unused_mut)] diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 0a6817e7712..5db1ba70ffa 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -2058,13 +2058,10 @@ pub trait ChannelMessageHandler: BaseMessageHandler { // Splicing /// Handle an incoming `splice_init` message from the given peer. - #[cfg(splicing)] fn handle_splice_init(&self, their_node_id: PublicKey, msg: &SpliceInit); /// Handle an incoming `splice_ack` message from the given peer. - #[cfg(splicing)] fn handle_splice_ack(&self, their_node_id: PublicKey, msg: &SpliceAck); /// Handle an incoming `splice_locked` message from the given peer. - #[cfg(splicing)] fn handle_splice_locked(&self, their_node_id: PublicKey, msg: &SpliceLocked); // Interactive channel construction diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 98e54eec925..71f146affcc 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -448,15 +448,12 @@ impl ChannelMessageHandler for ErroringMessageHandler { fn handle_stfu(&self, their_node_id: PublicKey, msg: &msgs::Stfu) { ErroringMessageHandler::push_error(&self, their_node_id, msg.channel_id); } - #[cfg(splicing)] fn handle_splice_init(&self, their_node_id: PublicKey, msg: &msgs::SpliceInit) { ErroringMessageHandler::push_error(&self, their_node_id, msg.channel_id); } - #[cfg(splicing)] fn handle_splice_ack(&self, their_node_id: PublicKey, msg: &msgs::SpliceAck) { ErroringMessageHandler::push_error(&self, their_node_id, msg.channel_id); } - #[cfg(splicing)] fn handle_splice_locked(&self, their_node_id: PublicKey, msg: &msgs::SpliceLocked) { ErroringMessageHandler::push_error(&self, their_node_id, msg.channel_id); } @@ -2481,16 +2478,13 @@ where self.message_handler.chan_handler.handle_stfu(their_node_id, &msg); }, - #[cfg(splicing)] // Splicing messages: wire::Message::SpliceInit(msg) => { self.message_handler.chan_handler.handle_splice_init(their_node_id, &msg); }, - #[cfg(splicing)] wire::Message::SpliceAck(msg) => { self.message_handler.chan_handler.handle_splice_ack(their_node_id, &msg); }, - #[cfg(splicing)] wire::Message::SpliceLocked(msg) => { self.message_handler.chan_handler.handle_splice_locked(their_node_id, &msg); }, diff --git a/lightning/src/ln/splicing_tests.rs b/lightning/src/ln/splicing_tests.rs index e822b8f7658..3f7d9f273ea 100644 --- a/lightning/src/ln/splicing_tests.rs +++ b/lightning/src/ln/splicing_tests.rs @@ -55,7 +55,7 @@ fn test_v1_splice_in() { // ==== Channel is now ready for normal operation // Expected balances - let mut exp_balance1 = 1000 * channel_value_sat; + let exp_balance1 = 1000 * channel_value_sat; let mut _exp_balance2 = 0; // === Start of Splicing diff --git a/lightning/src/ln/wire.rs b/lightning/src/ln/wire.rs index bd49bdd9eab..bc1d83adb68 100644 --- a/lightning/src/ln/wire.rs +++ b/lightning/src/ln/wire.rs @@ -63,11 +63,8 @@ pub(crate) enum Message { FundingCreated(msgs::FundingCreated), FundingSigned(msgs::FundingSigned), Stfu(msgs::Stfu), - #[cfg(splicing)] SpliceInit(msgs::SpliceInit), - #[cfg(splicing)] SpliceAck(msgs::SpliceAck), - #[cfg(splicing)] SpliceLocked(msgs::SpliceLocked), TxAddInput(msgs::TxAddInput), TxAddOutput(msgs::TxAddOutput), @@ -128,11 +125,8 @@ impl Writeable for Message { &Message::FundingCreated(ref msg) => msg.write(writer), &Message::FundingSigned(ref msg) => msg.write(writer), &Message::Stfu(ref msg) => msg.write(writer), - #[cfg(splicing)] &Message::SpliceInit(ref msg) => msg.write(writer), - #[cfg(splicing)] &Message::SpliceAck(ref msg) => msg.write(writer), - #[cfg(splicing)] &Message::SpliceLocked(ref msg) => msg.write(writer), &Message::TxAddInput(ref msg) => msg.write(writer), &Message::TxAddOutput(ref msg) => msg.write(writer), @@ -193,11 +187,8 @@ impl Type for Message { &Message::FundingCreated(ref msg) => msg.type_id(), &Message::FundingSigned(ref msg) => msg.type_id(), &Message::Stfu(ref msg) => msg.type_id(), - #[cfg(splicing)] &Message::SpliceInit(ref msg) => msg.type_id(), - #[cfg(splicing)] &Message::SpliceAck(ref msg) => msg.type_id(), - #[cfg(splicing)] &Message::SpliceLocked(ref msg) => msg.type_id(), &Message::TxAddInput(ref msg) => msg.type_id(), &Message::TxAddOutput(ref msg) => msg.type_id(), @@ -311,18 +302,15 @@ where msgs::FundingSigned::TYPE => { Ok(Message::FundingSigned(LengthReadable::read_from_fixed_length_buffer(buffer)?)) }, - #[cfg(splicing)] msgs::SpliceInit::TYPE => { Ok(Message::SpliceInit(LengthReadable::read_from_fixed_length_buffer(buffer)?)) }, msgs::Stfu::TYPE => { Ok(Message::Stfu(LengthReadable::read_from_fixed_length_buffer(buffer)?)) }, - #[cfg(splicing)] msgs::SpliceAck::TYPE => { Ok(Message::SpliceAck(LengthReadable::read_from_fixed_length_buffer(buffer)?)) }, - #[cfg(splicing)] msgs::SpliceLocked::TYPE => { Ok(Message::SpliceLocked(LengthReadable::read_from_fixed_length_buffer(buffer)?)) }, diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index b61916aa17f..d28d0abbc32 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -1129,15 +1129,12 @@ impl msgs::ChannelMessageHandler for TestChannelMessageHandler { fn handle_stfu(&self, _their_node_id: PublicKey, msg: &msgs::Stfu) { self.received_msg(wire::Message::Stfu(msg.clone())); } - #[cfg(splicing)] fn handle_splice_init(&self, _their_node_id: PublicKey, msg: &msgs::SpliceInit) { self.received_msg(wire::Message::SpliceInit(msg.clone())); } - #[cfg(splicing)] fn handle_splice_ack(&self, _their_node_id: PublicKey, msg: &msgs::SpliceAck) { self.received_msg(wire::Message::SpliceAck(msg.clone())); } - #[cfg(splicing)] fn handle_splice_locked(&self, _their_node_id: PublicKey, msg: &msgs::SpliceLocked) { self.received_msg(wire::Message::SpliceLocked(msg.clone())); } From 1bda3ebe69f54cc19017c78892636db0af84712a Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Mon, 8 Sep 2025 11:10:50 -0700 Subject: [PATCH 09/10] Remove useless use of format! throughout splicing errors --- lightning/src/ln/channel.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 5e8545c99ae..326ebf651ed 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -11487,9 +11487,9 @@ where // MUST send a warning and close the connection or send an error // and fail the channel. if !self.context.is_live() { - return Err(ChannelError::WarnAndDisconnect(format!( - "Splicing requested on a channel that is not live" - ))); + return Err(ChannelError::WarnAndDisconnect( + "Splicing requested on a channel that is not live".to_owned(), + )); } // TODO(splicing): Once splice acceptor can contribute, check that inputs are sufficient, @@ -11737,20 +11737,20 @@ where let funding_negotiation_context = match &self .pending_splice .as_ref() - .ok_or(ChannelError::Ignore(format!("Channel is not in pending splice")))? + .ok_or(ChannelError::Ignore("Channel is not in pending splice".to_owned()))? .funding_negotiation { Some(FundingNegotiation::AwaitingAck(context)) => context, Some(FundingNegotiation::ConstructingTransaction(_, _)) | Some(FundingNegotiation::AwaitingSignatures(_)) => { - return Err(ChannelError::WarnAndDisconnect(format!( - "Got unexpected splice_ack; splice negotiation already in progress" - ))); + return Err(ChannelError::WarnAndDisconnect( + "Got unexpected splice_ack; splice negotiation already in progress".to_owned(), + )); }, None => { - return Err(ChannelError::Ignore(format!( - "Got unexpected splice_ack; no splice negotiation in progress" - ))); + return Err(ChannelError::Ignore( + "Got unexpected splice_ack; no splice negotiation in progress".to_owned(), + )); }, }; @@ -11847,7 +11847,7 @@ where let pending_splice = match self.pending_splice.as_mut() { Some(pending_splice) => pending_splice, None => { - return Err(ChannelError::Ignore(format!("Channel is not in pending splice"))); + return Err(ChannelError::Ignore("Channel is not in pending splice".to_owned())); }, }; From 1dc190d06c804a6277a3a3be609d73a9683cb1f4 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Mon, 8 Sep 2025 12:07:14 -0700 Subject: [PATCH 10/10] Remove let binding for unit values in splice test --- lightning/src/ln/splicing_tests.rs | 34 ++++++++++-------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/lightning/src/ln/splicing_tests.rs b/lightning/src/ln/splicing_tests.rs index 3f7d9f273ea..0a5a5a27422 100644 --- a/lightning/src/ln/splicing_tests.rs +++ b/lightning/src/ln/splicing_tests.rs @@ -79,7 +79,7 @@ fn test_v1_splice_in() { }; // Initiate splice-in - let _res = initiator_node + initiator_node .node .splice_channel( &channel_id, @@ -104,9 +104,7 @@ fn test_v1_splice_in() { assert_eq!(splice_init_msg.funding_pubkey.to_string(), expected_initiator_funding_key); assert!(splice_init_msg.require_confirmed_inputs.is_none()); - let _res = acceptor_node - .node - .handle_splice_init(initiator_node.node.get_our_node_id(), &splice_init_msg); + acceptor_node.node.handle_splice_init(initiator_node.node.get_our_node_id(), &splice_init_msg); // Extract the splice_ack message let splice_ack_msg = get_event_msg!( acceptor_node, @@ -130,9 +128,7 @@ fn test_v1_splice_in() { assert!(channel.confirmations.unwrap() > 0); } - let _res = initiator_node - .node - .handle_splice_ack(acceptor_node.node.get_our_node_id(), &splice_ack_msg); + initiator_node.node.handle_splice_ack(acceptor_node.node.get_our_node_id(), &splice_ack_msg); // still pre-splice channel: capacity not updated, channel usable, and funding tx set assert_eq!(initiator_node.node.list_channels().len(), 1); @@ -176,7 +172,7 @@ fn test_v1_splice_in() { assert_eq!(tx_add_input_msg.shared_input_txid, None); } - let _res = acceptor_node + acceptor_node .node .handle_tx_add_input(initiator_node.node.get_our_node_id(), &tx_add_input_msg); let tx_complete_msg = get_event_msg!( @@ -185,9 +181,7 @@ fn test_v1_splice_in() { initiator_node.node.get_our_node_id() ); - let _res = initiator_node - .node - .handle_tx_complete(acceptor_node.node.get_our_node_id(), &tx_complete_msg); + initiator_node.node.handle_tx_complete(acceptor_node.node.get_our_node_id(), &tx_complete_msg); // Second input let tx_add_input2_msg = get_event_msg!( &initiator_node, @@ -211,7 +205,7 @@ fn test_v1_splice_in() { ); } - let _res = acceptor_node + acceptor_node .node .handle_tx_add_input(initiator_node.node.get_our_node_id(), &tx_add_input2_msg); let tx_complete_msg = get_event_msg!( @@ -220,9 +214,7 @@ fn test_v1_splice_in() { initiator_node.node.get_our_node_id() ); - let _res = initiator_node - .node - .handle_tx_complete(acceptor_node.node.get_our_node_id(), &tx_complete_msg); + initiator_node.node.handle_tx_complete(acceptor_node.node.get_our_node_id(), &tx_complete_msg); // TxAddOutput for the change output let tx_add_output_msg = get_event_msg!( @@ -238,7 +230,7 @@ fn test_v1_splice_in() { assert_eq!(tx_add_output_msg.sats, 13979); // extra_splice_funding_input_sats - splice_in_sats } - let _res = acceptor_node + acceptor_node .node .handle_tx_add_output(initiator_node.node.get_our_node_id(), &tx_add_output_msg); let tx_complete_msg = get_event_msg!( @@ -247,9 +239,7 @@ fn test_v1_splice_in() { initiator_node.node.get_our_node_id() ); - let _res = initiator_node - .node - .handle_tx_complete(acceptor_node.node.get_our_node_id(), &tx_complete_msg); + initiator_node.node.handle_tx_complete(acceptor_node.node.get_our_node_id(), &tx_complete_msg); // TxAddOutput for the splice funding let tx_add_output2_msg = get_event_msg!( &initiator_node, @@ -264,7 +254,7 @@ fn test_v1_splice_in() { assert_eq!(tx_add_output2_msg.sats, post_splice_channel_value); } - let _res = acceptor_node + acceptor_node .node .handle_tx_add_output(initiator_node.node.get_our_node_id(), &tx_add_output2_msg); let _tx_complete_msg = get_event_msg!( @@ -274,9 +264,7 @@ fn test_v1_splice_in() { ); // TODO(splicing) This is the last tx_complete, which triggers the commitment flow, which is not yet fully implemented - let _res = initiator_node - .node - .handle_tx_complete(acceptor_node.node.get_our_node_id(), &tx_complete_msg); + initiator_node.node.handle_tx_complete(acceptor_node.node.get_our_node_id(), &tx_complete_msg); let events = initiator_node.node.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); match events[0] {