Skip to content

Commit 88e8e71

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 2b57d9e commit 88e8e71

File tree

3 files changed

+44
-10
lines changed

3 files changed

+44
-10
lines changed

lightning/src/blinded_path/payment.rs

+23
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use crate::types::features::BlindedHopFeatures;
2222
use crate::ln::msgs::DecodeError;
2323
use crate::ln::onion_utils;
2424
use crate::offers::invoice_request::InvoiceRequestFields;
25+
use crate::offers::nonce::Nonce;
2526
use crate::offers::offer::OfferId;
2627
use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph};
2728
use crate::sign::{EntropySource, NodeSigner, Recipient};
@@ -318,6 +319,11 @@ pub enum PaymentContext {
318319
/// [`Offer`]: crate::offers::offer::Offer
319320
Bolt12Offer(Bolt12OfferContext),
320321

322+
/// The payment was made for a static invoice requested from a BOLT 12 [`Offer`].
323+
///
324+
/// [`Offer`]: crate::offers::offer::Offer
325+
AsyncBolt12Offer(AsyncBolt12OfferContext),
326+
321327
/// The payment was made for an invoice sent for a BOLT 12 [`Refund`].
322328
///
323329
/// [`Refund`]: crate::offers::refund::Refund
@@ -351,6 +357,18 @@ pub struct Bolt12OfferContext {
351357
pub invoice_request: InvoiceRequestFields,
352358
}
353359

360+
/// The context of a payment made for a static invoice requested from a BOLT 12 [`Offer`].
361+
///
362+
/// [`Offer`]: crate::offers::offer::Offer
363+
#[derive(Clone, Debug, Eq, PartialEq)]
364+
pub struct AsyncBolt12OfferContext {
365+
/// The [`Nonce`] used to verify that an inbound [`InvoiceRequest`] corresponds to this static
366+
/// invoice's offer.
367+
///
368+
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
369+
pub offer_nonce: Nonce,
370+
}
371+
354372
/// The context of a payment made for an invoice sent for a BOLT 12 [`Refund`].
355373
///
356374
/// [`Refund`]: crate::offers::refund::Refund
@@ -590,6 +608,7 @@ impl_writeable_tlv_based_enum_legacy!(PaymentContext,
590608
(0, Unknown),
591609
(1, Bolt12Offer),
592610
(2, Bolt12Refund),
611+
(3, AsyncBolt12Offer),
593612
);
594613

595614
impl<'a> Writeable for PaymentContextRef<'a> {
@@ -626,6 +645,10 @@ impl_writeable_tlv_based!(Bolt12OfferContext, {
626645
(2, invoice_request, required),
627646
});
628647

648+
impl_writeable_tlv_based!(AsyncBolt12OfferContext, {
649+
(0, offer_nonce, required),
650+
});
651+
629652
impl_writeable_tlv_based!(Bolt12RefundContext, {});
630653

631654
#[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
Some(PaymentContext::Unknown(_)) | 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
}
@@ -1836,7 +1841,8 @@ impl MaybeReadable for Event {
18361841
(13, payment_id, option),
18371842
});
18381843
let purpose = match payment_secret {
1839-
Some(secret) => PaymentPurpose::from_parts(payment_preimage, secret, payment_context),
1844+
Some(secret) => PaymentPurpose::from_parts(payment_preimage, secret, payment_context)
1845+
.map_err(|()| msgs::DecodeError::InvalidValue)?,
18401846
None if payment_preimage.is_some() => PaymentPurpose::SpontaneousPayment(payment_preimage.unwrap()),
18411847
None => return Err(msgs::DecodeError::InvalidValue),
18421848
};

lightning/src/ln/channelmanager.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -6078,11 +6078,16 @@ where
60786078
match claimable_htlc.onion_payload {
60796079
OnionPayload::Invoice { .. } => {
60806080
let payment_data = payment_data.unwrap();
6081-
let purpose = events::PaymentPurpose::from_parts(
6081+
let purpose = match events::PaymentPurpose::from_parts(
60826082
payment_preimage,
60836083
payment_data.payment_secret,
60846084
payment_context,
6085-
);
6085+
) {
6086+
Ok(purpose) => purpose,
6087+
Err(()) => {
6088+
fail_htlc!(claimable_htlc, payment_hash);
6089+
},
6090+
};
60866091
check_total_value!(purpose);
60876092
},
60886093
OnionPayload::Spontaneous(preimage) => {

0 commit comments

Comments
 (0)