@@ -830,6 +830,9 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
830830 	/// 
831831 	/// Because the datapoints are decayed slowly over time, values will eventually return to 
832832 	/// `Some(([0; 8], [0; 8]))`. 
833+  	/// 
834+  	/// In order to convert this into a success probability, as used in the scoring model, see 
835+  	/// [`Self::historical_estimated_payment_success_probability`]. 
833836 	pub  fn  historical_estimated_channel_liquidity_probabilities ( & self ,  scid :  u64 ,  target :  & NodeId ) 
834837	-> Option < ( [ u16 ;  8 ] ,  [ u16 ;  8 ] ) >  { 
835838		let  graph = self . network_graph . read_only ( ) ; 
@@ -856,6 +859,38 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerU
856859		None 
857860	} 
858861
862+ 	/// Query the probability of payment success (times 2^30) sending the given `amount_msat` over 
863+  	/// the channel with `scid` towards the given `target` node, based on the historical estimated 
864+  	/// liquidity bounds. 
865+  	/// 
866+  	/// These are the same bounds as returned by 
867+  	/// [`Self::historical_estimated_channel_liquidity_probabilities`] (but not those returned by 
868+  	/// [`Self::estimated_channel_liquidity_range`]). 
869+  	pub  fn  historical_estimated_payment_success_probability ( 
870+ 		& self ,  scid :  u64 ,  target :  & NodeId ,  amount_msat :  u64 ) 
871+ 	-> Option < u64 >  { 
872+ 		let  graph = self . network_graph . read_only ( ) ; 
873+ 
874+ 		if  let  Some ( chan)  = graph. channels ( ) . get ( & scid)  { 
875+ 			if  let  Some ( liq)  = self . channel_liquidities . get ( & scid)  { 
876+ 				if  let  Some ( ( directed_info,  source) )  = chan. as_directed_to ( target)  { 
877+ 					let  amt = directed_info. effective_capacity ( ) . as_msat ( ) ; 
878+ 					let  dir_liq = liq. as_directed ( source,  target,  0 ,  amt,  & self . params ) ; 
879+ 
880+ 					let  buckets = HistoricalMinMaxBuckets  { 
881+ 						min_liquidity_offset_history :  & dir_liq. min_liquidity_offset_history , 
882+ 						max_liquidity_offset_history :  & dir_liq. max_liquidity_offset_history , 
883+ 					} ; 
884+ 
885+ 					return  buckets. calculate_success_probability_times_billion ( T :: now ( ) , 
886+ 						* dir_liq. last_updated ,  self . params . historical_no_updates_half_life , 
887+ 						amount_msat,  directed_info. effective_capacity ( ) . as_msat ( ) ) ; 
888+ 				} 
889+ 			} 
890+ 		} 
891+ 		None 
892+ 	} 
893+ 
859894	/// Marks the node with the given `node_id` as banned, i.e., 
860895 	/// it will be avoided during path finding. 
861896 	pub  fn  add_banned ( & mut  self ,  node_id :  & NodeId )  { 
@@ -2786,13 +2821,19 @@ mod tests {
27862821		assert_eq ! ( scorer. channel_penalty_msat( 42 ,  & source,  & target,  usage) ,  47 ) ; 
27872822		assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 ,  & target) , 
27882823			None ) ; 
2824+ 		assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 ,  & target,  42 ) , 
2825+ 			None ) ; 
27892826
27902827		scorer. payment_path_failed ( & payment_path_for_amount ( 1 ) . iter ( ) . collect :: < Vec < _ > > ( ) ,  42 ) ; 
27912828		assert_eq ! ( scorer. channel_penalty_msat( 42 ,  & source,  & target,  usage) ,  2048 ) ; 
27922829		// The "it failed" increment is 32, where the probability should lie fully in the first 
27932830		// octile. 
27942831		assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 ,  & target) , 
27952832			Some ( ( [ 32 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ] ,  [ 32 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ] ) ) ) ; 
2833+ 		assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 ,  & target,  1 ) , 
2834+ 			Some ( 1024  *  1024  *  1024 ) ) ; 
2835+ 		assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 ,  & target,  500 ) , 
2836+ 			Some ( 0 ) ) ; 
27962837
27972838		// Even after we tell the scorer we definitely have enough available liquidity, it will 
27982839		// still remember that there was some failure in the past, and assign a non-0 penalty. 
@@ -2802,6 +2843,17 @@ mod tests {
28022843		assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 ,  & target) , 
28032844			Some ( ( [ 31 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  32 ] ,  [ 31 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  32 ] ) ) ) ; 
28042845
2846+ 		// The exact success probability is a bit complicated and involves integer rounding, so we 
2847+ 		// simply check bounds here. 
2848+ 		let  five_hundred_prob =
2849+ 			scorer. historical_estimated_payment_success_probability ( 42 ,  & target,  500 ) . unwrap ( ) ; 
2850+ 		assert ! ( five_hundred_prob > 512  *  1024  *  1024 ) ;  // 0.5 
2851+ 		assert ! ( five_hundred_prob < 532  *  1024  *  1024 ) ;  // ~ 0.52 
2852+ 		let  one_prob =
2853+ 			scorer. historical_estimated_payment_success_probability ( 42 ,  & target,  1 ) . unwrap ( ) ; 
2854+ 		assert ! ( one_prob < 1024  *  1024  *  1024 ) ; 
2855+ 		assert ! ( one_prob > 1023  *  1024  *  1024 ) ; 
2856+ 
28052857		// Advance the time forward 16 half-lives (which the docs claim will ensure all data is 
28062858		// gone), and check that we're back to where we started. 
28072859		SinceEpoch :: advance ( Duration :: from_secs ( 10  *  16 ) ) ; 
@@ -2810,6 +2862,7 @@ mod tests {
28102862		// data entirely instead. 
28112863		assert_eq ! ( scorer. historical_estimated_channel_liquidity_probabilities( 42 ,  & target) , 
28122864			Some ( ( [ 0 ;  8 ] ,  [ 0 ;  8 ] ) ) ) ; 
2865+ 		assert_eq ! ( scorer. historical_estimated_payment_success_probability( 42 ,  & target,  1 ) ,  None ) ; 
28132866
28142867		let  usage = ChannelUsage  { 
28152868			amount_msat :  100 , 
0 commit comments