Skip to content

Commit e50facd

Browse files
committed
f: Hold deferred_monitor_update_completions lock to prevent races
1 parent b15785c commit e50facd

File tree

1 file changed

+18
-15
lines changed

1 file changed

+18
-15
lines changed

lightning/src/chain/chainmonitor.rs

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,6 +1345,12 @@ where
13451345
let logger = WithChannelMonitor::from(&self.logger, &monitor, None);
13461346
log_trace!(logger, "Updating ChannelMonitor to id {}", update.update_id,);
13471347

1348+
// We hold `deferred_monitor_update_completions` through the entire
1349+
// update process so that `release_pending_monitor_events` either
1350+
// sees both the `MonitorEvent`s generated by `update_monitor` and
1351+
// the corresponding deferral entry, or neither.
1352+
let mut deferred =
1353+
monitor_state.deferred_monitor_update_completions.lock().unwrap();
13481354
// We hold a `pending_monitor_updates` lock through `update_monitor` to ensure we
13491355
// have well-ordered updates from the users' point of view. See the
13501356
// `pending_monitor_updates` docs for more.
@@ -1396,6 +1402,7 @@ where
13961402
ChannelMonitorUpdateStatus::UnrecoverableError => {
13971403
// Take the monitors lock for writing so that we poison it and any future
13981404
// operations going forward fail immediately.
1405+
core::mem::drop(deferred);
13991406
core::mem::drop(pending_monitor_updates);
14001407
core::mem::drop(monitors);
14011408
let _poison = self.monitors.write().unwrap();
@@ -1434,11 +1441,7 @@ where
14341441
// gets resolved during release_pending_monitor_events, together with
14351442
// those MonitorEvents.
14361443
pending_monitor_updates.push(update_id);
1437-
monitor_state
1438-
.deferred_monitor_update_completions
1439-
.lock()
1440-
.unwrap()
1441-
.push(update_id);
1444+
deferred.push(update_id);
14421445
log_debug!(
14431446
logger,
14441447
"Deferring completion of ChannelMonitorUpdate id {:?} (channel is post-close)",
@@ -1461,6 +1464,10 @@ where
14611464
let monitors = self.monitors.read().unwrap();
14621465
let mut pending_monitor_events = self.pending_monitor_events.lock().unwrap().split_off(0);
14631466
for monitor_state in monitors.values() {
1467+
// Hold the deferred lock across both `get_and_clear_pending_monitor_events`
1468+
// and the deferred resolution so that `update_monitor` cannot insert a
1469+
// `MonitorEvent` and deferral entry between the two steps.
1470+
let mut deferred = monitor_state.deferred_monitor_update_completions.lock().unwrap();
14641471
let monitor_events = monitor_state.monitor.get_and_clear_pending_monitor_events();
14651472
if monitor_events.len() > 0 {
14661473
let monitor_funding_txo = monitor_state.monitor.get_funding_txo();
@@ -1473,16 +1480,12 @@ where
14731480
counterparty_node_id,
14741481
));
14751482
}
1476-
}
1477-
// Resolve any deferred monitor update completions after collecting regular monitor
1478-
// events. The regular events include the force-close (CommitmentTxConfirmed), which
1479-
// ChannelManager processes first. The deferred completions come after, so that
1480-
// completion actions resolve once the ChannelForceClosed update (generated during
1481-
// force-close processing) also gets deferred and resolved in the next event cycle.
1482-
for monitor_state in monitors.values() {
1483-
let deferred =
1484-
monitor_state.deferred_monitor_update_completions.lock().unwrap().split_off(0);
1485-
for update_id in deferred {
1483+
// Resolve any deferred monitor update completions after collecting regular monitor
1484+
// events. The regular events include the force-close (CommitmentTxConfirmed), which
1485+
// ChannelManager processes first. The deferred completions come after, so that
1486+
// completion actions resolve once the ChannelForceClosed update (generated during
1487+
// force-close processing) also gets deferred and resolved in the next event cycle.
1488+
for update_id in deferred.drain(..) {
14861489
let mut pending = monitor_state.pending_monitor_updates.lock().unwrap();
14871490
pending.retain(|id| *id != update_id);
14881491
let monitor_is_pending_updates = monitor_state.has_pending_updates(&pending);

0 commit comments

Comments
 (0)