Skip to content

Commit 62d91fe

Browse files
committed
Special-case the 0th minimum bucket in historical scoring
Points in the 0th minimum bucket either indicate we sent a payment which is < 1/16,384th of the channel's capacity or, more likely, we failed to send a payment. In either case, averaging the success probability across the full range of upper-bounds doesn't make a whole lot of sense - if we've never managed to send a "real" payment over a channel, we should be considering it quite poor. To address this, we special-case the 0th minimum bucket and only look at the largest-offset max bucket when calculating the success probability.
1 parent 52b1807 commit 62d91fe

File tree

1 file changed

+32
-9
lines changed

1 file changed

+32
-9
lines changed

lightning/src/routing/scoring.rs

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1795,7 +1795,32 @@ mod bucketed_history {
17951795
}
17961796

17971797
let mut cumulative_success_prob_times_billion = 0;
1798-
for (min_idx, min_bucket) in self.min_liquidity_offset_history.buckets.iter().enumerate() {
1798+
// Special-case the 0th min bucket - it generally means we failed a payment, so only
1799+
// consider the highest (i.e. largest-offset-from-max-capacity) max bucket for all
1800+
// points against the 0th min bucket!
1801+
if self.min_liquidity_offset_history.buckets[0] != 0 {
1802+
let mut highest_max_bucket_with_points = 0;
1803+
let mut total_max_points = 0;
1804+
for (max_idx, max_bucket) in self.max_liquidity_offset_history.buckets.iter().enumerate() {
1805+
if *max_bucket >= 32 {
1806+
highest_max_bucket_with_points = cmp::max(highest_max_bucket_with_points, max_idx);
1807+
}
1808+
total_max_points += *max_bucket as u64;
1809+
}
1810+
let max_bucket_end_pos = BUCKET_START_POS[32 - highest_max_bucket_with_points] - 1;
1811+
if payment_pos < max_bucket_end_pos {
1812+
let bucket_prob_times_billion =
1813+
(self.min_liquidity_offset_history.buckets[0] as u64) * total_max_points
1814+
* 1024 * 1024 * 1024 / total_valid_points_tracked;
1815+
cumulative_success_prob_times_billion += bucket_prob_times_billion *
1816+
((max_bucket_end_pos - payment_pos) as u64) /
1817+
// Add an additional one in the divisor as the payment bucket has been
1818+
// rounded down.
1819+
(max_bucket_end_pos + 1) as u64;
1820+
}
1821+
}
1822+
1823+
for (min_idx, min_bucket) in self.min_liquidity_offset_history.buckets.iter().enumerate().skip(1) {
17991824
let min_bucket_start_pos = BUCKET_START_POS[min_idx];
18001825
for (max_idx, max_bucket) in self.max_liquidity_offset_history.buckets.iter().enumerate().take(32 - min_idx) {
18011826
let max_bucket_end_pos = BUCKET_START_POS[32 - max_idx] - 1;
@@ -3048,7 +3073,7 @@ mod tests {
30483073
// Even after we tell the scorer we definitely have enough available liquidity, it will
30493074
// still remember that there was some failure in the past, and assign a non-0 penalty.
30503075
scorer.payment_path_failed(&payment_path_for_amount(1000), 43);
3051-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 198);
3076+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 32);
30523077
// The first points should be decayed just slightly and the last bucket has a new point.
30533078
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
30543079
Some(([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, 32, 0, 0, 0, 0, 0],
@@ -3058,8 +3083,8 @@ mod tests {
30583083
// simply check bounds here.
30593084
let five_hundred_prob =
30603085
scorer.historical_estimated_payment_success_probability(42, &target, 500).unwrap();
3061-
assert!(five_hundred_prob > 512 * 1024 * 1024); // 0.5
3062-
assert!(five_hundred_prob < 532 * 1024 * 1024); // ~ 0.52
3086+
assert!(five_hundred_prob > 680 * 1024 * 1024); // ~0.66
3087+
assert!(five_hundred_prob < 690 * 1024 * 1024); // ~0.67
30633088
let one_prob =
30643089
scorer.historical_estimated_payment_success_probability(42, &target, 1).unwrap();
30653090
assert!(one_prob < 1024 * 1024 * 1024);
@@ -3083,7 +3108,7 @@ mod tests {
30833108
scorer.payment_path_failed(&payment_path_for_amount(1), 42);
30843109
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 2048);
30853110
usage.inflight_htlc_msat = 0;
3086-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 409);
3111+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, &params), 866);
30873112

30883113
let usage = ChannelUsage {
30893114
amount_msat: 1,
@@ -3269,9 +3294,7 @@ mod tests {
32693294
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
32703295
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],
32713296
[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])));
3272-
assert!(scorer.historical_estimated_payment_success_probability(42, &target, amount_msat)
3273-
.unwrap() > 251 * 1024 * 1024);
3274-
assert!(scorer.historical_estimated_payment_success_probability(42, &target, amount_msat)
3275-
.unwrap() < 256 * 1024 * 1024);
3297+
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, amount_msat),
3298+
Some(0));
32763299
}
32773300
}

0 commit comments

Comments
 (0)