@@ -225,6 +225,11 @@ pub struct PaymentParameters {
225
225
/// The maximum number of paths that may be used by (MPP) payments.
226
226
/// Defaults to [`DEFAULT_MAX_PATH_COUNT`].
227
227
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 > ,
228
233
}
229
234
230
235
impl_writeable_tlv_based ! ( PaymentParameters , {
@@ -233,6 +238,7 @@ impl_writeable_tlv_based!(PaymentParameters, {
233
238
( 2 , features, option) ,
234
239
( 3 , max_path_count, ( default_value, DEFAULT_MAX_PATH_COUNT ) ) ,
235
240
( 4 , route_hints, vec_type) ,
241
+ ( 5 , previously_failed_channels, vec_type) ,
236
242
( 6 , expiry_time, option) ,
237
243
} ) ;
238
244
@@ -246,6 +252,7 @@ impl PaymentParameters {
246
252
expiry_time : None ,
247
253
max_total_cltv_expiry_delta : DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA ,
248
254
max_path_count : DEFAULT_MAX_PATH_COUNT ,
255
+ previously_failed_channels : Vec :: new ( ) ,
249
256
}
250
257
}
251
258
@@ -956,7 +963,7 @@ where L::Target: Logger {
956
963
let contributes_sufficient_value = available_value_contribution_msat >= minimal_value_contribution_msat;
957
964
// Do not consider candidate hops that would exceed the maximum path length.
958
965
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 ;
960
967
961
968
// Do not consider candidates that exceed the maximum total cltv expiry limit.
962
969
// In order to already account for some of the privacy enhancing random CLTV
@@ -967,7 +974,7 @@ where L::Target: Logger {
967
974
. unwrap_or( payment_params. max_total_cltv_expiry_delta - final_cltv_expiry_delta) ;
968
975
let hop_total_cltv_delta = ( $next_hops_cltv_delta as u32 )
969
976
. 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;
971
978
972
979
let value_contribution_msat = cmp:: min( available_value_contribution_msat, $next_hops_value_contribution) ;
973
980
// Includes paying fees for the use of the following channels.
@@ -987,15 +994,19 @@ where L::Target: Logger {
987
994
( amount_to_transfer_over_msat < $next_hops_path_htlc_minimum_msat &&
988
995
recommended_value_msat > $next_hops_path_htlc_minimum_msat) ) ;
989
996
997
+ let payment_failed_on_this_channel =
998
+ payment_params. previously_failed_channels. contains( & short_channel_id) ;
999
+
990
1000
// If HTLC minimum is larger than the amount we're going to transfer, we shouldn't
991
1001
// bother considering this channel. If retrying with recommended_value_msat may
992
1002
// allow us to hit the HTLC minimum limit, set htlc_minimum_limit so that we go
993
1003
// 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 {
996
1008
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 {
999
1010
// Note that low contribution here (limited by available_liquidity_msat)
1000
1011
// might violate htlc_minimum_msat on the hops which are next along the
1001
1012
// payment path (upstream to the payee). To avoid that, we recompute
@@ -1915,6 +1926,8 @@ mod tests {
1915
1926
use prelude:: * ;
1916
1927
use sync:: { self , Arc } ;
1917
1928
1929
+ use core:: convert:: TryInto ;
1930
+
1918
1931
fn get_channel_details ( short_channel_id : Option < u64 > , node_id : PublicKey ,
1919
1932
features : InitFeatures , outbound_capacity_msat : u64 ) -> channelmanager:: ChannelDetails {
1920
1933
channelmanager:: ChannelDetails {
@@ -5492,6 +5505,35 @@ mod tests {
5492
5505
}
5493
5506
}
5494
5507
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
+
5495
5537
#[ test]
5496
5538
fn limits_path_length ( ) {
5497
5539
let ( secp_ctx, network, _, _, logger) = build_line_graph ( ) ;
0 commit comments