Skip to content

Commit 9f10157

Browse files
committed
Always process inb. shutdown ChannelMonitorUpdates asynchronously
We currently have two codepaths on most channel update functions - most methods return a set of messages to send a peer iff the `ChannelMonitorUpdate` succeeds, but if it does not we push the messages back into the `Channel` and then pull them back out when the `ChannelMonitorUpdate` completes and send them then. This adds a substantial amount of complexity in very critical codepaths. Instead, here we swap all our channel update codepaths to immediately set the channel-update-required flag and only return a `ChannelMonitorUpdate` to the `ChannelManager`. Internally in the `Channel` we store a queue of `ChannelMonitorUpdate`s, which will become critical in future work to surface pending `ChannelMonitorUpdate`s to users at startup so they can complete. This leaves some redundant work in `Channel` to be cleaned up later. Specifically, we still generate the messages which we will now ignore and regenerate later. This commit updates the `ChannelMonitorUpdate` pipeline for handling inbound `shutdown` messages.
1 parent a1d01e5 commit 9f10157

File tree

3 files changed

+28
-18
lines changed

3 files changed

+28
-18
lines changed

lightning/src/ln/chanmon_update_fail_tests.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2631,7 +2631,15 @@ fn test_permanent_error_during_handling_shutdown() {
26312631
assert!(nodes[0].node.close_channel(&channel_id, &nodes[1].node.get_our_node_id()).is_ok());
26322632
let shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
26332633
nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &nodes[0].node.init_features(), &shutdown);
2634-
check_closed_broadcast!(nodes[1], true);
2634+
2635+
// We always send the `shutdown` response when receiving a shutdown, even if we immediately
2636+
// close the channel thereafter.
2637+
let msg_events = nodes[1].node.get_and_clear_pending_msg_events();
2638+
assert_eq!(msg_events.len(), 3);
2639+
if let MessageSendEvent::SendShutdown { .. } = msg_events[0] {} else { panic!(); }
2640+
if let MessageSendEvent::BroadcastChannelUpdate { .. } = msg_events[1] {} else { panic!(); }
2641+
if let MessageSendEvent::HandleError { .. } = msg_events[2] {} else { panic!(); }
2642+
26352643
check_added_monitors!(nodes[1], 2);
26362644
check_closed_event!(nodes[1], 1, ClosureReason::ProcessingError { err: "ChannelMonitor storage failure".to_string() });
26372645
}

lightning/src/ln/channel.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4193,7 +4193,7 @@ impl<Signer: Sign> Channel<Signer> {
41934193

41944194
pub fn shutdown<SP: Deref>(
41954195
&mut self, signer_provider: &SP, their_features: &InitFeatures, msg: &msgs::Shutdown
4196-
) -> Result<(Option<msgs::Shutdown>, Option<ChannelMonitorUpdate>, Vec<(HTLCSource, PaymentHash)>), ChannelError>
4196+
) -> Result<(Option<msgs::Shutdown>, Option<&ChannelMonitorUpdate>, Vec<(HTLCSource, PaymentHash)>), ChannelError>
41974197
where SP::Target: SignerProvider
41984198
{
41994199
if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
@@ -4249,12 +4249,15 @@ impl<Signer: Sign> Channel<Signer> {
42494249

42504250
let monitor_update = if update_shutdown_script {
42514251
self.latest_monitor_update_id += 1;
4252-
Some(ChannelMonitorUpdate {
4252+
let monitor_update = ChannelMonitorUpdate {
42534253
update_id: self.latest_monitor_update_id,
42544254
updates: vec![ChannelMonitorUpdateStep::ShutdownScript {
42554255
scriptpubkey: self.get_closing_scriptpubkey(),
42564256
}],
4257-
})
4257+
};
4258+
self.monitor_updating_paused(false, false, false, Vec::new(), Vec::new(), Vec::new());
4259+
self.pending_monitor_updates.push(monitor_update);
4260+
Some(self.pending_monitor_updates.last().unwrap())
42584261
} else { None };
42594262
let shutdown = if send_shutdown {
42604263
Some(msgs::Shutdown {

lightning/src/ln/channelmanager.rs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4509,27 +4509,27 @@ where
45094509
if chan_entry.get().sent_shutdown() { " after we initiated shutdown" } else { "" });
45104510
}
45114511

4512-
let (shutdown, monitor_update, htlcs) = try_chan_entry!(self, chan_entry.get_mut().shutdown(&self.signer_provider, &their_features, &msg), chan_entry);
4512+
let funding_txo_opt = chan_entry.get().get_funding_txo();
4513+
let (shutdown, monitor_update_opt, htlcs) = try_chan_entry!(self,
4514+
chan_entry.get_mut().shutdown(&self.signer_provider, &their_features, &msg), chan_entry);
45134515
dropped_htlcs = htlcs;
45144516

4515-
// Update the monitor with the shutdown script if necessary.
4516-
if let Some(monitor_update) = monitor_update {
4517-
let update_res = self.chain_monitor.update_channel(chan_entry.get().get_funding_txo().unwrap(), &monitor_update);
4518-
let (result, is_permanent) =
4519-
handle_monitor_update_res!(self, update_res, chan_entry.get_mut(), RAACommitmentOrder::CommitmentFirst, chan_entry.key(), NO_UPDATE);
4520-
if is_permanent {
4521-
remove_channel!(self, chan_entry);
4522-
break result;
4523-
}
4524-
}
4525-
45264517
if let Some(msg) = shutdown {
4518+
// We can send the `shutdown` message before updating the `ChannelMonitor`
4519+
// here as we don't need the monitor update to complete until we send a
4520+
// `shutdown_signed`, which we'll delay if we're pending a monitor update.
45274521
peer_state.pending_msg_events.push(events::MessageSendEvent::SendShutdown {
45284522
node_id: *counterparty_node_id,
45294523
msg,
45304524
});
45314525
}
45324526

4527+
// Update the monitor with the shutdown script if necessary.
4528+
if let Some(monitor_update) = monitor_update_opt {
4529+
let update_id = monitor_update.update_id;
4530+
let update_res = self.chain_monitor.update_channel(funding_txo_opt.unwrap(), monitor_update);
4531+
break handle_new_monitor_update!(self, update_res, update_id, peer_state_lock, peer_state, chan_entry);
4532+
}
45334533
break Ok(());
45344534
},
45354535
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))
@@ -4541,8 +4541,7 @@ where
45414541
self.fail_htlc_backwards_internal(&htlc_source.0, &htlc_source.1, &reason, receiver);
45424542
}
45434543

4544-
let _ = handle_error!(self, result, *counterparty_node_id);
4545-
Ok(())
4544+
result
45464545
}
45474546

45484547
fn internal_closing_signed(&self, counterparty_node_id: &PublicKey, msg: &msgs::ClosingSigned) -> Result<(), MsgHandleErrInternal> {

0 commit comments

Comments
 (0)