@@ -967,7 +967,7 @@ where
967967 let mut htlc_msat = * first_hop_htlc_msat;
968968 let mut _error_code_ret = None ;
969969 let mut _error_packet_ret = None ;
970- let mut is_from_final_node = false ;
970+ let mut is_from_final_non_blinded_node = false ;
971971
972972 const BADONION : u16 = 0x8000 ;
973973 const PERM : u16 = 0x4000 ;
@@ -976,41 +976,72 @@ where
976976
977977 enum ErrorHop < ' a > {
978978 RouteHop ( & ' a RouteHop ) ,
979+ TrampolineHop ( & ' a TrampolineHop ) ,
979980 }
980981
981982 impl < ' a > ErrorHop < ' a > {
982983 fn fee_msat ( & self ) -> u64 {
983984 match self {
984985 ErrorHop :: RouteHop ( rh) => rh. fee_msat ,
986+ ErrorHop :: TrampolineHop ( th) => th. fee_msat ,
985987 }
986988 }
987989
988990 fn pubkey ( & self ) -> & PublicKey {
989991 match self {
990992 ErrorHop :: RouteHop ( rh) => rh. node_pubkey ( ) ,
993+ ErrorHop :: TrampolineHop ( th) => th. node_pubkey ( ) ,
991994 }
992995 }
993996
994997 fn short_channel_id ( & self ) -> Option < u64 > {
995998 match self {
996999 ErrorHop :: RouteHop ( rh) => Some ( rh. short_channel_id ) ,
1000+ ErrorHop :: TrampolineHop ( _) => None ,
9971001 }
9981002 }
9991003 }
10001004
1005+ let outer_session_priv = path. has_trampoline_hops ( ) . then ( || {
1006+ // if we have Trampoline hops, the outer onion session_priv is a hash of the inner one
1007+ let session_priv_hash = Sha256 :: hash ( & session_priv. secret_bytes ( ) ) . to_byte_array ( ) ;
1008+ SecretKey :: from_slice ( & session_priv_hash[ ..] ) . expect ( "You broke SHA-256!" )
1009+ } ) ;
1010+
10011011 let num_blinded_hops = path. blinded_tail . as_ref ( ) . map_or ( 0 , |bt| bt. hops . len ( ) ) ;
1012+
1013+ // We are first collecting all the unblinded `RouteHop`s inside `onion_keys`. Then, if applicable,
1014+ // we will add all the `TrampolineHop`s, and finally, the blinded hops.
10021015 let mut onion_keys = Vec :: with_capacity ( path. hops . len ( ) + num_blinded_hops) ;
10031016 construct_onion_keys_generic_callback (
10041017 secp_ctx,
10051018 & path. hops ,
1006- path. blinded_tail . as_ref ( ) ,
1007- session_priv,
1019+ // if we have Trampoline hops, the blinded hops are part of the inner Trampoline onion
1020+ if path. has_trampoline_hops ( ) { None } else { path. blinded_tail . as_ref ( ) } ,
1021+ outer_session_priv. as_ref ( ) . unwrap_or ( session_priv) ,
10081022 |shared_secret, _, _, route_hop_option : Option < & RouteHop > , _| {
10091023 onion_keys. push ( ( route_hop_option. map ( |rh| ErrorHop :: RouteHop ( rh) ) , shared_secret) )
10101024 } ,
10111025 )
10121026 . expect ( "Route we used spontaneously grew invalid keys in the middle of it?" ) ;
10131027
1028+ if path. has_trampoline_hops ( ) {
1029+ construct_onion_keys_generic_callback (
1030+ secp_ctx,
1031+ // Trampoline hops are part of the blinded tail, so this can never panic
1032+ & path. blinded_tail . as_ref ( ) . unwrap ( ) . trampoline_hops ,
1033+ path. blinded_tail . as_ref ( ) ,
1034+ session_priv,
1035+ |shared_secret, _, _, trampoline_hop_option : Option < & TrampolineHop > , _| {
1036+ onion_keys. push ( (
1037+ trampoline_hop_option. map ( |th| ErrorHop :: TrampolineHop ( th) ) ,
1038+ shared_secret,
1039+ ) )
1040+ } ,
1041+ )
1042+ . expect ( "Route we used spontaneously grew invalid keys in the middle of it?" ) ;
1043+ }
1044+
10141045 // Handle packed channel/node updates for passing back for the route handler
10151046 let mut iterator = onion_keys. into_iter ( ) . peekable ( ) ;
10161047 while let Some ( ( route_hop_option, shared_secret) ) = iterator. next ( ) {
@@ -1032,12 +1063,12 @@ where
10321063
10331064 // The failing hop includes either the inbound channel to the recipient or the outbound channel
10341065 // from the current hop (i.e., the next hop's inbound channel).
1035- // For 1-hop blinded paths, the final `path.hops ` entry is the recipient.
1066+ // For 1-hop blinded paths, the final `ErrorHop ` entry is the recipient.
10361067 // In our case that means that if we're on the last iteration, and there is no more than one
10371068 // blinded hop, the current iteration references the last non-blinded hop.
10381069 let next_hop = iterator. peek ( ) ;
1039- is_from_final_node = next_hop. is_none ( ) && num_blinded_hops <= 1 ;
1040- let failing_route_hop = if is_from_final_node {
1070+ is_from_final_non_blinded_node = next_hop. is_none ( ) && num_blinded_hops <= 1 ;
1071+ let failing_route_hop = if is_from_final_non_blinded_node {
10411072 route_hop
10421073 } else {
10431074 match next_hop {
@@ -1102,7 +1133,7 @@ where
11021133 res = Some ( FailureLearnings {
11031134 network_update,
11041135 short_channel_id,
1105- payment_failed_permanently : is_from_final_node ,
1136+ payment_failed_permanently : is_from_final_non_blinded_node ,
11061137 failed_within_blinded_path : false ,
11071138 } ) ;
11081139 break ;
@@ -1124,7 +1155,7 @@ where
11241155 res = Some ( FailureLearnings {
11251156 network_update,
11261157 short_channel_id,
1127- payment_failed_permanently : is_from_final_node ,
1158+ payment_failed_permanently : is_from_final_non_blinded_node ,
11281159 failed_within_blinded_path : false ,
11291160 } ) ;
11301161 break ;
@@ -1141,7 +1172,7 @@ where
11411172 let payment_failed = match error_code & 0xff {
11421173 15 | 16 | 17 | 18 | 19 | 23 => true ,
11431174 _ => false ,
1144- } && is_from_final_node ; // PERM bit observed below even if this error is from the intermediate nodes
1175+ } && is_from_final_non_blinded_node ; // PERM bit observed below even if this error is from the intermediate nodes
11451176
11461177 let mut network_update = None ;
11471178 let mut short_channel_id = None ;
@@ -1226,7 +1257,7 @@ where
12261257 res = Some ( FailureLearnings {
12271258 network_update,
12281259 short_channel_id,
1229- payment_failed_permanently : error_code & PERM == PERM && is_from_final_node ,
1260+ payment_failed_permanently : error_code & PERM == PERM && is_from_final_non_blinded_node ,
12301261 failed_within_blinded_path : false ,
12311262 } ) ;
12321263
@@ -1285,7 +1316,7 @@ where
12851316 DecodedOnionFailure {
12861317 network_update : None ,
12871318 short_channel_id : None ,
1288- payment_failed_permanently : is_from_final_node ,
1319+ payment_failed_permanently : is_from_final_non_blinded_node ,
12891320 failed_within_blinded_path : false ,
12901321 #[ cfg( any( test, feature = "_test_utils" ) ) ]
12911322 onion_error_code : None ,
0 commit comments