@@ -238,7 +238,7 @@ pub struct PaymentParameters {
238
238
/// A value of 0 will allow payments up to and including a channel's total announced usable
239
239
/// capacity, a value of one will only use up to half its capacity, two 1/4, etc.
240
240
///
241
- /// Default value: 1
241
+ /// Default value: 2
242
242
pub max_channel_saturation_power_of_half : u8 ,
243
243
244
244
/// A list of SCIDs which this payment was previously attempted over and which caused the
@@ -253,7 +253,7 @@ impl_writeable_tlv_based!(PaymentParameters, {
253
253
( 2 , features, option) ,
254
254
( 3 , max_path_count, ( default_value, DEFAULT_MAX_PATH_COUNT ) ) ,
255
255
( 4 , route_hints, vec_type) ,
256
- ( 5 , max_channel_saturation_power_of_half, ( default_value, 1 ) ) ,
256
+ ( 5 , max_channel_saturation_power_of_half, ( default_value, 2 ) ) ,
257
257
( 6 , expiry_time, option) ,
258
258
( 7 , previously_failed_channels, vec_type) ,
259
259
} ) ;
@@ -268,7 +268,7 @@ impl PaymentParameters {
268
268
expiry_time : None ,
269
269
max_total_cltv_expiry_delta : DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA ,
270
270
max_path_count : DEFAULT_MAX_PATH_COUNT ,
271
- max_channel_saturation_power_of_half : 1 ,
271
+ max_channel_saturation_power_of_half : 2 ,
272
272
previously_failed_channels : Vec :: new ( ) ,
273
273
}
274
274
}
@@ -754,7 +754,7 @@ where L::Target: Logger, GL::Target: Logger {
754
754
pub ( crate ) fn get_route < L : Deref , S : Score > (
755
755
our_node_pubkey : & PublicKey , payment_params : & PaymentParameters , network_graph : & ReadOnlyNetworkGraph ,
756
756
first_hops : Option < & [ & ChannelDetails ] > , final_value_msat : u64 , final_cltv_expiry_delta : u32 ,
757
- logger : L , scorer : & S , random_seed_bytes : & [ u8 ; 32 ]
757
+ logger : L , scorer : & S , _random_seed_bytes : & [ u8 ; 32 ]
758
758
) -> Result < Route , LightningError >
759
759
where L :: Target : Logger {
760
760
let payee_node_id = NodeId :: from_pubkey ( & payment_params. payee_pubkey ) ;
@@ -796,11 +796,11 @@ where L::Target: Logger {
796
796
// 4. See if we managed to collect paths which aggregately are able to transfer target value
797
797
// (not recommended value).
798
798
// 5. If yes, proceed. If not, fail routing.
799
- // 6. Randomly combine paths into routes having enough to fulfill the payment. (TODO: knapsack)
800
- // 7. Of all the found paths, select only those with the lowest total fee .
801
- // 8. The last path in every selected route is likely to be more than we need .
802
- // Reduce its value-to-transfer and recompute fees.
803
- // 9. Choose the best route by the lowest total fee .
799
+ // 6. Select the paths which have the lowest cost (fee plus scorer penalty) per amount
800
+ // transferred up to the transfer target value .
801
+ // 7. Reduce the value of the last path until we are sending only the target value .
802
+ // 8. If our maximum channel saturation limit caused us to pick two identical paths, combine
803
+ // them so that we're not sending two HTLCs along the same path .
804
804
805
805
// As for the actual search algorithm,
806
806
// we do a payee-to-payer pseudo-Dijkstra's sorting by each node's distance from the payee
@@ -1476,7 +1476,7 @@ where L::Target: Logger {
1476
1476
// Both these cases (and other cases except reaching recommended_value_msat) mean that
1477
1477
// paths_collection will be stopped because found_new_path==false.
1478
1478
// This is not necessarily a routing failure.
1479
- ' path_construction: while let Some ( RouteGraphNode { node_id, lowest_fee_to_node, total_cltv_delta, value_contribution_msat, path_htlc_minimum_msat, path_penalty_msat, path_length_to_node, .. } ) = targets. pop ( ) {
1479
+ ' path_construction: while let Some ( RouteGraphNode { node_id, lowest_fee_to_node, total_cltv_delta, mut value_contribution_msat, path_htlc_minimum_msat, path_penalty_msat, path_length_to_node, .. } ) = targets. pop ( ) {
1480
1480
1481
1481
// Since we're going payee-to-payer, hitting our node as a target means we should stop
1482
1482
// traversing the graph and arrange the path out of what we found.
@@ -1542,7 +1542,9 @@ where L::Target: Logger {
1542
1542
// on some channels we already passed (assuming dest->source direction). Here, we
1543
1543
// recompute the fees again, so that if that's the case, we match the currently
1544
1544
// underpaid htlc_minimum_msat with fees.
1545
- payment_path. update_value_and_recompute_fees ( cmp:: min ( value_contribution_msat, final_value_msat) ) ;
1545
+ debug_assert_eq ! ( payment_path. get_value_msat( ) , value_contribution_msat) ;
1546
+ value_contribution_msat = cmp:: min ( value_contribution_msat, final_value_msat) ;
1547
+ payment_path. update_value_and_recompute_fees ( value_contribution_msat) ;
1546
1548
1547
1549
// Since a path allows to transfer as much value as
1548
1550
// the smallest channel it has ("bottleneck"), we should recompute
@@ -1653,96 +1655,55 @@ where L::Target: Logger {
1653
1655
return Err ( LightningError { err : "Failed to find a sufficient route to the given destination" . to_owned ( ) , action : ErrorAction :: IgnoreError } ) ;
1654
1656
}
1655
1657
1656
- // Sort by total fees and take the best paths.
1657
- payment_paths. sort_unstable_by_key ( |path| path. get_total_fee_paid_msat ( ) ) ;
1658
- if payment_paths. len ( ) > 50 {
1659
- payment_paths. truncate ( 50 ) ;
1660
- }
1658
+ // Step (6).
1659
+ let mut selected_route = payment_paths;
1661
1660
1662
- // Draw multiple sufficient routes by randomly combining the selected paths.
1663
- let mut drawn_routes = Vec :: new ( ) ;
1664
- let mut prng = ChaCha20 :: new ( random_seed_bytes, & [ 0u8 ; 12 ] ) ;
1665
- let mut random_index_bytes = [ 0u8 ; :: core:: mem:: size_of :: < usize > ( ) ] ;
1661
+ debug_assert_eq ! ( selected_route. iter( ) . map( |p| p. get_value_msat( ) ) . sum:: <u64 >( ) , already_collected_value_msat) ;
1662
+ let mut overpaid_value_msat = already_collected_value_msat - final_value_msat;
1666
1663
1667
- let num_permutations = payment_paths. len ( ) ;
1668
- for _ in 0 ..num_permutations {
1669
- let mut cur_route = Vec :: < PaymentPath > :: new ( ) ;
1670
- let mut aggregate_route_value_msat = 0 ;
1664
+ // First, sort by the cost-per-value of the path, dropping the paths that cost the most for
1665
+ // the value they contribute towards the payment amount.
1666
+ // We sort in descending order as we will remove from the front in `retain`, next.
1667
+ selected_route. sort_unstable_by ( |a, b|
1668
+ ( ( ( b. get_cost_msat ( ) as u128 ) << 64 ) / ( b. get_value_msat ( ) as u128 ) )
1669
+ . cmp ( & ( ( ( a. get_cost_msat ( ) as u128 ) << 64 ) / ( a. get_value_msat ( ) as u128 ) ) )
1670
+ ) ;
1671
1671
1672
- // Step (6).
1673
- // Do a Fisher-Yates shuffle to create a random permutation of the payment paths
1674
- for cur_index in ( 1 ..payment_paths. len ( ) ) . rev ( ) {
1675
- prng. process_in_place ( & mut random_index_bytes) ;
1676
- let random_index = usize:: from_be_bytes ( random_index_bytes) . wrapping_rem ( cur_index+1 ) ;
1677
- payment_paths. swap ( cur_index, random_index) ;
1672
+ // We should make sure that at least 1 path left.
1673
+ let mut paths_left = selected_route. len ( ) ;
1674
+ selected_route. retain ( |path| {
1675
+ if paths_left == 1 {
1676
+ return true
1677
+ }
1678
+ let path_value_msat = path. get_value_msat ( ) ;
1679
+ if path_value_msat <= overpaid_value_msat {
1680
+ overpaid_value_msat -= path_value_msat;
1681
+ paths_left -= 1 ;
1682
+ return false ;
1678
1683
}
1684
+ true
1685
+ } ) ;
1686
+ debug_assert ! ( selected_route. len( ) > 0 ) ;
1679
1687
1688
+ if overpaid_value_msat != 0 {
1680
1689
// Step (7).
1681
- for payment_path in & payment_paths {
1682
- cur_route. push ( payment_path. clone ( ) ) ;
1683
- aggregate_route_value_msat += payment_path. get_value_msat ( ) ;
1684
- if aggregate_route_value_msat > final_value_msat {
1685
- // Last path likely overpaid. Substract it from the most expensive
1686
- // (in terms of proportional fee) path in this route and recompute fees.
1687
- // This might be not the most economically efficient way, but fewer paths
1688
- // also makes routing more reliable.
1689
- let mut overpaid_value_msat = aggregate_route_value_msat - final_value_msat;
1690
-
1691
- // First, we drop some expensive low-value paths entirely if possible, since fewer
1692
- // paths is better: the payment is less likely to fail. In order to do so, we sort
1693
- // by value and fall back to total fees paid, i.e., in case of equal values we
1694
- // prefer lower cost paths.
1695
- cur_route. sort_unstable_by ( |a, b| {
1696
- a. get_value_msat ( ) . cmp ( & b. get_value_msat ( ) )
1697
- // Reverse ordering for cost, so we drop higher-cost paths first
1698
- . then_with ( || b. get_cost_msat ( ) . cmp ( & a. get_cost_msat ( ) ) )
1699
- } ) ;
1700
-
1701
- // We should make sure that at least 1 path left.
1702
- let mut paths_left = cur_route. len ( ) ;
1703
- cur_route. retain ( |path| {
1704
- if paths_left == 1 {
1705
- return true
1706
- }
1707
- let mut keep = true ;
1708
- let path_value_msat = path. get_value_msat ( ) ;
1709
- if path_value_msat <= overpaid_value_msat {
1710
- keep = false ;
1711
- overpaid_value_msat -= path_value_msat;
1712
- paths_left -= 1 ;
1713
- }
1714
- keep
1715
- } ) ;
1716
-
1717
- if overpaid_value_msat == 0 {
1718
- break ;
1719
- }
1690
+ // Now, subtract the remaining overpaid value from the most-expensive path.
1691
+ // TODO: this could also be optimized by also sorting by feerate_per_sat_routed,
1692
+ // so that the sender pays less fees overall. And also htlc_minimum_msat.
1693
+ selected_route. sort_unstable_by ( |a, b| {
1694
+ let a_f = a. hops . iter ( ) . map ( |hop| hop. 0 . candidate . fees ( ) . proportional_millionths as u64 ) . sum :: < u64 > ( ) ;
1695
+ let b_f = b. hops . iter ( ) . map ( |hop| hop. 0 . candidate . fees ( ) . proportional_millionths as u64 ) . sum :: < u64 > ( ) ;
1696
+ a_f. cmp ( & b_f) . then_with ( || b. get_cost_msat ( ) . cmp ( & a. get_cost_msat ( ) ) )
1697
+ } ) ;
1698
+ let expensive_payment_path = selected_route. first_mut ( ) . unwrap ( ) ;
1720
1699
1721
- assert ! ( cur_route. len( ) > 0 ) ;
1722
-
1723
- // Step (8).
1724
- // Now, subtract the overpaid value from the most-expensive path.
1725
- // TODO: this could also be optimized by also sorting by feerate_per_sat_routed,
1726
- // so that the sender pays less fees overall. And also htlc_minimum_msat.
1727
- cur_route. sort_unstable_by_key ( |path| { path. hops . iter ( ) . map ( |hop| hop. 0 . candidate . fees ( ) . proportional_millionths as u64 ) . sum :: < u64 > ( ) } ) ;
1728
- let expensive_payment_path = cur_route. first_mut ( ) . unwrap ( ) ;
1729
-
1730
- // We already dropped all the small value paths above, meaning all the
1731
- // remaining paths are larger than remaining overpaid_value_msat.
1732
- // Thus, this can't be negative.
1733
- let expensive_path_new_value_msat = expensive_payment_path. get_value_msat ( ) - overpaid_value_msat;
1734
- expensive_payment_path. update_value_and_recompute_fees ( expensive_path_new_value_msat) ;
1735
- break ;
1736
- }
1737
- }
1738
- drawn_routes. push ( cur_route) ;
1700
+ // We already dropped all the paths with value below `overpaid_value_msat` above, thus this
1701
+ // can't go negative.
1702
+ let expensive_path_new_value_msat = expensive_payment_path. get_value_msat ( ) - overpaid_value_msat;
1703
+ expensive_payment_path. update_value_and_recompute_fees ( expensive_path_new_value_msat) ;
1739
1704
}
1740
1705
1741
- // Step (9).
1742
- // Select the best route by lowest total cost.
1743
- drawn_routes. sort_unstable_by_key ( |paths| paths. iter ( ) . map ( |path| path. get_cost_msat ( ) ) . sum :: < u64 > ( ) ) ;
1744
- let selected_route = drawn_routes. first_mut ( ) . unwrap ( ) ;
1745
-
1706
+ // Step (8).
1746
1707
// Sort by the path itself and combine redundant paths.
1747
1708
// Note that we sort by SCIDs alone as its simpler but when combining we have to ensure we
1748
1709
// compare both SCIDs and NodeIds as individual nodes may use random aliases causing collisions
@@ -4796,7 +4757,7 @@ mod tests {
4796
4757
cltv_expiry_delta: 42 ,
4797
4758
htlc_minimum_msat: None ,
4798
4759
htlc_maximum_msat: None ,
4799
- } ] ) ] ) ;
4760
+ } ] ) ] ) . with_max_channel_saturation_power_of_half ( 0 ) ;
4800
4761
4801
4762
// Keep only two paths from us to nodes[2], both with a 99sat HTLC maximum, with one with
4802
4763
// no fee and one with a 1msat fee. Previously, trying to route 100 sats to nodes[2] here
@@ -5780,7 +5741,7 @@ mod tests {
5780
5741
flags : 0 ,
5781
5742
cltv_expiry_delta : ( 4 << 4 ) | 1 ,
5782
5743
htlc_minimum_msat : 0 ,
5783
- htlc_maximum_msat : OptionalField :: Present ( 200_000_000 ) ,
5744
+ htlc_maximum_msat : OptionalField :: Present ( 250_000_000 ) ,
5784
5745
fee_base_msat : 0 ,
5785
5746
fee_proportional_millionths : 0 ,
5786
5747
excess_data : Vec :: new ( )
@@ -5792,7 +5753,7 @@ mod tests {
5792
5753
flags : 0 ,
5793
5754
cltv_expiry_delta : ( 13 << 4 ) | 1 ,
5794
5755
htlc_minimum_msat : 0 ,
5795
- htlc_maximum_msat : OptionalField :: Present ( 200_000_000 ) ,
5756
+ htlc_maximum_msat : OptionalField :: Present ( 250_000_000 ) ,
5796
5757
fee_base_msat : 0 ,
5797
5758
fee_proportional_millionths : 0 ,
5798
5759
excess_data : Vec :: new ( )
@@ -5801,8 +5762,8 @@ mod tests {
5801
5762
let payment_params = PaymentParameters :: from_node_id ( nodes[ 2 ] ) . with_features ( InvoiceFeatures :: known ( ) ) ;
5802
5763
let keys_manager = test_utils:: TestKeysInterface :: new ( & [ 0u8 ; 32 ] , Network :: Testnet ) ;
5803
5764
let random_seed_bytes = keys_manager. get_secure_random_bytes ( ) ;
5804
- // 150 ,000 sat is less than the available liquidity on each channel, set above.
5805
- let route = get_route ( & our_id, & payment_params, & network_graph. read_only ( ) , None , 150_000_000 , 42 , Arc :: clone ( & logger) , & scorer, & random_seed_bytes) . unwrap ( ) ;
5765
+ // 100 ,000 sats is less than the available liquidity on each channel, set above.
5766
+ let route = get_route ( & our_id, & payment_params, & network_graph. read_only ( ) , None , 100_000_000 , 42 , Arc :: clone ( & logger) , & scorer, & random_seed_bytes) . unwrap ( ) ;
5806
5767
assert_eq ! ( route. paths. len( ) , 2 ) ;
5807
5768
assert ! ( ( route. paths[ 0 ] [ 1 ] . short_channel_id == 4 && route. paths[ 1 ] [ 1 ] . short_channel_id == 13 ) ||
5808
5769
( route. paths[ 1 ] [ 1 ] . short_channel_id == 4 && route. paths[ 0 ] [ 1 ] . short_channel_id == 13 ) ) ;
0 commit comments