From c529c40afe7312e37f58013855c71758d1819079 Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Wed, 4 Feb 2026 10:55:56 +0100 Subject: [PATCH 1/2] Make `payment_id` a required field in `Event`s The switch to tracking payments by ID happend with LDK Node v0.3.0, which is >1.5 years old by now. We can be pretty certain that nobody is upgrading from an older version to the upcoming v0.8. Here we hence make the `payment_id` fields in `Event` required which is a nice API simplification that will also be utilized in the next commit. --- bindings/ldk_node.udl | 6 +++--- src/event.rs | 25 +++++++++---------------- tests/common/mod.rs | 6 +++--- tests/integration_tests_rust.rs | 30 +++++++++++++++--------------- 4 files changed, 30 insertions(+), 37 deletions(-) diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index 6bd031379..674dddd96 100644 --- a/bindings/ldk_node.udl +++ b/bindings/ldk_node.udl @@ -413,9 +413,9 @@ enum VssHeaderProviderError { [Enum] interface Event { - PaymentSuccessful(PaymentId? payment_id, PaymentHash payment_hash, PaymentPreimage? payment_preimage, u64? fee_paid_msat); - PaymentFailed(PaymentId? payment_id, PaymentHash? payment_hash, PaymentFailureReason? reason); - PaymentReceived(PaymentId? payment_id, PaymentHash payment_hash, u64 amount_msat, sequence custom_records); + PaymentSuccessful(PaymentId payment_id, PaymentHash payment_hash, PaymentPreimage? payment_preimage, u64? fee_paid_msat); + PaymentFailed(PaymentId payment_id, PaymentHash? payment_hash, PaymentFailureReason? reason); + PaymentReceived(PaymentId payment_id, PaymentHash payment_hash, u64 amount_msat, sequence custom_records); PaymentClaimable(PaymentId payment_id, PaymentHash payment_hash, u64 claimable_amount_msat, u32? claim_deadline, sequence custom_records); PaymentForwarded(ChannelId prev_channel_id, ChannelId next_channel_id, UserChannelId? prev_user_channel_id, UserChannelId? next_user_channel_id, PublicKey? prev_node_id, PublicKey? next_node_id, u64? total_fee_earned_msat, u64? skimmed_fee_msat, boolean claim_from_onchain_tx, u64? outbound_amount_forwarded_msat); diff --git a/src/event.rs b/src/event.rs index 6f0ed8e09..514525bae 100644 --- a/src/event.rs +++ b/src/event.rs @@ -62,9 +62,7 @@ pub enum Event { /// A sent payment was successful. PaymentSuccessful { /// A local identifier used to track the payment. - /// - /// Will only be `None` for events serialized with LDK Node v0.2.1 or prior. - payment_id: Option, + payment_id: PaymentId, /// The hash of the payment. payment_hash: PaymentHash, /// The preimage to the `payment_hash`. @@ -79,9 +77,7 @@ pub enum Event { /// A sent payment has failed. PaymentFailed { /// A local identifier used to track the payment. - /// - /// Will only be `None` for events serialized with LDK Node v0.2.1 or prior. - payment_id: Option, + payment_id: PaymentId, /// The hash of the payment. /// /// This will be `None` if the payment failed before receiving an invoice when paying a @@ -97,9 +93,7 @@ pub enum Event { /// A payment has been received. PaymentReceived { /// A local identifier used to track the payment. - /// - /// Will only be `None` for events serialized with LDK Node v0.2.1 or prior. - payment_id: Option, + payment_id: PaymentId, /// The hash of the payment. payment_hash: PaymentHash, /// The value, in thousandths of a satoshi, that has been received. @@ -262,17 +256,17 @@ impl_writeable_tlv_based_enum!(Event, (0, PaymentSuccessful) => { (0, payment_hash, required), (1, fee_paid_msat, option), - (3, payment_id, option), + (3, payment_id, required), (5, payment_preimage, option), }, (1, PaymentFailed) => { (0, payment_hash, option), (1, reason, upgradable_option), - (3, payment_id, option), + (3, payment_id, required), }, (2, PaymentReceived) => { (0, payment_hash, required), - (1, payment_id, option), + (1, payment_id, required), (2, amount_msat, required), (3, custom_records, optional_vec), }, @@ -1002,7 +996,7 @@ where } let event = Event::PaymentReceived { - payment_id: Some(payment_id), + payment_id, payment_hash, amount_msat, custom_records: onion_fields @@ -1063,7 +1057,7 @@ where ); }); let event = Event::PaymentSuccessful { - payment_id: Some(payment_id), + payment_id, payment_hash, payment_preimage: Some(payment_preimage), fee_paid_msat, @@ -1098,8 +1092,7 @@ where }, }; - let event = - Event::PaymentFailed { payment_id: Some(payment_id), payment_hash, reason }; + let event = Event::PaymentFailed { payment_id, payment_hash, reason }; match self.event_queue.add_event(event).await { Ok(_) => return Ok(()), Err(e) => { diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 5f6657260..f0257a9dd 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -122,7 +122,7 @@ macro_rules! expect_payment_received_event { ref e @ Event::PaymentReceived { payment_id, amount_msat, .. } => { println!("{} got event {:?}", $node.node_id(), e); assert_eq!(amount_msat, $amount_msat); - let payment = $node.payment(&payment_id.unwrap()).unwrap(); + let payment = $node.payment(&payment_id).unwrap(); if !matches!(payment.kind, PaymentKind::Onchain { .. }) { assert_eq!(payment.fee_paid_msat, None); } @@ -171,7 +171,7 @@ macro_rules! expect_payment_successful_event { if let Some(fee_msat) = $fee_paid_msat { assert_eq!(fee_paid_msat, fee_msat); } - let payment = $node.payment(&$payment_id.unwrap()).unwrap(); + let payment = $node.payment(&$payment_id).unwrap(); assert_eq!(payment.fee_paid_msat, fee_paid_msat); assert_eq!(payment_id, $payment_id); $node.event_handled().unwrap(); @@ -973,7 +973,7 @@ pub(crate) async fn do_channel_full_cycle( .claim_for_hash(manual_payment_hash, claimable_amount_msat, manual_preimage) .unwrap(); expect_payment_received_event!(node_b, claimable_amount_msat); - expect_payment_successful_event!(node_a, Some(manual_payment_id), None); + expect_payment_successful_event!(node_a, manual_payment_id, None); assert_eq!(node_a.payment(&manual_payment_id).unwrap().status, PaymentStatus::Succeeded); assert_eq!(node_a.payment(&manual_payment_id).unwrap().direction, PaymentDirection::Outbound); assert_eq!( diff --git a/tests/integration_tests_rust.rs b/tests/integration_tests_rust.rs index 605dd0613..f779cb6ce 100644 --- a/tests/integration_tests_rust.rs +++ b/tests/integration_tests_rust.rs @@ -1028,7 +1028,7 @@ async fn run_splice_channel_test(bitcoind_chain_source: bool) { let payment_id = node_b.spontaneous_payment().send(amount_msat, node_a.node_id(), None).unwrap(); - expect_payment_successful_event!(node_b, Some(payment_id), None); + expect_payment_successful_event!(node_b, payment_id, None); expect_payment_received_event!(node_a, amount_msat); // Mine a block to give time for the HTLC to resolve @@ -1123,7 +1123,7 @@ async fn simple_bolt12_send_receive() { .send(&offer, expected_quantity, expected_payer_note.clone(), None) .unwrap(); - expect_payment_successful_event!(node_a, Some(payment_id), None); + expect_payment_successful_event!(node_a, payment_id, None); let node_a_payments = node_a.list_payments_with_filter(|p| matches!(p.kind, PaymentKind::Bolt12Offer { .. })); assert_eq!(node_a_payments.len(), 1); @@ -1189,7 +1189,7 @@ async fn simple_bolt12_send_receive() { ) .unwrap(); - expect_payment_successful_event!(node_a, Some(payment_id), None); + expect_payment_successful_event!(node_a, payment_id, None); let node_a_payments = node_a.list_payments_with_filter(|p| { matches!(p.kind, PaymentKind::Bolt12Offer { .. }) && p.id == payment_id }); @@ -1262,7 +1262,7 @@ async fn simple_bolt12_send_receive() { .first() .unwrap() .id; - expect_payment_successful_event!(node_b, Some(node_b_payment_id), None); + expect_payment_successful_event!(node_b, node_b_payment_id, None); let node_b_payments = node_b.list_payments_with_filter(|p| { matches!(p.kind, PaymentKind::Bolt12Refund { .. }) && p.id == node_b_payment_id @@ -1439,7 +1439,7 @@ async fn async_payment() { node_receiver.start().unwrap(); - expect_payment_successful_event!(node_sender, Some(payment_id), None); + expect_payment_successful_event!(node_sender, payment_id, None); } #[tokio::test(flavor = "multi_thread", worker_threads = 1)] @@ -1647,7 +1647,7 @@ async fn unified_send_receive_bip21_uri() { }, }; - expect_payment_successful_event!(node_a, Some(offer_payment_id), None); + expect_payment_successful_event!(node_a, offer_payment_id, None); // Cut off the BOLT12 part to fallback to BOLT11. let uri_str_without_offer = uri_str.split("&lno=").next().unwrap(); @@ -1667,7 +1667,7 @@ async fn unified_send_receive_bip21_uri() { panic!("Expected Bolt11 payment but got error: {:?}", e); }, }; - expect_payment_successful_event!(node_a, Some(invoice_payment_id), None); + expect_payment_successful_event!(node_a, invoice_payment_id, None); let expect_onchain_amount_sats = 800_000; let onchain_uni_payment = @@ -1801,9 +1801,9 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) { let service_fee_msat = (jit_amount_msat * channel_opening_fee_ppm as u64) / 1_000_000; let expected_received_amount_msat = jit_amount_msat - service_fee_msat; - expect_payment_successful_event!(payer_node, Some(payment_id), None); + expect_payment_successful_event!(payer_node, payment_id, None); let client_payment_id = - expect_payment_received_event!(client_node, expected_received_amount_msat).unwrap(); + expect_payment_received_event!(client_node, expected_received_amount_msat); let client_payment = client_node.payment(&client_payment_id).unwrap(); match client_payment.kind { PaymentKind::Bolt11Jit { counterparty_skimmed_fee_msat, .. } => { @@ -1830,7 +1830,7 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) { // are working as expected. println!("Paying regular invoice!"); let payment_id = payer_node.bolt11_payment().send(&invoice, None).unwrap(); - expect_payment_successful_event!(payer_node, Some(payment_id), None); + expect_payment_successful_event!(payer_node, payment_id, None); expect_event!(service_node, PaymentForwarded); expect_payment_received_event!(client_node, amount_msat); @@ -1876,9 +1876,9 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) { .unwrap(); expect_event!(service_node, PaymentForwarded); - expect_payment_successful_event!(payer_node, Some(payment_id), None); + expect_payment_successful_event!(payer_node, payment_id, None); let client_payment_id = - expect_payment_received_event!(client_node, expected_received_amount_msat).unwrap(); + expect_payment_received_event!(client_node, expected_received_amount_msat); let client_payment = client_node.payment(&client_payment_id).unwrap(); match client_payment.kind { PaymentKind::Bolt11Jit { counterparty_skimmed_fee_msat, .. } => { @@ -1983,7 +1983,7 @@ async fn spontaneous_send_with_custom_preimage() { .unwrap(); // check payment status and verify stored preimage - expect_payment_successful_event!(node_a, Some(payment_id), None); + expect_payment_successful_event!(node_a, payment_id, None); let details: PaymentDetails = node_a.list_payments_with_filter(|p| p.id == payment_id).first().unwrap().clone(); assert_eq!(details.status, PaymentStatus::Succeeded); @@ -2168,9 +2168,9 @@ async fn lsps2_client_trusts_lsp() { .claim_for_hash(manual_payment_hash, jit_amount_msat, manual_preimage) .unwrap(); - expect_payment_successful_event!(payer_node, Some(payment_id), None); + expect_payment_successful_event!(payer_node, payment_id, None); - let _ = expect_payment_received_event!(client_node, expected_received_amount_msat).unwrap(); + let _ = expect_payment_received_event!(client_node, expected_received_amount_msat); // Check the nodes pick up on the confirmed funding tx now. wait_for_tx(&electrsd.client, funding_txo.txid).await; From 006927151fd413522c6f197993288108ac9135d1 Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Wed, 4 Feb 2026 11:20:04 +0100 Subject: [PATCH 2/2] WIP switch to `PaymentId` fully .. will require Payment metadata store --- bindings/ldk_node.udl | 4 +- src/event.rs | 134 +++++++++-------- src/payment/bolt11.rs | 168 ++++++++++++---------- tests/common/mod.rs | 246 +++++++++++++++++--------------- tests/integration_tests_rust.rs | 30 ++-- 5 files changed, 318 insertions(+), 264 deletions(-) diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index 674dddd96..8c17b2b18 100644 --- a/bindings/ldk_node.udl +++ b/bindings/ldk_node.udl @@ -214,9 +214,9 @@ interface Bolt11Payment { [Throws=NodeError] void send_probes_using_amount([ByRef]Bolt11Invoice invoice, u64 amount_msat, RouteParametersConfig? route_parameters); [Throws=NodeError] - void claim_for_hash(PaymentHash payment_hash, u64 claimable_amount_msat, PaymentPreimage preimage); + void claim_for_id(PaymentId payment_id, u64 claimable_amount_msat, PaymentPreimage preimage); [Throws=NodeError] - void fail_for_hash(PaymentHash payment_hash); + void fail_for_id(PaymentId payment_id); [Throws=NodeError] Bolt11Invoice receive(u64 amount_msat, [ByRef]Bolt11InvoiceDescription description, u32 expiry_secs); [Throws=NodeError] diff --git a/src/event.rs b/src/event.rs index 514525bae..a20815d84 100644 --- a/src/event.rs +++ b/src/event.rs @@ -635,9 +635,10 @@ where claim_deadline, onion_fields, counterparty_skimmed_fee_msat, + payment_id, .. } => { - let payment_id = PaymentId(payment_hash.0); + let payment_id = payment_id.unwrap_or(PaymentId(payment_hash.0)); if let Some(info) = self.payment_store.get(&payment_id) { if info.direction == PaymentDirection::Outbound { log_info!( @@ -744,46 +745,6 @@ where _ => debug_assert!(false, "We only expect the counterparty to get away with withholding fees for JIT payments."), } } - - // If this is known by the store but ChannelManager doesn't know the preimage, - // the payment has been registered via `_for_hash` variants and needs to be manually claimed via - // user interaction. - match info.kind { - PaymentKind::Bolt11 { preimage, .. } - | PaymentKind::Bolt11Jit { preimage, .. } => { - if purpose.preimage().is_none() { - debug_assert!( - preimage.is_none(), - "We would have registered the preimage if we knew" - ); - - let custom_records = onion_fields - .map(|cf| { - cf.custom_tlvs().into_iter().map(|tlv| tlv.into()).collect() - }) - .unwrap_or_default(); - let event = Event::PaymentClaimable { - payment_id, - payment_hash, - claimable_amount_msat: amount_msat, - claim_deadline, - custom_records, - }; - match self.event_queue.add_event(event).await { - Ok(_) => return Ok(()), - Err(e) => { - log_error!( - self.logger, - "Failed to push to event queue: {}", - e - ); - return Err(ReplayEvent()); - }, - }; - } - }, - _ => {}, - } } log_info!( @@ -793,7 +754,46 @@ where amount_msat, ); let payment_preimage = match purpose { - PaymentPurpose::Bolt11InvoicePayment { payment_preimage, .. } => { + PaymentPurpose::Bolt11InvoicePayment { + payment_preimage, + payment_secret, + .. + } => { + let kind = PaymentKind::Bolt11 { + hash: payment_hash, + preimage: payment_preimage, + secret: Some(payment_secret), + }; + + let payment = PaymentDetails::new( + payment_id, + kind, + Some(amount_msat), + None, + PaymentDirection::Inbound, + PaymentStatus::Pending, + ); + + match self.payment_store.insert(payment) { + Ok(false) => (), + Ok(true) => { + log_error!( + self.logger, + "Bolt11InvoicePayment with ID {} was previously known", + payment_id, + ); + debug_assert!(false); + }, + Err(e) => { + log_error!( + self.logger, + "Failed to insert payment with ID {}: {}", + payment_id, + e + ); + debug_assert!(false); + }, + } payment_preimage }, PaymentPurpose::Bolt12OfferPayment { @@ -892,25 +892,47 @@ where if let Some(preimage) = payment_preimage { self.channel_manager.claim_funds(preimage); } else { - log_error!( - self.logger, - "Failed to claim payment with ID {}: preimage unknown.", + // If ChannelManager doesn't know the preimage the payment needs to be + // manually claimed via user interaction. + //if purpose.preimage().is_none() { + let custom_records = onion_fields + .map(|cf| cf.custom_tlvs().into_iter().map(|tlv| tlv.into()).collect()) + .unwrap_or_default(); + let event = Event::PaymentClaimable { payment_id, - ); - self.channel_manager.fail_htlc_backwards(&payment_hash); - - let update = PaymentDetailsUpdate { - hash: Some(Some(payment_hash)), - status: Some(PaymentStatus::Failed), - ..PaymentDetailsUpdate::new(payment_id) + payment_hash, + claimable_amount_msat: amount_msat, + claim_deadline, + custom_records, }; - match self.payment_store.update(&update) { + match self.event_queue.add_event(event).await { Ok(_) => return Ok(()), Err(e) => { - log_error!(self.logger, "Failed to access payment store: {}", e); + log_error!(self.logger, "Failed to push to event queue: {}", e); return Err(ReplayEvent()); }, }; + //} + + //log_error!( + // self.logger, + // "Failed to claim payment with ID {}: preimage unknown.", + // payment_id, + //); + //self.channel_manager.fail_htlc_backwards(&payment_hash); + + //let update = PaymentDetailsUpdate { + // hash: Some(Some(payment_hash)), + // status: Some(PaymentStatus::Failed), + // ..PaymentDetailsUpdate::new(payment_id) + //}; + //match self.payment_store.update(&update) { + // Ok(_) => return Ok(()), + // Err(e) => { + // log_error!(self.logger, "Failed to access payment store: {}", e); + // return Err(ReplayEvent()); + // }, + //}; } }, LdkEvent::PaymentClaimed { @@ -921,9 +943,9 @@ where htlcs: _, sender_intended_total_msat: _, onion_fields, - payment_id: _, + payment_id, } => { - let payment_id = PaymentId(payment_hash.0); + let payment_id = payment_id.unwrap_or(PaymentId(payment_hash.0)); log_info!( self.logger, "Claimed payment with ID {} from payment hash {} of {}msat.", diff --git a/src/payment/bolt11.rs b/src/payment/bolt11.rs index 41597bfcc..158828897 100644 --- a/src/payment/bolt11.rs +++ b/src/payment/bolt11.rs @@ -21,6 +21,7 @@ use lightning_invoice::{ Bolt11Invoice as LdkBolt11Invoice, Bolt11InvoiceDescription as LdkBolt11InvoiceDescription, }; use lightning_types::payment::{PaymentHash, PaymentPreimage}; +use rand::RngCore; use crate::config::{Config, LDK_PAYMENT_RETRY_TIMEOUT}; use crate::connection::ConnectionManager; @@ -98,20 +99,23 @@ impl Bolt11Payment { } let invoice = maybe_deref(invoice); - let payment_hash = invoice.payment_hash(); - let payment_id = PaymentId(invoice.payment_hash().0); - if let Some(payment) = self.payment_store.get(&payment_id) { - if payment.status == PaymentStatus::Pending - || payment.status == PaymentStatus::Succeeded - { - log_error!(self.logger, "Payment error: an invoice must not be paid twice."); - return Err(Error::DuplicatePayment); - } - } + let mut random_bytes = [0u8; 32]; + rand::rng().fill_bytes(&mut random_bytes); + let payment_id = PaymentId(random_bytes); + // TODO: re-add checking for duplicate payments? + //if let Some(payment) = self.payment_store.get(&payment_id) { + // if payment.status == PaymentStatus::Pending + // || payment.status == PaymentStatus::Succeeded + // { + // log_error!(self.logger, "Payment error: an invoice must not be paid twice."); + // return Err(Error::DuplicatePayment); + // } + //} let route_parameters = route_parameters.or(self.config.route_parameters).unwrap_or_default(); let retry_strategy = Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT); + let payment_hash = invoice.payment_hash(); let payment_secret = Some(*invoice.payment_secret()); match self.channel_manager.pay_for_bolt11_invoice( @@ -205,15 +209,18 @@ impl Bolt11Payment { } let payment_hash = invoice.payment_hash(); - let payment_id = PaymentId(invoice.payment_hash().0); - if let Some(payment) = self.payment_store.get(&payment_id) { - if payment.status == PaymentStatus::Pending - || payment.status == PaymentStatus::Succeeded - { - log_error!(self.logger, "Payment error: an invoice must not be paid twice."); - return Err(Error::DuplicatePayment); - } - } + let mut random_bytes = [0u8; 32]; + rand::rng().fill_bytes(&mut random_bytes); + let payment_id = PaymentId(random_bytes); + // TODO: re-add checking for duplicate payments? + //if let Some(payment) = self.payment_store.get(&payment_id) { + // if payment.status == PaymentStatus::Pending + // || payment.status == PaymentStatus::Succeeded + // { + // log_error!(self.logger, "Payment error: an invoice must not be paid twice."); + // return Err(Error::DuplicatePayment); + // } + //} let route_parameters = route_parameters.or(self.config.route_parameters).unwrap_or_default(); @@ -304,32 +311,42 @@ impl Bolt11Payment { /// [`receive_variable_amount_for_hash`]: Self::receive_variable_amount_for_hash /// [`PaymentClaimable`]: crate::Event::PaymentClaimable /// [`PaymentReceived`]: crate::Event::PaymentReceived - pub fn claim_for_hash( - &self, payment_hash: PaymentHash, claimable_amount_msat: u64, preimage: PaymentPreimage, + pub fn claim_for_id( + &self, payment_id: PaymentId, claimable_amount_msat: u64, preimage: PaymentPreimage, ) -> Result<(), Error> { - let payment_id = PaymentId(payment_hash.0); - - let expected_payment_hash = PaymentHash(Sha256::hash(&preimage.0).to_byte_array()); - - if expected_payment_hash != payment_hash { - log_error!( - self.logger, - "Failed to manually claim payment as the given preimage doesn't match the hash {}", - payment_hash - ); - return Err(Error::InvalidPaymentPreimage); - } - if let Some(details) = self.payment_store.get(&payment_id) { // For payments requested via `receive*_via_jit_channel_for_hash()` // `skimmed_fee_msat` held by LSP must be taken into account. - let skimmed_fee_msat = match details.kind { + let (skimmed_fee_msat, payment_hash_opt) = match details.kind { + PaymentKind::Bolt11 { hash, .. } => (0, Some(hash)), + PaymentKind::Bolt12Offer { hash, .. } => (0, hash), + PaymentKind::Bolt12Refund { hash, .. } => (0, hash), PaymentKind::Bolt11Jit { + hash, counterparty_skimmed_fee_msat: Some(skimmed_fee_msat), .. - } => skimmed_fee_msat, - _ => 0, + } => (skimmed_fee_msat, Some(hash)), + _ => (0, None), }; + + let payment_hash = payment_hash_opt.ok_or_else(|| { + log_error!( + self.logger, + "Failed to manually claim payment due to unknown payment hash", + ); + Error::InvalidPaymentId + })?; + + let expected_payment_hash = PaymentHash(Sha256::hash(&preimage.0).to_byte_array()); + if expected_payment_hash != payment_hash { + log_error!( + self.logger, + "Failed to manually claim payment as the given preimage doesn't match the hash {}", + payment_hash + ); + return Err(Error::InvalidPaymentPreimage); + } + if let Some(invoice_amount_msat) = details.amount_msat { if claimable_amount_msat < invoice_amount_msat - skimmed_fee_msat { log_error!( @@ -343,10 +360,10 @@ impl Bolt11Payment { } else { log_error!( self.logger, - "Failed to manually claim unknown payment with hash: {}", - payment_hash + "Failed to manually claim unknown payment with ID: {}", + payment_id ); - return Err(Error::InvalidPaymentHash); + return Err(Error::InvalidPaymentId); } self.channel_manager.claim_funds(preimage); @@ -366,8 +383,31 @@ impl Bolt11Payment { /// [`receive_for_hash`]: Self::receive_for_hash /// [`receive_variable_amount_for_hash`]: Self::receive_variable_amount_for_hash /// [`PaymentClaimable`]: crate::Event::PaymentClaimable - pub fn fail_for_hash(&self, payment_hash: PaymentHash) -> Result<(), Error> { - let payment_id = PaymentId(payment_hash.0); + pub fn fail_for_id(&self, payment_id: PaymentId) -> Result<(), Error> { + let payment_hash = if let Some(details) = self.payment_store.get(&payment_id) { + let payment_hash_opt = match details.kind { + PaymentKind::Bolt11 { hash, .. } => Some(hash), + PaymentKind::Bolt12Offer { hash, .. } => hash, + PaymentKind::Bolt12Refund { hash, .. } => hash, + PaymentKind::Bolt11Jit { hash, .. } => Some(hash), + _ => None, + }; + + payment_hash_opt.ok_or_else(|| { + log_error!( + self.logger, + "Failed to manually fail payment due to unknown payment hash", + ); + Error::InvalidPaymentId + })? + } else { + log_error!( + self.logger, + "Failed to manually fail unknown payment with ID: {}", + payment_id + ); + return Err(Error::InvalidPaymentId); + }; let update = PaymentDetailsUpdate { status: Some(PaymentStatus::Failed), @@ -379,16 +419,16 @@ impl Bolt11Payment { Ok(DataStoreUpdateResult::NotFound) => { log_error!( self.logger, - "Failed to manually fail unknown payment with hash {}", - payment_hash, + "Failed to manually fail unknown payment with ID {}", + payment_id, ); - return Err(Error::InvalidPaymentHash); + return Err(Error::InvalidPaymentId); }, Err(e) => { log_error!( self.logger, - "Failed to manually fail payment with hash {}: {}", - payment_hash, + "Failed to manually fail payment with ID {}: {}", + payment_id, e ); return Err(e); @@ -494,36 +534,6 @@ impl Bolt11Payment { } }; - let payment_hash = invoice.payment_hash(); - let payment_secret = invoice.payment_secret(); - let id = PaymentId(payment_hash.0); - let preimage = if manual_claim_payment_hash.is_none() { - // If the user hasn't registered a custom payment hash, we're positive ChannelManager - // will know the preimage at this point. - let res = self - .channel_manager - .get_payment_preimage(payment_hash, payment_secret.clone()) - .ok(); - debug_assert!(res.is_some(), "We just let ChannelManager create an inbound payment, it can't have forgotten the preimage by now."); - res - } else { - None - }; - let kind = PaymentKind::Bolt11 { - hash: payment_hash, - preimage, - secret: Some(payment_secret.clone()), - }; - let payment = PaymentDetails::new( - id, - kind, - amount_msat, - None, - PaymentDirection::Inbound, - PaymentStatus::Pending, - ); - self.payment_store.insert(payment)?; - Ok(invoice) } @@ -718,7 +728,9 @@ impl Bolt11Payment { max_total_opening_fee_msat: lsp_total_opening_fee, max_proportional_opening_fee_ppm_msat: lsp_prop_opening_fee, }; - let id = PaymentId(payment_hash.0); + let mut random_bytes = [0u8; 32]; + rand::rng().fill_bytes(&mut random_bytes); + let id = PaymentId(random_bytes); let preimage = self.channel_manager.get_payment_preimage(payment_hash, payment_secret.clone()).ok(); let kind = PaymentKind::Bolt11Jit { diff --git a/tests/common/mod.rs b/tests/common/mod.rs index f0257a9dd..a766e10f6 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -122,10 +122,6 @@ macro_rules! expect_payment_received_event { ref e @ Event::PaymentReceived { payment_id, amount_msat, .. } => { println!("{} got event {:?}", $node.node_id(), e); assert_eq!(amount_msat, $amount_msat); - let payment = $node.payment(&payment_id).unwrap(); - if !matches!(payment.kind, PaymentKind::Onchain { .. }) { - assert_eq!(payment.fee_paid_msat, None); - } $node.event_handled().unwrap(); payment_id }, @@ -139,7 +135,7 @@ macro_rules! expect_payment_received_event { pub(crate) use expect_payment_received_event; macro_rules! expect_payment_claimable_event { - ($node:expr, $payment_id:expr, $payment_hash:expr, $claimable_amount_msat:expr) => {{ + ($node:expr, $payment_hash:expr, $claimable_amount_msat:expr) => {{ match $node.next_event_async().await { ref e @ Event::PaymentClaimable { payment_id, @@ -149,10 +145,9 @@ macro_rules! expect_payment_claimable_event { } => { println!("{} got event {:?}", std::stringify!($node), e); assert_eq!(payment_hash, $payment_hash); - assert_eq!(payment_id, $payment_id); assert_eq!(claimable_amount_msat, $claimable_amount_msat); $node.event_handled().unwrap(); - claimable_amount_msat + (payment_id, claimable_amount_msat) }, ref e => { panic!("{} got unexpected event!: {:?}", std::stringify!($node), e); @@ -820,10 +815,12 @@ pub(crate) async fn do_channel_full_cycle( .unwrap(); println!("\nA send"); - let payment_id = node_a.bolt11_payment().send(&invoice, None).unwrap(); - assert_eq!(node_a.bolt11_payment().send(&invoice, None), Err(NodeError::DuplicatePayment)); + // TODO: re-add checking for duplicate payments? + //assert_eq!(node_a.bolt11_payment().send(&invoice, None), Err(NodeError::DuplicatePayment)); - assert!(!node_a.list_payments_with_filter(|p| p.id == payment_id).is_empty()); + let node_a_payment_id = node_a.bolt11_payment().send(&invoice, None).unwrap(); + + assert!(!node_a.list_payments_with_filter(|p| p.id == node_a_payment_id).is_empty()); let outbound_payments_a = node_a.list_payments_with_filter(|p| { p.direction == PaymentDirection::Outbound && matches!(p.kind, PaymentKind::Bolt11 { .. }) @@ -840,30 +837,45 @@ pub(crate) async fn do_channel_full_cycle( }); assert_eq!(outbound_payments_b.len(), 0); + expect_event!(node_a, PaymentSuccessful); + let node_b_payment_id = expect_payment_received_event!(node_b, invoice_amount_1_msat); + let inbound_payments_b = node_b.list_payments_with_filter(|p| { p.direction == PaymentDirection::Inbound && matches!(p.kind, PaymentKind::Bolt11 { .. }) }); assert_eq!(inbound_payments_b.len(), 1); - expect_event!(node_a, PaymentSuccessful); - expect_event!(node_b, PaymentReceived); - assert_eq!(node_a.payment(&payment_id).unwrap().status, PaymentStatus::Succeeded); - assert_eq!(node_a.payment(&payment_id).unwrap().direction, PaymentDirection::Outbound); - assert_eq!(node_a.payment(&payment_id).unwrap().amount_msat, Some(invoice_amount_1_msat)); - assert!(matches!(node_a.payment(&payment_id).unwrap().kind, PaymentKind::Bolt11 { .. })); - assert_eq!(node_b.payment(&payment_id).unwrap().status, PaymentStatus::Succeeded); - assert_eq!(node_b.payment(&payment_id).unwrap().direction, PaymentDirection::Inbound); - assert_eq!(node_b.payment(&payment_id).unwrap().amount_msat, Some(invoice_amount_1_msat)); - assert!(matches!(node_b.payment(&payment_id).unwrap().kind, PaymentKind::Bolt11 { .. })); - - // Assert we fail duplicate outbound payments and check the status hasn't changed. - assert_eq!(Err(NodeError::DuplicatePayment), node_a.bolt11_payment().send(&invoice, None)); - assert_eq!(node_a.payment(&payment_id).unwrap().status, PaymentStatus::Succeeded); - assert_eq!(node_a.payment(&payment_id).unwrap().direction, PaymentDirection::Outbound); - assert_eq!(node_a.payment(&payment_id).unwrap().amount_msat, Some(invoice_amount_1_msat)); - assert_eq!(node_b.payment(&payment_id).unwrap().status, PaymentStatus::Succeeded); - assert_eq!(node_b.payment(&payment_id).unwrap().direction, PaymentDirection::Inbound); - assert_eq!(node_b.payment(&payment_id).unwrap().amount_msat, Some(invoice_amount_1_msat)); + assert_eq!(node_a.payment(&node_a_payment_id).unwrap().status, PaymentStatus::Succeeded); + assert_eq!(node_a.payment(&node_a_payment_id).unwrap().direction, PaymentDirection::Outbound); + assert_eq!( + node_a.payment(&node_a_payment_id).unwrap().amount_msat, + Some(invoice_amount_1_msat) + ); + assert!(matches!(node_a.payment(&node_a_payment_id).unwrap().kind, PaymentKind::Bolt11 { .. })); + + assert_eq!(node_b.payment(&node_b_payment_id).unwrap().status, PaymentStatus::Succeeded); + assert_eq!(node_b.payment(&node_b_payment_id).unwrap().direction, PaymentDirection::Inbound); + assert_eq!( + node_b.payment(&node_b_payment_id).unwrap().amount_msat, + Some(invoice_amount_1_msat) + ); + assert!(matches!(node_b.payment(&node_b_payment_id).unwrap().kind, PaymentKind::Bolt11 { .. })); + + // TODO: re-add checking for duplicate payments? + //// Assert we fail duplicate outbound payments and check the status hasn't changed. + //assert_eq!(Err(NodeError::DuplicatePayment), node_a.bolt11_payment().send(&invoice, None)); + //assert_eq!(node_a.payment(&node_a_payment_id).unwrap().status, PaymentStatus::Succeeded); + //assert_eq!(node_a.payment(&node_a_payment_id).unwrap().direction, PaymentDirection::Outbound); + //assert_eq!( + // node_a.payment(&node_a_payment_id).unwrap().amount_msat, + // Some(invoice_amount_1_msat) + //); + //assert_eq!(node_b.payment(&node_a_payment_id).unwrap().status, PaymentStatus::Succeeded); + //assert_eq!(node_b.payment(&node_a_payment_id).unwrap().direction, PaymentDirection::Inbound); + //assert_eq!( + // node_b.payment(&node_a_payment_id).unwrap().amount_msat, + // Some(invoice_amount_1_msat) + //); // Test under-/overpayment let invoice_amount_2_msat = 2500_000; @@ -886,28 +898,18 @@ pub(crate) async fn do_channel_full_cycle( let overpaid_amount_msat = invoice_amount_2_msat + 100; println!("\nA overpaid send"); - let payment_id = + let node_a_payment_id = node_a.bolt11_payment().send_using_amount(&invoice, overpaid_amount_msat, None).unwrap(); expect_event!(node_a, PaymentSuccessful); - let received_amount = match node_b.next_event_async().await { - ref e @ Event::PaymentReceived { amount_msat, .. } => { - println!("{} got event {:?}", std::stringify!(node_b), e); - node_b.event_handled().unwrap(); - amount_msat - }, - ref e => { - panic!("{} got unexpected event!: {:?}", std::stringify!(node_b), e); - }, - }; - assert_eq!(received_amount, overpaid_amount_msat); - assert_eq!(node_a.payment(&payment_id).unwrap().status, PaymentStatus::Succeeded); - assert_eq!(node_a.payment(&payment_id).unwrap().direction, PaymentDirection::Outbound); - assert_eq!(node_a.payment(&payment_id).unwrap().amount_msat, Some(overpaid_amount_msat)); - assert!(matches!(node_a.payment(&payment_id).unwrap().kind, PaymentKind::Bolt11 { .. })); - assert_eq!(node_b.payment(&payment_id).unwrap().status, PaymentStatus::Succeeded); - assert_eq!(node_b.payment(&payment_id).unwrap().direction, PaymentDirection::Inbound); - assert_eq!(node_b.payment(&payment_id).unwrap().amount_msat, Some(overpaid_amount_msat)); - assert!(matches!(node_b.payment(&payment_id).unwrap().kind, PaymentKind::Bolt11 { .. })); + let node_b_payment_id = expect_payment_received_event!(node_b, overpaid_amount_msat); + assert_eq!(node_a.payment(&node_a_payment_id).unwrap().status, PaymentStatus::Succeeded); + assert_eq!(node_a.payment(&node_a_payment_id).unwrap().direction, PaymentDirection::Outbound); + assert_eq!(node_a.payment(&node_a_payment_id).unwrap().amount_msat, Some(overpaid_amount_msat)); + assert!(matches!(node_a.payment(&node_a_payment_id).unwrap().kind, PaymentKind::Bolt11 { .. })); + assert_eq!(node_b.payment(&node_b_payment_id).unwrap().status, PaymentStatus::Succeeded); + assert_eq!(node_b.payment(&node_b_payment_id).unwrap().direction, PaymentDirection::Inbound); + assert_eq!(node_b.payment(&node_b_payment_id).unwrap().amount_msat, Some(overpaid_amount_msat)); + assert!(matches!(node_b.payment(&node_b_payment_id).unwrap().kind, PaymentKind::Bolt11 { .. })); // Test "zero-amount" invoice payment println!("\nB receive_variable_amount_payment"); @@ -921,31 +923,28 @@ pub(crate) async fn do_channel_full_cycle( node_a.bolt11_payment().send(&variable_amount_invoice, None) ); println!("\nA send_using_amount"); - let payment_id = node_a + let node_a_payment_id = node_a .bolt11_payment() .send_using_amount(&variable_amount_invoice, determined_amount_msat, None) .unwrap(); expect_event!(node_a, PaymentSuccessful); - let received_amount = match node_b.next_event_async().await { - ref e @ Event::PaymentReceived { amount_msat, .. } => { - println!("{} got event {:?}", std::stringify!(node_b), e); - node_b.event_handled().unwrap(); - amount_msat - }, - ref e => { - panic!("{} got unexpected event!: {:?}", std::stringify!(node_b), e); - }, - }; - assert_eq!(received_amount, determined_amount_msat); - assert_eq!(node_a.payment(&payment_id).unwrap().status, PaymentStatus::Succeeded); - assert_eq!(node_a.payment(&payment_id).unwrap().direction, PaymentDirection::Outbound); - assert_eq!(node_a.payment(&payment_id).unwrap().amount_msat, Some(determined_amount_msat)); - assert!(matches!(node_a.payment(&payment_id).unwrap().kind, PaymentKind::Bolt11 { .. })); - assert_eq!(node_b.payment(&payment_id).unwrap().status, PaymentStatus::Succeeded); - assert_eq!(node_b.payment(&payment_id).unwrap().direction, PaymentDirection::Inbound); - assert_eq!(node_b.payment(&payment_id).unwrap().amount_msat, Some(determined_amount_msat)); - assert!(matches!(node_b.payment(&payment_id).unwrap().kind, PaymentKind::Bolt11 { .. })); + let node_b_payment_id = expect_payment_received_event!(node_b, determined_amount_msat); + + assert_eq!(node_a.payment(&node_a_payment_id).unwrap().status, PaymentStatus::Succeeded); + assert_eq!(node_a.payment(&node_a_payment_id).unwrap().direction, PaymentDirection::Outbound); + assert_eq!( + node_a.payment(&node_a_payment_id).unwrap().amount_msat, + Some(determined_amount_msat) + ); + assert!(matches!(node_a.payment(&node_a_payment_id).unwrap().kind, PaymentKind::Bolt11 { .. })); + assert_eq!(node_b.payment(&node_b_payment_id).unwrap().status, PaymentStatus::Succeeded); + assert_eq!(node_b.payment(&node_b_payment_id).unwrap().direction, PaymentDirection::Inbound); + assert_eq!( + node_b.payment(&node_b_payment_id).unwrap().amount_msat, + Some(determined_amount_msat) + ); + assert!(matches!(node_b.payment(&node_b_payment_id).unwrap().kind, PaymentKind::Bolt11 { .. })); // Test claiming manually registered payments. let invoice_amount_3_msat = 5_532_000; @@ -962,17 +961,14 @@ pub(crate) async fn do_channel_full_cycle( .unwrap(); let manual_payment_id = node_a.bolt11_payment().send(&manual_invoice, None).unwrap(); - let claimable_amount_msat = expect_payment_claimable_event!( - node_b, - manual_payment_id, - manual_payment_hash, - invoice_amount_3_msat - ); + let (node_b_claimable_payment_id, claimable_amount_msat) = + expect_payment_claimable_event!(node_b, manual_payment_hash, invoice_amount_3_msat); node_b .bolt11_payment() - .claim_for_hash(manual_payment_hash, claimable_amount_msat, manual_preimage) + .claim_for_id(node_b_claimable_payment_id, claimable_amount_msat, manual_preimage) .unwrap(); - expect_payment_received_event!(node_b, claimable_amount_msat); + let node_b_manual_payment_id = expect_payment_received_event!(node_b, claimable_amount_msat); + assert_eq!(node_b_manual_payment_id, node_b_claimable_payment_id); expect_payment_successful_event!(node_a, manual_payment_id, None); assert_eq!(node_a.payment(&manual_payment_id).unwrap().status, PaymentStatus::Succeeded); assert_eq!(node_a.payment(&manual_payment_id).unwrap().direction, PaymentDirection::Outbound); @@ -981,13 +977,19 @@ pub(crate) async fn do_channel_full_cycle( Some(invoice_amount_3_msat) ); assert!(matches!(node_a.payment(&manual_payment_id).unwrap().kind, PaymentKind::Bolt11 { .. })); - assert_eq!(node_b.payment(&manual_payment_id).unwrap().status, PaymentStatus::Succeeded); - assert_eq!(node_b.payment(&manual_payment_id).unwrap().direction, PaymentDirection::Inbound); + assert_eq!(node_b.payment(&node_b_manual_payment_id).unwrap().status, PaymentStatus::Succeeded); assert_eq!( - node_b.payment(&manual_payment_id).unwrap().amount_msat, + node_b.payment(&node_b_manual_payment_id).unwrap().direction, + PaymentDirection::Inbound + ); + assert_eq!( + node_b.payment(&node_b_manual_payment_id).unwrap().amount_msat, Some(invoice_amount_3_msat) ); - assert!(matches!(node_b.payment(&manual_payment_id).unwrap().kind, PaymentKind::Bolt11 { .. })); + assert!(matches!( + node_b.payment(&node_b_manual_payment_id).unwrap().kind, + PaymentKind::Bolt11 { .. } + )); // Test failing manually registered payments. let invoice_amount_4_msat = 5_532_000; @@ -1005,13 +1007,9 @@ pub(crate) async fn do_channel_full_cycle( .unwrap(); let manual_fail_payment_id = node_a.bolt11_payment().send(&manual_fail_invoice, None).unwrap(); - expect_payment_claimable_event!( - node_b, - manual_fail_payment_id, - manual_fail_payment_hash, - invoice_amount_4_msat - ); - node_b.bolt11_payment().fail_for_hash(manual_fail_payment_hash).unwrap(); + let (node_b_manual_fail_payment_id, _) = + expect_payment_claimable_event!(node_b, manual_fail_payment_hash, invoice_amount_4_msat); + node_b.bolt11_payment().fail_for_id(node_b_manual_fail_payment_id).unwrap(); expect_event!(node_a, PaymentFailed); assert_eq!(node_a.payment(&manual_fail_payment_id).unwrap().status, PaymentStatus::Failed); assert_eq!( @@ -1026,17 +1024,20 @@ pub(crate) async fn do_channel_full_cycle( node_a.payment(&manual_fail_payment_id).unwrap().kind, PaymentKind::Bolt11 { .. } )); - assert_eq!(node_b.payment(&manual_fail_payment_id).unwrap().status, PaymentStatus::Failed); assert_eq!( - node_b.payment(&manual_fail_payment_id).unwrap().direction, + node_b.payment(&node_b_manual_fail_payment_id).unwrap().status, + PaymentStatus::Failed + ); + assert_eq!( + node_b.payment(&node_b_manual_fail_payment_id).unwrap().direction, PaymentDirection::Inbound ); assert_eq!( - node_b.payment(&manual_fail_payment_id).unwrap().amount_msat, + node_b.payment(&node_b_manual_fail_payment_id).unwrap().amount_msat, Some(invoice_amount_4_msat) ); assert!(matches!( - node_b.payment(&manual_fail_payment_id).unwrap().kind, + node_b.payment(&node_b_manual_fail_payment_id).unwrap().kind, PaymentKind::Bolt11 { .. } )); @@ -1044,36 +1045,57 @@ pub(crate) async fn do_channel_full_cycle( println!("\nA send_spontaneous_payment"); let keysend_amount_msat = 2500_000; let custom_tlvs = vec![CustomTlvRecord { type_num: 13377331, value: vec![1, 2, 3] }]; - let keysend_payment_id = node_a + let node_a_keysend_payment_id = node_a .spontaneous_payment() .send_with_custom_tlvs(keysend_amount_msat, node_b.node_id(), None, custom_tlvs.clone()) .unwrap(); expect_event!(node_a, PaymentSuccessful); let next_event = node_b.next_event_async().await; - let (received_keysend_amount, received_custom_records) = match next_event { - ref e @ Event::PaymentReceived { amount_msat, ref custom_records, .. } => { - println!("{} got event {:?}", std::stringify!(node_b), e); - node_b.event_handled().unwrap(); - (amount_msat, custom_records) - }, - ref e => { - panic!("{} got unexpected event!: {:?}", std::stringify!(node_b), e); - }, - }; + let (node_b_keysend_payment_id, received_keysend_amount, received_custom_records) = + match next_event { + ref e @ Event::PaymentReceived { + payment_id, amount_msat, ref custom_records, .. + } => { + println!("{} got event {:?}", std::stringify!(node_b), e); + node_b.event_handled().unwrap(); + (payment_id, amount_msat, custom_records) + }, + ref e => { + panic!("{} got unexpected event!: {:?}", std::stringify!(node_b), e); + }, + }; assert_eq!(received_keysend_amount, keysend_amount_msat); - assert_eq!(node_a.payment(&keysend_payment_id).unwrap().status, PaymentStatus::Succeeded); - assert_eq!(node_a.payment(&keysend_payment_id).unwrap().direction, PaymentDirection::Outbound); - assert_eq!(node_a.payment(&keysend_payment_id).unwrap().amount_msat, Some(keysend_amount_msat)); + assert_eq!( + node_a.payment(&node_a_keysend_payment_id).unwrap().status, + PaymentStatus::Succeeded + ); + assert_eq!( + node_a.payment(&node_a_keysend_payment_id).unwrap().direction, + PaymentDirection::Outbound + ); + assert_eq!( + node_a.payment(&node_a_keysend_payment_id).unwrap().amount_msat, + Some(keysend_amount_msat) + ); assert!(matches!( - node_a.payment(&keysend_payment_id).unwrap().kind, + node_a.payment(&node_a_keysend_payment_id).unwrap().kind, PaymentKind::Spontaneous { .. } )); assert_eq!(received_custom_records, &custom_tlvs); - assert_eq!(node_b.payment(&keysend_payment_id).unwrap().status, PaymentStatus::Succeeded); - assert_eq!(node_b.payment(&keysend_payment_id).unwrap().direction, PaymentDirection::Inbound); - assert_eq!(node_b.payment(&keysend_payment_id).unwrap().amount_msat, Some(keysend_amount_msat)); + assert_eq!( + node_b.payment(&node_b_keysend_payment_id).unwrap().status, + PaymentStatus::Succeeded + ); + assert_eq!( + node_b.payment(&node_b_keysend_payment_id).unwrap().direction, + PaymentDirection::Inbound + ); + assert_eq!( + node_b.payment(&node_b_keysend_payment_id).unwrap().amount_msat, + Some(keysend_amount_msat) + ); assert!(matches!( - node_b.payment(&keysend_payment_id).unwrap().kind, + node_b.payment(&node_b_keysend_payment_id).unwrap().kind, PaymentKind::Spontaneous { .. } )); assert_eq!( @@ -1082,7 +1104,7 @@ pub(crate) async fn do_channel_full_cycle( ); assert_eq!( node_b.list_payments_with_filter(|p| matches!(p.kind, PaymentKind::Bolt11 { .. })).len(), - 6 + 5 ); assert_eq!( node_a diff --git a/tests/integration_tests_rust.rs b/tests/integration_tests_rust.rs index f779cb6ce..999260d31 100644 --- a/tests/integration_tests_rust.rs +++ b/tests/integration_tests_rust.rs @@ -1829,13 +1829,13 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) { // Have the payer_node pay the invoice, to check regular forwards service_node -> client_node // are working as expected. println!("Paying regular invoice!"); - let payment_id = payer_node.bolt11_payment().send(&invoice, None).unwrap(); - expect_payment_successful_event!(payer_node, payment_id, None); + let payer_payment_id = payer_node.bolt11_payment().send(&invoice, None).unwrap(); + expect_payment_successful_event!(payer_node, payer_payment_id, None); expect_event!(service_node, PaymentForwarded); expect_payment_received_event!(client_node, amount_msat); //////////////////////////////////////////////////////////////////////////// - // receive_via_jit_channel_for_hash and claim_for_hash + // receive_via_jit_channel_for_hash and claim_for_id //////////////////////////////////////////////////////////////////////////// println!("Generating JIT invoice!"); // Increase the amount to make sure it does not fit into the existing channels. @@ -1855,7 +1855,7 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) { // Have the payer_node pay the invoice, therby triggering channel open service_node -> client_node. println!("Paying JIT invoice!"); - let payment_id = payer_node.bolt11_payment().send(&jit_invoice, None).unwrap(); + let payer_payment_id = payer_node.bolt11_payment().send(&jit_invoice, None).unwrap(); expect_channel_pending_event!(service_node, client_node.node_id()); expect_channel_ready_event!(service_node, client_node.node_id()); expect_channel_pending_event!(client_node, service_node.node_id()); @@ -1863,22 +1863,22 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) { let service_fee_msat = (jit_amount_msat * channel_opening_fee_ppm as u64) / 1_000_000; let expected_received_amount_msat = jit_amount_msat - service_fee_msat; - let claimable_amount_msat = expect_payment_claimable_event!( + let (client_claimable_payment_id, claimable_amount_msat) = expect_payment_claimable_event!( client_node, - payment_id, manual_payment_hash, expected_received_amount_msat ); println!("Claiming payment!"); client_node .bolt11_payment() - .claim_for_hash(manual_payment_hash, claimable_amount_msat, manual_preimage) + .claim_for_id(client_payment_id, claimable_amount_msat, manual_preimage) .unwrap(); expect_event!(service_node, PaymentForwarded); - expect_payment_successful_event!(payer_node, payment_id, None); + expect_payment_successful_event!(payer_node, payer_payment_id, None); let client_payment_id = expect_payment_received_event!(client_node, expected_received_amount_msat); + assert_eq!(client_payment_id, client_claimable_payment_id); let client_payment = client_node.payment(&client_payment_id).unwrap(); match client_payment.kind { PaymentKind::Bolt11Jit { counterparty_skimmed_fee_msat, .. } => { @@ -1888,7 +1888,7 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) { } //////////////////////////////////////////////////////////////////////////// - // receive_via_jit_channel_for_hash and fail_for_hash + // receive_via_jit_channel_for_hash and fail_for_id //////////////////////////////////////////////////////////////////////////// println!("Generating JIT invoice!"); // Increase the amount to make sure it does not fit into the existing channels. @@ -1908,7 +1908,7 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) { // Have the payer_node pay the invoice, therby triggering channel open service_node -> client_node. println!("Paying JIT invoice!"); - let payment_id = payer_node.bolt11_payment().send(&jit_invoice, None).unwrap(); + payer_node.bolt11_payment().send(&jit_invoice, None).unwrap(); expect_channel_pending_event!(service_node, client_node.node_id()); expect_channel_ready_event!(service_node, client_node.node_id()); expect_channel_pending_event!(client_node, service_node.node_id()); @@ -1916,17 +1916,16 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) { let service_fee_msat = (jit_amount_msat * channel_opening_fee_ppm as u64) / 1_000_000; let expected_received_amount_msat = jit_amount_msat - service_fee_msat; - expect_payment_claimable_event!( + let (client_payment_id, _) = expect_payment_claimable_event!( client_node, - payment_id, manual_payment_hash, expected_received_amount_msat ); println!("Failing payment!"); - client_node.bolt11_payment().fail_for_hash(manual_payment_hash).unwrap(); + client_node.bolt11_payment().fail_for_id(client_payment_id).unwrap(); expect_event!(payer_node, PaymentFailed); - assert_eq!(client_node.payment(&payment_id).unwrap().status, PaymentStatus::Failed); + assert_eq!(client_node.payment(&client_payment_id).unwrap().status, PaymentStatus::Failed); } #[tokio::test(flavor = "multi_thread", worker_threads = 1)] @@ -2158,14 +2157,13 @@ async fn lsps2_client_trusts_lsp() { let _ = expect_payment_claimable_event!( client_node, - payment_id, manual_payment_hash, expected_received_amount_msat ); client_node .bolt11_payment() - .claim_for_hash(manual_payment_hash, jit_amount_msat, manual_preimage) + .claim_for_id(payment_id, jit_amount_msat, manual_preimage) .unwrap(); expect_payment_successful_event!(payer_node, payment_id, None);