5252//! [`find_route`]: crate::routing::router::find_route
5353
5454use crate :: ln:: msgs:: DecodeError ;
55- use crate :: routing:: gossip:: { EffectiveCapacity , NetworkGraph , NodeId } ;
55+ use crate :: routing:: gossip:: { DirectedChannelInfo , EffectiveCapacity , NetworkGraph , NodeId } ;
5656use crate :: routing:: router:: { Path , CandidateRouteHop , PublicHopCandidate } ;
5757use crate :: routing:: log_approx;
5858use crate :: util:: ser:: { Readable , ReadableArgs , Writeable , Writer } ;
@@ -956,28 +956,84 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref> ProbabilisticScorer<G, L> whe
956956 /// with `scid` towards the given `target` node, based on the historical estimated liquidity
957957 /// bounds.
958958 ///
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+ ///
959965 /// These are the same bounds as returned by
960966 /// [`Self::historical_estimated_channel_liquidity_probabilities`] (but not those returned by
961967 /// [`Self::estimated_channel_liquidity_range`]).
962968 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 > {
965972 let graph = self . network_graph . read_only ( ) ;
966973
967974 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 ) {
970977 let capacity_msat = directed_info. effective_capacity ( ) . as_msat ( ) ;
971978 let dir_liq = liq. as_directed ( source, target, capacity_msat) ;
972979
973- return dir_liq. liquidity_history . calculate_success_probability_times_billion (
980+ let res = dir_liq. liquidity_history . calculate_success_probability_times_billion (
974981 & params, amount_msat, capacity_msat
975982 ) . 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+ ) ;
976992 }
977993 }
978994 }
979995 None
980996 }
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+ }
9811037}
9821038
9831039impl ChannelLiquidity {
@@ -3200,7 +3256,7 @@ mod tests {
32003256 }
32013257 assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
32023258 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 ) ,
32043260 None ) ;
32053261
32063262 scorer. payment_path_failed ( & payment_path_for_amount ( 1 ) , 42 , Duration :: ZERO ) ;
@@ -3221,9 +3277,9 @@ mod tests {
32213277 assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
32223278 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 ] ,
32233279 [ 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 )
32253281 . 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 ) ,
32273283 Some ( 0.0 ) ) ;
32283284
32293285 // Even after we tell the scorer we definitely have enough available liquidity, it will
@@ -3248,11 +3304,11 @@ mod tests {
32483304 // The exact success probability is a bit complicated and involves integer rounding, so we
32493305 // simply check bounds here.
32503306 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 ( ) ;
32523308 assert ! ( five_hundred_prob > 0.59 ) ;
32533309 assert ! ( five_hundred_prob < 0.60 ) ;
32543310 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 ( ) ;
32563312 assert ! ( one_prob < 0.85 ) ;
32573313 assert ! ( one_prob > 0.84 ) ;
32583314
@@ -3274,7 +3330,7 @@ mod tests {
32743330 // data entirely instead.
32753331 assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
32763332 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 ) ;
32783334
32793335 let usage = ChannelUsage {
32803336 amount_msat : 100 ,
@@ -3460,7 +3516,7 @@ mod tests {
34603516 assert_eq ! ( scorer. channel_penalty_msat( & candidate, usage, & params) , 1269 ) ;
34613517 assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
34623518 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 ) ,
34643520 None ) ;
34653521
34663522 // Fail to pay once, and then check the buckets and penalty.
@@ -3475,14 +3531,14 @@ mod tests {
34753531 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 ] ,
34763532 [ 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 ] ) ) ) ;
34773533 // 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 ) ,
34793535 Some ( 0.0 ) ) ;
34803536
34813537 // Now test again with the amount in the bottom bucket.
34823538 amount_msat /= 2 ;
34833539 // The new amount is entirely within the only minimum bucket with score, so the probability
34843540 // 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 ) ,
34863542 Some ( 0.5 ) ) ;
34873543
34883544 // ...but once we see a failure, we consider the payment to be substantially less likely,
@@ -3492,7 +3548,7 @@ mod tests {
34923548 assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 , & target) ,
34933549 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 ] ,
34943550 [ 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 ) ,
34963552 Some ( 0.0 ) ) ;
34973553 }
34983554}
0 commit comments