Skip to content

Commit 245f93a

Browse files
committed
Refactor channel failure penalty logic
Move channel failure penalty logic into a ChannelFailure abstraction. This encapsulates the logic for accumulating penalties and decaying them over time. It also is responsible for the no-std behavior. This cleans up Scorer and will make it easier to serialize it.
1 parent db05a14 commit 245f93a

File tree

1 file changed

+50
-43
lines changed

1 file changed

+50
-43
lines changed

lightning/src/routing/scorer.rs

Lines changed: 50 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ use routing::network_graph::NodeId;
5252
use routing::router::RouteHop;
5353

5454
use prelude::*;
55-
#[cfg(not(feature = "no-std"))]
5655
use core::time::Duration;
5756
#[cfg(not(feature = "no-std"))]
5857
use std::time::Instant;
@@ -67,10 +66,7 @@ use std::time::Instant;
6766
/// [module-level documentation]: crate::routing::scorer
6867
pub struct Scorer {
6968
params: ScoringParameters,
70-
#[cfg(not(feature = "no-std"))]
71-
channel_failures: HashMap<u64, (u64, Instant)>,
72-
#[cfg(feature = "no-std")]
73-
channel_failures: HashMap<u64, u64>,
69+
channel_failures: HashMap<u64, ChannelFailure>,
7470
}
7571

7672
/// Parameters for configuring [`Scorer`].
@@ -86,10 +82,21 @@ pub struct ScoringParameters {
8682
pub failure_penalty_msat: u64,
8783

8884
/// The time needed before any accumulated channel failure penalties are cut in half.
89-
#[cfg(not(feature = "no-std"))]
9085
pub failure_penalty_half_life: Duration,
9186
}
9287

88+
/// Accounting for penalties from channel failures.
89+
///
90+
/// Penalties decay over time, though accumulated as more failures occur.
91+
struct ChannelFailure {
92+
/// Accumulated penalty in msats for the channel as of `last_failed`.
93+
undecayed_penalty_msat: u64,
94+
95+
/// Last time the channel failed. Used to decay `undecayed_penalty_msat`.
96+
#[cfg(not(feature = "no-std"))]
97+
last_failed: Instant,
98+
}
99+
93100
impl Scorer {
94101
/// Creates a new scorer using the given scoring parameters.
95102
pub fn new(params: ScoringParameters) -> Self {
@@ -105,14 +112,41 @@ impl Scorer {
105112
Self::new(ScoringParameters {
106113
base_penalty_msat: penalty_msat,
107114
failure_penalty_msat: 0,
108-
#[cfg(not(feature = "no-std"))]
109115
failure_penalty_half_life: Duration::from_secs(0),
110116
})
111117
}
118+
}
119+
120+
impl ChannelFailure {
121+
fn new(failure_penalty_msat: u64) -> Self {
122+
Self {
123+
undecayed_penalty_msat: failure_penalty_msat,
124+
#[cfg(not(feature = "no-std"))]
125+
last_failed: Instant::now(),
126+
}
127+
}
112128

113-
#[cfg(not(feature = "no-std"))]
114-
fn decay_from(&self, penalty_msat: u64, last_failure: &Instant) -> u64 {
115-
decay_from(penalty_msat, last_failure, self.params.failure_penalty_half_life)
129+
fn add_penalty(&mut self, failure_penalty_msat: u64, half_life: Duration) {
130+
self.undecayed_penalty_msat = self.decayed_penalty(half_life) + failure_penalty_msat;
131+
#[cfg(not(feature = "no-std"))]
132+
{
133+
self.last_failed = Instant::now();
134+
}
135+
}
136+
137+
fn decayed_penalty(&self, half_life: Duration) -> u64 {
138+
let decays = self.elapsed().as_secs().checked_div(half_life.as_secs());
139+
match decays {
140+
Some(decays) => self.undecayed_penalty_msat >> decays,
141+
None => 0,
142+
}
143+
}
144+
145+
fn elapsed(&self) -> Duration {
146+
#[cfg(not(feature = "no-std"))]
147+
return self.last_failed.elapsed();
148+
#[cfg(feature = "no-std")]
149+
return Duration::from_secs(0);
116150
}
117151
}
118152

@@ -127,7 +161,6 @@ impl Default for ScoringParameters {
127161
Self {
128162
base_penalty_msat: 500,
129163
failure_penalty_msat: 1024 * 1000,
130-
#[cfg(not(feature = "no-std"))]
131164
failure_penalty_half_life: Duration::from_secs(3600),
132165
}
133166
}
@@ -137,45 +170,19 @@ impl routing::Score for Scorer {
137170
fn channel_penalty_msat(
138171
&self, short_channel_id: u64, _source: &NodeId, _target: &NodeId
139172
) -> u64 {
140-
#[cfg(not(feature = "no-std"))]
141-
let failure_penalty_msat = match self.channel_failures.get(&short_channel_id) {
142-
Some((penalty_msat, last_failure)) => self.decay_from(*penalty_msat, last_failure),
143-
None => 0,
144-
};
145-
#[cfg(feature = "no-std")]
146-
let failure_penalty_msat =
147-
self.channel_failures.get(&short_channel_id).copied().unwrap_or(0);
173+
let failure_penalty_msat = self.channel_failures
174+
.get(&short_channel_id)
175+
.map_or(0,|failure| failure.decayed_penalty(self.params.failure_penalty_half_life));
148176

149177
self.params.base_penalty_msat + failure_penalty_msat
150178
}
151179

152180
fn payment_path_failed(&mut self, _path: &Vec<RouteHop>, short_channel_id: u64) {
153181
let failure_penalty_msat = self.params.failure_penalty_msat;
154-
#[cfg(not(feature = "no-std"))]
155-
{
156-
let half_life = self.params.failure_penalty_half_life;
157-
self.channel_failures
158-
.entry(short_channel_id)
159-
.and_modify(|(penalty_msat, last_failure)| {
160-
let decayed_penalty = decay_from(*penalty_msat, last_failure, half_life);
161-
*penalty_msat = decayed_penalty + failure_penalty_msat;
162-
*last_failure = Instant::now();
163-
})
164-
.or_insert_with(|| (failure_penalty_msat, Instant::now()));
165-
}
166-
#[cfg(feature = "no-std")]
182+
let half_life = self.params.failure_penalty_half_life;
167183
self.channel_failures
168184
.entry(short_channel_id)
169-
.and_modify(|penalty_msat| *penalty_msat += failure_penalty_msat)
170-
.or_insert(failure_penalty_msat);
171-
}
172-
}
173-
174-
#[cfg(not(feature = "no-std"))]
175-
fn decay_from(penalty_msat: u64, last_failure: &Instant, half_life: Duration) -> u64 {
176-
let decays = last_failure.elapsed().as_secs().checked_div(half_life.as_secs());
177-
match decays {
178-
Some(decays) => penalty_msat >> decays,
179-
None => 0,
185+
.and_modify(|failure| failure.add_penalty(failure_penalty_msat, half_life))
186+
.or_insert_with(|| ChannelFailure::new(failure_penalty_msat));
180187
}
181188
}

0 commit comments

Comments
 (0)