Skip to content

Commit 009f952

Browse files
committed
Avoid retrying over recently failed channels
In ProbabilisticScorer, the channel liquidity balance is reduced whenever a payment fails at the corresponding channel. The payment may still be retried through the channel, however, because the liquidity penalty is capped. Use u64::max_value instead in this situation to avoid retrying over the same path. This effectively makes u64::max_value the penalty for amounts exceeding the upper bound, as well. As an edge case, avoid using u64::max_value on attempts where the amount is equal to the effective capacity, which may be the HTLC maximum when the channel capacity is unknown.
1 parent 7671ae5 commit 009f952

File tree

1 file changed

+20
-14
lines changed

1 file changed

+20
-14
lines changed

lightning/src/routing/scoring.rs

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,10 @@ pub struct ProbabilisticScoringParameters {
531531
///
532532
/// The penalty is based in part by the knowledge learned from prior successful and unsuccessful
533533
/// payments. This knowledge is decayed over time based on [`liquidity_offset_half_life`]. The
534-
/// penalty is effectively limited to `2 * liquidity_penalty_multiplier_msat`.
534+
/// penalty is effectively limited to `2 * liquidity_penalty_multiplier_msat` (corresponding to
535+
/// lower bounding the success probability to `0.01`) when the amount falls within the
536+
/// uncertainty bounds of the channel liquidity balance. Amounts above the upper bound will
537+
/// result in a `u64::max_value` penalty, however.
535538
///
536539
/// Default value: 40,000 msat
537540
///
@@ -666,19 +669,22 @@ impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiqui
666669
/// Returns a penalty for routing the given HTLC `amount_msat` through the channel in this
667670
/// direction.
668671
fn penalty_msat(&self, amount_msat: u64, liquidity_penalty_multiplier_msat: u64) -> u64 {
669-
let max_penalty_msat = liquidity_penalty_multiplier_msat.saturating_mul(2);
670672
let max_liquidity_msat = self.max_liquidity_msat();
671673
let min_liquidity_msat = core::cmp::min(self.min_liquidity_msat(), max_liquidity_msat);
672-
if amount_msat > max_liquidity_msat {
673-
max_penalty_msat
674-
} else if amount_msat <= min_liquidity_msat {
674+
if amount_msat <= min_liquidity_msat {
675675
0
676+
} else if amount_msat > max_liquidity_msat {
677+
u64::max_value()
678+
} else if amount_msat == max_liquidity_msat && max_liquidity_msat != self.capacity_msat {
679+
// Avoid using the failed channel on retry.
680+
u64::max_value()
676681
} else {
677682
let numerator = (max_liquidity_msat - amount_msat).saturating_add(1);
678683
let denominator = (max_liquidity_msat - min_liquidity_msat).saturating_add(1);
679684
let penalty_msat = approx::negative_log10_times_1024(numerator, denominator)
680685
.saturating_mul(liquidity_penalty_multiplier_msat) / 1024;
681686
// Upper bound the penalty to ensure some channel is selected.
687+
let max_penalty_msat = liquidity_penalty_multiplier_msat.saturating_mul(2);
682688
penalty_msat.min(max_penalty_msat)
683689
}
684690
}
@@ -1774,8 +1780,8 @@ mod tests {
17741780

17751781
assert_eq!(scorer.channel_penalty_msat(42, 39, 100, &source, &target), 0);
17761782
assert_ne!(scorer.channel_penalty_msat(42, 50, 100, &source, &target), 0);
1777-
assert_ne!(scorer.channel_penalty_msat(42, 50, 100, &source, &target), 2_000);
1778-
assert_eq!(scorer.channel_penalty_msat(42, 61, 100, &source, &target), 2_000);
1783+
assert_ne!(scorer.channel_penalty_msat(42, 50, 100, &source, &target), u64::max_value());
1784+
assert_eq!(scorer.channel_penalty_msat(42, 61, 100, &source, &target), u64::max_value());
17791785
}
17801786

17811787
#[test]
@@ -1839,8 +1845,8 @@ mod tests {
18391845
scorer.payment_path_failed(&path.iter().collect::<Vec<_>>(), 42);
18401846

18411847
assert_eq!(scorer.channel_penalty_msat(42, 250, 1_000, &source, &target), 300);
1842-
assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 2_000);
1843-
assert_eq!(scorer.channel_penalty_msat(42, 750, 1_000, &source, &target), 2_000);
1848+
assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), u64::max_value());
1849+
assert_eq!(scorer.channel_penalty_msat(42, 750, 1_000, &source, &target), u64::max_value());
18441850
}
18451851

18461852
#[test]
@@ -1888,19 +1894,19 @@ mod tests {
18881894
assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 0);
18891895
assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 97);
18901896
assert_eq!(scorer.channel_penalty_msat(42, 768, 1_024, &source, &target), 1_409);
1891-
assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), 2_000);
1897+
assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), u64::max_value());
18921898

18931899
SinceEpoch::advance(Duration::from_secs(9));
18941900
assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 0);
18951901
assert_eq!(scorer.channel_penalty_msat(42, 256, 1_024, &source, &target), 97);
18961902
assert_eq!(scorer.channel_penalty_msat(42, 768, 1_024, &source, &target), 1_409);
1897-
assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), 2_000);
1903+
assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), u64::max_value());
18981904

18991905
SinceEpoch::advance(Duration::from_secs(1));
19001906
assert_eq!(scorer.channel_penalty_msat(42, 64, 1_024, &source, &target), 0);
19011907
assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 34);
19021908
assert_eq!(scorer.channel_penalty_msat(42, 896, 1_024, &source, &target), 1_773);
1903-
assert_eq!(scorer.channel_penalty_msat(42, 960, 1_024, &source, &target), 2_000);
1909+
assert_eq!(scorer.channel_penalty_msat(42, 960, 1_024, &source, &target), u64::max_value());
19041910

19051911
// Fully decay liquidity lower bound.
19061912
SinceEpoch::advance(Duration::from_secs(10 * 7));
@@ -1995,7 +2001,7 @@ mod tests {
19952001
let target = target_node_id();
19962002

19972003
scorer.payment_path_failed(&payment_path_for_amount(500).iter().collect::<Vec<_>>(), 42);
1998-
assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 2_000);
2004+
assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), u64::max_value());
19992005

20002006
SinceEpoch::advance(Duration::from_secs(10));
20012007
assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 472);
@@ -2025,7 +2031,7 @@ mod tests {
20252031
let target = target_node_id();
20262032

20272033
scorer.payment_path_failed(&payment_path_for_amount(500).iter().collect::<Vec<_>>(), 42);
2028-
assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), 2_000);
2034+
assert_eq!(scorer.channel_penalty_msat(42, 500, 1_000, &source, &target), u64::max_value());
20292035

20302036
let mut serialized_scorer = Vec::new();
20312037
scorer.write(&mut serialized_scorer).unwrap();

0 commit comments

Comments
 (0)