Once again a weird place to commit, I have already done a lot of work, but I am just bad at using git, okay.
171 lines
6.1 KiB
TypeScript
171 lines
6.1 KiB
TypeScript
// This worker just sits on another thread and waits for message to solve
|
|
// challenges so that we dont block the render thread
|
|
|
|
import {
|
|
type WorkerRequest,
|
|
type SolutionMessage,
|
|
WorkerMessageType,
|
|
WorkerResponseType,
|
|
ChallengeStrategy,
|
|
} from "~/types/pow";
|
|
|
|
const worker_name = getWorkerName();
|
|
let solver: SolverModule | null = null;
|
|
|
|
let atomic_nonce: Int32Array | null = null;
|
|
let atomic_solution: Int32Array | null = null;
|
|
|
|
async function loadWasmSolver(module: WebAssembly.Module) {
|
|
if (atomic_nonce === null || atomic_solution === null) {
|
|
throw createError("Atomics not initialized");
|
|
}
|
|
|
|
console.debug(`[${worker_name}]: Loading WASM solver`);
|
|
|
|
solver = await WebAssembly.instantiate(module, {
|
|
env: {
|
|
__get_solution: () => Atomics.load(atomic_solution!, 0),
|
|
__set_solution: (value: number) => Atomics.store(atomic_solution!, 0, value),
|
|
__cmpxchg_solution: (expected: number, replacement: number) => Atomics.compareExchange(atomic_solution!, 0, expected, replacement),
|
|
__fetch_add_nonce: (value: number) => Atomics.add(atomic_nonce!, 0, value),
|
|
__log: (ptr: number, len: number) => {
|
|
const string_data = new Uint8Array(solver!.exports.memory.buffer, ptr, len);
|
|
console.log(`[${worker_name}]: ${new TextDecoder().decode(string_data)}`);
|
|
},
|
|
}
|
|
}) as unknown as SolverModule;
|
|
console.debug(`[${worker_name}]: WASM solver loaded`);
|
|
}
|
|
|
|
onmessage = async (event: MessageEvent<WorkerRequest>) => {
|
|
if (event.data.type === WorkerMessageType.Init) {
|
|
console.log(`[${worker_name}]: Initializing...`);
|
|
|
|
atomic_nonce = new Int32Array(event.data.sab, 0, 1);
|
|
atomic_solution = new Int32Array(event.data.sab, 4, 1);
|
|
|
|
try {
|
|
await loadWasmSolver(event.data.module);
|
|
} catch (error: any) {
|
|
console.error(`[${worker_name}]: Failed to load WASM solver:`, error);
|
|
postMessage({
|
|
type: WorkerResponseType.Error,
|
|
error: `Could not load WASM solver: ${error.message}`,
|
|
} as SolutionMessage);
|
|
return;
|
|
}
|
|
|
|
if (!solver) {
|
|
console.error(`[${worker_name}]: Failed to load WASM solver`);
|
|
postMessage({
|
|
type: WorkerResponseType.Error,
|
|
error: "Failed to load WASM solver",
|
|
} as SolutionMessage);
|
|
return;
|
|
}
|
|
|
|
postMessage({
|
|
type: WorkerResponseType.Ok,
|
|
} as SolutionMessage);
|
|
return;
|
|
}
|
|
|
|
if (!solver) {
|
|
postMessage({
|
|
type: WorkerResponseType.Error,
|
|
error: "WASM solver not loaded",
|
|
} as SolutionMessage);
|
|
return;
|
|
}
|
|
|
|
const { strategy } = event.data;
|
|
|
|
const encoder = new TextEncoder();
|
|
|
|
let solution: number;
|
|
let target: string = event.data.target;
|
|
let target_bytes, target_ptr;
|
|
let memory;
|
|
switch (strategy) {
|
|
case ChallengeStrategy.LeadingZeroes:
|
|
const { difficulty } = event.data;
|
|
console.debug(`[${worker_name}]: recieved ${strategy} challenge: ${target}, difficulty: ${difficulty}`);
|
|
|
|
target_bytes = encoder.encode(target);
|
|
|
|
target_ptr = solver.exports.malloc(target_bytes.length);
|
|
if (target_ptr === 0 || target_ptr === null) {
|
|
console.error(`[${worker_name}]: Failed to allocate memory for challenge string`);
|
|
postMessage({
|
|
type: WorkerResponseType.Error,
|
|
error: "Failed to allocate memory for challenge string",
|
|
} as SolutionMessage);
|
|
return;
|
|
}
|
|
|
|
memory = new Uint8Array(solver.exports.memory.buffer);
|
|
memory.set(target_bytes, target_ptr);
|
|
|
|
solution = solver.exports.solve_leaading_zeroes_challenge(
|
|
target_ptr,
|
|
target.length,
|
|
difficulty,
|
|
);
|
|
console.debug(`[${worker_name}]: WASM solver found nonce: ${solution}`);
|
|
break;
|
|
case ChallengeStrategy.TargetNumber:
|
|
const { salt } = event.data;
|
|
console.debug(`[${worker_name}]: recieved ${strategy} challenge: ${target}, salt: ${salt}`);
|
|
|
|
const salt_bytes = encoder.encode(salt);
|
|
target_bytes = encoder.encode(target);
|
|
|
|
const salt_ptr = solver.exports.malloc(salt_bytes.length);
|
|
if (salt_ptr === 0 || salt_ptr === null) {
|
|
console.error(`[${worker_name}]: Failed to allocate memory for salt string`);
|
|
postMessage({
|
|
type: WorkerResponseType.Error,
|
|
error: "Failed to allocate memory for salt string",
|
|
} as SolutionMessage);
|
|
return;
|
|
}
|
|
|
|
target_ptr = solver.exports.malloc(target_bytes.length);
|
|
if (target_ptr === 0 || target_ptr === null) {
|
|
console.error(`[${worker_name}]: Failed to allocate memory for target string`);
|
|
postMessage({
|
|
type: WorkerResponseType.Error,
|
|
error: "Failed to allocate memory for target string",
|
|
} as SolutionMessage);
|
|
return;
|
|
}
|
|
|
|
memory = new Uint8Array(solver.exports.memory.buffer);
|
|
memory.set(salt_bytes, salt_ptr);
|
|
memory.set(target_bytes, target_ptr);
|
|
|
|
solution = solver.exports.solve_target_number_challenge(
|
|
target_ptr,
|
|
target_bytes.length,
|
|
salt_ptr,
|
|
salt_bytes.length,
|
|
);
|
|
console.debug(`[${worker_name}]: WASM solver found nonce: ${solution}`);
|
|
|
|
break;
|
|
}
|
|
|
|
// we are just assuming that if its less than -1, its the min i32
|
|
if (solution < 0) {
|
|
return postMessage({
|
|
type: WorkerResponseType.Error,
|
|
error: "failed to solve challenge",
|
|
} as SolutionMessage);
|
|
}
|
|
|
|
postMessage({
|
|
type: WorkerResponseType.Solution,
|
|
nonce: solution === -1 ? null : solution.toString()
|
|
} as SolutionMessage);
|
|
};
|