Skip to content
This repository was archived by the owner on Feb 5, 2025. It is now read-only.

Commit 509e703

Browse files
committed
Change hashing libary, implement midstate caching, hashrate monitoring
1 parent 4f3fa4f commit 509e703

File tree

4 files changed

+114
-44
lines changed

4 files changed

+114
-44
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
nimcache/
22
nimblecache/
33
htmldocs/
4-
compile*
4+
compile*
5+
ducominer.exe
6+
ducominer

ducominer.nim

Lines changed: 108 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,104 @@
1-
import hashlib/rhash/sha1
2-
import net, httpclient
3-
import json
4-
import strutils, strformat
5-
import threadpool
6-
import os
7-
8-
proc recvAll(s: Socket): string = # Function for receiving an arbitrary amount of data from the socket
9-
var res = ""
10-
res = res & s.recv(1, timeout=45000)
11-
while s.hasDataBuffered():
12-
res = res & s.recv(1, timeout=45000)
13-
return res
1+
import std / [
2+
net,
3+
strutils, strformat, strscans,
4+
threadpool, atomics,
5+
os, times,
6+
json, httpclient
7+
]
8+
9+
import nimcrypto/sha
10+
11+
const
12+
monitorInterval = 7500
13+
14+
var
15+
startTime: Time
16+
acceptedCnt, rejectedCnt, hashesCnt, currentDifficulty: Atomic[int]
1417

15-
proc mine(username: string, pool_ip: string, pool_port: Port, difficulty: string, miner_name: string) {.thread.} = # Mining functions executed in multiple threads
16-
var soc: Socket = newSocket() # Creating a new TCP socket
17-
soc.connect(pool_ip, pool_port) # Connecting to the mining server
18-
discard soc.recv(3, timeout=45000) # Receiving the server version and voiding it
18+
# Function for receiving an arbitrary amount of data from the socket
19+
proc recvAll(s: Socket): string =
20+
result = s.recv(1, timeout=30000)
21+
while s.hasDataBuffered():
22+
result &= s.recv(1, timeout=30000)
1923

20-
echo fmt"Thread #{getThreadId()} connected to {pool_ip}:{pool_port}"
24+
proc minerThread(username: string, pool_ip: string, pool_port: Port, difficulty: string, miner_name: string) {.thread.} = # Mining functions executed in multiple threads
25+
# Connecting to the server and discarding the server verison
26+
var soc: Socket = newSocket()
27+
soc.connect(pool_ip, pool_port)
28+
discard soc.recvAll()
2129

22-
var job: seq[string]
23-
var feedback: string
30+
# echo fmt"Thread #{getThreadId()} connected to {pool_ip}:{pool_port}"
2431

