@@ -893,7 +893,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
893893 /// [`Self::historical_estimated_channel_liquidity_probabilities`] (but not those returned by
894894 /// [`Self::estimated_channel_liquidity_range`]).
895895 pub fn historical_estimated_payment_success_probability (
896- & self , scid : u64 , target : & NodeId , amount_msat : u64 )
896+ & self , scid : u64 , target : & NodeId , amount_msat : u64 , params : & ProbabilisticScoringFeeParameters )
897897 -> Option < f64 > {
898898 let graph = self . network_graph . read_only ( ) ;
899899
@@ -905,7 +905,8 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
905905
906906 return dir_liq. liquidity_history . calculate_success_probability_times_billion (
907907 dir_liq. now , * dir_liq. last_updated ,
908- self . decay_params . historical_no_updates_half_life , amount_msat, capacity_msat
908+ self . decay_params . historical_no_updates_half_life , & params, amount_msat,
909+ capacity_msat
909910 ) . map ( |p| p as f64 / ( 1024 * 1024 * 1024 ) as f64 ) ;
910911 }
911912 }
@@ -997,6 +998,23 @@ const PRECISION_LOWER_BOUND_DENOMINATOR: u64 = approx::LOWER_BITS_BOUND;
997998const AMOUNT_PENALTY_DIVISOR : u64 = 1 << 20 ;
998999const BASE_AMOUNT_PENALTY_DIVISOR : u64 = 1 << 30 ;
9991000
1001+ /// Given liquidity bounds, calculates the success probability (in the form of a numerator and
1002+ /// denominator) of an HTLC. This is a key assumption in our scoring models.
1003+ ///
1004+ /// Must not return a numerator or denominator greater than 2^31 for arguments less than 2^31.
1005+ ///
1006+ /// min_zero_implies_no_successes signals that a `min_liquidity_msat` of 0 means we've not
1007+ /// (recently) seen an HTLC successfully complete over this channel.
1008+ #[ inline( always) ]
1009+ fn success_probability (
1010+ amount_msat : u64 , min_liquidity_msat : u64 , max_liquidity_msat : u64 , _capacity_msat : u64 ,
1011+ _params : & ProbabilisticScoringFeeParameters , _min_zero_implies_no_successes : bool ,
1012+ ) -> ( u64 , u64 ) {
1013+ let numerator = max_liquidity_msat - amount_msat;
1014+ let denominator = ( max_liquidity_msat - min_liquidity_msat) . saturating_add ( 1 ) ;
1015+ ( numerator, denominator)
1016+ }
1017+
10001018impl < L : Deref < Target = u64 > , BRT : Deref < Target = HistoricalBucketRangeTracker > , T : Time , U : Deref < Target = T > > DirectedChannelLiquidity < L , BRT , T , U > {
10011019 /// Returns a liquidity penalty for routing the given HTLC `amount_msat` through the channel in
10021020 /// this direction.
@@ -1017,9 +1035,9 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
10171035 score_params. liquidity_penalty_amount_multiplier_msat )
10181036 . saturating_add ( score_params. considered_impossible_penalty_msat )
10191037 } else {
1020- let numerator = ( max_liquidity_msat - amount_msat) . saturating_add ( 1 ) ;
1021- let denominator = ( max_liquidity_msat - min_liquidity_msat ) . saturating_add ( 1 ) ;
1022- if amount_msat - min_liquidity_msat < denominator / PRECISION_LOWER_BOUND_DENOMINATOR {
1038+ let ( numerator, denominator ) = success_probability ( amount_msat,
1039+ min_liquidity_msat , max_liquidity_msat, available_capacity , score_params , false ) ;
1040+ if denominator - numerator < denominator / PRECISION_LOWER_BOUND_DENOMINATOR {
10231041 // If the failure probability is < 1.5625% (as 1 - numerator/denominator < 1/64),
10241042 // don't bother trying to use the log approximation as it gets too noisy to be
10251043 // particularly helpful, instead just round down to 0.
@@ -1046,7 +1064,8 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
10461064 score_params. historical_liquidity_penalty_amount_multiplier_msat != 0 {
10471065 if let Some ( cumulative_success_prob_times_billion) = self . liquidity_history
10481066 . calculate_success_probability_times_billion ( self . now , * self . last_updated ,
1049- self . decay_params . historical_no_updates_half_life , amount_msat, self . capacity_msat )
1067+ self . decay_params . historical_no_updates_half_life , score_params, amount_msat,
1068+ self . capacity_msat )
10501069 {
10511070 let historical_negative_log10_times_2048 = approx:: negative_log10_times_2048 ( cumulative_success_prob_times_billion + 1 , 1024 * 1024 * 1024 ) ;
10521071 res = res. saturating_add ( Self :: combined_penalty_msat ( amount_msat,
@@ -1056,9 +1075,8 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
10561075 // If we don't have any valid points (or, once decayed, we have less than a full
10571076 // point), redo the non-historical calculation with no liquidity bounds tracked and
10581077 // the historical penalty multipliers.
1059- let available_capacity = self . available_capacity ( ) ;
1060- let numerator = available_capacity. saturating_sub ( amount_msat) . saturating_add ( 1 ) ;
1061- let denominator = available_capacity. saturating_add ( 1 ) ;
1078+ let ( numerator, denominator) = success_probability ( amount_msat, 0 ,
1079+ available_capacity, available_capacity, score_params, true ) ;
10621080 let negative_log10_times_2048 =
10631081 approx:: negative_log10_times_2048 ( numerator, denominator) ;
10641082 res = res. saturating_add ( Self :: combined_penalty_msat ( amount_msat, negative_log10_times_2048,
@@ -1851,8 +1869,9 @@ mod bucketed_history {
18511869
18521870 #[ inline]
18531871 pub ( super ) fn calculate_success_probability_times_billion < T : Time > (
1854- & self , now : T , last_updated : T , half_life : Duration , amount_msat : u64 , capacity_msat : u64 )
1855- -> Option < u64 > {
1872+ & self , now : T , last_updated : T , half_life : Duration ,
1873+ params : & ProbabilisticScoringFeeParameters , amount_msat : u64 , capacity_msat : u64
1874+ ) -> Option < u64 > {
18561875 // If historical penalties are enabled, we try to calculate a probability of success
18571876 // given our historical distribution of min- and max-liquidity bounds in a channel.
18581877 // To do so, we walk the set of historical liquidity bucket (min, max) combinations
@@ -1887,14 +1906,13 @@ mod bucketed_history {
18871906 }
18881907 let max_bucket_end_pos = BUCKET_START_POS [ 32 - highest_max_bucket_with_points] - 1 ;
18891908 if payment_pos < max_bucket_end_pos {
1909+ let ( numerator, denominator) = success_probability ( payment_pos as u64 , 0 ,
1910+ max_bucket_end_pos as u64 , POSITION_TICKS as u64 - 1 , params, true ) ;
18901911 let bucket_prob_times_billion =
18911912 ( self . min_liquidity_offset_history . buckets [ 0 ] as u64 ) * total_max_points
18921913 * 1024 * 1024 * 1024 / total_valid_points_tracked;
18931914 cumulative_success_prob_times_billion += bucket_prob_times_billion *
1894- ( ( max_bucket_end_pos - payment_pos) as u64 ) /
1895- // Add an additional one in the divisor as the payment bucket has been
1896- // rounded down.
1897- ( max_bucket_end_pos + 1 ) as u64 ;
1915+ numerator / denominator;
18981916 }
18991917 }
19001918
@@ -1912,11 +1930,11 @@ mod bucketed_history {
19121930 } else if payment_pos < min_bucket_start_pos {
19131931 cumulative_success_prob_times_billion += bucket_prob_times_billion;
19141932 } else {
1933+ let ( numerator, denominator) = success_probability ( payment_pos as u64 ,
1934+ min_bucket_start_pos as u64 , max_bucket_end_pos as u64 ,
1935+ POSITION_TICKS as u64 - 1 , params, true ) ;
19151936 cumulative_success_prob_times_billion += bucket_prob_times_billion *
1916- ( ( max_bucket_end_pos - payment_pos) as u64 ) /
1917- // Add an additional one in the divisor as the payment bucket has been
1918- // rounded down.
1919- ( ( max_bucket_end_pos - min_bucket_start_pos + 1 ) as u64 ) ;
1937+ numerator / denominator;
19201938 }
19211939 }
19221940 }
@@ -2719,7 +2737,7 @@ mod tests {
27192737 let usage = ChannelUsage { amount_msat : 256 , ..usage } ;
27202738 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 106 ) ;
27212739 let usage = ChannelUsage { amount_msat : 768 , ..usage } ;
2722- assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 916 ) ;
2740+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 921 ) ;
27232741 let usage = ChannelUsage { amount_msat : 896 , ..usage } ;
27242742 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , u64 :: max_value( ) ) ;
27252743
@@ -2919,7 +2937,7 @@ mod tests {
29192937 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 300 ) ;
29202938
29212939 SinceEpoch :: advance ( Duration :: from_secs ( 10 ) ) ;
2922- assert_eq ! ( deserialized_scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 365 ) ;
2940+ assert_eq ! ( deserialized_scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 370 ) ;
29232941 }
29242942
29252943 #[ test]
@@ -3146,7 +3164,7 @@ mod tests {
31463164 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 47 ) ;
31473165 assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
31483166 None ) ;
3149- assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 42 ) ,
3167+ assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 42 , & params ) ,
31503168 None ) ;
31513169
31523170 scorer. payment_path_failed ( & payment_path_for_amount ( 1 ) , 42 ) ;
@@ -3157,9 +3175,9 @@ mod tests {
31573175 assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
31583176 Some ( ( [ 32 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ,
31593177 [ 0 , 0 , 0 , 0 , 0 , 0 , 32 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ) ) ) ;
3160- assert ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 1 )
3178+ assert ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 1 , & params )
31613179 . unwrap( ) > 0.35 ) ;
3162- assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 500 ) ,
3180+ assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 500 , & params ) ,
31633181 Some ( 0.0 ) ) ;
31643182
31653183 // Even after we tell the scorer we definitely have enough available liquidity, it will
@@ -3174,11 +3192,11 @@ mod tests {
31743192 // The exact success probability is a bit complicated and involves integer rounding, so we
31753193 // simply check bounds here.
31763194 let five_hundred_prob =
3177- scorer. historical_estimated_payment_success_probability ( 42 , & target, 500 ) . unwrap ( ) ;
3195+ scorer. historical_estimated_payment_success_probability ( 42 , & target, 500 , & params ) . unwrap ( ) ;
31783196 assert ! ( five_hundred_prob > 0.66 ) ;
31793197 assert ! ( five_hundred_prob < 0.68 ) ;
31803198 let one_prob =
3181- scorer. historical_estimated_payment_success_probability ( 42 , & target, 1 ) . unwrap ( ) ;
3199+ scorer. historical_estimated_payment_success_probability ( 42 , & target, 1 , & params ) . unwrap ( ) ;
31823200 assert ! ( one_prob < 1.0 ) ;
31833201 assert ! ( one_prob > 0.95 ) ;
31843202
@@ -3190,7 +3208,7 @@ mod tests {
31903208 // data entirely instead.
31913209 assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
31923210 None ) ;
3193- assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 1 ) , None ) ;
3211+ assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 1 , & params ) , None ) ;
31943212
31953213 let mut usage = ChannelUsage {
31963214 amount_msat : 100 ,
@@ -3354,7 +3372,7 @@ mod tests {
33543372 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 0 ) ;
33553373 assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
33563374 None ) ;
3357- assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 42 ) ,
3375+ assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 42 , & params ) ,
33583376 None ) ;
33593377
33603378 // Fail to pay once, and then check the buckets and penalty.
@@ -3369,14 +3387,14 @@ mod tests {
33693387 Some ( ( [ 32 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ,
33703388 [ 0 , 32 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ) ) ) ;
33713389 // The success probability estimate itself should be zero.
3372- assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, amount_msat) ,
3390+ assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, amount_msat, & params ) ,
33733391 Some ( 0.0 ) ) ;
33743392
33753393 // Now test again with the amount in the bottom bucket.
33763394 amount_msat /= 2 ;
33773395 // The new amount is entirely within the only minimum bucket with score, so the probability
33783396 // we assign is 1/2.
3379- assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, amount_msat) ,
3397+ assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, amount_msat, & params ) ,
33803398 Some ( 0.5 ) ) ;
33813399
33823400 // ...but once we see a failure, we consider the payment to be substantially less likely,
@@ -3386,7 +3404,7 @@ mod tests {
33863404 assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
33873405 Some ( ( [ 63 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ,
33883406 [ 32 , 31 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ) ) ) ;
3389- assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, amount_msat) ,
3407+ assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, amount_msat, & params ) ,
33903408 Some ( 0.0 ) ) ;
33913409 }
33923410}
0 commit comments