Skip to content

Commit 6452cc1

Browse files
committed
Option for including an amount penalty
TODO: fill in with details
1 parent 521a72b commit 6452cc1

File tree

1 file changed

+70
-10
lines changed

1 file changed

+70
-10
lines changed

lightning/src/routing/scoring.rs

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,12 @@ pub struct ProbabilisticScoringParameters {
555555
/// When built with the `no-std` feature, time will never elapse. Therefore, the channel
556556
/// liquidity knowledge will never decay except when the bounds cross.
557557
pub liquidity_offset_half_life: Duration,
558+
559+
/// Whether an additional penalty should be calculated based on the payment amount in order to
560+
/// provide higher penalties for large payments.
561+
///
562+
/// Default value: false
563+
pub include_amount_penalty: bool,
558564
}
559565

560566
/// Accounting for channel liquidity balance uncertainty.
@@ -608,6 +614,7 @@ impl Default for ProbabilisticScoringParameters {
608614
base_penalty_msat: 500,
609615
liquidity_penalty_multiplier_msat: 40_000,
610616
liquidity_offset_half_life: Duration::from_secs(3600),
617+
include_amount_penalty: false,
611618
}
612619
}
613620
}
@@ -665,11 +672,17 @@ impl<T: Time> ChannelLiquidity<T> {
665672
}
666673
}
667674

675+
/// Bounds `-log10` to avoid excessive liquidity penalties for payments with low success
676+
/// probabilities.
677+
const NEGATIVE_LOG10_UPPER_BOUND: u64 = 2;
678+
679+
/// The divisor used when computing the amount penalty.
680+
const AMOUNT_PENALTY_DIVISOR: u64 = 1024;
681+
668682
impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiquidity<L, T, U> {
669683
/// Returns a penalty for routing the given HTLC `amount_msat` through the channel in this
670684
/// direction.
671-
fn penalty_msat(&self, amount_msat: u64, liquidity_penalty_multiplier_msat: u64) -> u64 {
672-
let max_penalty_msat = liquidity_penalty_multiplier_msat.saturating_mul(2);
685+
fn penalty_msat(&self, amount_msat: u64, params: ProbabilisticScoringParameters) -> u64 {
673686
let max_liquidity_msat = self.max_liquidity_msat();
674687
let min_liquidity_msat = core::cmp::min(self.min_liquidity_msat(), max_liquidity_msat);
675688
if amount_msat <= min_liquidity_msat {
@@ -681,15 +694,36 @@ impl<L: Deref<Target = u64>, T: Time, U: Deref<Target = T>> DirectedChannelLiqui
681694
// Avoid using the failed channel on retry.
682695
u64::max_value()
683696
} else {
684-
max_penalty_msat
697+
let negative_log10_times_1024 = NEGATIVE_LOG10_UPPER_BOUND * 1024;
698+
self.combined_penalty_msat(amount_msat, negative_log10_times_1024, params)
685699
}
686700
} else {
687701
let numerator = (max_liquidity_msat - amount_msat).saturating_add(1);
688702
let denominator = (max_liquidity_msat - min_liquidity_msat).saturating_add(1);
689-
let penalty_msat = approx::negative_log10_times_1024(numerator, denominator)
690-
.saturating_mul(liquidity_penalty_multiplier_msat) / 1024;
691-
// Upper bound the penalty to ensure some channel is selected.
692-
penalty_msat.min(max_penalty_msat)
703+
let negative_log10_times_1024 =
704+
approx::negative_log10_times_1024(numerator, denominator);
705+
self.combined_penalty_msat(amount_msat, negative_log10_times_1024, params)
706+
}
707+
}
708+
709+
#[inline]
710+
fn combined_penalty_msat(
711+
&self, amount_msat: u64, negative_log10_times_1024: u64,
712+
params: ProbabilisticScoringParameters
713+
) -> u64 {
714+
// Upper bound the liquidity penalty to ensure some channel is selected.
715+
let multiplier_msat = params.liquidity_penalty_multiplier_msat;
716+
let max_penalty_msat = multiplier_msat.saturating_mul(NEGATIVE_LOG10_UPPER_BOUND);
717+
let penalty_msat = (negative_log10_times_1024.saturating_mul(multiplier_msat) / 1024)
718+
.min(max_penalty_msat)
719+
.saturating_add(params.base_penalty_msat);
720+
721+
if params.include_amount_penalty {
722+
let amount_penalty = negative_log10_times_1024.saturating_mul(amount_msat) / 1024
723+
/ AMOUNT_PENALTY_DIVISOR;
724+
penalty_msat.saturating_add(amount_penalty)
725+
} else {
726+
penalty_msat
693727
}
694728
}
695729

@@ -762,14 +796,12 @@ impl<G: Deref<Target = NetworkGraph>, T: Time> Score for ProbabilisticScorerUsin
762796
&self, short_channel_id: u64, amount_msat: u64, capacity_msat: u64, source: &NodeId,
763797
target: &NodeId
764798
) -> u64 {
765-
let liquidity_penalty_multiplier_msat = self.params.liquidity_penalty_multiplier_msat;
766799
let liquidity_offset_half_life = self.params.liquidity_offset_half_life;
767800
self.channel_liquidities
768801
.get(&short_channel_id)
769802
.unwrap_or(&ChannelLiquidity::new())
770803
.as_directed(source, target, capacity_msat, liquidity_offset_half_life)
771-
.penalty_msat(amount_msat, liquidity_penalty_multiplier_msat)
772-
.saturating_add(self.params.base_penalty_msat)
804+
.penalty_msat(amount_msat, self.params)
773805
}
774806

