Skip to content

Avoid repeated refreshes for persisted async invoices#4672

Open
tnull wants to merge 1 commit into
lightningdevkit:mainfrom
tnull:2026-06-used-offer-invoice-refresh
Open

Avoid repeated refreshes for persisted async invoices#4672
tnull wants to merge 1 commit into
lightningdevkit:mainfrom
tnull:2026-06-used-offer-invoice-refresh

Conversation

@tnull

@tnull tnull commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

When a used async receive offer's refreshed static invoice is persisted, advance the recorded invoice creation time. This keeps the refresh threshold anchored to the newest invoice instead of making the offer look stale on every timer tick.

Add coverage that a used offer does not enqueue another ServeStaticInvoice immediately after the server confirms the refresh.

Co-Authored-By: HAL 9000

This finding was discovered by Project Loupe

When a used async receive offer's refreshed static invoice is persisted, advance the recorded invoice creation time. This keeps the refresh threshold anchored to the newest invoice instead of making the offer look stale on every timer tick.

Add coverage that a used offer does not enqueue another ServeStaticInvoice immediately after the server confirms the refresh.

Co-Authored-By: HAL 9000

This finding was discovered by Project Loupe
@tnull tnull requested a review from valentinewallace June 10, 2026 11:39
@ldk-reviews-bot

ldk-reviews-bot commented Jun 10, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @valentinewallace 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.

@ldk-claude-review-bot

Copy link
Copy Markdown
Collaborator

No issues found.

The PR is a correct one-line bug fix: changing core::cmp::min to core::cmp::max in static_invoice_persisted (async_receive_offer_cache.rs:494). This aligns with the documented semantics that invoice_created_at tracks the last (newest) invoice confirmed persisted by the server. The previous min kept the oldest timestamp, leaving used offers perpetually stale and triggering a ServeStaticInvoice refresh on every timer tick. max also correctly handles out-of-order StaticInvoicePersisted messages by never regressing the recorded time.

The added test correctly verifies no extra ServeStaticInvoice is enqueued on a timer tick immediately after a successful refresh.

No bugs, security issues, or logic errors detected.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants