1use alloc::string::{String, ToString};
13use lightning::util::persist::KVStore;
14
15use core::default::Default;
16use core::ops::Deref;
17
18use crate::events::EventQueue;
19use crate::lsps0::ser::{LSPSProtocolMessageHandler, LSPSRequestId, LSPSResponseError};
20use crate::lsps2::event::LSPS2ClientEvent;
21use crate::message_queue::MessageQueue;
22use crate::prelude::{new_hash_map, new_hash_set, HashMap, HashSet};
23use crate::sync::{Arc, Mutex, RwLock};
24
25use lightning::ln::msgs::{ErrorAction, LightningError};
26use lightning::sign::EntropySource;
27use lightning::util::errors::APIError;
28use lightning::util::logger::Level;
29
30use bitcoin::secp256k1::PublicKey;
31
32use crate::lsps2::msgs::{
33 LSPS2BuyRequest, LSPS2BuyResponse, LSPS2GetInfoRequest, LSPS2GetInfoResponse, LSPS2Message,
34 LSPS2OpeningFeeParams, LSPS2Request, LSPS2Response,
35};
36
37#[derive(Clone, Debug, Copy, Default)]
39pub struct LSPS2ClientConfig {}
40
41struct InboundJITChannel {
42 payment_size_msat: Option<u64>,
43}
44
45impl InboundJITChannel {
46 fn new(payment_size_msat: Option<u64>) -> Self {
47 Self { payment_size_msat }
48 }
49}
50
51struct PeerState {
52 pending_get_info_requests: HashSet<LSPSRequestId>,
53 pending_buy_requests: HashMap<LSPSRequestId, InboundJITChannel>,
54}
55
56impl PeerState {
57 fn new() -> Self {
58 let pending_get_info_requests = new_hash_set();
59 let pending_buy_requests = new_hash_map();
60 Self { pending_get_info_requests, pending_buy_requests }
61 }
62}
63
64pub struct LSPS2ClientHandler<ES: Deref, K: Deref + Clone>
72where
73 ES::Target: EntropySource,
74 K::Target: KVStore,
75{
76 entropy_source: ES,
77 pending_messages: Arc<MessageQueue>,
78 pending_events: Arc<EventQueue<K>>,
79 per_peer_state: RwLock<HashMap<PublicKey, Mutex<PeerState>>>,
80 config: LSPS2ClientConfig,
81}
82
83impl<ES: Deref, K: Deref + Clone> LSPS2ClientHandler<ES, K>
84where
85 ES::Target: EntropySource,
86 K::Target: KVStore,
87{
88 pub(crate) fn new(
90 entropy_source: ES, pending_messages: Arc<MessageQueue>,
91 pending_events: Arc<EventQueue<K>>, config: LSPS2ClientConfig,
92 ) -> Self {
93 Self {
94 entropy_source,
95 pending_messages,
96 pending_events,
97 per_peer_state: RwLock::new(new_hash_map()),
98 config,
99 }
100 }
101
102 pub fn config(&self) -> &LSPS2ClientConfig {
104 &self.config
105 }
106
107 pub fn request_opening_params(
123 &self, counterparty_node_id: PublicKey, token: Option<String>,
124 ) -> LSPSRequestId {
125 let mut message_queue_notifier = self.pending_messages.notifier();
126
127 let request_id = crate::utils::generate_request_id(&self.entropy_source);
128
129 {
130 let mut outer_state_lock = self.per_peer_state.write().unwrap();
131 let inner_state_lock = outer_state_lock
132 .entry(counterparty_node_id)
133 .or_insert(Mutex::new(PeerState::new()));
134 let mut peer_state_lock = inner_state_lock.lock().unwrap();
135 peer_state_lock.pending_get_info_requests.insert(request_id.clone());
136 }
137
138 let request = LSPS2Request::GetInfo(LSPS2GetInfoRequest { token });
139 let msg = LSPS2Message::Request(request_id.clone(), request).into();
140 message_queue_notifier.enqueue(&counterparty_node_id, msg);
141
142 request_id
143 }
144
145 pub fn select_opening_params(
166 &self, counterparty_node_id: PublicKey, payment_size_msat: Option<u64>,
167 opening_fee_params: LSPS2OpeningFeeParams,
168 ) -> Result<LSPSRequestId, APIError> {
169 let mut message_queue_notifier = self.pending_messages.notifier();
170
171 let request_id = crate::utils::generate_request_id(&self.entropy_source);
172
173 {
174 let mut outer_state_lock = self.per_peer_state.write().unwrap();
175 let inner_state_lock = outer_state_lock
176 .entry(counterparty_node_id)
177 .or_insert(Mutex::new(PeerState::new()));
178 let mut peer_state_lock = inner_state_lock.lock().unwrap();
179
180 let jit_channel = InboundJITChannel::new(payment_size_msat);
181 if peer_state_lock
182 .pending_buy_requests
183 .insert(request_id.clone(), jit_channel)
184 .is_some()
185 {
186 return Err(APIError::APIMisuseError {
187 err: "Failed due to duplicate request_id. This should never happen!"
188 .to_string(),
189 });
190 }
191 }
192
193 let request = LSPS2Request::Buy(LSPS2BuyRequest { opening_fee_params, payment_size_msat });
194 let msg = LSPS2Message::Request(request_id.clone(), request).into();
195 message_queue_notifier.enqueue(&counterparty_node_id, msg);
196
197 Ok(request_id)
198 }
199
200 fn handle_get_info_response(
201 &self, request_id: LSPSRequestId, counterparty_node_id: &PublicKey,
202 result: LSPS2GetInfoResponse,
203 ) -> Result<(), LightningError> {
204 let event_queue_notifier = self.pending_events.notifier();
205
206 let outer_state_lock = self.per_peer_state.read().unwrap();
207 match outer_state_lock.get(counterparty_node_id) {
208 Some(inner_state_lock) => {
209 let mut peer_state = inner_state_lock.lock().unwrap();
210
211 if !peer_state.pending_get_info_requests.remove(&request_id) {
212 return Err(LightningError {
213 err: format!(
214 "Received get_info response for an unknown request: {:?}",
215 request_id
216 ),
217 action: ErrorAction::IgnoreAndLog(Level::Debug),
218 });
219 }
220
221 event_queue_notifier.enqueue(LSPS2ClientEvent::OpeningParametersReady {
222 request_id,
223 counterparty_node_id: *counterparty_node_id,
224 opening_fee_params_menu: result.opening_fee_params_menu,
225 });
226 },
227 None => {
228 return Err(LightningError {
229 err: format!(
230 "Received get_info response from unknown peer: {}",
231 counterparty_node_id
232 ),
233 action: ErrorAction::IgnoreAndLog(Level::Debug),
234 })
235 },
236 }
237
238 Ok(())
239 }
240
241 fn handle_get_info_error(
242 &self, request_id: LSPSRequestId, counterparty_node_id: &PublicKey,
243 error: LSPSResponseError,
244 ) -> Result<(), LightningError> {
245 let event_queue_notifier = self.pending_events.notifier();
246 let outer_state_lock = self.per_peer_state.read().unwrap();
247 match outer_state_lock.get(counterparty_node_id) {
248 Some(inner_state_lock) => {
249 let mut peer_state = inner_state_lock.lock().unwrap();
250
251 if !peer_state.pending_get_info_requests.remove(&request_id) {
252 return Err(LightningError {
253 err: format!(
254 "Received get_info error for an unknown request: {:?}",
255 request_id
256 ),
257 action: ErrorAction::IgnoreAndLog(Level::Debug),
258 });
259 }
260
261 let lightning_error = LightningError {
262 err: format!(
263 "Received get_info error response for request {:?}: {:?}",
264 request_id, error
265 ),
266 action: ErrorAction::IgnoreAndLog(Level::Error),
267 };
268
269 event_queue_notifier.enqueue(LSPS2ClientEvent::GetInfoFailed {
270 request_id,
271 counterparty_node_id: *counterparty_node_id,
272 error,
273 });
274
275 Err(lightning_error)
276 },
277 None => {
278 return Err(LightningError { err: format!("Received error response for a get_info request from an unknown counterparty {}",counterparty_node_id), action: ErrorAction::IgnoreAndLog(Level::Debug)});
279 },
280 }
281 }
282
283 fn handle_buy_response(
284 &self, request_id: LSPSRequestId, counterparty_node_id: &PublicKey,
285 result: LSPS2BuyResponse,
286 ) -> Result<(), LightningError> {
287 let event_queue_notifier = self.pending_events.notifier();
288
289 let outer_state_lock = self.per_peer_state.read().unwrap();
290 match outer_state_lock.get(counterparty_node_id) {
291 Some(inner_state_lock) => {
292 let mut peer_state = inner_state_lock.lock().unwrap();
293
294 let jit_channel =
295 peer_state.pending_buy_requests.remove(&request_id).ok_or(LightningError {
296 err: format!(
297 "Received buy response for an unknown request: {:?}",
298 request_id
299 ),
300 action: ErrorAction::IgnoreAndLog(Level::Debug),
301 })?;
302
303 if let Ok(intercept_scid) = result.jit_channel_scid.to_scid() {
304 event_queue_notifier.enqueue(LSPS2ClientEvent::InvoiceParametersReady {
305 request_id,
306 counterparty_node_id: *counterparty_node_id,
307 intercept_scid,
308 cltv_expiry_delta: result.lsp_cltv_expiry_delta,
309 payment_size_msat: jit_channel.payment_size_msat,
310 });
311 } else {
312 return Err(LightningError {
313 err: format!(
314 "Received buy response with an invalid intercept scid {:?}",
315 result.jit_channel_scid
316 ),
317 action: ErrorAction::IgnoreAndLog(Level::Info),
318 });
319 }
320 },
321 None => {
322 return Err(LightningError {
323 err: format!(
324 "Received buy response from unknown peer: {}",
325 counterparty_node_id
326 ),
327 action: ErrorAction::IgnoreAndLog(Level::Debug),
328 });
329 },
330 }
331 Ok(())
332 }
333
334 fn handle_buy_error(
335 &self, request_id: LSPSRequestId, counterparty_node_id: &PublicKey,
336 error: LSPSResponseError,
337 ) -> Result<(), LightningError> {
338 let event_queue_notifier = self.pending_events.notifier();
339 let outer_state_lock = self.per_peer_state.read().unwrap();
340 match outer_state_lock.get(counterparty_node_id) {
341 Some(inner_state_lock) => {
342 let mut peer_state = inner_state_lock.lock().unwrap();
343
344 peer_state.pending_buy_requests.remove(&request_id).ok_or(LightningError {
345 err: format!("Received buy error for an unknown request: {:?}", request_id),
346 action: ErrorAction::IgnoreAndLog(Level::Debug),
347 })?;
348
349 let lightning_error = LightningError {
350 err: format!(
351 "Received buy error response for request {:?}: {:?}",
352 request_id, error
353 ),
354 action: ErrorAction::IgnoreAndLog(Level::Error),
355 };
356
357 event_queue_notifier.enqueue(LSPS2ClientEvent::BuyRequestFailed {
358 request_id,
359 counterparty_node_id: *counterparty_node_id,
360 error,
361 });
362
363 Err(lightning_error)
364 },
365 None => {
366 return Err(LightningError {
367 err: format!(
368 "Received error response for a buy request from an unknown counterparty {}",
369 counterparty_node_id
370 ),
371 action: ErrorAction::IgnoreAndLog(Level::Debug),
372 });
373 },
374 }
375 }
376}
377
378impl<ES: Deref, K: Deref + Clone> LSPSProtocolMessageHandler for LSPS2ClientHandler<ES, K>
379where
380 ES::Target: EntropySource,
381 K::Target: KVStore,
382{
383 type ProtocolMessage = LSPS2Message;
384 const PROTOCOL_NUMBER: Option<u16> = Some(2);
385
386 fn handle_message(
387 &self, message: Self::ProtocolMessage, counterparty_node_id: &PublicKey,
388 ) -> Result<(), LightningError> {
389 match message {
390 LSPS2Message::Response(request_id, response) => match response {
391 LSPS2Response::GetInfo(result) => {
392 self.handle_get_info_response(request_id, counterparty_node_id, result)
393 },
394 LSPS2Response::GetInfoError(error) => {
395 self.handle_get_info_error(request_id, counterparty_node_id, error)
396 },
397 LSPS2Response::Buy(result) => {
398 self.handle_buy_response(request_id, counterparty_node_id, result)
399 },
400 LSPS2Response::BuyError(error) => {
401 self.handle_buy_error(request_id, counterparty_node_id, error)
402 },
403 },
404 _ => {
405 debug_assert!(
406 false,
407 "Client handler received LSPS2 request message. This should never happen."
408 );
409 Err(LightningError { err: format!("Client handler received LSPS2 request message from node {}. This should never happen.", counterparty_node_id), action: ErrorAction::IgnoreAndLog(Level::Info)})
410 },
411 }
412 }
413}
414
415#[cfg(test)]
416mod tests {}