From f6ac834ca472a4ba2a1f4634ebc15cb8575cb1db Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Sat, 23 May 2026 12:48:08 -0700 Subject: [PATCH] Use bytes throughout WASM until final result is found. --- src/lib/generate/wasm/index.ts | 24 ++++++++++++------------ src/lib/generate/wasm/worker.ts | 19 +++++++++---------- src/utils/bytes.ts | 10 ++++++++++ 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/lib/generate/wasm/index.ts b/src/lib/generate/wasm/index.ts index 61e26c5..87eae92 100644 --- a/src/lib/generate/wasm/index.ts +++ b/src/lib/generate/wasm/index.ts @@ -2,7 +2,7 @@ //! SPDX-License-Identifier: GPL-3.0-or-later import { NanoPowValidate } from '#lib/validate' -import { Bytes, BytesToHex, Logger, bigintRandom, bigintToHex } from '#utils' +import { BytesToHex, Logger, bigintRandom, isBytes } from '#utils' import { WorkGenerateResponse } from 'nano-pow' import { NanoPowWasmWorker } from './worker.js' @@ -10,7 +10,7 @@ const logger = new Logger() // Initialize CPU let isReady: boolean = false -let data: { [key: string]: string } = {} +let data: Record = {} let v: BigUint64Array = new BigUint64Array(16) let m: BigUint64Array = new BigUint64Array(16) let workers: Worker[] = [] @@ -38,8 +38,8 @@ function reset (): void { } async function init (hash: Bytes, difficulty: bigint, effort: number): Promise { - data.hash = BytesToHex(hash.buffer, 64) - data.difficulty = bigintToHex(difficulty, 16) + data.hash = hash + data.difficulty = difficulty for (let i = workers.length; i < effort; i++) { workers.push(new Worker(url, { type: 'module' })) @@ -70,20 +70,20 @@ async function workersStarted () { }) } -async function dispatch (): Promise { +async function dispatch (): Promise { return new Promise(next => { const attempts = [] for (const w of workers) { - data.seed = bigintToHex((bigintRandom() & ~((1n << 24n) - 1n)), 16) + data.seed = bigintRandom() & ~((1n << 24n) - 1n) const attempt = new Promise((resolve, reject) => { w.onerror = reject w.onmessage = (msg) => resolve(msg.data) - w.postMessage(JSON.stringify(data)) + w.postMessage(data) }) attempts.push(attempt) } Promise.all(attempts).then(results => { - const result = results.find(r => typeof r === 'bigint') + const result: Bytes | undefined = results.find(r => isBytes(r)) next(result ?? dispatch()) }) }) @@ -134,11 +134,11 @@ export async function generate (hash: Bytes, difficulty: bigint, effort: number, if (isReady === false) setup() await init(hash, difficulty, effort) - let work = 0n + let work: Bytes = new Uint8Array(8) let result = '' try { - work = await dispatch() - result = (await NanoPowValidate(Bytes(work, 8), hash, difficulty, debug)).difficulty + work.set(await dispatch()) + result = (await NanoPowValidate(work, hash, difficulty, debug)).difficulty } catch (err) { LOG: logger.log(err) } finally { @@ -154,7 +154,7 @@ export async function generate (hash: Bytes, difficulty: bigint, effort: number, return { hash: BytesToHex(hash.buffer, 64), - work: bigintToHex(work, 16), + work: BytesToHex(work.buffer, 16), difficulty: result } } diff --git a/src/lib/generate/wasm/worker.ts b/src/lib/generate/wasm/worker.ts index 945dd20..6f69147 100644 --- a/src/lib/generate/wasm/worker.ts +++ b/src/lib/generate/wasm/worker.ts @@ -3,7 +3,7 @@ //@ts-expect-error import compute from './asm/build/compute.wasm' -type Main = (w: bigint, h0: bigint, h1: bigint, h2: bigint, h3: bigint, d: bigint) => any +type Main = (w: bigint, h0: bigint, h1: bigint, h2: bigint, h3: bigint, d: bigint) => bigint const worker = async (compute: number[]): Promise => { let isReady = false @@ -33,7 +33,7 @@ const worker = async (compute: number[]): Promise => { } async function handleMessage (msg: any): Promise { - let result: any = null + let result: any = null, buffer: Transferable[] = [] try { if (!isReady) await setup() const hashArray = new BigUint64Array(4) @@ -45,21 +45,20 @@ const worker = async (compute: number[]): Promise => { removeEventListener('message', handleMessage) result = 'stopped' } else { - const data = JSON.parse(msg.data) - const seed = BigInt(`0x${data.seed}`) - const difficulty = BigInt(`0x${data.difficulty}`) - for (let i = 0; i < data.hash.length; i += 16) { - const u64 = data.hash.slice(i, i + 16) - hashView.setBigUint64(i / 2, BigInt(`0x${u64}`)) + const { data } = msg as { data: { hash: Uint8Array, difficulty: bigint, seed: bigint } } + const { difficulty, seed } = data + const hash = new BigUint64Array(data.hash.buffer) + for (let i = 0; i < hash.length; i++) { + hashView.setBigUint64(i << 3, hash[i], true) } const work = main(seed, hashArray[0], hashArray[1], hashArray[2], hashArray[3], difficulty) if (typeof work !== 'bigint') { throw new TypeError('Invalid work from WASM') } - const workArray = new BigUint64Array(1) + const workArray = new Uint8Array(8) const workView = new DataView(workArray.buffer) workView.setBigUint64(0, work, true) - result = workArray[0] + result = workArray } } catch (err: unknown) { if (typeof err === 'object' && err != null) { diff --git a/src/utils/bytes.ts b/src/utils/bytes.ts index 26a0815..504df38 100644 --- a/src/utils/bytes.ts +++ b/src/utils/bytes.ts @@ -47,3 +47,13 @@ export function BytesToHex (input: unknown, minLength: unknown = 2): string { const bytes = new Uint8Array(input) return [...bytes].map(b => b.toString(16).padStart(2, '0')).join('').padStart(minLength, '0') } + +/** + * Type narrowing for ArrayBufferLike bytes. + * + * @param {unknown} value + * @returns {boolean} + */ +export function isBytes (value: unknown): value is Bytes { + return value instanceof Uint8Array && value.buffer instanceof ArrayBuffer +} -- 2.52.0