Skip to content

Commit e5874fe

Browse files
committed
Default to ProbabilisticScorer with a base penalty
ProbabilisticScorer tends to prefer longer routes to shorter ones. Make the default scoring behavior include a customizable base penalty to avoid longer routes. A new DefaultScorer struct is used such that the default implementation could vary without requiring users to explicitly upgrade.
1 parent b4b0c09 commit e5874fe

File tree

1 file changed

+123
-12
lines changed

1 file changed

+123
-12
lines changed

lightning/src/routing/scoring.rs

Lines changed: 123 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99

1010
//! Utilities for scoring payment channels.
1111
//!
12-
//! [`ProbabilisticScorer`] may be given to [`find_route`] to score payment channels during path
13-
//! finding when a custom [`Score`] implementation is not needed.
12+
//! [`DefaultScorer`] may be given to [`find_route`] to score payment channels during path finding
13+
//! when a custom [`Score`] implementation is not needed.
1414
//!
1515
//! # Example
1616
//!
@@ -19,7 +19,7 @@
1919
//! #
2020
//! # use lightning::routing::network_graph::NetworkGraph;
2121
//! # use lightning::routing::router::{RouteParameters, find_route};
22-
//! # use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters, Scorer, ScoringParameters};
22+
//! # use lightning::routing::scoring::{DefaultScorer, DefaultScoringParameters, ProbabilisticScoringParameters};
2323
//! # use lightning::chain::keysinterface::{KeysManager, KeysInterface};
2424
//! # use lightning::util::logger::{Logger, Record};
2525
//! # use secp256k1::key::PublicKey;
@@ -32,15 +32,18 @@
3232
//! # let logger = FakeLogger {};
3333
//! #
3434
//! // Use the default channel penalties.
35-
//! let params = ProbabilisticScoringParameters::default();
36-
//! let scorer = ProbabilisticScorer::new(params, &network_graph);
35+
//! let params = DefaultScoringParameters::default();
36+
//! let scorer = DefaultScorer::new(params, &network_graph);
3737
//!
3838
//! // Or use custom channel penalties.
39-
//! let params = ProbabilisticScoringParameters {
40-
//! liquidity_penalty_multiplier_msat: 2 * 1000,
41-
//! ..ProbabilisticScoringParameters::default()
39+
//! let params = DefaultScoringParameters {
40+
//! base_penalty_msat: 1000,
41+
//! probabilistic_params: ProbabilisticScoringParameters {
42+
//! liquidity_penalty_multiplier_msat: 2 * 1000,
43+
//! ..Default::default()
44+
//! },
4245
//! };
43-
//! let scorer = ProbabilisticScorer::new(params, &network_graph);
46+
//! let scorer = DefaultScorer::new(params, &network_graph);
4447
//! # let random_seed_bytes = [42u8; 32];
4548
//!
4649
//! let route = find_route(&payer, &route_params, &network_graph, None, &logger, &scorer, &random_seed_bytes);
@@ -191,6 +194,93 @@ impl<'a, S: Writeable> Writeable for MutexGuard<'a, S> {
191194
}
192195
}
193196

