From ec2b1ced077c879b0f51ef4fcd0b5d2d22aa570d 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 | 55 ++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/lightning/src/routing/scoring.rs b/lightning/src/routing/scoring.rs index 4922fad7..cd2ae6d5 100644 --- a/lightning/src/routing/scoring.rs +++ b/lightning/src/routing/scoring.rs @@ -394,6 +394,25 @@ 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 channel's available liquidity. + /// + /// Note that in this case all other penalties, including the + /// [`liquidity_penalty_multiplier_msat`] and [`amount_penalty_multiplier_msat`]-based + /// penalties, as well as the [`base_penalty_msat`] and the [`anti_probing_penalty_msat`], if + /// applicable, are still included in the overall penalty. + /// + /// If you wish to avoid creating paths with such channels entirely, setting this to a value of + /// `u64::max_value()` will guarantee that. + /// + /// Default value: `u64::max_value()` + /// + /// [`liquidity_penalty_multiplier_msat`]: Self::liquidity_penalty_multiplier_msat + /// [`amount_penalty_multiplier_msat`]: Self::amount_penalty_multiplier_msat + /// [`base_penalty_msat`]: Self::base_penalty_msat + /// [`anti_probing_penalty_msat`]: Self::anti_probing_penalty_msat + pub considered_impossible_penalty_msat: u64, } /// Accounting for channel liquidity balance uncertainty. @@ -522,6 +541,7 @@ impl ProbabilisticScoringParameters { amount_penalty_multiplier_msat: 0, manual_node_penalties: HashMap::new(), anti_probing_penalty_msat: 0, + considered_impossible_penalty_msat: 0, } } @@ -543,6 +563,7 @@ impl Default for ProbabilisticScoringParameters { amount_penalty_multiplier_msat: 256, manual_node_penalties: HashMap::new(), anti_probing_penalty_msat: 250, + considered_impossible_penalty_msat: u64::max_value(), } } } @@ -620,17 +641,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); @@ -1624,7 +1640,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 { @@ -1654,6 +1670,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) @@ -1745,6 +1762,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); @@ -1811,6 +1829,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); @@ -1820,10 +1839,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); @@ -1867,20 +1886,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] @@ -1965,6 +1984,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); @@ -2001,6 +2021,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); -- 2.30.2