Skip to content

Commit bd297fe

Browse files
committed
Force close pending channels in internal_shutdown
1 parent a70b1f7 commit bd297fe

File tree

2 files changed

+49
-32
lines changed

2 files changed

+49
-32
lines changed

lightning/src/events/mod.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ impl_writeable_tlv_based_enum_upgradable!(PathFailure,
113113
);
114114

115115
#[derive(Clone, Debug, PartialEq, Eq)]
116-
/// The reason the channel was closed. See individual variants more details.
116+
/// The reason the channel was closed. See individual variants for more details.
117117
pub enum ClosureReason {
118118
/// Closure generated from receiving a peer error message.
119119
///
@@ -164,7 +164,10 @@ pub enum ClosureReason {
164164
///
165165
/// [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor
166166
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
167-
OutdatedChannelManager
167+
OutdatedChannelManager,
168+
/// The counterparty requested a cooperative close of a channel that had not been funded yet.
169+
/// The channel has been immediately closed.
170+
CounterpartyCoopClosedUnfundedChannel,
168171
}
169172

170173
impl core::fmt::Display for ClosureReason {
@@ -184,6 +187,7 @@ impl core::fmt::Display for ClosureReason {
184187
},
185188
ClosureReason::DisconnectedPeer => f.write_str("the peer disconnected prior to the channel being funded"),
186189
ClosureReason::OutdatedChannelManager => f.write_str("the ChannelManager read from disk was stale compared to ChannelMonitor(s)"),
190+
ClosureReason::CounterpartyCoopClosedUnfundedChannel => f.write_str("the peer requested the unfunded channel be closed"),
187191
}
188192
}
189193
}
@@ -197,6 +201,7 @@ impl_writeable_tlv_based_enum_upgradable!(ClosureReason,
197201
(8, ProcessingError) => { (1, err, required) },
198202
(10, DisconnectedPeer) => {},
199203
(12, OutdatedChannelManager) => {},
204+
(13, CounterpartyCoopClosedUnfundedChannel) => {},
200205
);
201206

202207
/// Intended destination of a failed HTLC as indicated in [`Event::HTLCHandlingFailed`].

lightning/src/ln/channelmanager.rs

+42-30
Original file line numberDiff line numberDiff line change
@@ -5530,38 +5530,50 @@ where
55305530
})?;
55315531
let mut peer_state_lock = peer_state_mutex.lock().unwrap();
55325532
let peer_state = &mut *peer_state_lock;
5533-
match peer_state.channel_by_id.entry(msg.channel_id.clone()) {
5534-
hash_map::Entry::Occupied(mut chan_entry) => {
5535-
5536-
if !chan_entry.get().received_shutdown() {
5537-
log_info!(self.logger, "Received a shutdown message from our counterparty for channel {}{}.",
5538-
log_bytes!(msg.channel_id),
5539-
if chan_entry.get().sent_shutdown() { " after we initiated shutdown" } else { "" });
5540-
}
5541-
5542-
let funding_txo_opt = chan_entry.get().context.get_funding_txo();
5543-
let (shutdown, monitor_update_opt, htlcs) = try_chan_entry!(self,
5544-
chan_entry.get_mut().shutdown(&self.signer_provider, &peer_state.latest_features, &msg), chan_entry);
5545-
dropped_htlcs = htlcs;
5533+
// TODO(dunxen): Fix this duplication when we switch to a single map with enums as per
5534+
// https://github.com/lightningdevkit/rust-lightning/issues/2422
5535+
if let hash_map::Entry::Occupied(chan_entry) = peer_state.outbound_v1_channel_by_id.entry(msg.channel_id.clone()) {
5536+
log_error!(self.logger, "Immediately closing unfunded channel {} as peer asked to cooperatively shut it down (which is unnecessary)", log_bytes!(&msg.channel_id[..]));
5537+
self.issue_channel_close_events(&chan_entry.get().context, ClosureReason::CounterpartyCoopClosedUnfundedChannel);
5538+
let mut chan = remove_channel!(self, chan_entry);
5539+
self.finish_force_close_channel(chan.context.force_shutdown(false));
5540+
return Ok(());
5541+
} else if let hash_map::Entry::Occupied(chan_entry) = peer_state.inbound_v1_channel_by_id.entry(msg.channel_id.clone()) {
5542+
log_error!(self.logger, "Immediately closing unfunded channel {} as peer asked to cooperatively shut it down (which is unnecessary)", log_bytes!(&msg.channel_id[..]));
5543+
self.issue_channel_close_events(&chan_entry.get().context, ClosureReason::CounterpartyCoopClosedUnfundedChannel);
5544+
let mut chan = remove_channel!(self, chan_entry);
5545+
self.finish_force_close_channel(chan.context.force_shutdown(false));
5546+
return Ok(());
5547+
} else if let hash_map::Entry::Occupied(mut chan_entry) = peer_state.channel_by_id.entry(msg.channel_id.clone()) {
5548+
if !chan_entry.get().received_shutdown() {
5549+
log_info!(self.logger, "Received a shutdown message from our counterparty for channel {}{}.",
5550+
log_bytes!(msg.channel_id),
5551+
if chan_entry.get().sent_shutdown() { " after we initiated shutdown" } else { "" });
5552+
}
55465553

5547-
if let Some(msg) = shutdown {
5548-
// We can send the `shutdown` message before updating the `ChannelMonitor`
5549-
// here as we don't need the monitor update to complete until we send a
5550-
// `shutdown_signed`, which we'll delay if we're pending a monitor update.
5551-
peer_state.pending_msg_events.push(events::MessageSendEvent::SendShutdown {
5552-
node_id: *counterparty_node_id,
5553-
msg,
5554-
});
5555-
}
5554+
let funding_txo_opt = chan_entry.get().context.get_funding_txo();
5555+
let (shutdown, monitor_update_opt, htlcs) = try_chan_entry!(self,
5556+
chan_entry.get_mut().shutdown(&self.signer_provider, &peer_state.latest_features, &msg), chan_entry);
5557+
dropped_htlcs = htlcs;
5558+
5559+
if let Some(msg) = shutdown {
5560+
// We can send the `shutdown` message before updating the `ChannelMonitor`
5561+
// here as we don't need the monitor update to complete until we send a
5562+
// `shutdown_signed`, which we'll delay if we're pending a monitor update.
5563+
peer_state.pending_msg_events.push(events::MessageSendEvent::SendShutdown {
5564+
node_id: *counterparty_node_id,
5565+
msg,
5566+
});
5567+
}
55565568

5557-
// Update the monitor with the shutdown script if necessary.
5558-
if let Some(monitor_update) = monitor_update_opt {
5559-
break handle_new_monitor_update!(self, funding_txo_opt.unwrap(), monitor_update,
5560-
peer_state_lock, peer_state, per_peer_state, chan_entry).map(|_| ());
5561-
}
5562-
break Ok(());
5563-
},
5564-
hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}", counterparty_node_id), msg.channel_id))
5569+
// Update the monitor with the shutdown script if necessary.
5570+
if let Some(monitor_update) = monitor_update_opt {
5571+
break handle_new_monitor_update!(self, funding_txo_opt.unwrap(), monitor_update,
5572+
peer_state_lock, peer_state, per_peer_state, chan_entry).map(|_| ());
5573+
}
5574+
break Ok(());
5575+
} else {
5576+
return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}", counterparty_node_id), msg.channel_id))
55655577
}
55665578
};
55675579
for htlc_source in dropped_htlcs.drain(..) {

0 commit comments

Comments
 (0)