Skip to content

Commit 0a32497

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 9c32d32 commit 0a32497

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(), &channelmanager::provided_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
@@ -4191,7 +4191,7 @@ impl<Signer: Sign> Channel<Signer> {
41914191

41924192
pub fn shutdown<K: Deref>(
41934193
&mut self, keys_provider: &K, their_features: &InitFeatures, msg: &msgs::Shutdown
4194-
) -> Result<(Option<msgs::Shutdown>, Option<ChannelMonitorUpdate>, Vec<(HTLCSource, PaymentHash)>), ChannelError>
4194+
) -> Result<(Option<msgs::Shutdown>, Option<&ChannelMonitorUpdate>, Vec<(HTLCSource, PaymentHash)>), ChannelError>
41954195
where K::Target: KeysInterface
41964196
{
41974197
if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 {
@@ -4247,12 +4247,15 @@ impl<Signer: Sign> Channel<Signer> {
42474247

42484248
let monitor_update = if update_shutdown_script {
42494249
self.latest_monitor_update_id += 1;
4250-
Some(ChannelMonitorUpdate {
4250+
let monitor_update = ChannelMonitorUpdate {
42514251
update_id: self.latest_monitor_update_id,
42524252
updates: vec![ChannelMonitorUpdateStep::ShutdownScript {
42534253
scriptpubkey: self.get_closing_scriptpubkey(),
42544254
}],
4255-
})
4255+
};
4256+
self.monitor_updating_paused(false, false, false, Vec::new(), Vec::new(), Vec::new());
4257+
self.pending_monitor_updates.push(monitor_update);
4258+
Some(self.pending_monitor_updates.last().unwrap())
42564259
} else { None };
42574260
let shutdown = if send_shutdown {
42584261
Some(msgs::Shutdown {

lightning/src/ln/channelmanager.rs

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

4501-
let (shutdown, monitor_update, htlcs) = try_chan_entry!(self, chan_entry.get_mut().shutdown(&self.keys_manager, &their_features, &msg), chan_entry);
4501+
let funding_txo_opt = chan_entry.get().get_funding_txo();
4502+
let (shutdown, monitor_update_opt, htlcs) =
4503+
try_chan_entry!(self, chan_entry.get_mut().shutdown(&self.keys_manager, &their_features, &msg), chan_entry);
45024504
dropped_htlcs = htlcs;
45034505

4504-
// Update the monitor with the shutdown script if necessary.
4505-
if let Some(monitor_update) = monitor_update {
4506-
let update_res = self.chain_monitor.update_channel(chan_entry.get().get_funding_txo().unwrap(), &monitor_update);
4507-
let (result, is_permanent) =
4508-
handle_monitor_update_res!(self, update_res, chan_entry.get_mut(), RAACommitmentOrder::CommitmentFirst, chan_entry.key(), NO_UPDATE);
4509-
if is_permanent {
4510-
remove_channel!(self, chan_entry);
4511-
break result;
4512-
}
4513-
}
4514-
45154506
if let Some(msg) = shutdown {
4507+
// We can send the `shutdown` message before updating the `ChannelMonitor`
4508+
// here as we don't need the monitor update to complete until we send a
4509+
// `shutdown_signed`, which we'll delay if we're pending a monitor update.
45164510
peer_state.pending_msg_events.push(events::MessageSendEvent::SendShutdown {
45174511
node_id: *counterparty_node_id,
45184512
msg,
45194513
});
45204514
}
45214515

4516+
// Update the monitor with the shutdown script if necessary.
4517+
if let Some(monitor_update) = monitor_update_opt {
4518+
let update_id = monitor_update.update_id;
4519+
let update_res = self.chain_monitor.update_channel(funding_txo_opt.unwrap(), monitor_update);
4520+
break handle_new_monitor_update!(self, update_res, update_id, peer_state_lock, peer_state, chan_entry);
4521+
}
45224522
break Ok(());
45234523
},
45244524
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))
@@ -4530,8 +4530,7 @@ where
45304530
self.fail_htlc_backwards_internal(&htlc_source.0, &htlc_source.1, &reason, receiver);
45314531
}
45324532

4533-
let _ = handle_error!(self, result, *counterparty_node_id);
4534-
Ok(())
4533+
result
45354534
}
45364535

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

0 commit comments

Comments
 (0)