Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions fuzz/src/invoice_request_deser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
let payment_context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
offer_id: OfferId([42; 32]),
invoice_request: invoice_request_fields,
payment_metadata: None,
});
let payee_tlvs = ReceiveTlvs {
payment_secret: PaymentSecret([42; 32]),
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/refund_deser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
) -> Result<UnsignedBolt12Invoice, Bolt12SemanticError> {
let entropy_source = Randomness {};
let receive_auth_key = ReceiveAuthKey([41; 32]);
let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext {});
let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext { payment_metadata: None });
let payee_tlvs = ReceiveTlvs {
payment_secret: PaymentSecret([42; 32]),
payment_constraints: PaymentConstraints {
Expand Down
24 changes: 23 additions & 1 deletion lightning/src/blinded_path/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

//! Data structures and methods for constructing [`BlindedMessagePath`]s to send a message over.

use alloc::collections::BTreeMap;

use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};

#[allow(unused_imports)]
Expand All @@ -29,7 +31,9 @@ use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph};
use crate::sign::{EntropySource, NodeSigner, ReceiveAuthKey, Recipient};
use crate::types::payment::PaymentHash;
use crate::util::scid_utils;
use crate::util::ser::{FixedLengthReader, LengthReadableArgs, Readable, Writeable, Writer};
use crate::util::ser::{
BigSizeKeyedMap, FixedLengthReader, LengthReadableArgs, Readable, Writeable, Writer,
};

