Skip to content

Conversation

@joostjager
Copy link
Contributor

@joostjager joostjager commented Dec 19, 2025

Replaces five monitor update handling macros with proper methods on ChannelManager:

  • handle_monitor_update_completion!
  • handle_initial_monitor!
  • handle_post_close_monitor_update!
  • handle_new_monitor_update_locked_actions_handled_by_caller!
  • handle_new_monitor_update!

Introduces MonitorUpdateCompletionData enum to cleanly separate the data extraction phase (requires locks) from the processing phase (after locks released).

Motivation

Macros make this code hard to debug, navigate, and understand due to implicit variable capture and non-obvious control flow. Methods provide clear signatures, explicit parameters, and proper stack traces.

No behavioral changes.

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Dec 19, 2025

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@joostjager joostjager force-pushed the update-handling-refactor branch from dd25afd to f687020 Compare December 19, 2025 09:10
@joostjager joostjager changed the title Convert internal update handling methods to methods Convert internal update handling fns to methods Dec 19, 2025
@joostjager joostjager force-pushed the update-handling-refactor branch from f687020 to dfbf531 Compare December 19, 2025 09:18
@codecov
Copy link

codecov bot commented Dec 19, 2025

Codecov Report

❌ Patch coverage is 93.56984% with 29 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.61%. Comparing base (62c5849) to head (20e8526).
⚠️ Report is 46 commits behind head on main.

Files with missing lines Patch % Lines
lightning/src/ln/channelmanager.rs 93.56% 26 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4291      +/-   ##
==========================================
- Coverage   89.38%   86.61%   -2.77%     
==========================================
  Files         180      158      -22     
  Lines      139834   102720   -37114     
  Branches   139834   102720   -37114     
