Skip to content

Conversation

@joostjager
Copy link
Contributor

@joostjager joostjager commented Jan 26, 2026

This PR changes ChainMonitor to defer monitor operations by queuing them in watch_channel and update_channel instead of immediately persisting. The actual persistence happens when the new flush() method is called. This enables correct persistence ordering where the ChannelManager is always persisted before its associated monitor updates, ensuring that on restart the manager state is never ahead of the monitor state. The background processor is updated to capture the pending operation count before persisting the ChannelManager, then flush only those operations afterward.

This commit changes `ChainMonitor` to queue monitor operations instead of
applying them immediately. When `watch_channel` or `update_channel` is
called, the operation is added to a pending queue and
`ChannelMonitorUpdateStatus::InProgress` is returned. The actual monitor
insertion/update and persistence happens when `flush()` is called.

This enables proper ordering of persistence: the `ChannelManager` can be
persisted first, then `flush()` is called to persist the monitors. This
ensures that on restart, the `ChannelManager` state is never ahead of the
monitor state.

The background processor is updated to:
1. Capture `pending_monitor_operation_count()` before persisting ChannelManager
2. After ChannelManager persistence completes, call `flush()` with that count
3. On shutdown, flush all remaining pending operations after final persistence

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ldk-reviews-bot
Copy link

👋 Hi! I see this is a draft PR.
I'll wait to assign reviewers until you mark it as ready for review.
Just convert it out of draft status when you're ready for review!

@joostjager joostjager changed the title Chain mon deferred writes Defer ChainMonitor updates and persistence to flush() Jan 26, 2026
Move the deferred persistence logic from ChainMonitor into a separate
DeferredChainMonitor wrapper type. This keeps ChainMonitor focused on
its core responsibilities while the wrapper handles the queuing of
monitor operations and their batched persistence via flush().

The wrapper intercepts watch_channel and update_channel calls, queues
them, and returns InProgress. When flush() is called, it processes the
queued operations and persists them in the correct order after
ChannelManager persistence.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@joostjager
Copy link
Contributor Author

Added a DeferredChainMonitor wrapper instead of modifying ChainMonitor directly. The wrapper intercepts watch_channel and update_channel calls, queues them, and returns InProgress. When flush is called, it processes the queued operations and persists them in the correct order after ChannelManager persistence. This approach keeps ChainMonitor unchanged so that existing tests which expect synchronous behavior continue to work without modification. Only the background processor and production code paths use the deferred wrapper while the test suite can keep using ChainMonitor directly.

joostjager and others added 3 commits January 26, 2026 12:37
Tests that DeferredChainMonitor properly defers watch_channel and
update_channel operations until flush() is called, using real
ChannelManagers and a complete channel open + payment flow between
two nodes both using DeferredChainMonitor.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This adds a new generic parameter M to DeferredChainMonitor that allows
passing any type implementing Deref to ChainMonitor, such as Arc or
references, rather than requiring ownership of the ChainMonitor.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Introduce DeferredPersistence trait that abstracts the deferred
persistence methods (pending_operation_count, flush). This allows
process_events_async to accept any chain monitor wrapper that
implements the trait, rather than being constrained to
DeferredChainMonitor<..., Arc<ChainMonitor<...>>>.

The relaxed bounds enable using DeferredChainMonitor with inner
monitor types other than Arc<ChainMonitor>, resolving lifetime
issues that could occur with non-Arc wrapper types.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants