Skip to content

Commit b0ec5eb

Browse files
joostjagerclaude
andcommitted
Skip ChannelManager persistence for message-only monitor completions
When a MonitorEvent::Completed fires and the only result of channel resumption is queuing outbound messages (commitment_signed, revoke_and_ack), skip the ChannelManager persist. This avoids an unnecessary write on every HTLC send where the monitor update for the counterparty's commitment completes. The persist decision is computed in try_resume_channel_post_monitor_update where MonitorRestoreUpdates fields are still available, and returned alongside the PostMonitorUpdateChanResume as a tuple. Persistence is requested only when state-changing operations occur (funding broadcast, channel_ready, announcement_sigs, HTLC forwards/failures/claims, update actions, or batch funding). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1683dbb commit b0ec5eb

File tree

1 file changed

+56
-25
lines changed

1 file changed

+56
-25
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10169,13 +10169,14 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1016910169
let logger = WithChannelContext::from(&self.logger, &chan.context, None);
1017010170
let update_completed = self.handle_monitor_update_res(update_res, logger);
1017110171
if update_completed {
10172-
Some(self.try_resume_channel_post_monitor_update(
10172+
let (data, _needs_persist) = self.try_resume_channel_post_monitor_update(
1017310173
in_flight_monitor_updates,
1017410174
monitor_update_blocked_actions,
1017510175
pending_msg_events,
1017610176
is_connected,
1017710177
chan,
10178-
))
10178+
);
10179+
Some(data)
1017910180
} else {
1018010181
None
1018110182
}
@@ -10235,13 +10236,14 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1023510236
);
1023610237

1023710238
let completion_data = if all_updates_complete {
10238-
Some(self.try_resume_channel_post_monitor_update(
10239+
let (data, _needs_persist) = self.try_resume_channel_post_monitor_update(
1023910240
in_flight_monitor_updates,
1024010241
monitor_update_blocked_actions,
1024110242
pending_msg_events,
1024210243
is_connected,
1024310244
chan,
10244-
))
10245+
);
10246+
Some(data)
1024510247
} else {
1024610248
None
1024710249
};
@@ -10266,7 +10268,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1026610268
>,
1026710269
pending_msg_events: &mut Vec<MessageSendEvent>, is_connected: bool,
1026810270
chan: &mut FundedChannel<SP>,
10269-
) -> PostMonitorUpdateChanResume {
10271+
) -> (PostMonitorUpdateChanResume, bool) {
1027010272
let chan_id = chan.context.channel_id();
1027110273
let outbound_alias = chan.context.outbound_scid_alias();
1027210274
let counterparty_node_id = chan.context.get_counterparty_node_id();
@@ -10284,7 +10286,8 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1028410286

1028510287
if chan.blocked_monitor_updates_pending() != 0 {
1028610288
log_debug!(logger, "Channel has blocked monitor updates, completing update actions but leaving channel blocked");
10287-
PostMonitorUpdateChanResume::Blocked { update_actions }
10289+
let needs_persist = !update_actions.is_empty();
10290+
(PostMonitorUpdateChanResume::Blocked { update_actions }, needs_persist)
1028810291
} else {
1028910292
log_debug!(logger, "Channel is open and awaiting update, resuming it");
1029010293
let updates = chan.monitor_updating_restored(
@@ -10315,6 +10318,11 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1031510318
None
1031610319
};
1031710320

10321+
// Checked before handle_channel_resumption moves these fields.
10322+
let has_state_changes = updates.funding_broadcastable.is_some()
10323+
|| updates.channel_ready.is_some()
10324+
|| updates.announcement_sigs.is_some();
10325+
1031810326
let (htlc_forwards, decode_update_add_htlcs) = self.handle_channel_resumption(
1031910327
pending_msg_events,
1032010328
chan,
@@ -10337,19 +10345,32 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1033710345
let unbroadcasted_batch_funding_txid =
1033810346
chan.context.unbroadcasted_batch_funding_txid(&chan.funding);
1033910347

10340-
PostMonitorUpdateChanResume::Unblocked {
10341-
channel_id: chan_id,
10342-
counterparty_node_id,
10343-
funding_txo: chan.funding_outpoint(),
10344-
user_channel_id: chan.context.get_user_id(),
10345-
unbroadcasted_batch_funding_txid,
10346-
update_actions,
10347-
htlc_forwards,
10348-
decode_update_add_htlcs,
10349-
finalized_claimed_htlcs: updates.finalized_claimed_htlcs,
10350-
failed_htlcs: updates.failed_htlcs,
10351-
committed_outbound_htlc_sources: updates.committed_outbound_htlc_sources,
10352-
}
10348+
// Queuing outbound messages (commitment_update, raa) alone does
10349+
// not require ChannelManager persistence.
10350+
let needs_persist = has_state_changes
10351+
|| !updates.finalized_claimed_htlcs.is_empty()
10352+
|| !updates.failed_htlcs.is_empty()
10353+
|| !update_actions.is_empty()
10354+
|| unbroadcasted_batch_funding_txid.is_some()
10355+
|| !htlc_forwards.is_empty()
10356+
|| decode_update_add_htlcs.is_some();
10357+
10358+
(
10359+
PostMonitorUpdateChanResume::Unblocked {
10360+
channel_id: chan_id,
10361+
counterparty_node_id,
10362+
funding_txo: chan.funding_outpoint(),
10363+
user_channel_id: chan.context.get_user_id(),
10364+
unbroadcasted_batch_funding_txid,
10365+
update_actions,
10366+
htlc_forwards,
10367+
decode_update_add_htlcs,
10368+
finalized_claimed_htlcs: updates.finalized_claimed_htlcs,
10369+
failed_htlcs: updates.failed_htlcs,
10370+
committed_outbound_htlc_sources: updates.committed_outbound_htlc_sources,
10371+
},
10372+
needs_persist,
10373+
)
1035310374
}
1035410375
}
1035510376

@@ -10618,13 +10639,14 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1061810639
}
1061910640

