@@ -495,6 +495,10 @@ 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
+ self . hops . first ( ) . map ( |h| h. 0 . path_penalty_msat ) . unwrap_or ( u64:: max_value ( ) )
500
+ }
501
+
498
502
fn get_total_fee_paid_msat ( & self ) -> u64 {
499
503
if self . hops . len ( ) < 1 {
500
504
return 0 ;
@@ -645,7 +649,7 @@ where L::Target: Logger {
645
649
pub ( crate ) fn get_route < L : Deref , S : Score > (
646
650
our_node_pubkey : & PublicKey , payment_params : & PaymentParameters , network_graph : & ReadOnlyNetworkGraph ,
647
651
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 ]
649
653
) -> Result < Route , LightningError >
650
654
where L :: Target : Logger {
651
655
let payee_node_id = NodeId :: from_pubkey ( & payment_params. payee_pubkey ) ;
@@ -1449,17 +1453,24 @@ where L::Target: Logger {
1449
1453
1450
1454
// Draw multiple sufficient routes by randomly combining the selected paths.
1451
1455
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 {
1453
1461
let mut cur_route = Vec :: < PaymentPath > :: new ( ) ;
1454
1462
let mut aggregate_route_value_msat = 0 ;
1455
1463
1456
1464
// 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
+ }
1460
1471
1461
1472
// Step (7).
1462
- for payment_path in cur_payment_paths {
1473
+ for payment_path in & payment_paths {
1463
1474
cur_route. push ( payment_path. clone ( ) ) ;
1464
1475
aggregate_route_value_msat += payment_path. get_value_msat ( ) ;
1465
1476
if aggregate_route_value_msat > final_value_msat {
@@ -1469,12 +1480,17 @@ where L::Target: Logger {
1469
1480
// also makes routing more reliable.
1470
1481
let mut overpaid_value_msat = aggregate_route_value_msat - final_value_msat;
1471
1482
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
+
1478
1494
// We should make sure that at least 1 path left.
1479
1495
let mut paths_left = cur_route. len ( ) ;
1480
1496
cur_route. retain ( |path| {
0 commit comments