Skip to content

Commit c35002f

Browse files
authored
Merge pull request #787 from TheBlueMatt/2021-02-check-close-source
2 parents 6dcb7c4 + bd8382a commit c35002f

File tree

3 files changed

+85
-14
lines changed

3 files changed

+85
-14
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -916,19 +916,22 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
916916
}
917917
}
918918

919-
/// Force closes a channel, immediately broadcasting the latest local commitment transaction to
920-
/// the chain and rejecting new HTLCs on the given channel. Fails if channel_id is unknown to the manager.
921-
pub fn force_close_channel(&self, channel_id: &[u8; 32]) -> Result<(), APIError>{
922-
let _consistency_lock = self.total_consistency_lock.read().unwrap();
923-
919+
fn force_close_channel_with_peer(&self, channel_id: &[u8; 32], peer_node_id: Option<&PublicKey>) -> Result<(), APIError> {
924920
let mut chan = {
925921
let mut channel_state_lock = self.channel_state.lock().unwrap();
926922
let channel_state = &mut *channel_state_lock;
927-
if let Some(chan) = channel_state.by_id.remove(channel_id) {
928-
if let Some(short_id) = chan.get_short_channel_id() {
923+
if let hash_map::Entry::Occupied(chan) = channel_state.by_id.entry(channel_id.clone()) {
924+
if let Some(node_id) = peer_node_id {
925+
if chan.get().get_counterparty_node_id() != *node_id {
926+
// Error or Ok here doesn't matter - the result is only exposed publicly
927+
// when peer_node_id is None anyway.
928+
return Ok(());
929+
}
930+
}
931+
if let Some(short_id) = chan.get().get_short_channel_id() {
929932
channel_state.short_to_id.remove(&short_id);
930933
}
931-
chan
934+
chan.remove_entry().1
932935
} else {
933936
return Err(APIError::ChannelUnavailable{err: "No such channel".to_owned()});
934937
}
@@ -945,6 +948,13 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
945948
Ok(())
946949
}
947950

951+
/// Force closes a channel, immediately broadcasting the latest local commitment transaction to
952+
/// the chain and rejecting new HTLCs on the given channel. Fails if channel_id is unknown to the manager.
953+
pub fn force_close_channel(&self, channel_id: &[u8; 32]) -> Result<(), APIError> {
954+
let _consistency_lock = self.total_consistency_lock.read().unwrap();
955+
self.force_close_channel_with_peer(channel_id, None)
956+
}
957+
948958
/// Force close all channels, immediately broadcasting the latest local commitment transaction
949959
/// for each to the chain and rejecting new HTLCs on each.
950960
pub fn force_close_all_channels(&self) {
@@ -3474,12 +3484,12 @@ impl<ChanSigner: ChannelKeys, M: Deref + Sync + Send, T: Deref + Sync + Send, K:
34743484
for chan in self.list_channels() {
34753485
if chan.remote_network_id == *counterparty_node_id {
34763486
// Untrusted messages from peer, we throw away the error if id points to a non-existent channel
3477-
let _ = self.force_close_channel(&msg.channel_id);
3487+
let _ = self.force_close_channel_with_peer(&chan.channel_id, Some(counterparty_node_id));
34783488
}
34793489
}
34803490
} else {
34813491
// Untrusted messages from peer, we throw away the error if id points to a non-existent channel
3482-
let _ = self.force_close_channel(&msg.channel_id);
3492+
let _ = self.force_close_channel_with_peer(&msg.channel_id, Some(counterparty_node_id));
34833493
}
34843494
}
34853495
}

lightning/src/ln/functional_tests.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8836,3 +8836,66 @@ fn test_duplicate_chan_id() {
88368836
update_nodes_with_chan_announce(&nodes, 0, 1, &announcement, &as_update, &bs_update);
88378837
send_payment(&nodes[0], &[&nodes[1]], 8000000, 8_000_000);
88388838
}
8839+
8840+
#[test]
8841+
fn test_error_chans_closed() {
8842+
// Test that we properly handle error messages, closing appropriate channels.
8843+
//
8844+
// Prior to #787 we'd allow a peer to make us force-close a channel we had with a different
8845+
// peer. The "real" fix for that is to index channels with peers_ids, however in the mean time
8846+
// we can test various edge cases around it to ensure we don't regress.
8847+
let chanmon_cfgs = create_chanmon_cfgs(3);
8848+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
8849+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
8850+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
8851+
8852+
// Create some initial channels
8853+
let chan_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
8854+
let chan_2 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
8855+
let chan_3 = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 100000, 10001, InitFeatures::known(), InitFeatures::known());
8856+
8857+
assert_eq!(nodes[0].node.list_usable_channels().len(), 3);
8858+
assert_eq!(nodes[1].node.list_usable_channels().len(), 2);
8859+
assert_eq!(nodes[2].node.list_usable_channels().len(), 1);
8860+
8861+
// Closing a channel from a different peer has no effect
8862+
nodes[0].node.handle_error(&nodes[1].node.get_our_node_id(), &msgs::ErrorMessage { channel_id: chan_3.2, data: "ERR".to_owned() });
8863+
assert_eq!(nodes[0].node.list_usable_channels().len(), 3);
8864+
8865+
// Closing one channel doesn't impact others
8866+
nodes[0].node.handle_error(&nodes[1].node.get_our_node_id(), &msgs::ErrorMessage { channel_id: chan_2.2, data: "ERR".to_owned() });
8867+
check_added_monitors!(nodes[0], 1);
8868+
check_closed_broadcast!(nodes[0], false);
8869+
assert_eq!(nodes[0].node.list_usable_channels().len(), 2);
8870+
assert!(nodes[0].node.list_usable_channels()[0].channel_id == chan_1.2 || nodes[0].node.list_usable_channels()[1].channel_id == chan_1.2);
8871+
assert!(nodes[0].node.list_usable_channels()[0].channel_id == chan_3.2 || nodes[0].node.list_usable_channels()[1].channel_id == chan_3.2);
8872+
8873+
// A null channel ID should close all channels
8874+
let _chan_4 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001, InitFeatures::known(), InitFeatures::known());
8875+
nodes[0].node.handle_error(&nodes[1].node.get_our_node_id(), &msgs::ErrorMessage { channel_id: [0; 32], data: "ERR".to_owned() });
8876+
check_added_monitors!(nodes[0], 2);
8877+
let events = nodes[0].node.get_and_clear_pending_msg_events();
8878+
assert_eq!(events.len(), 2);
8879+
match events[0] {
8880+
MessageSendEvent::BroadcastChannelUpdate { ref msg } => {
8881+
assert_eq!(msg.contents.flags & 2, 2);
8882+
},
8883+
_ => panic!("Unexpected event"),
8884+
}
8885+
match events[1] {
8886+
MessageSendEvent::BroadcastChannelUpdate { ref msg } => {
8887+
assert_eq!(msg.contents.flags & 2, 2);
8888+
},
8889+
_ => panic!("Unexpected event"),
8890+
}
8891+
// Note that at this point users of a standard PeerHandler will end up calling
8892+
// peer_disconnected with no_connection_possible set to false, duplicating the
8893+
// close-all-channels logic. That's OK, we don't want to end up not force-closing channels for
8894+
// users with their own peer handling logic. We duplicate the call here, however.
8895+
assert_eq!(nodes[0].node.list_usable_channels().len(), 1);
8896+
assert!(nodes[0].node.list_usable_channels()[0].channel_id == chan_3.2);
8897+
8898+
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), true);
8899+
assert_eq!(nodes[0].node.list_usable_channels().len(), 1);
8900+
assert!(nodes[0].node.list_usable_channels()[0].channel_id == chan_3.2);
8901+
}

lightning/src/ln/peer_handler.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,8 @@ pub trait SocketDescriptor : cmp::Eq + hash::Hash + Clone {
8888
}
8989

9090
/// Error for PeerManager errors. If you get one of these, you must disconnect the socket and
91-
/// generate no further read_event/write_buffer_space_avail calls for the descriptor, only
92-
/// triggering a single socket_disconnected call (unless it was provided in response to a
93-
/// new_*_connection event, in which case no such socket_disconnected() must be called and the
94-
/// socket silently disconencted).
91+
/// generate no further read_event/write_buffer_space_avail/socket_disconnected calls for the
92+
/// descriptor.
9593
pub struct PeerHandleError {
9694
/// Used to indicate that we probably can't make any future connections to this peer, implying
9795
/// we should go ahead and force-close any channels we have with it.

0 commit comments

Comments
 (0)