diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index 09d1d9b6ba8..edf304b5467 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -121,8 +121,8 @@ impl OffersMessageHandler for TestOffersMessageHandler { struct TestAsyncPaymentsMessageHandler {} impl AsyncPaymentsMessageHandler for TestAsyncPaymentsMessageHandler { - fn held_htlc_available( - &self, message: HeldHtlcAvailable, responder: Option, + fn handle_held_htlc_available( + &self, _message: HeldHtlcAvailable, responder: Option, ) -> Option<(ReleaseHeldHtlc, ResponseInstruction)> { let responder = match responder { Some(resp) => resp, @@ -130,7 +130,7 @@ impl AsyncPaymentsMessageHandler for TestAsyncPaymentsMessageHandler { }; Some((ReleaseHeldHtlc {}, responder.respond())) } - fn release_held_htlc(&self, _message: ReleaseHeldHtlc, _context: AsyncPaymentsContext) {} + fn handle_release_held_htlc(&self, _message: ReleaseHeldHtlc, _context: AsyncPaymentsContext) {} } #[derive(Debug)] diff --git a/lightning/src/events/mod.rs b/lightning/src/events/mod.rs index c450c1d91cd..3538aa36780 100644 --- a/lightning/src/events/mod.rs +++ b/lightning/src/events/mod.rs @@ -560,11 +560,15 @@ pub enum PaymentFailureReason { /// [`PaymentParameters::expiry_time`]: crate::routing::router::PaymentParameters::expiry_time /// [`InvoiceRequestExpired`]: Self::InvoiceRequestExpired PaymentExpired, - /// We failed to find a route while retrying the payment. + /// We failed to find a route while sending or retrying the payment. /// /// Note that this generally indicates that we've exhausted the available set of possible /// routes - we tried the payment over a few routes but were not able to find any further /// candidate routes beyond those. + /// + /// Also used for [`BlindedPathCreationFailed`] when downgrading to versions prior to 0.0.124. + /// + /// [`BlindedPathCreationFailed`]: Self::BlindedPathCreationFailed RouteNotFound, /// This error should generally never happen. This likely means that there is a problem with /// your router. @@ -577,6 +581,12 @@ pub enum PaymentFailureReason { /// /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest InvoiceRequestRejected, + /// Failed to create a blinded path back to ourselves. + /// We attempted to initiate payment to a static invoice but failed to create a reply path for our + /// [`HeldHtlcAvailable`] message. + /// + /// [`HeldHtlcAvailable`]: crate::onion_message::async_payments::HeldHtlcAvailable + BlindedPathCreationFailed, } impl_writeable_tlv_based_enum_upgradable!(PaymentFailureReason, @@ -587,6 +597,7 @@ impl_writeable_tlv_based_enum_upgradable!(PaymentFailureReason, (4, RetriesExhausted) => {}, (5, InvoiceRequestRejected) => {}, (6, PaymentExpired) => {}, + (7, BlindedPathCreationFailed) => {}, (8, RouteNotFound) => {}, (10, UnexpectedError) => {}, ); @@ -1651,6 +1662,8 @@ impl Writeable for Event { &Some(PaymentFailureReason::RetriesExhausted), Some(PaymentFailureReason::InvoiceRequestRejected) => &Some(PaymentFailureReason::RecipientRejected), + Some(PaymentFailureReason::BlindedPathCreationFailed) => + &Some(PaymentFailureReason::RouteNotFound) }; write_tlv_fields!(writer, { (0, payment_id, required), diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index 79b24e06db3..aa399b9d4d6 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -318,7 +318,7 @@ fn do_forward_checks_failure(check: ForwardCheckFail, intro_fails: bool) { let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); let cur_height = nodes[0].best_block_info().1; let (mut onion_payloads, ..) = onion_utils::build_onion_payloads( - &route.paths[0], amt_msat, &recipient_onion_fields, cur_height, &None).unwrap(); + &route.paths[0], amt_msat, &recipient_onion_fields, cur_height, &None, None).unwrap(); // Remove the receive payload so the blinded forward payload is encoded as a final payload // (i.e. next_hop_hmac == [0; 32]) onion_payloads.pop(); @@ -897,7 +897,7 @@ fn do_multi_hop_receiver_fail(check: ReceiveCheckFail) { let cur_height = nodes[0].best_block_info().1; let recipient_onion_fields = RecipientOnionFields::spontaneous_empty(); let (mut onion_payloads, ..) = onion_utils::build_onion_payloads( - &route.paths[0], amt_msat, &recipient_onion_fields, cur_height, &None).unwrap(); + &route.paths[0], amt_msat, &recipient_onion_fields, cur_height, &None, None).unwrap(); let update_add = &mut payment_event_1_2.msgs[0]; onion_payloads.last_mut().map(|p| { @@ -1447,7 +1447,7 @@ fn route_blinding_spec_test_vector() { }), }; let cur_height = 747_000; - let (bob_onion, _, _) = onion_utils::create_payment_onion(&secp_ctx, &path, &session_priv, amt_msat, &RecipientOnionFields::spontaneous_empty(), cur_height, &PaymentHash([0; 32]), &None, [0; 32]).unwrap(); + let (bob_onion, _, _) = onion_utils::create_payment_onion(&secp_ctx, &path, &session_priv, amt_msat, &RecipientOnionFields::spontaneous_empty(), cur_height, &PaymentHash([0; 32]), &None, None, [0; 32]).unwrap(); struct TestEcdhSigner { node_secret: SecretKey, diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index f31c23b5a67..891259881b3 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -4306,14 +4306,14 @@ where let _lck = self.total_consistency_lock.read().unwrap(); self.send_payment_along_path(SendAlongPathArgs { path, payment_hash, recipient_onion: &recipient_onion, total_value, - cur_height, payment_id, keysend_preimage, session_priv_bytes + cur_height, payment_id, keysend_preimage, invoice_request: None, session_priv_bytes }) } fn send_payment_along_path(&self, args: SendAlongPathArgs) -> Result<(), APIError> { let SendAlongPathArgs { path, payment_hash, recipient_onion, total_value, cur_height, payment_id, keysend_preimage, - session_priv_bytes + invoice_request, session_priv_bytes } = args; // The top-level caller should hold the total_consistency_lock read lock. debug_assert!(self.total_consistency_lock.try_write().is_err()); @@ -4322,7 +4322,7 @@ where let (onion_packet, htlc_msat, htlc_cltv) = onion_utils::create_payment_onion( &self.secp_ctx, &path, &session_priv, total_value, recipient_onion, cur_height, - payment_hash, keysend_preimage, prng_seed + payment_hash, keysend_preimage, invoice_request, prng_seed ).map_err(|e| { let logger = WithContext::from(&self.logger, Some(path.hops.first().unwrap().pubkey), None, Some(*payment_hash)); log_error!(logger, "Failed to build an onion for path for payment hash {}", payment_hash); @@ -4590,7 +4590,7 @@ where ) { Ok(paths) => paths, Err(()) => { - self.abandon_payment_with_reason(payment_id, PaymentFailureReason::RouteNotFound); + self.abandon_payment_with_reason(payment_id, PaymentFailureReason::BlindedPathCreationFailed); res = Err(Bolt12PaymentError::BlindedPathCreationFailed); return NotifyOption::DoPersist } @@ -11474,13 +11474,13 @@ where MR::Target: MessageRouter, L::Target: Logger, { - fn held_htlc_available( + fn handle_held_htlc_available( &self, _message: HeldHtlcAvailable, _responder: Option ) -> Option<(ReleaseHeldHtlc, ResponseInstruction)> { None } - fn release_held_htlc(&self, _message: ReleaseHeldHtlc, _context: AsyncPaymentsContext) { + fn handle_release_held_htlc(&self, _message: ReleaseHeldHtlc, _context: AsyncPaymentsContext) { #[cfg(async_payments)] { let AsyncPaymentsContext::OutboundPayment { payment_id, hmac, nonce } = _context; if payment_id.verify_for_async_payment(hmac, nonce, &self.inbound_payment_key).is_err() { return } diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index ee73b30baef..79ce43507d8 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -1438,7 +1438,7 @@ fn test_fee_spike_violation_fails_htlc() { let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap(); let recipient_onion_fields = RecipientOnionFields::secret_only(payment_secret); let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], - 3460001, &recipient_onion_fields, cur_height, &None).unwrap(); + 3460001, &recipient_onion_fields, cur_height, &None, None).unwrap(); let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash).unwrap(); let msg = msgs::UpdateAddHTLC { channel_id: chan.2, @@ -1637,7 +1637,7 @@ fn test_chan_reserve_violation_inbound_htlc_outbound_channel() { let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap(); let recipient_onion_fields = RecipientOnionFields::secret_only(payment_secret); let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], - 700_000, &recipient_onion_fields, cur_height, &None).unwrap(); + 700_000, &recipient_onion_fields, cur_height, &None, None).unwrap(); let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash).unwrap(); let msg = msgs::UpdateAddHTLC { channel_id: chan.2, @@ -1817,7 +1817,7 @@ fn test_chan_reserve_violation_inbound_htlc_inbound_chan() { let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route_2.paths[0], &session_priv).unwrap(); let recipient_onion_fields = RecipientOnionFields::spontaneous_empty(); let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads( - &route_2.paths[0], recv_value_2, &recipient_onion_fields, cur_height, &None).unwrap(); + &route_2.paths[0], recv_value_2, &recipient_onion_fields, cur_height, &None, None).unwrap(); let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash_1).unwrap(); let msg = msgs::UpdateAddHTLC { channel_id: chan.2, @@ -3556,7 +3556,7 @@ fn fail_backward_pending_htlc_upon_channel_failure() { let current_height = nodes[1].node.best_block.read().unwrap().height + 1; let recipient_onion_fields = RecipientOnionFields::secret_only(payment_secret); let (onion_payloads, _amount_msat, cltv_expiry) = onion_utils::build_onion_payloads( - &route.paths[0], 50_000, &recipient_onion_fields, current_height, &None).unwrap(); + &route.paths[0], 50_000, &recipient_onion_fields, current_height, &None, None).unwrap(); let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap(); let onion_routing_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash).unwrap(); @@ -6551,7 +6551,7 @@ fn test_update_add_htlc_bolt2_receiver_check_max_htlc_limit() { let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::signing_only(), &route.paths[0], &session_priv).unwrap(); let recipient_onion_fields = RecipientOnionFields::secret_only(our_payment_secret); let (onion_payloads, _htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads( - &route.paths[0], send_amt, &recipient_onion_fields, cur_height, &None).unwrap(); + &route.paths[0], send_amt, &recipient_onion_fields, cur_height, &None, None).unwrap(); let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash).unwrap(); let mut msg = msgs::UpdateAddHTLC { @@ -8294,7 +8294,7 @@ fn test_onion_value_mpp_set_calculation() { let mut onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); let recipient_onion_fields = RecipientOnionFields::secret_only(our_payment_secret); let (mut onion_payloads, _, _) = onion_utils::build_onion_payloads(&route.paths[0], 100_000, - &recipient_onion_fields, height + 1, &None).unwrap(); + &recipient_onion_fields, height + 1, &None, None).unwrap(); // Edit amt_to_forward to simulate the sender having set // the final amount and the routing node taking less fee if let msgs::OutboundOnionPayload::Receive { diff --git a/lightning/src/ln/max_payment_path_len_tests.rs b/lightning/src/ln/max_payment_path_len_tests.rs index 8c24ef36339..af30003ee5d 100644 --- a/lightning/src/ln/max_payment_path_len_tests.rs +++ b/lightning/src/ln/max_payment_path_len_tests.rs @@ -110,7 +110,7 @@ fn large_payment_metadata() { let secp_ctx = Secp256k1::signing_only(); route_0_1.paths[0].hops[0].fee_msat = MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY; route_0_1.paths[0].hops[0].cltv_expiry_delta = DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA; - let err = onion_utils::create_payment_onion(&secp_ctx, &route_0_1.paths[0], &test_utils::privkey(42), MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY, &recipient_onion_too_large_md, nodes[0].best_block_info().1 + DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, &payment_hash, &None, [0; 32]).unwrap_err(); + let err = onion_utils::create_payment_onion(&secp_ctx, &route_0_1.paths[0], &test_utils::privkey(42), MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY, &recipient_onion_too_large_md, nodes[0].best_block_info().1 + DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, &payment_hash, &None, None, [0; 32]).unwrap_err(); match err { APIError::InvalidRoute { err } => { assert_eq!(err, "Route size too large considering onion data"); @@ -184,6 +184,7 @@ fn one_hop_blinded_path_with_custom_tlv() { encrypted_tlvs: &blinded_path.blinded_hops()[0].encrypted_payload, intro_node_blinding_point: Some(blinded_path.blinding_point()), keysend_preimage: None, + invoice_request: None, custom_tlvs: &Vec::new() }.serialized_length(); let max_custom_tlv_len = 1300 @@ -275,7 +276,7 @@ fn blinded_path_with_custom_tlv() { let reserved_packet_bytes_without_custom_tlv: usize = onion_utils::build_onion_payloads( &route.paths[0], MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY, &RecipientOnionFields::spontaneous_empty(), - nodes[0].best_block_info().1 + DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, &None + nodes[0].best_block_info().1 + DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, &None, None ) .unwrap() .0 @@ -317,7 +318,7 @@ fn blinded_path_with_custom_tlv() { let secp_ctx = Secp256k1::signing_only(); route.paths[0].hops[0].fee_msat = MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY; route.paths[0].hops[0].cltv_expiry_delta = DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA; - let err = onion_utils::create_payment_onion(&secp_ctx, &route.paths[0], &test_utils::privkey(42), MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY, &recipient_onion_too_large_custom_tlv, nodes[0].best_block_info().1 + DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, &payment_hash, &None, [0; 32]).unwrap_err(); + let err = onion_utils::create_payment_onion(&secp_ctx, &route.paths[0], &test_utils::privkey(42), MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY, &recipient_onion_too_large_custom_tlv, nodes[0].best_block_info().1 + DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, &payment_hash, &None, None, [0; 32]).unwrap_err(); match err { APIError::InvalidRoute { err } => { assert_eq!(err, "Route size too large considering onion data"); diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 4837a40e104..6f508efa636 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -1747,6 +1747,7 @@ pub struct FinalOnionHopData { mod fuzzy_internal_msgs { use bitcoin::secp256k1::PublicKey; use crate::blinded_path::payment::{BlindedPaymentPath, PaymentConstraints, PaymentContext, PaymentRelay}; + use crate::offers::invoice_request::InvoiceRequest; use crate::types::payment::{PaymentPreimage, PaymentSecret}; use crate::types::features::{BlindedHopFeatures, Bolt12InvoiceFeatures}; use super::{FinalOnionHopData, TrampolineOnionPacket}; @@ -1827,6 +1828,7 @@ mod fuzzy_internal_msgs { intro_node_blinding_point: Option, // Set if the introduction node of the blinded path is the final node keysend_preimage: Option, custom_tlvs: &'a Vec<(u64, Vec)>, + invoice_request: Option<&'a InvoiceRequest>, } } @@ -2760,13 +2762,17 @@ impl<'a> Writeable for OutboundOnionPayload<'a> { }, Self::BlindedReceive { sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, encrypted_tlvs, - intro_node_blinding_point, keysend_preimage, ref custom_tlvs, + intro_node_blinding_point, keysend_preimage, ref invoice_request, ref custom_tlvs, } => { // We need to update [`ln::outbound_payment::RecipientOnionFields::with_custom_tlvs`] // to reject any reserved types in the experimental range if new ones are ever // standardized. + let invoice_request_tlv = invoice_request.map(|invreq| (77_777, invreq.encode())); // TODO: update TLV type once the async payments spec is merged let keysend_tlv = keysend_preimage.map(|preimage| (5482373484, preimage.encode())); - let mut custom_tlvs: Vec<&(u64, Vec)> = custom_tlvs.iter().chain(keysend_tlv.iter()).collect(); + let mut custom_tlvs: Vec<&(u64, Vec)> = custom_tlvs.iter() + .chain(invoice_request_tlv.iter()) + .chain(keysend_tlv.iter()) + .collect(); custom_tlvs.sort_unstable_by_key(|(typ, _)| *typ); _encode_varint_length_prefixed_tlv!(w, { (2, HighZeroBytesDroppedBigSize(*sender_intended_htlc_amt_msat), required), diff --git a/lightning/src/ln/onion_payment.rs b/lightning/src/ln/onion_payment.rs index 528b5e7d886..a62846f75cd 100644 --- a/lightning/src/ln/onion_payment.rs +++ b/lightning/src/ln/onion_payment.rs @@ -541,7 +541,7 @@ mod tests { let path = Path { hops, blinded_tail: None, }; let onion_keys = super::onion_utils::construct_onion_keys(&secp_ctx, &path, &session_priv).unwrap(); let (onion_payloads, ..) = super::onion_utils::build_onion_payloads( - &path, total_amt_msat, &recipient_onion, cur_height + 1, &Some(keysend_preimage) + &path, total_amt_msat, &recipient_onion, cur_height + 1, &Some(keysend_preimage), None ).unwrap(); assert!(super::onion_utils::construct_onion_packet( @@ -569,7 +569,7 @@ mod tests { let (onion, amount_msat, cltv_expiry) = create_payment_onion( &secp_ctx, &path, &session_priv, total_amt_msat, &recipient_onion, - cur_height, &payment_hash, &Some(preimage), prng_seed + cur_height, &payment_hash, &Some(preimage), None, prng_seed ).unwrap(); let msg = make_update_add_msg(amount_msat, cltv_expiry, payment_hash, onion); diff --git a/lightning/src/ln/onion_route_tests.rs b/lightning/src/ln/onion_route_tests.rs index c0253166d99..3ab03ae91fe 100644 --- a/lightning/src/ln/onion_route_tests.rs +++ b/lightning/src/ln/onion_route_tests.rs @@ -356,7 +356,7 @@ fn test_onion_failure() { let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); let recipient_onion_fields = RecipientOnionFields::spontaneous_empty(); let (mut onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads( - &route.paths[0], 40000, &recipient_onion_fields, cur_height, &None).unwrap(); + &route.paths[0], 40000, &recipient_onion_fields, cur_height, &None, None).unwrap(); let mut new_payloads = Vec::new(); for payload in onion_payloads.drain(..) { new_payloads.push(BogusOnionHopData::new(payload)); @@ -375,7 +375,7 @@ fn test_onion_failure() { let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); let recipient_onion_fields = RecipientOnionFields::spontaneous_empty(); let (mut onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads( - &route.paths[0], 40000, &recipient_onion_fields, cur_height, &None).unwrap(); + &route.paths[0], 40000, &recipient_onion_fields, cur_height, &None, None).unwrap(); let mut new_payloads = Vec::new(); for payload in onion_payloads.drain(..) { new_payloads.push(BogusOnionHopData::new(payload)); @@ -627,7 +627,7 @@ fn test_onion_failure() { let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); let recipient_onion_fields = RecipientOnionFields::spontaneous_empty(); let (onion_payloads, _, htlc_cltv) = onion_utils::build_onion_payloads( - &route.paths[0], 40000, &recipient_onion_fields, height, &None).unwrap(); + &route.paths[0], 40000, &recipient_onion_fields, height, &None, None).unwrap(); let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash).unwrap(); msg.cltv_expiry = htlc_cltv; msg.onion_routing_packet = onion_packet; @@ -964,7 +964,7 @@ fn test_always_create_tlv_format_onion_payloads() { let cur_height = nodes[0].best_block_info().1 + 1; let recipient_onion_fields = RecipientOnionFields::spontaneous_empty(); let (onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads( - &route.paths[0], 40000, &recipient_onion_fields, cur_height, &None).unwrap(); + &route.paths[0], 40000, &recipient_onion_fields, cur_height, &None, None).unwrap(); match onion_payloads[0] { msgs::OutboundOnionPayload::Forward {..} => {}, @@ -1221,7 +1221,7 @@ fn test_phantom_invalid_onion_payload() { let recipient_onion_fields = RecipientOnionFields::secret_only(payment_secret); let (mut onion_payloads, _, _) = onion_utils::build_onion_payloads( &route.paths[0], msgs::MAX_VALUE_MSAT + 1, - &recipient_onion_fields, height + 1, &None).unwrap(); + &recipient_onion_fields, height + 1, &None, None).unwrap(); // We only want to construct the onion packet for the last hop, not the entire route, so // remove the first hop's payload and its keys. onion_keys.remove(0); diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs index 208096c128e..960209c0e0a 100644 --- a/lightning/src/ln/onion_utils.rs +++ b/lightning/src/ln/onion_utils.rs @@ -13,6 +13,7 @@ use crate::crypto::streams::ChaChaReader; use crate::ln::channel::TOTAL_BITCOIN_SUPPLY_SATOSHIS; use crate::ln::channelmanager::{HTLCSource, RecipientOnionFields}; use crate::ln::msgs; +use crate::offers::invoice_request::InvoiceRequest; use crate::routing::gossip::NetworkUpdate; use crate::routing::router::{Path, RouteHop, RouteParameters}; use crate::sign::NodeSigner; @@ -179,6 +180,7 @@ pub(super) fn construct_onion_keys( pub(super) fn build_onion_payloads<'a>( path: &'a Path, total_msat: u64, recipient_onion: &'a RecipientOnionFields, starting_htlc_offset: u32, keysend_preimage: &Option, + invoice_request: Option<&'a InvoiceRequest>, ) -> Result<(Vec>, u64, u32), APIError> { let mut res: Vec = Vec::with_capacity( path.hops.len() + path.blinded_tail.as_ref().map_or(0, |t| t.hops.len()), @@ -197,6 +199,7 @@ pub(super) fn build_onion_payloads<'a>( recipient_onion, starting_htlc_offset, keysend_preimage, + invoice_request, |action, payload| match action { PayloadCallbackAction::PushBack => res.push(payload), PayloadCallbackAction::PushFront => res.insert(0, payload), @@ -218,7 +221,8 @@ enum PayloadCallbackAction { fn build_onion_payloads_callback<'a, H, B, F>( hops: H, mut blinded_tail: Option>, total_msat: u64, recipient_onion: &'a RecipientOnionFields, starting_htlc_offset: u32, - keysend_preimage: &Option, mut callback: F, + keysend_preimage: &Option, invoice_request: Option<&'a InvoiceRequest>, + mut callback: F, ) -> Result<(u64, u32), APIError> where H: DoubleEndedIterator, @@ -262,6 +266,7 @@ where encrypted_tlvs: &blinded_hop.encrypted_payload, intro_node_blinding_point: blinding_point.take(), keysend_preimage: *keysend_preimage, + invoice_request, custom_tlvs: &recipient_onion.custom_tlvs, }, ); @@ -315,7 +320,8 @@ pub(crate) const MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY: u64 = 100_000_000; pub(crate) fn set_max_path_length( route_params: &mut RouteParameters, recipient_onion: &RecipientOnionFields, - keysend_preimage: Option, best_block_height: u32, + keysend_preimage: Option, invoice_request: Option<&InvoiceRequest>, + best_block_height: u32, ) -> Result<(), ()> { const PAYLOAD_HMAC_LEN: usize = 32; let unblinded_intermed_payload_len = msgs::OutboundOnionPayload::Forward { @@ -362,6 +368,7 @@ pub(crate) fn set_max_path_length( &recipient_onion, best_block_height, &keysend_preimage, + invoice_request, |_, payload| { num_reserved_bytes = num_reserved_bytes .saturating_add(payload.serialized_length()) @@ -1157,7 +1164,8 @@ where pub fn create_payment_onion( secp_ctx: &Secp256k1, path: &Path, session_priv: &SecretKey, total_msat: u64, recipient_onion: &RecipientOnionFields, cur_block_height: u32, payment_hash: &PaymentHash, - keysend_preimage: &Option, prng_seed: [u8; 32], + keysend_preimage: &Option, invoice_request: Option<&InvoiceRequest>, + prng_seed: [u8; 32], ) -> Result<(msgs::OnionPacket, u64, u32), APIError> { let onion_keys = construct_onion_keys(&secp_ctx, &path, &session_priv).map_err(|_| { APIError::InvalidRoute { err: "Pubkey along hop was maliciously selected".to_owned() } @@ -1168,6 +1176,7 @@ pub fn create_payment_onion( recipient_onion, cur_block_height, keysend_preimage, + invoice_request, )?; let onion_packet = construct_onion_packet(onion_payloads, onion_keys, prng_seed, payment_hash) .map_err(|_| APIError::InvalidRoute { diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index 9c8998b8970..c3fde629a83 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -83,6 +83,7 @@ pub(crate) enum PendingOutboundPayment { keysend_preimage: PaymentPreimage, retry_strategy: Retry, route_params: RouteParameters, + invoice_request: InvoiceRequest, }, Retryable { retry_strategy: Option, @@ -93,6 +94,7 @@ pub(crate) enum PendingOutboundPayment { payment_secret: Option, payment_metadata: Option>, keysend_preimage: Option, + invoice_request: Option, custom_tlvs: Vec<(u64, Vec)>, pending_amt_msat: u64, /// Used to track the fee paid. Present iff the payment was serialized on 0.0.103+. @@ -641,6 +643,7 @@ impl RecipientOnionFields { for (typ, _) in custom_tlvs.iter() { if *typ < 1 << 16 { return Err(()); } if *typ == 5482373484 { return Err(()); } // keysend + if *typ == 77_777 { return Err(()); } // invoice requests for async payments match prev_type { Some(prev) if prev >= *typ => return Err(()), _ => {}, @@ -715,6 +718,7 @@ pub(super) struct SendAlongPathArgs<'a> { pub cur_height: u32, pub payment_id: PaymentId, pub keysend_preimage: &'a Option, + pub invoice_request: Option<&'a InvoiceRequest>, pub session_priv_bytes: [u8; 32], } @@ -768,7 +772,7 @@ impl OutboundPayments { F: Fn(SendAlongPathArgs) -> Result<(), APIError> { let onion_session_privs = self.add_new_pending_payment(payment_hash, recipient_onion.clone(), payment_id, None, route, None, None, entropy_source, best_block_height)?; - self.pay_route_internal(route, payment_hash, &recipient_onion, None, payment_id, None, + self.pay_route_internal(route, payment_hash, &recipient_onion, None, None, payment_id, None, onion_session_privs, node_signer, best_block_height, &send_payment_along_path) .map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e }) } @@ -813,7 +817,7 @@ impl OutboundPayments { let onion_session_privs = self.add_new_pending_payment(payment_hash, recipient_onion.clone(), payment_id, Some(preimage), &route, None, None, entropy_source, best_block_height)?; - match self.pay_route_internal(route, payment_hash, &recipient_onion, Some(preimage), + match self.pay_route_internal(route, payment_hash, &recipient_onion, Some(preimage), None, payment_id, None, onion_session_privs, node_signer, best_block_height, &send_payment_along_path ) { Ok(()) => Ok(payment_hash), @@ -878,7 +882,7 @@ impl OutboundPayments { route_params.max_total_routing_fee_msat = Some(max_fee_msat); } self.send_payment_for_bolt12_invoice_internal( - payment_id, payment_hash, None, route_params, retry_strategy, router, first_hops, + payment_id, payment_hash, None, None, route_params, retry_strategy, router, first_hops, inflight_htlcs, entropy_source, node_signer, node_id_lookup, secp_ctx, best_block_height, logger, pending_events, send_payment_along_path ) @@ -888,10 +892,10 @@ impl OutboundPayments { R: Deref, ES: Deref, NS: Deref, NL: Deref, IH, SP, L: Deref >( &self, payment_id: PaymentId, payment_hash: PaymentHash, - keysend_preimage: Option, mut route_params: RouteParameters, - retry_strategy: Retry, router: &R, first_hops: Vec, inflight_htlcs: IH, - entropy_source: &ES, node_signer: &NS, node_id_lookup: &NL, - secp_ctx: &Secp256k1, best_block_height: u32, logger: &L, + keysend_preimage: Option, invoice_request: Option<&InvoiceRequest>, + mut route_params: RouteParameters, retry_strategy: Retry, router: &R, + first_hops: Vec, inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS, + node_id_lookup: &NL, secp_ctx: &Secp256k1, best_block_height: u32, logger: &L, pending_events: &Mutex)>>, send_payment_along_path: SP, ) -> Result<(), Bolt12PaymentError> @@ -928,8 +932,9 @@ impl OutboundPayments { custom_tlvs: vec![], }; let route = match self.find_initial_route( - payment_id, payment_hash, &recipient_onion, None, &mut route_params, router, - &first_hops, &inflight_htlcs, node_signer, best_block_height, logger, + payment_id, payment_hash, &recipient_onion, keysend_preimage, invoice_request, + &mut route_params, router, &first_hops, &inflight_htlcs, node_signer, best_block_height, + logger, ) { Ok(route) => route, Err(e) => { @@ -945,25 +950,38 @@ impl OutboundPayments { }; let payment_params = Some(route_params.payment_params.clone()); - let (retryable_payment, onion_session_privs) = self.create_pending_payment( - payment_hash, recipient_onion.clone(), keysend_preimage, &route, Some(retry_strategy), - payment_params, entropy_source, best_block_height - ); - match self.pending_outbound_payments.lock().unwrap().entry(payment_id) { + let mut outbounds = self.pending_outbound_payments.lock().unwrap(); + let onion_session_privs = match outbounds.entry(payment_id) { hash_map::Entry::Occupied(entry) => match entry.get() { - PendingOutboundPayment::InvoiceReceived { .. } - | PendingOutboundPayment::StaticInvoiceReceived { .. } => { + PendingOutboundPayment::InvoiceReceived { .. } => { + let (retryable_payment, onion_session_privs) = Self::create_pending_payment( + payment_hash, recipient_onion.clone(), keysend_preimage, None, &route, + Some(retry_strategy), payment_params, entropy_source, best_block_height + ); *entry.into_mut() = retryable_payment; + onion_session_privs + }, + PendingOutboundPayment::StaticInvoiceReceived { .. } => { + let invreq = if let PendingOutboundPayment::StaticInvoiceReceived { invoice_request, .. } = entry.remove() { + invoice_request + } else { unreachable!() }; + let (retryable_payment, onion_session_privs) = Self::create_pending_payment( + payment_hash, recipient_onion.clone(), keysend_preimage, Some(invreq), &route, + Some(retry_strategy), payment_params, entropy_source, best_block_height + ); + outbounds.insert(payment_id, retryable_payment); + onion_session_privs }, _ => return Err(Bolt12PaymentError::DuplicateInvoice), }, hash_map::Entry::Vacant(_) => return Err(Bolt12PaymentError::UnexpectedInvoice), - } + }; + core::mem::drop(outbounds); let result = self.pay_route_internal( - &route, payment_hash, &recipient_onion, keysend_preimage, payment_id, - Some(route_params.final_value_msat), onion_session_privs, node_signer, - best_block_height, &send_payment_along_path + &route, payment_hash, &recipient_onion, keysend_preimage, invoice_request, payment_id, + Some(route_params.final_value_msat), onion_session_privs, node_signer, best_block_height, + &send_payment_along_path ); log_info!( logger, "Sending payment with id {} and hash {} returned {:?}", payment_id, @@ -1002,7 +1020,7 @@ impl OutboundPayments { } match self.pending_outbound_payments.lock().unwrap().entry(payment_id) { - hash_map::Entry::Occupied(mut entry) => match entry.get() { + hash_map::Entry::Occupied(mut entry) => match entry.get_mut() { PendingOutboundPayment::AwaitingInvoice { retry_strategy, retryable_invoice_request, max_total_routing_fee_msat, .. } => { @@ -1035,7 +1053,7 @@ impl OutboundPayments { if let Err(()) = onion_utils::set_max_path_length( &mut route_params, &RecipientOnionFields::spontaneous_empty(), Some(keysend_preimage), - best_block_height + Some(invreq), best_block_height ) { abandon_with_entry!(entry, PaymentFailureReason::RouteNotFound); return Err(Bolt12PaymentError::SendingFailed(RetryableSendFailure::OnionPacketSizeExceeded)) @@ -1046,6 +1064,11 @@ impl OutboundPayments { keysend_preimage, retry_strategy: *retry_strategy, route_params, + invoice_request: + retryable_invoice_request + .take() + .ok_or(Bolt12PaymentError::UnexpectedInvoice)? + .invoice_request, }; return Ok(()) }, @@ -1074,13 +1097,14 @@ impl OutboundPayments { IH: Fn() -> InFlightHtlcs, SP: Fn(SendAlongPathArgs) -> Result<(), APIError>, { - let (payment_hash, keysend_preimage, route_params, retry_strategy) = + let (payment_hash, keysend_preimage, route_params, retry_strategy, invoice_request) = match self.pending_outbound_payments.lock().unwrap().entry(payment_id) { hash_map::Entry::Occupied(entry) => match entry.get() { PendingOutboundPayment::StaticInvoiceReceived { - payment_hash, route_params, retry_strategy, keysend_preimage, .. + payment_hash, route_params, retry_strategy, keysend_preimage, invoice_request, .. } => { - (*payment_hash, *keysend_preimage, route_params.clone(), *retry_strategy) + (*payment_hash, *keysend_preimage, route_params.clone(), *retry_strategy, + invoice_request.clone()) }, _ => return Err(Bolt12PaymentError::DuplicateInvoice), }, @@ -1088,9 +1112,9 @@ impl OutboundPayments { }; self.send_payment_for_bolt12_invoice_internal( - payment_id, payment_hash, Some(keysend_preimage), route_params, retry_strategy, router, - first_hops, inflight_htlcs, entropy_source, node_signer, node_id_lookup, secp_ctx, - best_block_height, logger, pending_events, send_payment_along_path + payment_id, payment_hash, Some(keysend_preimage), Some(&invoice_request), route_params, + retry_strategy, router, first_hops, inflight_htlcs, entropy_source, node_signer, + node_id_lookup, secp_ctx, best_block_height, logger, pending_events, send_payment_along_path ) } @@ -1159,8 +1183,8 @@ impl OutboundPayments { } fn find_initial_route( - &self, payment_id: PaymentId, payment_hash: PaymentHash, - recipient_onion: &RecipientOnionFields, keysend_preimage: Option, + &self, payment_id: PaymentId, payment_hash: PaymentHash, recipient_onion: &RecipientOnionFields, + keysend_preimage: Option, invoice_request: Option<&InvoiceRequest>, route_params: &mut RouteParameters, router: &R, first_hops: &Vec, inflight_htlcs: &IH, node_signer: &NS, best_block_height: u32, logger: &L, ) -> Result @@ -1179,7 +1203,7 @@ impl OutboundPayments { } onion_utils::set_max_path_length( - route_params, recipient_onion, keysend_preimage, best_block_height + route_params, recipient_onion, keysend_preimage, invoice_request, best_block_height ) .map_err(|()| { log_error!(logger, "Can't construct an onion packet without exceeding 1300-byte onion \ @@ -1227,7 +1251,7 @@ impl OutboundPayments { SP: Fn(SendAlongPathArgs) -> Result<(), APIError>, { let route = self.find_initial_route( - payment_id, payment_hash, &recipient_onion, keysend_preimage, &mut route_params, router, + payment_id, payment_hash, &recipient_onion, keysend_preimage, None, &mut route_params, router, &first_hops, &inflight_htlcs, node_signer, best_block_height, logger, )?; @@ -1241,7 +1265,7 @@ impl OutboundPayments { })?; let res = self.pay_route_internal(&route, payment_hash, &recipient_onion, - keysend_preimage, payment_id, None, onion_session_privs, node_signer, + keysend_preimage, None, payment_id, None, onion_session_privs, node_signer, best_block_height, &send_payment_along_path); log_info!(logger, "Sending payment with id {} and hash {} returned {:?}", payment_id, payment_hash, res); @@ -1315,14 +1339,14 @@ impl OutboundPayments { } } } - let (total_msat, recipient_onion, keysend_preimage, onion_session_privs) = { + let (total_msat, recipient_onion, keysend_preimage, onion_session_privs, invoice_request) = { let mut outbounds = self.pending_outbound_payments.lock().unwrap(); match outbounds.entry(payment_id) { hash_map::Entry::Occupied(mut payment) => { match payment.get() { PendingOutboundPayment::Retryable { total_msat, keysend_preimage, payment_secret, payment_metadata, - custom_tlvs, pending_amt_msat, .. + custom_tlvs, pending_amt_msat, invoice_request, .. } => { const RETRY_OVERFLOW_PERCENTAGE: u64 = 10; let retry_amt_msat = route.get_total_amount(); @@ -1345,6 +1369,7 @@ impl OutboundPayments { custom_tlvs: custom_tlvs.clone(), }; let keysend_preimage = *keysend_preimage; + let invoice_request = invoice_request.clone(); let mut onion_session_privs = Vec::with_capacity(route.paths.len()); for _ in 0..route.paths.len() { @@ -1357,7 +1382,7 @@ impl OutboundPayments { payment.get_mut().increment_attempts(); - (total_msat, recipient_onion, keysend_preimage, onion_session_privs) + (total_msat, recipient_onion, keysend_preimage, onion_session_privs, invoice_request) }, PendingOutboundPayment::Legacy { .. } => { log_error!(logger, "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102"); @@ -1395,8 +1420,8 @@ impl OutboundPayments { } }; let res = self.pay_route_internal(&route, payment_hash, &recipient_onion, keysend_preimage, - payment_id, Some(total_msat), onion_session_privs, node_signer, best_block_height, - &send_payment_along_path); + invoice_request.as_ref(), payment_id, Some(total_msat), onion_session_privs, node_signer, + best_block_height, &send_payment_along_path); log_info!(logger, "Result retrying payment id {}: {:?}", &payment_id, res); if let Err(e) = res { self.handle_pay_route_err(e, payment_id, payment_hash, route, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path); @@ -1507,7 +1532,8 @@ impl OutboundPayments { let recipient_onion_fields = RecipientOnionFields::spontaneous_empty(); match self.pay_route_internal(&route, payment_hash, &recipient_onion_fields, - None, payment_id, None, onion_session_privs, node_signer, best_block_height, &send_payment_along_path + None, None, payment_id, None, onion_session_privs, node_signer, best_block_height, + &send_payment_along_path ) { Ok(()) => Ok((payment_hash, payment_id)), Err(e) => { @@ -1546,8 +1572,8 @@ impl OutboundPayments { match pending_outbounds.entry(payment_id) { hash_map::Entry::Occupied(_) => Err(PaymentSendFailure::DuplicatePayment), hash_map::Entry::Vacant(entry) => { - let (payment, onion_session_privs) = self.create_pending_payment( - payment_hash, recipient_onion, keysend_preimage, route, retry_strategy, + let (payment, onion_session_privs) = Self::create_pending_payment( + payment_hash, recipient_onion, keysend_preimage, None, route, retry_strategy, payment_params, entropy_source, best_block_height ); entry.insert(payment); @@ -1557,9 +1583,10 @@ impl OutboundPayments { } fn create_pending_payment( - &self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, - keysend_preimage: Option, route: &Route, retry_strategy: Option, - payment_params: Option, entropy_source: &ES, best_block_height: u32 + payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, + keysend_preimage: Option, invoice_request: Option, + route: &Route, retry_strategy: Option, payment_params: Option, + entropy_source: &ES, best_block_height: u32 ) -> (PendingOutboundPayment, Vec<[u8; 32]>) where ES::Target: EntropySource, @@ -1580,6 +1607,7 @@ impl OutboundPayments { payment_secret: recipient_onion.payment_secret, payment_metadata: recipient_onion.payment_metadata, keysend_preimage, + invoice_request, custom_tlvs: recipient_onion.custom_tlvs, starting_block_height: best_block_height, total_msat: route.get_total_amount(), @@ -1619,9 +1647,9 @@ impl OutboundPayments { fn pay_route_internal( &self, route: &Route, payment_hash: PaymentHash, recipient_onion: &RecipientOnionFields, - keysend_preimage: Option, payment_id: PaymentId, recv_value_msat: Option, - onion_session_privs: Vec<[u8; 32]>, node_signer: &NS, best_block_height: u32, - send_payment_along_path: &F + keysend_preimage: Option, invoice_request: Option<&InvoiceRequest>, + payment_id: PaymentId, recv_value_msat: Option, onion_session_privs: Vec<[u8; 32]>, + node_signer: &NS, best_block_height: u32, send_payment_along_path: &F ) -> Result<(), PaymentSendFailure> where NS::Target: NodeSigner, @@ -1674,7 +1702,7 @@ impl OutboundPayments { for (path, session_priv_bytes) in route.paths.iter().zip(onion_session_privs.into_iter()) { let mut path_res = send_payment_along_path(SendAlongPathArgs { path: &path, payment_hash: &payment_hash, recipient_onion, total_value, - cur_height, payment_id, keysend_preimage: &keysend_preimage, + cur_height, payment_id, keysend_preimage: &keysend_preimage, invoice_request, session_priv_bytes }); match path_res { @@ -1759,7 +1787,7 @@ impl OutboundPayments { F: Fn(SendAlongPathArgs) -> Result<(), APIError>, { self.pay_route_internal(route, payment_hash, &recipient_onion, - keysend_preimage, payment_id, recv_value_msat, onion_session_privs, + keysend_preimage, None, payment_id, recv_value_msat, onion_session_privs, node_signer, best_block_height, &send_payment_along_path) .map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e }) } @@ -2141,6 +2169,7 @@ impl OutboundPayments { 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 + invoice_request: None, // only used for retries, and we'll never retry on startup custom_tlvs: Vec::new(), // only used for retries, and we'll never retry on startup pending_amt_msat: path_amt, pending_fee_msat: Some(path_fee), @@ -2227,6 +2256,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment, (9, custom_tlvs, optional_vec), (10, starting_block_height, required), (11, remaining_max_total_routing_fee_msat, option), + (13, invoice_request, option), (not_written, retry_strategy, (static_value, None)), (not_written, attempts, (static_value, PaymentAttempts::new())), }, @@ -2246,13 +2276,14 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment, (2, retry_strategy, required), (4, max_total_routing_fee_msat, option), }, - // Added in 0.0.125. Prior versions will drop these outbounds on downgrade, which is safe because - // no HTLCs are in-flight. + // Added in 0.1. Prior versions will drop these outbounds on downgrade, which is safe because no + // HTLCs are in-flight. (9, StaticInvoiceReceived) => { (0, payment_hash, required), (2, keysend_preimage, required), (4, retry_strategy, required), (6, route_params, required), + (8, invoice_request, required), }, ); @@ -2267,15 +2298,19 @@ mod tests { use crate::events::{Event, PathFailure, PaymentFailureReason}; use crate::types::payment::{PaymentHash, PaymentPreimage}; use crate::ln::channelmanager::{PaymentId, RecipientOnionFields}; + use crate::ln::inbound_payment::ExpandedKey; use crate::types::features::{Bolt12InvoiceFeatures, ChannelFeatures, NodeFeatures}; use crate::ln::msgs::{ErrorAction, LightningError}; use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, PendingOutboundPayment, Retry, RetryableSendFailure, StaleExpiration}; #[cfg(feature = "std")] use crate::offers::invoice::DEFAULT_RELATIVE_EXPIRY; + use crate::offers::invoice_request::InvoiceRequest; + use crate::offers::nonce::Nonce; use crate::offers::offer::OfferBuilder; use crate::offers::test_utils::*; use crate::routing::gossip::NetworkGraph; use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters}; + use crate::sign::KeyMaterial; use crate::sync::{Arc, Mutex, RwLock}; use crate::util::errors::APIError; use crate::util::hash_tables::new_hash_map; @@ -2820,6 +2855,22 @@ mod tests { assert!(pending_events.lock().unwrap().is_empty()); } + fn dummy_invoice_request() -> InvoiceRequest { + let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let entropy = FixedEntropy {}; + let nonce = Nonce::from_entropy_source(&entropy); + let secp_ctx = Secp256k1::new(); + let payment_id = PaymentId([1; 32]); + + OfferBuilder::new(recipient_pubkey()) + .amount_msats(1000) + .build().unwrap() + .request_invoice_deriving_signing_pubkey(&expanded_key, nonce, &secp_ctx, payment_id) + .unwrap() + .build_and_sign() + .unwrap() + } + #[test] fn time_out_unreleased_async_payments() { let pending_events = Mutex::new(VecDeque::new()); @@ -2841,6 +2892,7 @@ mod tests { keysend_preimage: PaymentPreimage([0; 32]), retry_strategy: Retry::Attempts(0), route_params, + invoice_request: dummy_invoice_request(), }; outbounds.insert(payment_id, outbound); core::mem::drop(outbounds); @@ -2887,6 +2939,7 @@ mod tests { keysend_preimage: PaymentPreimage([0; 32]), retry_strategy: Retry::Attempts(0), route_params, + invoice_request: dummy_invoice_request(), }; outbounds.insert(payment_id, outbound); core::mem::drop(outbounds); diff --git a/lightning/src/ln/payment_tests.rs b/lightning/src/ln/payment_tests.rs index 7839b49be77..ca386682fa0 100644 --- a/lightning/src/ln/payment_tests.rs +++ b/lightning/src/ln/payment_tests.rs @@ -4271,7 +4271,7 @@ fn peel_payment_onion_custom_tlvs() { let (onion_routing_packet, first_hop_msat, cltv_expiry) = onion_utils::create_payment_onion( &secp_ctx, &route.paths[0], &session_priv, amt_msat, &recipient_onion, - nodes[0].best_block_info().1, &payment_hash, &Some(keysend_preimage), prng_seed + nodes[0].best_block_info().1, &payment_hash, &Some(keysend_preimage), None, prng_seed ).unwrap(); let update_add = msgs::UpdateAddHTLC { diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 2d4416e5aea..9470346f852 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -148,12 +148,12 @@ impl OffersMessageHandler for IgnoringMessageHandler { } } impl AsyncPaymentsMessageHandler for IgnoringMessageHandler { - fn held_htlc_available( + fn handle_held_htlc_available( &self, _message: HeldHtlcAvailable, _responder: Option, ) -> Option<(ReleaseHeldHtlc, ResponseInstruction)> { None } - fn release_held_htlc(&self, _message: ReleaseHeldHtlc, _context: AsyncPaymentsContext) {} + fn handle_release_held_htlc(&self, _message: ReleaseHeldHtlc, _context: AsyncPaymentsContext) {} } impl DNSResolverMessageHandler for IgnoringMessageHandler { fn handle_dnssec_query( diff --git a/lightning/src/onion_message/async_payments.rs b/lightning/src/onion_message/async_payments.rs index cc4ca5edfb0..d81010e5d5f 100644 --- a/lightning/src/onion_message/async_payments.rs +++ b/lightning/src/onion_message/async_payments.rs @@ -27,13 +27,13 @@ const RELEASE_HELD_HTLC_TLV_TYPE: u64 = 74; pub trait AsyncPaymentsMessageHandler { /// Handle a [`HeldHtlcAvailable`] message. A [`ReleaseHeldHtlc`] should be returned to release /// the held funds. - fn held_htlc_available( + fn handle_held_htlc_available( &self, message: HeldHtlcAvailable, responder: Option, ) -> Option<(ReleaseHeldHtlc, ResponseInstruction)>; /// Handle a [`ReleaseHeldHtlc`] message. If authentication of the message succeeds, an HTLC /// should be released to the corresponding payee. - fn release_held_htlc(&self, message: ReleaseHeldHtlc, context: AsyncPaymentsContext); + fn handle_release_held_htlc(&self, message: ReleaseHeldHtlc, context: AsyncPaymentsContext); /// Release any [`AsyncPaymentsMessage`]s that need to be sent. /// diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index 23fd30c9ec8..f9d73f05ff3 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -84,12 +84,12 @@ impl OffersMessageHandler for TestOffersMessageHandler { struct TestAsyncPaymentsMessageHandler {} impl AsyncPaymentsMessageHandler for TestAsyncPaymentsMessageHandler { - fn held_htlc_available( + fn handle_held_htlc_available( &self, _message: HeldHtlcAvailable, _responder: Option, ) -> Option<(ReleaseHeldHtlc, ResponseInstruction)> { None } - fn release_held_htlc(&self, _message: ReleaseHeldHtlc, _context: AsyncPaymentsContext) {} + fn handle_release_held_htlc(&self, _message: ReleaseHeldHtlc, _context: AsyncPaymentsContext) {} } struct TestDNSResolverMessageHandler {} diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 8162c55ac08..0331a1060b8 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -1623,7 +1623,7 @@ where }, #[cfg(async_payments)] ParsedOnionMessageContents::AsyncPayments(AsyncPaymentsMessage::HeldHtlcAvailable(msg)) => { - let response_instructions = self.async_payments_handler.held_htlc_available( + let response_instructions = self.async_payments_handler.handle_held_htlc_available( msg, responder ); if let Some((msg, instructions)) = response_instructions { @@ -1640,7 +1640,7 @@ where }, None => return, }; - self.async_payments_handler.release_held_htlc(msg, context); + self.async_payments_handler.handle_release_held_htlc(msg, context); }, ParsedOnionMessageContents::DNSResolver(DNSResolverMessage::DNSSECQuery(msg)) => { let response_instructions = self.dns_resolver_handler.handle_dnssec_query(msg, responder); diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 4c01bdcc4c0..b91b1b47d6e 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -613,8 +613,9 @@ impl RouteParameters { &mut self, recipient_onion: &RecipientOnionFields, is_keysend: bool, best_block_height: u32 ) -> Result<(), ()> { let keysend_preimage_opt = is_keysend.then(|| PaymentPreimage([42; 32])); + // TODO: no way to account for the invoice request here yet onion_utils::set_max_path_length( - self, recipient_onion, keysend_preimage_opt, best_block_height + self, recipient_onion, keysend_preimage_opt, None, best_block_height ) } }