-
Notifications
You must be signed in to change notification settings - Fork 456
Commit to payment_metadata in inbound payment HMAC #4528
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b583310
fac4f22
7464c69
b9e5b12
410dce0
44f36b9
3851100
3f9b79a
4bf195c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8611,6 +8611,7 @@ impl< | |
| let verify_res = inbound_payment::verify( | ||
| payment_hash, | ||
| &payment_data, | ||
| onion_fields.payment_metadata.as_deref(), | ||
| self.highest_seen_timestamp.load(Ordering::Acquire) as u64, | ||
| &self.inbound_payment_key, | ||
| &self.logger, | ||
|
|
@@ -14272,7 +14273,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ | |
| ) -> Result<Bolt11Invoice, SignOrCreationError<()>> { | ||
| let Bolt11InvoiceParameters { | ||
| amount_msats, description, invoice_expiry_delta_secs, min_final_cltv_expiry_delta, | ||
| payment_hash, | ||
| payment_hash, payment_metadata, | ||
| } = params; | ||
|
|
||
| let currency = | ||
|
|
@@ -14305,6 +14306,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ | |
| payment_hash, amount_msats, | ||
| invoice_expiry_delta_secs.unwrap_or(DEFAULT_EXPIRY_TIME as u32), | ||
| min_final_cltv_expiry_delta, | ||
| payment_metadata.as_deref(), | ||
| ) | ||
| .map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?; | ||
| (payment_hash, payment_secret) | ||
|
|
@@ -14314,6 +14316,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ | |
| .create_inbound_payment( | ||
| amount_msats, invoice_expiry_delta_secs.unwrap_or(DEFAULT_EXPIRY_TIME as u32), | ||
| min_final_cltv_expiry_delta, | ||
| payment_metadata.as_deref(), | ||
| ) | ||
| .map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))? | ||
| }, | ||
|
|
@@ -14352,7 +14355,11 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ | |
| invoice = invoice.private_route(hint); | ||
| } | ||
|
|
||
| let raw_invoice = invoice.build_raw().map_err(|e| SignOrCreationError::CreationError(e))?; | ||
| let raw_invoice = if let Some(payment_metadata) = payment_metadata { | ||
| invoice.payment_metadata(payment_metadata).build_raw() | ||
| } else { | ||
| invoice.build_raw() | ||
| }.map_err(|e| SignOrCreationError::CreationError(e))?; | ||
| let signature = self.node_signer.sign_invoice(&raw_invoice, Recipient::Node); | ||
|
|
||
| raw_invoice | ||
|
|
@@ -14431,6 +14438,14 @@ pub struct Bolt11InvoiceParameters { | |
| /// involving another protocol where the payment hash is also involved outside the scope of | ||
| /// lightning. | ||
| pub payment_hash: Option<PaymentHash>, | ||
|
|
||
| /// The `payment_metadata` to include in the invoice. This is provided back to us in the payment | ||
| /// onion by the sender, available as [`RecipientOnionFields::payment_metadata`] via | ||
| /// [`Event::PaymentClaimable::onion_fields`]. | ||
| /// | ||
| /// Note that because it is exposed to the sender in the invoice you should consider encrypting | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Utilities for encryption will be part of lightningdevkit/ldk-node#899, but I do wonder if we should maybe offer something similar upstream? |
||
| /// it. It is committed to, however, so cannot be modified by the sender. | ||
| pub payment_metadata: Option<Vec<u8>>, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: this could've been a separate commit |
||
| } | ||
|
|
||
| impl Default for Bolt11InvoiceParameters { | ||
|
|
@@ -14441,6 +14456,7 @@ impl Default for Bolt11InvoiceParameters { | |
| invoice_expiry_delta_secs: None, | ||
| min_final_cltv_expiry_delta: None, | ||
| payment_hash: None, | ||
| payment_metadata: None, | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -14932,7 +14948,7 @@ impl< | |
| refund, | ||
| self.list_usable_channels(), | ||
| |amount_msats, relative_expiry| { | ||
| self.create_inbound_payment(Some(amount_msats), relative_expiry, None) | ||
| self.create_inbound_payment(Some(amount_msats), relative_expiry, None, None) | ||
| .map_err(|()| Bolt12SemanticError::InvalidAmount) | ||
| }, | ||
| )?; | ||
|
|
@@ -14975,7 +14991,7 @@ impl< | |
| /// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash | ||
| pub fn create_inbound_payment( | ||
| &self, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32, | ||
| min_final_cltv_expiry_delta: Option<u16>, | ||
| min_final_cltv_expiry_delta: Option<u16>, payment_metadata: Option<&[u8]>, | ||
|
TheBlueMatt marked this conversation as resolved.
|
||
| ) -> Result<(PaymentHash, PaymentSecret), ()> { | ||
| inbound_payment::create( | ||
| &self.inbound_payment_key, | ||
|
|
@@ -14984,6 +15000,7 @@ impl< | |
| &self.entropy_source, | ||
| self.highest_seen_timestamp.load(Ordering::Acquire) as u64, | ||
| min_final_cltv_expiry_delta, | ||
| payment_metadata, | ||
| ) | ||
| } | ||
|
|
||
|
|
@@ -15003,6 +15020,9 @@ impl< | |
| /// before a [`PaymentClaimable`] event will be generated, ensuring that we do not provide the | ||
| /// sender "proof-of-payment" unless they have paid the required amount. | ||
| /// | ||
| /// The returned secret commits to the `payment_metadata` and thus the invoice's metadata must | ||
| /// match what is provided here. | ||
| /// | ||
| /// `invoice_expiry_delta_secs` describes the number of seconds that the invoice is valid for | ||
| /// in excess of the current time. This should roughly match the expiry time set in the invoice. | ||
| /// After this many seconds, we will remove the inbound payment, resulting in any attempts to | ||
|
|
@@ -15036,6 +15056,7 @@ impl< | |
| pub fn create_inbound_payment_for_hash( | ||
| &self, payment_hash: PaymentHash, min_value_msat: Option<u64>, | ||
| invoice_expiry_delta_secs: u32, min_final_cltv_expiry: Option<u16>, | ||
| payment_metadata: Option<&[u8]>, | ||
| ) -> Result<PaymentSecret, ()> { | ||
| inbound_payment::create_from_hash( | ||
| &self.inbound_payment_key, | ||
|
|
@@ -15044,18 +15065,25 @@ impl< | |
| invoice_expiry_delta_secs, | ||
| self.highest_seen_timestamp.load(Ordering::Acquire) as u64, | ||
| min_final_cltv_expiry, | ||
| payment_metadata, | ||
| ) | ||
| } | ||
|
|
||
| /// Gets an LDK-generated payment preimage from a payment hash and payment secret that were | ||
| /// Gets an LDK-generated payment preimage from a payment hash, metadata and secret that were | ||
| /// previously returned from [`create_inbound_payment`]. | ||
| /// | ||
| /// [`create_inbound_payment`]: Self::create_inbound_payment | ||
| pub fn get_payment_preimage( | ||
| &self, payment_hash: PaymentHash, payment_secret: PaymentSecret, | ||
| payment_metadata: Option<&[u8]>, | ||
|
TheBlueMatt marked this conversation as resolved.
|
||
| ) -> Result<PaymentPreimage, APIError> { | ||
| let expanded_key = &self.inbound_payment_key; | ||
| inbound_payment::get_payment_preimage(payment_hash, payment_secret, expanded_key) | ||
| inbound_payment::get_payment_preimage( | ||
| payment_hash, | ||
| payment_secret, | ||
| payment_metadata, | ||
| expanded_key, | ||
| ) | ||
| } | ||
|
|
||
| /// [`BlindedMessagePath`]s for an async recipient to communicate with this node and interactively | ||
|
|
@@ -17108,7 +17136,8 @@ impl< | |
| self.create_inbound_payment( | ||
| Some(amount_msats), | ||
| relative_expiry, | ||
| None | ||
| None, | ||
| None, | ||
| ).map_err(|_| Bolt12SemanticError::InvalidAmount) | ||
| }; | ||
|
|
||
|
|
@@ -21319,15 +21348,15 @@ mod tests { | |
| // payment verification fails as expected. | ||
| let mut bad_payment_hash = payment_hash.clone(); | ||
| bad_payment_hash.0[0] += 1; | ||
| match inbound_payment::verify(bad_payment_hash, &payment_data, nodes[0].node.highest_seen_timestamp.load(Ordering::Acquire) as u64, &nodes[0].node.inbound_payment_key, &nodes[0].logger) { | ||
| match inbound_payment::verify(bad_payment_hash, &payment_data, None, nodes[0].node.highest_seen_timestamp.load(Ordering::Acquire) as u64, &nodes[0].node.inbound_payment_key, &nodes[0].logger) { | ||
| Ok(_) => panic!("Unexpected ok"), | ||
| Err(()) => { | ||
| nodes[0].logger.assert_log_contains("lightning::ln::inbound_payment", "Failing HTLC with user-generated payment_hash", 1); | ||
| } | ||
| } | ||
|
|
||
| // Check that using the original payment hash succeeds. | ||
| assert!(inbound_payment::verify(payment_hash, &payment_data, nodes[0].node.highest_seen_timestamp.load(Ordering::Acquire) as u64, &nodes[0].node.inbound_payment_key, &nodes[0].logger).is_ok()); | ||
| assert!(inbound_payment::verify(payment_hash, &payment_data, None, nodes[0].node.highest_seen_timestamp.load(Ordering::Acquire) as u64, &nodes[0].node.inbound_payment_key, &nodes[0].logger).is_ok()); | ||
| } | ||
|
|
||
| fn check_not_connected_to_peer_error<T>( | ||
|
|
@@ -22000,7 +22029,7 @@ pub mod bench { | |
| payment_preimage.0[0..8].copy_from_slice(&payment_count.to_le_bytes()); | ||
| payment_count += 1; | ||
| let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).to_byte_array()); | ||
| let payment_secret = $node_b.create_inbound_payment_for_hash(payment_hash, None, 7200, None).unwrap(); | ||
| let payment_secret = $node_b.create_inbound_payment_for_hash(payment_hash, None, 7200, None, None).unwrap(); | ||
|
|
||
| $node_a.send_payment(payment_hash, RecipientOnionFields::secret_only(payment_secret, 10_000), | ||
| PaymentId(payment_hash.0), | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check length of
payment_metadataand return error if greater than max allowed length of field in invoice?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm,
lightning-invoiceisn't aware of a limit - if there is one we should enforce it everywhere which seems like an orthogonal PR.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't it be aware of the protocol limit here? https://github.com/TheBlueMatt/rust-lightning/blob/4bf195c5edae74699e9d7a9f598fa99a04679c29/lightning-invoice/src/ser.rs#L427
so passing metadata in the
Bolt11InvoiceParametersabove this would cause ldk to panic.