Skip to content

Commit 978e4ce

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 9b5697b commit 978e4ce

File tree

1 file changed

+34
-11
lines changed

1 file changed

+34
-11
lines changed

lightning/src/routing/scoring.rs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,7 +1758,32 @@ mod bucketed_history {
17581758
}
17591759

17601760
let mut cumulative_success_prob_times_billion = 0;
1761-
for (min_idx, min_bucket) in self.min_liquidity_offset_history.buckets.iter().enumerate() {
1761+
// Special-case the 0th min bucket - it generally means we failed a payment, so only
1762+
// consider the highest (i.e. largest-offset-from-max-capacity) max bucket for all
1763+
// points against the 0th min bucket!
1764+
if self.min_liquidity_offset_history.buckets[0] != 0 {
1765+
let mut highest_max_bucket_with_points = 0;
1766+
let mut total_max_points = 0;
1767+
for (max_idx, max_bucket) in self.max_liquidity_offset_history.buckets.iter().enumerate() {
1768+
if *max_bucket >= 32 {
1769+
highest_max_bucket_with_points = cmp::max(highest_max_bucket_with_points, max_idx);
1770+
}
1771+
total_max_points += *max_bucket as u64;
1772+
}
1773+
let max_bucket_end_pos = BUCKET_START_POS[32 - highest_max_bucket_with_points] - 1;
1774+
if payment_pos < max_bucket_end_pos {
1775+
let bucket_prob_times_billion =
1776+
(self.min_liquidity_offset_history.buckets[0] as u64) * total_max_points
1777+
* 1024 * 1024 * 1024 / total_valid_points_tracked;
1778+
cumulative_success_prob_times_billion += bucket_prob_times_billion *
1779+
((max_bucket_end_pos - payment_pos) as u64) /
1780+
// Add an additional one in the divisor as the payment bucket has been
1781+
// rounded down.
1782+
(max_bucket_end_pos + 1) as u64;
1783+
}
1784+
}
1785+
1786+
for (min_idx, min_bucket) in self.min_liquidity_offset_history.buckets.iter().enumerate().skip(1) {
17621787
let min_bucket_start_pos = BUCKET_START_POS[min_idx];
17631788
for (max_idx, max_bucket) in self.max_liquidity_offset_history.buckets.iter().enumerate().take(32 - min_idx) {
17641789
let max_bucket_end_pos = BUCKET_START_POS[32 - max_idx] - 1;
@@ -2987,7 +3012,7 @@ mod tests {
29873012
// Even after we tell the scorer we definitely have enough available liquidity, it will
29883013
// still remember that there was some failure in the past, and assign a non-0 penalty.
29893014
scorer.payment_path_failed(&payment_path_for_amount(1000).iter().collect::<Vec<_>>(), 43);
2990-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 198);
3015+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 32);
29913016
// The first points should be decayed just slightly and the last bucket has a new point.
29923017
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
29933018
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],
@@ -2997,8 +3022,8 @@ mod tests {
29973022
// simply check bounds here.
29983023
let five_hundred_prob =
29993024
scorer.historical_estimated_payment_success_probability(42, &target, 500).unwrap();
3000-
assert!(five_hundred_prob > 512 * 1024 * 1024); // 0.5
3001-
assert!(five_hundred_prob < 532 * 1024 * 1024); // ~ 0.52
3025+
assert!(five_hundred_prob > 680 * 1024 * 1024); // ~0.66
3026+
assert!(five_hundred_prob < 690 * 1024 * 1024); // ~0.67
30023027
let one_prob =
30033028
scorer.historical_estimated_payment_success_probability(42, &target, 1).unwrap();
30043029
assert!(one_prob < 1024 * 1024 * 1024);
@@ -3147,16 +3172,14 @@ mod tests {
31473172
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, amount_msat),
31483173
Some(512 * 1024 * 1024));
31493174

3150-
// ...but once we see a failure, we consider the payment to be substantially less likely,
3151-
// even though not a probability of zero as we still look at the second max bucket which
3152-
// now shows 31.
3175+
// Once we see a second failure for the lower amount, we'll again consider the success
3176+
// probability zero, as we only look at the lowest-value maximum bucket when all previous
3177+
// attempts at using a channel have failed.
31533178
scorer.payment_path_failed(&payment_path_for_amount(amount_msat).iter().collect::<Vec<_>>(), 42);
31543179
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
31553180
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],
31563181
[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])));
3157-
assert!(scorer.historical_estimated_payment_success_probability(42, &target, amount_msat)
3158-
.unwrap() > 251 * 1024 * 1024);
3159-
assert!(scorer.historical_estimated_payment_success_probability(42, &target, amount_msat)
3160-
.unwrap() < 256 * 1024 * 1024);
3182+
assert_eq!(scorer.historical_estimated_payment_success_probability(42, &target, amount_msat),
3183+
Some(0));
31613184
}
31623185
}

0 commit comments

Comments
 (0)