==========================================
- Hits       124985    88975   -36010     
+ Misses      12262    11330     -932     
+ Partials     2587     2415     -172     
Flag Coverage Δ
fuzzing 37.08% <64.30%> (+1.87%) ⬆️
tests 85.91% <93.12%> (-2.81%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@joostjager joostjager marked this pull request as ready for review December 19, 2025 11:41
@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 2nd Reminder

Hey @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 3rd Reminder

Hey @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 4th Reminder

Hey @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 5th Reminder

Hey @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 6th Reminder

Hey @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 7th Reminder

Hey @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

Copy link
Contributor

@valentinewallace valentinewallace left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm kind of meh on whether this improves readability, tbh. Is it just the CM argument?

@ldk-reviews-bot
Copy link

👋 The first review has been submitted!

Do you think this PR is ready for a second reviewer? If so, click here to assign a second reviewer.

Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this is a readability reduction - instead of having the code next to the macros that call it (that its effectively an implementation detail of), this moves the code to some unrelated part of the file. If we can make the macros a function great, but separating the code from the code calling it seems like a loss.

@joostjager
Copy link
Contributor Author

In my opinion those functions really are methods based on what they access inside ChannelManager. Having them be actual methods - even when not located next to the macro code - is an improvement for me, but of course this is a matter of preference.

But as you both don't share this preference, the code should probably remain what it is.

@TheBlueMatt
Copy link
Collaborator

In my opinion those functions really are methods based on what they access inside ChannelManager.

I agree with this, but that really applies to the things that are still macros after this PR - the things that are being called should be methods on ChannelManager, not macros. The internal details of those things should remain with them, though. You may well be able to move them out of macros though - the borrow checker is way smarter than it was when some of the macros were written and some of them might not have been necessary when they were written either.

@joostjager
Copy link
Contributor Author

Done in the latest push. This does introduce some duplication with the lock dropping and completion handling repeated at each call site. However, I think this is a worthwhile trade-off. As someone relatively new to the codebase, the macros have been a constant source of confusion. They obscure control flow, don't show up in symbol navigation, and create gaps in the call stack during debugging. The explicit code is much easier to follow and reason about, in my opinion.

Let's decide if we want to go this way (I think we should), and then I'll do a closer inspection of the claude generated code to see if it's all sound.

@joostjager joostjager force-pushed the update-handling-refactor branch from a12908f to 8cd1f51 Compare January 7, 2026 10:21
@valentinewallace
Copy link
Contributor

Concept ACK, needs a fair amount of cleanup and would prefer if the last commit were broken up a bunch though

@joostjager joostjager force-pushed the update-handling-refactor branch 5 times, most recently from 89a8981 to f59d1ab Compare January 8, 2026 12:06
@joostjager
Copy link
Contributor Author

Broke up the big refactor commit and scrutinized the claude code. I think it should be much more reviewable now.

@joostjager joostjager changed the title Convert internal update handling fns to methods Convert monitor update macros to ChannelManager methods Jan 8, 2026
@joostjager joostjager force-pushed the update-handling-refactor branch from f59d1ab to abdbf82 Compare January 8, 2026 12:14
@joostjager joostjager requested a review from TheBlueMatt January 8, 2026 16:16
@joostjager joostjager self-assigned this Jan 8, 2026
@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @TheBlueMatt @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

1 similar comment
@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @TheBlueMatt @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 2nd Reminder

Hey @TheBlueMatt @valentinewallace! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

if let Some((_, funding_txo, _, update)) = shutdown_res.monitor_update.take() {
handle_new_monitor_update_locked_actions_handled_by_caller!(
self,
self.handle_new_monitor_update_internal(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not call a method called _internal :). Rename it if its supposed to be called or improve the call semantics if not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Renamed to the simple update_channel_monitor.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update_channel_monitor absolutely doesn't capture the "this function is weird, you probably shouldn't use it, its only for cases where you have to handle the post-update stuff manually for some specific reason". We're gonna screw this up in the future and someone is gonna use update_channel_monitor thinking its just a normal method to call when they need to update the channel monitor and no one is gonna catch it in review.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous "_internal" at least communicated some of that... Do you have a suggestion? update_channel_monitor_without_completion_handling?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or perhaps use the removed macro name handle_new_monitor_update_locked_actions_handled_by_caller ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going with handle_new_monitor_update_locked_actions_handled_by_caller, to also address @valentinewallace 's concern #4291 (comment)


/// Processes monitor update completion data after locks have been released.
/// Call this after dropping peer_state_lock and per_peer_state locks.
fn handle_monitor_update_completion_data(&self, data: MonitorUpdateCompletionData) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please debug-assert locks not held.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

);

/// Data extracted from a channel while locks are held, to be processed after locks are released.
enum MonitorUpdateCompletionData {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a #[must_use]

Copy link
Contributor

@valentinewallace valentinewallace left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really nice code navigation improvement

Comment on lines -3344 to -3511
/// Useful because monitor updates need to be handled in the same mutex where the channel generated
/// them (otherwise they can end up getting applied out-of-order) but it's not always possible to
/// drop the aforementioned peer state locks at a given callsite. In this situation, use this macro
/// to apply the monitor update immediately and handle the monitor update completion actions at a
/// later time.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should keep these docs around somewhere

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved part of this to update_channel_monitor.

enum MonitorUpdateCompletionData {
/// Channel has blocked monitor updates pending. Only process update actions.
Blocked { update_actions: Vec<MonitorUpdateCompletionAction> },
/// Channel is fully unblocked and can be resumed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The below fields get returned if the channel is successfully resumed, so this doesn't seem accurate to me

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both comments updated.

@joostjager joostjager force-pushed the update-handling-refactor branch from abdbf82 to 1bb7c18 Compare January 13, 2026 09:37
@joostjager
Copy link
Contributor Author

joostjager commented Jan 13, 2026

Comments addressed. Not a fun job with the split into commits. diff

joostjager and others added 7 commits January 13, 2026 10:39
Pure code move except for the context logger which is now instantiated
when needed in update_channel_monitor.
Extract the monitor update completion logic from the
handle_monitor_update_completion macro into two new helper methods:

- try_resume_channel_post_monitor_update: Attempts to resume a channel
  after a monitor update completes while locks are still held

- handle_post_monitor_update_chan_resume: Completes channel resumption
  after locks have been released

This refactoring improves code organization by separating the locked
phase (which may resume the channel) from the unlocked phase (which
processes remaining work). The macro is now a thin wrapper that calls
these two methods with proper lock management.

The new PostMonitorUpdateChanResume enum captures the result of the
resume attempt, containing any remaining work to process after locks
are released.
Expand the macro at its three call sites and remove the macro
definition, as it no longer provides significant abstraction benefit
after refactoring the core logic into helper methods.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Convert the handle_initial_monitor! macro to a method that returns
optional completion data, allowing callers to release locks before
processing the completion.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Convert the handle_post_close_monitor_update! macro to a method that
returns optional completion actions, allowing callers to release locks
before processing the completion.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Convert the handle_new_monitor_update macro to methods and update all
call sites. Adds handle_new_monitor_update and
handle_new_monitor_update_with_status methods that return completion
data for processing after locks are released.

Also removes handle_monitor_update_completion macro as it's no longer
needed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Copy link
Contributor

@valentinewallace valentinewallace left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really liking this change.

I think some of the methods could be reordered (like, start with higher level ones handle_initial_monitor_update -> handle_new_update -> handle_post_close_update, with the more internal-only ones below). But not gonna hold this up, I think it's a strict improvement as-is

@@ -14767,12 +14993,12 @@ where
insert_short_channel_id!(short_to_chan_info, funded_channel);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I question whether we're losing something by removing the locked_actions_handled_by_caller part of the name. But also, I don't even see the actions being handled at some of these callsites, so not sure I have full context here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed update_channel_monitor to the old name

Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This takes cargo rustc --profile=test --lib -- -Zunpretty=expanded from 479,448 LoC to 478,346 LoC. Honestly I was hoping it'd be much more :(

if let Some((_, funding_txo, _, update)) = shutdown_res.monitor_update.take() {
handle_new_monitor_update_locked_actions_handled_by_caller!(
self,
self.handle_new_monitor_update_internal(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update_channel_monitor absolutely doesn't capture the "this function is weird, you probably shouldn't use it, its only for cases where you have to handle the post-update stuff manually for some specific reason". We're gonna screw this up in the future and someone is gonna use update_channel_monitor thinking its just a normal method to call when they need to update the channel monitor and no one is gonna catch it in review.

…ions_handled_by_caller

The previous name didn't capture that this function is unusual and
requires the caller to handle post-update actions manually. The new
name makes it clear that callers are responsible for handling locked
actions themselves, reducing the risk of misuse.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@joostjager
Copy link
Contributor Author

@TheBlueMatt pushed rename in a separate commit. Didn't want to go through the whole commit stack with its macros once again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

4 participants