Skip to content

Commit 60c1073

Browse files
authored
Merge pull request #2657 from Fedeparma74/fix-close-channel-deadlock
Fix deadlock when closing an unavailable channel
2 parents 989304e + 7cdb31a commit 60c1073

File tree

2 files changed

+45
-3
lines changed

2 files changed

+45
-3
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2616,6 +2616,8 @@ where
26162616
// it does not exist for this peer. Either way, we can attempt to force-close it.
26172617
//
26182618
// An appropriate error will be returned for non-existence of the channel if that's the case.
2619+
mem::drop(peer_state_lock);
2620+
mem::drop(per_peer_state);
26192621
return self.force_close_channel_with_peer(&channel_id, counterparty_node_id, None, false).map(|_| ())
26202622
},
26212623
}
@@ -4001,7 +4003,7 @@ where
40014003
for channel_id in channel_ids {
40024004
if !peer_state.has_channel(channel_id) {
40034005
return Err(APIError::ChannelUnavailable {
4004-
err: format!("Channel with ID {} was not found for the passed counterparty_node_id {}", channel_id, counterparty_node_id),
4006+
err: format!("Channel with id {} not found for the passed counterparty node_id {}", channel_id, counterparty_node_id),
40054007
});
40064008
};
40074009
}
@@ -4112,7 +4114,7 @@ where
41124114
next_hop_channel_id, next_node_id)
41134115
}),
41144116
None => return Err(APIError::ChannelUnavailable {
4115-
err: format!("Channel with id {} not found for the passed counterparty node_id {}.",
4117+
err: format!("Channel with id {} not found for the passed counterparty node_id {}",
41164118
next_hop_channel_id, next_node_id)
41174119
})
41184120
}
@@ -10750,6 +10752,16 @@ mod tests {
1075010752
check_api_error_message(expected_message, res_err)
1075110753
}
1075210754

10755+
fn check_channel_unavailable_error<T>(res_err: Result<T, APIError>, expected_channel_id: ChannelId, peer_node_id: PublicKey) {
10756+
let expected_message = format!("Channel with id {} not found for the passed counterparty node_id {}", expected_channel_id, peer_node_id);
10757+
check_api_error_message(expected_message, res_err)
10758+
}
10759+
10760+
fn check_api_misuse_error<T>(res_err: Result<T, APIError>) {
10761+
let expected_message = "No such channel awaiting to be accepted.".to_string();
10762+
check_api_error_message(expected_message, res_err)
10763+
}
10764+
1075310765
fn check_api_error_message<T>(expected_err_message: String, res_err: Result<T, APIError>) {
1075410766
match res_err {
1075510767
Err(APIError::APIMisuseError { err }) => {
@@ -10794,6 +10806,36 @@ mod tests {
1079410806
check_unkown_peer_error(nodes[0].node.update_channel_config(&unkown_public_key, &[channel_id], &ChannelConfig::default()), unkown_public_key);
1079510807
}
1079610808

10809+
#[test]
10810+
fn test_api_calls_with_unavailable_channel() {
10811+
// Tests that our API functions that expects a `counterparty_node_id` and a `channel_id`
10812+
// as input, behaves as expected if the `counterparty_node_id` is a known peer in the
10813+
// `ChannelManager::per_peer_state` map, but the peer state doesn't contain a channel with
10814+
// the given `channel_id`.
10815+
let chanmon_cfg = create_chanmon_cfgs(2);
10816+
let node_cfg = create_node_cfgs(2, &chanmon_cfg);
10817+
let node_chanmgr = create_node_chanmgrs(2, &node_cfg, &[None, None]);
10818+
let nodes = create_network(2, &node_cfg, &node_chanmgr);
10819+
10820+
let counterparty_node_id = nodes[1].node.get_our_node_id();
10821+
10822+
// Dummy values
10823+
let channel_id = ChannelId::from_bytes([4; 32]);
10824+
10825+
// Test the API functions.
10826+
check_api_misuse_error(nodes[0].node.accept_inbound_channel(&channel_id, &counterparty_node_id, 42));
10827+
10828+
check_channel_unavailable_error(nodes[0].node.close_channel(&channel_id, &counterparty_node_id), channel_id, counterparty_node_id);
10829+
10830+
check_channel_unavailable_error(nodes[0].node.force_close_broadcasting_latest_txn(&channel_id, &counterparty_node_id), channel_id, counterparty_node_id);
10831+
10832+
check_channel_unavailable_error(nodes[0].node.force_close_without_broadcasting_txn(&channel_id, &counterparty_node_id), channel_id, counterparty_node_id);
10833+
10834+
check_channel_unavailable_error(nodes[0].node.forward_intercepted_htlc(InterceptId([0; 32]), &channel_id, counterparty_node_id, 1_000_000), channel_id, counterparty_node_id);
10835+
10836+
check_channel_unavailable_error(nodes[0].node.update_channel_config(&counterparty_node_id, &[channel_id], &ChannelConfig::default()), channel_id, counterparty_node_id);
10837+
}
10838+
1079710839
#[test]
1079810840
fn test_connection_limiting() {
1079910841
// Test that we limit un-channel'd peers and un-funded channels properly.

lightning/src/ln/payment_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1906,7 +1906,7 @@ fn do_test_intercepted_payment(test: InterceptTest) {
19061906
// Check for unknown channel id error.
19071907
let unknown_chan_id_err = nodes[1].node.forward_intercepted_htlc(intercept_id, &ChannelId::from_bytes([42; 32]), nodes[2].node.get_our_node_id(), expected_outbound_amount_msat).unwrap_err();
19081908
assert_eq!(unknown_chan_id_err , APIError::ChannelUnavailable {
1909-
err: format!("Channel with id {} not found for the passed counterparty node_id {}.",
1909+
err: format!("Channel with id {} not found for the passed counterparty node_id {}",
19101910
log_bytes!([42; 32]), nodes[2].node.get_our_node_id()) });
19111911

19121912
if test == InterceptTest::Fail {

0 commit comments

Comments
 (0)