11use crate :: {
2- types:: { ConnectionID , Difficulties , Difficulty , DifficultySettings , VarDiffBuffer } ,
2+ types:: {
3+ BanStats , ConnectionID , Difficulties , Difficulty , DifficultySettings , MinerStats ,
4+ VarDiffBuffer , VarDiffStats ,
5+ } ,
36 utils, ConfigManager , SessionID ,
47} ;
58use parking_lot:: Mutex ;
@@ -25,10 +28,12 @@ pub(crate) struct Inner {
2528 pub ( crate ) name : Option < String > ,
2629}
2730
31+ //@todo random reminder for myself here -> Would it be more efficient to wrap this entire struct in
32+ //a Mutex? My guess is no... But let's jsut re-review.
2833#[ derive( Debug ) ]
2934pub ( crate ) struct Shared {
3035 difficulties : Mutex < Difficulties > ,
31- needs_ban : Mutex < bool > ,
36+ ban_stats : Mutex < BanStats > ,
3237 stats : Mutex < MinerStats > ,
3338 var_diff_stats : Mutex < VarDiffStats > ,
3439 difficulty_settings : Mutex < DifficultySettings > ,
@@ -49,7 +54,10 @@ impl Miner {
4954
5055 let shared = Shared {
5156 difficulties : Mutex :: new ( Difficulties :: new_only_current ( difficulty. default ) ) ,
52- needs_ban : Mutex :: new ( false ) ,
57+ ban_stats : Mutex :: new ( BanStats {
58+ last_ban_check_share : 0 ,
59+ needs_ban : false ,
60+ } ) ,
5361 stats : Mutex :: new ( MinerStats {
5462 accepted : 0 ,
5563 stale : 0 ,
@@ -82,34 +90,52 @@ impl Miner {
8290 }
8391 }
8492
85- // pub(crate) fn id(&self) -> Uuid {
86- // self.inner.id
87- // }
88-
8993 pub ( crate ) fn ban ( & self ) {
90- * self . shared . needs_ban . lock ( ) = true ;
94+ //@todo I now set needs ban in consider ban so that I don't have to drop the Mutex. In
95+ //here, we just really want to either contact the session, or disconnect the miner
96+ // let mut ban_stats = self.shared.ban_stats.lock();
97+ // ban_stats.needs_ban = true;
9198
9299 //@todo I think we need to disconnect here as well.
100+ //@todo ok as far as I can tell, a ban will *not* lead to a miner being disconnected from
101+ //the pool right now.
102+ //
103+ //Couple of thoughts.
104+ //
105+ //1. Let's go with the most complex scenario. Single connection with multiple miners. We
106+ // want to disconnect this miner ONLY - How we do that will be complex because we will
107+ // want the other miners in this connection to still work.
108+ //
109+ //2. If it is a single miner and single connection, I think this becomes a bit easier. We
110+ // probably need a check in the tcp loop where we see if there are still remaining miners
111+ // on a connection? Or we just send this individual miner a ban signal (tbd)
112+ }
113+
114+ pub fn needs_ban ( & self ) -> bool {
115+ self . shared . ban_stats . lock ( ) . needs_ban
93116 }
94117
95118 pub fn consider_ban ( & self ) {
96119 let stats = self . shared . stats . lock ( ) ;
120+ let mut ban_stats = self . shared . ban_stats . lock ( ) ;
97121
98122 //@note this could possibly possibly possibly overflow - let's just think about that as we
99123 //move forward.
124+ //@todo I think this needs to be moved to like how retarget it used. Last ban check etc.
100125 let total = stats. accepted + stats. stale + stats. rejected ;
101126
102- let config = & self . config_manager . current_config ( ) . connection ;
127+ let config = & self . config_manager . connection_config ( ) ;
103128
104- if total >= config. check_threshold {
129+ if total - ban_stats . last_ban_check_share >= config. check_threshold {
105130 let percent_bad: f64 = ( ( stats. stale + stats. rejected ) as f64 / total as f64 ) * 100.0 ;
106131
132+ ban_stats. last_ban_check_share = total;
133+
107134 if percent_bad < config. invalid_percent {
108- //@todo do we want to reset though?
109- //Although if we don't, then this will trigger on every new share after 500.
110- //So we could switch it to modulo 500 == 0
111- //@todo make this possible. Reset stats to 0.
112- // self.stats.lock().await = MinerStats::default();
135+ //Does not need a ban
136+ //@todo not sure if this is a good idea. Basically what we are saying is if the
137+ //miner doesn't get banned in time, they can redeem themselves.
138+ ban_stats. needs_ban = false ;
113139 } else {
114140 warn ! (
115141 id = ?self . inner. connection_id,
@@ -120,6 +146,8 @@ impl Miner {
120146 stats. stale + stats. rejected,
121147 total
122148 ) ;
149+ ban_stats. needs_ban = true ;
150+
123151 self . ban ( ) ;
124152 }
125153 }
@@ -153,9 +181,7 @@ impl Miner {
153181
154182 self . consider_ban ( ) ;
155183
156- //@todo see below
157- //I don't think we want to retarget on invalid shares, but let's double check later.
158- // self.retarget().await;
184+ self . retarget ( ) ;
159185 }
160186
161187 pub fn rejected_share ( & self ) {
@@ -168,21 +194,18 @@ impl Miner {
168194
169195 self . consider_ban ( ) ;
170196
171- //@todo see below
172- //I don't think we want to retarget on invalid shares, but let's double check later.
173- // self.retarget().await;
197+ self . retarget ( ) ;
174198 }
175199
176- //@todo note, this only can be sent over ExMessage when it's hit a certain threshold.
177- //@todo self.set_difficulty
178- //@todo self.set_next_difficulty
179- //@todo does this need to return a result? Ideally not, but if we send difficulty, then maybe.
180- //@todo see if we can solve a lot of these recasting issues.
181- //@todo wrap u64 with a custom difficulty type.
182200 fn retarget ( & self ) {
183201 //This is in milliseconds
184202 let now = utils:: now ( ) ;
185- // let retarget_time = self.config_manager.difficulty_config().retarget_time() * 1000.0;
203+ let difficulty_config = self . config_manager . difficulty_config ( ) ;
204+
205+ //@todo why not just store this as u128... Let's do that now.
206+ let retarget_time = difficulty_config. retarget_time as u128 * 1000 ;
207+ let retarget_share_amount = difficulty_config. retarget_share_amount ;
208+ //@todo see above, should we just store this as f64 * 1000.0?
186209
187210 let mut difficulties = self . shared . difficulties . lock ( ) ;
188211 let mut var_diff_stats = self . shared . var_diff_stats . lock ( ) ;
@@ -193,53 +216,35 @@ impl Miner {
193216 var_diff_stats. vardiff_buf . append ( since_last) ;
194217 var_diff_stats. last_timestamp = now;
195218
196- //@todo review this code, see if we can make this easier.
197- if !( ( ( stats. accepted - var_diff_stats. last_retarget_share )
198- >= self
199- . config_manager
200- . difficulty_config ( )
201- . retarget_share_amount )
202- || ( now - var_diff_stats. last_retarget )
203- >= ( self . config_manager . difficulty_config ( ) . retarget_time as u128 * 1000 ) )
204- {
219+ //@todo add this as a function on miner stats please.
220+ let total = stats. accepted + stats. rejected + stats. stale ;
221+
222+ //This is the amoutn of shares we've added since the last retarget
223+ let share_difference = total - var_diff_stats. last_retarget_share ;
224+ let time_difference = now - var_diff_stats. last_retarget ;
225+
226+ if !( ( share_difference >= retarget_share_amount) || time_difference >= retarget_time) {
205227 return ;
206228 }
207229
208- // dbg!(stats.accepted);
209- //
210- // dbg!(var_diff_stats.last_retarget_share);
211- // dbg!(
212- // self.config_manager
213- // .difficulty_config()
214- // .retarget_share_amount
215- // );
216-
217230 var_diff_stats. last_retarget = now;
218231 var_diff_stats. last_retarget_share = stats. accepted ;
219232
220- // let variance = self.options.target_time * (self.options.variance_percent as f64 / 100.0);
221- // let time_min = self.options.target_time as f64 * 0.40;
222- // let time_max = self.options.target_time as f64 * 1.40;
223-
224233 //This average is in milliseconds
225234 let avg = var_diff_stats. vardiff_buf . avg ( ) ;
226235
227- // debug!(average = ?avg);
228- // dbg!(avg);
229-
230236 if avg <= 0.0 {
231237 return ;
232238 }
233239
234240 let mut new_diff;
235241
236- //@todo figure out what else needs to come from config here, and comment out this function.
237- let target_time = self . config_manager . difficulty_config ( ) . target_time as f64 * 1000.0 ;
242+ let target_time = difficulty_config. target_time as f64 * 1000.0 ;
238243
244+ //@todo these variances should probs come from config.
239245 if avg > target_time {
240246 //@todo this needs to just be target_time since we multiplied it above.
241- if ( avg / ( self . config_manager . difficulty_config ( ) . target_time as f64 * 1000.0 ) ) <= 1.5
242- {
247+ if ( avg / target_time) <= 1.5 {
243248 return ;
244249 }
245250 new_diff = difficulties. current ( ) . as_u64 ( ) / 2 ;
@@ -251,7 +256,7 @@ impl Miner {
251256
252257 new_diff = new_diff. clamp (
253258 self . shared . difficulty_settings . lock ( ) . minimum . as_u64 ( ) ,
254- self . config_manager . difficulty_config ( ) . maximum_difficulty ,
259+ difficulty_config. maximum_difficulty ,
255260 ) ;
256261
257262 if new_diff != difficulties. current ( ) . as_u64 ( ) {
@@ -289,23 +294,6 @@ impl Miner {
289294 }
290295}
291296
292- //@todo either wrap miner in a folder, or move these both to types
293- #[ derive( Debug , Clone ) ]
294- pub struct MinerStats {
295- accepted : u64 ,
296- stale : u64 ,
297- rejected : u64 ,
298- last_active : u128 ,
299- }
300-
301- #[ derive( Debug ) ]
302- pub struct VarDiffStats {
303- last_timestamp : u128 ,
304- last_retarget_share : u64 ,
305- last_retarget : u128 ,
306- vardiff_buf : VarDiffBuffer ,
307- }
308-
309297#[ cfg( test) ]
310298mod test {
311299 use std:: thread:: sleep;
@@ -356,6 +344,39 @@ mod test {
356344 //@todo we need some actual result here lol
357345 }
358346
347+ #[ test]
348+ fn test_ban ( ) {
349+ let connection_id = ConnectionID :: new ( ) ;
350+ let worker_id = Uuid :: new_v4 ( ) ;
351+ let session_id = SessionID :: from ( 1 ) ;
352+
353+ let config = Config :: default ( ) ;
354+ let config_manager = ConfigManager :: new ( config. clone ( ) ) ;
355+
356+ let diff_settings = DifficultySettings {
357+ default : Difficulty :: from ( config. difficulty . initial_difficulty ) ,
358+ minimum : Difficulty :: from ( config. difficulty . minimum_difficulty ) ,
359+ } ;
360+ let miner = Miner :: new (
361+ connection_id,
362+ worker_id,
363+ session_id,
364+ None ,
365+ None ,
366+ config_manager,
367+ diff_settings,
368+ ) ;
369+
370+ miner. valid_share ( ) ;
371+
372+ //Note Check threshold for miner bans is 500.
373+ for _ in 0 ..500 {
374+ miner. stale_share ( ) ;
375+ }
376+
377+ assert ! ( miner. needs_ban( ) ) ;
378+ }
379+
359380 #[ test]
360381 fn test_retarget ( ) {
361382 let connection_id = ConnectionID :: new ( ) ;
@@ -382,7 +403,7 @@ mod test {
382403
383404 // OK what do we need to test here....
384405 // 1. We need to solve the issue with why difficulty is flucuating so much with the single
385- // miner that is on the pool right now from CLSK .
406+ // miner that is on the pool right now.
386407 //
387408 // Scenario:
388409 // The current miner should be at roughly 120 TH/s
0 commit comments