Include Offer context in blinded payment paths
authorJeffrey Czyz <jkczyz@gmail.com>
Tue, 26 Mar 2024 23:48:39 +0000 (18:48 -0500)
committerJeffrey Czyz <jkczyz@gmail.com>
Thu, 18 Apr 2024 14:15:21 +0000 (09:15 -0500)
When constructing blinded payment paths for a Bolt12Invoice response,
include the OfferId so that the eventual payment can be correlated with
the Offer.

lightning/src/blinded_path/payment.rs
lightning/src/ln/channelmanager.rs
lightning/src/offers/offer.rs

index 39f7c7f11088c51bdb5a55393084274d96631820..99979ecf4a37140ef5f7375fdc2c0cc67e0eaa7b 100644 (file)
@@ -12,6 +12,7 @@ use crate::ln::channelmanager::CounterpartyForwardingInfo;
 use crate::ln::features::BlindedHopFeatures;
 use crate::ln::msgs::DecodeError;
 use crate::offers::invoice::BlindedPayInfo;
+use crate::offers::offer::OfferId;
 use crate::util::ser::{HighZeroBytesDroppedBigSize, Readable, Writeable, Writer};
 
 #[allow(unused_imports)]
@@ -108,12 +109,28 @@ pub struct PaymentConstraints {
 pub enum PaymentContext {
        /// The payment context was unknown.
        Unknown(UnknownPaymentContext),
+
+       /// The payment was made for an invoice requested from a BOLT 12 [`Offer`].
+       ///
+       /// [`Offer`]: crate::offers::offer::Offer
+       Bolt12Offer(Bolt12OfferContext),
 }
 
 /// An unknown payment context.
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct UnknownPaymentContext(());
 
+/// The context of a payment made for an invoice requested from a BOLT 12 [`Offer`].
+///
+/// [`Offer`]: crate::offers::offer::Offer
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct Bolt12OfferContext {
+       /// The identifier of the [`Offer`].
+       ///
+       /// [`Offer`]: crate::offers::offer::Offer
+       pub offer_id: OfferId,
+}
+
 impl PaymentContext {
        pub(crate) fn unknown() -> Self {
                PaymentContext::Unknown(UnknownPaymentContext(()))
@@ -340,6 +357,7 @@ impl Readable for PaymentConstraints {
 impl_writeable_tlv_based_enum!(PaymentContext,
        ;
        (0, Unknown),
+       (1, Bolt12Offer),
 );
 
 impl Writeable for UnknownPaymentContext {
@@ -354,6 +372,10 @@ impl Readable for UnknownPaymentContext {
        }
 }
 
+impl_writeable_tlv_based!(Bolt12OfferContext, {
+       (0, offer_id, required),
+});
+
 #[cfg(test)]
 mod tests {
        use bitcoin::secp256k1::PublicKey;
index ef10717add2df28520b464a95741c0f40ad8c139..5487ae8ab84ce4c3bcdaee9226c43a821169c4bc 100644 (file)
@@ -32,7 +32,7 @@ use bitcoin::secp256k1::Secp256k1;
 use bitcoin::{secp256k1, Sequence};
 
 use crate::blinded_path::{BlindedPath, NodeIdLookUp};
-use crate::blinded_path::payment::{PaymentConstraints, PaymentContext, ReceiveTlvs};
+use crate::blinded_path::payment::{Bolt12OfferContext, PaymentConstraints, PaymentContext, ReceiveTlvs};
 use crate::chain;
 use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock};
 use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator};
@@ -8826,7 +8826,10 @@ where
 
                match self.create_inbound_payment(Some(amount_msats), relative_expiry, None) {
                        Ok((payment_hash, payment_secret)) => {
-                               let payment_paths = self.create_blinded_payment_paths(amount_msats, payment_secret)
+                               let payment_context = PaymentContext::unknown();
+                               let payment_paths = self.create_blinded_payment_paths(
+                                       amount_msats, payment_secret, payment_context
+                               )
                                        .map_err(|_| Bolt12SemanticError::MissingPaths)?;
 
                                #[cfg(feature = "std")]
@@ -8992,7 +8995,7 @@ where
        /// Creates multi-hop blinded payment paths for the given `amount_msats` by delegating to
        /// [`Router::create_blinded_payment_paths`].
        fn create_blinded_payment_paths(
-               &self, amount_msats: u64, payment_secret: PaymentSecret
+               &self, amount_msats: u64, payment_secret: PaymentSecret, payment_context: PaymentContext
        ) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()> {
                let secp_ctx = &self.secp_ctx;
 
@@ -9006,7 +9009,7 @@ where
                                max_cltv_expiry,
                                htlc_minimum_msat: 1,
                        },
-                       payment_context: PaymentContext::unknown(),
+                       payment_context,
                };
                self.router.create_blinded_payment_paths(
                        payee_node_id, first_hops, payee_tlvs, amount_msats, secp_ctx
@@ -10360,8 +10363,11 @@ where
                                        },
                                };
 
+                               let payment_context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
+                                       offer_id: invoice_request.offer_id,
+                               });
                                let payment_paths = match self.create_blinded_payment_paths(
-                                       amount_msats, payment_secret
+                                       amount_msats, payment_secret, payment_context
                                ) {
                                        Ok(payment_paths) => payment_paths,
                                        Err(()) => {
index 324e3ea42c94d378cd71020a36c1c97d63ee8348..3dedc6cd35d25166263603fb58fb6173faeb8935 100644 (file)
@@ -115,7 +115,7 @@ use std::time::SystemTime;
 pub(super) const IV_BYTES: &[u8; IV_LEN] = b"LDK Offer ~~~~~~";
 
 /// An identifier for an [`Offer`] built using [`DerivedMetadata`].
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
 pub struct OfferId(pub [u8; 32]);
 
 impl OfferId {