@@ -893,7 +893,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
893
893
/// [`Self::historical_estimated_channel_liquidity_probabilities`] (but not those returned by
894
894
/// [`Self::estimated_channel_liquidity_range`]).
895
895
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 )
897
897
-> Option < f64 > {
898
898
let graph = self . network_graph . read_only ( ) ;
899
899
@@ -905,7 +905,8 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
905
905
906
906
return dir_liq. liquidity_history . calculate_success_probability_times_billion (
907
907
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
909
910
) . map ( |p| p as f64 / ( 1024 * 1024 * 1024 ) as f64 ) ;
910
911
}
911
912
}
@@ -997,6 +998,23 @@ const PRECISION_LOWER_BOUND_DENOMINATOR: u64 = approx::LOWER_BITS_BOUND;
997
998
const AMOUNT_PENALTY_DIVISOR : u64 = 1 << 20 ;
998
999
const BASE_AMOUNT_PENALTY_DIVISOR : u64 = 1 << 30 ;
999
1000
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
+
1000
1018
impl < L : Deref < Target = u64 > , BRT : Deref < Target = HistoricalBucketRangeTracker > , T : Time , U : Deref < Target = T > > DirectedChannelLiquidity < L , BRT , T , U > {
1001
1019
/// Returns a liquidity penalty for routing the given HTLC `amount_msat` through the channel in
1002
1020
/// this direction.
@@ -1017,9 +1035,9 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
1017
1035
score_params. liquidity_penalty_amount_multiplier_msat )
1018
1036
. saturating_add ( score_params. considered_impossible_penalty_msat )
1019
1037
} 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 {
1023
1041
// If the failure probability is < 1.5625% (as 1 - numerator/denominator < 1/64),
1024
1042
// don't bother trying to use the log approximation as it gets too noisy to be
1025
1043
// particularly helpful, instead just round down to 0.
@@ -1046,7 +1064,8 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
1046
1064
score_params. historical_liquidity_penalty_amount_multiplier_msat != 0 {
1047
1065
if let Some ( cumulative_success_prob_times_billion) = self . liquidity_history
1048
1066
. 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 )
1050
1069
{
1051
1070
let historical_negative_log10_times_2048 = approx:: negative_log10_times_2048 ( cumulative_success_prob_times_billion + 1 , 1024 * 1024 * 1024 ) ;
1052
1071
res = res. saturating_add ( Self :: combined_penalty_msat ( amount_msat,
@@ -1056,9 +1075,8 @@ impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>,
1056
1075
// If we don't have any valid points (or, once decayed, we have less than a full
1057
1076
// point), redo the non-historical calculation with no liquidity bounds tracked and
1058
1077
// 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 ) ;
1062
1080
let negative_log10_times_2048 =
1063
1081
approx:: negative_log10_times_2048 ( numerator, denominator) ;
1064
1082
res = res. saturating_add ( Self :: combined_penalty_msat ( amount_msat, negative_log10_times_2048,
@@ -1851,8 +1869,9 @@ mod bucketed_history {
1851
1869
1852
1870
#[ inline]
1853
1871
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 > {
1856
1875
// If historical penalties are enabled, we try to calculate a probability of success
1857
1876
// given our historical distribution of min- and max-liquidity bounds in a channel.
1858
1877
// To do so, we walk the set of historical liquidity bucket (min, max) combinations
@@ -1887,14 +1906,13 @@ mod bucketed_history {
1887
1906
}
1888
1907
let max_bucket_end_pos = BUCKET_START_POS [ 32 - highest_max_bucket_with_points] - 1 ;
1889
1908
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 ) ;
1890
1911
let bucket_prob_times_billion =
1891
1912
( self . min_liquidity_offset_history . buckets [ 0 ] as u64 ) * total_max_points
1892
1913
* 1024 * 1024 * 1024 / total_valid_points_tracked;
1893
1914
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;
1898
1916
}
1899
1917
}
1900
1918
@@ -1912,11 +1930,11 @@ mod bucketed_history {
1912
1930
} else if payment_pos < min_bucket_start_pos {
1913
1931
cumulative_success_prob_times_billion += bucket_prob_times_billion;
1914
1932
} 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 ) ;
1915
1936
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;
1920
1938
}
1921
1939
}
1922
1940
}
@@ -2719,7 +2737,7 @@ mod tests {
2719
2737
let usage = ChannelUsage { amount_msat : 256 , ..usage } ;
2720
2738
assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 106 ) ;
2721
2739
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 ) ;
2723
2741
let usage = ChannelUsage { amount_msat : 896 , ..usage } ;
2724
2742
assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , u64 :: max_value( ) ) ;
2725
2743
@@ -2919,7 +2937,7 @@ mod tests {
2919
2937
assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 300 ) ;
2920
2938
2921
2939
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 ) ;
2923
2941
}
2924
2942
2925
2943
#[ test]
@@ -3146,7 +3164,7 @@ mod tests {
3146
3164
assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 47 ) ;
3147
3165
assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
3148
3166
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 ) ,
3150
3168
None ) ;
3151
3169
3152
3170
scorer. payment_path_failed ( & payment_path_for_amount ( 1 ) , 42 ) ;
@@ -3157,9 +3175,9 @@ mod tests {
3157
3175
assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
3158
3176
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 ] ,
3159
3177
[ 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 )
3161
3179
. 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 ) ,
3163
3181
Some ( 0.0 ) ) ;
3164
3182
3165
3183
// Even after we tell the scorer we definitely have enough available liquidity, it will
@@ -3174,11 +3192,11 @@ mod tests {
3174
3192
// The exact success probability is a bit complicated and involves integer rounding, so we
3175
3193
// simply check bounds here.
3176
3194
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 ( ) ;
3178
3196
assert ! ( five_hundred_prob > 0.66 ) ;
3179
3197
assert ! ( five_hundred_prob < 0.68 ) ;
3180
3198
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 ( ) ;
3182
3200
assert ! ( one_prob < 1.0 ) ;
3183
3201
assert ! ( one_prob > 0.95 ) ;
3184
3202
@@ -3190,7 +3208,7 @@ mod tests {
3190
3208
// data entirely instead.
3191
3209
assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
3192
3210
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 ) ;
3194
3212
3195
3213
let mut usage = ChannelUsage {
3196
3214
amount_msat : 100 ,
@@ -3354,7 +3372,7 @@ mod tests {
3354
3372
assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage, & params) , 0 ) ;
3355
3373
assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
3356
3374
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 ) ,
3358
3376
None ) ;
3359
3377
3360
3378
// Fail to pay once, and then check the buckets and penalty.
@@ -3369,14 +3387,14 @@ mod tests {
3369
3387
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 ] ,
3370
3388
[ 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 ] ) ) ) ;
3371
3389
// 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 ) ,
3373
3391
Some ( 0.0 ) ) ;
3374
3392
3375
3393
// Now test again with the amount in the bottom bucket.
3376
3394
amount_msat /= 2 ;
3377
3395
// The new amount is entirely within the only minimum bucket with score, so the probability
3378
3396
// 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 ) ,
3380
3398
Some ( 0.5 ) ) ;
3381
3399
3382
3400
// ...but once we see a failure, we consider the payment to be substantially less likely,
@@ -3386,7 +3404,7 @@ mod tests {
3386
3404
assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
3387
3405
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 ] ,
3388
3406
[ 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 ) ,
3390
3408
Some ( 0.0 ) ) ;
3391
3409
}
3392
3410
}
0 commit comments