Ignore late failures for successful payments - #1065
thesimplekid wants to merge 3 commits into
Conversation
|
I've assigned @tnull as a reviewer! |
| @@ -1477,6 +1470,32 @@ where | |||
| }, | |||
| }; | |||
|
|
|||
| // LDK may emit `PaymentFailed` after `PaymentSent` in exceedingly rare cases. | |||
| // The payment-store update above preserves success in that case; re-read the | |||
| // resulting state so we also avoid surfacing a contradictory public event. | |||
| match self.payment_store.get(&payment_id).await { | |||
| Ok(Some(payment)) if payment.status == PaymentStatus::Succeeded => { | |||
| log_info!( | |||
| self.logger, | |||
| "Ignoring late payment failure for already-succeeded payment with ID {}.", | |||
| payment_id | |||
| ); | |||
| return Ok(()); | |||
| }, | |||
| Ok(_) => {}, | |||
| Err(e) => { | |||
| log_error!(self.logger, "Failed to access payment store: {}", e); | |||
| return Err(ReplayEvent()); | |||
| }, | |||
| } | |||
|
|
|||
| log_info!( | |||
| self.logger, | |||
| "Failed to send payment with ID {} due to {:?}.", | |||
| payment_id, | |||
| reason | |||
| ); | |||
|
|
|||
| let event = Event::PaymentFailed { payment_id, payment_hash, reason }; | |||
| match self.event_queue.add_event(event).await { | |||
| Ok(_) => return Ok(()), | |||
There was a problem hiding this comment.
This is again related to the split-brain situation with persistence, but can the initial payment store write fail after LDK accepts the payment? PaymentSent then accepts Ok(NotFound) and emits success, so a replayed late failure could escape this check after restart.
rust-lightning documents that PaymentFailed can arrive after PaymentSent in rare cases. In that ordering, the failure must be ignored and the payment must be treated as successful: https://github.com/lightningdevkit/rust-lightning/blob/9174965af9437196c527a9aa0df36bbcf050c8bb/lightning/src/events/mod.rs#L1230-L1233 Keep succeeded outbound Lightning records monotonic and suppress the contradictory user-facing PaymentFailed event. Cover both BOLT11 and BOLT12 on the persistence-backed store path. Developed with assistance from OpenAI Codex.
Move the late-failure guard from payment-store updates into the event handler. Use mutate to preserve the entire succeeded Lightning payment and suppress its failure event without a second store lookup. Keep failure notifications for unchanged or missing records so replay still delivers the event. Cover BOLT11 and BOLT12 metadata preservation and notifications for pending, already-failed, and missing payments. Developed with assistance from OpenAI Codex.
4df77f4 to
8cf15f2
Compare
Move late-failure handling into the PaymentFailed match arm to match the existing event-handler structure. Restore the original event-queue error handling and remove the helper-dependent tests as requested in review. Remove leftover status and preimage changes from the payment-store test. Developed with assistance from OpenAI Codex.
tnull
left a comment
There was a problem hiding this comment.
Please squash, one minor comment though.
| // LDK may emit PaymentFailed after PaymentSent. Ignore the entire late | ||
| // failure so it cannot alter payment metadata or emit a contradictory event. | ||
| if current.direction == PaymentDirection::Outbound | ||
| && !matches!(current.kind, PaymentKind::Onchain { .. }) |
There was a problem hiding this comment.
Hmm, going forward we might add additional variants to PaymentKind, so matching by negation like this is a footgun. Let's add a prefactor commit that adds PaymentKind::is_lightning_payment or similar that matches on the Lightning variants. Then use it here.
rust-lightning documents that PaymentFailed can arrive after PaymentSent in rare cases. In that ordering, the failure must be ignored and the payment must be treated as successful:
https://github.com/lightningdevkit/rust-lightning/blob/9174965af9437196c527a9aa0df36bbcf050c8bb/lightning/src/events/mod.rs#L1230-L1233
Keep succeeded outbound Lightning records monotonic and suppress the contradictory user-facing PaymentFailed event. Cover both BOLT11 and BOLT12 on the persistence-backed store path.
Developed with assistance from OpenAI Codex.