Skip to content
This repository was archived by the owner on Apr 3, 2023. It is now read-only.

Commit 0b5514d

Browse files
author
bhat
committed
Add beta Sha1Hasher.
1 parent fb97936 commit 0b5514d

File tree

3 files changed

+196
-126
lines changed

3 files changed

+196
-126
lines changed

src/hasher.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
use sha1::{Digest, Sha1};
2+
3+
use std::collections::HashMap;
4+
use std::sync::Arc;
5+
6+
use tokio::sync::{Mutex, RwLock};
7+
8+
fn sha1_digest(input: &str) -> String {
9+
let mut hasher = Sha1::new();
10+
sha1::Digest::update(&mut hasher, input.as_bytes());
11+
12+
let h = hasher.finalize();
13+
format!("{:x}", h)
14+
}
15+
16+
#[derive(Clone)]
17+
pub struct Sha1Hasher {
18+
hashmap: Arc<RwLock<HashMap<String, Vec<String>>>>,
19+
stack: Arc<Mutex<Vec<String>>>,
20+
}
21+
22+
impl Sha1Hasher {
23+
const HASHMAP_LIMIT: usize = 100;
24+
25+
pub fn new() -> Self {
26+
Self {
27+
hashmap: Arc::new(RwLock::new(HashMap::new())),
28+
stack: Arc::new(Mutex::new(Vec::new())),
29+
}
30+
}
31+
32+
pub async fn get_hash(&self, last_block_hash: String, expected_hash: String, diff: u32) -> u32 {
33+
{
34+
let hashmap = self.hashmap.read().await;
35+
if let Some(hashes) = hashmap.get(&last_block_hash) {
36+
if hashes.len() < diff as usize {
37+
log::warn!("Diff changed, recalculating.");
38+
} else {
39+
// Optimized for lower difficulty, uses AVX.
40+
for (duco_numeric_result, hash) in hashes.iter().enumerate() {
41+
if hash == &expected_hash {
42+
return duco_numeric_result as u32;
43+
}
44+
}
45+
}
46+
}
47+
} // Unlock hashmap
48+
49+
let hashes = self.precompute(last_block_hash, diff).await;
50+
51+
for (duco_numeric_result, hash) in hashes.iter().enumerate() {
52+
if hash == &expected_hash {
53+
return duco_numeric_result as u32;
54+
}
55+
}
56+
57+
return 0;
58+
}
59+
60+
async fn precompute(&self, last_block_hash: String, diff: u32) -> Vec<String> {
61+
let mut hashmap = self.hashmap.write().await;
62+
let mut stack = self.stack.lock().await;
63+
64+
if hashmap.len() > Self::HASHMAP_LIMIT {
65+
for _ in 0..(hashmap.len() - Self::HASHMAP_LIMIT) {
66+
let k = stack.remove(0);
67+
hashmap.remove(&k);
68+
}
69+
}
70+
71+
let hashes: Vec<String> = (0..diff)
72+
.map(|duco_numeric_result| format!("{}{}", last_block_hash, duco_numeric_result))
73+
.map(|h| sha1_digest(h.as_str()))
74+
.collect();
75+
76+
hashmap.insert(last_block_hash.clone(), hashes.clone());
77+
stack.push(last_block_hash);
78+
79+
hashes
80+
}
81+
}

src/main.rs

Lines changed: 76 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1+
mod hasher;
2+
mod util;
3+
14
use duino_miner::error::MinerError;
25

6+
use crate::util::{generate_8hex, get_pool_info};
7+
38
use serde::{Deserialize, Serialize};
49

510
use std::time::{Duration, SystemTime};
@@ -8,20 +13,12 @@ use tokio::fs::File;
813
use tokio::io::{AsyncReadExt, AsyncWriteExt};
914
use tokio::net::TcpStream;
1015

11-
use log::{error, info, warn};
12-
1316
use rand::Rng;
14-
use sha1::{Digest, Sha1};
1517

16-
use clap::{AppSettings, Clap, Subcommand};
18+
use log::{error, info, warn};
1719

18-
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
19-
pub struct Pool {
20-
pub name: String,
21-
pub ip: String,
22-
pub port: u16,
23-
pub connections: u32,
24-
}
20+
use crate::hasher::Sha1Hasher;
21+
use clap::{AppSettings, Clap, Subcommand};
2522

