Skip to content

Commit fc57737

Browse files
committed
Avoid repeated refreshes for persisted async invoices
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
1 parent c9260ee commit fc57737

2 files changed

Lines changed: 20 additions & 1 deletion

File tree

lightning/src/ln/async_payments_tests.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2450,6 +2450,25 @@ fn refresh_static_invoices_for_used_offers() {
24502450
.handle_onion_message(server.node.get_our_node_id(), &invoice_persisted_om);
24512451
assert_eq!(recipient.node.flow.test_get_async_receive_offers().len(), 1);
24522452

2453+
// The invoice was just refreshed and persisted. A later timer tick must wait until the next
2454+
// refresh threshold before generating another invoice for the same offer.
2455+
recipient.node.timer_tick_occurred();
2456+
let pending_oms_after = recipient.onion_messenger.release_pending_msgs();
2457+
let mut extra_serve_invoices = 0;
2458+
if let Some(msgs) = pending_oms_after.get(&server.node.get_our_node_id()) {
2459+
for msg in msgs {
2460+
if let PeeledOnion::AsyncPayments(AsyncPaymentsMessage::ServeStaticInvoice(_), _, _) =
2461+
server.onion_messenger.peel_onion_message(&msg).unwrap()
2462+
{
2463+
extra_serve_invoices += 1;
2464+
}
2465+
}
2466+
}
2467+
assert_eq!(
2468+
extra_serve_invoices, 0,
2469+
"used offer invoice was refreshed again immediately after a successful refresh"
2470+
);
2471+
24532472
// Remove the peer restriction added above.
24542473
server.message_router.peers_override.lock().unwrap().clear();
24552474
recipient.message_router.peers_override.lock().unwrap().clear();

lightning/src/offers/async_receive_offer_cache.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ impl AsyncReceiveOfferCache {
491491
match offer.status {
492492
OfferStatus::Used { invoice_created_at: ref mut inv_created_at }
493493
| OfferStatus::Ready { invoice_created_at: ref mut inv_created_at } => {
494-
*inv_created_at = core::cmp::min(invoice_created_at, *inv_created_at);
494+
*inv_created_at = core::cmp::max(invoice_created_at, *inv_created_at);
495495
},
496496
OfferStatus::Pending => offer.status = OfferStatus::Ready { invoice_created_at },
497497
}

0 commit comments

Comments
 (0)