Skip to content

Commit 61b0a90

Browse files
authored
Merge pull request #1617 from TheBlueMatt/2022-07-base-ppm
Add a per-amount base penalty in the ProbabilisticScorer
2 parents 79b55f0 + 7f80972 commit 61b0a90

File tree

1 file changed

+61
-29
lines changed

1 file changed

+61
-29
lines changed

lightning/src/routing/scoring.rs

+61-29
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
///
@@ -369,7 +386,7 @@ pub struct ProbabilisticScoringParameters {
369386
/// multiplier and `2^20`ths of the payment amount, weighted by the negative `log10` of the
370387
/// success probability.
371388
///
372-
/// `-log10(success_probability) * amount_penalty_multiplier_msat * amount_msat / 2^20`
389+
/// `-log10(success_probability) * liquidity_penalty_amount_multiplier_msat * amount_msat / 2^20`
373390
///
374391
/// In practice, this means for 0.1 success probability (`-log10(0.1) == 1`) each `2^20`th of
375392
/// the amount will result in a penalty of the multiplier. And, as the success probability
@@ -378,7 +395,7 @@ pub struct ProbabilisticScoringParameters {
378395
/// fall below `1`.
379396
///
380397
/// Default value: 256 msat
381-
pub amount_penalty_multiplier_msat: u64,
398+
pub liquidity_penalty_amount_multiplier_msat: u64,
382399

383400
/// Manual penalties used for the given nodes. Allows to set a particular penalty for a given
384401
/// node. Note that a manual penalty of `u64::max_value()` means the node would not ever be
@@ -399,7 +416,7 @@ pub struct ProbabilisticScoringParameters {
399416
/// current estimate of the channel's available liquidity.
400417
///
401418
/// Note that in this case all other penalties, including the
402-
/// [`liquidity_penalty_multiplier_msat`] and [`amount_penalty_multiplier_msat`]-based
419+
/// [`liquidity_penalty_multiplier_msat`] and [`liquidity_penalty_amount_multiplier_msat`]-based
403420
/// penalties, as well as the [`base_penalty_msat`] and the [`anti_probing_penalty_msat`], if
404421
/// applicable, are still included in the overall penalty.
405422
///
@@ -409,7 +426,7 @@ pub struct ProbabilisticScoringParameters {
409426
/// Default value: 1_0000_0000_000 msat (1 Bitcoin)
410427
///
411428
/// [`liquidity_penalty_multiplier_msat`]: Self::liquidity_penalty_multiplier_msat
412-
/// [`amount_penalty_multiplier_msat`]: Self::amount_penalty_multiplier_msat
429+
/// [`liquidity_penalty_amount_multiplier_msat`]: Self::liquidity_penalty_amount_multiplier_msat
413430
/// [`base_penalty_msat`]: Self::base_penalty_msat
414431
/// [`anti_probing_penalty_msat`]: Self::anti_probing_penalty_msat
415432
pub considered_impossible_penalty_msat: u64,
@@ -536,9 +553,10 @@ 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),
541-
amount_penalty_multiplier_msat: 0,
559+
liquidity_penalty_amount_multiplier_msat: 0,
542560
manual_node_penalties: HashMap::new(),
543561
anti_probing_penalty_msat: 0,
544562
considered_impossible_penalty_msat: 0,
@@ -558,9 +576,10 @@ 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),
563-
amount_penalty_multiplier_msat: 256,
582+
liquidity_penalty_amount_multiplier_msat: 256,
564583
manual_node_penalties: HashMap::new(),
565584
anti_probing_penalty_msat: 250,
566585
considered_impossible_penalty_msat: 1_0000_0000_000,
@@ -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,
@@ -676,12 +696,10 @@ impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiqui
676696
(negative_log10_times_2048.saturating_mul(multiplier_msat) / 2048).min(max_penalty_msat)
677697
};
678698
let amount_penalty_msat = negative_log10_times_2048
679-
.saturating_mul(params.amount_penalty_multiplier_msat)
699+
.saturating_mul(params.liquidity_penalty_amount_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]
@@ -2153,15 +2185,15 @@ mod tests {
21532185

21542186
let params = ProbabilisticScoringParameters {
21552187
liquidity_penalty_multiplier_msat: 1_000,
2156-
amount_penalty_multiplier_msat: 0,
2188+
liquidity_penalty_amount_multiplier_msat: 0,
21572189
..ProbabilisticScoringParameters::zero_penalty()
21582190
};
21592191
let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
21602192
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
21612193

21622194
let params = ProbabilisticScoringParameters {
21632195
liquidity_penalty_multiplier_msat: 1_000,
2164-
amount_penalty_multiplier_msat: 256,
2196+
liquidity_penalty_amount_multiplier_msat: 256,
21652197
..ProbabilisticScoringParameters::zero_penalty()
21662198
};
21672199
let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);

0 commit comments

Comments
 (0)