Skip to content

Commit 8a5cef0

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 fa1ba8a commit 8a5cef0

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
///
@@ -536,6 +547,7 @@ impl ProbabilisticScoringParameters {
536547
fn zero_penalty() -> Self {
537548
Self {
538549
base_penalty_msat: 0,
550+
base_penalty_amount_multiplier_msat: 0,
539551
liquidity_penalty_multiplier_msat: 0,
540552
liquidity_offset_half_life: Duration::from_secs(3600),
541553
amount_penalty_multiplier_msat: 0,
@@ -558,6 +570,7 @@ impl Default for ProbabilisticScoringParameters {
558570
fn default() -> Self {
559571
Self {
560572
base_penalty_msat: 500,
573+
base_penalty_amount_multiplier_msat: 8192,
561574
liquidity_penalty_multiplier_msat: 40_000,
562575
liquidity_offset_half_life: Duration::from_secs(3600),
563576
amount_penalty_multiplier_msat: 256,
@@ -631,10 +644,11 @@ const PRECISION_LOWER_BOUND_DENOMINATOR: u64 = approx::LOWER_BITS_BOUND;
631644

632645
/// The divisor used when computing the amount penalty.
633646
const AMOUNT_PENALTY_DIVISOR: u64 = 1 << 20;
647+
const BASE_AMOUNT_PENALTY_DIVISOR: u64 = 1 << 30;
634648

635649
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.
650+
/// Returns a liquidity penalty for routing the given HTLC `amount_msat` through the channel in
651+
/// this direction.
638652
fn penalty_msat(&self, amount_msat: u64, params: &ProbabilisticScoringParameters) -> u64 {
639653
let max_liquidity_msat = self.max_liquidity_msat();
640654
let min_liquidity_msat = core::cmp::min(self.min_liquidity_msat(), max_liquidity_msat);
@@ -653,8 +667,8 @@ impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiqui
653667
if amount_msat - min_liquidity_msat < denominator / PRECISION_LOWER_BOUND_DENOMINATOR {
654668
// If the failure probability is < 1.5625% (as 1 - numerator/denominator < 1/64),
655669
// 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
670+
// particularly helpful, instead just round down to 0.
671+
0
658672
} else {
659673
let negative_log10_times_2048 =
660674
approx::negative_log10_times_2048(numerator, denominator);
@@ -679,9 +693,7 @@ impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiqui
679693
.saturating_mul(params.amount_penalty_multiplier_msat)
680694
.saturating_mul(amount_msat) / 2048 / AMOUNT_PENALTY_DIVISOR;
681695

682-
params.base_penalty_msat
683-
.saturating_add(liquidity_penalty_msat)
684-
.saturating_add(amount_penalty_msat)
696+
liquidity_penalty_msat.saturating_add(amount_penalty_msat)
685697
}
686698

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

778+
let base_penalty_msat = self.params.base_penalty_msat.saturating_add(
779+
self.params.base_penalty_amount_multiplier_msat
780+
.saturating_mul(usage.amount_msat) / BASE_AMOUNT_PENALTY_DIVISOR);
781+
766782
let mut anti_probing_penalty_msat = 0;
767783
match usage.effective_capacity {
768784
EffectiveCapacity::ExactLiquidity { liquidity_msat } => {
769785
if usage.amount_msat > liquidity_msat {
770786
return u64::max_value();
771787
} else {
772-
return self.params.base_penalty_msat;
788+
return base_penalty_msat;
773789
}
774790
},
775791
EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat: Some(htlc_maximum_msat) } => {
@@ -790,6 +806,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
790806
.as_directed(source, target, capacity_msat, liquidity_offset_half_life)
791807
.penalty_msat(amount_msat, &self.params)
792808
.saturating_add(anti_probing_penalty_msat)
809+
.saturating_add(base_penalty_msat)
793810
}
794811

795812
fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
@@ -2069,47 +2086,47 @@ mod tests {
20692086
inflight_htlc_msat: 0,
20702087
effective_capacity: EffectiveCapacity::Total { capacity_msat: 950_000_000, htlc_maximum_msat: Some(1_000) },
20712088
};
2072-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 3613);
2089+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 4375);
20732090
let usage = ChannelUsage {
20742091
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20752092
};
2076-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1977);
2093+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2739);
20772094
let usage = ChannelUsage {
20782095
effective_capacity: EffectiveCapacity::Total { capacity_msat: 2_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20792096
};
2080-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1474);
2097+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2236);
20812098
let usage = ChannelUsage {
20822099
effective_capacity: EffectiveCapacity::Total { capacity_msat: 3_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20832100
};
2084-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1223);
2101+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1985);
20852102
let usage = ChannelUsage {
20862103
effective_capacity: EffectiveCapacity::Total { capacity_msat: 4_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20872104
};
2088-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 877);
2105+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1639);
20892106
let usage = ChannelUsage {
20902107
effective_capacity: EffectiveCapacity::Total { capacity_msat: 5_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20912108
};
2092-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 845);
2109+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1607);
20932110
let usage = ChannelUsage {
20942111
effective_capacity: EffectiveCapacity::Total { capacity_msat: 6_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20952112
};
2096-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2113+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
20972114
let usage = ChannelUsage {
20982115
effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_450_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
20992116
};
2100-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2117+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
21012118
let usage = ChannelUsage {
21022119
effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
21032120
};
2104-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2121+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
21052122
let usage = ChannelUsage {
21062123
effective_capacity: EffectiveCapacity::Total { capacity_msat: 8_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
21072124
};
2108-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2125+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
21092126
let usage = ChannelUsage {
21102127
effective_capacity: EffectiveCapacity::Total { capacity_msat: 9_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
21112128
};
2112-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
2129+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1262);
21132130
}
21142131

21152132
#[test]
@@ -2137,6 +2154,15 @@ mod tests {
21372154
};
21382155
let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
21392156
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 558);
2157+
2158+
let params = ProbabilisticScoringParameters {
2159+
base_penalty_msat: 500, liquidity_penalty_multiplier_msat: 1_000,
2160+
base_penalty_amount_multiplier_msat: (1<<30),
2161+
anti_probing_penalty_msat: 0, ..Default::default()
2162+
};
2163+
2164+
let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
2165+
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 558 + 128);
21402166
}
21412167

21422168
#[test]

0 commit comments

Comments
 (0)