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

Commit f01639c

Browse files
committed
LSPS2 service: Drop lock before enqueuing responses
.. which avoids a potential deadlock
1 parent 12a0b11 commit f01639c

File tree

1 file changed

+150
-95
lines changed

1 file changed

+150
-95
lines changed

src/lsps2/service.rs

Lines changed: 150 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -495,35 +495,51 @@ where
495495
pub fn invalid_token_provided(
496496
&self, counterparty_node_id: &PublicKey, request_id: RequestId,
497497
) -> Result<(), APIError> {
498-
let outer_state_lock = self.per_peer_state.read().unwrap();
498+
let (result, response) = {
499+
let outer_state_lock = self.per_peer_state.read().unwrap();
499500

500-
match outer_state_lock.get(counterparty_node_id) {
501-
Some(inner_state_lock) => {
502-
let mut peer_state = inner_state_lock.lock().unwrap();
501+
match outer_state_lock.get(counterparty_node_id) {
502+
Some(inner_state_lock) => {
503+
let mut peer_state = inner_state_lock.lock().unwrap();
503504

504-
match peer_state.pending_requests.remove(&request_id) {
505-
Some(LSPS2Request::GetInfo(_)) => {
506-
let response = LSPS2Response::GetInfoError(ResponseError {
507-
code: LSPS2_GET_INFO_REQUEST_UNRECOGNIZED_OR_STALE_TOKEN_ERROR_CODE,
508-
message: "an unrecognized or stale token was provided".to_string(),
509-
data: None,
510-
});
511-
let msg = LSPS2Message::Response(request_id, response).into();
512-
self.pending_messages.enqueue(counterparty_node_id, msg);
513-
Ok(())
514-
},
515-
_ => Err(APIError::APIMisuseError {
505+
match peer_state.pending_requests.remove(&request_id) {
506+
Some(LSPS2Request::GetInfo(_)) => {
507+
let response = LSPS2Response::GetInfoError(ResponseError {
508+
code: LSPS2_GET_INFO_REQUEST_UNRECOGNIZED_OR_STALE_TOKEN_ERROR_CODE,
509+
message: "an unrecognized or stale token was provided".to_string(),
510+
data: None,
511+
});
512+
(Ok(()), Some(response))
513+
},
514+
_ => (
515+
Err(APIError::APIMisuseError {
516+
err: format!(
517+
"No pending get_info request for request_id: {:?}",
518+
request_id
519+
),
520+
}),
521+
None,
522+
),
523+
}
524+
},
525+
None => (
526+
Err(APIError::APIMisuseError {
516527
err: format!(
517-
"No pending get_info request for request_id: {:?}",
518-
request_id
528+
"No state for the counterparty exists: {:?}",
529+
counterparty_node_id
519530
),
520531
}),
521-
}
522-
},
523-
None => Err(APIError::APIMisuseError {
524-
err: format!("No state for the counterparty exists: {:?}", counterparty_node_id),
525-
}),
532+
None,
533+
),
534+
}
535+
};
536+
537+
if let Some(response) = response {
538+
let msg = LSPS2Message::Response(request_id, response).into();
539+
self.pending_messages.enqueue(counterparty_node_id, msg);
526540
}
541+
542+
result
527543
}
528544

529545
/// Used by LSP to provide fee parameters to a client requesting a JIT Channel.
@@ -535,38 +551,54 @@ where
535551
&self, counterparty_node_id: &PublicKey, request_id: RequestId,
536552
opening_fee_params_menu: Vec<RawOpeningFeeParams>,
537553
) -> Result<(), APIError> {
538-
let outer_state_lock = self.per_peer_state.read().unwrap();
554+
let (result, response) = {
555+
let outer_state_lock = self.per_peer_state.read().unwrap();
539556

540-
match outer_state_lock.get(counterparty_node_id) {
541-
Some(inner_state_lock) => {
542-
let mut peer_state = inner_state_lock.lock().unwrap();
557+
match outer_state_lock.get(counterparty_node_id) {
558+
Some(inner_state_lock) => {
559+
let mut peer_state = inner_state_lock.lock().unwrap();
543560

544-
match peer_state.pending_requests.remove(&request_id) {
545-
Some(LSPS2Request::GetInfo(_)) => {
546-
let response = LSPS2Response::GetInfo(GetInfoResponse {
547-
opening_fee_params_menu: opening_fee_params_menu
548-
.into_iter()
549-
.map(|param| {
550-
param.into_opening_fee_params(&self.config.promise_secret)
551-
})
552-
.collect(),
553-
});
554-
let msg = LSPS2Message::Response(request_id, response).into();
555-
self.pending_messages.enqueue(counterparty_node_id, msg);
556-
Ok(())
557-
},
558-
_ => Err(APIError::APIMisuseError {
561+
match peer_state.pending_requests.remove(&request_id) {
562+
Some(LSPS2Request::GetInfo(_)) => {
563+
let response = LSPS2Response::GetInfo(GetInfoResponse {
564+
opening_fee_params_menu: opening_fee_params_menu
565+
.into_iter()
566+
.map(|param| {
567+
param.into_opening_fee_params(&self.config.promise_secret)
568+
})
569+
.collect(),
570+
});
571+
(Ok(()), Some(response))
572+
},
573+
_ => (
574+
Err(APIError::APIMisuseError {
575+
err: format!(
576+
"No pending get_info request for request_id: {:?}",
577+
request_id
578+
),
579+
}),
580+
None,
581+
),
582+
}
583+
},
584+
None => (
585+
Err(APIError::APIMisuseError {
559586
err: format!(
560-
"No pending get_info request for request_id: {:?}",
561-
request_id
587+
"No state for the counterparty exists: {:?}",
588+
counterparty_node_id
562589
),
563590
}),
564-
}
565-
},
566-
None => Err(APIError::APIMisuseError {
567-
err: format!("No state for the counterparty exists: {:?}", counterparty_node_id),
568-
}),
591+
None,
592+
),
593+
}
594+
};
595+
596+
if let Some(response) = response {
597+
let msg = LSPS2Message::Response(request_id, response).into();
598+
self.pending_messages.enqueue(counterparty_node_id, msg);
569599
}
600+
601+
result
570602
}
571603

572604
/// Used by LSP to provide client with the intercept scid and cltv_expiry_delta to use in their invoice.
@@ -578,50 +610,70 @@ where
578610
&self, counterparty_node_id: &PublicKey, request_id: RequestId, intercept_scid: u64,
579611
cltv_expiry_delta: u32, client_trusts_lsp: bool, user_channel_id: u128,
580612
) -> Result<(), APIError> {
581-
let outer_state_lock = self.per_peer_state.read().unwrap();
582-
583-
match outer_state_lock.get(counterparty_node_id) {
584-
Some(inner_state_lock) => {
585-
let mut peer_state = inner_state_lock.lock().unwrap();
613+
let (result, response) = {
614+
let outer_state_lock = self.per_peer_state.read().unwrap();
586615

587-
match peer_state.pending_requests.remove(&request_id) {
588-
Some(LSPS2Request::Buy(buy_request)) => {
589-
{
590-
let mut peer_by_intercept_scid =
591-
self.peer_by_intercept_scid.write().unwrap();
592-
peer_by_intercept_scid.insert(intercept_scid, *counterparty_node_id);
593-
}
616+
match outer_state_lock.get(counterparty_node_id) {
617+
Some(inner_state_lock) => {
618+
let mut peer_state = inner_state_lock.lock().unwrap();
594619

595-
let outbound_jit_channel = OutboundJITChannel::new(
596-
buy_request.payment_size_msat,
597-
buy_request.opening_fee_params,
598-
user_channel_id,
599-
);
600-
601-
peer_state
602-
.intercept_scid_by_user_channel_id
603-
.insert(user_channel_id, intercept_scid);
604-
peer_state.insert_outbound_channel(intercept_scid, outbound_jit_channel);
605-
606-
let response = LSPS2Response::Buy(BuyResponse {
607-
intercept_scid: intercept_scid.into(),
608-
lsp_cltv_expiry_delta: cltv_expiry_delta,
609-
client_trusts_lsp,
610-
});
611-
let msg = LSPS2Message::Response(request_id, response).into();
612-
self.pending_messages.enqueue(counterparty_node_id, msg);
620+
match peer_state.pending_requests.remove(&request_id) {
621+
Some(LSPS2Request::Buy(buy_request)) => {
622+
{
623+
let mut peer_by_intercept_scid =
624+
self.peer_by_intercept_scid.write().unwrap();
625+
peer_by_intercept_scid
626+
.insert(intercept_scid, *counterparty_node_id);
627+
}
613628

614-
Ok(())
615-
},
616-
_ => Err(APIError::APIMisuseError {
617-
err: format!("No pending buy request for request_id: {:?}", request_id),
629+
let outbound_jit_channel = OutboundJITChannel::new(
630+
buy_request.payment_size_msat,
631+
buy_request.opening_fee_params,
632+
user_channel_id,
633+
);
634+
635+
peer_state
636+
.intercept_scid_by_user_channel_id
637+
.insert(user_channel_id, intercept_scid);
638+
peer_state
639+
.insert_outbound_channel(intercept_scid, outbound_jit_channel);
640+
641+
let response = LSPS2Response::Buy(BuyResponse {
642+
intercept_scid: intercept_scid.into(),
643+
lsp_cltv_expiry_delta: cltv_expiry_delta,
644+
client_trusts_lsp,
645+
});
646+
(Ok(()), Some(response))
647+
},
648+
_ => (
649+
Err(APIError::APIMisuseError {
650+
err: format!(
651+
"No pending buy request for request_id: {:?}",
652+
request_id
653+
),
654+
}),
655+
None,
656+
),
657+
}
658+
},
659+
None => (
660+
Err(APIError::APIMisuseError {
661+
err: format!(
662+
"No state for the counterparty exists: {:?}",
663+
counterparty_node_id
664+
),
618665
}),
619-
}
620-
},
621-
None => Err(APIError::APIMisuseError {
622-
err: format!("No state for the counterparty exists: {:?}", counterparty_node_id),
623-
}),
666+
None,
667+
),
668+
}
669+
};
670+
671+
if let Some(response) = response {
672+
let msg = LSPS2Message::Response(request_id, response).into();
673+
self.pending_messages.enqueue(counterparty_node_id, msg);
624674
}
675+
676+
result
625677
}
626678

627679
/// Forward [`Event::HTLCIntercepted`] event parameters into this function.
@@ -1031,13 +1083,16 @@ where
10311083
});
10321084
}
10331085

1034-
let mut outer_state_lock = self.per_peer_state.write().unwrap();
1035-
let inner_state_lock =
1036-
outer_state_lock.entry(*counterparty_node_id).or_insert(Mutex::new(PeerState::new()));
1037-
let mut peer_state_lock = inner_state_lock.lock().unwrap();
1038-
peer_state_lock
1039-
.pending_requests
1040-
.insert(request_id.clone(), LSPS2Request::Buy(params.clone()));
1086+
{
1087+
let mut outer_state_lock = self.per_peer_state.write().unwrap();
1088+
let inner_state_lock = outer_state_lock
1089+
.entry(*counterparty_node_id)
1090+
.or_insert(Mutex::new(PeerState::new()));
1091+
let mut peer_state_lock = inner_state_lock.lock().unwrap();
1092+
peer_state_lock
1093+
.pending_requests
1094+
.insert(request_id.clone(), LSPS2Request::Buy(params.clone()));
1095+
}
10411096

10421097
let event = Event::LSPS2Service(LSPS2ServiceEvent::BuyRequest {
10431098
request_id,

0 commit comments

Comments
 (0)