Skip to content

Commit db0e626

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 #1616
1 parent aad65c8 commit db0e626

File tree

1 file changed

+45
-19
lines changed

1 file changed

+45
-19
lines changed

lightning/src/routing/scoring.rs

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,17 @@ pub struct ProbabilisticScoringParameters {
331331
/// Default value: 500 msat
332332
pub base_penalty_msat: u64,
333333

334+
/// A fixed penalty in msats to apply to each channel, multiplied by the payment amount.
335+
///
336+
/// The purpose of the amount penalty is to avoid having fees dominate the channel cost (i.e.,
337+
/// fees plus penalty) for large payments. The penalty is computed as the product of this
338+
/// multiplier and `2^30`ths of the payment amount.
339+
///
340+
/// ie `amount_penalty_multiplier_msat * amount_msat / 2^30`
341+
///
342+
/// Default value: 8,192 msat
343+
pub base_penalty_amount_multiplier_msat: u64,
344+
334345
/// A multiplier used in conjunction with the negative `log10` of the channel's success
335346
/// probability for a payment to determine the liquidity penalty.
336347
///
@@ -505,6 +516,7 @@ impl ProbabilisticScoringParameters {
505516
fn zero_penalty() -> Self {
506517
Self {
507518
base_penalty_msat: 0,
519+
base_penalty_amount_multiplier_msat: 0,
508520
liquidity_penalty_multiplier_msat: 0,
509521
liquidity_offset_half_life: Duration::from_secs(3600),
510522
amount_penalty_multiplier_msat: 0,
@@ -526,6 +538,7 @@ impl Default for ProbabilisticScoringParameters {
526538
fn default() -> Self {
527539
Self {
528540
base_penalty_msat: 500,
541+
base_penalty_amount_multiplier_msat: 8192,
529542
liquidity_penalty_multiplier_msat: 40_000,
530543
liquidity_offset_half_life: Duration::from_secs(3600),
531544
amount_penalty_multiplier_msat: 256,
@@ -598,10 +611,11 @@ const PRECISION_LOWER_BOUND_DENOMINATOR: u64 = approx::LOWER_BITS_BOUND;
598611

599612
/// The divisor used when computing the amount penalty.
600613
const AMOUNT_PENALTY_DIVISOR: u64 = 1 << 20;
614+
const BASE_AMOUNT_PENALTY_DIVISOR: u64 = 1 << 30;
601615

602616
impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiquidity<L, T, U> {
603-
/// Returns a penalty for routing the given HTLC `amount_msat` through the channel in this
604-
/// direction.
617+
/// Returns a liquidity penalty for routing the given HTLC `amount_msat` through the channel in
618+
/// this direction.
605619
fn penalty_msat(&self, amount_msat: u64, params: &ProbabilisticScoringParameters) -> u64 {
606620
let max_liquidity_msat = self.max_liquidity_msat();
607621
let min_liquidity_msat = core::cmp::min(self.min_liquidity_msat(), max_liquidity_msat);
@@ -625,8 +639,8 @@ impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiqui
625639
if amount_msat - min_liquidity_msat < denominator / PRECISION_LOWER_BOUND_DENOMINATOR {
626640
// If the failure probability is < 1.5625% (as 1 - numerator/denominator < 1/64),
627641
// don't bother trying to use the log approximation as it gets too noisy to be
628-
// particularly helpful, instead just round down to 0 and return the base penalty.
629-
params.base_penalty_msat
642+
// particularly helpful, instead just round down to 0.
643+
0
630644
} else {
631645
let negative_log10_times_2048 =
632646
approx::negative_log10_times_2048(numerator, denominator);
@@ -651,9 +665,7 @@ impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiqui
651665
.saturating_mul(params.amount_penalty_multiplier_msat)
652666
.saturating_mul(amount_msat) / 2048 / AMOUNT_PENALTY_DIVISOR;
653667

654-
params.base_penalty_msat
655-
.saturating_add(liquidity_penalty_msat)
656-
.saturating_add(amount_penalty_msat)
668+
liquidity_penalty_msat.saturating_add(amount_penalty_msat)
657669
}
658670

659671
/// Returns the lower bound of the channel liquidity balance in this direction.
@@ -735,13 +747,17 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
735747
return u64::max_value();
736748
}
737749

750+
let base_penalty_msat = self.params.base_penalty_msat.saturating_add(
751+
self.params.base_penalty_amount_multiplier_msat
752+
.saturating_mul(usage.amount_msat) / BASE_AMOUNT_PENALTY_DIVISOR);
753+
738754
let mut anti_probing_penalty_msat = 0;
739755
match usage.effective_capacity {
740756
EffectiveCapacity::ExactLiquidity { liquidity_msat } => {
741757
if usage.amount_msat > liquidity_msat {
742758
return u64::max_value();
743759
} else {
744-
return self.params.base_penalty_msat;
760+
return base_penalty_msat;
745761
}
746762
},
747763
EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat: Some(htlc_maximum_msat) } => {
@@ -762,6 +778,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
762778
.as_directed(source, target, capacity_msat, liquidity_offset_half_life)
763779
.penalty_msat(amount_msat, &self.params)
764780
.saturating_add(anti_probing_penalty_msat)
781+
.saturating_add(base_penalty_msat)
765782
}
766783

767784
fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
@@ -2024,47 +2041,47 @@ mod tests {
20242041
inflight_htlc_msat: 0,
20252042
effective_capacity: EffectiveCapacity::Total { capacity_msat: 950_000_000, htlc_maximum_msat: Some(1_000) },
20262043
};
2027-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 3613);
2044+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 4375);
20282045
let usage = ChannelUsage {
20292046
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20302047
};
2031-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1977);
2048+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2739);
20322049
let usage = ChannelUsage {
20332050
effective_capacity: EffectiveCapacity::Total { capacity_msat: 2_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20342051
};
2035-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1474);
2052+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2236);
20362053
let usage = ChannelUsage {
20372054
effective_capacity: EffectiveCapacity::Total { capacity_msat: 3_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20382055
};
2039-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1223);
2056+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1985);
20402057
let usage = ChannelUsage {
20412058
effective_capacity: EffectiveCapacity::Total { capacity_msat: 4_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20422059
};
2043-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 877);
2060+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1639);
20442061
let usage = ChannelUsage {
20452062
effective_capacity: EffectiveCapacity::Total { capacity_msat: 5_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20462063
};
2047-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 845);
2064+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1607);
20482065
let usage = ChannelUsage {
20492066
effective_capacity: EffectiveCapacity::Total { capacity_msat: 6_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20502067
};
2051-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2068+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
20522069
let usage = ChannelUsage {
20532070
effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_450_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20542071
};
2055-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2072+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
20562073
let usage = ChannelUsage {
20572074
effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20582075
};
2059-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2076+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
20602077
let usage = ChannelUsage {
20612078
effective_capacity: EffectiveCapacity::Total { capacity_msat: 8_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20622079
};
2063-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2080+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
20642081
let usage = ChannelUsage {
20652082
effective_capacity: EffectiveCapacity::Total { capacity_msat: 9_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20662083
};
2067-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2084+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
20682085
}
20692086

20702087
#[test]
@@ -2092,6 +2109,15 @@ mod tests {
20922109
};
20932110
let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
20942111
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 558);
2112+
2113+
let params = ProbabilisticScoringParameters {
2114+
base_penalty_msat: 500, liquidity_penalty_multiplier_msat: 1_000,
2115+
base_penalty_amount_multiplier_msat: (1<<30),
2116+
anti_probing_penalty_msat: 0, ..Default::default()
2117+
};
2118+
2119+
let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
2120+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 558 + 128);
20952121
}
20962122

20972123
#[test]

0 commit comments

Comments
 (0)