Skip to content

Commit 9bec35d

Browse files
committed
Penalize large HTLCs relative to channels in default Scorer
Sending HTLCs which are any greater than a very small fraction of the channel size tend to fail at a much higher rate. Thus, by default we start applying a penalty at only 1/8th the channel size and increase it linearly as the amount reaches the channel's capacity, 20 msat per 1024th of the channel capacity.
1 parent 8dc7cfa commit 9bec35d

File tree

1 file changed

+74
-2
lines changed

1 file changed

+74
-2
lines changed

lightning/src/routing/scorer.rs

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,16 +98,37 @@ pub struct ScorerUsingTime<T: Time> {
9898
/// Parameters for configuring [`Scorer`].
9999
pub struct ScoringParameters {
100100
/// A fixed penalty in msats to apply to each channel.
101+
///
102+
/// Default value: 500 msat
101103
pub base_penalty_msat: u64,
102104

103105
/// A penalty in msats to apply to a channel upon failing to relay a payment.
104106
///
105107
/// This accumulates for each failure but may be reduced over time based on
106108
/// [`failure_penalty_half_life`].
107109
///
110+
/// Default value: 1,024,000 msat
111+
///
108112
/// [`failure_penalty_half_life`]: Self::failure_penalty_half_life
109113
pub failure_penalty_msat: u64,
110114

115+
/// When the amount being sent over a channel is this many 1024ths of the total channel
116+
/// capacity, we begin applying [`overuse_penalty_msat_per_1024th`].
117+
///
118+
/// Default value: 128 1024ths (i.e. begin penalizing when an HTLC uses 1/8th of a channel)
119+
///
120+
/// [`overuse_penalty_msat_per_1024th`]: Self::overuse_penalty_msat_per_1024th
121+
pub overuse_penalty_start_1024th: u16,
122+
123+
/// A penalty applied, per whole 1024ths of the channel capacity which the amount being sent
124+
/// over the channel exceeds [`overuse_penalty_start_1024th`] by.
125+
///
126+
/// Default value: 20 msat (i.e. 2560 msat penalty to use 1/4th of a channel, 7680 msat penalty
127+
/// to use half a channel, and 12,560 msat penalty to use 3/4ths of a channel)
128+
///
129+
/// [`overuse_penalty_start_1024th`]: Self::overuse_penalty_start_1024th
130+
pub overuse_penalty_msat_per_1024th: u64,
131+
111132
/// The time required to elapse before any accumulated [`failure_penalty_msat`] penalties are
112133
/// cut in half.
113134
///
@@ -122,7 +143,9 @@ pub struct ScoringParameters {
122143

123144
impl_writeable_tlv_based!(ScoringParameters, {
124145
(0, base_penalty_msat, required),
146+
(1, overuse_penalty_start_1024th, (default_value, 128)),
125147
(2, failure_penalty_msat, required),
148+
(3, overuse_penalty_msat_per_1024th, (default_value, 20)),
126149
(4, failure_penalty_half_life, required),
127150
});
128151

@@ -167,6 +190,8 @@ impl<T: Time> ScorerUsingTime<T> {
167190
base_penalty_msat: penalty_msat,
168191
failure_penalty_msat: 0,
169192
failure_penalty_half_life: Duration::from_secs(0),
193+
overuse_penalty_start_1024th: 1024,
194+
overuse_penalty_msat_per_1024th: 0,
170195
})
171196
}
172197
}
@@ -205,19 +230,34 @@ impl Default for ScoringParameters {
205230
base_penalty_msat: 500,
206231
failure_penalty_msat: 1024 * 1000,
207232
failure_penalty_half_life: Duration::from_secs(3600),
233+
overuse_penalty_start_1024th: 1024 / 8,
234+
overuse_penalty_msat_per_1024th: 20,
208235
}
209236
}
210237
}
211238