1062010641
#[rustfmt::skip]
10621-
fn channel_monitor_updated(&self, channel_id: &ChannelId, highest_applied_update_id: Option<u64>, counterparty_node_id: &PublicKey) {
10642+
fn channel_monitor_updated(&self, channel_id: &ChannelId, highest_applied_update_id: Option<u64>, counterparty_node_id: &PublicKey) -> bool {
1062210643
debug_assert!(self.total_consistency_lock.try_write().is_err()); // Caller holds read lock
1062310644

1062410645
let per_peer_state = self.per_peer_state.read().unwrap();
1062510646
let mut peer_state_lock;
1062610647
let peer_state_mutex_opt = per_peer_state.get(counterparty_node_id);
10627-
if peer_state_mutex_opt.is_none() { return }
10648+
// Peer is gone; conservatively request persistence.
10649+
if peer_state_mutex_opt.is_none() { return true }
1062810650
peer_state_lock = peer_state_mutex_opt.unwrap().lock().unwrap();
1062910651
let peer_state = &mut *peer_state_lock;
1063010652

@@ -10656,15 +10678,15 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1065610678
} else { 0 };
1065710679

1065810680
if remaining_in_flight != 0 {
10659-
return;
10681+
return false;
1066010682
}
1066110683

1066210684
if let Some(chan) = peer_state.channel_by_id
1066310685
.get_mut(channel_id)
1066410686
.and_then(Channel::as_funded_mut)
1066510687
{
1066610688
if chan.is_awaiting_monitor_update() {
10667-
let completion_data = self.try_resume_channel_post_monitor_update(
10689+
let (completion_data, needs_persist) = self.try_resume_channel_post_monitor_update(
1066810690
&mut peer_state.in_flight_monitor_updates,
1066910691
&mut peer_state.monitor_update_blocked_actions,
1067010692
&mut peer_state.pending_msg_events,
@@ -10679,16 +10701,20 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1067910701

1068010702
self.handle_post_monitor_update_chan_resume(completion_data);
1068110703
self.handle_holding_cell_free_result(holding_cell_res);
10704+
needs_persist
1068210705
} else {
1068310706
log_trace!(logger, "Channel is open but not awaiting update");
10707+
false
1068410708
}
1068510709
} else {
1068610710
let update_actions = peer_state.monitor_update_blocked_actions
1068710711
.remove(channel_id).unwrap_or(Vec::new());
10712+
let needs_persist = !update_actions.is_empty();
1068810713
log_trace!(logger, "Channel is closed, applying {} post-update actions", update_actions.len());
1068910714
mem::drop(peer_state_lock);
1069010715
mem::drop(per_peer_state);
1069110716
self.handle_monitor_update_completion_actions(update_actions);
10717+
needs_persist
1069210718
}
1069310719
}
1069410720

@@ -13027,6 +13053,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1302713053
if pending_monitor_events.is_empty() {
1302813054
return NotifyOption::SkipPersistNoEvents;
1302913055
}
13056+
let mut needs_persist = true;
1303013057
for (funding_outpoint, channel_id, mut monitor_events, counterparty_node_id) in
1303113058
pending_monitor_events.drain(..)
1303213059
{
@@ -13138,7 +13165,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1313813165
}
1313913166
},
1314013167
MonitorEvent::Completed { channel_id, monitor_update_id, .. } => {
13141-
self.channel_monitor_updated(
13168+
needs_persist = self.channel_monitor_updated(
1314213169
&channel_id,
1314313170
Some(monitor_update_id),
1314413171
&counterparty_node_id,
@@ -13152,7 +13179,11 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1315213179
let _ = self.handle_error(err, counterparty_node_id);
1315313180
}
1315413181

13155-
NotifyOption::DoPersist
13182+
if needs_persist {
13183+
NotifyOption::DoPersist
13184+
} else {
13185+
NotifyOption::SkipPersistHandleEvents
13186+
}
1315613187
}
1315713188

1315813189
fn handle_holding_cell_free_result(&self, result: FreeHoldingCellsResult) {

0 commit comments

Comments
 (0)