Skip to content

Commit 075a2e3

Browse files
committed
Make PaymentFailureReason downgradable
The PaymentFailureReason variants for invoice request failures will cause downgrades to break. Instead, use a new TLV for the reason and continue to write the old TLV, only use None for the new reasons.
1 parent bb94320 commit 075a2e3

File tree

2 files changed

+41
-4
lines changed

2 files changed

+41
-4
lines changed

lightning/src/events/mod.rs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,12 @@ impl_writeable_tlv_based_enum!(InterceptNextHop,
502502
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
503503
pub enum PaymentFailureReason {
504504
/// The intended recipient rejected our payment.
505+
///
506+
/// Also used for [`UnknownRequiredFeatures`] and [`InvoiceRequestRejected`] when downgrading to
507+
/// version prior to 0.0.124.
508+
///
509+
/// [`UnknownRequiredFeatures`]: Self::UnknownRequiredFeatures
510+
/// [`InvoiceRequestRejected`]: Self::InvoiceRequestRejected
505511
RecipientRejected,
506512
/// The user chose to abandon this payment by calling [`ChannelManager::abandon_payment`].
507513
///
@@ -517,7 +523,10 @@ pub enum PaymentFailureReason {
517523
/// The payment expired while retrying, based on the provided
518524
/// [`PaymentParameters::expiry_time`].
519525
///
526+
/// Also used for [`InvoiceRequestExpired`] when downgrading to version prior to 0.0.124.
527+
///
520528
/// [`PaymentParameters::expiry_time`]: crate::routing::router::PaymentParameters::expiry_time
529+
/// [`InvoiceRequestExpired`]: Self::InvoiceRequestExpired
521530
PaymentExpired,
522531
/// We failed to find a route while retrying the payment.
523532
///
@@ -878,8 +887,8 @@ pub enum Event {
878887
/// [`Offer`]: crate::offers::offer::Offer
879888
payment_hash: Option<PaymentHash>,
880889
/// The reason the payment failed. This is only `None` for events generated or serialized
881-
/// by versions prior to 0.0.115, or when downgrading to 0.0.124 or later with a reason that
882-
/// was added after.
890+
/// by versions prior to 0.0.115, or when downgrading to a version with a reason that was
891+
/// added after.
883892
reason: Option<PaymentFailureReason>,
884893
},
885894
/// Indicates that a path for an outbound payment was successful.
@@ -1554,11 +1563,30 @@ impl Writeable for Event {
15541563
Some(payment_hash) => (payment_hash, true),
15551564
None => (&PaymentHash([0; 32]), false),
15561565
};
1566+
let legacy_reason = match reason {
1567+
None => &None,
1568+
// Variants available prior to version 0.0.124.
1569+
Some(PaymentFailureReason::RecipientRejected)
1570+
| Some(PaymentFailureReason::UserAbandoned)
1571+
| Some(PaymentFailureReason::RetriesExhausted)
1572+
| Some(PaymentFailureReason::PaymentExpired)
1573+
| Some(PaymentFailureReason::RouteNotFound)
1574+
| Some(PaymentFailureReason::UnexpectedError) => reason,
1575+
// Variants introduced at version 0.0.124 or later. Prior versions fail to parse
1576+
// unknown variants, while versions 0.0.124 or later will use None.
1577+
Some(PaymentFailureReason::UnknownRequiredFeatures) =>
1578+
&Some(PaymentFailureReason::RecipientRejected),
1579+
Some(PaymentFailureReason::InvoiceRequestExpired) =>
1580+
&Some(PaymentFailureReason::RetriesExhausted),
1581+
Some(PaymentFailureReason::InvoiceRequestRejected) =>
1582+
&Some(PaymentFailureReason::RecipientRejected),
1583+
};
15571584
write_tlv_fields!(writer, {
15581585
(0, payment_id, required),
1559-
(1, reason, option),
1586+
(1, legacy_reason, option),
15601587
(2, payment_hash, required),
15611588
(3, invoice_received, required),
1589+
(5, reason, option),
15621590
})
15631591
},
15641592
&Event::OpenChannelRequest { .. } => {
@@ -1926,17 +1954,20 @@ impl MaybeReadable for Event {
19261954
let mut payment_hash = PaymentHash([0; 32]);
19271955
let mut payment_id = PaymentId([0; 32]);
19281956
let mut reason = None;
1957+
let mut legacy_reason = None;
19291958
let mut invoice_received: Option<bool> = None;
19301959
read_tlv_fields!(reader, {
19311960
(0, payment_id, required),
1932-
(1, reason, upgradable_option),
1961+
(1, legacy_reason, upgradable_option),
19331962
(2, payment_hash, required),
19341963
(3, invoice_received, option),
1964+
(5, reason, upgradable_option),
19351965
});
19361966
let payment_hash = match invoice_received {
19371967
Some(invoice_received) => invoice_received.then(|| payment_hash),
19381968
None => (payment_hash != PaymentHash([0; 32])).then(|| payment_hash),
19391969
};
1970+
let reason = reason.or(legacy_reason);
19401971
Ok(Some(Event::PaymentFailed {
19411972
payment_id,
19421973
payment_hash,

pending_changelog/3192-invoice-request-failed-event.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,9 @@
1010
* Any `Event::PaymentFailed` generated without a payment hash will deserialize
1111
with `PaymentHash([0; 32])` when downgrading. This can be treated like an
1212
`Event::InvoiceRequestFailed` (#3192).
13+
* An `Event::PaymentFailed` generated with one of the following
14+
`PaymentFailureReason`s will deserialize with the corresponding reason after
15+
downgrading to a version prior to 0.0.124:
16+
- `UnknownRequiredFeatures` to `RecipientRejected`,
17+
- `InvoiceRequestExpired` to `RetriesExhausted`, and
18+
- `InvoiceRequestRejected` to `RecipientRejected` (#3192).

0 commit comments

Comments
 (0)