Skip to content

Commit b60ba66

Browse files
committed
Split OffersContext::OutboundPayment into InRefund/InInvReq
Because they end up both being used to validate a `Bolt12Invoice`, we ended up with a single `OffersContext` both for inclusion in a `Refund` and an `InvoiceRequest`. However, this is ambiguous, and while it doesn't seem like an issue, it also seems like a nice property to only use a given `OffersContext` in one place. Further, in the next commit, we use `OffersContext` to figure out what we're building a blinded path for and changing behavior based on it, so its nice to be unambiguous. Thus, we split the single existing context into `OutboundPaymentInRefund` and `OutboundPaymentInInvReq`.
1 parent e42e74e commit b60ba66

File tree

4 files changed

+83
-37
lines changed

4 files changed

+83
-37
lines changed

lightning/src/blinded_path/message.rs

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -416,28 +416,45 @@ pub enum OffersContext {
416416
/// Useful to timeout async recipients that are no longer supported as clients.
417417
path_absolute_expiry: Duration,
418418
},
419-
/// Context used by a [`BlindedMessagePath`] within a [`Refund`] or as a reply path for an
420-
/// [`InvoiceRequest`].
419+
/// Context used by a [`BlindedMessagePath`] within a [`Refund`].
421420
///
422421
/// This variant is intended to be received when handling a [`Bolt12Invoice`] or an
423422
/// [`InvoiceError`].
424423
///
425424
/// [`Refund`]: crate::offers::refund::Refund
426-
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
427425
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
428426
/// [`InvoiceError`]: crate::offers::invoice_error::InvoiceError
429-
OutboundPayment {
430-
/// Payment ID used when creating a [`Refund`] or [`InvoiceRequest`].
427+
OutboundPaymentInRefund {
428+
/// Payment ID used when creating a [`Refund`].
431429
///
432430
/// [`Refund`]: crate::offers::refund::Refund
433-
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
434431
payment_id: PaymentId,
435432

436-
/// A nonce used for authenticating that a [`Bolt12Invoice`] is for a valid [`Refund`] or
437-
/// [`InvoiceRequest`] and for deriving their signing keys.
433+
/// A nonce used for authenticating that a [`Bolt12Invoice`] is for a valid [`Refund`] and
434+
/// for deriving its signing keys.
438435
///
439436
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
440437
/// [`Refund`]: crate::offers::refund::Refund
438+
nonce: Nonce,
439+
},
440+
/// Context used by a [`BlindedMessagePath`] as a reply path for an [`InvoiceRequest`].
441+
///
442+
/// This variant is intended to be received when handling a [`Bolt12Invoice`] or an
443+
/// [`InvoiceError`].
444+
///
445+
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
446+
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
447+
/// [`InvoiceError`]: crate::offers::invoice_error::InvoiceError
448+
OutboundPaymentInInvReq {
449+
/// Payment ID used when creating an [`InvoiceRequest`].
450+
///
451+
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
452+
payment_id: PaymentId,
453+
454+
/// A nonce used for authenticating that a [`Bolt12Invoice`] is for a valid
455+
/// [`InvoiceRequest`] and for deriving its signing keys.
456+
///
457+
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
441458
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
442459
nonce: Nonce,
443460
},
@@ -619,7 +636,7 @@ impl_writeable_tlv_based_enum!(OffersContext,
619636
(0, InvoiceRequest) => {
620637
(0, nonce, required),
621638
},
622-
(1, OutboundPayment) => {
639+
(1, OutboundPaymentInRefund) => {
623640
(0, payment_id, required),
624641
(1, nonce, required),
625642
},
@@ -631,6 +648,10 @@ impl_writeable_tlv_based_enum!(OffersContext,
631648
(2, invoice_slot, required),
632649
(4, path_absolute_expiry, required),
633650
},
651+
(4, OutboundPaymentInInvReq) => {
652+
(0, payment_id, required),
653+
(1, nonce, required),
654+
},
634655
);
635656

636657
impl_writeable_tlv_based_enum!(AsyncPaymentsContext,

lightning/src/ln/channelmanager.rs

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5593,29 +5593,12 @@ where
55935593
pub fn send_payment_for_bolt12_invoice(
55945594
&self, invoice: &Bolt12Invoice, context: Option<&OffersContext>,
55955595
) -> Result<(), Bolt12PaymentError> {
5596-
match self.verify_bolt12_invoice(invoice, context) {
5596+
match self.flow.verify_bolt12_invoice(invoice, context) {
55975597
Ok(payment_id) => self.send_payment_for_verified_bolt12_invoice(invoice, payment_id),
55985598
Err(()) => Err(Bolt12PaymentError::UnexpectedInvoice),
55995599
}
56005600
}
56015601

5602-
fn verify_bolt12_invoice(
5603-
&self, invoice: &Bolt12Invoice, context: Option<&OffersContext>,
5604-
) -> Result<PaymentId, ()> {
5605-
let secp_ctx = &self.secp_ctx;
5606-
let expanded_key = &self.inbound_payment_key;
5607-
5608-
match context {
5609-
None if invoice.is_for_refund_without_paths() => {
5610-
invoice.verify_using_metadata(expanded_key, secp_ctx)
5611-
},
5612-
Some(&OffersContext::OutboundPayment { payment_id, nonce, .. }) => {
5613-
invoice.verify_using_payer_data(payment_id, nonce, expanded_key, secp_ctx)
5614-
},
5615-
_ => Err(()),
5616-
}
5617-
}
5618-
56195602
fn send_payment_for_verified_bolt12_invoice(
56205603
&self, invoice: &Bolt12Invoice, payment_id: PaymentId,
56215604
) -> Result<(), Bolt12PaymentError> {
@@ -15366,7 +15349,7 @@ where
1536615349
},
1536715350
OffersMessage::StaticInvoice(invoice) => {
1536815351
let payment_id = match context {
15369-
Some(OffersContext::OutboundPayment { payment_id, .. }) => payment_id,
15352+
Some(OffersContext::OutboundPaymentInInvReq { payment_id, .. }) => payment_id,
1537015353
_ => return None
1537115354
};
1537215355
let res = self.initiate_async_payment(&invoice, payment_id);
@@ -15382,7 +15365,8 @@ where
1538215365
log_trace!(logger, "Received invoice_error: {}", invoice_error);
1538315366

1538415367
match context {
15385-
Some(OffersContext::OutboundPayment { payment_id, .. }) => {
15368+
Some(OffersContext::OutboundPaymentInInvReq { payment_id, .. })
15369+
|Some(OffersContext::OutboundPaymentInRefund { payment_id, .. }) => {
1538615370
self.abandon_payment_with_reason(
1538715371
payment_id, PaymentFailureReason::InvoiceRequestRejected,
1538815372
);

lightning/src/offers/flow.rs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -495,11 +495,12 @@ where
495495
Ok(InvreqResponseInstructions::SendInvoice(invoice_request))
496496
}
497497

498-
/// Verifies a [`Bolt12Invoice`] using the provided [`OffersContext`] or the invoice's payer metadata,
499-
/// returning the corresponding [`PaymentId`] if successful.
498+
/// Verifies a [`Bolt12Invoice`] using the provided [`OffersContext`] or the invoice's payer
499+
/// metadata, returning the corresponding [`PaymentId`] if successful.
500500
///
501-
/// - If an [`OffersContext::OutboundPayment`] with a `nonce` is provided, verification is performed
502-
/// using this to form the payer metadata.
501+
/// - If an [`OffersContext::OutboundPaymentInInvReq`] or
502+
/// [`OffersContext::OutboundPaymentInRefund`] with a `nonce` is provided, verification is
503+
/// performed using this to form the payer metadata.
503504
/// - If no context is provided and the invoice corresponds to a [`Refund`] without blinded paths,
504505
/// verification is performed using the [`Bolt12Invoice::payer_metadata`].
505506
/// - If neither condition is met, verification fails.
@@ -513,8 +514,19 @@ where
513514
None if invoice.is_for_refund_without_paths() => {
514515
invoice.verify_using_metadata(expanded_key, secp_ctx)
515516
},
516-
Some(&OffersContext::OutboundPayment { payment_id, nonce, .. }) => {
517-
invoice.verify_using_payer_data(payment_id, nonce, expanded_key, secp_ctx)
517+
Some(&OffersContext::OutboundPaymentInInvReq { payment_id, nonce, .. }) => {
518+
if invoice.is_for_offer() {
519+
invoice.verify_using_payer_data(payment_id, nonce, expanded_key, secp_ctx)
520+
} else {
521+
Err(())
522+
}
523+
},
524+
Some(&OffersContext::OutboundPaymentInRefund { payment_id, nonce, .. }) => {
525+
if invoice.is_for_refund() {
526+
invoice.verify_using_payer_data(payment_id, nonce, expanded_key, secp_ctx)
527+
} else {
528+
Err(())
529+
}
518530
},
519531
_ => Err(()),
520532
}
@@ -680,7 +692,8 @@ where
680692
let secp_ctx = &self.secp_ctx;
681693

682694
let nonce = Nonce::from_entropy_source(entropy);
683-
let context = MessageContext::Offers(OffersContext::OutboundPayment { payment_id, nonce });
695+
let context =
696+
MessageContext::Offers(OffersContext::OutboundPaymentInRefund { payment_id, nonce });
684697

685698
// Create the base builder with common properties
686699
let mut builder = RefundBuilder::deriving_signing_pubkey(
@@ -1116,7 +1129,8 @@ where
11161129
&self, invoice_request: InvoiceRequest, payment_id: PaymentId, nonce: Nonce,
11171130
peers: Vec<MessageForwardNode>,
11181131
) -> Result<(), Bolt12SemanticError> {
1119-
let context = MessageContext::Offers(OffersContext::OutboundPayment { payment_id, nonce });
1132+
let context =
1133+
MessageContext::Offers(OffersContext::OutboundPaymentInInvReq { payment_id, nonce });
11201134
let reply_paths = self
11211135
.create_blinded_paths(peers, context)
11221136
.map_err(|_| Bolt12SemanticError::MissingPaths)?;

lightning/src/offers/invoice.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,19 @@ struct InvoiceFields {
778778
}
779779

780780
macro_rules! invoice_accessors { ($self: ident, $contents: expr) => {
781+
/// Whether the invoice was created in response to a [`Refund`].
782+
pub fn is_for_refund(&$self) -> bool {
783+
$contents.is_for_refund()
784+
}
785+
786+
/// Whether the invoice was created in response to an [`InvoiceRequest`] created from an
787+
/// [`Offer`].
788+
///
789+
/// [`Offer`]: crate::offers::offer::Offer
790+
pub fn is_for_offer(&$self) -> bool {
791+
$contents.is_for_offer()
792+
}
793+
781794
/// The chains that may be used when paying a requested invoice.
782795
///
783796
/// From [`Offer::chains`]; `None` if the invoice was created in response to a [`Refund`].
@@ -1093,6 +1106,20 @@ impl InvoiceContents {
10931106
}
10941107
}
10951108

1109+
fn is_for_refund(&self) -> bool {
1110+
match self {
1111+
InvoiceContents::ForRefund { .. } => true,
1112+
InvoiceContents::ForOffer { .. } => false,
1113+
}
1114+
}
1115+
1116+
fn is_for_offer(&self) -> bool {
1117+
match self {
1118+
InvoiceContents::ForRefund { .. } => false,
1119+
InvoiceContents::ForOffer { .. } => true,
1120+
}
1121+
}
1122+
10961123
fn offer_chains(&self) -> Option<Vec<ChainHash>> {
10971124
match self {
10981125
InvoiceContents::ForOffer { invoice_request, .. } => {

0 commit comments

Comments
 (0)