mirror of
https://github.com/JorySeverijnse/ui-fixer-supreme.git
synced 2025-12-06 13:36:57 +00:00
390 lines
12 KiB
JavaScript
390 lines
12 KiB
JavaScript
// This is the dedicated Emscripten worker script.
|
|
|
|
const messageQueue = [];
|
|
|
|
// Define the Module object for Emscripten
|
|
var Module = { // Use a different name to avoid confusion
|
|
locateFile: (path) => {
|
|
console.log(`EmscriptenWorker: locateFile called for path: ${path}`);
|
|
if (path.endsWith('.wasm')) {
|
|
console.log("EmscriptenWorker: Returning /web-randomx.wasm for WASM file.");
|
|
return '/web-randomx.wasm'; // WASM file is in public/
|
|
}
|
|
return path;
|
|
},
|
|
onRuntimeInitialized: () => {
|
|
console.log("EmscriptenWorker: Emscripten runtime initialized.");
|
|
try {
|
|
hashingLogic = new HashingWrapper(Module); // Module is now the actual Emscripten module
|
|
console.log("EmscriptenWorker: HashingWrapper instantiated.");
|
|
self.postMessage({ type: 'emscripten-initialized' }); // Notify parent worker
|
|
|
|
// Process any queued messages
|
|
while (messageQueue.length > 0) {
|
|
processMessage(messageQueue.shift());
|
|
}
|
|
} catch (e) {
|
|
console.error("EmscriptenWorker: Error instantiating HashingWrapper:", e);
|
|
}
|
|
}
|
|
};
|
|
console.log("EmscriptenWorker: Emscripten module config defined.");
|
|
|
|
// Import the Emscripten-generated web-randomx.js
|
|
try {
|
|
self.importScripts('/web-randomx.js');
|
|
console.log("EmscriptenWorker: web-randomx.js imported successfully.");
|
|
|
|
} catch (e) {
|
|
console.error("EmscriptenWorker: Error importing or executing web-randomx.js:", e);
|
|
}
|
|
|
|
let hashingLogic = null;
|
|
|
|
class HashingWrapper {
|
|
constructor(module) {
|
|
this.module = module;
|
|
|
|
// Available exported functions from WASM
|
|
this.initCacheFunc = this.module._web_randomx_init_cache;
|
|
this.createVmFunc = this.module._web_randomx_create_vm;
|
|
this.hashFunc = this.module._web_randomx_hash;
|
|
this.releaseCacheFunc= this.module._web_randomx_release_cache;
|
|
this.destroyVmFunc = this.module._web_randomx_destroy_vm;
|
|
|
|
const exportedKeys = Object.keys(this.module).filter(key =>
|
|
key.startsWith('_web') || key.startsWith('_randomx') || key.startsWith('_')
|
|
);
|
|
console.log("EmscriptenWorker: DIAGNOSIS - Available exported keys:", exportedKeys);
|
|
|
|
if (!this.initCacheFunc || !this.createVmFunc || !this.hashFunc) {
|
|
console.error("EmscriptenWorker: CRITICAL: Required functions not found. Hashing will fail.");
|
|
}
|
|
|
|
// Internal state
|
|
this.currentJob = null;
|
|
this.throttleWait = 0;
|
|
this.throttledStart = 0;
|
|
this.throttledHashes = 0;
|
|
this.workThrottledBound = this.workThrottled.bind(this);
|
|
this.target = new Uint8Array(32);
|
|
this.input = null;
|
|
this.output = null;
|
|
this.seed_input = null;
|
|
this.blob = null;
|
|
this.seed_blob = null;
|
|
this.variant = 0;
|
|
this.height = 0;
|
|
this.isWorking = false;
|
|
}
|
|
|
|
|
|
allocateMemory() {
|
|
if (this.input && this.input.byteLength > 0) return;
|
|
|
|
try {
|
|
const mallocFunc = this.module._malloc || this.module.malloc;
|
|
|
|
if (this.module.HEAPU8 && this.module.HEAPU8.buffer && mallocFunc) {
|
|
// Allocate space for the job blob (256 bytes is a common max)
|
|
this.input = new Uint8Array(this.module.HEAPU8.buffer, mallocFunc(256), 256);
|
|
// Allocate space for the 32-byte hash output
|
|
this.output = new Uint8Array(this.module.HEAPU8.buffer, mallocFunc(32), 32);
|
|
// Allocate space for the 32-byte seed hash input
|
|
this.seed_input = new Uint8Array(this.module.HEAPU8.buffer, mallocFunc(32), 32);
|
|
|
|
if (this.input.byteOffset === 0) {
|
|
console.error("EmscriptenWorker: Malloc returned 0. Allocation failed.");
|
|
this.input = null;
|
|
}
|
|
} else {
|
|
console.error(`EmscriptenWorker: Memory allocation failed. _malloc is missing.`);
|
|
}
|
|
} catch (e) {
|
|
console.error("EmscriptenWorker: Alloc error:", e);
|
|
}
|
|
}
|
|
|
|
hexToBytes(hex) {
|
|
const len = hex.length / 2;
|
|
let bytes = new Uint8Array(len);
|
|
for (let i = 0; i < len; ++i) {
|
|
bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
|
|
}
|
|
return bytes;
|
|
}
|
|
|
|
bytesToHex(bytes) {
|
|
let hex = '';
|
|
for (let i = 0; i < bytes.length; ++i) {
|
|
hex += (bytes[i] >>> 4).toString(16);
|
|
hex += (15 & bytes[i]).toString(16);
|
|
}
|
|
return hex;
|
|
}
|
|
|
|
meetsTarget(output, target) {
|
|
let isZero = true;
|
|
for (let j = 0; j < output.length; j++) {
|
|
if (output[j] !== 0) {
|
|
isZero = false;
|
|
break;
|
|
}
|
|
}
|
|
if (isZero) return false;
|
|
|
|
for (let i = 1; i <= target.length; ++i) {
|
|
if (output[output.length - i] > target[target.length - i]) return false;
|
|
if (output[output.length - i] < target[target.length - i]) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
setJob(data) {
|
|
console.log('EmscriptenWorker: Setting new job:', data);
|
|
this.allocateMemory();
|
|
if (!this.input) {
|
|
console.error("EmscriptenWorker: setJob aborted, memory not allocated.");
|
|
return;
|
|
}
|
|
try {
|
|
this.currentJob = data;
|
|
this.blob = this.hexToBytes(data.blob);
|
|
this.input.set(this.blob);
|
|
|
|
const targetBytes = this.hexToBytes(data.target);
|
|
if (targetBytes.length <= 8) {
|
|
for (let i = 1; i <= targetBytes.length; ++i) {
|
|
this.target[this.target.length - i] = targetBytes[targetBytes.length - i];
|
|
}
|
|
for (let i = 0; i < this.target.length - targetBytes.length; ++i) {
|
|
this.target[i] = 255;
|
|
}
|
|
} else {
|
|
this.target.set(targetBytes);
|
|
}
|
|
|
|
this.variant = data.variant === undefined ? 0 : data.variant;
|
|
this.height = data.height === undefined ? 0 : data.height;
|
|
this.seed_blob = this.hexToBytes(data.seed_hash);
|
|
this.seed_input.set(this.seed_blob);
|
|
|
|
if (this.initCacheFunc) {
|
|
try {
|
|
console.log('EmscriptenWorker: Initializing cache.');
|
|
this.initCacheFunc(this.variant, BigInt(this.height), this.seed_input.byteOffset);
|
|
console.log('EmscriptenWorker: Cache initialized.');
|
|
} catch (initError) {
|
|
console.error("EmscriptenWorker: RandomX VM initialization failed in WASM (setJob).", initError);
|
|
}
|
|
} else {
|
|
console.error("EmscriptenWorker: Critical: Initialization function not found. Hashing will fail.");
|
|
}
|
|
|
|
} catch (e) {
|
|
console.error("Job set error:", e);
|
|
}
|
|
}
|
|
|
|
now() {
|
|
return (self.performance ? self.performance.now() : Date.now());
|
|
}
|
|
|
|
hash(input, output, byteLength, variant, height, seed) {
|
|
if (!this.input || this.input.byteLength === 0 || !this.hashFunc) return 0;
|
|
|
|
try {
|
|
const nonce = 4294967295 * Math.random() + 1 >>> 0;
|
|
this.input[39] = (4278190080 & nonce) >> 24;
|
|
this.input[40] = (16711680 & nonce) >> 16;
|
|
this.input[41] = (65280 & nonce) >> 8;
|
|
this.input[42] = (255 & nonce) >> 0;
|
|
|
|
this.hashFunc(this.variant, BigInt(this.height), seed.byteOffset, input.byteOffset, byteLength, output.byteOffset);
|
|
return 1;
|
|
} catch (e) {
|
|
// The crash is due to uninitialized VM, which is fixed by recompiling (Step 1)
|
|
console.error('EmscriptenWorker: Error during hash calculation:', e);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
work() {
|
|
if (!this.isWorking || !this.currentJob) {
|
|
console.log('EmscriptenWorker: Work loop stopped. isWorking:', this.isWorking, 'currentJob:', this.currentJob);
|
|
return;
|
|
}
|
|
|
|
this.allocateMemory();
|
|
if (!this.input) {
|
|
setTimeout(() => this.work(), 100);
|
|
return;
|
|
}
|
|
|
|
const workStart = this.now();
|
|
let hashes = 0;
|
|
let ifMeetTarget = false;
|
|
let interval = 0;
|
|
let loopCount = 0;
|
|
|
|
while (!ifMeetTarget && interval < 1000 && loopCount < 100000) {
|
|
hashes += this.hash(this.input, this.output, this.blob.length, this.variant, this.height, this.seed_input);
|
|
ifMeetTarget = this.meetsTarget(this.output, this.target);
|
|
interval = this.now() - workStart;
|
|
loopCount++;
|
|
}
|
|
|
|
const effectiveInterval = interval > 0 ? interval : 1;
|
|
const hashesPerSecond = hashes / (effectiveInterval / 1e3);
|
|
|
|
if (ifMeetTarget) {
|
|
const nonce = this.bytesToHex(this.input.subarray(39, 43));
|
|
const result = this.bytesToHex(this.output);
|
|
self.postMessage({
|
|
type: 'hash-found',
|
|
payload: {
|
|
hashesPerSecond: hashesPerSecond,
|
|
hashes: hashes,
|
|
job_id: this.currentJob.job_id,
|
|
nonce: nonce,
|
|
result: result
|
|
}
|
|
});
|
|
} else {
|
|
self.postMessage({
|
|
type: 'hash-stats',
|
|
payload: {
|
|
hashesPerSecond: hashesPerSecond,
|
|
hashes: hashes
|
|
}
|
|
});
|
|
}
|
|
|
|
if (this.isWorking) {
|
|
setTimeout(() => this.work(), 0);
|
|
}
|
|
}
|
|
|
|
workThrottled() {
|
|
console.log('EmscriptenWorker: Starting throttled work loop.');
|
|
if (!this.isWorking || !this.currentJob) {
|
|
console.log('EmscriptenWorker: Throttled work loop stopped. isWorking:', this.isWorking, 'currentJob:', this.currentJob);
|
|
return;
|
|
}
|
|
|
|
this.allocateMemory();
|
|
if (!this.input) {
|
|
setTimeout(this.workThrottledBound, 100);
|
|
return;
|
|
}
|
|
|
|
const WORK_BURST_MS = 50;
|
|
const throttleRatio = 1 / (1 - this.throttleWait) - 1;
|
|
const SLEEP_TIME_MS = WORK_BURST_MS * throttleRatio;
|
|
|
|
const burstStart = this.now();
|
|
if (this.throttledStart === 0) this.throttledStart = burstStart;
|
|
|
|
let hashesInBurst = 0;
|
|
let targetFound = false;
|
|
|
|
while ((this.now() - burstStart) < WORK_BURST_MS) {
|
|
hashesInBurst += this.hash(this.input, this.output, this.blob.length, this.variant, this.height, this.seed_input);
|
|
if (this.meetsTarget(this.output, this.target)) {
|
|
targetFound = true;
|
|
break;
|
|
}
|
|
}
|
|
this.throttledHashes += hashesInBurst;
|
|
|
|
const totalInterval = this.now() - this.throttledStart;
|
|
const effectiveTotal = totalInterval > 0 ? totalInterval : 1;
|
|
const hashesPerSecond = this.throttledHashes / (effectiveTotal / 1e3);
|
|
|
|
if (targetFound) {
|
|
const nonce = this.bytesToHex(this.input.subarray(39, 43));
|
|
const result = this.bytesToHex(this.output);
|
|
|
|
self.postMessage({
|
|
type: 'hash-found',
|
|
payload: {
|
|
hashesPerSecond: hashesPerSecond,
|
|
hashes: this.throttledHashes,
|
|
job_id: this.currentJob.job_id,
|
|
nonce: nonce,
|
|
result: result
|
|
}
|
|
});
|
|
this.throttledHashes = 0;
|
|
this.throttledStart = 0;
|
|
setTimeout(this.workThrottledBound, 0);
|
|
|
|
} else if (totalInterval > 1000) {
|
|
self.postMessage({
|
|
type: 'hash-stats',
|
|
payload: {
|
|
hashesPerSecond: hashesPerSecond,
|
|
hashes: this.throttledHashes
|
|
}
|
|
});
|
|
// TYPO FIX: Changed 'thisottledHashes' to 'this.throttledHashes'
|
|
this.throttledHashes = 0;
|
|
this.throttledStart = 0;
|
|
setTimeout(this.workThrottledBound, 0);
|
|
|
|
} else {
|
|
const delay = Math.max(1, SLEEP_TIME_MS);
|
|
setTimeout(this.workThrottledBound, delay);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// This worker will receive messages from its parent worker (miner.worker.js)
|
|
function processMessage(data) {
|
|
const { type, payload } = data;
|
|
console.log('EmscriptenWorker: Processing message:', data);
|
|
|
|
if (!hashingLogic) {
|
|
console.warn("EmscriptenWorker: Hashing logic not yet initialized, queueing message.");
|
|
messageQueue.push(data);
|
|
return;
|
|
}
|
|
|
|
switch (type) {
|
|
case 'set-job':
|
|
hashingLogic.setJob(payload.job);
|
|
hashingLogic.throttleWait = 1 / (1 - payload.throttle) - 1; // Set throttle
|
|
hashingLogic.isWorking = true;
|
|
hashingLogic.work();
|
|
break;
|
|
case 'start-work':
|
|
hashingLogic.isWorking = true;
|
|
hashingLogic.work();
|
|
break;
|
|
case 'start-throttled-work':
|
|
hashingLogic.isWorking = true;
|
|
hashingLogic.workThrottled();
|
|
break;
|
|
case 'stop-hashing':
|
|
hashingLogic.isWorking = false;
|
|
break;
|
|
case 'set-throttle':
|
|
hashingLogic.throttleWait = 1 / (1 - payload) - 1;
|
|
break;
|
|
case 'set-threads':
|
|
// Emscripten module might not directly support setting threads from here
|
|
console.warn("EmscriptenWorker: set-threads not directly supported by HashingWrapper.");
|
|
break;
|
|
default:
|
|
console.log("EmscriptenWorker: Unknown message type", type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
self.addEventListener('message', (event) => {
|
|
processMessage(event.data);
|
|
});
|
|
|
|
console.log("EmscriptenWorker: Script loaded.");
|