@@ -230,6 +230,10 @@ pub struct PaymentParameters {
230
230
/// channel, as a power of 1/2. A higher value prefers to send the payment using more MPP parts
231
231
/// whereas a lower value prefers to send larger MPP parts, potentially saturating channels.
232
232
///
233
+ /// Note that this restriction will be relaxed during pathfinding after paths which meet this
234
+ /// restriction have been found. While paths which meet this criteria will be searched for, it
235
+ /// is ultimately up to the scorer to select them over other paths.
236
+ ///
233
237
/// A value of 0 will allow payments up to and including a channel's total announced usable
234
238
/// capacity, a value of one will only use up to half its capacity, two 1/4, etc.
235
239
///
@@ -257,10 +261,6 @@ impl PaymentParameters {
257
261
expiry_time : None ,
258
262
max_total_cltv_expiry_delta : DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA ,
259
263
max_path_count : DEFAULT_MAX_PATH_COUNT ,
260
- #[ cfg( test) ] // Many tests were written prior to the introduction of this parameter, so
261
- // we leave it as 0 by default in tests, and change it for a few.
262
- max_channel_saturation_power_of_half : 0 ,
263
- #[ cfg( not( test) ) ]
264
264
max_channel_saturation_power_of_half : 1 ,
265
265
}
266
266
}
@@ -304,6 +304,13 @@ impl PaymentParameters {
304
304
pub fn with_max_path_count ( self , max_path_count : u8 ) -> Self {
305
305
Self { max_path_count, ..self }
306
306
}
307
+
308
+ /// Includes a limit for the maximum number of payment paths that may be used.
309
+ ///
310
+ /// (C-not exported) since bindings don't support move semantics
311
+ pub fn with_max_channel_saturation_power_of_half ( self , max_channel_saturation_power_of_half : u8 ) -> Self {
312
+ Self { max_channel_saturation_power_of_half, ..self }
313
+ }
307
314
}
308
315
309
316
/// A list of hops along a payment path terminating with a channel to the recipient.
@@ -486,6 +493,17 @@ fn max_htlc_from_capacity(capacity: EffectiveCapacity, max_channel_saturation_po
486
493
}
487
494
}
488
495
496
+ fn iter_equal < I1 : Iterator , I2 : Iterator > ( mut iter_a : I1 , mut iter_b : I2 )
497
+ -> bool where I1 :: Item : PartialEq < I2 :: Item > {
498
+ loop {
499
+ let a = iter_a. next ( ) ;
500
+ let b = iter_b. next ( ) ;
501
+ if a. is_none ( ) && b. is_none ( ) { return true ; }
502
+ if a. is_none ( ) || b. is_none ( ) { return false ; }
503
+ if a. unwrap ( ) . ne ( & b. unwrap ( ) ) { return false ; }
504
+ }
505
+ }
506
+
489
507
/// It's useful to keep track of the hops associated with the fees required to use them,
490
508
/// so that we can choose cheaper paths (as per Dijkstra's algorithm).
491
509
/// Fee values should be updated only in the context of the whole path, see update_value_and_recompute_fees.
@@ -593,10 +611,9 @@ impl<'a> PaymentPath<'a> {
593
611
// to the fees being paid not lining up with the actual limits.
594
612
//
595
613
// Note that this function is not aware of the available_liquidity limit, and thus does not
596
- // support increasing the value being transferred.
614
+ // support increasing the value being transferred beyond what was selected during the initial
615
+ // routing passes.
597
616
fn update_value_and_recompute_fees ( & mut self , value_msat : u64 ) {
598
- assert ! ( value_msat <= self . hops. last( ) . unwrap( ) . 0 . fee_msat) ;
599
-
600
617
let mut total_fee_paid_msat = 0 as u64 ;
601
618
for i in ( 0 ..self . hops . len ( ) ) . rev ( ) {
602
619
let last_hop = i == self . hops . len ( ) - 1 ;
@@ -904,6 +921,11 @@ where L::Target: Logger {
904
921
final_value_msat
905
922
} ;
906
923
924
+ // When we start collecting routes we enforce the max_channel_saturation_power_of_half
925
+ // requirement strictly. After we've collected enough (or if we fail to find new routes) we
926
+ // drop the requirement by setting this to 0.
927
+ let mut channel_saturation_pow_half = payment_params. max_channel_saturation_power_of_half ;
928
+
907
929
// Keep track of how much liquidity has been used in selected channels. Used to determine
908
930
// if the channel can be used by additional MPP paths or to inform path finding decisions. It is
909
931
// aware of direction *only* to ensure that the correct htlc_maximum_msat value is used. Hence,
@@ -957,7 +979,7 @@ where L::Target: Logger {
957
979
if $src_node_id != $dest_node_id {
958
980
let short_channel_id = $candidate. short_channel_id( ) ;
959
981
let effective_capacity = $candidate. effective_capacity( ) ;
960
- let htlc_maximum_msat = max_htlc_from_capacity( effective_capacity, payment_params . max_channel_saturation_power_of_half ) ;
982
+ let htlc_maximum_msat = max_htlc_from_capacity( effective_capacity, channel_saturation_pow_half ) ;
961
983
962
984
// It is tricky to subtract $next_hops_fee_msat from available liquidity here.
963
985
// It may be misleading because we might later choose to reduce the value transferred
@@ -1529,8 +1551,7 @@ where L::Target: Logger {
1529
1551
. and_modify ( |used_liquidity_msat| * used_liquidity_msat += spent_on_hop_msat)
1530
1552
. or_insert ( spent_on_hop_msat) ;
1531
1553
let hop_capacity = hop. candidate . effective_capacity ( ) ;
1532
- let hop_max_msat = max_htlc_from_capacity ( hop_capacity,
1533
- payment_params. max_channel_saturation_power_of_half ) ;
1554
+ let hop_max_msat = max_htlc_from_capacity ( hop_capacity, channel_saturation_pow_half) ;
1534
1555
if * used_liquidity_msat == hop_max_msat {
1535
1556
// If this path used all of this channel's available liquidity, we know
1536
1557
// this path will not be selected again in the next loop iteration.
@@ -1577,6 +1598,10 @@ where L::Target: Logger {
1577
1598
}
1578
1599
1579
1600
if !allow_mpp {
1601
+ if !found_new_path && channel_saturation_pow_half != 0 {
1602
+ channel_saturation_pow_half = 0 ;
1603
+ continue ' paths_collection;
1604
+ }
1580
1605
// If we don't support MPP, no use trying to gather more value ever.
1581
1606
break ' paths_collection;
1582
1607
}
@@ -1586,7 +1611,9 @@ where L::Target: Logger {
1586
1611
// iteration.
1587
1612
// In the latter case, making another path finding attempt won't help,
1588
1613
// because we deterministically terminated the search due to low liquidity.
1589
- if already_collected_value_msat >= recommended_value_msat || !found_new_path {
1614
+ if !found_new_path && channel_saturation_pow_half != 0 {
1615
+ channel_saturation_pow_half = 0 ;
1616
+ } else if already_collected_value_msat >= recommended_value_msat || !found_new_path {
1590
1617
log_trace ! ( logger, "Have now collected {} msat (seeking {} msat) in paths. Last path loop {} a new path." ,
1591
1618
already_collected_value_msat, recommended_value_msat, if found_new_path { "found" } else { "did not find" } ) ;
1592
1619
break ' paths_collection;
@@ -1702,8 +1729,32 @@ where L::Target: Logger {
1702
1729
// Step (9).
1703
1730
// Select the best route by lowest total cost.
1704
1731
drawn_routes. sort_unstable_by_key ( |paths| paths. iter ( ) . map ( |path| path. get_cost_msat ( ) ) . sum :: < u64 > ( ) ) ;
1732
+ let selected_route = drawn_routes. first_mut ( ) . unwrap ( ) ;
1733
+
1734
+ // Sort by the path itself and combine redundant paths.
1735
+ // Note that we sort by SCIDs alone as its simpler but when combining we have to ensure we
1736
+ // compare both SCIDs and NodeIds as individual nodes may use random aliases causing collisions
1737
+ // across nodes.
1738
+ selected_route. sort_unstable_by_key ( |path| {
1739
+ let mut key = [ 0u64 ; MAX_PATH_LENGTH_ESTIMATE as usize ] ;
1740
+ debug_assert ! ( path. hops. len( ) <= key. len( ) ) ;
1741
+ for ( scid, key) in path. hops . iter ( ) . map ( |h| h. 0 . candidate . short_channel_id ( ) ) . zip ( key. iter_mut ( ) ) {
1742
+ * key = scid;
1743
+ }
1744
+ key
1745
+ } ) ;
1746
+ for idx in 0 ..( selected_route. len ( ) - 1 ) {
1747
+ if idx + 1 >= selected_route. len ( ) { break ; }
1748
+ if iter_equal ( selected_route[ idx ] . hops . iter ( ) . map ( |h : & ( PathBuildingHop < ' _ > , _ ) | ( h. 0 . candidate . short_channel_id ( ) , h. 0 . node_id ) ) ,
1749
+ selected_route[ idx + 1 ] . hops . iter ( ) . map ( |h : & ( PathBuildingHop < ' _ > , _ ) | ( h. 0 . candidate . short_channel_id ( ) , h. 0 . node_id ) ) ) {
1750
+ let new_value = selected_route[ idx] . get_value_msat ( ) + selected_route[ idx + 1 ] . get_value_msat ( ) ;
1751
+ selected_route[ idx] . update_value_and_recompute_fees ( new_value) ;
1752
+ selected_route. remove ( idx + 1 ) ;
1753
+ }
1754
+ }
1755
+
1705
1756
let mut selected_paths = Vec :: < Vec < Result < RouteHop , LightningError > > > :: new ( ) ;
1706
- for payment_path in drawn_routes . first ( ) . unwrap ( ) {
1757
+ for payment_path in selected_route {
1707
1758
let mut path = payment_path. hops . iter ( ) . map ( |( payment_hop, node_features) | {
1708
1759
Ok ( RouteHop {
1709
1760
pubkey : PublicKey :: from_slice ( payment_hop. node_id . as_slice ( ) ) . map_err ( |_| LightningError { err : format ! ( "Public key {:?} is invalid" , & payment_hop. node_id) , action : ErrorAction :: IgnoreAndLog ( Level :: Trace ) } ) ?,
@@ -4789,17 +4840,18 @@ mod tests {
4789
4840
4790
4841
// Get a route for 100 sats and check that we found the MPP route no problem and didn't
4791
4842
// overpay at all.
4792
- let route = get_route ( & our_id, & payment_params, & network_graph. read_only ( ) , None , 100_000 , 42 , Arc :: clone ( & logger) , & scorer, & random_seed_bytes) . unwrap ( ) ;
4843
+ let mut route = get_route ( & our_id, & payment_params, & network_graph. read_only ( ) , None , 100_000 , 42 , Arc :: clone ( & logger) , & scorer, & random_seed_bytes) . unwrap ( ) ;
4793
4844
assert_eq ! ( route. paths. len( ) , 2 ) ;
4794
- // Paths are somewhat randomly ordered, but:
4795
- // * the first is channel 2 (1 msat fee) -> channel 4 -> channel 42
4796
- // * the second is channel 1 (0 fee, but 99 sat maximum) -> channel 3 -> channel 42
4797
- assert_eq ! ( route. paths[ 0 ] [ 0 ] . short_channel_id, 2 ) ;
4798
- assert_eq ! ( route. paths[ 0 ] [ 0 ] . fee_msat, 1 ) ;
4799
- assert_eq ! ( route. paths[ 0 ] [ 2 ] . fee_msat, 1_000 ) ;
4800
- assert_eq ! ( route. paths[ 1 ] [ 0 ] . short_channel_id, 1 ) ;
4801
- assert_eq ! ( route. paths[ 1 ] [ 0 ] . fee_msat, 0 ) ;
4802
- assert_eq ! ( route. paths[ 1 ] [ 2 ] . fee_msat, 99_000 ) ;
4845
+ route. paths . sort_by_key ( |path| path[ 0 ] . short_channel_id ) ;
4846
+ // Paths are manually ordered ordered by SCID, so:
4847
+ // * the first is channel 1 (0 fee, but 99 sat maximum) -> channel 3 -> channel 42
4848
+ // * the second is channel 2 (1 msat fee) -> channel 4 -> channel 42
4849
+ assert_eq ! ( route. paths[ 0 ] [ 0 ] . short_channel_id, 1 ) ;
4850
+ assert_eq ! ( route. paths[ 0 ] [ 0 ] . fee_msat, 0 ) ;
4851
+ assert_eq ! ( route. paths[ 0 ] [ 2 ] . fee_msat, 99_000 ) ;
4852
+ assert_eq ! ( route. paths[ 1 ] [ 0 ] . short_channel_id, 2 ) ;
4853
+ assert_eq ! ( route. paths[ 1 ] [ 0 ] . fee_msat, 1 ) ;
4854
+ assert_eq ! ( route. paths[ 1 ] [ 2 ] . fee_msat, 1_000 ) ;
4803
4855
assert_eq ! ( route. get_total_fees( ) , 1 ) ;
4804
4856
assert_eq ! ( route. get_total_amount( ) , 100_000 ) ;
4805
4857
}
@@ -4813,7 +4865,8 @@ mod tests {
4813
4865
let scorer = test_utils:: TestScorer :: with_penalty ( 0 ) ;
4814
4866
let keys_manager = test_utils:: TestKeysInterface :: new ( & [ 0u8 ; 32 ] , Network :: Testnet ) ;
4815
4867
let random_seed_bytes = keys_manager. get_secure_random_bytes ( ) ;
4816
- let payment_params = PaymentParameters :: from_node_id ( nodes[ 2 ] ) . with_features ( InvoiceFeatures :: known ( ) ) ;
4868
+ let payment_params = PaymentParameters :: from_node_id ( nodes[ 2 ] ) . with_features ( InvoiceFeatures :: known ( ) )
4869
+ . with_max_channel_saturation_power_of_half ( 0 ) ;
4817
4870
4818
4871
// We need a route consisting of 3 paths:
4819
4872
// From our node to node2 via node0, node7, node1 (three paths one hop each).
@@ -5261,12 +5314,13 @@ mod tests {
5261
5314
assert_eq ! ( route. paths[ 0 ] . len( ) , 1 ) ;
5262
5315
assert_eq ! ( route. paths[ 1 ] . len( ) , 1 ) ;
5263
5316
5317
+ assert ! ( ( route. paths[ 0 ] [ 0 ] . short_channel_id == 3 && route. paths[ 1 ] [ 0 ] . short_channel_id == 2 ) ||
5318
+ ( route. paths[ 0 ] [ 0 ] . short_channel_id == 2 && route. paths[ 1 ] [ 0 ] . short_channel_id == 3 ) ) ;
5319
+
5264
5320
assert_eq ! ( route. paths[ 0 ] [ 0 ] . pubkey, nodes[ 0 ] ) ;
5265
- assert_eq ! ( route. paths[ 0 ] [ 0 ] . short_channel_id, 3 ) ;
5266
5321
assert_eq ! ( route. paths[ 0 ] [ 0 ] . fee_msat, 50_000 ) ;
5267
5322
5268
5323
assert_eq ! ( route. paths[ 1 ] [ 0 ] . pubkey, nodes[ 0 ] ) ;
5269
- assert_eq ! ( route. paths[ 1 ] [ 0 ] . short_channel_id, 2 ) ;
5270
5324
assert_eq ! ( route. paths[ 1 ] [ 0 ] . fee_msat, 50_000 ) ;
5271
5325
}
5272
5326
0 commit comments