@@ -13,7 +13,7 @@ use util::ser::{Writeable, Readable};
13
13
use util:: logger:: Logger ;
14
14
15
15
use std:: cmp;
16
- use std:: collections:: { HashMap , BinaryHeap } ;
16
+ use std:: collections:: { HashMap , BinaryHeap , HashSet } ;
17
17
use std:: ops:: Deref ;
18
18
19
19
/// A hop in a route
@@ -119,7 +119,7 @@ pub struct RouteHint {
119
119
pub htlc_maximum_msat : Option < u64 > ,
120
120
}
121
121
122
- #[ derive( Eq , PartialEq ) ]
122
+ #[ derive( Eq , PartialEq , Clone ) ]
123
123
struct RouteGraphNode {
124
124
pubkey : PublicKey ,
125
125
lowest_fee_to_peer_through_node : u64 ,
@@ -336,7 +336,7 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, targ
336
336
}
337
337
338
338
macro_rules! add_entries_to_cheapest_to_target_node {
339
- ( $node: expr, $node_id: expr, $fee_to_target_msat: expr ) => {
339
+ ( $node: expr, $node_id: expr, $fee_to_target_msat: expr, $channels_to_avoid : expr ) => {
340
340
if first_hops. is_some( ) {
341
341
if let Some ( & ( ref first_hop, ref features) ) = first_hop_targets. get( & $node_id) {
342
342
add_entry!( first_hop, * our_node_id, $node_id, dummy_directional_info, None :: <u64 >, features. to_context( ) , $fee_to_target_msat) ;
@@ -352,6 +352,9 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, targ
352
352
353
353
if !features. requires_unknown_bits( ) {
354
354
for chan_id in $node. channels. iter( ) {
355
+ if $channels_to_avoid. contains( chan_id) {
356
+ continue ;
357
+ }
355
358
let chan = network. get_channels( ) . get( chan_id) . unwrap( ) ;
356
359
if !chan. features. requires_unknown_bits( ) {
357
360
if chan. node_one == * $node_id {
@@ -382,7 +385,7 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, targ
382
385
match network. get_nodes ( ) . get ( target) {
383
386
None => { } ,
384
387
Some ( node) => {
385
- add_entries_to_cheapest_to_target_node ! ( node, target, 0 ) ;
388
+ add_entries_to_cheapest_to_target_node ! ( node, target, 0 , HashSet :: < u64 > :: new ( ) ) ;
386
389
} ,
387
390
}
388
391
@@ -405,53 +408,85 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, targ
405
408
}
406
409
}
407
410
408
- while let Some ( RouteGraphNode { pubkey, lowest_fee_to_node, .. } ) = targets. pop ( ) {
409
- if pubkey == * our_node_id {
410
- let mut res = vec ! ( dist. remove( & our_node_id) . unwrap( ) . 3 ) ;
411
- loop {
412
- if let Some ( & ( _, ref features) ) = first_hop_targets. get ( & res. last ( ) . unwrap ( ) . pubkey ) {
413
- res. last_mut ( ) . unwrap ( ) . node_features = features. to_context ( ) ;
414
- } else if let Some ( node) = network. get_nodes ( ) . get ( & res. last ( ) . unwrap ( ) . pubkey ) {
415
- if let Some ( node_info) = node. announcement_info . as_ref ( ) {
416
- res. last_mut ( ) . unwrap ( ) . node_features = node_info. features . clone ( ) ;
411
+ let mut payment_paths = Vec :: new ( ) ;
412
+ let mut channels_to_avoid = HashSet :: new ( ) ;
413
+ let mut paths_cap = 3 ; // TODO: be smarter at limiting paths number considering the known available capacity.
414
+ ' route_finding: loop {
415
+ let mut cur_dist = dist. clone ( ) ;
416
+ let mut cur_targets = targets. clone ( ) ;
417
+ let mut using_low_capacity_channel = false ;
418
+ while let Some ( RouteGraphNode { pubkey, lowest_fee_to_node, .. } ) = cur_targets. pop ( ) {
419
+ if pubkey == * our_node_id {
420
+ let mut new_entry = cur_dist. remove ( & our_node_id) . unwrap ( ) ;
421
+ let mut res = vec ! ( new_entry. 3 . clone( ) ) ;
422
+ loop {
423
+ if let Some ( & ( _, ref features) ) = first_hop_targets. get ( & res. last ( ) . unwrap ( ) . pubkey ) {
424
+ res. last_mut ( ) . unwrap ( ) . node_features = features. to_context ( ) ;
425
+ } else if let Some ( node) = network. get_nodes ( ) . get ( & res. last ( ) . unwrap ( ) . pubkey ) {
426
+ if let Some ( node_info) = node. announcement_info . as_ref ( ) {
427
+ res. last_mut ( ) . unwrap ( ) . node_features = node_info. features . clone ( ) ;
428
+ } else {
429
+ res. last_mut ( ) . unwrap ( ) . node_features = NodeFeatures :: empty ( ) ;
430
+ }
417
431
} else {
418
- res. last_mut ( ) . unwrap ( ) . node_features = NodeFeatures :: empty ( ) ;
432
+ // We should be able to fill in features for everything except the last
433
+ // hop, if the last hop was provided via a BOLT 11 invoice (though we
434
+ // should be able to extend it further as BOLT 11 does have feature
435
+ // flags for the last hop node itself).
436
+ assert ! ( res. last( ) . unwrap( ) . pubkey == * target) ;
419
437
}
420
- } else {
421
- // We should be able to fill in features for everything except the last
422
- // hop, if the last hop was provided via a BOLT 11 invoice (though we
423
- // should be able to extend it further as BOLT 11 does have feature
424
- // flags for the last hop node itself).
425
- assert ! ( res. last( ) . unwrap( ) . pubkey == * target) ;
438
+
439
+ if let Some ( available_msat) = new_entry. 4 {
440
+ if available_msat < recommended_available_msat {
441
+ using_low_capacity_channel = true ;
442
+ }
443
+ } else {
444
+ using_low_capacity_channel = true ;
445
+ }
446
+
447
+ if using_low_capacity_channel {
448
+ // Do not use low-capacity channel for next MPP try.
449
+ channels_to_avoid. insert ( new_entry. 3 . short_channel_id ) ;
450
+ }
451
+
452
+ // TODO: for next MPP path, reduce the available capacity of channels
453
+ // used in the MPP path of current iteration.
454
+
455
+ if res. last ( ) . unwrap ( ) . pubkey == * target {
456
+ break ;
457
+ }
458
+
459
+ new_entry = match cur_dist. remove ( & res. last ( ) . unwrap ( ) . pubkey ) {
460
+ Some ( hop) => hop,
461
+ None => return Err ( LightningError { err : "Failed to find a non-fee-overflowing path to the given destination" . to_owned ( ) , action : ErrorAction :: IgnoreError } ) ,
462
+ } ;
463
+ res. last_mut ( ) . unwrap ( ) . fee_msat = new_entry. 3 . fee_msat ;
464
+ res. last_mut ( ) . unwrap ( ) . cltv_expiry_delta = new_entry. 3 . cltv_expiry_delta ;
465
+ res. push ( new_entry. 3 . clone ( ) ) ;
426
466
}
427
- if res. last ( ) . unwrap ( ) . pubkey == * target {
428
- break ;
467
+ res. last_mut ( ) . unwrap ( ) . fee_msat = final_value_msat;
468
+ res. last_mut ( ) . unwrap ( ) . cltv_expiry_delta = final_cltv;
469
+ payment_paths. push ( res) ;
470
+ tries += 1 ;
471
+ if !using_low_capacity_channel || tries == 5 {
472
+ break ' route_finding;
429
473
}
474
+ }
430
475
431
- let new_entry = match dist. remove ( & res. last ( ) . unwrap ( ) . pubkey ) {
432
- Some ( hop) => hop. 3 ,
433
- None => return Err ( LightningError { err : "Failed to find a non-fee-overflowing path to the given destination" . to_owned ( ) , action : ErrorAction :: IgnoreError } ) ,
434
- } ;
435
- res. last_mut ( ) . unwrap ( ) . fee_msat = new_entry. fee_msat ;
436
- res. last_mut ( ) . unwrap ( ) . cltv_expiry_delta = new_entry. cltv_expiry_delta ;
437
- res. push ( new_entry) ;
476
+ match network. get_nodes ( ) . get ( & pubkey) {
477
+ None => { } ,
478
+ Some ( node) => {
479
+ add_entries_to_cheapest_to_target_node ! ( node, & pubkey, lowest_fee_to_node, channels_to_avoid) ;
480
+ } ,
438
481
}
439
- res. last_mut ( ) . unwrap ( ) . fee_msat = final_value_msat;
440
- res. last_mut ( ) . unwrap ( ) . cltv_expiry_delta = final_cltv;
441
- let route = Route { paths : vec ! [ res] } ;
442
- log_trace ! ( logger, "Got route: {}" , log_route!( route) ) ;
443
- return Ok ( route) ;
444
482
}
445
483
446
- match network. get_nodes ( ) . get ( & pubkey) {
447
- None => { } ,
448
- Some ( node) => {
449
- add_entries_to_cheapest_to_target_node ! ( node, & pubkey, lowest_fee_to_node) ;
450
- } ,
451
- }
484
+ return Err ( LightningError { err : "Failed to find a path to the given destination" . to_owned ( ) , action : ErrorAction :: IgnoreError } ) ;
452
485
}
453
486
454
- Err ( LightningError { err : "Failed to find a path to the given destination" . to_owned ( ) , action : ErrorAction :: IgnoreError } )
487
+ let route = Route { paths : payment_paths } ;
488
+ log_trace ! ( logger, "Got route: {}" , log_route!( route) ) ;
489
+ return Ok ( route) ;
455
490
}
456
491
457
492
#[ cfg( test) ]
0 commit comments