From 149fc6e584a33d9e916eba8f1834bef26eadffe7 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 6 Jul 2022 21:05:54 +0000 Subject: [PATCH] Make the `ProbabilisticScorer` impossibility penalty configurable When we consider sending an HTLC over a given channel impossible due to our current knowledge of the channel's liquidity, we currently always assign a penalty of `u64::max_value()`. However, because we now refuse to retry a payment along the same path in the router itself, we can now make this value configurable. This allows users to have a relatively high knowledge decay interval without the side-effect of refusing to try the only available path in cases where a channel is intermittently available. --- lightning/src/routing/scoring.rs | 53 ++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/lightning/src/routing/scoring.rs b/lightning/src/routing/scoring.rs index 524f0ed3158..b325514efe7 100644 --- a/lightning/src/routing/scoring.rs +++ b/lightning/src/routing/scoring.rs @@ -374,6 +374,19 @@ pub struct ProbabilisticScoringParameters { /// /// Default value: 250 msat pub anti_probing_penalty_msat: u64, + + /// This penalty is applied when the amount we're attempting to send over a channel exceeds our + /// current estimate of the liquidity available on a channel. + /// + /// Note that in this case the liquidity penalties are still included to ensure such channels + /// which may have enough liquidity are scored worse than channels which we do not believe have + /// enough. + /// + /// Note if you wish to avoid creating paths with such channels entirely, a penalty of + /// `u64::max_value()` will guarantee that. + /// + /// Default value: `u64::max_value()` + pub considered_impossible_penalty_msat: u64, } /// Accounting for channel liquidity balance uncertainty. @@ -492,6 +505,7 @@ impl ProbabilisticScoringParameters { amount_penalty_multiplier_msat: 0, banned_nodes: HashSet::new(), anti_probing_penalty_msat: 0, + considered_impossible_penalty_msat: 0, } } @@ -513,6 +527,7 @@ impl Default for ProbabilisticScoringParameters { amount_penalty_multiplier_msat: 256, banned_nodes: HashSet::new(), anti_probing_penalty_msat: 250, + considered_impossible_penalty_msat: u64::max_value(), } } } @@ -590,17 +605,12 @@ impl, T: Time, U: Deref> DirectedChannelLiqui if amount_msat <= min_liquidity_msat { 0 } else if amount_msat >= max_liquidity_msat { - if amount_msat > max_liquidity_msat { - u64::max_value() - } else if max_liquidity_msat != self.capacity_msat { - // Avoid using the failed channel on retry. - u64::max_value() - } else { - // Equivalent to hitting the else clause below with the amount equal to the - // effective capacity and without any certainty on the liquidity upper bound. - let negative_log10_times_2048 = NEGATIVE_LOG10_UPPER_BOUND * 2048; - self.combined_penalty_msat(amount_msat, negative_log10_times_2048, params) - } + // Equivalent to hitting the else clause below with the amount equal to the effective + // capacity and without any certainty on the liquidity upper bound, plus the + // impossibility penalty. + let negative_log10_times_2048 = NEGATIVE_LOG10_UPPER_BOUND * 2048; + self.combined_penalty_msat(amount_msat, negative_log10_times_2048, params) + .saturating_add(params.considered_impossible_penalty_msat) } else { let numerator = (max_liquidity_msat - amount_msat).saturating_add(1); let denominator = (max_liquidity_msat - min_liquidity_msat).saturating_add(1); @@ -1574,7 +1584,7 @@ mod tests { assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0); let usage = ChannelUsage { amount_msat: 102_400, ..usage }; assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 47); - let usage = ChannelUsage { amount_msat: 1_024_000, ..usage }; + let usage = ChannelUsage { amount_msat: 1_023_999, ..usage }; assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000); let usage = ChannelUsage { @@ -1604,6 +1614,7 @@ mod tests { let network_graph = network_graph(&logger); let params = ProbabilisticScoringParameters { liquidity_penalty_multiplier_msat: 1_000, + considered_impossible_penalty_msat: u64::max_value(), ..ProbabilisticScoringParameters::zero_penalty() }; let scorer = ProbabilisticScorer::new(params, &network_graph, &logger) @@ -1695,6 +1706,7 @@ mod tests { let network_graph = network_graph(&logger); let params = ProbabilisticScoringParameters { liquidity_penalty_multiplier_msat: 1_000, + considered_impossible_penalty_msat: u64::max_value(), ..ProbabilisticScoringParameters::zero_penalty() }; let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger); @@ -1761,6 +1773,7 @@ mod tests { let params = ProbabilisticScoringParameters { liquidity_penalty_multiplier_msat: 1_000, liquidity_offset_half_life: Duration::from_secs(10), + considered_impossible_penalty_msat: u64::max_value(), ..ProbabilisticScoringParameters::zero_penalty() }; let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger); @@ -1770,10 +1783,10 @@ mod tests { let usage = ChannelUsage { amount_msat: 0, inflight_htlc_msat: 0, - effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: Some(1_000) }, + effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: Some(1_024) }, }; assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0); - let usage = ChannelUsage { amount_msat: 1_024, ..usage }; + let usage = ChannelUsage { amount_msat: 1_023, ..usage }; assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000); scorer.payment_path_failed(&payment_path_for_amount(768).iter().collect::>(), 42); @@ -1817,20 +1830,20 @@ mod tests { let usage = ChannelUsage { amount_msat: 1_023, ..usage }; assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000); let usage = ChannelUsage { amount_msat: 1_024, ..usage }; - assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000); + assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value()); // Fully decay liquidity upper bound. SinceEpoch::advance(Duration::from_secs(10)); let usage = ChannelUsage { amount_msat: 0, ..usage }; assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0); let usage = ChannelUsage { amount_msat: 1_024, ..usage }; - assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000); + assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value()); SinceEpoch::advance(Duration::from_secs(10)); let usage = ChannelUsage { amount_msat: 0, ..usage }; assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0); let usage = ChannelUsage { amount_msat: 1_024, ..usage }; - assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000); + assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value()); } #[test] @@ -1915,6 +1928,7 @@ mod tests { let params = ProbabilisticScoringParameters { liquidity_penalty_multiplier_msat: 1_000, liquidity_offset_half_life: Duration::from_secs(10), + considered_impossible_penalty_msat: u64::max_value(), ..ProbabilisticScoringParameters::zero_penalty() }; let mut scorer = ProbabilisticScorer::new(params.clone(), &network_graph, &logger); @@ -1951,6 +1965,7 @@ mod tests { let params = ProbabilisticScoringParameters { liquidity_penalty_multiplier_msat: 1_000, liquidity_offset_half_life: Duration::from_secs(10), + considered_impossible_penalty_msat: u64::max_value(), ..ProbabilisticScoringParameters::zero_penalty() }; let mut scorer = ProbabilisticScorer::new(params.clone(), &network_graph, &logger); @@ -2110,11 +2125,11 @@ mod tests { }; let params = ProbabilisticScoringParameters { - liquidity_penalty_multiplier_msat: 40_000, + considered_impossible_penalty_msat: 42_420, ..ProbabilisticScoringParameters::zero_penalty() }; let scorer = ProbabilisticScorer::new(params, &network_graph, &logger); - assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 80_000); + assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 42_420); } #[test]