]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Don't interpret decayed data as we've failed to send tiny values 2024-10-decayed-non-null
authorMatt Corallo <git@bluematt.me>
Mon, 14 Oct 2024 17:11:04 +0000 (17:11 +0000)
committerMatt Corallo <git@bluematt.me>
Mon, 14 Oct 2024 19:38:16 +0000 (19:38 +0000)
When we're calculating the success probability for min-/max-bucket
pairs and are looking at the 0th' min-bucket, we only look at the
highest max-bucket to decide the success probability. We ignore
max-buckets which have a value below `BUCKET_FIXED_POINT_ONE` to
only consider values which aren't substantially decayed.

However, if all of our data is substantially decayed, this filter
causes us to conclude that the highest max-bucket is bucket zero
even though we really should then be looking at any bucket.

We make this change here, looking at the highest non-zero
max-bucket if no max-buckets have a value above
`BUCKET_FIXED_POINT_ONE`.

lightning/src/routing/scoring.rs

index b27a9f97b02664507a7369e8d18b3245d18e0eb2..6e41066cefce381a40883c1be0b3dd77af53d200 100644 (file)
@@ -1818,15 +1818,27 @@ mod bucketed_history {
                        // values, which will result in us thinking we have some nontrivial probability of
                        // routing up to that amount.
                        if min_liquidity_offset_history_buckets[0] != 0 {
-                               let mut highest_max_bucket_with_points = 0; // The highest max-bucket with any data
+                               // Track the highest max-buckets with any data at all, as well as the highest
+                               // max-bucket with at least BUCKET_FIXED_POINT_ONE.
+                               let mut highest_max_bucket_with_points = 0;
+                               let mut highest_max_bucket_with_full_points = None;
                                let mut total_max_points = 0; // Total points in max-buckets to consider
                                for (max_idx, max_bucket) in max_liquidity_offset_history_buckets.iter().enumerate() {
                                        if *max_bucket >= BUCKET_FIXED_POINT_ONE {
+                                               highest_max_bucket_with_full_points = Some(cmp::max(highest_max_bucket_with_full_points.unwrap_or(0), max_idx));
+                                       }
+                                       if *max_bucket != 0 {
                                                highest_max_bucket_with_points = cmp::max(highest_max_bucket_with_points, max_idx);
                                        }
                                        total_max_points += *max_bucket as u64;
                                }
-                               let max_bucket_end_pos = BUCKET_START_POS[32 - highest_max_bucket_with_points] - 1;
+                               // Use the highest max-bucket with at least BUCKET_FIXED_POINT_ONE, but if none is
+                               // available use the highest max-bucket with any non-zero value. This ensures that
+                               // if we have substantially decayed data we don't end up thinking the highest
+                               // max-bucket is zero even though we have no points in the 0th max-bucket and do
+                               // have points elsewhere.
+                               let selected_max = highest_max_bucket_with_full_points.unwrap_or(highest_max_bucket_with_points);
+                               let max_bucket_end_pos = BUCKET_START_POS[32 - selected_max] - 1;
                                if payment_pos < max_bucket_end_pos {
                                        let (numerator, denominator) = success_probability(payment_pos as u64, 0,
                                                max_bucket_end_pos as u64, POSITION_TICKS as u64 - 1, params, true);