Skip to content

Commit bc516ff

Browse files
committed
Implement (de)serialization for Scorer
Scorer should be serialized to retain penalty data between restarts. Implement (de)serialization for Scorer by serializing last failure times as duration since the UNIX epoch. For no-std, the zero-Duration is used.
1 parent 600529b commit bc516ff

File tree

2 files changed

+87
-6
lines changed

2 files changed

+87
-6
lines changed

lightning/src/routing/scorer.rs

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,15 @@
4646
4747
use routing;
4848

49+
use ln::msgs::DecodeError;
4950
use routing::network_graph::NodeId;
5051
use routing::router::RouteHop;
52+
use util::ser::{Readable, Writeable, Writer};
5153

5254
use prelude::*;
55+
use core::ops::Sub;
5356
use core::time::Duration;
57+
use io::{self, Read};
5458

5559
/// [`routing::Score`] implementation that provides reasonable default behavior.
5660
///
@@ -60,7 +64,7 @@ use core::time::Duration;
6064
/// See [module-level documentation] for usage.
6165
///
6266
/// [module-level documentation]: crate::routing::scorer
63-
pub struct Scorer<C: Clock> {
67+
pub struct Scorer<C: Clock + Sub<Duration, Output = C>> {
6468
params: ScoringParameters,
6569
channel_failures: HashMap<u64, ChannelFailure<C>>,
6670
}
@@ -81,10 +85,16 @@ pub struct ScoringParameters {
8185
pub failure_penalty_half_life: Duration,
8286
}
8387

88+
impl_writeable_tlv_based!(ScoringParameters, {
89+
(0, base_penalty_msat, required),
90+
(2, failure_penalty_msat, required),
91+
(4, failure_penalty_half_life, required),
92+
});
93+
8494
/// Accounting for penalties from channel failures.
8595
///
8696
/// Penalties decay over time, though accumulated as more failures occur.
87-
struct ChannelFailure<C: Clock> {
97+
struct ChannelFailure<C: Clock + Sub<Duration, Output = C>> {
8898
/// Accumulated penalty in msats for the channel as of `last_failed`.
8999
undecayed_penalty_msat: u64,
90100

@@ -101,7 +111,7 @@ pub trait Clock {
101111
fn elapsed(&self) -> Duration;
102112
}
103113

104-
impl<C: Clock> Scorer<C> {
114+
impl<C: Clock + Sub<Duration, Output = C>> Scorer<C> {
105115
/// Creates a new scorer using the given scoring parameters.
106116
pub fn new(params: ScoringParameters) -> Self {
107117
Self {
@@ -121,7 +131,7 @@ impl<C: Clock> Scorer<C> {
121131
}
122132
}
123133

124-
impl<C: Clock> ChannelFailure<C> {
134+
impl<C: Clock + Sub<Duration, Output = C>> ChannelFailure<C> {
125135
fn new(failure_penalty_msat: u64) -> Self {
126136
Self {
127137
undecayed_penalty_msat: failure_penalty_msat,
@@ -143,7 +153,7 @@ impl<C: Clock> ChannelFailure<C> {
143153
}
144154
}
145155

146-
impl<C: Clock> Default for Scorer<C> {
156+
impl<C: Clock + Sub<Duration, Output = C>> Default for Scorer<C> {
147157
fn default() -> Self {
148158
Scorer::new(ScoringParameters::default())
149159
}
@@ -159,7 +169,7 @@ impl Default for ScoringParameters {
159169
}
160170
}
161171

162-
impl<C: Clock> routing::Score for Scorer<C> {
172+
impl<C: Clock + Sub<Duration, Output = C>> routing::Score for Scorer<C> {
163173
fn channel_penalty_msat(
164174
&self, short_channel_id: u64, _source: &NodeId, _target: &NodeId
165175
) -> u64 {
@@ -203,3 +213,57 @@ impl Clock for AlwaysPresent {
203213
Duration::from_secs(0)
204214
}
205215
}
216+
217+
impl Sub<Duration> for AlwaysPresent {
218+
type Output = Self;
219+
220+
fn sub(self, _other: Duration) -> Self {
221+
self
222+
}
223+
}
224+
225+
impl<C: Clock + Sub<Duration, Output = C>> Writeable for Scorer<C> {
226+
#[inline]
227+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
228+
self.params.write(w)?;
229+
self.channel_failures.write(w)
230+
}
231+
}
232+
233+
impl<C: Clock + Sub<Duration, Output = C>> Readable for Scorer<C> {
234+
#[inline]
235+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
236+
Ok(Scorer {
237+
params: Readable::read(r)?,
238+
channel_failures: Readable::read(r)?,
239+
})
240+
}
241+
}
242+
243+
impl<C: Clock + Sub<Duration, Output = C>> Writeable for ChannelFailure<C> {
244+
#[inline]
245+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
246+
self.undecayed_penalty_msat.write(w)?;
247+
(duration_since_epoch() - self.last_failed.elapsed()).write(w)
248+
}
249+
}
250+
251+
impl<C: Clock + Sub<Duration, Output = C>> Readable for ChannelFailure<C> {
252+
#[inline]
253+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
254+
Ok(ChannelFailure {
255+
undecayed_penalty_msat: Readable::read(r)?,
256+
last_failed: C::now() - (duration_since_epoch() - Readable::read(r)?),
257+
})
258+
}
259+
}
260+
261+
fn duration_since_epoch() -> Duration {
262+
#[cfg(not(feature = "no-std"))]
263+
{
264+
use std::time::SystemTime;
265+
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap()
266+
}
267+
#[cfg(feature = "no-std")]
268+
return Duration::from_secs(0);
269+
}

lightning/src/util/ser.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use bitcoin::consensus::Encodable;
2727
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
2828
use bitcoin::hash_types::{Txid, BlockHash};
2929
use core::marker::Sized;
30+
use core::time::Duration;
3031
use ln::msgs::DecodeError;
3132
use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
3233

@@ -911,3 +912,19 @@ impl Readable for String {
911912
Ok(ret)
912913
}
913914
}
915+
916+
impl Writeable for Duration {
917+
#[inline]
918+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
919+
self.as_secs().write(w)?;
920+
self.subsec_nanos().write(w)
921+
}
922+
}
923+
impl Readable for Duration {
924+
#[inline]
925+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
926+
let secs = Readable::read(r)?;
927+
let nanos = Readable::read(r)?;
928+
Ok(Duration::new(secs, nanos))
929+
}
930+
}

0 commit comments

Comments
 (0)