@@ -579,6 +579,28 @@ pub struct ProbabilisticScoringFeeParameters {
579579 /// [`base_penalty_msat`]: Self::base_penalty_msat
580580 /// [`anti_probing_penalty_msat`]: Self::anti_probing_penalty_msat
581581 pub considered_impossible_penalty_msat : u64 ,
582+
583+ /// In order to calculate most of the scores above, we must first convert a lower and upper
584+ /// bound on the available liquidity in a channel into the probability that we think a payment
585+ /// will succeed. That probability is derived from a Probability Density Function for where we
586+ /// think the liquidity in a channel likely lies, given such bounds.
587+ ///
588+ /// If this flag is set, that PDF is simply a constant - we assume that the actual available
589+ /// liquidity in a channel is just as likely to be at any point between our lower and upper
590+ /// bounds.
591+ ///
592+ /// If this flag is *not* set, that PDF is `(x - 0.5*capacity) ^ 2`. That is, we use an
593+ /// exponential curve which expects the liquidity of a channel to lie "at the edges". This
594+ /// matches experimental results - most routing nodes do not aggressively rebalance their
595+ /// channels and flows in the network are often unbalanced, leaving liquidity usually
596+ /// unavailable.
597+ ///
598+ /// Thus, for the "best" routes, leave this flag `false`. However, the flag does imply a number
599+ /// of floating-point multiplications in the hottest routing code, which may lead to routing
600+ /// performance degradation on some machines.
601+ ///
602+ /// Default value: false
603+ pub linear_success_probability : bool ,
582604}
583605
584606impl Default for ProbabilisticScoringFeeParameters {
@@ -593,6 +615,7 @@ impl Default for ProbabilisticScoringFeeParameters {
593615 considered_impossible_penalty_msat : 1_0000_0000_000 ,
594616 historical_liquidity_penalty_multiplier_msat : 10_000 ,
595617 historical_liquidity_penalty_amount_multiplier_msat : 64 ,
618+ linear_success_probability : false ,
596619 }
597620 }
598621}
@@ -646,6 +669,7 @@ impl ProbabilisticScoringFeeParameters {
646669 manual_node_penalties : HashMap :: new ( ) ,
647670 anti_probing_penalty_msat : 0 ,
648671 considered_impossible_penalty_msat : 0 ,
672+ linear_success_probability : true ,
649673 }
650674 }
651675}
@@ -998,6 +1022,12 @@ const PRECISION_LOWER_BOUND_DENOMINATOR: u64 = approx::LOWER_BITS_BOUND;
9981022const AMOUNT_PENALTY_DIVISOR : u64 = 1 << 20 ;
9991023const BASE_AMOUNT_PENALTY_DIVISOR : u64 = 1 << 30 ;
10001024
1025+ /// Raises three `f64`s to the 3rd power, without `powi` because it requires `std` (dunno why).
1026+ #[ inline( always) ]
1027+ fn three_f64_pow_3 ( a : f64 , b : f64 , c : f64 ) -> ( f64 , f64 , f64 ) {
1028+ ( a * a * a, b * b * b, c * c * c)
1029+ }
1030+
10011031/// Given liquidity bounds, calculates the success probability (in the form of a numerator and
10021032/// denominator) of an HTLC. This is a key assumption in our scoring models.
10031033///
@@ -1008,14 +1038,46 @@ const BASE_AMOUNT_PENALTY_DIVISOR: u64 = 1 << 30;
10081038#[ inline( always) ]
10091039fn success_probability (
10101040 amount_msat : u64 , min_liquidity_msat : u64 , max_liquidity_msat : u64 , capacity_msat : u64 ,
1011- _params : & ProbabilisticScoringFeeParameters , min_zero_implies_no_successes : bool ,
1041+ params : & ProbabilisticScoringFeeParameters , min_zero_implies_no_successes : bool ,
10121042) -> ( u64 , u64 ) {
10131043 debug_assert ! ( min_liquidity_msat <= amount_msat) ;
10141044 debug_assert ! ( amount_msat < max_liquidity_msat) ;
10151045 debug_assert ! ( max_liquidity_msat <= capacity_msat) ;
10161046
1017- let numerator = max_liquidity_msat - amount_msat;
1018- let mut denominator = ( max_liquidity_msat - min_liquidity_msat) . saturating_add ( 1 ) ;
1047+ let ( numerator, mut denominator) =
1048+ if params. linear_success_probability {
1049+ ( max_liquidity_msat - amount_msat,
1050+ ( max_liquidity_msat - min_liquidity_msat) . saturating_add ( 1 ) )
1051+ } else {
1052+ let capacity = capacity_msat as f64 ;
1053+ let min = ( min_liquidity_msat as f64 ) / capacity;
1054+ let max = ( max_liquidity_msat as f64 ) / capacity;
1055+ let amount = ( amount_msat as f64 ) / capacity;
1056+
1057+ // Assume the channel has a probability density function of (x - 0.5)^2 for values from
1058+ // 0 to 1 (where 1 is the channel's full capacity). The success probability given some
1059+ // liquidity bounds is thus the integral under the curve from the amount to maximum
1060+ // estimated liquidity, divided by the same integral from the minimum to the maximum
1061+ // estimated liquidity bounds.
1062+ //
1063+ // Because the integral from x to y is simply (y - 0.5)^3 - (x - 0.5)^3, we can
1064+ // calculate the cumulative density function between the min/max bounds trivially. Note
1065+ // that we don't bother to normalize the CDF to total to 1, as it will come out in the
1066+ // division of num / den.
1067+ let ( max_pow, amt_pow, min_pow) = three_f64_pow_3 ( max - 0.5 , amount - 0.5 , min - 0.5 ) ;
1068+ let num = max_pow - amt_pow;
1069+ let den = max_pow - min_pow;
1070+
1071+ // Because our numerator and denominator max out at 0.5^3 we need to multiply them by
1072+ // quite a large factor to get something useful (ideally in the 2^30 range).
1073+ const BILLIONISH : f64 = 1024.0 * 1024.0 * 1024.0 ;
1074+ let numerator = ( num * BILLIONISH ) as u64 + 1 ;
1075+ let denominator = ( den * BILLIONISH ) as u64 + 1 ;
1076+ debug_assert ! ( numerator <= 1 << 30 , "Got large numerator ({}) from float {}." , numerator, num) ;
1077+ debug_assert ! ( denominator <= 1 << 30 , "Got large denominator ({}) from float {}." , denominator, den) ;
1078+ ( numerator, denominator)
1079+ } ;
1080+
10191081 if min_zero_implies_no_successes && min_liquidity_msat == 0 &&
10201082 denominator < u64:: max_value ( ) / 21
10211083 {
@@ -2963,47 +3025,47 @@ mod tests {
29633025 inflight_htlc_msat : 0 ,
29643026 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 950_000_000 , htlc_maximum_msat : 1_000 } ,
29653027 } ;
2966- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 6262 ) ;
3028+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 11497 ) ;
29673029 let usage = ChannelUsage {
29683030 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
29693031 } ;
2970- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4634 ) ;
3032+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 7408 ) ;
29713033 let usage = ChannelUsage {
29723034 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 2_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
29733035 } ;
2974- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4186 ) ;
3036+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 6151 ) ;
29753037 let usage = ChannelUsage {
29763038 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 3_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
29773039 } ;
2978- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 3909 ) ;
3040+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 5427 ) ;
29793041 let usage = ChannelUsage {
29803042 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 4_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
29813043 } ;
2982- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 3556 ) ;
3044+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4955 ) ;
29833045 let usage = ChannelUsage {
29843046 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 5_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
29853047 } ;
2986- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 3533 ) ;
3048+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4736 ) ;
29873049 let usage = ChannelUsage {
29883050 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 6_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
29893051 } ;
2990- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 3172 ) ;
3052+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4484 ) ;
29913053 let usage = ChannelUsage {
29923054 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 7_450_000_000 , htlc_maximum_msat : 1_000 } , ..usage
29933055 } ;
2994- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 3211 ) ;
3056+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4484 ) ;
29953057 let usage = ChannelUsage {
29963058 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 7_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
29973059 } ;
2998- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 3243 ) ;
3060+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4263 ) ;
29993061 let usage = ChannelUsage {
30003062 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 8_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
30013063 } ;
3002- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 3297 ) ;
3064+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4263 ) ;
30033065 let usage = ChannelUsage {
30043066 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 9_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
30053067 } ;
3006- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 3250 ) ;
3068+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4044 ) ;
30073069 }
30083070
30093071 #[ test]
0 commit comments