You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix unified payment falling back to on-chain after PersistenceFailed
In `UnifiedPayment::send`, the BOLT11 leg's `bolt11_invoice.send` only
returns `Err(PersistenceFailed)` *after* `pay_for_bolt11_invoice` has
already succeeded and the Lightning payment is in-flight. The previous
match treated every error (via `Err(e)`) as a fall-through to the next
payment method, so a persistence failure after initiation would
broadcast an on-chain transaction for the same URI — a duplicate
payment.
We now treat `Err(Error::PersistenceFailed)` on the BOLT11 leg as
terminal, mirroring how `DuplicatePayment` is already handled, and abort
the unified payment instead of falling back to on-chain.
This is a regression hazard raised during review of the #1033 fix
(PR #1038). It is pre-existing and orthogonal to #1033 (which only made
`DuplicatePayment` terminal); tracked separately as the unified variant
of the broader post-commit persistence hazard.
Adds `unified_send_bolt11_persistence_failure_no_onchain_fallback`, which
arms a failing payment-store write on a `KVStore`-backed node and asserts
that `send` returns `PersistenceFailed` without recording any on-chain
payment.
Co-Authored-By: Claude <noreply@anthropic.com>
// A duplicate payment already exists, so falling back to the
327
+
// on-chain method would pay the same invoice a second time.
326
328
Err(Error::DuplicatePayment) => {
327
329
log_error!(self.logger,"Failed to send BOLT11 invoice: DuplicatePayment. This is part of a unified payment. Aborting to avoid duplicate payment.");
328
330
returnErr(Error::DuplicatePayment);
329
331
},
332
+
// A persistence failure may occur after the Lightning payment has
333
+
// already been initiated with the ChannelManager. Falling back to
334
+
// the on-chain method in that case would double-pay, so we abort
335
+
// instead of proceeding to the next payment method.
336
+
Err(Error::PersistenceFailed) => {
337
+
log_error!(self.logger,"Failed to send BOLT11 invoice: PersistenceFailed. This is part of a unified payment. Aborting to avoid a potential duplicate payment.");
338
+
returnErr(Error::PersistenceFailed);
339
+
},
330
340
Err(e) => {
331
341
log_error!(self.logger,"Failed to send BOLT11 invoice: {:?}. This is part of a unified payment. Falling back to the on-chain transaction.", e);
0 commit comments