@@ -495,6 +495,13 @@ impl<'a> PaymentPath<'a> {
495
495
self . hops . last ( ) . unwrap ( ) . 0 . fee_msat
496
496
}
497
497
498
+ fn get_path_penalty_msat ( & self ) -> u64 {
499
+ if self . hops . len ( ) < 1 {
500
+ return u64:: max_value ( ) ;
501
+ }
502
+ self . hops . first ( ) . unwrap ( ) . 0 . path_penalty_msat
503
+ }
504
+
498
505
fn get_total_fee_paid_msat ( & self ) -> u64 {
499
506
if self . hops . len ( ) < 1 {
500
507
return 0 ;
@@ -645,7 +652,7 @@ where L::Target: Logger {
645
652
pub ( crate ) fn get_route < L : Deref , S : Score > (
646
653
our_node_pubkey : & PublicKey , payment_params : & PaymentParameters , network_graph : & ReadOnlyNetworkGraph ,
647
654
first_hops : Option < & [ & ChannelDetails ] > , final_value_msat : u64 , final_cltv_expiry_delta : u32 ,
648
- logger : L , scorer : & S , _random_seed_bytes : & [ u8 ; 32 ]
655
+ logger : L , scorer : & S , random_seed_bytes : & [ u8 ; 32 ]
649
656
) -> Result < Route , LightningError >
650
657
where L :: Target : Logger {
651
658
let payee_node_id = NodeId :: from_pubkey ( & payment_params. payee_pubkey ) ;
@@ -1449,17 +1456,24 @@ where L::Target: Logger {
1449
1456
1450
1457
// Draw multiple sufficient routes by randomly combining the selected paths.
1451
1458
let mut drawn_routes = Vec :: new ( ) ;
1452
- for i in 0 ..payment_paths. len ( ) {
1459
+ let mut prng = ChaCha20 :: new ( random_seed_bytes, & [ 0u8 ; 12 ] ) ;
1460
+ let mut random_index_bytes = [ 0u8 ; :: core:: mem:: size_of :: < usize > ( ) ] ;
1461
+
1462
+ let num_permutations = payment_paths. len ( ) ;
1463
+ for _ in 0 ..num_permutations {
1453
1464
let mut cur_route = Vec :: < PaymentPath > :: new ( ) ;
1454
1465
let mut aggregate_route_value_msat = 0 ;
1455
1466
1456
1467
// 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 ( ) ;
1468
+ // Do a Fisher-Yates shuffle to create a random permutation of the payment paths
1469
+ for cur_index in ( 1 ..payment_paths. len ( ) ) . rev ( ) {
1470
+ prng. process_in_place ( & mut random_index_bytes) ;
1471
+ let random_index = usize:: from_be_bytes ( random_index_bytes) . wrapping_rem ( cur_index+1 ) ;
1472
+ payment_paths. swap ( cur_index, random_index) ;
1473
+ }
1460
1474
1461
1475
// Step (7).
1462
- for payment_path in cur_payment_paths {
1476
+ for payment_path in & payment_paths {
1463
1477
cur_route. push ( payment_path. clone ( ) ) ;
1464
1478
aggregate_route_value_msat += payment_path. get_value_msat ( ) ;
1465
1479
if aggregate_route_value_msat > final_value_msat {
@@ -1469,12 +1483,17 @@ where L::Target: Logger {
1469
1483
// also makes routing more reliable.
1470
1484
let mut overpaid_value_msat = aggregate_route_value_msat - final_value_msat;
1471
1485
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 ( ) ) ;
1486
+ // First, we drop some expensive low-value paths entirely if possible, since fewer
1487
+ // paths is better: the payment is less likely to fail. In order to do so, we sort
1488
+ // by value and fall back to total fees paid, i.e., in case of equal values values
1489
+ // we prefer lower cost paths.
1490
+ cur_route. sort_unstable_by ( |a, b| {
1491
+ a. get_value_msat ( ) . cmp ( & b. get_value_msat ( ) )
1492
+ // Reverse ordering for fees, so we drop higher-fee paths first
1493
+ . then_with ( || b. get_total_fee_paid_msat ( ) . saturating_add ( b. get_path_penalty_msat ( ) )
1494
+ . cmp ( & a. get_total_fee_paid_msat ( ) . saturating_add ( a. get_path_penalty_msat ( ) ) ) )
1495
+ } ) ;
1496
+
1478
1497
// We should make sure that at least 1 path left.
1479
1498
let mut paths_left = cur_route. len ( ) ;
1480
1499
cur_route. retain ( |path| {
0 commit comments