@@ -4741,7 +4741,9 @@ impl<
47414741 /// [`Event::DiscardFunding`] is seen.
47424742 ///
47434743 /// After initial signatures have been exchanged, [`Event::FundingTransactionReadyForSigning`]
4744- /// will be generated and [`ChannelManager::funding_transaction_signed`] should be called.
4744+ /// may be generated. To proceed, call [`ChannelManager::funding_transaction_signed`]. To cancel
4745+ /// the pending splice negotiation instead, call [`ChannelManager::cancel_splice`] before
4746+ /// providing the funding signatures.
47454747 ///
47464748 /// If any failures occur while negotiating the funding transaction, an [`Event::SpliceFailed`]
47474749 /// will be emitted. Any contributed inputs no longer used will be included here and thus can
@@ -4887,96 +4889,108 @@ impl<
48874889 }
48884890 }
48894891
4890- #[cfg(test)]
4891- pub(crate) fn abandon_splice(
4892- &self, channel_id: &ChannelId, counterparty_node_id: &PublicKey,
4893- ) -> Result<(), APIError> {
4894- let mut res = Ok(());
4895- PersistenceNotifierGuard::optionally_notify(self, || {
4896- let result = self.internal_abandon_splice(channel_id, counterparty_node_id);
4897- res = result;
4898- match res {
4899- Ok(_) => NotifyOption::SkipPersistHandleEvents,
4900- Err(_) => NotifyOption::SkipPersistNoEvents,
4901- }
4902- });
4903- res
4904- }
4905-
4906- #[cfg(test)]
4907- fn internal_abandon_splice(
4892+ /// Cancels a pending splice negotiation for which a local contribution was made and queues a
4893+ /// `tx_abort` for the counterparty.
4894+ ///
4895+ /// This is primarily useful after receiving an [`Event::FundingTransactionReadyForSigning`] for
4896+ /// a splice if you no longer wish to proceed. The pending splice must still be pending
4897+ /// negotiation, which for the final signing stage means
4898+ /// [`ChannelManager::funding_transaction_signed`] must not have been called yet.
4899+ ///
4900+ /// Returns [`ChannelUnavailable`] when a channel is not found or an incorrect
4901+ /// `counterparty_node_id` is provided.
4902+ ///
4903+ /// Returns [`APIMisuseError`] when the channel is not funded, has no pending splice to cancel,
4904+ /// the pending splice has no local contribution to reclaim, or the pending splice can no longer
4905+ /// be canceled.
4906+ ///
4907+ /// [`Event::FundingTransactionReadyForSigning`]: events::Event::FundingTransactionReadyForSigning
4908+ /// [`ChannelUnavailable`]: APIError::ChannelUnavailable
4909+ /// [`APIMisuseError`]: APIError::APIMisuseError
4910+ pub fn cancel_splice(
49084911 &self, channel_id: &ChannelId, counterparty_node_id: &PublicKey,
49094912 ) -> Result<(), APIError> {
4910- let per_peer_state = self.per_peer_state.read().unwrap();
4911-
4912- let peer_state_mutex = match per_peer_state
4913- .get(counterparty_node_id)
4914- .ok_or_else(|| APIError::no_such_peer(counterparty_node_id))
4915- {
4916- Ok(p) => p,
4917- Err(e) => return Err(e),
4918- };
4919-
4920- let mut peer_state_lock = peer_state_mutex.lock().unwrap();
4921- let peer_state = &mut *peer_state_lock;
4913+ let mut result = Ok(());
4914+ PersistenceNotifierGuard::manually_notify(self, || {
4915+ let per_peer_state = self.per_peer_state.read().unwrap();
4916+ let peer_state_mutex = match per_peer_state
4917+ .get(counterparty_node_id)
4918+ .ok_or_else(|| APIError::no_such_peer(counterparty_node_id))
4919+ {
4920+ Ok(p) => p,
4921+ Err(e) => {
4922+ result = Err(e);
4923+ return;
4924+ },
4925+ };
4926+ let mut peer_state_lock = peer_state_mutex.lock().unwrap();
4927+ let peer_state = &mut *peer_state_lock;
49224928
4923- // Look for the channel
4924- match peer_state.channel_by_id.entry(*channel_id) {
4925- hash_map::Entry::Occupied(mut chan_phase_entry) => {
4926- if !chan_phase_entry.get().context().is_connected() {
4927- // TODO: We should probably support this, but right now `splice_channel` refuses when
4928- // the peer is disconnected, so we just check it here.
4929- return Err(APIError::ChannelUnavailable {
4930- err: "Cannot abandon splice while peer is disconnected".to_owned(),
4931- });
4932- }
4929+ match peer_state.channel_by_id.entry(*channel_id) {
4930+ hash_map::Entry::Occupied(mut chan_entry) => {
4931+ if let Some(channel) = chan_entry.get_mut().as_funded_mut() {
4932+ let InteractiveTxMsgError { err, splice_funding_failed, exited_quiescence } =
4933+ match channel.cancel_splice() {
4934+ Ok(v) => v,
4935+ Err(e) => {
4936+ result = Err(e);
4937+ return;
4938+ },
4939+ };
49334940
4934- if let Some(chan) = chan_phase_entry.get_mut().as_funded_mut() {
4935- let (tx_abort, splice_funding_failed) = chan.abandon_splice()?;
4941+ let splice_funding_failed = splice_funding_failed
4942+ .expect("Only splices with local contributions can be canceled");
4943+ {
4944+ let pending_events = &mut self.pending_events.lock().unwrap();
4945+ pending_events.push_back((
4946+ events::Event::SpliceFailed {
4947+ channel_id: *channel_id,
4948+ counterparty_node_id: *counterparty_node_id,
4949+ user_channel_id: channel.context().get_user_id(),
4950+ abandoned_funding_txo: splice_funding_failed.funding_txo,
4951+ channel_type: splice_funding_failed.channel_type.clone(),
4952+ },
4953+ None,
4954+ ));
4955+ pending_events.push_back((
4956+ events::Event::DiscardFunding {
4957+ channel_id: *channel_id,
4958+ funding_info: FundingInfo::Contribution {
4959+ inputs: splice_funding_failed.contributed_inputs,
4960+ outputs: splice_funding_failed.contributed_outputs,
4961+ },
4962+ },
4963+ None,
4964+ ));
4965+ }
49364966
4937- peer_state.pending_msg_events.push(MessageSendEvent::SendTxAbort {
4938- node_id: *counterparty_node_id,
4939- msg: tx_abort,
4940- });
4967+ mem::drop(peer_state_lock);
4968+ mem::drop(per_peer_state);
49414969
4942- if let Some(splice_funding_failed) = splice_funding_failed {
4943- let pending_events = &mut self.pending_events.lock().unwrap();
4944- pending_events.push_back((
4945- events::Event::SpliceFailed {
4946- channel_id: *channel_id,
4947- counterparty_node_id: *counterparty_node_id,
4948- user_channel_id: chan.context.get_user_id(),
4949- abandoned_funding_txo: splice_funding_failed.funding_txo,
4950- channel_type: splice_funding_failed.channel_type,
4951- },
4952- None,
4953- ));
4954- pending_events.push_back((
4955- events::Event::DiscardFunding {
4956- channel_id: *channel_id,
4957- funding_info: FundingInfo::Contribution {
4958- inputs: splice_funding_failed.contributed_inputs,
4959- outputs: splice_funding_failed.contributed_outputs,
4960- },
4961- },
4962- None,
4963- ));
4970+ self.needs_persist_flag.store(true, Ordering::Release);
4971+ self.event_persist_notifier.notify();
4972+ let err: Result<(), _> =
4973+ Err(MsgHandleErrInternal::from_chan_no_close(err, *channel_id)
4974+ .with_exited_quiescence(exited_quiescence));
4975+ let _ = self.handle_error(err, *counterparty_node_id);
4976+ } else {
4977+ result = Err(APIError::ChannelUnavailable {
4978+ err: format!(
4979+ "Channel with id {} is not funded, cannot cancel splice",
4980+ channel_id
4981+ ),
4982+ });
4983+ return;
49644984 }
4965-
4966- Ok(())
4967- } else {
4968- Err(APIError::ChannelUnavailable {
4969- err: format!(
4970- "Channel with id {} is not funded, cannot abandon splice",
4971- channel_id
4972- ),
4973- })
4974- }
4975- },
4976- hash_map::Entry::Vacant(_) => {
4977- Err(APIError::no_such_channel_for_peer(channel_id, counterparty_node_id))
4978- },
4979- }
4985+ },
4986+ hash_map::Entry::Vacant(_) => {
4987+ result =
4988+ Err(APIError::no_such_channel_for_peer(channel_id, counterparty_node_id));
4989+ return;
4990+ },
4991+ }
4992+ });
4993+ result
49804994 }
49814995
49824996 fn forward_needs_intercept_to_known_chan(
0 commit comments