@@ -32,10 +32,11 @@ use crate::prelude::{new_hash_map, HashMap};
3232use crate :: sync:: { Arc , Mutex , MutexGuard , RwLock } ;
3333
3434use lightning:: events:: HTLCHandlingFailureType ;
35- use lightning:: ln:: channelmanager:: { AChannelManager , InterceptId } ;
35+ use lightning:: ln:: channelmanager:: { AChannelManager , FailureCode , InterceptId } ;
3636use lightning:: ln:: msgs:: { ErrorAction , LightningError } ;
3737use lightning:: ln:: types:: ChannelId ;
3838use lightning:: util:: errors:: APIError ;
39+ use lightning:: util:: hash_tables:: HashSet ;
3940use lightning:: util:: logger:: Level ;
4041
4142use lightning_types:: payment:: PaymentHash ;
@@ -985,6 +986,131 @@ where
985986 Ok ( ( ) )
986987 }
987988
989+ /// Abandons a pending JIT‐open flow for `user_channel_id`, removing all local state.
990+ ///
991+ /// This removes the intercept SCID, any outbound channel state, and associated
992+ /// channel‐ID mappings for the specified `user_channel_id`, but only while the JIT
993+ /// channel is still in `PendingInitialPayment` or `PendingChannelOpen`.
994+ ///
995+ /// Returns an error if:
996+ /// - there is no channel matching `user_channel_id`, or
997+ /// - the channel has already advanced past `PendingChannelOpen` (e.g. to
998+ /// `PendingPaymentForward` or beyond).
999+ ///
1000+ /// Note: this does *not* close or roll back any on‐chain channel which may already
1001+ /// have been opened. The caller must only invoke this before a channel is actually
1002+ /// confirmed (or else provide its own on‐chain cleanup) and is responsible for
1003+ /// managing any pending channel open attempts separately.
1004+ pub fn channel_open_abandoned (
1005+ & self , counterparty_node_id : & PublicKey , user_channel_id : u128 ,
1006+ ) -> Result < ( ) , APIError > {
1007+ let outer_state_lock = self . per_peer_state . read ( ) . unwrap ( ) ;
1008+ let inner_state_lock =
1009+ outer_state_lock. get ( counterparty_node_id) . ok_or_else ( || APIError :: APIMisuseError {
1010+ err : format ! ( "No counterparty state for: {}" , counterparty_node_id) ,
1011+ } ) ?;
1012+ let mut peer_state = inner_state_lock. lock ( ) . unwrap ( ) ;
1013+
1014+ let intercept_scid = peer_state
1015+ . intercept_scid_by_user_channel_id
1016+ . remove ( & user_channel_id)
1017+ . ok_or_else ( || APIError :: APIMisuseError {
1018+ err : format ! ( "Could not find a channel with user_channel_id {}" , user_channel_id) ,
1019+ } ) ?;
1020+
1021+ if let Some ( jit_channel) =
1022+ peer_state. outbound_channels_by_intercept_scid . get ( & intercept_scid)
1023+ {
1024+ if !matches ! (
1025+ jit_channel. state,
1026+ OutboundJITChannelState :: PendingInitialPayment { .. }
1027+ | OutboundJITChannelState :: PendingChannelOpen { .. }
1028+ ) {
1029+ return Err ( APIError :: APIMisuseError {
1030+ err : "Cannot abandon channel open after channel creation or payment forwarding"
1031+ . to_string ( ) ,
1032+ } ) ;
1033+ }
1034+ }
1035+
1036+ peer_state. outbound_channels_by_intercept_scid . remove ( & intercept_scid) ;
1037+
1038+ peer_state. intercept_scid_by_channel_id . retain ( |_, & mut scid| scid != intercept_scid) ;
1039+
1040+ Ok ( ( ) )
1041+ }
1042+
1043+ /// Used to fail intercepted HTLCs backwards when a channel open attempt ultimately fails.
1044+ ///
1045+ /// This function should be called after receiving an [`LSPS2ServiceEvent::OpenChannel`] event
1046+ /// but only if the channel could not be successfully established. It resets the JIT channel
1047+ /// state so that the payer may try the payment again.
1048+ ///
1049+ /// [`LSPS2ServiceEvent::OpenChannel`]: crate::lsps2::event::LSPS2ServiceEvent::OpenChannel
1050+ pub fn channel_open_failed (
1051+ & self , counterparty_node_id : & PublicKey , user_channel_id : u128 ,
1052+ ) -> Result < ( ) , APIError > {
1053+ let outer_state_lock = self . per_peer_state . read ( ) . unwrap ( ) ;
1054+
1055+ let inner_state_lock =
1056+ outer_state_lock. get ( counterparty_node_id) . ok_or_else ( || APIError :: APIMisuseError {
1057+ err : format ! ( "No counterparty state for: {}" , counterparty_node_id) ,
1058+ } ) ?;
1059+
1060+ let mut peer_state = inner_state_lock. lock ( ) . unwrap ( ) ;
1061+
1062+ let intercept_scid = peer_state
1063+ . intercept_scid_by_user_channel_id
1064+ . get ( & user_channel_id)
1065+ . copied ( )
1066+ . ok_or_else ( || APIError :: APIMisuseError {
1067+ err : format ! ( "Could not find a channel with user_channel_id {}" , user_channel_id) ,
1068+ } ) ?;
1069+
1070+ let jit_channel = peer_state
1071+ . outbound_channels_by_intercept_scid
1072+ . get_mut ( & intercept_scid)
1073+ . ok_or_else ( || APIError :: APIMisuseError {
1074+ err : format ! (
1075+ "Failed to map intercept_scid {} for user_channel_id {} to a channel." ,
1076+ intercept_scid, user_channel_id,
1077+ ) ,
1078+ } ) ?;
1079+
1080+ if !matches ! ( jit_channel. state, OutboundJITChannelState :: PendingChannelOpen { .. } ) {
1081+ return Err ( APIError :: APIMisuseError {
1082+ err : "Channel is not in the PendingChannelOpen state." . to_string ( ) ,
1083+ } ) ;
1084+ }
1085+
1086+ let mut payment_queue = match & jit_channel. state {
1087+ OutboundJITChannelState :: PendingChannelOpen { payment_queue, .. } => {
1088+ payment_queue. clone ( )
1089+ } ,
1090+ _ => {
1091+ return Err ( APIError :: APIMisuseError {
1092+ err : "Channel is not in the PendingChannelOpen state." . to_string ( ) ,
1093+ } ) ;
1094+ } ,
1095+ } ;
1096+ let payment_hashes: Vec < _ > = payment_queue
1097+ . clear ( )
1098+ . into_iter ( )
1099+ . map ( |htlc| htlc. payment_hash )
1100+ . collect :: < HashSet < _ > > ( )
1101+ . into_iter ( )
1102+ . collect ( ) ;
1103+ for payment_hash in payment_hashes {
1104+ self . channel_manager
1105+ . get_cm ( )
1106+ . fail_htlc_backwards_with_reason ( & payment_hash, FailureCode :: TemporaryNodeFailure ) ;
1107+ }
1108+
1109+ jit_channel. state = OutboundJITChannelState :: PendingInitialPayment { payment_queue } ;
1110+
1111+ Ok ( ( ) )
1112+ }
1113+
9881114 /// Forward [`Event::ChannelReady`] event parameters into this function.
9891115 ///
9901116 /// Will forward the intercepted HTLC if it matches a channel
0 commit comments