775807
fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
@@ -1884,6 +1916,7 @@ mod tests {
18841916
base_penalty_msat: 0,
18851917
liquidity_penalty_multiplier_msat: 1_000,
18861918
liquidity_offset_half_life: Duration::from_secs(10),
1919+
..Default::default()
18871920
};
18881921
let mut scorer = ProbabilisticScorer::new(params, &network_graph);
18891922
let source = source_node_id();
@@ -1936,6 +1969,7 @@ mod tests {
19361969
base_penalty_msat: 0,
19371970
liquidity_penalty_multiplier_msat: 1_000,
19381971
liquidity_offset_half_life: Duration::from_secs(10),
1972+
..Default::default()
19391973
};
19401974
let mut scorer = ProbabilisticScorer::new(params, &network_graph);
19411975
let source = source_node_id();
@@ -1961,6 +1995,7 @@ mod tests {
19611995
base_penalty_msat: 0,
19621996
liquidity_penalty_multiplier_msat: 1_000,
19631997
liquidity_offset_half_life: Duration::from_secs(10),
1998+
..Default::default()
19641999
};
19652000
let mut scorer = ProbabilisticScorer::new(params, &network_graph);
19662001
let source = source_node_id();
@@ -1999,6 +2034,7 @@ mod tests {
19992034
base_penalty_msat: 0,
20002035
liquidity_penalty_multiplier_msat: 1_000,
20012036
liquidity_offset_half_life: Duration::from_secs(10),
2037+
..Default::default()
20022038
};
20032039
let mut scorer = ProbabilisticScorer::new(params, &network_graph);
20042040
let source = source_node_id();
@@ -2029,6 +2065,7 @@ mod tests {
20292065
base_penalty_msat: 0,
20302066
liquidity_penalty_multiplier_msat: 1_000,
20312067
liquidity_offset_half_life: Duration::from_secs(10),
2068+
..Default::default()
20322069
};
20332070
let mut scorer = ProbabilisticScorer::new(params, &network_graph);
20342071
let source = source_node_id();
@@ -2073,6 +2110,29 @@ mod tests {
20732110
assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 558);
20742111
}
20752112

2113+
#[test]
2114+
fn adds_amount_penalty_to_liquidity_penalty() {
2115+
let network_graph = network_graph();
2116+
let source = source_node_id();
2117+
let target = target_node_id();
2118+
2119+
let params = ProbabilisticScoringParameters {
2120+
liquidity_penalty_multiplier_msat: 1_000,
2121+
include_amount_penalty: false,
2122+
..Default::default()
2123+
};
2124+
let scorer = ProbabilisticScorer::new(params, &network_graph);
2125+
assert_eq!(scorer.channel_penalty_msat(42, 512_000, 1_024_000, &source, &target), 800);
2126+
2127+
let params = ProbabilisticScoringParameters {
2128+
liquidity_penalty_multiplier_msat: 1_000,
2129+
include_amount_penalty: true,
2130+
..Default::default()
2131+
};
2132+
let scorer = ProbabilisticScorer::new(params, &network_graph);
2133+
assert_eq!(scorer.channel_penalty_msat(42, 512_000, 1_024_000, &source, &target), 950);
2134+
}
2135+
20762136
#[test]
20772137
fn calculates_log10_without_overflowing_u64_max_value() {
20782138
let network_graph = network_graph();

0 commit comments

Comments
 (0)