@@ -22,6 +22,7 @@ use crate::sign::{NodeSigner, Recipient};
2222use crate :: types:: features:: BlindedHopFeatures ;
2323use crate :: types:: payment:: PaymentHash ;
2424use crate :: util:: logger:: Logger ;
25+ use crate :: util:: ser:: Writeable ;
2526
2627#[ allow( unused_imports) ]
2728use crate :: prelude:: * ;
@@ -74,6 +75,24 @@ fn check_blinded_forward(
7475 Ok ( ( amt_to_forward, outgoing_cltv_value) )
7576}
7677
78+ fn check_trampoline_onion_constraints (
79+ outer_hop_data : & msgs:: InboundTrampolineEntrypointPayload , trampoline_cltv_value : u32 ,
80+ trampoline_amount : u64 ,
81+ ) -> Result < ( ) , LocalHTLCFailureReason > {
82+ if outer_hop_data. outgoing_cltv_value < trampoline_cltv_value {
83+ return Err ( LocalHTLCFailureReason :: FinalIncorrectCLTVExpiry ) ;
84+ }
85+ let outgoing_amount = outer_hop_data
86+ . multipath_trampoline_data
87+ . as_ref ( )
88+ . map_or ( outer_hop_data. amt_to_forward , |mtd| mtd. total_msat ) ;
89+ if outgoing_amount < trampoline_amount {
90+ return Err ( LocalHTLCFailureReason :: FinalIncorrectHTLCAmount ) ;
91+ }
92+
93+ Ok ( ( ) )
94+ }
95+
7796enum RoutingInfo {
7897 Direct {
7998 short_channel_id : u64 ,
@@ -135,7 +154,25 @@ pub(super) fn create_fwd_pending_htlc_info(
135154 reason : LocalHTLCFailureReason :: InvalidOnionPayload ,
136155 err_data : Vec :: new ( ) ,
137156 } ) ,
138- onion_utils:: Hop :: TrampolineForward { next_trampoline_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, trampoline_shared_secret, .. } => {
157+ onion_utils:: Hop :: TrampolineForward { ref outer_hop_data, next_trampoline_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, trampoline_shared_secret, .. } => {
158+ check_trampoline_onion_constraints ( outer_hop_data, next_trampoline_hop_data. outgoing_cltv_value , next_trampoline_hop_data. amt_to_forward ) . map_err ( |reason| {
159+ let mut err_data = Vec :: new ( ) ;
160+ match reason {
161+ LocalHTLCFailureReason :: FinalIncorrectCLTVExpiry => {
162+ outer_hop_data. outgoing_cltv_value . write ( & mut err_data) . unwrap ( ) ;
163+ }
164+ LocalHTLCFailureReason :: FinalIncorrectHTLCAmount => {
165+ outer_hop_data. amt_to_forward . write ( & mut err_data) . unwrap ( ) ;
166+ }
167+ _ => unreachable ! ( )
168+ }
169+ // The Trampoline onion's amt and CLTV values cannot exceed the outer onion's
170+ InboundHTLCErr {
171+ reason,
172+ err_data,
173+ msg : "Underflow calculating outbound amount or CLTV value for Trampoline forward" ,
174+ }
175+ } ) ?;
139176 (
140177 RoutingInfo :: Trampoline {
141178 next_trampoline : next_trampoline_hop_data. next_trampoline ,
@@ -150,7 +187,7 @@ pub(super) fn create_fwd_pending_htlc_info(
150187 None
151188 )
152189 } ,
153- onion_utils:: Hop :: TrampolineBlindedForward { outer_hop_data, next_trampoline_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, trampoline_shared_secret, .. } => {
190+ onion_utils:: Hop :: TrampolineBlindedForward { ref outer_hop_data, next_trampoline_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, trampoline_shared_secret, .. } => {
154191 let ( amt_to_forward, outgoing_cltv_value) = check_blinded_forward (
155192 msg. amount_msat , msg. cltv_expiry , & next_trampoline_hop_data. payment_relay , & next_trampoline_hop_data. payment_constraints , & next_trampoline_hop_data. features
156193 ) . map_err ( |( ) | {
@@ -162,6 +199,15 @@ pub(super) fn create_fwd_pending_htlc_info(
162199 err_data : vec ! [ 0 ; 32 ] ,
163200 }
164201 } ) ?;
202+ check_trampoline_onion_constraints ( outer_hop_data, outgoing_cltv_value, amt_to_forward) . map_err ( |_| {
203+ // The Trampoline onion's amt and CLTV values cannot exceed the outer onion's, but
204+ // we're inside a blinded path
205+ InboundHTLCErr {
206+ reason : LocalHTLCFailureReason :: InvalidOnionBlinding ,
207+ err_data : vec ! [ 0 ; 32 ] ,
208+ msg : "Underflow calculating outbound amount or CLTV value for Trampoline forward" ,
209+ }
210+ } ) ?;
165211 (
166212 RoutingInfo :: Trampoline {
167213 next_trampoline : next_trampoline_hop_data. next_trampoline ,
@@ -281,14 +327,35 @@ pub(super) fn create_recv_pending_htlc_info(
281327 intro_node_blinding_point. is_none ( ) , true , invoice_request)
282328 }
283329 onion_utils:: Hop :: TrampolineReceive {
330+ ref outer_hop_data,
284331 trampoline_hop_data : msgs:: InboundOnionReceivePayload {
285332 payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat,
286333 cltv_expiry_height, payment_metadata, ..
287334 } , ..
288- } =>
335+ } => {
336+ check_trampoline_onion_constraints ( outer_hop_data, cltv_expiry_height, sender_intended_htlc_amt_msat) . map_err ( |reason| {
337+ let mut err_data = Vec :: new ( ) ;
338+ match reason {
339+ LocalHTLCFailureReason :: FinalIncorrectCLTVExpiry => {
340+ outer_hop_data. outgoing_cltv_value . write ( & mut err_data) . unwrap ( ) ;
341+ }
342+ LocalHTLCFailureReason :: FinalIncorrectHTLCAmount => {
343+ outer_hop_data. amt_to_forward . write ( & mut err_data) . unwrap ( ) ;
344+ }
345+ _ => unreachable ! ( )
346+ }
347+ // The Trampoline onion's amt and CLTV values cannot exceed the outer onion's
348+ InboundHTLCErr {
349+ reason,
350+ err_data,
351+ msg : "Underflow calculating skimmable amount or CLTV value for Trampoline receive" ,
352+ }
353+ } ) ?;
289354 ( payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat,
290- cltv_expiry_height, payment_metadata, None , false , keysend_preimage. is_none ( ) , None ) ,
355+ cltv_expiry_height, payment_metadata, None , false , keysend_preimage. is_none ( ) , None )
356+ }
291357 onion_utils:: Hop :: TrampolineBlindedReceive {
358+ ref outer_hop_data,
292359 trampoline_hop_data : msgs:: InboundOnionBlindedReceivePayload {
293360 sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, payment_secret,
294361 intro_node_blinding_point, payment_constraints, payment_context, keysend_preimage,
@@ -306,6 +373,15 @@ pub(super) fn create_recv_pending_htlc_info(
306373 }
307374 } ) ?;
308375 let payment_data = msgs:: FinalOnionHopData { payment_secret, total_msat } ;
376+ check_trampoline_onion_constraints ( outer_hop_data, cltv_expiry_height, sender_intended_htlc_amt_msat) . map_err ( |_| {
377+ // The Trampoline onion's amt and CLTV values cannot exceed the outer onion's, but
378+ // we're inside a blinded path
379+ InboundHTLCErr {
380+ reason : LocalHTLCFailureReason :: InvalidOnionBlinding ,
381+ err_data : vec ! [ 0 ; 32 ] ,
382+ msg : "Underflow calculating skimmable amount or CLTV value for Trampoline receive" ,
383+ }
384+ } ) ?;
309385 ( Some ( payment_data) , keysend_preimage, custom_tlvs,
310386 sender_intended_htlc_amt_msat, cltv_expiry_height, None , Some ( payment_context) ,
311387 intro_node_blinding_point. is_none ( ) , true , invoice_request)
@@ -602,6 +678,25 @@ where
602678 outgoing_cltv_value,
603679 } )
604680 }
681+ onion_utils:: Hop :: TrampolineBlindedForward { next_trampoline_hop_data : msgs:: InboundTrampolineBlindedForwardPayload { next_trampoline, ref payment_relay, ref payment_constraints, ref features, .. } , outer_shared_secret, trampoline_shared_secret, incoming_trampoline_public_key, .. } => {
682+ let ( amt_to_forward, outgoing_cltv_value) = match check_blinded_forward (
683+ msg. amount_msat , msg. cltv_expiry , & payment_relay, & payment_constraints, & features
684+ ) {
685+ Ok ( ( amt, cltv) ) => ( amt, cltv) ,
686+ Err ( ( ) ) => {
687+ return encode_relay_error ( "Underflow calculating outbound amount or cltv value for blinded forward" ,
688+ LocalHTLCFailureReason :: InvalidOnionBlinding , outer_shared_secret. secret_bytes ( ) , Some ( trampoline_shared_secret. secret_bytes ( ) ) , & [ 0 ; 32 ] ) ;
689+ }
690+ } ;
691+ let next_trampoline_packet_pubkey = onion_utils:: next_hop_pubkey ( secp_ctx,
692+ incoming_trampoline_public_key, & trampoline_shared_secret. secret_bytes ( ) ) ;
693+ Some ( NextPacketDetails {
694+ next_packet_pubkey : next_trampoline_packet_pubkey,
695+ outgoing_connector : HopConnector :: Trampoline ( next_trampoline) ,
696+ outgoing_amt_msat : amt_to_forward,
697+ outgoing_cltv_value,
698+ } )
699+ }
605700 _ => None
606701 } ;
607702
0 commit comments