From f68b1249a9d2ff73680333a25b533f287125fa97 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Mon, 22 Jul 2024 15:22:54 -0400 Subject: [PATCH] Support next_blinding_override in blinded payment paths. This allow us to forward blinded payments where the blinded path that we are forwarding within was concatenated to another blinded path that starts at the next hop. Also allows constructing blinded paths using this override. --- fuzz/src/invoice_request_deser.rs | 1 + fuzz/src/refund_deser.rs | 1 + lightning/src/blinded_path/payment.rs | 13 +++++++++++++ lightning/src/ln/blinded_payment_tests.rs | 1 + lightning/src/ln/channelmanager.rs | 19 +++++++++++++------ lightning/src/ln/msgs.rs | 4 +++- lightning/src/ln/onion_payment.rs | 10 +++++++--- lightning/src/routing/router.rs | 1 + 8 files changed, 40 insertions(+), 10 deletions(-) diff --git a/fuzz/src/invoice_request_deser.rs b/fuzz/src/invoice_request_deser.rs index a5db1c4be..3abb0974e 100644 --- a/fuzz/src/invoice_request_deser.rs +++ b/fuzz/src/invoice_request_deser.rs @@ -113,6 +113,7 @@ fn build_response( htlc_minimum_msat: 100, }, features: BlindedHopFeatures::empty(), + next_blinding_override: None, }, node_id: pubkey(43), htlc_maximum_msat: 1_000_000_000_000, diff --git a/fuzz/src/refund_deser.rs b/fuzz/src/refund_deser.rs index 58dc68eed..17f255081 100644 --- a/fuzz/src/refund_deser.rs +++ b/fuzz/src/refund_deser.rs @@ -91,6 +91,7 @@ fn build_response( htlc_minimum_msat: 100, }, features: BlindedHopFeatures::empty(), + next_blinding_override: None, }, node_id: pubkey(43), htlc_maximum_msat: 1_000_000_000_000, diff --git a/lightning/src/blinded_path/payment.rs b/lightning/src/blinded_path/payment.rs index 765e0b91f..ca937c57d 100644 --- a/lightning/src/blinded_path/payment.rs +++ b/lightning/src/blinded_path/payment.rs @@ -201,6 +201,9 @@ pub struct ForwardTlvs { /// /// [`BlindedHop::encrypted_payload`]: crate::blinded_path::BlindedHop::encrypted_payload pub features: BlindedHopFeatures, + /// Set if this [`BlindedPaymentPath`] is concatenated to another, to indicate the + /// [`BlindedPaymentPath::blinding_point`] of the appended blinded path. + pub next_blinding_override: Option, } /// Data to construct a [`BlindedHop`] for receiving a payment. This payload is custom to LDK and @@ -379,6 +382,7 @@ impl Readable for BlindedPaymentTlvs { _init_and_read_tlv_stream!(r, { (1, _padding, option), (2, scid, option), + (8, next_blinding_override, option), (10, payment_relay, option), (12, payment_constraints, required), (14, features, option), @@ -395,6 +399,7 @@ impl Readable for BlindedPaymentTlvs { short_channel_id, payment_relay: payment_relay.ok_or(DecodeError::InvalidValue)?, payment_constraints: payment_constraints.0.unwrap(), + next_blinding_override, features: features.unwrap_or_else(BlindedHopFeatures::empty), })) } else { @@ -602,6 +607,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 100, }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: u64::max_value(), @@ -618,6 +624,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 1_000, }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: u64::max_value(), @@ -675,6 +682,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 1, }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: u64::max_value() @@ -691,6 +699,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 2_000, }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: u64::max_value() @@ -726,6 +735,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 5_000, }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: u64::max_value() @@ -742,6 +752,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 2_000, }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: u64::max_value() @@ -781,6 +792,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 1, }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: 5_000, @@ -797,6 +809,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 1, }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: 10_000 diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index b13b1e04d..e959000d3 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -49,6 +49,7 @@ fn blinded_payment_path( htlc_minimum_msat: intro_node_min_htlc_opt.take() .unwrap_or_else(|| channel_upds[idx - 1].htlc_minimum_msat), }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: intro_node_max_htlc_opt.take() diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 641810f2f..e08b45558 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -226,6 +226,10 @@ pub struct BlindedForward { /// If needed, this determines how this HTLC should be failed backwards, based on whether we are /// the introduction node. pub failure: BlindedFailure, + /// Overrides the next hop's [`msgs::UpdateAddHTLC::blinding_point`]. Set if this HTLC is being + /// forwarded within a [`BlindedPaymentPath`] that was concatenated to another blinded path that + /// starts at the next hop. + pub next_blinding_override: Option, } impl PendingHTLCRouting { @@ -5313,12 +5317,14 @@ where blinded_failure: blinded.map(|b| b.failure), }); let next_blinding_point = blinded.and_then(|b| { - let encrypted_tlvs_ss = self.node_signer.ecdh( - Recipient::Node, &b.inbound_blinding_point, None - ).unwrap().secret_bytes(); - onion_utils::next_hop_pubkey( - &self.secp_ctx, b.inbound_blinding_point, &encrypted_tlvs_ss - ).ok() + b.next_blinding_override.or_else(|| { + let encrypted_tlvs_ss = self.node_signer.ecdh( + Recipient::Node, &b.inbound_blinding_point, None + ).unwrap().secret_bytes(); + onion_utils::next_hop_pubkey( + &self.secp_ctx, b.inbound_blinding_point, &encrypted_tlvs_ss + ).ok() + }) }); // Forward the HTLC over the most appropriate channel with the corresponding peer, @@ -11034,6 +11040,7 @@ impl_writeable_tlv_based!(PhantomRouteHints, { impl_writeable_tlv_based!(BlindedForward, { (0, inbound_blinding_point, required), (1, failure, (default_value, BlindedFailure::FromIntroductionNode)), + (3, next_blinding_override, option), }); impl_writeable_tlv_based_enum!(PendingHTLCRouting, diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 85f1ae0aa..83ce4f914 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -1764,6 +1764,7 @@ mod fuzzy_internal_msgs { payment_constraints: PaymentConstraints, features: BlindedHopFeatures, intro_node_blinding_point: Option, + next_blinding_override: Option, }, BlindedReceive { sender_intended_htlc_amt_msat: u64, @@ -2808,7 +2809,7 @@ impl ReadableArgs<(Option, &NS)> for InboundOnionPayload w let mut reader = FixedLengthReader::new(&mut s, enc_tlvs.len() as u64); match ChaChaPolyReadAdapter::read(&mut reader, rho)? { ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Forward(ForwardTlvs { - short_channel_id, payment_relay, payment_constraints, features + short_channel_id, payment_relay, payment_constraints, features, next_blinding_override })} => { if amt.is_some() || cltv_value.is_some() || total_msat.is_some() || keysend_preimage.is_some() @@ -2821,6 +2822,7 @@ impl ReadableArgs<(Option, &NS)> for InboundOnionPayload w payment_constraints, features, intro_node_blinding_point, + next_blinding_override, }) }, ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(ReceiveTlvs { diff --git a/lightning/src/ln/onion_payment.rs b/lightning/src/ln/onion_payment.rs index f62ca5d84..1163a5e63 100644 --- a/lightning/src/ln/onion_payment.rs +++ b/lightning/src/ln/onion_payment.rs @@ -75,12 +75,14 @@ pub(super) fn create_fwd_pending_htlc_info( }; let ( - short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point + short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point, + next_blinding_override ) = match hop_data { msgs::InboundOnionPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } => - (short_channel_id, amt_to_forward, outgoing_cltv_value, None), + (short_channel_id, amt_to_forward, outgoing_cltv_value, None, None), msgs::InboundOnionPayload::BlindedForward { short_channel_id, payment_relay, payment_constraints, intro_node_blinding_point, features, + next_blinding_override, } => { let (amt_to_forward, outgoing_cltv_value) = check_blinded_forward( msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features @@ -93,7 +95,8 @@ pub(super) fn create_fwd_pending_htlc_info( err_data: vec![0; 32], } })?; - (short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point) + (short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point, + next_blinding_override) }, msgs::InboundOnionPayload::Receive { .. } | msgs::InboundOnionPayload::BlindedReceive { .. } => return Err(InboundHTLCErr { @@ -110,6 +113,7 @@ pub(super) fn create_fwd_pending_htlc_info( blinded: intro_node_blinding_point.or(msg.blinding_point) .map(|bp| BlindedForward { inbound_blinding_point: bp, + next_blinding_override, failure: intro_node_blinding_point .map(|_| BlindedFailure::FromIntroductionNode) .unwrap_or(BlindedFailure::FromBlindedNode), diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 2d7450b91..43c4b7343 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -151,6 +151,7 @@ impl>, L: Deref, ES: Deref, S: Deref, SP: Size short_channel_id, payment_relay, payment_constraints, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, node_id: details.counterparty.node_id, -- 2.39.5