From 9b3e30707ec3b1d96fc83b4c340ccf14c940497f Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Fri, 28 Jun 2024 12:11:01 -0400 Subject: [PATCH] Support including invreqs when building onion payloads Add a new invoice request parameter to onion_utils::build_onion_payloads. As of this commit it will always be passed in as None, to be updated in future commits. Per BOLTs PR 1149, when paying a static invoice we need to include our original invoice request in the HTLC onion since the recipient wouldn't have received it previously. --- lightning/src/ln/blinded_payment_tests.rs | 4 ++-- lightning/src/ln/functional_tests.rs | 12 ++++++------ lightning/src/ln/max_payment_path_len_tests.rs | 2 +- lightning/src/ln/onion_payment.rs | 2 +- lightning/src/ln/onion_route_tests.rs | 10 +++++----- lightning/src/ln/onion_utils.rs | 10 ++++++++-- 6 files changed, 23 insertions(+), 17 deletions(-) diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index 79b24e06d..3a6d996b5 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| { diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 42a57b114..cb6e8d521 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(); @@ -6548,7 +6548,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 { @@ -8291,7 +8291,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 501ddcc57..90326b9c5 100644 --- a/lightning/src/ln/max_payment_path_len_tests.rs +++ b/lightning/src/ln/max_payment_path_len_tests.rs @@ -276,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 diff --git a/lightning/src/ln/onion_payment.rs b/lightning/src/ln/onion_payment.rs index 528b5e7d8..d76c0d3a9 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( diff --git a/lightning/src/ln/onion_route_tests.rs b/lightning/src/ln/onion_route_tests.rs index c0253166d..3ab03ae91 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 68866fc03..16b8885d2 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,7 +266,7 @@ where encrypted_tlvs: &blinded_hop.encrypted_payload, intro_node_blinding_point: blinding_point.take(), keysend_preimage: *keysend_preimage, - invoice_request: None, + invoice_request, custom_tlvs: &recipient_onion.custom_tlvs, }, ); @@ -363,6 +367,7 @@ pub(crate) fn set_max_path_length( &recipient_onion, best_block_height, &keysend_preimage, + None, |_, payload| { num_reserved_bytes = num_reserved_bytes .saturating_add(payload.serialized_length()) @@ -1169,6 +1174,7 @@ pub fn create_payment_onion( recipient_onion, cur_block_height, keysend_preimage, + None, )?; let onion_packet = construct_onion_packet(onion_payloads, onion_keys, prng_seed, payment_hash) .map_err(|_| APIError::InvalidRoute { -- 2.39.5