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
2 changes: 1 addition & 1 deletion fuzz/src/chanmon_consistency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ fn get_payment_secret_hash(dest: &ChanMan, payment_ctr: &mut u64) -> (PaymentSec
*payment_ctr += 1;
let payment_hash = PaymentHash(Sha256::hash(&[*payment_ctr as u8]).to_byte_array());
let payment_secret = dest
.create_inbound_payment_for_hash(payment_hash, None, 3600, None)
.create_inbound_payment_for_hash(payment_hash, None, 3600, None, None)
.expect("create_inbound_payment_for_hash failed");
(payment_secret, payment_hash)
}
Expand Down
2 changes: 1 addition & 1 deletion fuzz/src/full_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,7 @@ pub fn do_test(mut data: &[u8], logger: &Arc<dyn Logger + MaybeSend + MaybeSync>
PaymentHash(Sha256::hash(&payment_preimage.0[..]).to_byte_array());
// Note that this may fail - our hashes may collide and we'll end up trying to
// double-register the same payment_hash.
let _ = channelmanager.create_inbound_payment_for_hash(payment_hash, None, 1, None);
let _ = channelmanager.create_inbound_payment_for_hash(payment_hash, None, 1, None, None);
},
9 => {
for payment in payments_received.drain(..) {
Expand Down
2 changes: 1 addition & 1 deletion lightning-liquidity/tests/lsps2_integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ fn create_jit_invoice(
let min_final_cltv_expiry_delta = MIN_FINAL_CLTV_EXPIRY_DELTA + 2;
let (payment_hash, payment_secret) = node
.node
.create_inbound_payment(None, expiry_secs, Some(min_final_cltv_expiry_delta))
.create_inbound_payment(None, expiry_secs, Some(min_final_cltv_expiry_delta), None)
.map_err(|e| {
log_error!(node.logger, "Failed to register inbound payment: {:?}", e);
})?;
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/bolt11_payment_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn payment_metadata_end_to_end_for_invoice_with_amount() {
let payment_metadata = vec![42, 43, 44, 45, 46, 47, 48, 49, 42];

let (payment_hash, payment_secret) =
nodes[1].node.create_inbound_payment(None, 7200, None).unwrap();
nodes[1].node.create_inbound_payment(None, 7200, None, Some(&payment_metadata)).unwrap();

let timestamp = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
let invoice = InvoiceBuilder::new(Currency::Bitcoin)
Expand Down Expand Up @@ -98,7 +98,7 @@ fn payment_metadata_end_to_end_for_invoice_with_no_amount() {
let payment_metadata = vec![42, 43, 44, 45, 46, 47, 48, 49, 42];

let (payment_hash, payment_secret) =
nodes[1].node.create_inbound_payment(None, 7200, None).unwrap();
nodes[1].node.create_inbound_payment(None, 7200, None, Some(&payment_metadata)).unwrap();

let timestamp = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
let invoice = InvoiceBuilder::new(Currency::Bitcoin)
Expand Down
44 changes: 35 additions & 9 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8481,6 +8481,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,
Expand Down Expand Up @@ -14123,7 +14124,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 =
Expand Down Expand Up @@ -14156,6 +14157,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)
Expand All @@ -14165,6 +14167,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))?
},
Expand Down Expand Up @@ -14203,7 +14206,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
Expand Down Expand Up @@ -14282,6 +14289,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
/// it. It is committed to, however, so cannot be modified by the sender.
pub payment_metadata: Option<Vec<u8>>,
}

impl Default for Bolt11InvoiceParameters {
Expand All @@ -14292,6 +14307,7 @@ impl Default for Bolt11InvoiceParameters {
invoice_expiry_delta_secs: None,
min_final_cltv_expiry_delta: None,
payment_hash: None,
payment_metadata: None,
}
}
}
Expand Down Expand Up @@ -14776,7 +14792,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)
},
)?;
Expand Down Expand Up @@ -14885,7 +14901,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]>,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doc comment for create_inbound_payment doesn't document the new payment_metadata parameter. Worth adding a note explaining that when provided, the metadata is committed to in the payment secret HMAC, so the sender must relay it exactly for payment verification to succeed.

) -> Result<(PaymentHash, PaymentSecret), ()> {
inbound_payment::create(
&self.inbound_payment_key,
Expand All @@ -14894,6 +14910,7 @@ impl<
&self.entropy_source,
self.highest_seen_timestamp.load(Ordering::Acquire) as u64,
min_final_cltv_expiry_delta,
payment_metadata,
)
}

