1use super::event::LSPS1ClientEvent;
13use super::msgs::{
14 CreateOrderRequest, CreateOrderResponse, GetInfoRequest, GetInfoResponse, GetOrderRequest,
15 LSPS1Message, LSPS1Request, LSPS1Response, OrderId, OrderParameters,
16};
17use crate::message_queue::MessageQueue;
18
19use crate::events::{Event, EventQueue};
20use crate::lsps0::ser::{ProtocolMessageHandler, RequestId, ResponseError};
21use crate::prelude::{new_hash_map, HashMap, HashSet};
22use crate::sync::{Arc, Mutex, RwLock};
23
24use lightning::ln::msgs::{ErrorAction, LightningError};
25use lightning::sign::EntropySource;
26use lightning::util::logger::Level;
27
28use bitcoin::secp256k1::PublicKey;
29use bitcoin::Address;
30
31use core::ops::Deref;
32
33#[derive(Clone, Debug)]
35pub struct LSPS1ClientConfig {
36 pub max_channel_fees_msat: Option<u64>,
38}
39
40#[derive(Default)]
41struct PeerState {
42 pending_get_info_requests: HashSet<RequestId>,
43 pending_create_order_requests: HashSet<RequestId>,
44 pending_get_order_requests: HashSet<RequestId>,
45}
46
47pub struct LSPS1ClientHandler<ES: Deref>
49where
50 ES::Target: EntropySource,
51{
52 entropy_source: ES,
53 pending_messages: Arc<MessageQueue>,
54 pending_events: Arc<EventQueue>,
55 per_peer_state: RwLock<HashMap<PublicKey, Mutex<PeerState>>>,
56 _config: LSPS1ClientConfig,
57}
58
59impl<ES: Deref> LSPS1ClientHandler<ES>
60where
61 ES::Target: EntropySource,
62{
63 pub(crate) fn new(
65 entropy_source: ES, pending_messages: Arc<MessageQueue>, pending_events: Arc<EventQueue>,
66 config: LSPS1ClientConfig,
67 ) -> Self {
68 Self {
69 entropy_source,
70 pending_messages,
71 pending_events,
72 per_peer_state: RwLock::new(new_hash_map()),
73 _config: config,
74 }
75 }
76
77 pub fn request_supported_options(&self, counterparty_node_id: PublicKey) -> RequestId {
87 let request_id = crate::utils::generate_request_id(&self.entropy_source);
88 {
89 let mut outer_state_lock = self.per_peer_state.write().unwrap();
90 let inner_state_lock = outer_state_lock
91 .entry(counterparty_node_id)
92 .or_insert(Mutex::new(PeerState::default()));
93 let mut peer_state_lock = inner_state_lock.lock().unwrap();
94 peer_state_lock.pending_get_info_requests.insert(request_id.clone());
95 }
96
97 let request = LSPS1Request::GetInfo(GetInfoRequest {});
98 let msg = LSPS1Message::Request(request_id.clone(), request).into();
99 self.pending_messages.enqueue(&counterparty_node_id, msg);
100 request_id
101 }
102
103 fn handle_get_info_response(
104 &self, request_id: RequestId, counterparty_node_id: &PublicKey, result: GetInfoResponse,
105 ) -> Result<(), LightningError> {
106 let outer_state_lock = self.per_peer_state.write().unwrap();
107
108 match outer_state_lock.get(counterparty_node_id) {
109 Some(inner_state_lock) => {
110 let mut peer_state_lock = inner_state_lock.lock().unwrap();
111
112 if !peer_state_lock.pending_get_info_requests.remove(&request_id) {
113 return Err(LightningError {
114 err: format!(
115 "Received get_info response for an unknown request: {:?}",
116 request_id
117 ),
118 action: ErrorAction::IgnoreAndLog(Level::Debug),
119 });
120 }
121
122 self.pending_events.enqueue(Event::LSPS1Client(
123 LSPS1ClientEvent::SupportedOptionsReady {
124 counterparty_node_id: *counterparty_node_id,
125 supported_options: result.options,
126 request_id,
127 },
128 ));
129 Ok(())
130 },
131 None => Err(LightningError {
132 err: format!(
133 "Received get_info response from unknown peer: {:?}",
134 counterparty_node_id
135 ),
136 action: ErrorAction::IgnoreAndLog(Level::Debug),
137 }),
138 }
139 }
140
141 fn handle_get_info_error(
142 &self, request_id: RequestId, counterparty_node_id: &PublicKey, error: ResponseError,
143 ) -> Result<(), LightningError> {
144 let outer_state_lock = self.per_peer_state.read().unwrap();
145 match outer_state_lock.get(counterparty_node_id) {
146 Some(inner_state_lock) => {
147 let mut peer_state_lock = inner_state_lock.lock().unwrap();
148
149 if !peer_state_lock.pending_get_info_requests.remove(&request_id) {
150 return Err(LightningError {
151 err: format!(
152 "Received get_info error for an unknown request: {:?}",
153 request_id
154 ),
155 action: ErrorAction::IgnoreAndLog(Level::Debug),
156 });
157 }
158
159 self.pending_events.enqueue(Event::LSPS1Client(
160 LSPS1ClientEvent::SupportedOptionsRequestFailed {
161 request_id: request_id.clone(),
162 counterparty_node_id: *counterparty_node_id,
163 error: error.clone(),
164 },
165 ));
166
167 Err(LightningError {
168 err: format!(
169 "Received get_info error response for request {:?}: {:?}",
170 request_id, error
171 ),
172 action: ErrorAction::IgnoreAndLog(Level::Error),
173 })
174 },
175 None => {
176 return Err(LightningError {
177 err: format!(
178 "Received get_info error response from an unknown counterparty ({:?})",
179 counterparty_node_id
180 ),
181 action: ErrorAction::IgnoreAndLog(Level::Debug),
182 });
183 },
184 }
185 }
186
187 pub fn create_order(
191 &self, counterparty_node_id: &PublicKey, order: OrderParameters,
192 refund_onchain_address: Option<Address>,
193 ) -> RequestId {
194 let (request_id, request_msg) = {
195 let mut outer_state_lock = self.per_peer_state.write().unwrap();
196 let inner_state_lock = outer_state_lock
197 .entry(*counterparty_node_id)
198 .or_insert(Mutex::new(PeerState::default()));
199 let mut peer_state_lock = inner_state_lock.lock().unwrap();
200
201 let request_id = crate::utils::generate_request_id(&self.entropy_source);
202 let request =
203 LSPS1Request::CreateOrder(CreateOrderRequest { order, refund_onchain_address });
204 let msg = LSPS1Message::Request(request_id.clone(), request).into();
205 peer_state_lock.pending_create_order_requests.insert(request_id.clone());
206
207 (request_id, Some(msg))
208 };
209
210 if let Some(msg) = request_msg {
211 self.pending_messages.enqueue(&counterparty_node_id, msg);
212 }
213
214 request_id
215 }
216
217 fn handle_create_order_response(
218 &self, request_id: RequestId, counterparty_node_id: &PublicKey,
219 response: CreateOrderResponse,
220 ) -> Result<(), LightningError> {
221 let outer_state_lock = self.per_peer_state.read().unwrap();
222 match outer_state_lock.get(counterparty_node_id) {
223 Some(inner_state_lock) => {
224 let mut peer_state_lock = inner_state_lock.lock().unwrap();
225
226 if !peer_state_lock.pending_create_order_requests.remove(&request_id) {
227 return Err(LightningError {
228 err: format!(
229 "Received create_order response for an unknown request: {:?}",
230 request_id
231 ),
232 action: ErrorAction::IgnoreAndLog(Level::Debug),
233 });
234 }
235
236 self.pending_events.enqueue(Event::LSPS1Client(LSPS1ClientEvent::OrderCreated {
237 request_id,
238 counterparty_node_id: *counterparty_node_id,
239 order_id: response.order_id,
240 order: response.order,
241 payment: response.payment,
242 channel: response.channel,
243 }));
244 },
245 None => {
246 return Err(LightningError {
247 err: format!(
248 "Received create_order response from unknown peer: {}",
249 counterparty_node_id
250 ),
251 action: ErrorAction::IgnoreAndLog(Level::Debug),
252 })
253 },
254 }
255
256 Ok(())
257 }
258
259 fn handle_create_order_error(
260 &self, request_id: RequestId, counterparty_node_id: &PublicKey, error: ResponseError,
261 ) -> Result<(), LightningError> {
262 let outer_state_lock = self.per_peer_state.read().unwrap();
263 match outer_state_lock.get(counterparty_node_id) {
264 Some(inner_state_lock) => {
265 let mut peer_state_lock = inner_state_lock.lock().unwrap();
266
267 if !peer_state_lock.pending_create_order_requests.remove(&request_id) {
268 return Err(LightningError {
269 err: format!(
270 "Received create order error for an unknown request: {:?}",
271 request_id
272 ),
273 action: ErrorAction::IgnoreAndLog(Level::Debug),
274 });
275 }
276
277 self.pending_events.enqueue(Event::LSPS1Client(
278 LSPS1ClientEvent::OrderRequestFailed {
279 request_id: request_id.clone(),
280 counterparty_node_id: *counterparty_node_id,
281 error: error.clone(),
282 },
283 ));
284
285 Err(LightningError {
286 err: format!(
287 "Received create_order error response for request {:?}: {:?}",
288 request_id, error
289 ),
290 action: ErrorAction::IgnoreAndLog(Level::Error),
291 })
292 },
293 None => {
294 return Err(LightningError {
295 err: format!(
296 "Received error response for a create order request from an unknown counterparty ({:?})",
297 counterparty_node_id
298 ),
299 action: ErrorAction::IgnoreAndLog(Level::Debug),
300 });
301 },
302 }
303 }
304
305 pub fn check_order_status(
311 &self, counterparty_node_id: &PublicKey, order_id: OrderId,
312 ) -> RequestId {
313 let (request_id, request_msg) = {
314 let mut outer_state_lock = self.per_peer_state.write().unwrap();
315 let inner_state_lock = outer_state_lock
316 .entry(*counterparty_node_id)
317 .or_insert(Mutex::new(PeerState::default()));
318 let mut peer_state_lock = inner_state_lock.lock().unwrap();
319
320 let request_id = crate::utils::generate_request_id(&self.entropy_source);
321 peer_state_lock.pending_get_order_requests.insert(request_id.clone());
322
323 let request = LSPS1Request::GetOrder(GetOrderRequest { order_id: order_id.clone() });
324 let msg = LSPS1Message::Request(request_id.clone(), request).into();
325
326 (request_id, Some(msg))
327 };
328
329 if let Some(msg) = request_msg {
330 self.pending_messages.enqueue(&counterparty_node_id, msg);
331 }
332
333 request_id
334 }
335
336 fn handle_get_order_response(
337 &self, request_id: RequestId, counterparty_node_id: &PublicKey,
338 response: CreateOrderResponse,
339 ) -> Result<(), LightningError> {
340 let outer_state_lock = self.per_peer_state.read().unwrap();
341 match outer_state_lock.get(counterparty_node_id) {
342 Some(inner_state_lock) => {
343 let mut peer_state_lock = inner_state_lock.lock().unwrap();
344
345 if !peer_state_lock.pending_get_order_requests.remove(&request_id) {
346 return Err(LightningError {
347 err: format!(
348 "Received get_order response for an unknown request: {:?}",
349 request_id
350 ),
351 action: ErrorAction::IgnoreAndLog(Level::Debug),
352 });
353 }
354
355 self.pending_events.enqueue(Event::LSPS1Client(LSPS1ClientEvent::OrderStatus {
356 request_id,
357 counterparty_node_id: *counterparty_node_id,
358 order_id: response.order_id,
359 order: response.order,
360 payment: response.payment,
361 channel: response.channel,
362 }));
363 },
364 None => {
365 return Err(LightningError {
366 err: format!(
367 "Received get_order response from unknown peer: {}",
368 counterparty_node_id
369 ),
370 action: ErrorAction::IgnoreAndLog(Level::Debug),
371 })
372 },
373 }
374
375 Ok(())
376 }
377
378 fn handle_get_order_error(
379 &self, request_id: RequestId, counterparty_node_id: &PublicKey, error: ResponseError,
380 ) -> Result<(), LightningError> {
381 let outer_state_lock = self.per_peer_state.read().unwrap();
382 match outer_state_lock.get(counterparty_node_id) {
383 Some(inner_state_lock) => {
384 let mut peer_state_lock = inner_state_lock.lock().unwrap();
385
386 if !peer_state_lock.pending_get_order_requests.remove(&request_id) {
387 return Err(LightningError {
388 err: format!(
389 "Received get order error for an unknown request: {:?}",
390 request_id
391 ),
392 action: ErrorAction::IgnoreAndLog(Level::Debug),
393 });
394 }
395
396 self.pending_events.enqueue(Event::LSPS1Client(
397 LSPS1ClientEvent::OrderRequestFailed {
398 request_id: request_id.clone(),
399 counterparty_node_id: *counterparty_node_id,
400 error: error.clone(),
401 },
402 ));
403
404 Err(LightningError {
405 err: format!(
406 "Received get_order error response for request {:?}: {:?}",
407 request_id, error
408 ),
409 action: ErrorAction::IgnoreAndLog(Level::Error),
410 })
411 },
412 None => {
413 return Err(LightningError {
414 err: format!(
415 "Received error response for a get order request from an unknown counterparty ({:?})",
416 counterparty_node_id
417 ),
418 action: ErrorAction::IgnoreAndLog(Level::Debug),
419 });
420 },
421 }
422 }
423}
424
425impl<ES: Deref> ProtocolMessageHandler for LSPS1ClientHandler<ES>
426where
427 ES::Target: EntropySource,
428{
429 type ProtocolMessage = LSPS1Message;
430 const PROTOCOL_NUMBER: Option<u16> = Some(1);
431
432 fn handle_message(
433 &self, message: Self::ProtocolMessage, counterparty_node_id: &PublicKey,
434 ) -> Result<(), LightningError> {
435 match message {
436 LSPS1Message::Response(request_id, response) => match response {
437 LSPS1Response::GetInfo(params) => {
438 self.handle_get_info_response(request_id, counterparty_node_id, params)
439 },
440 LSPS1Response::GetInfoError(error) => {
441 self.handle_get_info_error(request_id, counterparty_node_id, error)
442 },
443 LSPS1Response::CreateOrder(params) => {
444 self.handle_create_order_response(request_id, counterparty_node_id, params)
445 },
446 LSPS1Response::CreateOrderError(error) => {
447 self.handle_create_order_error(request_id, counterparty_node_id, error)
448 },
449 LSPS1Response::GetOrder(params) => {
450 self.handle_get_order_response(request_id, counterparty_node_id, params)
451 },
452 LSPS1Response::GetOrderError(error) => {
453 self.handle_get_order_error(request_id, counterparty_node_id, error)
454 },
455 },
456 _ => {
457 debug_assert!(
458 false,
459 "Client handler received LSPS1 request message. This should never happen."
460 );
461 Err(LightningError {
462 err: format!(
463 "Client handler received LSPS1 request message from node {:?}. This should never happen.",
464 counterparty_node_id
465 ),
466 action: ErrorAction::IgnoreAndLog(Level::Error),
467 })
468 },
469 }
470 }
471}