@@ -197,10 +197,6 @@ pub struct FixedPenaltyScorer {
197197 penalty_msat : u64 ,
198198}
199199
200- impl_writeable_tlv_based ! ( FixedPenaltyScorer , {
201- ( 0 , penalty_msat, required) ,
202- } ) ;
203-
204200impl FixedPenaltyScorer {
205201 /// Creates a new scorer using `penalty_msat`.
206202 pub fn with_penalty ( penalty_msat : u64 ) -> Self {
@@ -218,6 +214,22 @@ impl Score for FixedPenaltyScorer {
218214 fn payment_path_successful ( & mut self , _path : & [ & RouteHop ] ) { }
219215}
220216
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+
221233/// [`Score`] implementation that provides reasonable default behavior.
222234///
223235/// 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
504516}
505517
506518/// 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).
507522#[ derive( Clone , Copy ) ]
508523pub 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.
512525 ///
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`.
518535 ///
519- /// Default value: 10 ,000 msat
536+ /// Default value: 40 ,000 msat
520537 ///
521538 /// [`liquidity_offset_half_life`]: Self::liquidity_offset_half_life
522539 pub liquidity_penalty_multiplier_msat : u64 ,
@@ -537,11 +554,6 @@ pub struct ProbabilisticScoringParameters {
537554 pub liquidity_offset_half_life : Duration ,
538555}
539556
540- impl_writeable_tlv_based ! ( ProbabilisticScoringParameters , {
541- ( 0 , liquidity_penalty_multiplier_msat, required) ,
542- ( 2 , liquidity_offset_half_life, required) ,
543- } ) ;
544-
545557/// Accounting for channel liquidity balance uncertainty.
546558///
547559/// 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
590602impl Default for ProbabilisticScoringParameters {
591603 fn default ( ) -> Self {
592604 Self {
593- liquidity_penalty_multiplier_msat : 10_000 ,
605+ base_penalty_msat : 500 ,
606+ liquidity_penalty_multiplier_msat : 40_000 ,
594607 liquidity_offset_half_life : Duration :: from_secs ( 3600 ) ,
595608 }
596609 }
@@ -653,20 +666,21 @@ impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiqui
653666 /// Returns a penalty for routing the given HTLC `amount_msat` through the channel in this
654667 /// direction.
655668 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 ) ;
656670 let max_liquidity_msat = self . max_liquidity_msat ( ) ;
657671 let min_liquidity_msat = core:: cmp:: min ( self . min_liquidity_msat ( ) , max_liquidity_msat) ;
658672 if amount_msat > max_liquidity_msat {
659- u64 :: max_value ( )
673+ max_penalty_msat
660674 } else if amount_msat <= min_liquidity_msat {
661675 0
662676 } 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)
667683 }
668- // Upper bound the penalty to ensure some channel is selected.
669- . min ( 2 * liquidity_penalty_multiplier_msat)
670684 }
671685
672686 /// 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
745759 . unwrap_or ( & ChannelLiquidity :: new ( ) )
746760 . as_directed ( source, target, capacity_msat, liquidity_offset_half_life)
747761 . penalty_msat ( amount_msat, liquidity_penalty_multiplier_msat)
762+ . saturating_add ( self . params . base_penalty_msat )
748763 }
749764
750765 fn payment_path_failed ( & mut self , path : & [ & RouteHop ] , short_channel_id : u64 ) {
@@ -1722,7 +1737,7 @@ mod tests {
17221737 fn increased_penalty_nearing_liquidity_upper_bound ( ) {
17231738 let network_graph = network_graph ( ) ;
17241739 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 ( )
17261741 } ;
17271742 let scorer = ProbabilisticScorer :: new ( params, & network_graph) ;
17281743 let source = source_node_id ( ) ;
@@ -1747,7 +1762,7 @@ mod tests {
17471762 let last_updated = SinceEpoch :: now ( ) ;
17481763 let network_graph = network_graph ( ) ;
17491764 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 ( )
17511766 } ;
17521767 let scorer = ProbabilisticScorer :: new ( params, & network_graph)
17531768 . with_channel ( 42 ,
@@ -1767,7 +1782,7 @@ mod tests {
17671782 fn does_not_further_penalize_own_channel ( ) {
17681783 let network_graph = network_graph ( ) ;
17691784 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 ( )
17711786 } ;
17721787 let mut scorer = ProbabilisticScorer :: new ( params, & network_graph) ;
17731788 let sender = sender_node_id ( ) ;
@@ -1788,7 +1803,7 @@ mod tests {
17881803 fn sets_liquidity_lower_bound_on_downstream_failure ( ) {
17891804 let network_graph = network_graph ( ) ;
17901805 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 ( )
17921807 } ;
17931808 let mut scorer = ProbabilisticScorer :: new ( params, & network_graph) ;
17941809 let source = source_node_id ( ) ;
@@ -1810,7 +1825,7 @@ mod tests {
18101825 fn sets_liquidity_upper_bound_on_failure ( ) {
18111826 let network_graph = network_graph ( ) ;
18121827 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 ( )
18141829 } ;
18151830 let mut scorer = ProbabilisticScorer :: new ( params, & network_graph) ;
18161831 let source = source_node_id ( ) ;
@@ -1832,7 +1847,7 @@ mod tests {
18321847 fn reduces_liquidity_upper_bound_along_path_on_success ( ) {
18331848 let network_graph = network_graph ( ) ;
18341849 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 ( )
18361851 } ;
18371852 let mut scorer = ProbabilisticScorer :: new ( params, & network_graph) ;
18381853 let sender = sender_node_id ( ) ;
@@ -1856,6 +1871,7 @@ mod tests {
18561871 fn decays_liquidity_bounds_over_time ( ) {
18571872 let network_graph = network_graph ( ) ;
18581873 let params = ProbabilisticScoringParameters {
1874+ base_penalty_msat : 0 ,
18591875 liquidity_penalty_multiplier_msat : 1_000 ,
18601876 liquidity_offset_half_life : Duration :: from_secs ( 10 ) ,
18611877 } ;
@@ -1907,6 +1923,7 @@ mod tests {
19071923 fn decays_liquidity_bounds_without_shift_overflow ( ) {
19081924 let network_graph = network_graph ( ) ;
19091925 let params = ProbabilisticScoringParameters {
1926+ base_penalty_msat : 0 ,
19101927 liquidity_penalty_multiplier_msat : 1_000 ,
19111928 liquidity_offset_half_life : Duration :: from_secs ( 10 ) ,
19121929 } ;
@@ -1931,6 +1948,7 @@ mod tests {
19311948 fn restricts_liquidity_bounds_after_decay ( ) {
19321949 let network_graph = network_graph ( ) ;
19331950 let params = ProbabilisticScoringParameters {
1951+ base_penalty_msat : 0 ,
19341952 liquidity_penalty_multiplier_msat : 1_000 ,
19351953 liquidity_offset_half_life : Duration :: from_secs ( 10 ) ,
19361954 } ;
@@ -1968,6 +1986,7 @@ mod tests {
19681986 fn restores_persisted_liquidity_bounds ( ) {
19691987 let network_graph = network_graph ( ) ;
19701988 let params = ProbabilisticScoringParameters {
1989+ base_penalty_msat : 0 ,
19711990 liquidity_penalty_multiplier_msat : 1_000 ,
19721991 liquidity_offset_half_life : Duration :: from_secs ( 10 ) ,
19731992 } ;
@@ -1997,6 +2016,7 @@ mod tests {
19972016 fn decays_persisted_liquidity_bounds ( ) {
19982017 let network_graph = network_graph ( ) ;
19992018 let params = ProbabilisticScoringParameters {
2019+ base_penalty_msat : 0 ,
20002020 liquidity_penalty_multiplier_msat : 1_000 ,
20012021 liquidity_offset_half_life : Duration :: from_secs ( 10 ) ,
20022022 } ;
@@ -2023,4 +2043,39 @@ mod tests {
20232043 SinceEpoch :: advance ( Duration :: from_secs ( 10 ) ) ;
20242044 assert_eq ! ( deserialized_scorer. channel_penalty_msat( 42 , 500 , 1_000 , & source, & target) , 371 ) ;
20252045 }
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+ }
20262081}
0 commit comments