Skip to content

Commit 84f200f

Browse files
Add PaymentContext for async payments
This context is stored in the blinded payment paths we put in static invoices and is useful to authenticate payments over these paths to the recipient. We can't reuse Bolt12OfferContext for this because we don't have access to the invoice request fields at static invoice creation time.
1 parent 542deeb commit 84f200f

File tree

3 files changed

+43
-10
lines changed

3 files changed

+43
-10
lines changed

lightning/src/blinded_path/payment.rs

+22
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,11 @@ pub enum PaymentContext {
349349
/// [`Offer`]: crate::offers::offer::Offer
350350
Bolt12Offer(Bolt12OfferContext),
351351

352+
/// The payment was made for a static invoice requested from a BOLT 12 [`Offer`].
353+
///
354+
/// [`Offer`]: crate::offers::offer::Offer
355+
AsyncBolt12Offer(AsyncBolt12OfferContext),
356+
352357
/// The payment was made for an invoice sent for a BOLT 12 [`Refund`].
353358
///
354359
/// [`Refund`]: crate::offers::refund::Refund
@@ -378,6 +383,18 @@ pub struct Bolt12OfferContext {
378383
pub invoice_request: InvoiceRequestFields,
379384
}
380385

386+
/// The context of a payment made for a static invoice requested from a BOLT 12 [`Offer`].
387+
///
388+
/// [`Offer`]: crate::offers::offer::Offer
389+
#[derive(Clone, Debug, Eq, PartialEq)]
390+
pub struct AsyncBolt12OfferContext {
391+
/// The [`Nonce`] used to verify that an inbound [`InvoiceRequest`] corresponds to this static
392+
/// invoice's offer.
393+
///
394+
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
395+
pub offer_nonce: Nonce,
396+
}
397+
381398
/// The context of a payment made for an invoice sent for a BOLT 12 [`Refund`].
382399
///
383400
/// [`Refund`]: crate::offers::refund::Refund
@@ -627,6 +644,7 @@ impl_writeable_tlv_based_enum_legacy!(PaymentContext,
627644
// 0 for Unknown removed in version 0.1.
628645
(1, Bolt12Offer),
629646
(2, Bolt12Refund),
647+
(3, AsyncBolt12Offer),
630648
);
631649

632650
impl<'a> Writeable for PaymentContextRef<'a> {
@@ -651,6 +669,10 @@ impl_writeable_tlv_based!(Bolt12OfferContext, {
651669
(2, invoice_request, required),
652670
});
653671

672+
impl_writeable_tlv_based!(AsyncBolt12OfferContext, {
673+
(0, offer_nonce, required),
674+
});
675+
654676
impl_writeable_tlv_based!(Bolt12RefundContext, {});
655677

656678
#[cfg(test)]

lightning/src/events/mod.rs

+14-8
Original file line numberDiff line numberDiff line change
@@ -181,27 +181,32 @@ impl PaymentPurpose {
181181
pub(crate) fn from_parts(
182182
payment_preimage: Option<PaymentPreimage>, payment_secret: PaymentSecret,
183183
payment_context: Option<PaymentContext>,
184-
) -> Self {
184+
) -> Result<Self, ()> {
185185
match payment_context {
186186
None => {
187-
PaymentPurpose::Bolt11InvoicePayment {
187+
Ok(PaymentPurpose::Bolt11InvoicePayment {
188188
payment_preimage,
189189
payment_secret,
190-
}
190+
})
191191
},
192192
Some(PaymentContext::Bolt12Offer(context)) => {
193-
PaymentPurpose::Bolt12OfferPayment {
193+
Ok(PaymentPurpose::Bolt12OfferPayment {
194194
payment_preimage,
195195
payment_secret,
196196
payment_context: context,
197-
}
197+
})
198198
},
199199
Some(PaymentContext::Bolt12Refund(context)) => {
200-
PaymentPurpose::Bolt12RefundPayment {
200+
Ok(PaymentPurpose::Bolt12RefundPayment {
201201
payment_preimage,
202202
payment_secret,
203203
payment_context: context,
204-
}
204+
})
205+
},
206+
Some(PaymentContext::AsyncBolt12Offer(_context)) => {
207+
// This code will change to return Self::Bolt12OfferPayment when we add support for async
208+
// receive.
209+
Err(())
205210
},
206211
}
207212
}
@@ -1865,7 +1870,8 @@ impl MaybeReadable for Event {
18651870
(13, payment_id, option),
18661871
});
18671872
let purpose = match payment_secret {
1868-
Some(secret) => PaymentPurpose::from_parts(payment_preimage, secret, payment_context),
1873+
Some(secret) => PaymentPurpose::from_parts(payment_preimage, secret, payment_context)
1874+
.map_err(|()| msgs::DecodeError::InvalidValue)?,
18691875
None if payment_preimage.is_some() => PaymentPurpose::SpontaneousPayment(payment_preimage.unwrap()),
18701876
None => return Err(msgs::DecodeError::InvalidValue),
18711877
};

lightning/src/ln/channelmanager.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -6253,11 +6253,16 @@ where
62536253
match claimable_htlc.onion_payload {
62546254
OnionPayload::Invoice { .. } => {
62556255
let payment_data = payment_data.unwrap();
6256-
let purpose = events::PaymentPurpose::from_parts(
6256+
let purpose = match events::PaymentPurpose::from_parts(
62576257
payment_preimage,
62586258
payment_data.payment_secret,
62596259
payment_context,
6260-
);
6260+
) {
6261+
Ok(purpose) => purpose,
6262+
Err(()) => {
6263+
fail_htlc!(claimable_htlc, payment_hash);
6264+
},
6265+
};
62616266
check_total_value!(purpose);
62626267
},
62636268
OnionPayload::Spontaneous(preimage) => {

0 commit comments

Comments
 (0)