52
52
//! [`find_route`]: crate::routing::router::find_route
53
53
54
54
use crate :: ln:: msgs:: DecodeError ;
55
- use crate :: routing:: gossip:: { EffectiveCapacity , NetworkGraph , NodeId } ;
55
+ use crate :: routing:: gossip:: { DirectedChannelInfo , EffectiveCapacity , NetworkGraph , NodeId } ;
56
56
use crate :: routing:: router:: { Path , CandidateRouteHop , PublicHopCandidate } ;
57
57
use crate :: routing:: log_approx;
58
58
use crate :: util:: ser:: { Readable , ReadableArgs , Writeable , Writer } ;
@@ -956,28 +956,84 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref> ProbabilisticScorer<G, L> whe
956
956
/// with `scid` towards the given `target` node, based on the historical estimated liquidity
957
957
/// bounds.
958
958
///
959
+ /// Returns `None` if:
960
+ /// - the given channel is not in the network graph, the provided `target` is not a party to
961
+ /// the channel, or we don't have forwarding parameters for either direction in the channel.
962
+ /// - `allow_fallback_estimation` is *not* set and there is no (or insufficient) historical
963
+ /// data for the given channel.
964
+ ///
959
965
/// These are the same bounds as returned by
960
966
/// [`Self::historical_estimated_channel_liquidity_probabilities`] (but not those returned by
961
967
/// [`Self::estimated_channel_liquidity_range`]).
962
968
pub fn historical_estimated_payment_success_probability (
963
- & self , scid : u64 , target : & NodeId , amount_msat : u64 , params : & ProbabilisticScoringFeeParameters )
964
- -> Option < f64 > {
969
+ & self , scid : u64 , target : & NodeId , amount_msat : u64 , params : & ProbabilisticScoringFeeParameters ,
970
+ allow_fallback_estimation : bool ,
971
+ ) -> Option < f64 > {
965
972
let graph = self . network_graph . read_only ( ) ;
966
973
967
974
if let Some ( chan) = graph. channels ( ) . get ( & scid) {
968
- if let Some ( liq ) = self . channel_liquidities . get ( & scid ) {
969
- if let Some ( ( directed_info , source ) ) = chan . as_directed_to ( target ) {
975
+ if let Some ( ( directed_info , source ) ) = chan . as_directed_to ( target ) {
976
+ if let Some ( liq ) = self . channel_liquidities . get ( & scid ) {
970
977
let capacity_msat = directed_info. effective_capacity ( ) . as_msat ( ) ;
971
978
let dir_liq = liq. as_directed ( source, target, capacity_msat) ;
972
979
973
- return dir_liq. liquidity_history . calculate_success_probability_times_billion (
980
+ let res = dir_liq. liquidity_history . calculate_success_probability_times_billion (
974
981
& params, amount_msat, capacity_msat
975
982
) . map ( |p| p as f64 / ( 1024 * 1024 * 1024 ) as f64 ) ;
983
+ if res. is_some ( ) {
984
+ return res;
985
+ }
986
+ }
987
+ if allow_fallback_estimation {
988
+ let amt = amount_msat;
989
+ return Some (
990
+ self . calc_live_prob ( scid, source, target, directed_info, amt, params, true )
991
+ ) ;
976
992
}
977
993
}
978
994
}
979
995
None
980
996
}
997
+
998
+ fn calc_live_prob (
999
+ & self , scid : u64 , source : & NodeId , target : & NodeId , directed_info : DirectedChannelInfo ,
1000
+ amt : u64 , params : & ProbabilisticScoringFeeParameters ,
1001
+ min_zero_penalty : bool ,
1002
+ ) -> f64 {
1003
+ let capacity_msat = directed_info. effective_capacity ( ) . as_msat ( ) ;
1004
+ let dummy_liq = ChannelLiquidity :: new ( Duration :: ZERO ) ;
1005
+ let liq = self . channel_liquidities . get ( & scid)
1006
+ . unwrap_or ( & dummy_liq)
1007
+ . as_directed ( & source, & target, capacity_msat) ;
1008
+ let min_liq = liq. min_liquidity_msat ( ) ;
1009
+ let max_liq = liq. max_liquidity_msat ( ) ;
1010
+ if amt <= liq. min_liquidity_msat ( ) {
1011
+ return 1.0 ;
1012
+ } else if amt > liq. max_liquidity_msat ( ) {
1013
+ return 0.0 ;
1014
+ }
1015
+ let ( num, den) =
1016
+ success_probability ( amt, min_liq, max_liq, capacity_msat, & params, min_zero_penalty) ;
1017
+ num as f64 / den as f64
1018
+ }
1019
+
1020
+ /// Query the probability of payment success sending the given `amount_msat` over the channel
1021
+ /// with `scid` towards the given `target` node, based on the live estimated liquidity bounds.
1022
+ ///
1023
+ /// This will return `Some` for any channel which is present in the [`NetworkGraph`], including
1024
+ /// if we have no bound information beside the channel's capacity.
1025
+ pub fn live_estimated_payment_success_probability (
1026
+ & self , scid : u64 , target : & NodeId , amount_msat : u64 , params : & ProbabilisticScoringFeeParameters ,
1027
+ ) -> Option < f64 > {
1028
+ let graph = self . network_graph . read_only ( ) ;
1029
+
1030
+ if let Some ( chan) = graph. channels ( ) . get ( & scid) {
1031
+ if let Some ( ( directed_info, source) ) = chan. as_directed_to ( target) {
1032
+ return Some ( self . calc_live_prob ( scid, source, target, directed_info, amount_msat, params, false ) ) ;
1033
+ }
1034
+ }
1035
+ None
1036
+ }
981
1037
}
982
1038
983
1039
impl ChannelLiquidity {
@@ -3200,7 +3256,7 @@ mod tests {
3200
3256
}
3201
3257
assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
3202
3258
None ) ;
3203
- assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 42 , & params) ,
3259
+ assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 42 , & params, false ) ,
3204
3260
None ) ;
3205
3261
3206
3262
scorer. payment_path_failed ( & payment_path_for_amount ( 1 ) , 42 , Duration :: ZERO ) ;
@@ -3221,9 +3277,9 @@ mod tests {
3221
3277
assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
3222
3278
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 ] ,
3223
3279
[ 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 ] ) ) ) ;
3224
- assert ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 1 , & params)
3280
+ assert ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 1 , & params, false )
3225
3281
. unwrap( ) > 0.35 ) ;
3226
- assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 500 , & params) ,
3282
+ assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 500 , & params, false ) ,
3227
3283
Some ( 0.0 ) ) ;
3228
3284
3229
3285
// Even after we tell the scorer we definitely have enough available liquidity, it will
@@ -3248,11 +3304,11 @@ mod tests {
3248
3304
// The exact success probability is a bit complicated and involves integer rounding, so we
3249
3305
// simply check bounds here.
3250
3306
let five_hundred_prob =
3251
- scorer. historical_estimated_payment_success_probability ( 42 , & target, 500 , & params) . unwrap ( ) ;
3307
+ scorer. historical_estimated_payment_success_probability ( 42 , & target, 500 , & params, false ) . unwrap ( ) ;
3252
3308
assert ! ( five_hundred_prob > 0.59 ) ;
3253
3309
assert ! ( five_hundred_prob < 0.60 ) ;
3254
3310
let one_prob =
3255
- scorer. historical_estimated_payment_success_probability ( 42 , & target, 1 , & params) . unwrap ( ) ;
3311
+ scorer. historical_estimated_payment_success_probability ( 42 , & target, 1 , & params, false ) . unwrap ( ) ;
3256
3312
assert ! ( one_prob < 0.85 ) ;
3257
3313
assert ! ( one_prob > 0.84 ) ;
3258
3314
@@ -3274,7 +3330,7 @@ mod tests {
3274
3330
// data entirely instead.
3275
3331
assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
3276
3332
Some ( ( [ 0 ; 32 ] , [ 0 ; 32 ] ) ) ) ;
3277
- assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 1 , & params) , None ) ;
3333
+ assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 1 , & params, false ) , None ) ;
3278
3334
3279
3335
let usage = ChannelUsage {
3280
3336
amount_msat : 100 ,
@@ -3460,7 +3516,7 @@ mod tests {
3460
3516
assert_eq ! ( scorer. channel_penalty_msat( & candidate, usage, & params) , 1269 ) ;
3461
3517
assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
3462
3518
None ) ;
3463
- assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 42 , & params) ,
3519
+ assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, 42 , & params, false ) ,
3464
3520
None ) ;
3465
3521
3466
3522
// Fail to pay once, and then check the buckets and penalty.
@@ -3475,14 +3531,14 @@ mod tests {
3475
3531
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 ] ,
3476
3532
[ 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 ] ) ) ) ;
3477
3533
// The success probability estimate itself should be zero.
3478
- assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, amount_msat, & params) ,
3534
+ assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, amount_msat, & params, false ) ,
3479
3535
Some ( 0.0 ) ) ;
3480
3536
3481
3537
// Now test again with the amount in the bottom bucket.
3482
3538
amount_msat /= 2 ;
3483
3539
// The new amount is entirely within the only minimum bucket with score, so the probability
3484
3540
// we assign is 1/2.
3485
- assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, amount_msat, & params) ,
3541
+ assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, amount_msat, & params, false ) ,
3486
3542
Some ( 0.5 ) ) ;
3487
3543
3488
3544
// ...but once we see a failure, we consider the payment to be substantially less likely,
@@ -3492,7 +3548,7 @@ mod tests {
3492
3548
assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
3493
3549
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 ] ,
3494
3550
[ 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 ] ) ) ) ;
3495
- assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, amount_msat, & params) ,
3551
+ assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 , & target, amount_msat, & params, false ) ,
3496
3552
Some ( 0.0 ) ) ;
3497
3553
}
3498
3554
}
0 commit comments