+ /// Query the historical estimated minimum and maximum liquidity available for sending a
+ /// payment over the channel with `scid` towards the given `target` node.
+ ///
+ /// Returns two sets of 8 buckets. The first set describes the octiles for lower-bound
+ /// liquidity estimates, the second set describes the octiles for upper-bound liquidity
+ /// estimates. Each bucket describes the relative frequency at which we've seen a liquidity
+ /// bound in the octile relative to the channel's total capacity, on an arbitrary scale.
+ /// Because the values are slowly decayed, more recent data points are weighted more heavily
+ /// than older datapoints.
+ ///
+ /// When scoring, the estimated probability that an upper-/lower-bound lies in a given octile
+ /// relative to the channel's total capacity is calculated by dividing that bucket's value with
+ /// the total of all buckets for the given bound.
+ ///
+ /// For example, a value of `[0, 0, 0, 0, 0, 0, 32]` indicates that we believe the probability
+ /// of a bound being in the top octile to be 100%, and have never (recently) seen it in any
+ /// other octiles. A value of `[31, 0, 0, 0, 0, 0, 0, 32]` indicates we've seen the bound being
+ /// both in the top and bottom octile, and roughly with similar (recent) frequency.
+ ///
+ /// Because the datapoints are decayed slowly over time, values will eventually return to
+ /// `Some(([0; 8], [0; 8]))`.
+ pub fn historical_estimated_channel_liquidity_probabilities(&self, scid: u64, target: &NodeId)
+ -> Option<([u16; 8], [u16; 8])> {
+ let graph = self.network_graph.read_only();
+
+ if let Some(chan) = graph.channels().get(&scid) {
+ if let Some(liq) = self.channel_liquidities.get(&scid) {
+ if let Some((directed_info, source)) = chan.as_directed_to(target) {
+ let amt = directed_info.effective_capacity().as_msat();
+ let dir_liq = liq.as_directed(source, target, amt, &self.params);
+
+ let buckets = HistoricalMinMaxBuckets {
+ min_liquidity_offset_history: &dir_liq.min_liquidity_offset_history,
+ max_liquidity_offset_history: &dir_liq.max_liquidity_offset_history,
+ };
+ let (min_buckets, mut max_buckets, _) = buckets.get_decayed_buckets(T::now(),
+ *dir_liq.last_updated, self.params.historical_no_updates_half_life);
+ // Note that the liquidity buckets are an offset from the edge, so we inverse
+ // the max order to get the probabilities from zero.
+ max_buckets.reverse();
+ return Some((min_buckets, max_buckets));
+ }
+ }
+ }
+ None
+ }
+