@@ -52,7 +52,6 @@ use routing::network_graph::NodeId;
52
52
use routing:: router:: RouteHop ;
53
53
54
54
use prelude:: * ;
55
- #[ cfg( not( feature = "no-std" ) ) ]
56
55
use core:: time:: Duration ;
57
56
#[ cfg( not( feature = "no-std" ) ) ]
58
57
use std:: time:: Instant ;
@@ -67,10 +66,8 @@ use std::time::Instant;
67
66
/// [module-level documentation]: crate::routing::scorer
68
67
pub struct Scorer {
69
68
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
+ // TODO: Remove entries of closed channels.
70
+ channel_failures : HashMap < u64 , ChannelFailure > ,
74
71
}
75
72
76
73
/// Parameters for configuring [`Scorer`].
@@ -86,10 +83,21 @@ pub struct ScoringParameters {
86
83
pub failure_penalty_msat : u64 ,
87
84
88
85
/// The time needed before any accumulated channel failure penalties are cut in half.
89
- #[ cfg( not( feature = "no-std" ) ) ]
90
86
pub failure_penalty_half_life : Duration ,
91
87
}
92
88
89
+ /// Accounting for penalties from channel failures.
90
+ ///
91
+ /// Penalties decay over time, though accumulate as more failures occur.
92
+ struct ChannelFailure {
93
+ /// Accumulated penalty in msats for the channel as of `last_failed`.
94
+ undecayed_penalty_msat : u64 ,
95
+
96
+ /// Last time the channel failed. Used to decay `undecayed_penalty_msat`.
97
+ #[ cfg( not( feature = "no-std" ) ) ]
98
+ last_failed : Instant ,
99
+ }
100
+
93
101
impl Scorer {
94
102
/// Creates a new scorer using the given scoring parameters.
95
103
pub fn new ( params : ScoringParameters ) -> Self {
@@ -105,14 +113,41 @@ impl Scorer {
105
113
Self :: new ( ScoringParameters {
106
114
base_penalty_msat : penalty_msat,
107
115
failure_penalty_msat : 0 ,
108
- #[ cfg( not( feature = "no-std" ) ) ]
109
116
failure_penalty_half_life : Duration :: from_secs ( 0 ) ,
110
117
} )
111
118
}
119
+ }
120
+
121
+ impl ChannelFailure {
122
+ fn new ( failure_penalty_msat : u64 ) -> Self {
123
+ Self {
124
+ undecayed_penalty_msat : failure_penalty_msat,
125
+ #[ cfg( not( feature = "no-std" ) ) ]
126
+ last_failed : Instant :: now ( ) ,
127
+ }
128
+ }
112
129
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 )
130
+ fn add_penalty ( & mut self , failure_penalty_msat : u64 , half_life : Duration ) {
131
+ self . undecayed_penalty_msat = self . decayed_penalty_msat ( half_life) + failure_penalty_msat;
132
+ #[ cfg( not( feature = "no-std" ) ) ]
133
+ {
134
+ self . last_failed = Instant :: now ( ) ;
135
+ }
136
+ }
137
+
138
+ fn decayed_penalty_msat ( & self , half_life : Duration ) -> u64 {
139
+ let decays = self . elapsed ( ) . as_secs ( ) . checked_div ( half_life. as_secs ( ) ) ;
140
+ match decays {
141
+ Some ( decays) => self . undecayed_penalty_msat >> decays,
142
+ None => 0 ,
143
+ }
144
+ }
145
+
146
+ fn elapsed ( & self ) -> Duration {
147
+ #[ cfg( not( feature = "no-std" ) ) ]
148
+ return self . last_failed . elapsed ( ) ;
149
+ #[ cfg( feature = "no-std" ) ]
150
+ return Duration :: from_secs ( 0 ) ;
116
151
}
117
152
}
118
153
@@ -127,7 +162,6 @@ impl Default for ScoringParameters {
127
162
Self {
128
163
base_penalty_msat : 500 ,
129
164
failure_penalty_msat : 1024 * 1000 ,
130
- #[ cfg( not( feature = "no-std" ) ) ]
131
165
failure_penalty_half_life : Duration :: from_secs ( 3600 ) ,
132
166
}
133
167
}
@@ -137,45 +171,19 @@ impl routing::Score for Scorer {
137
171
fn channel_penalty_msat (
138
172
& self , short_channel_id : u64 , _source : & NodeId , _target : & NodeId
139
173
) -> 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 ) ;
174
+ let failure_penalty_msat = self . channel_failures
175
+ . get ( & short_channel_id)
176
+ . map_or ( 0 , |value| value. decayed_penalty_msat ( self . params . failure_penalty_half_life ) ) ;
148
177
149
178
self . params . base_penalty_msat + failure_penalty_msat
150
179
}
151
180
152
181
fn payment_path_failed ( & mut self , _path : & Vec < RouteHop > , short_channel_id : u64 ) {
153
182
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" ) ]
183
+ let half_life = self . params . failure_penalty_half_life ;
167
184
self . channel_failures
168
185
. 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 ,
186
+ . and_modify ( |failure| failure. add_penalty ( failure_penalty_msat, half_life) )
187
+ . or_insert_with ( || ChannelFailure :: new ( failure_penalty_msat) ) ;
180
188
}
181
189
}
0 commit comments