@@ -580,6 +580,28 @@ pub struct ProbabilisticScoringFeeParameters {
580580 /// [`base_penalty_msat`]: Self::base_penalty_msat
581581 /// [`anti_probing_penalty_msat`]: Self::anti_probing_penalty_msat
582582 pub considered_impossible_penalty_msat : u64 ,
583+
584+ /// In order to calculate most of the scores above, we must first convert a lower and upper
585+ /// bound on the available liquidity in a channel into the probability that we think a payment
586+ /// will succeed. That probability is derived from a Probability Density Function for where we
587+ /// think the liquidity in a channel likely lies, given such bounds.
588+ ///
589+ /// If this flag is set, that PDF is simply a constant - we assume that the actual available
590+ /// liquidity in a channel is just as likely to be at any point between our lower and upper
591+ /// bounds.
592+ ///
593+ /// If this flag is *not* set, that PDF is `(x - 0.5*capacity) ^ 2`. That is, we use an
594+ /// exponential curve which expects the liquidity of a channel to lie "at the edges". This
595+ /// matches experimental results - most routing nodes do not aggressively rebalance their
596+ /// channels and flows in the network are often unbalanced, leaving liquidity usually
597+ /// unavailable.
598+ ///
599+ /// Thus, for the "best" routes, leave this flag `false`. However, the flag does imply a number
600+ /// of floating-point multiplications in the hottest routing code, which may lead to routing
601+ /// performance degradation on some machines.
602+ ///
603+ /// Default value: false
604+ pub linear_success_probability : bool ,
583605}
584606
585607impl Default for ProbabilisticScoringFeeParameters {
@@ -594,6 +616,7 @@ impl Default for ProbabilisticScoringFeeParameters {
594616 considered_impossible_penalty_msat : 1_0000_0000_000 ,
595617 historical_liquidity_penalty_multiplier_msat : 10_000 ,
596618 historical_liquidity_penalty_amount_multiplier_msat : 64 ,
619+ linear_success_probability : false ,
597620 }
598621 }
599622}
@@ -647,6 +670,7 @@ impl ProbabilisticScoringFeeParameters {
647670 manual_node_penalties : HashMap :: new ( ) ,
648671 anti_probing_penalty_msat : 0 ,
649672 considered_impossible_penalty_msat : 0 ,
673+ linear_success_probability : true ,
650674 }
651675 }
652676}
@@ -999,6 +1023,12 @@ const PRECISION_LOWER_BOUND_DENOMINATOR: u64 = approx::LOWER_BITS_BOUND;
9991023const AMOUNT_PENALTY_DIVISOR : u64 = 1 << 20 ;
10001024const BASE_AMOUNT_PENALTY_DIVISOR : u64 = 1 << 30 ;
10011025
1026+ /// Raises three `f64`s to the 3rd power, without `powi` because it requires `std` (dunno why).
1027+ #[ inline( always) ]
1028+ fn three_f64_pow_3 ( a : f64 , b : f64 , c : f64 ) -> ( f64 , f64 , f64 ) {
1029+ ( a * a * a, b * b * b, c * c * c)
1030+ }
1031+
10021032/// Given liquidity bounds, calculates the success probability (in the form of a numerator and
10031033/// denominator) of an HTLC. This is a key assumption in our scoring models.
10041034///
@@ -1009,14 +1039,46 @@ const BASE_AMOUNT_PENALTY_DIVISOR: u64 = 1 << 30;
10091039#[ inline( always) ]
10101040fn success_probability (
10111041 amount_msat : u64 , min_liquidity_msat : u64 , max_liquidity_msat : u64 , capacity_msat : u64 ,
1012- _params : & ProbabilisticScoringFeeParameters , min_zero_implies_no_successes : bool ,
1042+ params : & ProbabilisticScoringFeeParameters , min_zero_implies_no_successes : bool ,
10131043) -> ( u64 , u64 ) {
10141044 debug_assert ! ( min_liquidity_msat <= amount_msat) ;
10151045 debug_assert ! ( amount_msat < max_liquidity_msat) ;
10161046 debug_assert ! ( max_liquidity_msat <= capacity_msat) ;
10171047
1018- let numerator = max_liquidity_msat - amount_msat;
1019- let mut denominator = ( max_liquidity_msat - min_liquidity_msat) . saturating_add ( 1 ) ;
1048+ let ( numerator, mut denominator) =
1049+ if params. linear_success_probability {
1050+ ( max_liquidity_msat - amount_msat,
1051+ ( max_liquidity_msat - min_liquidity_msat) . saturating_add ( 1 ) )
1052+ } else {
1053+ let capacity = capacity_msat as f64 ;
1054+ let min = ( min_liquidity_msat as f64 ) / capacity;
1055+ let max = ( max_liquidity_msat as f64 ) / capacity;
1056+ let amount = ( amount_msat as f64 ) / capacity;
1057+
1058+ // Assume the channel has a probability density function of (x - 0.5)^2 for values from
1059+ // 0 to 1 (where 1 is the channel's full capacity). The success probability given some
1060+ // liquidity bounds is thus the integral under the curve from the amount to maximum
1061+ // estimated liquidity, divided by the same integral from the minimum to the maximum
1062+ // estimated liquidity bounds.
1063+ //
1064+ // Because the integral from x to y is simply (y - 0.5)^3 - (x - 0.5)^3, we can
1065+ // calculate the cumulative density function between the min/max bounds trivially. Note
1066+ // that we don't bother to normalize the CDF to total to 1, as it will come out in the
1067+ // division of num / den.
1068+ let ( max_pow, amt_pow, min_pow) = three_f64_pow_3 ( max - 0.5 , amount - 0.5 , min - 0.5 ) ;
1069+ let num = max_pow - amt_pow;
1070+ let den = max_pow - min_pow;
1071+
1072+ // Because our numerator and denominator max out at 0.5^3 we need to multiply them by
1073+ // quite a large factor to get something useful (ideally in the 2^30 range).
1074+ const BILLIONISH : f64 = 1024.0 * 1024.0 * 1024.0 ;
1075+ let numerator = ( num * BILLIONISH ) as u64 + 1 ;
1076+ let denominator = ( den * BILLIONISH ) as u64 + 1 ;
1077+ debug_assert ! ( numerator <= 1 << 30 , "Got large numerator ({}) from float {}." , numerator, num) ;
1078+ debug_assert ! ( denominator <= 1 << 30 , "Got large denominator ({}) from float {}." , denominator, den) ;
1079+ ( numerator, denominator)
1080+ } ;
1081+
10201082 if min_zero_implies_no_successes && min_liquidity_msat == 0 &&
10211083 denominator < u64:: max_value ( ) / 21
10221084 {
@@ -2964,47 +3026,47 @@ mod tests {
29643026 inflight_htlc_msat : 0 ,
29653027 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 950_000_000 , htlc_maximum_msat : 1_000 } ,
29663028 } ;
2967- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 6262 ) ;
3029+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 11497 ) ;
29683030 let usage = ChannelUsage {
29693031 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
29703032 } ;
2971- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4634 ) ;
3033+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 7408 ) ;
29723034 let usage = ChannelUsage {
29733035 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 2_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
29743036 } ;
2975- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4186 ) ;
3037+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 6151 ) ;
29763038 let usage = ChannelUsage {
29773039 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 3_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
29783040 } ;
2979- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 3909 ) ;
3041+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 5427 ) ;
29803042 let usage = ChannelUsage {
29813043 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 4_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
29823044 } ;
2983- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 3556 ) ;
3045+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4955 ) ;
29843046 let usage = ChannelUsage {
29853047 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 5_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
29863048 } ;
2987- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 3533 ) ;
3049+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4736 ) ;
29883050 let usage = ChannelUsage {
29893051 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 6_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
29903052 } ;
2991- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 3172 ) ;
3053+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4484 ) ;
29923054 let usage = ChannelUsage {
29933055 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 7_450_000_000 , htlc_maximum_msat : 1_000 } , ..usage
29943056 } ;
2995- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 3211 ) ;
3057+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4484 ) ;
29963058 let usage = ChannelUsage {
29973059 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 7_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
29983060 } ;
2999- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 3243 ) ;
3061+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4263 ) ;
30003062 let usage = ChannelUsage {
30013063 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 8_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
30023064 } ;
3003- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 3297 ) ;
3065+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4263 ) ;
30043066 let usage = ChannelUsage {
30053067 effective_capacity : EffectiveCapacity :: Total { capacity_msat : 9_950_000_000 , htlc_maximum_msat : 1_000 } , ..usage
30063068 } ;
3007- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 3250 ) ;
3069+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 4044 ) ;
30083070 }
30093071
30103072 #[ test]
0 commit comments