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

Commit 8c03f38

Browse files
committed
LSPS1 service: Drop lock before enqueuing responses
.. which avoids a potential deadlock
1 parent a830466 commit 8c03f38

File tree

1 file changed

+116
-88
lines changed

1 file changed

+116
-88
lines changed

src/lsps1/service.rs

Lines changed: 116 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -211,16 +211,18 @@ where
211211
});
212212
}
213213

214-
let mut outer_state_lock = self.per_peer_state.write().unwrap();
214+
{
215+
let mut outer_state_lock = self.per_peer_state.write().unwrap();
215216

216-
let inner_state_lock = outer_state_lock
217-
.entry(*counterparty_node_id)
218-
.or_insert(Mutex::new(PeerState::default()));
219-
let mut peer_state_lock = inner_state_lock.lock().unwrap();
217+
let inner_state_lock = outer_state_lock
218+
.entry(*counterparty_node_id)
219+
.or_insert(Mutex::new(PeerState::default()));
220+
let mut peer_state_lock = inner_state_lock.lock().unwrap();
220221

221-
peer_state_lock
222-
.pending_requests
223-
.insert(request_id.clone(), LSPS1Request::CreateOrder(params.clone()));
222+
peer_state_lock
223+
.pending_requests
224+
.insert(request_id.clone(), LSPS1Request::CreateOrder(params.clone()));
225+
}
224226

