@@ -240,6 +240,11 @@ pub struct PaymentParameters {
240240 ///
241241 /// Default value: 1
242242 pub max_channel_saturation_power_of_half : u8 ,
243+
244+ /// A list of SCIDs which this payment was previously attempted over and which caused the
245+ /// payment to fail. Future attempts for the same payment shouldn't be relayed through any of
246+ /// these SCIDs.
247+ pub previously_failed_channels : Vec < u64 > ,
243248}
244249
245250impl_writeable_tlv_based ! ( PaymentParameters , {
@@ -250,6 +255,7 @@ impl_writeable_tlv_based!(PaymentParameters, {
250255 ( 4 , route_hints, vec_type) ,
251256 ( 5 , max_channel_saturation_power_of_half, ( default_value, 1 ) ) ,
252257 ( 6 , expiry_time, option) ,
258+ ( 7 , previously_failed_channels, vec_type) ,
253259} ) ;
254260
255261impl PaymentParameters {
@@ -263,6 +269,7 @@ impl PaymentParameters {
263269 max_total_cltv_expiry_delta : DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA ,
264270 max_path_count : DEFAULT_MAX_PATH_COUNT ,
265271 max_channel_saturation_power_of_half : 1 ,
272+ previously_failed_channels : Vec :: new ( ) ,
266273 }
267274 }
268275
@@ -1002,7 +1009,7 @@ where L::Target: Logger {
10021009 let contributes_sufficient_value = available_value_contribution_msat >= minimal_value_contribution_msat;
10031010 // Do not consider candidate hops that would exceed the maximum path length.
10041011 let path_length_to_node = $next_hops_path_length + 1 ;
1005- let doesnt_exceed_max_path_length = path_length_to_node <= MAX_PATH_LENGTH_ESTIMATE ;
1012+ let exceeds_max_path_length = path_length_to_node > MAX_PATH_LENGTH_ESTIMATE ;
10061013
10071014 // Do not consider candidates that exceed the maximum total cltv expiry limit.
10081015 // In order to already account for some of the privacy enhancing random CLTV
@@ -1013,7 +1020,7 @@ where L::Target: Logger {
10131020 . unwrap_or( payment_params. max_total_cltv_expiry_delta - final_cltv_expiry_delta) ;
10141021 let hop_total_cltv_delta = ( $next_hops_cltv_delta as u32 )
10151022 . saturating_add( $candidate. cltv_expiry_delta( ) ) ;
1016- let doesnt_exceed_cltv_delta_limit = hop_total_cltv_delta <= max_total_cltv_expiry_delta;
1023+ let exceeds_cltv_delta_limit = hop_total_cltv_delta > max_total_cltv_expiry_delta;
10171024
10181025 let value_contribution_msat = cmp:: min( available_value_contribution_msat, $next_hops_value_contribution) ;
10191026 // Includes paying fees for the use of the following channels.
@@ -1033,15 +1040,19 @@ where L::Target: Logger {
10331040 ( amount_to_transfer_over_msat < $next_hops_path_htlc_minimum_msat &&
10341041 recommended_value_msat > $next_hops_path_htlc_minimum_msat) ) ;
10351042
1043+ let payment_failed_on_this_channel =
1044+ payment_params. previously_failed_channels. contains( & short_channel_id) ;
1045+
10361046 // If HTLC minimum is larger than the amount we're going to transfer, we shouldn't
10371047 // bother considering this channel. If retrying with recommended_value_msat may
10381048 // allow us to hit the HTLC minimum limit, set htlc_minimum_limit so that we go
10391049 // around again with a higher amount.
1040- if contributes_sufficient_value && doesnt_exceed_max_path_length &&
1041- doesnt_exceed_cltv_delta_limit && may_overpay_to_meet_path_minimum_msat {
1050+ if !contributes_sufficient_value || exceeds_max_path_length ||
1051+ exceeds_cltv_delta_limit || payment_failed_on_this_channel {
1052+ // Path isn't useful, ignore it and move on.
1053+ } else if may_overpay_to_meet_path_minimum_msat {
10421054 hit_minimum_limit = true ;
1043- } else if contributes_sufficient_value && doesnt_exceed_max_path_length &&
1044- doesnt_exceed_cltv_delta_limit && over_path_minimum_msat {
1055+ } else if over_path_minimum_msat {
10451056 // Note that low contribution here (limited by available_liquidity_msat)
10461057 // might violate htlc_minimum_msat on the hops which are next along the
10471058 // payment path (upstream to the payee). To avoid that, we recompute
@@ -1993,6 +2004,8 @@ mod tests {
19932004 use prelude:: * ;
19942005 use sync:: { self , Arc } ;
19952006
2007+ use core:: convert:: TryInto ;
2008+
19962009 fn get_channel_details ( short_channel_id : Option < u64 > , node_id : PublicKey ,
19972010 features : InitFeatures , outbound_capacity_msat : u64 ) -> channelmanager:: ChannelDetails {
19982011 channelmanager:: ChannelDetails {
@@ -5573,6 +5586,35 @@ mod tests {
55735586 }
55745587 }
55755588
5589+ #[ test]
5590+ fn avoids_recently_failed_paths ( ) {
5591+ // Ensure that the router always avoids all of the `previously_failed_channels` channels by
5592+ // randomly inserting channels into it until we can't find a route anymore.
5593+ let ( secp_ctx, network, _, _, logger) = build_graph ( ) ;
5594+ let ( _, our_id, _, nodes) = get_nodes ( & secp_ctx) ;
5595+ let network_graph = network. read_only ( ) ;
5596+
5597+ let scorer = test_utils:: TestScorer :: with_penalty ( 0 ) ;
5598+ let mut payment_params = PaymentParameters :: from_node_id ( nodes[ 6 ] ) . with_route_hints ( last_hops ( & nodes) )
5599+ . with_max_path_count ( 1 ) ;
5600+ let keys_manager = test_utils:: TestKeysInterface :: new ( & [ 0u8 ; 32 ] , Network :: Testnet ) ;
5601+ let random_seed_bytes = keys_manager. get_secure_random_bytes ( ) ;
5602+
5603+ // We should be able to find a route initially, and then after we fail a few random
5604+ // channels eventually we won't be able to any longer.
5605+ assert ! ( get_route( & our_id, & payment_params, & network_graph, None , 100 , 0 , Arc :: clone( & logger) , & scorer, & random_seed_bytes) . is_ok( ) ) ;
5606+ loop {
5607+ if let Ok ( route) = get_route ( & our_id, & payment_params, & network_graph, None , 100 , 0 , Arc :: clone ( & logger) , & scorer, & random_seed_bytes) {
5608+ for chan in route. paths [ 0 ] . iter ( ) {
5609+ assert ! ( !payment_params. previously_failed_channels. contains( & chan. short_channel_id) ) ;
5610+ }
5611+ let victim = ( u64:: from_ne_bytes ( random_seed_bytes[ 0 ..8 ] . try_into ( ) . unwrap ( ) ) as usize )
5612+ % route. paths [ 0 ] . len ( ) ;
5613+ payment_params. previously_failed_channels . push ( route. paths [ 0 ] [ victim] . short_channel_id ) ;
5614+ } else { break ; }
5615+ }
5616+ }
5617+
55765618 #[ test]
55775619 fn limits_path_length ( ) {
55785620 let ( secp_ctx, network, _, _, logger) = build_line_graph ( ) ;
0 commit comments