@@ -2068,6 +2068,65 @@ mod tests {
20682068 ) ) ;
20692069 }
20702070
2071+ #[ tokio:: test]
2072+ async fn test_payment_failure_returns_correct_hop_index_of_failure ( ) {
2073+ let chan_capacity = 500_000_000 ;
2074+ let test_kit =
2075+ DispatchPaymentTestKit :: new ( chan_capacity, vec ! [ ] , CustomRecords :: default ( ) ) . await ;
2076+
2077+ let mut node = SimNode :: new (
2078+ node_info ( test_kit. nodes [ 0 ] , String :: default ( ) ) ,
2079+ Arc :: new ( Mutex :: new ( test_kit. graph ) ) ,
2080+ test_kit. routing_graph . clone ( ) ,
2081+ Arc :: new ( SystemClock { } ) ,
2082+ )
2083+ . unwrap ( ) ;
2084+
2085+ let route = build_route_from_hops (
2086+ & test_kit. nodes [ 0 ] ,
2087+ & [ test_kit. nodes [ 1 ] , test_kit. nodes [ 2 ] , test_kit. nodes [ 3 ] ] ,
2088+ & RouteParameters {
2089+ payment_params : PaymentParameters :: from_node_id ( * test_kit. nodes . last ( ) . unwrap ( ) , 0 )
2090+ . with_max_total_cltv_expiry_delta ( u32:: MAX )
2091+ . with_max_path_count ( 1 )
2092+ . with_max_channel_saturation_power_of_half ( 1 ) ,
2093+ final_value_msat : 20_000 ,
2094+ max_total_routing_fee_msat : None ,
2095+ } ,
2096+ & test_kit. routing_graph ,
2097+ & WrappedLog { } ,
2098+ & [ 0 ; 32 ] ,
2099+ )
2100+ . unwrap ( ) ;
2101+
2102+ // We are altering the route to make sure that we fail at each hop in turn.
2103+ // We will assert that the failure index returned is the index of the hop that we altered.
2104+ // This is done by setting the CLTV expiry delta to a value that will cause the payment to fail at that hop.
2105+ // The last hop will always succeed, so we only test the first n-1 hops.
2106+ for i in 0 ..route. paths [ 0 ] . hops . len ( ) - 1 {
2107+ let mut route_clone = route. clone ( ) ;
2108+ // Alter route_clone to make payment fail on this hop.
2109+ route_clone. paths [ 0 ] . hops [ i] . cltv_expiry_delta = 39 ;
2110+
2111+ let preimage = PaymentPreimage ( rand:: random ( ) ) ;
2112+ let payment_hash = preimage. into ( ) ;
2113+ let send_result = node. send_to_route ( route_clone, payment_hash, None ) . await ;
2114+
2115+ assert ! ( send_result. is_ok( ) ) ;
2116+
2117+ let ( _, shutdown_listener) = triggered:: trigger ( ) ;
2118+ let result = node
2119+ . track_payment ( & payment_hash, shutdown_listener)
2120+ . await
2121+ . unwrap ( ) ;
2122+
2123+ assert ! ( matches!(
2124+ result. payment_outcome,
2125+ PaymentOutcome :: IndexFailure ( idx) if idx == i
2126+ ) ) ;
2127+ }
2128+ }
2129+
20712130 mock ! {
20722131 #[ derive( Debug ) ]
20732132 TestInterceptor { }
0 commit comments