162 lines
5.0 KiB
Python
162 lines
5.0 KiB
Python
import time
|
|
import copy
|
|
import threading
|
|
import uuid
|
|
import string, random, hashlib, datetime
|
|
from multiprocessing import Process, Manager, Event
|
|
|
|
from libs.noSys.noSysModule import NoSysModule
|
|
from .minerApiBlueprint import Blueprint
|
|
from .minerSocketio import HandlerSocketio
|
|
|
|
class Miner(NoSysModule):
|
|
def __init__(self, nosys_core):
|
|
super().__init__(nosys_core)
|
|
self.manager = Manager()
|
|
self.tasks = {}
|
|
|
|
def setup(self):
|
|
self.nosys_core.modules.api.register_blueprint(Blueprint(self).blueprint)
|
|
self.socketio = HandlerSocketio(self)
|
|
self.nosys_core.modules.api.register_socketio(self.socketio)
|
|
|
|
def monitor_task_result(self, task_id, result):
|
|
last_state = {}
|
|
while True:
|
|
try:
|
|
current_state = dict(result)
|
|
except Exception:
|
|
break
|
|
|
|
if current_state != last_state:
|
|
self.socketio.emit("taskUpdated", {
|
|
"task_id": task_id,
|
|
"result": current_state
|
|
})
|
|
last_state = copy.deepcopy(current_state)
|
|
|
|
if current_state.get("status") in ("completed", "cancelled", "error"):
|
|
break
|
|
|
|
time.sleep(1)
|
|
|
|
def start_mining(self, force, data, nonce_length):
|
|
task_id = str(uuid.uuid4())
|
|
result = self.manager.dict({
|
|
"status": "running",
|
|
"target_force": force,
|
|
"data": data,
|
|
"nonce": None,
|
|
"hash": None,
|
|
"best_nonce": None,
|
|
"best_hash": None,
|
|
"best_force": 0,
|
|
"attempts": 0,
|
|
"duration": 0,
|
|
})
|
|
stop_event = Event()
|
|
pause_event = Event()
|
|
|
|
proc = Process(target=self.mine_worker, args=(data, force, nonce_length, result, stop_event, pause_event))
|
|
proc.start()
|
|
|
|
monitor_thread = threading.Thread(
|
|
target=self.monitor_task_result,
|
|
args=(task_id, result),
|
|
daemon=True
|
|
)
|
|
monitor_thread.start()
|
|
|
|
self.tasks[task_id] = {
|
|
"process": proc,
|
|
"result": result,
|
|
"stop_event": stop_event,
|
|
"pause_event": pause_event,
|
|
}
|
|
|
|
return task_id
|
|
|
|
def pause_task(self, task_id):
|
|
task = self.tasks.get(task_id)
|
|
if not task:
|
|
return False
|
|
task["pause_event"].set()
|
|
task["result"]["status"] = "paused"
|
|
return True
|
|
|
|
def resume_task(self, task_id):
|
|
task = self.tasks.get(task_id)
|
|
if not task:
|
|
return False
|
|
|
|
task["pause_event"].clear()
|
|
task["result"]["status"] = "running"
|
|
return True
|
|
|
|
def cancel_task(self, task_id):
|
|
task = self.tasks.get(task_id)
|
|
if not task:
|
|
return False
|
|
|
|
task["stop_event"].set()
|
|
task["process"].terminate()
|
|
task["process"].join()
|
|
task["result"]["status"] = "cancelled"
|
|
return True
|
|
|
|
@staticmethod
|
|
def mine_worker(public_key, force, nonce_length, result_dict, stop_event, pause_event):
|
|
def hash_string(text):
|
|
return hashlib.sha256(text.encode('utf-8')).hexdigest()
|
|
|
|
def random_nonce(characters, length):
|
|
return ''.join(random.choices(characters, k=length))
|
|
|
|
def count_leading_zeros(hex_hash):
|
|
return len(hex_hash) - len(hex_hash.lstrip("0"))
|
|
|
|
characters = string.ascii_letters + string.digits + '[@_!#$%^&*()<>?/\\|}{~:]'
|
|
attempts = 0
|
|
best_force = -1
|
|
start_time = datetime.datetime.now()
|
|
|
|
while not stop_event.is_set():
|
|
if pause_event.is_set():
|
|
pause_event.wait(1)
|
|
continue
|
|
|
|
nonce = random_nonce(characters, nonce_length)
|
|
hash_result = hash_string(public_key + nonce)
|
|
attempts += 1
|
|
leading_zeros = count_leading_zeros(hash_result)
|
|
|
|
if leading_zeros > best_force:
|
|
best_force = leading_zeros
|
|
result_dict.update({
|
|
"best_nonce": nonce,
|
|
"best_hash": hash_result,
|
|
"best_force": best_force,
|
|
"attempts": attempts,
|
|
})
|
|
|
|
if leading_zeros >= force:
|
|
duration = (datetime.datetime.now() - start_time).total_seconds()
|
|
result_dict.update({
|
|
"status": "completed",
|
|
"nonce": nonce,
|
|
"hash": hash_result,
|
|
"attempts": attempts,
|
|
"duration": duration,
|
|
"best_force": leading_zeros,
|
|
"best_nonce": nonce,
|
|
"best_hash": hash_result,
|
|
})
|
|
stop_event.set()
|
|
break
|
|
|
|
if stop_event.is_set() and result_dict.get("status") not in ("completed", "cancelled"):
|
|
result_dict.update({
|
|
"status": "cancelled",
|
|
"duration": (datetime.datetime.now() - start_time).total_seconds(),
|
|
})
|