]> git.codecow.com Git - nano-pow.git/commitdiff
Use bytes throughout WASM until final result is found.
authorChris Duncan <chris@codecow.com>
Sat, 23 May 2026 19:48:08 +0000 (12:48 -0700)
committerChris Duncan <chris@codecow.com>
Sat, 23 May 2026 19:48:08 +0000 (12:48 -0700)
src/lib/generate/wasm/index.ts
src/lib/generate/wasm/worker.ts
src/utils/bytes.ts

index 61e26c5e427e5c8db14c38839ead63dc8ab22515..87eae923d94770fd6aed712abaa1432af4ad8a29 100644 (file)
@@ -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<string, bigint | Bytes> = {}
 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<void> {
-       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<bigint> {
+async function dispatch (): Promise<Bytes> {
        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
        }
 }
index 945dd20d9125df387d1ea38ca71896cb7a2503c4..6f69147272de0c28c2136229ae0e192b30319cff 100644 (file)
@@ -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<void> => {
        let isReady = false
@@ -33,7 +33,7 @@ const worker = async (compute: number[]): Promise<void> => {
        }
 
        async function handleMessage (msg: any): Promise<void> {
-               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<void> => {
                                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) {
index 26a08155594fc98883b60640c2348f2052609a1c..504df382194bd0f77a68d24ee9fbbe8cbc11b1f3 100644 (file)
@@ -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
+}