Skip to content

Commit dfb250b

Browse files
authored
Merge pull request #3021 from TheBlueMatt/2024-04-drop-blocked-completed-updates
Drop completed blocked `ChannelMonitorUpdate`s on startup
2 parents eebab40 + c40504a commit dfb250b

File tree

3 files changed

+60
-2
lines changed

3 files changed

+60
-2
lines changed

lightning/src/ln/channel.rs

+20
Original file line numberDiff line numberDiff line change
@@ -6251,6 +6251,26 @@ impl<SP: Deref> Channel<SP> where
62516251
}
62526252
}
62536253

6254+
/// On startup, its possible we detect some monitor updates have actually completed (and the
6255+
/// ChannelManager was simply stale). In that case, we should simply drop them, which we do
6256+
/// here after logging them.
6257+
pub fn on_startup_drop_completed_blocked_mon_updates_through<L: Logger>(&mut self, logger: &L, loaded_mon_update_id: u64) {
6258+
let channel_id = self.context.channel_id();
6259+
self.context.blocked_monitor_updates.retain(|update| {
6260+
if update.update.update_id <= loaded_mon_update_id {
6261+
log_info!(
6262+
logger,
6263+
"Dropping completed ChannelMonitorUpdate id {} on channel {} due to a stale ChannelManager",
6264+
update.update.update_id,
6265+
channel_id,
6266+
);
6267+
false
6268+
} else {
6269+
true
6270+
}
6271+
});
6272+
}
6273+
62546274
pub fn blocked_monitor_updates_pending(&self) -> usize {
62556275
self.context.blocked_monitor_updates.len()
62566276
}

lightning/src/ln/channelmanager.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -11561,9 +11561,10 @@ where
1156111561
}
1156211562
}
1156311563
} else {
11564-
log_info!(logger, "Successfully loaded channel {} at update_id {} against monitor at update id {}",
11564+
channel.on_startup_drop_completed_blocked_mon_updates_through(&logger, monitor.get_latest_update_id());
11565+
log_info!(logger, "Successfully loaded channel {} at update_id {} against monitor at update id {} with {} blocked updates",
1156511566
&channel.context.channel_id(), channel.context.get_latest_monitor_update_id(),
11566-
monitor.get_latest_update_id());
11567+
monitor.get_latest_update_id(), channel.blocked_monitor_updates_pending());
1156711568
if let Some(short_channel_id) = channel.context.get_short_channel_id() {
1156811569
short_to_chan_info.insert(short_channel_id, (channel.context.get_counterparty_node_id(), channel.context.channel_id()));
1156911570
}

lightning/src/ln/monitor_tests.rs

+37
Original file line numberDiff line numberDiff line change
@@ -2877,3 +2877,40 @@ fn test_monitor_claims_with_random_signatures() {
28772877
do_test_monitor_claims_with_random_signatures(true, false);
28782878
do_test_monitor_claims_with_random_signatures(true, true);
28792879
}
2880+
2881+
#[test]
2882+
fn test_event_replay_causing_monitor_replay() {
2883+
// In LDK 0.0.121 there was a bug where if a `PaymentSent` event caused an RAA
2884+
// `ChannelMonitorUpdate` hold and then the node was restarted after the `PaymentSent` event
2885+
// and `ChannelMonitorUpdate` both completed but without persisting the `ChannelManager` we'd
2886+
// replay the `ChannelMonitorUpdate` on restart (which is fine, but triggered a safety panic).
2887+
let chanmon_cfgs = create_chanmon_cfgs(2);
2888+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
2889+
let persister;
2890+
let new_chain_monitor;
2891+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
2892+
let node_deserialized;
2893+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
2894+
2895+
let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000);
2896+
2897+
let payment_preimage = route_payment(&nodes[0], &[&nodes[1]], 1_000_000).0;
2898+
2899+
do_claim_payment_along_route(&nodes[0], &[&[&nodes[1]]], false, payment_preimage);
2900+
2901+
// At this point the `PaymentSent` event has not been processed but the full commitment signed
2902+
// dance has completed.
2903+
let serialized_channel_manager = nodes[0].node.encode();
2904+
2905+
// Now process the `PaymentSent` to get the final RAA `ChannelMonitorUpdate`, checking that it
2906+
// resulted in a `ChannelManager` persistence request.
2907+
nodes[0].node.get_and_clear_needs_persistence();
2908+
expect_payment_sent(&nodes[0], payment_preimage, None, true, true /* expected post-event monitor update*/);
2909+
assert!(nodes[0].node.get_and_clear_needs_persistence());
2910+
2911+
let serialized_monitor = get_monitor!(nodes[0], chan.2).encode();
2912+
reload_node!(nodes[0], &serialized_channel_manager, &[&serialized_monitor], persister, new_chain_monitor, node_deserialized);
2913+
2914+
// Expect the `PaymentSent` to get replayed, this time without the duplicate monitor update
2915+
expect_payment_sent(&nodes[0], payment_preimage, None, false, false /* expected post-event monitor update*/);
2916+
}

0 commit comments

Comments
 (0)