Skip to content

Commit fe39a89

Browse files
committed
Add a per-amount base penalty in the ProbabilisticScorer
There's not much reason to not have a per-hop-per-amount penalty in the `ProbabilisticScorer` to go along with the per-hop penalty to let it scale up to larger amounts, so we add one here. Notably, we use a divisor of 2^30 instead of 2^20 (like the equivalent liquidity penalty) as it allows for more flexibility, and there's not really any reason to worry about us not being able to create high enough penalties. Closes lightningdevkit#1616
1 parent 5023ff0 commit fe39a89

File tree

1 file changed

+52
-20
lines changed

1 file changed

+52
-20
lines changed

lightning/src/routing/scoring.rs

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -324,13 +324,30 @@ where L::Target: Logger {
324324
///
325325
/// Used to configure base, liquidity, and amount penalties, the sum of which comprises the channel
326326
/// penalty (i.e., the amount in msats willing to be paid to avoid routing through the channel).
327+
///
328+
/// The penalty applied to any channel by the [`ProbabilisticScorer`] is the sum of each of the
329+
/// parameters here.
327330
#[derive(Clone)]
328331
pub struct ProbabilisticScoringParameters {
329332
/// A fixed penalty in msats to apply to each channel.
330333
///
331334
/// Default value: 500 msat
332335
pub base_penalty_msat: u64,
333336

337+
/// A multiplier used with the payment amount to calculate a fixed penalty applied to each
338+
/// channel, in excess of the [`base_penalty_msat`].
339+
///
340+
/// The purpose of the amount penalty is to avoid having fees dominate the channel cost (i.e.,
341+
/// fees plus penalty) for large payments. The penalty is computed as the product of this
342+
/// multiplier and `2^30`ths of the payment amount.
343+
///
344+
/// ie `base_penalty_amount_multiplier_msat * amount_msat / 2^30`
345+
///
346+
/// Default value: 8,192 msat
347+
///
348+
/// [`base_penalty_msat`]: Self::base_penalty_msat
349+
pub base_penalty_amount_multiplier_msat: u64,
350+
334351
/// A multiplier used in conjunction with the negative `log10` of the channel's success
335352
/// probability for a payment to determine the liquidity penalty.
336353
///
@@ -536,6 +553,7 @@ impl ProbabilisticScoringParameters {
536553
fn zero_penalty() -> Self {
537554
Self {
538555
base_penalty_msat: 0,
556+
base_penalty_amount_multiplier_msat: 0,
539557
liquidity_penalty_multiplier_msat: 0,
540558
liquidity_offset_half_life: Duration::from_secs(3600),
541559
amount_penalty_multiplier_msat: 0,
@@ -558,6 +576,7 @@ impl Default for ProbabilisticScoringParameters {
558576
fn default() -> Self {
559577
Self {
560578
base_penalty_msat: 500,
579+
base_penalty_amount_multiplier_msat: 8192,
561580
liquidity_penalty_multiplier_msat: 40_000,
562581
liquidity_offset_half_life: Duration::from_secs(3600),
563582
amount_penalty_multiplier_msat: 256,
@@ -631,10 +650,11 @@ const PRECISION_LOWER_BOUND_DENOMINATOR: u64 = approx::LOWER_BITS_BOUND;
631650

632651
/// The divisor used when computing the amount penalty.
633652
const AMOUNT_PENALTY_DIVISOR: u64 = 1 << 20;
653+
const BASE_AMOUNT_PENALTY_DIVISOR: u64 = 1 << 30;
634654

635655
impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiquidity<L, T, U> {
636-
/// Returns a penalty for routing the given HTLC `amount_msat` through the channel in this
637-
/// direction.
656+
/// Returns a liquidity penalty for routing the given HTLC `amount_msat` through the channel in
657+
/// this direction.
638658
fn penalty_msat(&self, amount_msat: u64, params: &ProbabilisticScoringParameters) -> u64 {
639659
let max_liquidity_msat = self.max_liquidity_msat();
640660
let min_liquidity_msat = core::cmp::min(self.min_liquidity_msat(), max_liquidity_msat);
@@ -653,8 +673,8 @@ impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiqui
653673
if amount_msat - min_liquidity_msat < denominator / PRECISION_LOWER_BOUND_DENOMINATOR {
654674
// If the failure probability is < 1.5625% (as 1 - numerator/denominator < 1/64),
655675
// don't bother trying to use the log approximation as it gets too noisy to be
656-
// particularly helpful, instead just round down to 0 and return the base penalty.
657-
params.base_penalty_msat
676+
// particularly helpful, instead just round down to 0.
677+
0
658678
} else {
659679
let negative_log10_times_2048 =
660680
approx::negative_log10_times_2048(numerator, denominator);
@@ -663,7 +683,7 @@ impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiqui
663683
}
664684
}
665685

666-
/// Computes the liquidity and amount penalties and adds them to the base penalty.
686+
/// Computes the liquidity penalty from the penalty multipliers.
667687
#[inline(always)]
668688
fn combined_penalty_msat(
669689
&self, amount_msat: u64, negative_log10_times_2048: u64,
@@ -679,9 +699,7 @@ impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiqui
679699
.saturating_mul(params.amount_penalty_multiplier_msat)
680700
.saturating_mul(amount_msat) / 2048 / AMOUNT_PENALTY_DIVISOR;
681701

682-
params.base_penalty_msat
683-
.saturating_add(liquidity_penalty_msat)
684-
.saturating_add(amount_penalty_msat)
702+
liquidity_penalty_msat.saturating_add(amount_penalty_msat)
685703
}
686704

687705
/// Returns the lower bound of the channel liquidity balance in this direction.
@@ -763,13 +781,17 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
763781
return *penalty;
764782
}
765783

784+
let base_penalty_msat = self.params.base_penalty_msat.saturating_add(
785+
self.params.base_penalty_amount_multiplier_msat
786+
.saturating_mul(usage.amount_msat) / BASE_AMOUNT_PENALTY_DIVISOR);
787+
766788
let mut anti_probing_penalty_msat = 0;
767789
match usage.effective_capacity {
768790
EffectiveCapacity::ExactLiquidity { liquidity_msat } => {
769791
if usage.amount_msat > liquidity_msat {
770792
return u64::max_value();
771793
} else {
772-
return self.params.base_penalty_msat;
794+
return base_penalty_msat;
773795
}
774796
},
775797
EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat: Some(htlc_maximum_msat) } => {
@@ -790,6 +812,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
790812
.as_directed(source, target, capacity_msat, liquidity_offset_half_life)
791813
.penalty_msat(amount_msat, &self.params)
792814
.saturating_add(anti_probing_penalty_msat)
815+
.saturating_add(base_penalty_msat)
793816
}
794817

795818
fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
@@ -2069,47 +2092,47 @@ mod tests {
20692092
inflight_htlc_msat: 0,
20702093
effective_capacity: EffectiveCapacity::Total { capacity_msat: 950_000_000, htlc_maximum_msat: Some(1_000) },
20712094
};
2072-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 3613);
2095+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 4375);
20732096
let usage = ChannelUsage {
20742097
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20752098
};
2076-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1977);
2099+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2739);
20772100
let usage = ChannelUsage {
20782101
effective_capacity: EffectiveCapacity::Total { capacity_msat: 2_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20792102
};
2080-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1474);
2103+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2236);
20812104
let usage = ChannelUsage {
20822105
effective_capacity: EffectiveCapacity::Total { capacity_msat: 3_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20832106
};
2084-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1223);
2107+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1985);
20852108
let usage = ChannelUsage {
20862109
effective_capacity: EffectiveCapacity::Total { capacity_msat: 4_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20872110
};
2088-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 877);
2111+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1639);
20892112
let usage = ChannelUsage {
20902113
effective_capacity: EffectiveCapacity::Total { capacity_msat: 5_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20912114
};
2092-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 845);
2115+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1607);
20932116
let usage = ChannelUsage {
20942117
effective_capacity: EffectiveCapacity::Total { capacity_msat: 6_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20952118
};
2096-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2119+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
20972120
let usage = ChannelUsage {
20982121
effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_450_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20992122
};
2100-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2123+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
21012124
let usage = ChannelUsage {
21022125
effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
21032126
};
2104-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2127+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
21052128
let usage = ChannelUsage {
21062129
effective_capacity: EffectiveCapacity::Total { capacity_msat: 8_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
21072130
};
2108-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2131+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
21092132
let usage = ChannelUsage {
21102133
effective_capacity: EffectiveCapacity::Total { capacity_msat: 9_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
21112134
};
2112-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2135+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
21132136
}
21142137

21152138
#[test]
@@ -2137,6 +2160,15 @@ mod tests {
21372160
};
21382161
let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
21392162
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 558);
2163+
2164+
let params = ProbabilisticScoringParameters {
2165+
base_penalty_msat: 500, liquidity_penalty_multiplier_msat: 1_000,
2166+
base_penalty_amount_multiplier_msat: (1 << 30),
2167+
anti_probing_penalty_msat: 0, ..Default::default()
2168+
};
2169+
2170+
let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
2171+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 558 + 128);
21402172
}
21412173

21422174
#[test]

0 commit comments

Comments
 (0)