Skip to content
This repository was archived by the owner on Jan 6, 2025. It is now read-only.

Commit b82779c

Browse files
ability to signal channel open failure
1 parent 30e80d4 commit b82779c

File tree

2 files changed

+91
-9
lines changed

2 files changed

+91
-9
lines changed

src/lsps2/payment_queue.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ impl PaymentQueue {
4949
position.map(|position| self.payments.remove(position))
5050
}
5151

52-
pub(crate) fn clear(&mut self) -> Vec<InterceptedHTLC> {
53-
self.payments.drain(..).map(|(_k, v)| v).flatten().collect()
52+
pub(crate) fn clear(&mut self) -> Vec<(PaymentHash, Vec<InterceptedHTLC>)> {
53+
self.payments.drain(..).collect()
5454
}
5555
}
5656

@@ -109,11 +109,14 @@ mod tests {
109109
);
110110
assert_eq!(
111111
payment_queue.clear(),
112-
vec![InterceptedHTLC {
113-
intercept_id: InterceptId([1; 32]),
114-
expected_outbound_amount_msat: 300_000_000,
115-
payment_hash: PaymentHash([101; 32]),
116-
}]
112+
vec![(
113+
PaymentHash([101; 32]),
114+
vec![InterceptedHTLC {
115+
intercept_id: InterceptId([1; 32]),
116+
expected_outbound_amount_msat: 300_000_000,
117+
payment_hash: PaymentHash([101; 32]),
118+
}]
119+
)]
117120
);
118121
}
119122
}

src/lsps2/service.rs

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::prelude::{HashMap, String, ToString, Vec};
1919
use crate::sync::{Arc, Mutex, RwLock};
2020

2121
use lightning::events::HTLCDestination;
22-
use lightning::ln::channelmanager::{AChannelManager, InterceptId};
22+
use lightning::ln::channelmanager::{AChannelManager, FailureCode, InterceptId};
2323
use lightning::ln::msgs::{ErrorAction, LightningError};
2424
use lightning::ln::{ChannelId, PaymentHash};
2525
use lightning::util::errors::APIError;
@@ -362,7 +362,13 @@ impl OutboundJITChannelState {
362362
let mut payment_queue_lock = payment_queue.lock().unwrap();
363363
let payment_forwarded =
364364
OutboundJITChannelState::PaymentForwarded { channel_id: *channel_id };
365-
let forward_htlcs = ForwardHTLCsAction(*channel_id, payment_queue_lock.clear());
365+
let htlcs = payment_queue_lock
366+
.clear()
367+
.into_iter()
368+
.map(|(_, htlcs)| htlcs)
369+
.flatten()
370+
.collect();
371+
let forward_htlcs = ForwardHTLCsAction(*channel_id, htlcs);
366372
Ok((payment_forwarded, Some(forward_htlcs)))
367373
},
368374
OutboundJITChannelState::PaymentForwarded { channel_id } => {
@@ -898,6 +904,79 @@ where
898904
Ok(())
899905
}
900906

907+
/// Used by LSP to fail intercepted htlcs backwards when the channel open fails for any reason.
908+
///
909+
/// Should be called in response to receiving a [`LSPS2ServiceEvent::OpenChannel`] event.
910+
///
911+
/// The JIT channel state is reset such that the payer can attempt payment again.
912+
/// [`LSPS2ServiceEvent::OpenChannel`]: crate::lsps2::event::LSPS2ServiceEvent::OpenChannel
913+
pub fn channel_open_failed(
914+
&self, counterparty_node_id: &PublicKey, user_channel_id: u128,
915+
) -> Result<(), APIError> {
916+
let outer_state_lock = self.per_peer_state.read().unwrap();
917+
match outer_state_lock.get(counterparty_node_id) {
918+
Some(inner_state_lock) => {
919+
let mut peer_state = inner_state_lock.lock().unwrap();
920+
921+
if let Some(intercept_scid) =
922+
peer_state.intercept_scid_by_user_channel_id.get(&user_channel_id).copied()
923+
{
924+
if let Some(jit_channel) =
925+
peer_state.outbound_channels_by_intercept_scid.get_mut(&intercept_scid)
926+
{
927+
let new_state = if let OutboundJITChannelState::PendingChannelOpen {
928+
payment_queue,
929+
..
930+
} = &jit_channel.state
931+
{
932+
let mut queue = payment_queue.lock().unwrap();
933+
let payment_hashes = queue
934+
.clear()
935+
.into_iter()
936+
.map(|(payment_hash, _)| payment_hash)
937+
.collect::<Vec<_>>();
938+
for payment_hash in payment_hashes {
939+
self.channel_manager.get_cm().fail_htlc_backwards_with_reason(
940+
&payment_hash,
941+
FailureCode::TemporaryNodeFailure,
942+
);
943+
}
944+
OutboundJITChannelState::PendingInitialPayment {
945+
payment_queue: payment_queue.clone(),
946+
}
947+
} else {
948+
return Err(APIError::APIMisuseError {
949+
err: format!("Channel is not in the PendingChannelOpen state.",),
950+
});
951+
};
952+
jit_channel.state = new_state;
953+
} else {
954+
return Err(APIError::APIMisuseError {
955+
err: format!(
956+
"Failed to map the stored intercept_scid {} for the provided user_channel_id {} to a channel.",
957+
intercept_scid,
958+
user_channel_id,
959+
),
960+
});
961+
}
962+
} else {
963+
return Err(APIError::APIMisuseError {
964+
err: format!(
965+
"Could not find a channel with user_channel_id {}",
966+
user_channel_id
967+
),
968+
});
969+
}
970+
},
971+
None => {
972+
return Err(APIError::APIMisuseError {
973+
err: format!("No counterparty state for: {}", counterparty_node_id),
974+
});
975+
},
976+
}
977+
Ok(())
978+
}
979+
901980
/// Forward [`Event::ChannelReady`] event parameters into this function.
902981
///
903982
/// Will forward the intercepted HTLC if it matches a channel

0 commit comments

Comments
 (0)