Skip to content

Commit d1a33db

Browse files
committed
feat: misc updates, bump new version
1 parent 08759f5 commit d1a33db

File tree

8 files changed

+159
-88
lines changed

8 files changed

+159
-88
lines changed

server/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "stratum-server"
3-
version = "5.7.4"
3+
version = "5.7.5"
44
authors = ["Sean Kilgarriff sean@urkel.com"]
55
rust-version = "1.67.1"
66
edition = "2021"

server/src/config.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ pub struct ConfigManager {
77
config: Arc<Config>,
88
}
99

10-
//@todo just looking at this now, it seems highly highly inefficient if we are moving or cloning
1110
impl ConfigManager {
1211
pub(crate) fn new(config: Config) -> Self {
1312
Self {
@@ -32,6 +31,10 @@ impl ConfigManager {
3231
&self.config.difficulty
3332
}
3433

34+
pub(crate) fn connection_config(&self) -> &ConnectionConfig {
35+
&self.config.connection
36+
}
37+
3538
pub(crate) fn ban_manager_enabled(&self) -> bool {
3639
self.config.bans.enabled
3740
}
@@ -71,6 +74,9 @@ pub struct ConnectionConfig {
7174
pub(crate) max_connections: Option<usize>,
7275
/// Active Timeout is how long with no activity before we disconnect a miner.
7376
pub(crate) active_timeout: u64,
77+
/// Initial Timeout is how long we wait for an initial message from a miner. Once they are
78+
/// active, we switch to the active timeout setting.
79+
pub(crate) inital_timeout: u64,
7480
//@todo maybe move this to a new struct called MinerConfig, but for now I think it's ok.
7581
/// Check Threshold is how many shares until we consider a ban on a miner
7682
pub(crate) check_threshold: u64,
@@ -85,6 +91,7 @@ impl Default for ConnectionConfig {
8591
proxy_protocol: false,
8692
max_connections: None,
8793
active_timeout: 600,
94+
inital_timeout: 15,
8895
check_threshold: 500,
8996
invalid_percent: 50.0,
9097
}

server/src/connection.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ impl ConnectionReader {
161161
continue;
162162
}
163163

164+
//@todo I think we may want to log the buf here if it fails on trace - Right now we
165+
//can't see what these connections are sending.
164166
let msg: Request = serde_json::from_str(&buf)?;
165167

166168
return Ok(Some(Frame::V1(msg)));

server/src/miner.rs

Lines changed: 97 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use 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
};
58
use 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)]
2934
pub(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)]
310298
mod 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

Comments
 (0)