@@ -240,6 +240,11 @@ pub struct PaymentParameters {
240
240
///
241
241
/// Default value: 1
242
242
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 > ,
243
248
}
244
249
245
250
impl_writeable_tlv_based ! ( PaymentParameters , {
@@ -250,6 +255,7 @@ impl_writeable_tlv_based!(PaymentParameters, {
250
255
( 4 , route_hints, vec_type) ,
251
256
( 5 , max_channel_saturation_power_of_half, ( default_value, 1 ) ) ,
252
257
( 6 , expiry_time, option) ,
258
+ ( 7 , previously_failed_channels, vec_type) ,
253
259
} ) ;
254
260
255
261
impl PaymentParameters {
@@ -263,6 +269,7 @@ impl PaymentParameters {
263
269
max_total_cltv_expiry_delta : DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA ,
264
270
max_path_count : DEFAULT_MAX_PATH_COUNT ,
265
271
max_channel_saturation_power_of_half : 1 ,
272
+ previously_failed_channels : Vec :: new ( ) ,
266
273
}
267
274
}
268
275
@@ -1002,7 +1009,7 @@ where L::Target: Logger {
1002
1009
let contributes_sufficient_value = available_value_contribution_msat >= minimal_value_contribution_msat;
1003
1010
// Do not consider candidate hops that would exceed the maximum path length.
1004
1011
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 ;
1006
1013
1007
1014
// Do not consider candidates that exceed the maximum total cltv expiry limit.
1008
1015
// In order to already account for some of the privacy enhancing random CLTV
@@ -1013,7 +1020,7 @@ where L::Target: Logger {
1013
1020
. unwrap_or( payment_params. max_total_cltv_expiry_delta - final_cltv_expiry_delta) ;
1014
1021
let hop_total_cltv_delta = ( $next_hops_cltv_delta as u32 )
1015
1022
. 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;
1017
1024
1018
1025
let value_contribution_msat = cmp:: min( available_value_contribution_msat, $next_hops_value_contribution) ;
1019
1026
// Includes paying fees for the use of the following channels.
@@ -1033,15 +1040,19 @@ where L::Target: Logger {
1033
1040
( amount_to_transfer_over_msat < $next_hops_path_htlc_minimum_msat &&
1034
1041
recommended_value_msat > $next_hops_path_htlc_minimum_msat) ) ;
1035
1042
1043
+ let payment_failed_on_this_channel =
1044
+ payment_params. previously_failed_channels. contains( & short_channel_id) ;
1045
+
1036
1046
// If HTLC minimum is larger than the amount we're going to transfer, we shouldn't
1037
1047
// bother considering this channel. If retrying with recommended_value_msat may
1038
1048
// allow us to hit the HTLC minimum limit, set htlc_minimum_limit so that we go
1039
1049
// 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 {
1042
1054
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 {
1045
1056
// Note that low contribution here (limited by available_liquidity_msat)
1046
1057
// might violate htlc_minimum_msat on the hops which are next along the
1047
1058
// payment path (upstream to the payee). To avoid that, we recompute
@@ -1993,6 +2004,8 @@ mod tests {
1993
2004
use prelude:: * ;
1994
2005
use sync:: { self , Arc } ;
1995
2006
2007
+ use core:: convert:: TryInto ;
2008
+
1996
2009
fn get_channel_details ( short_channel_id : Option < u64 > , node_id : PublicKey ,
1997
2010
features : InitFeatures , outbound_capacity_msat : u64 ) -> channelmanager:: ChannelDetails {
1998
2011
channelmanager:: ChannelDetails {
@@ -5573,6 +5586,35 @@ mod tests {
5573
5586
}
5574
5587
}
5575
5588
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
+
5576
5618
#[ test]
5577
5619
fn limits_path_length ( ) {
5578
5620
let ( secp_ctx, network, _, _, logger) = build_line_graph ( ) ;
0 commit comments