225227
self.pending_events.enqueue(Event::LSPS1Service(
226228
LSPS1ServiceEvent::RequestForPaymentDetails {
@@ -242,56 +244,68 @@ where
242244
&self, request_id: RequestId, counterparty_node_id: &PublicKey, payment: OrderPayment,
243245
created_at: chrono::DateTime<Utc>, expires_at: chrono::DateTime<Utc>,
244246
) -> Result<(), APIError> {
245-
let outer_state_lock = self.per_peer_state.read().unwrap();
246-
247-
match outer_state_lock.get(counterparty_node_id) {
248-
Some(inner_state_lock) => {
249-
let mut peer_state_lock = inner_state_lock.lock().unwrap();
250-
251-
match peer_state_lock.pending_requests.remove(&request_id) {
252-
Some(LSPS1Request::CreateOrder(params)) => {
253-
let order_id = self.generate_order_id();
254-
let channel = OutboundCRChannel::new(
255-
params.order.clone(),
256-
created_at.clone(),
257-
expires_at.clone(),
258-
order_id.clone(),
259-
payment.clone(),
260-
);
261-
262-
peer_state_lock.insert_outbound_channel(order_id.clone(), channel);
263-
264-
let response = LSPS1Response::CreateOrder(CreateOrderResponse {
265-
order: params.order,
266-
order_id,
267-
order_state: OrderState::Created,
268-
created_at,
269-
expires_at,
270-
payment,
271-
channel: None,
272-
});
273-
let msg = LSPS1Message::Response(request_id, response).into();
274-
self.pending_messages.enqueue(counterparty_node_id, msg);
275-
},
247+
let (result, response) = {
248+
let outer_state_lock = self.per_peer_state.read().unwrap();
249+
250+
match outer_state_lock.get(counterparty_node_id) {
251+
Some(inner_state_lock) => {
252+
let mut peer_state_lock = inner_state_lock.lock().unwrap();
253+
254+
match peer_state_lock.pending_requests.remove(&request_id) {
255+
Some(LSPS1Request::CreateOrder(params)) => {
256+
let order_id = self.generate_order_id();
257+
let channel = OutboundCRChannel::new(
258+
params.order.clone(),
259+
created_at.clone(),
260+
expires_at.clone(),
261+
order_id.clone(),
262+
payment.clone(),
263+
);
264+
265+
peer_state_lock.insert_outbound_channel(order_id.clone(), channel);
266+
267+
let response = LSPS1Response::CreateOrder(CreateOrderResponse {
268+
order: params.order,
269+
order_id,
270+
order_state: OrderState::Created,
271+
created_at,
272+
expires_at,
273+
payment,
274+
channel: None,
275+
});
276+
277+
(Ok(()), Some(response))
278+
},
279+
280+
_ => (
281+
Err(APIError::APIMisuseError {
282+
err: format!(
283+
"No pending buy request for request_id: {:?}",
284+
request_id
285+
),
286+
}),
287+
None,
288+
),
289+
}
290+
},
291+
None => (
292+
Err(APIError::APIMisuseError {
293+
err: format!(
294+
"No state for the counterparty exists: {:?}",
295+
counterparty_node_id
296+
),
297+
}),
298+
None,
299+
),
300+
}
301+
};
276302

277-
_ => {
278-
return Err(APIError::APIMisuseError {
279-
err: format!("No pending buy request for request_id: {:?}", request_id),
280-
})
281-
},
282-
}
283-
},
284-
None => {
285-
return Err(APIError::APIMisuseError {
286-
err: format!(
287-
"No state for the counterparty exists: {:?}",
288-
counterparty_node_id
289-
),
290-
})
291-
},
303+
if let Some(response) = response {
304+
let msg = LSPS1Message::Response(request_id, response).into();
305+
self.pending_messages.enqueue(counterparty_node_id, msg);
292306
}
293307

294-
Ok(())
308+
result
295309
}
296310

297311
fn handle_get_order_request(
@@ -337,7 +351,7 @@ where
337351
},
338352
None => {
339353
return Err(LightningError {
340-
err: format!("Received error response for a create order request from an unknown counterparty ({:?})",counterparty_node_id),
354+
err: format!("Received error response for a create order request from an unknown counterparty ({:?})", counterparty_node_id),
341355
action: ErrorAction::IgnoreAndLog(Level::Info),
342356
});
343357
},
@@ -358,41 +372,55 @@ where
358372
&self, request_id: RequestId, counterparty_node_id: PublicKey, order_id: OrderId,
359373
order_state: OrderState, channel: Option<ChannelInfo>,
360374
) -> Result<(), APIError> {
361-
let outer_state_lock = self.per_peer_state.read().unwrap();
375+
let (result, response) = {
376+
let outer_state_lock = self.per_peer_state.read().unwrap();
362377

363-
match outer_state_lock.get(&counterparty_node_id) {
364-
Some(inner_state_lock) => {
365-
let mut peer_state_lock = inner_state_lock.lock().unwrap();
378+
match outer_state_lock.get(&counterparty_node_id) {
379+
Some(inner_state_lock) => {
380+
let mut peer_state_lock = inner_state_lock.lock().unwrap();
366381

367-
if let Some(outbound_channel) =
368-
peer_state_lock.outbound_channels_by_order_id.get_mut(&order_id)
369-
{
370-
let config = &outbound_channel.config;
371-
372-
let response = LSPS1Response::GetOrder(CreateOrderResponse {
373-
order_id,
374-
order: config.order.clone(),
375-
order_state,
376-
created_at: config.created_at,
377-
expires_at: config.expires_at,
378-
payment: config.payment.clone(),
379-
channel,
380-
});
381-
let msg = LSPS1Message::Response(request_id, response).into();
382-
self.pending_messages.enqueue(counterparty_node_id, msg);
383-
} else {
384-
return Err(APIError::APIMisuseError {
385-
err: format!("Channel with order_id {} not found", order_id.0),
386-
});
387-
}
388-
},
389-
None => {
390-
return Err(APIError::APIMisuseError {
391-
err: format!("No existing state with counterparty {}", counterparty_node_id),
392-
})
393-
},
382+
if let Some(outbound_channel) =
383+
peer_state_lock.outbound_channels_by_order_id.get_mut(&order_id)
384+
{
385+
let config = &outbound_channel.config;
386+
387+
let response = LSPS1Response::GetOrder(CreateOrderResponse {
388+
order_id,
389+
order: config.order.clone(),
390+
order_state,
391+
created_at: config.created_at,
392+
expires_at: config.expires_at,
393+
payment: config.payment.clone(),
394+
channel,
395+
});
396+
(Ok(()), Some(response))
397+
} else {
398+
(
399+
Err(APIError::APIMisuseError {
400+
err: format!("Channel with order_id {} not found", order_id.0),
401+
}),
402+
None,
403+
)
404+
}
405+
},
406+
None => (
407+
Err(APIError::APIMisuseError {
408+
err: format!(
409+
"No existing state with counterparty {}",
410+
counterparty_node_id
411+
),
412+
}),
413+
None,
414+
),
415+
}
416+
};
417+
418+
if let Some(response) = response {
419+
let msg = LSPS1Message::Response(request_id, response).into();
420+
self.pending_messages.enqueue(counterparty_node_id, msg);
394421
}
395-
Ok(())
422+
423+
result
396424
}
397425

398426
fn generate_order_id(&self) -> OrderId {

0 commit comments

Comments
 (0)