From: Matt Corallo Date: Fri, 24 Mar 2023 01:31:14 +0000 (+0000) Subject: Add a `payment_metadata` field to `RecipientOnionFields` X-Git-Tag: v0.0.115~14^2~8 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=ee9afd315d22151e314aff2ca826561569ac4d03;p=rust-lightning Add a `payment_metadata` field to `RecipientOnionFields` This adds the new `payment_metadata` to `RecipientOnionFields`, passing the metadata from BOLT11 invoices through the send pipeline and finally copying them info the onion when sending HTLCs. This completes send-side support for the new payment metadata feature. --- diff --git a/lightning-invoice/src/payment.rs b/lightning-invoice/src/payment.rs index 00b17db78..ce0d37ee3 100644 --- a/lightning-invoice/src/payment.rs +++ b/lightning-invoice/src/payment.rs @@ -145,8 +145,10 @@ fn pay_invoice_using_amount( payer: P ) -> Result<(), PaymentError> where P::Target: Payer { let payment_hash = PaymentHash((*invoice.payment_hash()).into_inner()); - let payment_secret = Some(*invoice.payment_secret()); - let recipient_onion = RecipientOnionFields { payment_secret }; + let recipient_onion = RecipientOnionFields { + payment_secret: Some(*invoice.payment_secret()), + payment_metadata: invoice.payment_metadata().map(|v| v.clone()), + }; let mut payment_params = PaymentParameters::from_node_id(invoice.recover_payee_pub_key(), invoice.min_final_cltv_expiry_delta() as u32) .with_expiry_time(expiry_time_from_unix_epoch(invoice).as_secs()) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 7590d6f2f..4ca934185 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -7603,6 +7603,7 @@ where session_privs: [session_priv_bytes].iter().map(|a| *a).collect(), payment_hash: htlc.payment_hash, payment_secret: None, // only used for retries, and we'll never retry on startup + payment_metadata: None, // only used for retries, and we'll never retry on startup keysend_preimage: None, // only used for retries, and we'll never retry on startup pending_amt_msat: path_amt, pending_fee_msat: Some(path_fee), diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs index a751cb092..b9f36bbd8 100644 --- a/lightning/src/ln/onion_utils.rs +++ b/lightning/src/ln/onion_utils.rs @@ -170,7 +170,7 @@ pub(super) fn build_onion_payloads(path: &Vec, total_msat: u64, mut re total_msat, }) } else { None }, - payment_metadata: None, + payment_metadata: recipient_onion.payment_metadata.take(), keysend_preimage: *keysend_preimage, } } else { diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index 3dde7f243..738c1d195 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -46,6 +46,7 @@ pub(crate) enum PendingOutboundPayment { session_privs: HashSet<[u8; 32]>, payment_hash: PaymentHash, payment_secret: Option, + payment_metadata: Option>, keysend_preimage: Option, pending_amt_msat: u64, /// Used to track the fee paid. Only present if the payment was serialized on 0.0.103+. @@ -422,6 +423,19 @@ pub struct RecipientOnionFields { /// receives, thus you should generally never be providing a secret here for spontaneous /// payments. pub payment_secret: Option, + /// The payment metadata serves a similar purpose as [`Self::payment_secret`] but is of + /// arbitrary length. This gives recipients substantially more flexibility to receive + /// additional data. + /// + /// In LDK, while the [`Self::payment_secret`] is fixed based on an internal authentication + /// scheme to authenticate received payments against expected payments and invoices, this field + /// is not used in LDK for received payments, and can be used to store arbitrary data in + /// invoices which will be received with the payment. + /// + /// Note that this field was added to the lightning specification more recently than + /// [`Self::payment_secret`] and while nearly all lightning senders support secrets, metadata + /// may not be supported as universally. + pub payment_metadata: Option>, } impl RecipientOnionFields { @@ -429,7 +443,7 @@ impl RecipientOnionFields { /// set of onion fields for today's BOLT11 invoices - most nodes require a [`PaymentSecret`] /// but do not require or provide any further data. pub fn secret_only(payment_secret: PaymentSecret) -> Self { - Self { payment_secret: Some(payment_secret) } + Self { payment_secret: Some(payment_secret), payment_metadata: None } } /// Creates a new [`RecipientOnionFields`] with no fields. This generally does not create @@ -438,7 +452,7 @@ impl RecipientOnionFields { /// /// [`ChannelManager::send_spontaneous_payment`]: super::channelmanager::ChannelManager::send_spontaneous_payment pub fn spontaneous_empty() -> Self { - Self { payment_secret: None } + Self { payment_secret: None, payment_metadata: None } } } @@ -719,7 +733,7 @@ impl OutboundPayments { hash_map::Entry::Occupied(mut payment) => { let res = match payment.get() { PendingOutboundPayment::Retryable { - total_msat, keysend_preimage, payment_secret, pending_amt_msat, .. + total_msat, keysend_preimage, payment_secret, payment_metadata, pending_amt_msat, .. } => { let retry_amt_msat: u64 = route.paths.iter().map(|path| path.last().unwrap().fee_msat).sum(); if retry_amt_msat + *pending_amt_msat > *total_msat * (100 + RETRY_OVERFLOW_PERCENTAGE) / 100 { @@ -729,6 +743,7 @@ impl OutboundPayments { } (*total_msat, RecipientOnionFields { payment_secret: *payment_secret, + payment_metadata: payment_metadata.clone(), }, *keysend_preimage) }, PendingOutboundPayment::Legacy { .. } => { @@ -912,6 +927,7 @@ impl OutboundPayments { pending_fee_msat: Some(0), payment_hash, payment_secret: recipient_onion.payment_secret, + payment_metadata: recipient_onion.payment_metadata, keysend_preimage, starting_block_height: best_block_height, total_msat: route.get_total_amount(), @@ -1345,6 +1361,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment, (4, payment_secret, option), (5, keysend_preimage, option), (6, total_msat, required), + (7, payment_metadata, option), (8, pending_amt_msat, required), (10, starting_block_height, required), (not_written, retry_strategy, (static_value, None)),