Skip to content

Panic when applying monitor update during channel force close #3857

@whfuyn

Description

@whfuyn

if self.latest_update_id + 1 != updates.update_id {
panic!("Attempted to apply ChannelMonitorUpdates out of order, check the update_id before passing an update to update_monitor!");
}

Our node panicked here. The expected update_id for the channel monitor is 104, but we got an update with id 105.

2025-06-13T07:14:36.486669Z DEBUG lightning::ln::channel:5855: Received a valid revoke_and_ack for channel e45b958e1ddde1e145820e8a1bbdef7e3a427d056ba4b5000d2b7f7b1c62bc81. Responding with a commitment update with 0 HTLCs failed. Holding monitor update.
2025-06-13T07:14:36.486742Z DEBUG lightning::ln::peer_handler:2315: Handling SendRevokeAndACK event in peer_handler for node 030e7e79d6b5eae143391535574d320b1f432cd12587b20ad5b2f9334bded49ee0 for channel e45b958e1ddde1e145820e8a1bbdef7e3a427d056ba4b5000d2b7f7b1c62bc81
2025-06-13T07:14:36.486875Z DEBUG lightning::ln::peer_handler:1798: Got Err message from 030e7e79d6b5eae143391535574d320b1f432cd12587b20ad5b2f9334bded49ee0: 
2025-06-13T07:14:36.493859Z ERROR lightning::ln::channelmanager:4166: Force-closing channel e45b958e1ddde1e145820e8a1bbdef7e3a427d056ba4b5000d2b7f7b1c62bc81
2025-06-13T07:14:36.493914Z DEBUG lightning::chain::chainmonitor:824: Updating ChannelMonitor with update ChannelMonitorUpdate {
    updates: [
        ChannelForceClosed {
            should_broadcast: true,
        },
    ],
    counterparty_node_id: Some(
        PublicKey(
            e09ed4de4b33f9b2d50ab28725d12c431f0b324d5735153943e1eab5d6797e0e874ee011af78e4452bd3b16cf4890fc7d8a96ba00a46b85da7cba51fb498f205,
        ),
    ),
    update_id: 105,
    channel_id: Some(
        0xe45b958e1ddde1e145820e8a1bbdef7e3a427d056ba4b5000d2b7f7b1c62bc81,
    ),
} for channel e45b958e1ddde1e145820e8a1bbdef7e3a427d056ba4b5000d2b7f7b1c62bc81
2025-06-13T07:14:36.493926Z DEBUG lightning::chain::chainmonitor:830: pending_monitor_updates lock acquired
2025-06-13T07:14:36.493928Z  INFO lightning::chain::channelmonitor:3225: Applying update to monitor e45b958e1ddde1e145820e8a1bbdef7e3a427d056ba4b5000d2b7f7b1c62bc81, bringing update_id from 103 to 105 with 1 change(s).

Notice the Holding monitor update in the first line of the logs.

let release_monitor = self.context.blocked_monitor_updates.is_empty() && !hold_mon_update;
let release_state_str =
if hold_mon_update { "Holding" } else if release_monitor { "Releasing" } else { "Blocked" };
macro_rules! return_with_htlcs_to_fail {
($htlcs_to_fail: expr) => {
if !release_monitor {
self.context.blocked_monitor_updates.push(PendingChannelMonitorUpdate {
update: monitor_update,
});
return Ok(($htlcs_to_fail, None));
} else {
return Ok(($htlcs_to_fail, Some(monitor_update)));
}
}
}

There are blocked monitor updates not yet applied when the channel is force-closed. But latest_monitor_update_id has been incremented and assigned to these updates.

if !self.channel_state.is_pre_funded_state() {
self.latest_monitor_update_id += 1;
Some((self.get_counterparty_node_id(), funding_txo, self.channel_id(), ChannelMonitorUpdate {
update_id: self.latest_monitor_update_id,
updates: vec![ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast }],
channel_id: Some(self.channel_id()),
}))
} else { None }

The ChannelForceClosed update is applied to the monitor before the blocked updates, leaving a gap in update_id and causing panic.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions