Skip to content

Commit 2e39e08

Browse files
committed
Test for extra locks held in handle_error unconditionally
`handle_error` must be called without `per_peer_state` mutex or `pending_events` mutex locks held or we may risk deadlocks. Previously we checked this in debug builds in the error path, but not in the success path. As it turns out, `funding_transaction_generated`'s error path does hold a `per_peer_state` lock, which we fix here as well as move the tests to happen unconditionally.
1 parent 8fcbe64 commit 2e39e08

File tree

1 file changed

+27
-28
lines changed

1 file changed

+27
-28
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,15 +1345,15 @@ pub struct PhantomRouteHints {
13451345
}
13461346

13471347
macro_rules! handle_error {
1348-
($self: ident, $internal: expr, $counterparty_node_id: expr) => {
1348+
($self: ident, $internal: expr, $counterparty_node_id: expr) => { {
1349+
// In testing, ensure there are no deadlocks where the lock is already held upon
1350+
// entering the macro.
1351+
debug_assert_ne!($self.pending_events.held_by_thread(), LockHeldState::HeldByThread);
1352+
debug_assert_ne!($self.per_peer_state.held_by_thread(), LockHeldState::HeldByThread);
1353+
13491354
match $internal {
13501355
Ok(msg) => Ok(msg),
13511356
Err(MsgHandleErrInternal { err, chan_id, shutdown_finish }) => {
1352-
// In testing, ensure there are no deadlocks where the lock is already held upon
1353-
// entering the macro.
1354-
debug_assert_ne!($self.pending_events.held_by_thread(), LockHeldState::HeldByThread);
1355-
debug_assert_ne!($self.per_peer_state.held_by_thread(), LockHeldState::HeldByThread);
1356-
13571357
let mut msg_events = Vec::with_capacity(2);
13581358

13591359
if let Some((shutdown_res, update_option)) = shutdown_finish {
@@ -1392,7 +1392,7 @@ macro_rules! handle_error {
13921392
Err(err)
13931393
},
13941394
}
1395-
}
1395+
} }
13961396
}
13971397

13981398
macro_rules! update_maps_on_chan_removal {
@@ -2790,29 +2790,28 @@ where
27902790

27912791
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
27922792
let peer_state = &mut *peer_state_lock;
2793-
let (chan, msg) = {
2794-
let (res, chan) = {
2795-
match peer_state.channel_by_id.remove(temporary_channel_id) {
2796-
Some(mut chan) => {
2797-
let funding_txo = find_funding_output(&chan, &funding_transaction)?;
2798-
2799-
(chan.get_outbound_funding_created(funding_transaction, funding_txo, &self.logger)
2800-
.map_err(|e| if let ChannelError::Close(msg) = e {
2801-
MsgHandleErrInternal::from_finish_shutdown(msg, chan.channel_id(), chan.get_user_id(), chan.force_shutdown(true), None)
2802-
} else { unreachable!(); })
2803-
, chan)
2793+
let (msg, chan) = match peer_state.channel_by_id.remove(temporary_channel_id) {
2794+
Some(mut chan) => {
2795+
let funding_txo = find_funding_output(&chan, &funding_transaction)?;
2796+
2797+
let funding_res = chan.get_outbound_funding_created(funding_transaction, funding_txo, &self.logger)
2798+
.map_err(|e| if let ChannelError::Close(msg) = e {
2799+
MsgHandleErrInternal::from_finish_shutdown(msg, chan.channel_id(), chan.get_user_id(), chan.force_shutdown(true), None)
2800+
} else { unreachable!(); });
2801+
match funding_res {
2802+
Ok(funding_msg) => (funding_msg, chan),
2803+
Err(_) => {
2804+
mem::drop(peer_state_lock);
2805+
mem::drop(per_peer_state);
2806+
2807+
let _ = handle_error!(self, funding_res, chan.get_counterparty_node_id());
2808+
return Err(APIError::ChannelUnavailable {
2809+
err: "Signer refused to sign the initial commitment transaction".to_owned()
2810+
});
28042811
},
2805-
None => { return Err(APIError::ChannelUnavailable { err: format!("Channel with id {} not found for the passed counterparty node_id {}", log_bytes!(*temporary_channel_id), counterparty_node_id) }) },
28062812
}
2807-
};
2808-
match handle_error!(self, res, chan.get_counterparty_node_id()) {
2809-
Ok(funding_msg) => {
2810-
(chan, funding_msg)
2811-
},
2812-
Err(_) => { return Err(APIError::ChannelUnavailable {
2813-
err: "Signer refused to sign the initial commitment transaction".to_owned()
2814-
}) },
2815-
}
2813+
},
2814+
None => { return Err(APIError::ChannelUnavailable { err: format!("Channel with id {} not found for the passed counterparty node_id {}", log_bytes!(*temporary_channel_id), counterparty_node_id) }) },
28162815
};
28172816

28182817
peer_state.pending_msg_events.push(events::MessageSendEvent::SendFundingCreated {

0 commit comments

Comments
 (0)