Skip to content

Commit 2ad413c

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 9687183 commit 2ad413c

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
///
@@ -517,6 +528,7 @@ impl ProbabilisticScoringParameters {
517528
fn zero_penalty() -> Self {
518529
Self {
519530
base_penalty_msat: 0,
531+
base_penalty_amount_multiplier_msat: 0,
520532
liquidity_penalty_multiplier_msat: 0,
521533
liquidity_offset_half_life: Duration::from_secs(3600),
522534
amount_penalty_multiplier_msat: 0,
@@ -538,6 +550,7 @@ impl Default for ProbabilisticScoringParameters {
538550
fn default() -> Self {
539551
Self {
540552
base_penalty_msat: 500,
553+
base_penalty_amount_multiplier_msat: 8192,
541554
liquidity_penalty_multiplier_msat: 40_000,
542555
liquidity_offset_half_life: Duration::from_secs(3600),
543556
amount_penalty_multiplier_msat: 256,
@@ -610,10 +623,11 @@ const PRECISION_LOWER_BOUND_DENOMINATOR: u64 = approx::LOWER_BITS_BOUND;
610623

611624
/// The divisor used when computing the amount penalty.
612625
const AMOUNT_PENALTY_DIVISOR: u64 = 1 << 20;
626+
const BASE_AMOUNT_PENALTY_DIVISOR: u64 = 1 << 30;
613627

614628
impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiquidity<L, T, U> {
615-
/// Returns a penalty for routing the given HTLC `amount_msat` through the channel in this
616-
/// direction.
629+
/// Returns a liquidity penalty for routing the given HTLC `amount_msat` through the channel in
630+
/// this direction.
617631
fn penalty_msat(&self, amount_msat: u64, params: &ProbabilisticScoringParameters) -> u64 {
618632
let max_liquidity_msat = self.max_liquidity_msat();
619633
let min_liquidity_msat = core::cmp::min(self.min_liquidity_msat(), max_liquidity_msat);
@@ -637,8 +651,8 @@ impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiqui
637651
if amount_msat - min_liquidity_msat < denominator / PRECISION_LOWER_BOUND_DENOMINATOR {
638652
// If the failure probability is < 1.5625% (as 1 - numerator/denominator < 1/64),
639653
// don't bother trying to use the log approximation as it gets too noisy to be
640-
// particularly helpful, instead just round down to 0 and return the base penalty.
641-
params.base_penalty_msat
654+
// particularly helpful, instead just round down to 0.
655+
0
642656
} else {
643657
let negative_log10_times_2048 =
644658
approx::negative_log10_times_2048(numerator, denominator);
@@ -663,9 +677,7 @@ impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiqui
663677
.saturating_mul(params.amount_penalty_multiplier_msat)
664678
.saturating_mul(amount_msat) / 2048 / AMOUNT_PENALTY_DIVISOR;
665679

666-
params.base_penalty_msat
667-
.saturating_add(liquidity_penalty_msat)
668-
.saturating_add(amount_penalty_msat)
680+
liquidity_penalty_msat.saturating_add(amount_penalty_msat)
669681
}
670682

671683
/// Returns the lower bound of the channel liquidity balance in this direction.
@@ -747,13 +759,17 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
747759
return *penalty;
748760
}
749761

762+
let base_penalty_msat = self.params.base_penalty_msat.saturating_add(
763+
self.params.base_penalty_amount_multiplier_msat
764+
.saturating_mul(usage.amount_msat) / BASE_AMOUNT_PENALTY_DIVISOR);
765+
750766
let mut anti_probing_penalty_msat = 0;
751767
match usage.effective_capacity {
752768
EffectiveCapacity::ExactLiquidity { liquidity_msat } => {
753769
if usage.amount_msat > liquidity_msat {
754770
return u64::max_value();
755771
} else {
756-
return self.params.base_penalty_msat;
772+
return base_penalty_msat;
757773
}
758774
},
759775
EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat: Some(htlc_maximum_msat) } => {
@@ -774,6 +790,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
774790
.as_directed(source, target, capacity_msat, liquidity_offset_half_life)
775791
.penalty_msat(amount_msat, &self.params)
776792
.saturating_add(anti_probing_penalty_msat)
793+
.saturating_add(base_penalty_msat)
777794
}
778795

779796
fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
@@ -2048,47 +2065,47 @@ mod tests {
20482065
inflight_htlc_msat: 0,
20492066
effective_capacity: EffectiveCapacity::Total { capacity_msat: 950_000_000, htlc_maximum_msat: Some(1_000) },
20502067
};
2051-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 3613);
2068+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 4375);
20522069
let usage = ChannelUsage {
20532070
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20542071
};
2055-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1977);
2072+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2739);
20562073
let usage = ChannelUsage {
20572074
effective_capacity: EffectiveCapacity::Total { capacity_msat: 2_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20582075
};
2059-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1474);
2076+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2236);
20602077
let usage = ChannelUsage {
20612078
effective_capacity: EffectiveCapacity::Total { capacity_msat: 3_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20622079
};
2063-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1223);
2080+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1985);
20642081
let usage = ChannelUsage {
20652082
effective_capacity: EffectiveCapacity::Total { capacity_msat: 4_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20662083
};
2067-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 877);
2084+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1639);
20682085
let usage = ChannelUsage {
20692086
effective_capacity: EffectiveCapacity::Total { capacity_msat: 5_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20702087
};
2071-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 845);
2088+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1607);
20722089
let usage = ChannelUsage {
20732090
effective_capacity: EffectiveCapacity::Total { capacity_msat: 6_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20742091
};
2075-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2092+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
20762093
let usage = ChannelUsage {
20772094
effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_450_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20782095
};
2079-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2096+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
20802097
let usage = ChannelUsage {
20812098
effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20822099
};
2083-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2100+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
20842101
let usage = ChannelUsage {
20852102
effective_capacity: EffectiveCapacity::Total { capacity_msat: 8_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20862103
};
2087-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2104+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
20882105
let usage = ChannelUsage {
20892106
effective_capacity: EffectiveCapacity::Total { capacity_msat: 9_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20902107
};
2091-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2108+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
20922109
}
20932110

20942111
#[test]
@@ -2116,6 +2133,15 @@ mod tests {
21162133
};
21172134
let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
21182135
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 558);
2136+
2137+
let params = ProbabilisticScoringParameters {
2138+
base_penalty_msat: 500, liquidity_penalty_multiplier_msat: 1_000,
2139+
base_penalty_amount_multiplier_msat: (1<<30),
2140+
anti_probing_penalty_msat: 0, ..Default::default()
2141+
};
2142+
2143+
let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
2144+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 558 + 128);
21192145
}
21202146

21212147
#[test]

0 commit comments

Comments
 (0)