@@ -19,6 +19,7 @@ use crate::ln::onion_utils;
1919use crate :: ln:: onion_utils:: { HTLCFailReason , ONION_DATA_LEN , LocalHTLCFailureReason } ;
2020use crate :: sign:: { NodeSigner , Recipient } ;
2121use crate :: util:: logger:: Logger ;
22+ use crate :: util:: ser:: Writeable ;
2223
2324#[ allow( unused_imports) ]
2425use crate :: prelude:: * ;
@@ -69,6 +70,16 @@ fn check_blinded_forward(
6970 Ok ( ( amt_to_forward, outgoing_cltv_value) )
7071}
7172
73+ fn check_trampoline_onion_constraints ( outer_hop_data : & msgs:: InboundTrampolineEntrypointPayload , trampoline_cltv_value : u32 , trampoline_amount : u64 ) -> Result < ( ) , LocalHTLCFailureReason > {
74+ if outer_hop_data. outgoing_cltv_value < trampoline_cltv_value {
75+ return Err ( LocalHTLCFailureReason :: FinalIncorrectCLTVExpiry ) ;
76+ }
77+ if outer_hop_data. multipath_trampoline_data . as_ref ( ) . map_or ( outer_hop_data. amt_to_forward , |mtd| mtd. total_msat ) < trampoline_amount {
78+ return Err ( LocalHTLCFailureReason :: FinalIncorrectHTLCAmount ) ;
79+ }
80+ Ok ( ( ) )
81+ }
82+
7283enum RoutingInfo {
7384 Direct {
7485 short_channel_id : u64 ,
@@ -129,7 +140,25 @@ pub(super) fn create_fwd_pending_htlc_info(
129140 reason : LocalHTLCFailureReason :: InvalidOnionPayload ,
130141 err_data : Vec :: new ( ) ,
131142 } ) ,
132- onion_utils:: Hop :: TrampolineForward { next_trampoline_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, trampoline_shared_secret, .. } => {
143+ onion_utils:: Hop :: TrampolineForward { ref outer_hop_data, next_trampoline_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, trampoline_shared_secret, .. } => {
144+ check_trampoline_onion_constraints ( outer_hop_data, next_trampoline_hop_data. outgoing_cltv_value , next_trampoline_hop_data. amt_to_forward ) . map_err ( |reason| {
145+ let mut err_data = Vec :: new ( ) ;
146+ match reason {
147+ LocalHTLCFailureReason :: FinalIncorrectCLTVExpiry => {
148+ outer_hop_data. outgoing_cltv_value . write ( & mut err_data) . unwrap ( ) ;
149+ }
150+ LocalHTLCFailureReason :: FinalIncorrectHTLCAmount => {
151+ outer_hop_data. amt_to_forward . write ( & mut err_data) . unwrap ( ) ;
152+ }
153+ _ => unreachable ! ( )
154+ }
155+ // The Trampoline onion's amt and CLTV values cannot exceed the outer onion's
156+ InboundHTLCErr {
157+ reason,
158+ err_data,
159+ msg : "Underflow calculating outbound amount or CLTV value for Trampoline forward" ,
160+ }
161+ } ) ?;
133162 (
134163 RoutingInfo :: Trampoline {
135164 next_trampoline : next_trampoline_hop_data. next_trampoline ,
@@ -144,7 +173,7 @@ pub(super) fn create_fwd_pending_htlc_info(
144173 None
145174 )
146175 } ,
147- onion_utils:: Hop :: TrampolineBlindedForward { outer_hop_data, next_trampoline_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, trampoline_shared_secret, .. } => {
176+ onion_utils:: Hop :: TrampolineBlindedForward { ref outer_hop_data, next_trampoline_hop_data, next_trampoline_hop_hmac, new_trampoline_packet_bytes, trampoline_shared_secret, .. } => {
148177 let ( amt_to_forward, outgoing_cltv_value) = check_blinded_forward (
149178 msg. amount_msat , msg. cltv_expiry , & next_trampoline_hop_data. payment_relay , & next_trampoline_hop_data. payment_constraints , & next_trampoline_hop_data. features
150179 ) . map_err ( |( ) | {
@@ -156,6 +185,15 @@ pub(super) fn create_fwd_pending_htlc_info(
156185 err_data : vec ! [ 0 ; 32 ] ,
157186 }
158187 } ) ?;
188+ check_trampoline_onion_constraints ( outer_hop_data, outgoing_cltv_value, amt_to_forward) . map_err ( |_| {
189+ // The Trampoline onion's amt and CLTV values cannot exceed the outer onion's, but
190+ // we're inside a blinded path
191+ InboundHTLCErr {
192+ reason : LocalHTLCFailureReason :: InvalidOnionBlinding ,
193+ err_data : vec ! [ 0 ; 32 ] ,
194+ msg : "Underflow calculating outbound amount or CLTV value for Trampoline forward" ,
195+ }
196+ } ) ?;
159197 (
160198 RoutingInfo :: Trampoline {
161199 next_trampoline : next_trampoline_hop_data. next_trampoline ,
@@ -274,14 +312,35 @@ pub(super) fn create_recv_pending_htlc_info(
274312 intro_node_blinding_point. is_none ( ) , true , invoice_request)
275313 }
276314 onion_utils:: Hop :: TrampolineReceive {
315+ ref outer_hop_data,
277316 trampoline_hop_data : msgs:: InboundOnionReceivePayload {
278317 payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat,
279318 cltv_expiry_height, payment_metadata, ..
280319 } , ..
281- } =>
320+ } => {
321+ check_trampoline_onion_constraints ( outer_hop_data, cltv_expiry_height, sender_intended_htlc_amt_msat) . map_err ( |reason| {
322+ let mut err_data = Vec :: new ( ) ;
323+ match reason {
324+ LocalHTLCFailureReason :: FinalIncorrectCLTVExpiry => {
325+ outer_hop_data. outgoing_cltv_value . write ( & mut err_data) . unwrap ( ) ;
326+ }
327+ LocalHTLCFailureReason :: FinalIncorrectHTLCAmount => {
328+ outer_hop_data. amt_to_forward . write ( & mut err_data) . unwrap ( ) ;
329+ }
330+ _ => unreachable ! ( )
331+ }
332+ // The Trampoline onion's amt and CLTV values cannot exceed the outer onion's
333+ InboundHTLCErr {
334+ reason,
335+ err_data,
336+ msg : "Underflow calculating skimmable amount or CLTV value for Trampoline receive" ,
337+ }
338+ } ) ?;
282339 ( payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat,
283- cltv_expiry_height, payment_metadata, None , false , keysend_preimage. is_none ( ) , None ) ,
340+ cltv_expiry_height, payment_metadata, None , false , keysend_preimage. is_none ( ) , None )
341+ } ,
284342 onion_utils:: Hop :: TrampolineBlindedReceive {
343+ ref outer_hop_data,
285344 trampoline_hop_data : msgs:: InboundOnionBlindedReceivePayload {
286345 sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, payment_secret,
287346 intro_node_blinding_point, payment_constraints, payment_context, keysend_preimage,
@@ -298,6 +357,15 @@ pub(super) fn create_recv_pending_htlc_info(
298357 msg : "Amount or cltv_expiry violated blinded payment constraints within Trampoline onion" ,
299358 }
300359 } ) ?;
360+ check_trampoline_onion_constraints ( outer_hop_data, cltv_expiry_height, sender_intended_htlc_amt_msat) . map_err ( |_| {
361+ // The Trampoline onion's amt and CLTV values cannot exceed the outer onion's, but
362+ // we're inside a blinded path
363+ InboundHTLCErr {
364+ reason : LocalHTLCFailureReason :: InvalidOnionBlinding ,
365+ err_data : vec ! [ 0 ; 32 ] ,
366+ msg : "Underflow calculating skimmable amount or CLTV value for Trampoline receive" ,
367+ }
368+ } ) ?;
301369 let payment_data = msgs:: FinalOnionHopData { payment_secret, total_msat } ;
302370 ( Some ( payment_data) , keysend_preimage, custom_tlvs,
303371 sender_intended_htlc_amt_msat, cltv_expiry_height, None , Some ( payment_context) ,
@@ -583,7 +651,54 @@ where
583651 outgoing_cltv_value
584652 } )
585653 }
586- onion_utils:: Hop :: TrampolineForward { next_trampoline_hop_data : msgs:: InboundTrampolineForwardPayload { amt_to_forward, outgoing_cltv_value, next_trampoline } , trampoline_shared_secret, incoming_trampoline_public_key, .. } => {
654+ onion_utils:: Hop :: TrampolineForward { ref outer_hop_data, next_trampoline_hop_data : msgs:: InboundTrampolineForwardPayload { amt_to_forward, outgoing_cltv_value, next_trampoline } , outer_shared_secret, trampoline_shared_secret, incoming_trampoline_public_key, .. } => {
655+ if let Err ( reason) = check_trampoline_onion_constraints ( outer_hop_data, outgoing_cltv_value, amt_to_forward) {
656+ let mut data = Vec :: new ( ) ;
657+ match reason {
658+ LocalHTLCFailureReason :: FinalIncorrectCLTVExpiry => {
659+ outer_hop_data. outgoing_cltv_value . write ( & mut data) . unwrap ( ) ;
660+ }
661+ LocalHTLCFailureReason :: FinalIncorrectHTLCAmount => {
662+ outer_hop_data. amt_to_forward . write ( & mut data) . unwrap ( ) ;
663+ }
664+ _ => unreachable ! ( )
665+ }
666+ return encode_relay_error ( "Underflow calculating outbound amount or CLTV value for Trampoline forward" ,
667+ reason, outer_shared_secret. secret_bytes ( ) , Some ( trampoline_shared_secret. secret_bytes ( ) ) , & data) ;
668+ }
669+ let next_trampoline_packet_pubkey = onion_utils:: next_hop_pubkey ( secp_ctx,
670+ incoming_trampoline_public_key, & trampoline_shared_secret. secret_bytes ( ) ) ;
671+ Some ( NextPacketDetails {
672+ next_packet_pubkey : next_trampoline_packet_pubkey,
673+ outgoing_connector : HopConnector :: Trampoline ( next_trampoline) ,
674+ outgoing_amt_msat : amt_to_forward,
675+ outgoing_cltv_value,
676+ } )
677+ }
678+ onion_utils:: Hop :: TrampolineBlindedForward { ref outer_hop_data, 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, .. } => {
679+ let ( amt_to_forward, outgoing_cltv_value) = match check_blinded_forward (
680+ msg. amount_msat , msg. cltv_expiry , & payment_relay, & payment_constraints, & features
681+ ) {
682+ Ok ( ( amt, cltv) ) => ( amt, cltv) ,
683+ Err ( ( ) ) => {
684+ return encode_relay_error ( "Underflow calculating outbound amount or cltv value for blinded forward" ,
685+ LocalHTLCFailureReason :: InvalidOnionBlinding , outer_shared_secret. secret_bytes ( ) , Some ( trampoline_shared_secret. secret_bytes ( ) ) , & [ 0 ; 32 ] ) ;
686+ }
687+ } ;
688+ if let Err ( reason) = check_trampoline_onion_constraints ( outer_hop_data, outgoing_cltv_value, amt_to_forward) {
689+ let mut data = Vec :: new ( ) ;
690+ match reason {
691+ LocalHTLCFailureReason :: FinalIncorrectCLTVExpiry => {
692+ outer_hop_data. outgoing_cltv_value . write ( & mut data) . unwrap ( ) ;
693+ }
694+ LocalHTLCFailureReason :: FinalIncorrectHTLCAmount => {
695+ outer_hop_data. amt_to_forward . write ( & mut data) . unwrap ( ) ;
696+ }
697+ _ => unreachable ! ( )
698+ }
699+ return encode_relay_error ( "Underflow calculating outbound amount or CLTV value for Trampoline forward" ,
700+ reason, outer_shared_secret. secret_bytes ( ) , Some ( trampoline_shared_secret. secret_bytes ( ) ) , & data) ;
701+ }
587702 let next_trampoline_packet_pubkey = onion_utils:: next_hop_pubkey ( secp_ctx,
588703 incoming_trampoline_public_key, & trampoline_shared_secret. secret_bytes ( ) ) ;
589704 Some ( NextPacketDetails {
0 commit comments