197+
/// [`Score`] implementation providing reasonable default behavior.
198+
pub struct DefaultScorer<G: Deref<Target = NetworkGraph>> {
199+
base_penalty_scorer: FixedPenaltyScorer,
200+
probabilistic_scorer: ProbabilisticScorer<G>,
201+
}
202+
203+
/// Parameters for configuring [`DefaultScorer`].
204+
pub struct DefaultScoringParameters {
205+
/// A fixed penalty in msats to apply to each channel.
206+
///
207+
/// Default value: 500 msat
208+
pub base_penalty_msat: u64,
209+
210+
/// Parameters for calculating a penalty for routing a payment through a channel using a
211+
/// probabilistic model of success.
212+
pub probabilistic_params: ProbabilisticScoringParameters,
213+
}
214+
215+
impl<G: Deref<Target = NetworkGraph>> DefaultScorer<G> {
216+
/// Creates a new scorer using the given scoring parameters for sending payments from a node
217+
/// through a network graph.
218+
pub fn new(params: DefaultScoringParameters, network_graph: G) -> Self {
219+
Self {
220+
base_penalty_scorer: FixedPenaltyScorer::with_penalty(params.base_penalty_msat),
221+
probabilistic_scorer:
222+
ProbabilisticScorer::new(params.probabilistic_params, network_graph),
223+
}
224+
}
225+
}
226+
227+
impl Default for DefaultScoringParameters {
228+
fn default() -> Self {
229+
Self {
230+
base_penalty_msat: 500,
231+
probabilistic_params: Default::default(),
232+
}
233+
}
234+
}
235+
236+
impl<G: Deref<Target = NetworkGraph>> Score for DefaultScorer<G> {
237+
fn channel_penalty_msat(
238+
&self, short_channel_id: u64, amount_msat: u64, capacity_msat: u64, source: &NodeId,
239+
target: &NodeId
240+
) -> u64 {
241+
let base_penalty_msat = self.base_penalty_scorer.channel_penalty_msat(
242+
short_channel_id, amount_msat, capacity_msat, source, target
243+
);
244+
let probabilistic_penalty_msat = self.probabilistic_scorer.channel_penalty_msat(
245+
short_channel_id, amount_msat, capacity_msat, source, target
246+
);
247+
base_penalty_msat.saturating_add(probabilistic_penalty_msat)
248+
}
249+
250+
fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
251+
self.base_penalty_scorer.payment_path_failed(path, short_channel_id);
252+
self.probabilistic_scorer.payment_path_failed(path, short_channel_id);
253+
}
254+
255+
fn payment_path_successful(&mut self, path: &[&RouteHop]) {
256+
self.base_penalty_scorer.payment_path_successful(path);
257+
self.probabilistic_scorer.payment_path_successful(path);
258+
}
259+
}
260+
261+
impl<G: Deref<Target = NetworkGraph>> Writeable for DefaultScorer<G> {
262+
#[inline]
263+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
264+
self.base_penalty_scorer.write(w)?;
265+
self.probabilistic_scorer.write(w)
266+
}
267+
}
268+
269+
impl<G> ReadableArgs<(DefaultScoringParameters, G)> for DefaultScorer<G>
270+
where
271+
G: Deref<Target = NetworkGraph>,
272+
{
273+
#[inline]
274+
fn read<R: Read>(r: &mut R, args: (DefaultScoringParameters, G)) -> Result<Self, DecodeError> {
275+
let (params, network_graph) = args;
276+
Ok(Self {
277+
base_penalty_scorer: ReadableArgs::read(r, params.base_penalty_msat)?,
278+
probabilistic_scorer:
279+
ReadableArgs::read(r, (params.probabilistic_params, network_graph))?,
280+
})
281+
}
282+
}
283+
194284
#[derive(Clone)]
195285
/// [`Score`] implementation that uses a fixed penalty.
196286
pub struct FixedPenaltyScorer {
@@ -235,7 +325,7 @@ impl ReadableArgs<u64> for FixedPenaltyScorer {
235325
/// Used to apply a fixed penalty to each channel, thus avoiding long paths when shorter paths with
236326
/// slightly higher fees are available. Will further penalize channels that fail to relay payments.
237327
///
238-
/// See [module-level documentation] for usage and [`ScoringParameters`] for customization.
328+
/// See [`ScoringParameters`] for customization.
239329
///
240330
/// # Note
241331
///
@@ -245,7 +335,7 @@ impl ReadableArgs<u64> for FixedPenaltyScorer {
245335
/// [module-level documentation]: crate::routing::scoring
246336
#[deprecated(
247337
since = "0.0.105",
248-
note = "ProbabilisticScorer should be used instead of Scorer.",
338+
note = "DefaultScorer should be used instead of Scorer.",
249339
)]
250340
pub type Scorer = ScorerUsingTime::<ConfiguredTime>;
251341

@@ -1100,7 +1190,7 @@ pub(crate) use self::time::Time;
11001190

11011191
#[cfg(test)]
11021192
mod tests {
1103-
use super::{ChannelLiquidity, ProbabilisticScoringCostFunction, ProbabilisticScoringParameters, ProbabilisticScorerUsingTime, ScoringParameters, ScorerUsingTime, Time};
1193+
use super::{ChannelLiquidity, DefaultScorer, DefaultScoringParameters, ProbabilisticScoringCostFunction, ProbabilisticScoringParameters, ProbabilisticScorerUsingTime, ScoringParameters, ScorerUsingTime, Time};
11041194
use super::time::Eternity;
11051195

11061196
use ln::features::{ChannelFeatures, NodeFeatures};
@@ -1187,6 +1277,27 @@ mod tests {
11871277
assert_eq!(later - elapsed, now);
11881278
}
11891279

1280+
// `DefaultScorer` tests
1281+
1282+
#[test]
1283+
fn adds_base_penalty_to_scorer_penalty() {
1284+
let network_graph = network_graph();
1285+
let source = source_node_id();
1286+
let target = target_node_id();
1287+
1288+
let params = DefaultScoringParameters {
1289+
base_penalty_msat: 0, ..Default::default()
1290+
};
1291+
let scorer = DefaultScorer::new(params, &network_graph);
1292+
assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 585);
1293+
1294+
let params = DefaultScoringParameters {
1295+
base_penalty_msat: 500, ..Default::default()
1296+
};
1297+
let scorer = DefaultScorer::new(params, &network_graph);
1298+
assert_eq!(scorer.channel_penalty_msat(42, 128, 1_024, &source, &target), 1085);
1299+
}
1300+
11901301
// `Scorer` tests
11911302

11921303
/// A scorer for testing with time that can be manually advanced.

0 commit comments

Comments
 (0)