Skip to content

Refresh async static invoices after channel changes#13

Open
shaavan wants to merge 4 commits into
mainfrom
static-update-review
Open

Refresh async static invoices after channel changes#13
shaavan wants to merge 4 commits into
mainfrom
static-update-review

Conversation

@shaavan

@shaavan shaavan commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Refresh async receive static invoices when local channel state changes, so
already-published async offers do not keep serving stale payment paths until the
normal refresh threshold.

This adds a forced refresh path for cached async receive offers:

  • selects used and pending offers for immediate static invoice refresh
  • reuses the existing static invoice construction flow
  • marks refresh needed when channels become ready, close, or local fee updates
    are queued
  • defers the actual refresh until after channel locks are released

Ready unused offers are left to the existing offer rotation path because they
have not been returned to the application yet.

Summary by CodeRabbit

  • New Features

    • Async receive offer static-invoice refresh now supports both timer-based and forced refresh flows when channel conditions change.
    • Channel readiness and channel lifecycle events can trigger refreshed static invoice generation, including for offers already marked used.
  • Bug Fixes

    • Deferred refresh logic ensures cached static invoices are rebuilt only after relevant channel state updates complete.
    • Refresh selection now better targets offers needing immediate forced invoice updates after local channel changes.
  • Tests

    • Added coverage for refreshed static invoices when channels open and used-offer scenarios.

shaavan and others added 3 commits June 26, 2026 14:54
Async receive offers currently decide static invoice refreshes from
timer-based freshness only. Channel changes need a separate selector so
callers can rebuild server-side invoices without waiting for the normal age
threshold.

Add a cache helper that returns used and pending offers for forced invoice
refresh. Ready offers stay on the existing offer rotation path because they
have not been returned to the application yet.

AI-assisted: planning and writing commit

Co-Authored-By: OpenAI Codex <codex@openai.com>
The cache can now identify offers whose static invoices should be rebuilt
immediately, but callers still need one canonical path that turns those offers
into ServeStaticInvoice messages.

Thread a forced-refresh entry point through OffersMessageFlow and
ChannelManager while reusing the existing static invoice construction code.
This keeps the later channel-change behavior focused on deciding when to
refresh, not how to rebuild invoices.

AI-assisted: planning and writing commit

Co-Authored-By: OpenAI Codex <codex@openai.com>
Static invoices contain blinded payment paths built from the recipient's
current channels and fees. When channels become usable, close, or require a
local fee update, cached async receive offers can otherwise keep serving stale
payment instructions until the normal refresh threshold passes.

Mark those channel changes as requiring a forced async static invoice refresh,
then process the refresh after channel locks are released. The deferred flag
avoids rebuilding invoices while holding peer/channel locks, since invoice
rebuilding needs a fresh usable-channel snapshot.

AI-assisted: planning and writing commit

Co-Authored-By: OpenAI Codex <codex@openai.com>
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@shaavan, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 55 minutes and 53 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 23600034-c4bf-4642-88c0-a7fe9d96d4c5

📥 Commits

Reviewing files that changed from the base of the PR and between c7a7887 and 5f3f1f0.

📒 Files selected for processing (1)
  • lightning/src/ln/async_payments_tests.rs
📝 Walkthrough

Walkthrough

The PR adds forced async receive static-invoice refreshes on channel-state changes, coordinates pending refreshes in ChannelManager, and adds a test that verifies refreshed invoices after a new channel opens.

Changes

Async receive static invoice refresh

Layer / File(s) Summary
Forced refresh selection
lightning/src/offers/async_receive_offer_cache.rs, lightning/src/offers/flow.rs
OffersMessageFlow now distinguishes forced and timer-driven static-invoice refreshes and builds ServeStaticInvoice messages from the selected cached offers.
Pending refresh plumbing
lightning/src/ln/channelmanager.rs
ChannelManager adds an atomic pending-refresh flag, initializes it in construction paths, and adds helpers to trigger or process the forced refresh flow.
Channel-ready and fee triggers
lightning/src/ln/channelmanager.rs
Initial channel-ready emission and fee-update handling now mark static-invoice refreshes pending and process them after the state update.
Lifecycle and message triggers
lightning/src/ln/channelmanager.rs
Shutdown, close, splice, discarded-funding, and inbound channel message handlers now route pending static-invoice refresh processing after their internal handling.
Channel-open refresh test
lightning/src/ln/async_payments_tests.rs
A helper extracts pending ServeStaticInvoice onion messages, and a test verifies refreshed invoices are sent and persisted when a new channel opens.

Sequence Diagram(s)

sequenceDiagram
  participant ChannelManager
  participant OffersMessageFlow
  participant AsyncReceiveOfferCache
  participant Recipient
  participant StaticInvoiceServer
  ChannelManager->>OffersMessageFlow: process_pending_async_receive_static_invoice_refresh()
  OffersMessageFlow->>AsyncReceiveOfferCache: offers_needing_forced_invoice_refresh()
  OffersMessageFlow->>Recipient: ServeStaticInvoice
  Recipient->>StaticInvoiceServer: deliver ServeStaticInvoice
  StaticInvoiceServer->>StaticInvoiceServer: PersistStaticInvoice
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

A bunny hopped by channel light,
With invoices fresh and tails all bright.
Pending flags went boing, then clear,
New refreshes sprouted far and near.
Crunch, crunch — the static stars align 🐰

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: forcing async static invoice refreshes when channel state changes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch static-update-review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lightning/src/ln/async_payments_tests.rs`:
- Around line 433-434: The extractor in async_payments_tests should ignore
OfferPathsRequest instead of rejecting every message, since this refresh path
can queue a server-bound path request before ServeStaticInvoice. Update the call
to extract_expected_om to use a predicate that filters out
AsyncPaymentsMessage::OfferPathsRequest while still matching the expected
invoice-related message, so the test follows the same construction flow used
elsewhere in the file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f8f507a7-f4a9-48e0-8076-4e87cdb9b6eb

📥 Commits

Reviewing files that changed from the base of the PR and between 9df5c9d and a945650.

📒 Files selected for processing (4)
  • lightning/src/ln/async_payments_tests.rs
  • lightning/src/ln/channelmanager.rs
  • lightning/src/offers/async_receive_offer_cache.rs
  • lightning/src/offers/flow.rs

Comment thread lightning/src/ln/async_payments_tests.rs Outdated
@shaavan shaavan force-pushed the static-update-review branch from a945650 to c7a7887 Compare June 26, 2026 11:30
Used async receive offers may already be published by the application, so a
new usable channel should refresh the static invoice stored by the server
without waiting for the normal age threshold.

Add a focused async payments test that marks an offer used, opens another
channel to the static invoice server, and asserts that a replacement
ServeStaticInvoice is sent for the same server slot.

AI-assisted: planning and writing commit

Co-Authored-By: OpenAI Codex <codex@openai.com>
@shaavan shaavan force-pushed the static-update-review branch from c7a7887 to 5f3f1f0 Compare June 26, 2026 11:34
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.

1 participant