2623
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2724
pub struct Config {
@@ -77,21 +74,6 @@ struct Run {
7774
pool: Option<String>,
7875
}
7976

80-
fn generate_8hex() -> String {
81-
const HEX_ARRAY: [char; 16] = [
82-
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
83-
];
84-
85-
let mut result = String::new();
86-
87-
for _ in 0..8 {
88-
let n: usize = rand::thread_rng().gen_range(0..16);
89-
result.push(HEX_ARRAY[n]);
90-
}
91-
92-
result
93-
}
94-
9577
async fn generate_config(
9678
file_path: String,
9779
gen: &Generate,
@@ -122,26 +104,7 @@ async fn generate_config(
122104
Ok(())
123105
}
124106

125-
fn sha1_digest(input: &str) -> String {
126-
let mut hasher = Sha1::new();
127-
sha1::Digest::update(&mut hasher, input.as_bytes());
128-
129-
let h = hasher.finalize();
130-
format!("{:x}", h)
131-
}
132-
133-
async fn get_pool_info() -> Result<Pool, MinerError> {
134-
let pool: Pool = reqwest::get("http://51.15.127.80:4242/getPool")
135-
.await
136-
.map_err(|_| MinerError::Connection)?
137-
.json()
138-
.await
139-
.map_err(|_| MinerError::Connection)?;
140-
141-
Ok(pool)
142-
}
143-
144-
async fn start_miner(device: Device, pool: String) -> Result<(), MinerError> {
107+
async fn start_miner(device: Device, pool: String, hasher: Sha1Hasher) -> Result<(), MinerError> {
145108
let heatup_duration: u64 = rand::thread_rng().gen_range(10..10000);
146109
tokio::time::sleep(Duration::from_millis(heatup_duration)).await;
147110

@@ -198,98 +161,84 @@ async fn start_miner(device: Device, pool: String) -> Result<(), MinerError> {
198161

199162
let start = SystemTime::now();
200163

201-
for duco_numeric_result in 0..diff {
202-
let h = format!("{}{}", last_block_hash, duco_numeric_result);
203-
let result = sha1_digest(h.as_str());
204-
205-
if result == expected_hash {
206-
let end = SystemTime::now();
207-
let duration = end.duration_since(start).unwrap().as_micros();
208-
let real_rate = duco_numeric_result as f64 / duration as f64 * 1000000f64;
209-
210-
let expected_duration = expected_interval * duco_numeric_result as u128;
211-
212-
if duration < expected_duration {
213-
let wait_duration = (expected_duration - duration) as u64;
214-
tokio::time::sleep(Duration::from_micros(wait_duration)).await;
215-
info!("waited {} micro sec", wait_duration);
216-
} else {
217-
warn!(
218-
"system too slow, lag {} micro sec",
219-
duration - expected_duration
220-
);
221-
}
222-
223-
let end = SystemTime::now();
224-
let duration = end.duration_since(start).unwrap().as_micros();
225-
let emu_rate = duco_numeric_result as f64 / duration as f64 * 1000000f64;
226-
227-
let lag_duration: u64 = rand::thread_rng().gen_range(0..100);
228-
tokio::time::sleep(Duration::from_millis(lag_duration)).await;
229-
230-
let cmd_out = format!(
231-
"{},{:.2},{},{},{}\n",
232-
duco_numeric_result,
233-
emu_rate,
234-
device.firmware,
235-
device.device_name,
236-
device.chip_id
237-
);
238-
stream
239-
.write(cmd_out.as_bytes())
240-
.await
241-
.map_err(|_| MinerError::SendCommand)?;
242-
243-
let n = stream
244-
.read(&mut cmd_in)
245-
.await
246-
.map_err(|_| MinerError::RecvCommand)?;
247-
let resp = std::str::from_utf8(&cmd_in[..n])
248-
.map_err(|_| MinerError::InvalidUTF8)?
249-
.trim();
250-
251-
if resp == "GOOD" {
252-
info!(
253-
"result good, result: {}, rate: {:.2}, real: {:.2}",
254-
duco_numeric_result, emu_rate, real_rate
255-
);
256-
} else if resp == "BLOCK" {
257-
info!(
258-
"FOUND BLOCK!, result: {}, rate: {:.2}, real: {:.2}",
259-
duco_numeric_result, emu_rate, real_rate
260-
);
261-
} else {
262-
warn!(
263-
"resp: {}, result: {}, rate: {:.2}, real: {:.2}",
264-
resp, duco_numeric_result, emu_rate, real_rate
265-
);
266-
}
267-
268-
break;
269-
}
164+
let duco_numeric_result = hasher
165+
.get_hash(last_block_hash.to_string(), expected_hash.to_string(), diff)
166+
.await;
167+
168+
let end = SystemTime::now();
169+
let duration = end.duration_since(start).unwrap().as_micros();
170+
let real_rate = duco_numeric_result as f64 / duration as f64 * 1000000f64;
171+
172+
let expected_duration = expected_interval * duco_numeric_result as u128;
173+
174+
if duration < expected_duration {
175+
let wait_duration = (expected_duration - duration) as u64;
176+
tokio::time::sleep(Duration::from_micros(wait_duration)).await;
177+
info!("waited {} micro sec", wait_duration);
178+
} else {
179+
warn!(
180+
"system too slow, lag {} micro sec",
181+
duration - expected_duration
182+
);
183+
}
184+
185+
let end = SystemTime::now();
186+
let duration = end.duration_since(start).unwrap().as_micros();
187+
let emu_rate = duco_numeric_result as f64 / duration as f64 * 1000000f64;
188+
189+
let lag_duration: u64 = rand::thread_rng().gen_range(0..100);
190+
tokio::time::sleep(Duration::from_millis(lag_duration)).await;
191+
192+
let cmd_out = format!(
193+
"{},{:.2},{},{},{}\n",
194+
duco_numeric_result, emu_rate, device.firmware, device.device_name, device.chip_id
195+
);
196+
stream
197+
.write(cmd_out.as_bytes())
198+
.await
199+
.map_err(|_| MinerError::SendCommand)?;
200+
201+
let n = stream
202+
.read(&mut cmd_in)
203+
.await
204+
.map_err(|_| MinerError::RecvCommand)?;
205+
let resp = std::str::from_utf8(&cmd_in[..n])
206+
.map_err(|_| MinerError::InvalidUTF8)?
207+
.trim();
208+
209+
if resp == "GOOD" {
210+
info!(
211+
"result good, result: {}, rate: {:.2}, real: {:.2}",
212+
duco_numeric_result, emu_rate, real_rate
213+
);
214+
} else if resp == "BLOCK" {
215+
info!(
216+
"FOUND BLOCK!, result: {}, rate: {:.2}, real: {:.2}",
217+
duco_numeric_result, emu_rate, real_rate
218+
);
219+
} else {
220+
warn!(
221+
"resp: {}, result: {}, rate: {:.2}, real: {:.2}",
222+
resp, duco_numeric_result, emu_rate, real_rate
223+
);
270224
}
271225
}
272226
}
273227

274-
async fn start_miners(devices: Vec<Device>, pool: Option<String>) {
228+
async fn start_miners(devices: Vec<Device>, pool: Option<String>, hasher: Sha1Hasher) {
275229
loop {
276230
let pool = if let Some(pool) = pool.clone() {
277231
pool
278232
} else {
279-
let pool = get_pool_info().await.unwrap_or(Pool {
280-
name: "Default pool".to_string(),
281-
ip: "server.duinocoin.com".to_string(),
282-
port: 2813,
283-
connections: 1,
284-
});
285-
286-
format!("{}:{}", pool.ip, pool.port)
233+
get_pool_info()
234+
.await
235+
.unwrap_or(format!("{}:{}", "server.duinocoin.com", 2813))
287236
};
288237

289238
let mut futures_vec = Vec::new();
290239

291240
for device in &devices {
292-
let f = start_miner(device.clone(), pool.clone());
241+
let f = start_miner(device.clone(), pool.clone(), hasher.clone());
293242
futures_vec.push(f);
294243
}
295244

@@ -316,7 +265,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
316265

317266
info!("running with {} miners", c.devices.len());
318267

319-
start_miners(c.devices, run.pool).await;
268+
let hasher = Sha1Hasher::new();
269+
start_miners(c.devices, run.pool, hasher).await;
320270
}
321271
}
322272

src/util.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use duino_miner::error::MinerError;
2+
3+
use serde::{Deserialize, Serialize};
4+
5+
use rand::Rng;
6+
7+
pub fn generate_8hex() -> String {
8+
const HEX_ARRAY: [char; 16] = [
9+
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
10+
];
11+
12+
let mut result = String::new();
13+
14+
for _ in 0..8 {
15+
let n: usize = rand::thread_rng().gen_range(0..16);
16+
result.push(HEX_ARRAY[n]);
17+
}
18+
19+
result
20+
}
21+
22+
pub async fn get_pool_info() -> Result<String, MinerError> {
23+
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
24+
struct Pool {
25+
pub name: String,
26+
pub ip: String,
27+
pub port: u16,
28+
pub connections: u32,
29+
}
30+
31+
let pool: Pool = reqwest::get("http://51.15.127.80:4242/getPool")
32+
.await
33+
.map_err(|_| MinerError::Connection)?
34+
.json()
35+
.await
36+
.map_err(|_| MinerError::Connection)?;
37+
38+
Ok(format!("{}:{}", pool.ip, pool.port))
39+
}

0 commit comments

Comments
 (0)