@@ -495,6 +495,10 @@ impl<'a> PaymentPath<'a> {
495495 self . hops . last ( ) . unwrap ( ) . 0 . fee_msat
496496 }
497497
498+ fn get_path_penalty_msat ( & self ) -> u64 {
499+ self . hops . first ( ) . map ( |h| h. 0 . path_penalty_msat ) . unwrap_or ( u64:: max_value ( ) )
500+ }
501+
498502 fn get_total_fee_paid_msat ( & self ) -> u64 {
499503 if self . hops . len ( ) < 1 {
500504 return 0 ;
@@ -645,7 +649,7 @@ where L::Target: Logger {
645649pub ( crate ) fn get_route < L : Deref , S : Score > (
646650 our_node_pubkey : & PublicKey , payment_params : & PaymentParameters , network_graph : & ReadOnlyNetworkGraph ,
647651 first_hops : Option < & [ & ChannelDetails ] > , final_value_msat : u64 , final_cltv_expiry_delta : u32 ,
648- logger : L , scorer : & S , _random_seed_bytes : & [ u8 ; 32 ]
652+ logger : L , scorer : & S , random_seed_bytes : & [ u8 ; 32 ]
649653) -> Result < Route , LightningError >
650654where L :: Target : Logger {
651655 let payee_node_id = NodeId :: from_pubkey ( & payment_params. payee_pubkey ) ;
@@ -1449,17 +1453,24 @@ where L::Target: Logger {
14491453
14501454 // Draw multiple sufficient routes by randomly combining the selected paths.
14511455 let mut drawn_routes = Vec :: new ( ) ;
1452- for i in 0 ..payment_paths. len ( ) {
1456+ let mut prng = ChaCha20 :: new ( random_seed_bytes, & [ 0u8 ; 12 ] ) ;
1457+ let mut random_index_bytes = [ 0u8 ; :: core:: mem:: size_of :: < usize > ( ) ] ;
1458+
1459+ let num_permutations = payment_paths. len ( ) ;
1460+ for _ in 0 ..num_permutations {
14531461 let mut cur_route = Vec :: < PaymentPath > :: new ( ) ;
14541462 let mut aggregate_route_value_msat = 0 ;
14551463
14561464 // Step (6).
1457- // TODO: real random shuffle
1458- // Currently just starts with i_th and goes up to i-1_th in a looped way.
1459- let cur_payment_paths = [ & payment_paths[ i..] , & payment_paths[ ..i] ] . concat ( ) ;
1465+ // Do a Fisher-Yates shuffle to create a random permutation of the payment paths
1466+ for cur_index in ( 1 ..payment_paths. len ( ) ) . rev ( ) {
1467+ prng. process_in_place ( & mut random_index_bytes) ;
1468+ let random_index = usize:: from_be_bytes ( random_index_bytes) . wrapping_rem ( cur_index+1 ) ;
1469+ payment_paths. swap ( cur_index, random_index) ;
1470+ }
14601471
14611472 // Step (7).
1462- for payment_path in cur_payment_paths {
1473+ for payment_path in & payment_paths {
14631474 cur_route. push ( payment_path. clone ( ) ) ;
14641475 aggregate_route_value_msat += payment_path. get_value_msat ( ) ;
14651476 if aggregate_route_value_msat > final_value_msat {
@@ -1469,12 +1480,17 @@ where L::Target: Logger {
14691480 // also makes routing more reliable.
14701481 let mut overpaid_value_msat = aggregate_route_value_msat - final_value_msat;
14711482
1472- // First, drop some expensive low-value paths entirely if possible.
1473- // Sort by value so that we drop many really-low values first, since
1474- // fewer paths is better: the payment is less likely to fail.
1475- // TODO: this could also be optimized by also sorting by feerate_per_sat_routed,
1476- // so that the sender pays less fees overall. And also htlc_minimum_msat.
1477- cur_route. sort_by_key ( |path| path. get_value_msat ( ) ) ;
1483+ // First, we drop some expensive low-value paths entirely if possible, since fewer
1484+ // paths is better: the payment is less likely to fail. In order to do so, we sort
1485+ // by value and fall back to total fees paid, i.e., in case of equal values we
1486+ // prefer lower cost paths.
1487+ cur_route. sort_unstable_by ( |a, b| {
1488+ a. get_value_msat ( ) . cmp ( & b. get_value_msat ( ) )
1489+ // Reverse ordering for fees, so we drop higher-fee paths first
1490+ . then_with ( || b. get_total_fee_paid_msat ( ) . saturating_add ( b. get_path_penalty_msat ( ) )
1491+ . cmp ( & a. get_total_fee_paid_msat ( ) . saturating_add ( a. get_path_penalty_msat ( ) ) ) )
1492+ } ) ;
1493+
14781494 // We should make sure that at least 1 path left.
14791495 let mut paths_left = cur_route. len ( ) ;
14801496 cur_route. retain ( |path| {
0 commit comments