Skip to content

Commit 3f34ded

Browse files
committed
Don't abandon payments for duplicate invoices
When making an outbound BOLT12 payment, multiple invoices may be received for the same payment id. Instead of abandoning the payment when a duplicate invoice received, simply ignore it without responding with an InvoiceError. This prevents abandoning in-progress payments and sending unnecessary onion messages.
1 parent 20b8704 commit 3f34ded

File tree

2 files changed

+48
-45
lines changed

2 files changed

+48
-45
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10846,43 +10846,51 @@ where
1084610846
&self.logger, None, None, Some(invoice.payment_hash()),
1084710847
);
1084810848

10849-
let result = {
10850-
let features = self.bolt12_invoice_features();
10851-
if invoice.invoice_features().requires_unknown_bits_from(&features) {
10852-
Err(InvoiceError::from(Bolt12SemanticError::UnknownRequiredFeatures))
10853-
} else if self.default_configuration.manually_handle_bolt12_invoices {
10854-
let event = Event::InvoiceReceived {
10855-
payment_id, invoice, context, responder,
10856-
};
10857-
self.pending_events.lock().unwrap().push_back((event, None));
10858-
return ResponseInstruction::NoResponse;
10859-
} else {
10860-
self.send_payment_for_verified_bolt12_invoice(&invoice, payment_id)
10861-
.map_err(|e| {
10862-
log_trace!(logger, "Failed paying invoice: {:?}", e);
10863-
InvoiceError::from_string(format!("{:?}", e))
10864-
})
10865-
}
10866-
};
10849+
let features = self.bolt12_invoice_features();
10850+
if invoice.invoice_features().requires_unknown_bits_from(&features) {
10851+
log_trace!(
10852+
logger, "Invoice requires unknown features: {:?}",
10853+
invoice.invoice_features(),
10854+
);
10855+
abandon_if_payment(context);
1086710856

10868-
match result {
10869-
Ok(_) => ResponseInstruction::NoResponse,
10870-
Err(err) => match responder {
10871-
Some(responder) => {
10872-
abandon_if_payment(context);
10873-
responder.respond(OffersMessage::InvoiceError(err))
10874-
},
10857+
let error = InvoiceError::from(Bolt12SemanticError::UnknownRequiredFeatures);
10858+
let response = match responder {
10859+
Some(responder) => responder.respond(OffersMessage::InvoiceError(error)),
1087510860
None => {
10876-
abandon_if_payment(context);
10877-
log_trace!(
10878-
logger,
10879-
"An error response was generated, but there is no reply_path specified \
10880-
for sending the response. Error: {}",
10881-
err
10882-
);
10883-
return ResponseInstruction::NoResponse;
10861+
log_trace!(logger, "No reply path to send error: {:?}", error);
10862+
ResponseInstruction::NoResponse
1088410863
},
10864+
};
10865+
return response;
10866+
}
10867+
10868+
if self.default_configuration.manually_handle_bolt12_invoices {
10869+
let event = Event::InvoiceReceived {
10870+
payment_id, invoice, context, responder,
10871+
};
10872+
self.pending_events.lock().unwrap().push_back((event, None));
10873+
return ResponseInstruction::NoResponse;
10874+
}
10875+
10876+
match self.send_payment_for_verified_bolt12_invoice(&invoice, payment_id) {
10877+
// Payments with SendingFailed error will already have been abandoned.
10878+
Err(Bolt12PaymentError::SendingFailed(e)) => {
10879+
log_trace!(logger, "Failed paying invoice: {:?}", e);
10880+
10881+
let err = InvoiceError::from_string(format!("{:?}", e));
10882+
match responder {
10883+
Some(responder) => responder.respond(OffersMessage::InvoiceError(err)),
10884+
None => {
10885+
log_trace!(logger, "No reply path to send error: {:?}", err);
10886+
ResponseInstruction::NoResponse
10887+
},
10888+
}
1088510889
},
10890+
// Otherwise, don't abandon unknown, pending, or successful payments.
10891+
Err(Bolt12PaymentError::UnexpectedInvoice)
10892+
| Err(Bolt12PaymentError::DuplicateInvoice)
10893+
| Ok(()) => ResponseInstruction::NoResponse,
1088610894
}
1088710895
},
1088810896
#[cfg(async_payments)]

lightning/src/ln/offers_tests.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2027,16 +2027,13 @@ fn fails_paying_invoice_more_than_once() {
20272027
let onion_message = charlie.onion_messenger.next_onion_message_for_peer(david_id).unwrap();
20282028
david.onion_messenger.handle_onion_message(&charlie_id, &onion_message);
20292029

2030-
// David pays the first invoice
2030+
// David initiates paying the first invoice
20312031
let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext {});
20322032
let (invoice1, _) = extract_invoice(david, &onion_message);
20332033

20342034
route_bolt12_payment(david, &[charlie, bob, alice], &invoice1);
20352035
expect_recent_payment!(david, RecentPaymentDetails::Pending, payment_id);
20362036

2037-
claim_bolt12_payment(david, &[charlie, bob, alice], payment_context);
2038-
expect_recent_payment!(david, RecentPaymentDetails::Fulfilled, payment_id);
2039-
20402037
disconnect_peers(alice, &[charlie]);
20412038

20422039
// Alice sends the second invoice
@@ -2054,13 +2051,11 @@ fn fails_paying_invoice_more_than_once() {
20542051
let (invoice2, _) = extract_invoice(david, &onion_message);
20552052
assert_eq!(invoice1.payer_metadata(), invoice2.payer_metadata());
20562053

2057-
// David sends an error instead of paying the second invoice
2058-
let onion_message = david.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
2059-
bob.onion_messenger.handle_onion_message(&david_id, &onion_message);
2060-
2061-
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
2062-
alice.onion_messenger.handle_onion_message(&bob_id, &onion_message);
2054+
// David doesn't initiate paying the second invoice
2055+
assert!(david.onion_messenger.next_onion_message_for_peer(bob_id).is_none());
2056+
assert!(david.node.get_and_clear_pending_msg_events().is_empty());
20632057

2064-
let invoice_error = extract_invoice_error(alice, &onion_message);
2065-
assert_eq!(invoice_error, InvoiceError::from_string("DuplicateInvoice".to_string()));
2058+
// Complete paying the first invoice
2059+
claim_bolt12_payment(david, &[charlie, bob, alice], payment_context);
2060+
expect_recent_payment!(david, RecentPaymentDetails::Fulfilled, payment_id);
20662061
}

0 commit comments

Comments
 (0)