212239
impl<T: Time> routing::Score for ScorerUsingTime<T> {
213240
fn channel_penalty_msat(
214-
&self, short_channel_id: u64, _send_amt_msat: u64, _chan_capacity_msat: Option<u64>, _source: &NodeId, _target: &NodeId
241+
&self, short_channel_id: u64, send_amt_msat: u64, chan_capacity_opt: Option<u64>, _source: &NodeId, _target: &NodeId
215242
) -> u64 {
216243
let failure_penalty_msat = self.channel_failures
217244
.get(&short_channel_id)
218245
.map_or(0, |value| value.decayed_penalty_msat(self.params.failure_penalty_half_life));
219246

220-
self.params.base_penalty_msat + failure_penalty_msat
247+
let mut penalty_msat = self.params.base_penalty_msat + failure_penalty_msat;
248+
249+
if let Some(chan_capacity_msat) = chan_capacity_opt {
250+
let send_1024ths = send_amt_msat.checked_mul(1024).unwrap_or(u64::max_value()) / chan_capacity_msat;
251+
252+
if send_1024ths > self.params.overuse_penalty_start_1024th as u64 {
253+
penalty_msat = penalty_msat.checked_add(
254+
(send_1024ths - self.params.overuse_penalty_start_1024th as u64)
255+
.checked_mul(self.params.overuse_penalty_msat_per_1024th).unwrap_or(u64::max_value()))
256+
.unwrap_or(u64::max_value());
257+
}
258+
}
259+
260+
penalty_msat
221261
}
222262

223263
fn payment_path_failed(&mut self, _path: &[&RouteHop], short_channel_id: u64) {
@@ -414,6 +454,8 @@ mod tests {
414454
base_penalty_msat: 1_000,
415455
failure_penalty_msat: 512,
416456
failure_penalty_half_life: Duration::from_secs(1),
457+
overuse_penalty_start_1024th: 1024,
458+
overuse_penalty_msat_per_1024th: 0,
417459
});
418460
let source = source_node_id();
419461
let target = target_node_id();
@@ -429,6 +471,8 @@ mod tests {
429471
base_penalty_msat: 1_000,
430472
failure_penalty_msat: 64,
431473
failure_penalty_half_life: Duration::from_secs(10),
474+
overuse_penalty_start_1024th: 1024,
475+
overuse_penalty_msat_per_1024th: 0,
432476
});
433477
let source = source_node_id();
434478
let target = target_node_id();
@@ -450,6 +494,8 @@ mod tests {
450494
base_penalty_msat: 1_000,
451495
failure_penalty_msat: 512,
452496
failure_penalty_half_life: Duration::from_secs(10),
497+
overuse_penalty_start_1024th: 1024,
498+
overuse_penalty_msat_per_1024th: 0,
453499
});
454500
let source = source_node_id();
455501
let target = target_node_id();
@@ -480,6 +526,8 @@ mod tests {
480526
base_penalty_msat: 1_000,
481527
failure_penalty_msat: 512,
482528
failure_penalty_half_life: Duration::from_secs(10),
529+
overuse_penalty_start_1024th: 1024,
530+
overuse_penalty_msat_per_1024th: 0,
483531
});
484532
let source = source_node_id();
485533
let target = target_node_id();
@@ -504,6 +552,8 @@ mod tests {
504552
base_penalty_msat: 1_000,
505553
failure_penalty_msat: 512,
506554
failure_penalty_half_life: Duration::from_secs(10),
555+
overuse_penalty_start_1024th: 1024,
556+
overuse_penalty_msat_per_1024th: 0,
507557
});
508558
let source = source_node_id();
509559
let target = target_node_id();
@@ -531,6 +581,8 @@ mod tests {
531581
base_penalty_msat: 1_000,
532582
failure_penalty_msat: 512,
533583
failure_penalty_half_life: Duration::from_secs(10),
584+
overuse_penalty_start_1024th: 1024,
585+
overuse_penalty_msat_per_1024th: 0,
534586
});
535587
let source = source_node_id();
536588
let target = target_node_id();
@@ -549,4 +601,24 @@ mod tests {
549601
SinceEpoch::advance(Duration::from_secs(10));
550602
assert_eq!(deserialized_scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_128);
551603
}
604+
605+
#[test]
606+
fn charges_per_1024th_penalty() {
607+
let scorer = Scorer::new(ScoringParameters {
608+
base_penalty_msat: 0,
609+
failure_penalty_msat: 0,
610+
failure_penalty_half_life: Duration::from_secs(0),
611+
overuse_penalty_start_1024th: 256,
612+
overuse_penalty_msat_per_1024th: 100,
613+
});
614+
let source = source_node_id();
615+
let target = target_node_id();
616+
617+
assert_eq!(scorer.channel_penalty_msat(42, 1_000, None, &source, &target), 0);
618+
assert_eq!(scorer.channel_penalty_msat(42, 1_000, Some(1_024_000), &source, &target), 0);
619+
assert_eq!(scorer.channel_penalty_msat(42, 256_999, Some(1_024_000), &source, &target), 0);
620+
assert_eq!(scorer.channel_penalty_msat(42, 257_000, Some(1_024_000), &source, &target), 100);
621+
assert_eq!(scorer.channel_penalty_msat(42, 258_000, Some(1_024_000), &source, &target), 200);
622+
assert_eq!(scorer.channel_penalty_msat(42, 512_000, Some(1_024_000), &source, &target), 256 * 100);
623+
}
552624
}

0 commit comments

Comments
 (0)