Skip to content

Commit e09b191

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 5cc5c5d commit e09b191

File tree

2 files changed

+41
-4
lines changed

2 files changed

+41
-4
lines changed

lightning/src/events/mod.rs

+35-4
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
///
@@ -879,8 +888,8 @@ pub enum Event {
879888
payment_hash: Option<PaymentHash>,
880889
/// The reason the payment failed. This is only `None` for events generated or serialized
881890
/// by versions prior to 0.0.115, when deserializing an `Event::InvoiceRequestFailed` (which
882-
/// was removed in 0.0.124), or when downgrading to 0.0.124 or later with a reason that was
883-
/// added after.
891+
/// was removed in 0.0.124), or when downgrading to a version with a reason that was added
892+
/// after.
884893
reason: Option<PaymentFailureReason>,
885894
},
886895
/// Indicates that a path for an outbound payment was successful.
@@ -1555,11 +1564,30 @@ impl Writeable for Event {
15551564
Some(payment_hash) => (payment_hash, true),
15561565
None => (&PaymentHash([0; 32]), false),
15571566
};
1567+
let legacy_reason = match reason {
1568+
None => &None,
1569+
// Variants available prior to version 0.0.124.
1570+
Some(PaymentFailureReason::RecipientRejected)
1571+
| Some(PaymentFailureReason::UserAbandoned)
1572+
| Some(PaymentFailureReason::RetriesExhausted)
1573+
| Some(PaymentFailureReason::PaymentExpired)
1574+
| Some(PaymentFailureReason::RouteNotFound)
1575+
| Some(PaymentFailureReason::UnexpectedError) => reason,
1576+
// Variants introduced at version 0.0.124 or later. Prior versions fail to parse
1577+
// unknown variants, while versions 0.0.124 or later will use None.
1578+
Some(PaymentFailureReason::UnknownRequiredFeatures) =>
1579+
&Some(PaymentFailureReason::RecipientRejected),
1580+
Some(PaymentFailureReason::InvoiceRequestExpired) =>
1581+
&Some(PaymentFailureReason::RetriesExhausted),
1582+
Some(PaymentFailureReason::InvoiceRequestRejected) =>
1583+
&Some(PaymentFailureReason::RecipientRejected),
1584+
};
15581585
write_tlv_fields!(writer, {
15591586
(0, payment_id, required),
1560-
(1, reason, option),
1587+
(1, legacy_reason, option),
15611588
(2, payment_hash, required),
15621589
(3, invoice_received, required),
1590+
(5, reason, option),
15631591
})
15641592
},
15651593
&Event::OpenChannelRequest { .. } => {
@@ -1927,17 +1955,20 @@ impl MaybeReadable for Event {
19271955
let mut payment_hash = PaymentHash([0; 32]);
19281956
let mut payment_id = PaymentId([0; 32]);
19291957
let mut reason = None;
1958+
let mut legacy_reason = None;
19301959
let mut invoice_received: Option<bool> = None;
19311960
read_tlv_fields!(reader, {
19321961
(0, payment_id, required),
1933-
(1, reason, upgradable_option),
1962+
(1, legacy_reason, upgradable_option),
19341963
(2, payment_hash, required),
19351964
(3, invoice_received, option),
1965+
(5, reason, upgradable_option),
19361966
});
19371967
let payment_hash = match invoice_received {
19381968
Some(invoice_received) => invoice_received.then(|| payment_hash),
19391969
None => (payment_hash != PaymentHash([0; 32])).then(|| payment_hash),
19401970
};
1971+
let reason = reason.or(legacy_reason);
19411972
Ok(Some(Event::PaymentFailed {
19421973
payment_id,
19431974
payment_hash,

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

+6
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)