@@ -197,10 +197,6 @@ pub struct FixedPenaltyScorer {
197
197
penalty_msat : u64 ,
198
198
}
199
199
200
- impl_writeable_tlv_based ! ( FixedPenaltyScorer , {
201
- ( 0 , penalty_msat, required) ,
202
- } ) ;
203
-
204
200
impl FixedPenaltyScorer {
205
201
/// Creates a new scorer using `penalty_msat`.
206
202
pub fn with_penalty ( penalty_msat : u64 ) -> Self {
@@ -218,6 +214,22 @@ impl Score for FixedPenaltyScorer {
218
214
fn payment_path_successful ( & mut self , _path : & [ & RouteHop ] ) { }
219
215
}
220
216
217
+ impl Writeable for FixedPenaltyScorer {
218
+ #[ inline]
219
+ fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , io:: Error > {
220
+ write_tlv_fields ! ( w, { } ) ;
221
+ Ok ( ( ) )
222
+ }
223
+ }
224
+
225
+ impl ReadableArgs < u64 > for FixedPenaltyScorer {
226
+ #[ inline]
227
+ fn read < R : Read > ( r : & mut R , penalty_msat : u64 ) -> Result < Self , DecodeError > {
228
+ read_tlv_fields ! ( r, { } ) ;
229
+ Ok ( Self { penalty_msat } )
230
+ }
231
+ }
232
+
221
233
/// [`Score`] implementation that provides reasonable default behavior.
222
234
///
223
235
/// Used to apply a fixed penalty to each channel, thus avoiding long paths when shorter paths with
@@ -504,19 +516,24 @@ pub struct ProbabilisticScorerUsingTime<G: Deref<Target = NetworkGraph>, T: Time
504
516
}
505
517
506
518
/// Parameters for configuring [`ProbabilisticScorer`].
519
+ ///
520
+ /// Used to configure a base penalty and a liquidity penalty, the sum of which is the channel
521
+ /// penalty (i.e., the amount in msats willing to be paid to avoid routing through the channel).
507
522
#[ derive( Clone , Copy ) ]
508
523
pub struct ProbabilisticScoringParameters {
509
- /// A multiplier used to determine the amount in msats willing to be paid to avoid routing
510
- /// through a channel, as per multiplying by the negative `log10` of the channel's success
511
- /// probability for a payment.
524
+ /// A fixed penalty in msats to apply to each channel.
512
525
///
513
- /// The success probability is determined by the effective channel capacity, the payment amount,
514
- /// and knowledge learned from prior successful and unsuccessful payments. The lower bound of
515
- /// the success probability is 0.01, effectively limiting the penalty to the range
516
- /// `0..=2*liquidity_penalty_multiplier_msat`. The knowledge learned is decayed over time based
517
- /// on [`liquidity_offset_half_life`].
526
+ /// Default value: 500 msat
527
+ pub base_penalty_msat : u64 ,
528
+
529
+ /// A multiplier used in conjunction with the negative `log10` of the channel's success
530
+ /// probability for a payment to determine the liquidity penalty.
531
+ ///
532
+ /// The penalty is based in part by the knowledge learned from prior successful and unsuccessful
533
+ /// payments. This knowledge is decayed over time based on [`liquidity_offset_half_life`]. The
534
+ /// penalty is effectively limited to `2 * liquidity_penalty_multiplier_msat`.
518
535
///
519
- /// Default value: 10 ,000 msat
536
+ /// Default value: 40 ,000 msat
520
537
///
521
538
/// [`liquidity_offset_half_life`]: Self::liquidity_offset_half_life
522
539
pub liquidity_penalty_multiplier_msat : u64 ,
@@ -537,11 +554,6 @@ pub struct ProbabilisticScoringParameters {
537
554
pub liquidity_offset_half_life : Duration ,
538
555
}
539
556
540
- impl_writeable_tlv_based ! ( ProbabilisticScoringParameters , {
541
- ( 0 , liquidity_penalty_multiplier_msat, required) ,
542
- ( 2 , liquidity_offset_half_life, required) ,
543
- } ) ;
544
-
545
557
/// Accounting for channel liquidity balance uncertainty.
546
558
///
547
559
/// Direction is defined in terms of [`NodeId`] partial ordering, where the source node is the
@@ -590,7 +602,8 @@ impl<G: Deref<Target = NetworkGraph>, T: Time> ProbabilisticScorerUsingTime<G, T
590
602
impl Default for ProbabilisticScoringParameters {
591
603
fn default ( ) -> Self {
592
604
Self {
593
- liquidity_penalty_multiplier_msat : 10_000 ,
605
+ base_penalty_msat : 500 ,
606
+ liquidity_penalty_multiplier_msat : 40_000 ,
594
607
liquidity_offset_half_life : Duration :: from_secs ( 3600 ) ,
595
608
}
596
609
}
@@ -653,20 +666,21 @@ impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiqui
653
666
/// Returns a penalty for routing the given HTLC `amount_msat` through the channel in this
654
667
/// direction.
655
668
fn penalty_msat ( & self , amount_msat : u64 , liquidity_penalty_multiplier_msat : u64 ) -> u64 {
669
+ let max_penalty_msat = liquidity_penalty_multiplier_msat. saturating_mul ( 2 ) ;
656
670
let max_liquidity_msat = self . max_liquidity_msat ( ) ;
657
671
let min_liquidity_msat = core:: cmp:: min ( self . min_liquidity_msat ( ) , max_liquidity_msat) ;
658
672
if amount_msat > max_liquidity_msat {
659
- u64 :: max_value ( )
673
+ max_penalty_msat
660
674
} else if amount_msat <= min_liquidity_msat {
661
675
0
662
676
} else {
663
- let numerator = max_liquidity_msat + 1 - amount_msat;
664
- let denominator = max_liquidity_msat + 1 - min_liquidity_msat;
665
- approx:: negative_log10_times_1024 ( numerator, denominator)
666
- . saturating_mul ( liquidity_penalty_multiplier_msat) / 1024
677
+ let numerator = ( max_liquidity_msat - amount_msat) . saturating_add ( 1 ) ;
678
+ let denominator = ( max_liquidity_msat - min_liquidity_msat) . saturating_add ( 1 ) ;
679
+ let penalty_msat = approx:: negative_log10_times_1024 ( numerator, denominator)
680
+ . saturating_mul ( liquidity_penalty_multiplier_msat) / 1024 ;
681
+ // Upper bound the penalty to ensure some channel is selected.
682
+ penalty_msat. min ( max_penalty_msat)
667
683
}
668
- // Upper bound the penalty to ensure some channel is selected.
669
- . min ( 2 * liquidity_penalty_multiplier_msat)
670
684
}
671
685
672
686
/// Returns the lower bound of the channel liquidity balance in this direction.
@@ -745,6 +759,7 @@ impl<G: Deref<Target = NetworkGraph>, T: Time> Score for ProbabilisticScorerUsin
745
759
. unwrap_or ( & ChannelLiquidity :: new ( ) )
746
760
. as_directed ( source, target, capacity_msat, liquidity_offset_half_life)
747
761
. penalty_msat ( amount_msat, liquidity_penalty_multiplier_msat)
762
+ . saturating_add ( self . params . base_penalty_msat )
748
763
}
749
764
750
765
fn payment_path_failed ( & mut self , path : & [ & RouteHop ] , short_channel_id : u64 ) {
@@ -1722,7 +1737,7 @@ mod tests {
1722
1737
fn increased_penalty_nearing_liquidity_upper_bound ( ) {
1723
1738
let network_graph = network_graph ( ) ;
1724
1739
let params = ProbabilisticScoringParameters {
1725
- liquidity_penalty_multiplier_msat : 1_000 , ..Default :: default ( )
1740
+ base_penalty_msat : 0 , liquidity_penalty_multiplier_msat : 1_000 , ..Default :: default ( )
1726
1741
} ;
1727
1742
let scorer = ProbabilisticScorer :: new ( params, & network_graph) ;
1728
1743
let source = source_node_id ( ) ;
@@ -1747,7 +1762,7 @@ mod tests {
1747
1762
let last_updated = SinceEpoch :: now ( ) ;
1748
1763
let network_graph = network_graph ( ) ;
1749
1764
let params = ProbabilisticScoringParameters {
1750
- liquidity_penalty_multiplier_msat : 1_000 , ..Default :: default ( )
1765
+ base_penalty_msat : 0 , liquidity_penalty_multiplier_msat : 1_000 , ..Default :: default ( )
1751
1766
} ;
1752
1767
let scorer = ProbabilisticScorer :: new ( params, & network_graph)
1753
1768
. with_channel ( 42 ,
@@ -1767,7 +1782,7 @@ mod tests {
1767
1782
fn does_not_further_penalize_own_channel ( ) {
1768
1783
let network_graph = network_graph ( ) ;
1769
1784
let params = ProbabilisticScoringParameters {
1770
- liquidity_penalty_multiplier_msat : 1_000 , ..Default :: default ( )
1785
+ base_penalty_msat : 0 , liquidity_penalty_multiplier_msat : 1_000 , ..Default :: default ( )
1771
1786
} ;
1772
1787
let mut scorer = ProbabilisticScorer :: new ( params, & network_graph) ;
1773
1788
let sender = sender_node_id ( ) ;
@@ -1788,7 +1803,7 @@ mod tests {
1788
1803
fn sets_liquidity_lower_bound_on_downstream_failure ( ) {
1789
1804
let network_graph = network_graph ( ) ;
1790
1805
let params = ProbabilisticScoringParameters {
1791
- liquidity_penalty_multiplier_msat : 1_000 , ..Default :: default ( )
1806
+ base_penalty_msat : 0 , liquidity_penalty_multiplier_msat : 1_000 , ..Default :: default ( )
1792
1807
} ;
1793
1808
let mut scorer = ProbabilisticScorer :: new ( params, & network_graph) ;
1794
1809
let source = source_node_id ( ) ;
@@ -1810,7 +1825,7 @@ mod tests {
1810
1825
fn sets_liquidity_upper_bound_on_failure ( ) {
1811
1826
let network_graph = network_graph ( ) ;
1812
1827
let params = ProbabilisticScoringParameters {
1813
- liquidity_penalty_multiplier_msat : 1_000 , ..Default :: default ( )
1828
+ base_penalty_msat : 0 , liquidity_penalty_multiplier_msat : 1_000 , ..Default :: default ( )
1814
1829
} ;
1815
1830
let mut scorer = ProbabilisticScorer :: new ( params, & network_graph) ;
1816
1831
let source = source_node_id ( ) ;
@@ -1832,7 +1847,7 @@ mod tests {
1832
1847
fn reduces_liquidity_upper_bound_along_path_on_success ( ) {
1833
1848
let network_graph = network_graph ( ) ;
1834
1849
let params = ProbabilisticScoringParameters {
1835
- liquidity_penalty_multiplier_msat : 1_000 , ..Default :: default ( )
1850
+ base_penalty_msat : 0 , liquidity_penalty_multiplier_msat : 1_000 , ..Default :: default ( )
1836
1851
} ;
1837
1852
let mut scorer = ProbabilisticScorer :: new ( params, & network_graph) ;
1838
1853
let sender = sender_node_id ( ) ;
@@ -1856,6 +1871,7 @@ mod tests {
1856
1871
fn decays_liquidity_bounds_over_time ( ) {
1857
1872
let network_graph = network_graph ( ) ;
1858
1873
let params = ProbabilisticScoringParameters {
1874
+ base_penalty_msat : 0 ,
1859
1875
liquidity_penalty_multiplier_msat : 1_000 ,
1860
1876
liquidity_offset_half_life : Duration :: from_secs ( 10 ) ,
1861
1877
} ;
@@ -1907,6 +1923,7 @@ mod tests {
1907
1923
fn decays_liquidity_bounds_without_shift_overflow ( ) {
1908
1924
let network_graph = network_graph ( ) ;
1909
1925
let params = ProbabilisticScoringParameters {
1926
+ base_penalty_msat : 0 ,
1910
1927
liquidity_penalty_multiplier_msat : 1_000 ,
1911
1928
liquidity_offset_half_life : Duration :: from_secs ( 10 ) ,
1912
1929
} ;
@@ -1931,6 +1948,7 @@ mod tests {
1931
1948
fn restricts_liquidity_bounds_after_decay ( ) {
1932
1949
let network_graph = network_graph ( ) ;
1933
1950
let params = ProbabilisticScoringParameters {
1951
+ base_penalty_msat : 0 ,
1934
1952
liquidity_penalty_multiplier_msat : 1_000 ,
1935
1953
liquidity_offset_half_life : Duration :: from_secs ( 10 ) ,
1936
1954
} ;
@@ -1968,6 +1986,7 @@ mod tests {
1968
1986
fn restores_persisted_liquidity_bounds ( ) {
1969
1987
let network_graph = network_graph ( ) ;
1970
1988
let params = ProbabilisticScoringParameters {
1989
+ base_penalty_msat : 0 ,
1971
1990
liquidity_penalty_multiplier_msat : 1_000 ,
1972
1991
liquidity_offset_half_life : Duration :: from_secs ( 10 ) ,
1973
1992
} ;
@@ -1997,6 +2016,7 @@ mod tests {
1997
2016
fn decays_persisted_liquidity_bounds ( ) {
1998
2017
let network_graph = network_graph ( ) ;
1999
2018
let params = ProbabilisticScoringParameters {
2019
+ base_penalty_msat : 0 ,
2000
2020
liquidity_penalty_multiplier_msat : 1_000 ,
2001
2021
liquidity_offset_half_life : Duration :: from_secs ( 10 ) ,
2002
2022
} ;
@@ -2023,4 +2043,39 @@ mod tests {
2023
2043
SinceEpoch :: advance ( Duration :: from_secs ( 10 ) ) ;
2024
2044
assert_eq ! ( deserialized_scorer. channel_penalty_msat( 42 , 500 , 1_000 , & source, & target) , 371 ) ;
2025
2045
}
2046
+
2047
+ #[ test]
2048
+ fn adds_base_penalty_to_liquidity_penalty ( ) {
2049
+ let network_graph = network_graph ( ) ;
2050
+ let source = source_node_id ( ) ;
2051
+ let target = target_node_id ( ) ;
2052
+
2053
+ let params = ProbabilisticScoringParameters {
2054
+ base_penalty_msat : 0 , liquidity_penalty_multiplier_msat : 1_000 , ..Default :: default ( )
2055
+ } ;
2056
+ let scorer = ProbabilisticScorer :: new ( params, & network_graph) ;
2057
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 128 , 1_024 , & source, & target) , 58 ) ;
2058
+
2059
+ let params = ProbabilisticScoringParameters {
2060
+ base_penalty_msat : 500 , liquidity_penalty_multiplier_msat : 1_000 , ..Default :: default ( )
2061
+ } ;
2062
+ let scorer = ProbabilisticScorer :: new ( params, & network_graph) ;
2063
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , 128 , 1_024 , & source, & target) , 558 ) ;
2064
+ }
2065
+
2066
+ #[ test]
2067
+ fn calculates_log10_without_overflowing_u64_max_value ( ) {
2068
+ let network_graph = network_graph ( ) ;
2069
+ let source = source_node_id ( ) ;
2070
+ let target = target_node_id ( ) ;
2071
+
2072
+ let params = ProbabilisticScoringParameters {
2073
+ base_penalty_msat : 0 , ..Default :: default ( )
2074
+ } ;
2075
+ let scorer = ProbabilisticScorer :: new ( params, & network_graph) ;
2076
+ assert_eq ! (
2077
+ scorer. channel_penalty_msat( 42 , u64 :: max_value( ) , u64 :: max_value( ) , & source, & target) ,
2078
+ 80_000 ,
2079
+ ) ;
2080
+ }
2026
2081
}
0 commit comments