@@ -225,6 +225,11 @@ pub struct PaymentParameters {
225225 /// The maximum number of paths that may be used by (MPP) payments.
226226 /// Defaults to [`DEFAULT_MAX_PATH_COUNT`].
227227 pub max_path_count : u8 ,
228+
229+ /// A list of SCIDs which this payment was previously attempted over and which caused the
230+ /// payment to fail. Future attempts for the same payment shouldn't be relayed through any of
231+ /// these SCIDs.
232+ pub previously_failed_channels : Vec < u64 > ,
228233}
229234
230235impl_writeable_tlv_based ! ( PaymentParameters , {
@@ -233,6 +238,7 @@ impl_writeable_tlv_based!(PaymentParameters, {
233238 ( 2 , features, option) ,
234239 ( 3 , max_path_count, ( default_value, DEFAULT_MAX_PATH_COUNT ) ) ,
235240 ( 4 , route_hints, vec_type) ,
241+ ( 5 , previously_failed_channels, vec_type) ,
236242 ( 6 , expiry_time, option) ,
237243} ) ;
238244
@@ -246,6 +252,7 @@ impl PaymentParameters {
246252 expiry_time : None ,
247253 max_total_cltv_expiry_delta : DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA ,
248254 max_path_count : DEFAULT_MAX_PATH_COUNT ,
255+ previously_failed_channels : Vec :: new ( ) ,
249256 }
250257 }
251258
@@ -956,7 +963,7 @@ where L::Target: Logger {
956963 let contributes_sufficient_value = available_value_contribution_msat >= minimal_value_contribution_msat;
957964 // Do not consider candidate hops that would exceed the maximum path length.
958965 let path_length_to_node = $next_hops_path_length + 1 ;
959- let doesnt_exceed_max_path_length = path_length_to_node <= MAX_PATH_LENGTH_ESTIMATE ;
966+ let exceeds_max_path_length = path_length_to_node > MAX_PATH_LENGTH_ESTIMATE ;
960967
961968 // Do not consider candidates that exceed the maximum total cltv expiry limit.
962969 // In order to already account for some of the privacy enhancing random CLTV
@@ -967,7 +974,7 @@ where L::Target: Logger {
967974 . unwrap_or( payment_params. max_total_cltv_expiry_delta - final_cltv_expiry_delta) ;
968975 let hop_total_cltv_delta = ( $next_hops_cltv_delta as u32 )
969976 . saturating_add( $candidate. cltv_expiry_delta( ) ) ;
970- let doesnt_exceed_cltv_delta_limit = hop_total_cltv_delta <= max_total_cltv_expiry_delta;
977+ let exceeds_cltv_delta_limit = hop_total_cltv_delta > max_total_cltv_expiry_delta;
971978
972979 let value_contribution_msat = cmp:: min( available_value_contribution_msat, $next_hops_value_contribution) ;
973980 // Includes paying fees for the use of the following channels.
@@ -987,15 +994,19 @@ where L::Target: Logger {
987994 ( amount_to_transfer_over_msat < $next_hops_path_htlc_minimum_msat &&
988995 recommended_value_msat > $next_hops_path_htlc_minimum_msat) ) ;
989996
997+ let payment_failed_on_this_channel =
998+ payment_params. previously_failed_channels. contains( & short_channel_id) ;
999+
9901000 // If HTLC minimum is larger than the amount we're going to transfer, we shouldn't
9911001 // bother considering this channel. If retrying with recommended_value_msat may
9921002 // allow us to hit the HTLC minimum limit, set htlc_minimum_limit so that we go
9931003 // around again with a higher amount.
994- if contributes_sufficient_value && doesnt_exceed_max_path_length &&
995- doesnt_exceed_cltv_delta_limit && may_overpay_to_meet_path_minimum_msat {
1004+ if !contributes_sufficient_value || exceeds_max_path_length ||
1005+ exceeds_cltv_delta_limit || payment_failed_on_this_channel {
1006+ // Path isn't useful, ignore it and move on.
1007+ } else if may_overpay_to_meet_path_minimum_msat {
9961008 hit_minimum_limit = true ;
997- } else if contributes_sufficient_value && doesnt_exceed_max_path_length &&
998- doesnt_exceed_cltv_delta_limit && over_path_minimum_msat {
1009+ } else if over_path_minimum_msat {
9991010 // Note that low contribution here (limited by available_liquidity_msat)
10001011 // might violate htlc_minimum_msat on the hops which are next along the
10011012 // payment path (upstream to the payee). To avoid that, we recompute
@@ -1915,6 +1926,8 @@ mod tests {
19151926 use prelude:: * ;
19161927 use sync:: { self , Arc } ;
19171928
1929+ use core:: convert:: TryInto ;
1930+
19181931 fn get_channel_details ( short_channel_id : Option < u64 > , node_id : PublicKey ,
19191932 features : InitFeatures , outbound_capacity_msat : u64 ) -> channelmanager:: ChannelDetails {
19201933 channelmanager:: ChannelDetails {
@@ -5492,6 +5505,35 @@ mod tests {
54925505 }
54935506 }
54945507
5508+ #[ test]
5509+ fn avoids_recently_failed_paths ( ) {
5510+ // Ensure that the router always avoids all of the `previously_failed_channels` channels by
5511+ // randomly inserting channels into it until we can't find a route anymore.
5512+ let ( secp_ctx, network, _, _, logger) = build_graph ( ) ;
5513+ let ( _, our_id, _, nodes) = get_nodes ( & secp_ctx) ;
5514+ let network_graph = network. read_only ( ) ;
5515+
5516+ let scorer = test_utils:: TestScorer :: with_penalty ( 0 ) ;
5517+ let mut payment_params = PaymentParameters :: from_node_id ( nodes[ 6 ] ) . with_route_hints ( last_hops ( & nodes) )
5518+ . with_max_path_count ( 1 ) ;
5519+ let keys_manager = test_utils:: TestKeysInterface :: new ( & [ 0u8 ; 32 ] , Network :: Testnet ) ;
5520+ let random_seed_bytes = keys_manager. get_secure_random_bytes ( ) ;
5521+
5522+ // We should be able to find a route initially, and then after we fail a few random
5523+ // channels eventually we won't be able to any longer.
5524+ assert ! ( get_route( & our_id, & payment_params, & network_graph, None , 100 , 0 , Arc :: clone( & logger) , & scorer, & random_seed_bytes) . is_ok( ) ) ;
5525+ loop {
5526+ if let Ok ( route) = get_route ( & our_id, & payment_params, & network_graph, None , 100 , 0 , Arc :: clone ( & logger) , & scorer, & random_seed_bytes) {
5527+ for chan in route. paths [ 0 ] . iter ( ) {
5528+ assert ! ( !payment_params. previously_failed_channels. contains( & chan. short_channel_id) ) ;
5529+ }
5530+ let victim = ( u64:: from_ne_bytes ( random_seed_bytes[ 0 ..8 ] . try_into ( ) . unwrap ( ) ) as usize )
5531+ % route. paths [ 0 ] . len ( ) ;
5532+ payment_params. previously_failed_channels . push ( route. paths [ 0 ] [ victim] . short_channel_id ) ;
5533+ } else { break ; }
5534+ }
5535+ }
5536+
54955537 #[ test]
54965538 fn limits_path_length ( ) {
54975539 let ( secp_ctx, network, _, _, logger) = build_line_graph ( ) ;
0 commit comments