25-
while true: # An infinite loop of requesting and solving jobs
26-
if difficulty == "NORMAL": # Checking if the difficulty is set to "NORMAL" and sending a job request to the server
32+
while true:
33+
# Checking if the difficulty is set to "NORMAL" and sending a job request to the server
34+
if difficulty == "NORMAL":
2735
soc.send(fmt"JOB,{username}")
2836
else:
2937
soc.send(fmt"JOB,{username},{difficulty}")
30-
job = soc.recvAll().split(",") # Receiving a job from the server that is comma-separated
31-
for result in 0..100 * parseInt(job[2]): # A loop for solving the job
32-
if $count[RHASH_SHA1](job[0] & $(result)) == job[1]: # Checking if the hashes of the job matches our hash
33-
soc.send($(result) & ",," & miner_name) # Sending the result to the server
34-
feedback = soc.recvAll() # Receiving feedback from the server
38+
39+
# Receiving and parsing the job from the server
40+
var job = soc.recvAll()
41+
var
42+
prefix, target: string
43+
diff: int
44+
if not scanf(job, "$+,$+,$i", prefix, target, diff):
45+
quit("Error: couldn't parse job from the server!")
46+
target = target.toUpper()
47+
currentDifficulty.store(diff)
48+
49+
# Initialize the sha1 context and add prefix
50+
var ctx: sha1
51+
ctx.init()
52+
ctx.update(prefix)
53+
54+
# A loop for solving the job
55+
for res in 0 .. 100 * diff:
56+
# Copy the initialized context and add the value
57+
var ctxCopy = ctx
58+
ctxCopy.update($res)
59+
60+
# Checking if the hash of the job matches our hash
61+
if $ctxCopy.finish() == target:
62+
hashesCnt.atomicInc(res)
63+
soc.send(fmt"{$res},,{miner_name}")
64+
65+
# Receiving and checking the feedback from the server
66+
let feedback = soc.recvAll()
3567
if feedback == "GOOD": # Checking the server feedback
36-
echo fmt"Accepted share {result} with a difficulty of {parseInt(job[2])}"
68+
acceptedCnt.atomicInc()
3769
elif feedback == "BAD":
38-
echo fmt"Rejected share {result} with a difficulty of {parseInt(job[2])}"
39-
break # Breaking from the loop, as the job was solved
70+
rejectedCnt.atomicInc()
71+
72+
# Breaking from the loop, because the job was solved
73+
break
74+
75+
76+
proc monitorThread() {.thread.} =
77+
startTime = getTime()
78+
echo fmt"Statistics update interval: {monitorInterval / 1000} seconds"
79+
while true:
80+
sleep(monitorInterval)
81+
# Get time diff in milliseconds
82+
let mils = (getTime() - startTime).inMilliseconds.float
83+
84+
# Calculate amount of hashes per second
85+
let hashesSec = (hashesCnt.load().float / mils) * 1000
86+
let khsec = hashesSec / 1000
87+
let mhsec = khsec / 1000
88+
let toShow = if mhsec >= 1:
89+
mhsec.formatFloat(ffDecimal, 2) & " MH/s"
90+
elif khsec >= 1:
91+
khsec.formatFloat(ffDecimal, 2) & " KH/s"
92+
else:
93+
hashesSec.formatFloat(ffDecimal, 2) & " H/s"
94+
95+
startTime = getTime()
96+
let strTime = startTime.format("HH:mm:ss")
97+
echo fmt"{strTime} Hashrate: {toShow}, Accepted: {acceptedCnt.load()}, Rejected: {rejectedCnt.load()}, Difficulty: {currentDifficulty.load()}"
98+
99+
# Resetting hash count
100+
hashesCnt.store(0)
101+
40102

41103
var config: JsonNode
42104
if paramCount() < 1:
@@ -54,16 +116,22 @@ else:
54116

55117
let client: HttpClient = newHttpClient() # Creating a new HTTP client
56118

57-
var pool_address: string = client.getContent(config["ip_url"].getStr()) # Making a request to the URL specified in the config for getting mining server details
119+
var pool_address: seq[string] = client.getContent(config["ip_url"].getStr()).split("\n") # Making a request to the URL specified in the config for getting mining server details
120+
121+
var pool_ip: string = pool_address[0] # Parsing the server IP
122+
var pool_port: Port = Port(parseInt(pool_address[1])) # Parsing the server port
58123

59-
var pool_ip: string = pool_address.split("\n")[0] # Parsing the server IP
60-
var pool_port: Port = Port(parseInt(pool_address.split("\n")[1])) # Parsing the server port
124+
var username = config["username"].getStr()
125+
var difficulty = config["difficulty"].getStr()
126+
var miner_name = config["miner_name"].getStr()
127+
var thread_count = config["thread_count"].getInt()
61128

62-
var username = config["username"].getStr(default = "5Q")
63-
var difficulty = config["difficulty"].getStr(default = "NORMAL")
64-
var miner_name = config["miner_name"].getStr(default = "DUCOMiner-Nim")
65-
var thread_count = config["thread_count"].getInt(default = 16)
129+
# Starting mining threads and the monitor thread
130+
for i in 0 ..< thread_count:
131+
spawn minerThread(username, pool_ip, pool_port, difficulty, miner_name)
132+
sleep(300)
133+
echo "Started all mining threads"
134+
spawn monitorThread()
66135

67-
for i in countup(0, thread_count - 1): # A loop that spawns new threads executing the mine() function
68-
spawn mine(username, pool_ip, pool_port, difficulty, miner_name)
69-
sync() # Synchronizing the threads so the program doesn't exit until Ctrl+C is pressed or an exception is raised
136+
# Synchronizing the threads so the program doesn't exit until Ctrl+C is pressed or an exception is raised
137+
sync()

ducominer.nim.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
-d:ssl
2-
--threads:on
2+
--threads:on

ducominer.nimble

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Package Information
2-
version = "1.0.0"
2+
version = "1.2.0"
33
author = "its5Q"
44
description = "A multithreaded miner for DuinoCoin written in Nim."
55
license = "MIT"
66

77
bin = @["ducominer"]
88

99
# Dependencies
10-
requires "hashlib"
10+
requires "nimcrypto"

0 commit comments

Comments
 (0)