-
Notifications
You must be signed in to change notification settings - Fork 402
Add idempotency check to prevent duplicate InvoiceReceived
events
#3658
New issue
Have a question about this project? No Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “No Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? No Sign in to your account
Conversation
👋 Thanks for assigning @jkczyz as a reviewer! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it seems send_payment_for_bolt12_invoice is not idempotent either so this would effect everyone using manually_handle_bolt12_invoices
Hi Ben! AFAIU, send_payment_for_bolt12_invoice
does seem idempotent, as in, it won’t allow paying the same invoice twice (see this link).
Let me know if I’m misunderstanding the issue or if there’s still a potential problem here that I might be missing. Thanks!
👋 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. |
@TheBlueMatt Is the following line still correct after this change?
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I believe that specific logic is still fine.
lightning/src/ln/outbound_payment.rs
Outdated
if !with_manual_handling { self.mark_invoice_received(payment_id, payment_hash)? } | ||
|
||
let (retry_strategy, params_config) = self.received_invoice_details(payment_id)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we avoid taking the lock twice here when with_manual_handling
is false?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the pointer, Jeff!
I’ve updated the mark_invoice_received
function to also return the retry
and route_params
, so we can avoid taking the lock twice in pr3658.04
.
Let me know if this looks good — thanks again!
lightning/src/ln/outbound_payment.rs
Outdated
fn received_invoice_details( | ||
&self, payment_id: PaymentId, | ||
) -> Result<(Retry, RouteParametersConfig), Bolt12PaymentError> { | ||
match self.pending_outbound_payments.lock().unwrap().entry(payment_id) { | ||
hash_map::Entry::Occupied(entry) => match entry.get() { | ||
PendingOutboundPayment::InvoiceReceived { | ||
retry_strategy, route_params_config, .. | ||
} => { | ||
return Ok((*retry_strategy, *route_params_config)) | ||
}, | ||
_ => return Err(Bolt12PaymentError::DuplicateInvoice), | ||
}, | ||
hash_map::Entry::Vacant(_) => return Err(Bolt12PaymentError::UnexpectedInvoice), | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably can re-inline this to avoid taking the lock again.
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #3658 +/- ##
==========================================
+ Coverage 89.21% 91.47% +2.26%
==========================================
Files 155 157 +2
Lines 118966 145966 +27000
Branches 118966 145966 +27000
==========================================
+ Hits 106133 133525 +27392
+ Misses 10253 9985 -268
+ Partials 2580 2456 -124 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Just some small changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Updated from pr3658.06 to pr3658.07 (diff): Changes:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes LGTM!
Ensures `InvoiceReceived` events are not generated multiple times when `manually_handle_bolt12_invoice` is enabled. Duplicate events for the same invoice could cause confusion—this change introduces an idempotency check to prevent that.
Updated from pr3658.07 to pr3658.08 (diff): Changes:
|
Backported in #3757 |
v0.1.3 - Apr 30, 2025 - "Routing Unicode in 2025" Bug Fixes ========= * `Event::InvoiceReceived` is now only generated once for each `Bolt12Invoice` received matching a pending outbound payment. Previously it would be provided each time we received an invoice, which may happen many times if the sender sends redundant messages to improve success rates (lightningdevkit#3658). * LDK's router now more fully saturates paths which are subject to HTLC maximum restrictions after the first hop. In some rare cases this can result in finding paths when it would previously spuriously decide it cannot find enough diverse paths (lightningdevkit#3707, lightningdevkit#3755). Security ======== 0.1.3 fixes a denial-of-service vulnerability which cause a crash of an LDK-based node if an attacker has access to a valid `Bolt12Offer` which the LDK-based node created. * A malicious payer which requests a BOLT 12 Invoice from an LDK-based node (via the `Bolt12InvoiceRequest` message) can cause the panic of the LDK-based node due to the way `String::truncate` handles UTF-8 codepoints. The codepath can only be reached once the received `Botlt12InvoiceRequest` has been authenticated to be based on a valid `Bolt12Offer` which the same LDK-based node issued (lightningdevkit#3747, lightningdevkit#3750).
Solves #3653
When
manually_handle_bolt12_invoice
is enabled, we shouldn’t emit multipleInvoiceReceived
events for the same invoice — it can be confusing and misleading for consumers of the event stream.This PR adds a simple idempotency check to make sure we only emit the event once per invoice.
Also added a test to make sure this behavior stays in place going forward.