use core::time::Duration;
use core::{cmp, mem};
Expand Down Expand Up @@ -391,6 +395,23 @@ pub enum OffersContext {
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
/// [`Offer`]: crate::offers::offer::Offer
nonce: Nonce,

/// Additional data about this payment which is not used in LDK and can be used for any
/// purpose.
///
/// This is analogous to the BOLT 11 [`RecipientOnionFields::payment_metadata`] (which is
/// provided to payers via [`Bolt11Invoice::payment_metadata`]) and can be used any time data
/// needs to be "stored" by a payment recipient for their own internal use, provided back to
/// them with the payment.
///
/// Note that because this is included in the payment onion, its size must be tightly
/// constrained. More than a few hundred bytes and the payment will be entirely unpayable (with
/// limited routing options as size increases). Further, any data placed here will increase
/// the size of the offer which may make it difficult to fit in QR codes.
///
/// [`RecipientOnionFields::payment_metadata`]: crate::ln::outbound_payment::RecipientOnionFields::payment_metadata
/// [`Bolt11Invoice::payment_metadata`]: lightning_invoice::Bolt11Invoice::payment_metadata
payment_metadata: Option<BTreeMap<u64, Vec<u8>>>,
},
/// Context used by a [`BlindedMessagePath`] within the [`Offer`] of an async recipient.
///
Expand Down Expand Up @@ -648,6 +669,7 @@ impl_writeable_tlv_based_enum!(MessageContext,
impl_writeable_tlv_based_enum!(OffersContext,
(0, InvoiceRequest) => {
(0, nonce, required),
(1, payment_metadata, (option, encoding: (BTreeMap<u64, Vec<u8>>, BigSizeKeyedMap))),
},
(1, OutboundPaymentForRefund) => {
(0, payment_id, required),
Expand Down
92 changes: 83 additions & 9 deletions lightning/src/blinded_path/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

//! Data structures and methods for constructing [`BlindedPaymentPath`]s to send a payment over.

use alloc::collections::BTreeMap;

use bitcoin::secp256k1::ecdh::SharedSecret;
use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};

Expand All @@ -29,8 +31,8 @@ use crate::types::features::BlindedHopFeatures;
use crate::types::payment::PaymentSecret;
use crate::types::routing::RoutingFees;
use crate::util::ser::{
FixedLengthReader, HighZeroBytesDroppedBigSize, LengthReadableArgs, Readable, WithoutLength,
Writeable, Writer,
BigSizeKeyedMap, FixedLengthReader, HighZeroBytesDroppedBigSize, LengthReadableArgs, Readable,
WithoutLength, Writeable, Writer,
};

#[allow(unused_imports)]
Expand Down Expand Up @@ -572,6 +574,16 @@ pub enum PaymentContext {
/// [`Refund`]: crate::offers::refund::Refund
Bolt12Refund(Bolt12RefundContext),
}
impl PaymentContext {
/// Returns the additional payment metadata stored alongside this payment context, if any.
pub fn payment_metadata(&self) -> Option<&BTreeMap<u64, Vec<u8>>> {
match self {
Self::Bolt12Offer(Bolt12OfferContext { payment_metadata, .. })
| Self::AsyncBolt12Offer(AsyncBolt12OfferContext { payment_metadata, .. })
| Self::Bolt12Refund(Bolt12RefundContext { payment_metadata, .. }) => payment_metadata.as_ref(),
}
}
}

// Used when writing PaymentContext in Event::PaymentClaimable to avoid cloning.
pub(crate) enum PaymentContextRef<'a> {
Expand All @@ -594,6 +606,22 @@ pub struct Bolt12OfferContext {
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
pub invoice_request: InvoiceRequestFields,

/// Additional data about this payment which is not used in LDK and can be used for any
/// purpose.
///
/// This is analogous to the BOLT 11 [`RecipientOnionFields::payment_metadata`] (which is
/// provided to payers via [`Bolt11Invoice::payment_metadata`]) and can be used any time data
/// needs to be "stored" by a payment recipient for their own internal use, provided back to
/// them with the payment.
///
Comment thread
TheBlueMatt marked this conversation as resolved.
/// Note that because this is included in the payment onion, its size must be tightly
/// constrained. More than a few hundred bytes and the payment will be entirely unpayable (with
/// limited routing options as size increases).
///
/// [`RecipientOnionFields::payment_metadata`]: crate::ln::outbound_payment::RecipientOnionFields::payment_metadata
/// [`Bolt11Invoice::payment_metadata`]: lightning_invoice::Bolt11Invoice::payment_metadata
pub payment_metadata: Option<BTreeMap<u64, Vec<u8>>>,
}

/// The context of a payment made for a static invoice requested from a BOLT 12 [`Offer`].
Expand All @@ -606,13 +634,45 @@ pub struct AsyncBolt12OfferContext {
///
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
pub offer_nonce: Nonce,

/// Additional data about this payment which is not used in LDK and can be used for any
/// purpose.
///
/// This is analogous to the BOLT 11 [`RecipientOnionFields::payment_metadata`] (which is
/// provided to payers via [`Bolt11Invoice::payment_metadata`]) and can be used any time data
/// needs to be "stored" by a payment recipient for their own internal use, provided back to
/// them with the payment.
///
/// Note that because this is included in the payment onion, its size must be tightly
/// constrained. More than a few hundred bytes and the payment will be entirely unpayable (with
/// limited routing options as size increases).
///
/// [`RecipientOnionFields::payment_metadata`]: crate::ln::outbound_payment::RecipientOnionFields::payment_metadata
/// [`Bolt11Invoice::payment_metadata`]: lightning_invoice::Bolt11Invoice::payment_metadata
pub payment_metadata: Option<BTreeMap<u64, Vec<u8>>>,
}

/// The context of a payment made for an invoice sent for a BOLT 12 [`Refund`].
///
/// [`Refund`]: crate::offers::refund::Refund
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Bolt12RefundContext {}
pub struct Bolt12RefundContext {
/// Additional data about this payment which is not used in LDK and can be used for any
/// purpose.
///
/// This is analogous to the BOLT 11 [`RecipientOnionFields::payment_metadata`] (which is
/// provided to payers via [`Bolt11Invoice::payment_metadata`]) and can be used any time data
/// needs to be "stored" by a payment recipient for their own internal use, provided back to
/// them with the payment.
///
/// Note that because this is included in the payment onion, its size must be tightly
/// constrained. More than a few hundred bytes and the payment will be entirely unpayable (with
/// limited routing options as size increases).
///
/// [`RecipientOnionFields::payment_metadata`]: crate::ln::outbound_payment::RecipientOnionFields::payment_metadata
/// [`Bolt11Invoice::payment_metadata`]: lightning_invoice::Bolt11Invoice::payment_metadata
pub payment_metadata: Option<BTreeMap<u64, Vec<u8>>>,
}

impl TryFrom<CounterpartyForwardingInfo> for PaymentRelay {
type Error = ();
Expand Down Expand Up @@ -1031,14 +1091,18 @@ impl<'a> Writeable for PaymentContextRef<'a> {

impl_writeable_tlv_based!(Bolt12OfferContext, {
(0, offer_id, required),
(1, payment_metadata, (option, encoding: (BTreeMap<u64, Vec<u8>>, BigSizeKeyedMap))),
(2, invoice_request, required),
});

impl_writeable_tlv_based!(AsyncBolt12OfferContext, {
(0, offer_nonce, required),
(1, payment_metadata, (option, encoding: (BTreeMap<u64, Vec<u8>>, BigSizeKeyedMap))),
});

impl_writeable_tlv_based!(Bolt12RefundContext, {});
impl_writeable_tlv_based!(Bolt12RefundContext, {
(1, payment_metadata, (option, encoding: (BTreeMap<u64, Vec<u8>>, BigSizeKeyedMap))),
});

#[cfg(test)]
mod tests {
Expand Down Expand Up @@ -1097,7 +1161,9 @@ mod tests {
let recv_tlvs = ReceiveTlvs {
payment_secret: PaymentSecret([0; 32]),
payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 1 },
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {
payment_metadata: None,
}),
};
let htlc_maximum_msat = 100_000;
let blinded_payinfo =
Expand All @@ -1115,7 +1181,9 @@ mod tests {
let recv_tlvs = ReceiveTlvs {
payment_secret: PaymentSecret([0; 32]),
payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 1 },
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {
payment_metadata: None,
}),
};
let blinded_payinfo = super::compute_payinfo::<ForwardTlvs>(
&[],
Expand Down Expand Up @@ -1178,7 +1246,9 @@ mod tests {
let recv_tlvs = ReceiveTlvs {
payment_secret: PaymentSecret([0; 32]),
payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 3 },
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {
payment_metadata: None,
}),
};
let htlc_maximum_msat = 100_000;
let blinded_payinfo = super::compute_payinfo(
Expand Down Expand Up @@ -1238,7 +1308,9 @@ mod tests {
let recv_tlvs = ReceiveTlvs {
payment_secret: PaymentSecret([0; 32]),
payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 1 },
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {
payment_metadata: None,
}),
};
let htlc_minimum_msat = 3798;
assert!(super::compute_payinfo(
Expand Down Expand Up @@ -1309,7 +1381,9 @@ mod tests {
let recv_tlvs = ReceiveTlvs {
payment_secret: PaymentSecret([0; 32]),
payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 1 },
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {
payment_metadata: None,
}),
};

let blinded_payinfo = super::compute_payinfo(
Expand Down
Loading
Loading