Expand Down Expand Up @@ -14946,6 +14963,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,
Expand All @@ -14954,6 +14972,7 @@ impl<
invoice_expiry_delta_secs,
self.highest_seen_timestamp.load(Ordering::Acquire) as u64,
min_final_cltv_expiry,
payment_metadata,
)
}

Expand All @@ -14963,9 +14982,15 @@ impl<
/// [`create_inbound_payment`]: Self::create_inbound_payment
pub fn get_payment_preimage(
&self, payment_hash: PaymentHash, payment_secret: PaymentSecret,
payment_metadata: Option<&[u8]>,
Comment on lines 14983 to +14985
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doc comment for this public API method doesn't mention the new payment_metadata parameter. Callers need to know that if a payment was created with payment_metadata via create_inbound_payment, the same metadata must be provided here for preimage derivation to succeed. Without this documentation, a caller may pass None and get a confusing APIMisuseError.

) -> 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
Expand Down Expand Up @@ -17017,7 +17042,8 @@ impl<
self.create_inbound_payment(
Some(amount_msats),
relative_expiry,
None
None,
None,
).map_err(|_| Bolt12SemanticError::InvalidAmount)
};

Expand Down Expand Up @@ -21275,15 +21301,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>(
Expand Down Expand Up @@ -21956,7 +21982,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),
Expand Down
1 change: 1 addition & 0 deletions lightning/src/ln/functional_test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2818,6 +2818,7 @@ pub fn get_payment_preimage_hash(
min_value_msat,
7200,
min_final_cltv_expiry_delta,
None,
)
.unwrap();
(payment_preimage, payment_hash, payment_secret)
Expand Down
38 changes: 23 additions & 15 deletions lightning/src/ln/functional_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,10 @@ pub fn test_duplicate_htlc_different_direction_onchain() {
let (payment_preimage, payment_hash, ..) = route_payment(&nodes[0], &[&nodes[1]], 900_000);

let (route, _, _, _) = get_route_and_payment_hash!(nodes[1], nodes[0], payment_value_msats);
let node_a_payment_secret =
nodes[0].node.create_inbound_payment_for_hash(payment_hash, None, 7200, None).unwrap();
let node_a_payment_secret = nodes[0]
.node
.create_inbound_payment_for_hash(payment_hash, None, 7200, None, None)
.unwrap();
send_along_route_with_secret(
&nodes[1],
route,
Expand Down Expand Up @@ -4156,8 +4158,10 @@ pub fn test_duplicate_payment_hash_one_failure_one_success() {
let (our_payment_preimage, dup_payment_hash, ..) =
route_payment(&nodes[0], &[&nodes[1], &nodes[2], &nodes[3]], 900_000);

let payment_secret =
nodes[4].node.create_inbound_payment_for_hash(dup_payment_hash, None, 7200, None).unwrap();
let payment_secret = nodes[4]
.node
.create_inbound_payment_for_hash(dup_payment_hash, None, 7200, None, None)
.unwrap();
let payment_params = PaymentParameters::from_node_id(node_e_id, TEST_FINAL_CLTV)
.with_bolt11_features(nodes[4].node.bolt11_invoice_features())
.unwrap();
Expand Down Expand Up @@ -4424,13 +4428,13 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
// 2nd HTLC (not added - smaller than dust limit + HTLC tx fee):
let path_5: &[&[_]] = &[&[&nodes[2], &nodes[3], &nodes[5]]];
let payment_secret =
nodes[5].node.create_inbound_payment_for_hash(hash_1, None, 7200, None).unwrap();
nodes[5].node.create_inbound_payment_for_hash(hash_1, None, 7200, None, None).unwrap();
let route = route_to_5.clone();
send_along_route_with_secret(&nodes[1], route, path_5, dust_limit_msat, hash_1, payment_secret);

// 3rd HTLC (not added - smaller than dust limit + HTLC tx fee):
let payment_secret =
nodes[5].node.create_inbound_payment_for_hash(hash_2, None, 7200, None).unwrap();
nodes[5].node.create_inbound_payment_for_hash(hash_2, None, 7200, None, None).unwrap();
let route = route_to_5;
send_along_route_with_secret(&nodes[1], route, path_5, dust_limit_msat, hash_2, payment_secret);

Expand All @@ -4443,12 +4447,12 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno

// 6th HTLC:
let payment_secret =
nodes[5].node.create_inbound_payment_for_hash(hash_3, None, 7200, None).unwrap();
nodes[5].node.create_inbound_payment_for_hash(hash_3, None, 7200, None, None).unwrap();
send_along_route_with_secret(&nodes[1], route.clone(), path_5, 1000000, hash_3, payment_secret);

// 7th HTLC:
let payment_secret =
nodes[5].node.create_inbound_payment_for_hash(hash_4, None, 7200, None).unwrap();
nodes[5].node.create_inbound_payment_for_hash(hash_4, None, 7200, None, None).unwrap();
send_along_route_with_secret(&nodes[1], route, path_5, 1000000, hash_4, payment_secret);

// 8th HTLC:
Expand All @@ -4457,7 +4461,7 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
// 9th HTLC (not added - smaller than dust limit + HTLC tx fee):
let (route, _, _, _) = get_route_and_payment_hash!(nodes[1], nodes[5], dust_limit_msat);
let payment_secret =
nodes[5].node.create_inbound_payment_for_hash(hash_5, None, 7200, None).unwrap();
nodes[5].node.create_inbound_payment_for_hash(hash_5, None, 7200, None, None).unwrap();
send_along_route_with_secret(&nodes[1], route, path_5, dust_limit_msat, hash_5, payment_secret);

// 10th HTLC (not added - smaller than dust limit + HTLC tx fee):
Expand All @@ -4466,7 +4470,7 @@ fn do_test_fail_backwards_unrevoked_remote_announce(deliver_last_raa: bool, anno
// 11th HTLC:
let (route, _, _, _) = get_route_and_payment_hash!(nodes[1], nodes[5], 1000000);
let payment_secret =
nodes[5].node.create_inbound_payment_for_hash(hash_6, None, 7200, None).unwrap();
nodes[5].node.create_inbound_payment_for_hash(hash_6, None, 7200, None, None).unwrap();
send_along_route_with_secret(&nodes[1], route, path_5, 1000000, hash_6, payment_secret);

// Double-check that six of the new HTLC were added
Expand Down Expand Up @@ -6061,7 +6065,7 @@ pub fn test_check_htlc_underpaying() {
let (_, our_payment_hash, _) = get_payment_preimage_hash(&nodes[0], None, None);
let our_payment_secret = nodes[1]
.node
.create_inbound_payment_for_hash(our_payment_hash, Some(100_000), 7200, None)
.create_inbound_payment_for_hash(our_payment_hash, Some(100_000), 7200, None, None)
.unwrap();
let onion = RecipientOnionFields::secret_only(our_payment_secret, route.get_total_amount());
let id = PaymentId(our_payment_hash.0);
Expand Down Expand Up @@ -7229,7 +7233,7 @@ pub fn test_preimage_storage() {

{
let (payment_hash, payment_secret) =
nodes[1].node.create_inbound_payment(Some(100_000), 7200, None).unwrap();
nodes[1].node.create_inbound_payment(Some(100_000), 7200, None, None).unwrap();
let (route, _, _, _) = get_route_and_payment_hash!(nodes[0], nodes[1], 100_000);
let onion = RecipientOnionFields::secret_only(payment_secret, 100_000);
let id = PaymentId(payment_hash.0);
Expand Down Expand Up @@ -7274,7 +7278,7 @@ pub fn test_bad_secret_hash() {
let random_hash = PaymentHash([42; 32]);
let random_secret = PaymentSecret([43; 32]);
let (our_payment_hash, our_payment_secret) =
nodes[1].node.create_inbound_payment(Some(100_000), 2, None).unwrap();
nodes[1].node.create_inbound_payment(Some(100_000), 2, None, None).unwrap();
let (route, _, _, _) = get_route_and_payment_hash!(nodes[0], nodes[1], 100_000);

// All the below cases should end up being handled exactly identically, so we macro the
Expand Down Expand Up @@ -9482,9 +9486,13 @@ fn do_payment_with_custom_min_final_cltv_expiry(valid_delta: bool, use_user_hash
} else {
let (hash, payment_secret) = nodes[1]
.node
.create_inbound_payment(Some(recv_value), 7200, Some(min_cltv_expiry_delta))
.create_inbound_payment(Some(recv_value), 7200, Some(min_cltv_expiry_delta), None)
.unwrap();
(hash, nodes[1].node.get_payment_preimage(hash, payment_secret).unwrap(), payment_secret)
(
hash,
nodes[1].node.get_payment_preimage(hash, payment_secret, None).unwrap(),
payment_secret,
)
};
let route = get_route!(nodes[0], payment_parameters, recv_value).unwrap();
let onion = RecipientOnionFields::secret_only(payment_secret, recv_value);
Expand Down
Loading
Loading