From f09f0c68786f52240d343308ee606b20711100ce Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Mon, 22 Jun 2026 15:37:14 -0700 Subject: [PATCH] Refactor bigint conversion helpers. --- src/lib/config/index.ts | 12 ++++---- src/lib/generate/wasm/index.ts | 6 ++-- src/lib/generate/webgl/index.ts | 16 +++++------ src/lib/generate/webgpu/index.ts | 16 +++++------ src/lib/index.ts | 47 +++++++++++++++----------------- src/lib/validate/index.ts | 18 ++++++------ src/utils/bigint.ts | 11 +++----- 7 files changed, 60 insertions(+), 66 deletions(-) diff --git a/src/lib/config/index.ts b/src/lib/config/index.ts index 8a9d07b..3ffd796 100644 --- a/src/lib/config/index.ts +++ b/src/lib/config/index.ts @@ -1,7 +1,7 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { ApiSupport, SEND, bigintFrom, bigintToHex } from '#utils' +import { ApiSupport, big, bigHex, SEND } from '#utils' type ApiSupportedTypes = keyof typeof ApiSupport @@ -33,7 +33,7 @@ class NanoPowConfigConstructor implements NanoPowOptions { return { api: this.api, debug: this.debug, - difficulty: bigintToHex(this.difficulty, 16), + difficulty: bigHex(this.difficulty, 16), effort: this.effort } } @@ -117,14 +117,14 @@ class NanoPowConfigConstructor implements NanoPowOptions { if (input != null && input.difficulty != null) { if (typeof input.difficulty === 'string') { try { - input.difficulty = bigintFrom(input.difficulty, 'hex') + input.difficulty = big(input.difficulty) } catch { } } if (typeof input.difficulty !== 'bigint') { - throw new Error(`Invalid difficulty (${typeof input.difficulty})${input.difficulty}`) + throw new Error(`Invalid difficulty ${input.difficulty}`) } - if (input.difficulty < 0x0n || input.difficulty > SEND) { - throw new Error(`Invalid difficulty ${bigintToHex(input.difficulty, 16)}`) + if (input.difficulty < 0n || input.difficulty > SEND) { + throw new Error(`Invalid difficulty ${bigHex(input.difficulty, 16)}`) } return input.difficulty } diff --git a/src/lib/generate/wasm/index.ts b/src/lib/generate/wasm/index.ts index 46cbdbd..d0e07b9 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 { Logger, bigintToHex } from '#utils' +import { bigHex, Logger } from '#utils' import { WorkGenerateResponse } from 'nano-pow' import { NanoPowWasmWorker } from './worker.js' @@ -159,8 +159,8 @@ export async function generate (hash: bigint, difficulty: bigint, effort: number } return { - hash: bigintToHex(hash, 64), - work: bigintToHex(work, 16), + hash: bigHex(hash, 64), + work: bigHex(work, 16), difficulty: result } } diff --git a/src/lib/generate/webgl/index.ts b/src/lib/generate/webgl/index.ts index 5800dcb..0c36071 100644 --- a/src/lib/generate/webgl/index.ts +++ b/src/lib/generate/webgl/index.ts @@ -2,7 +2,7 @@ //! SPDX-FileContributor: Ben Green //! SPDX-License-Identifier: GPL-3.0-or-later AND MIT -import { Logger, bigintToHex, bigintToU32 } from '#utils' +import { bigHex, bigToU32, Logger } from '#utils' import { WorkGenerateResponse } from 'nano-pow' import { downsampleSource, drawSource, quadSource } from './shaders' @@ -295,7 +295,7 @@ function init (hash: Uint32Array, difficulty: bigint): void { // Set up INPUT which must be 16 bytes per 32-bit value due to array alignment for (let i = 0; i < 8; i++) { - inputHashView.setUint32(i * 16, hash[i]) + inputHashView.setUint32(i * 16, hash[i], true) } inputDifficultyView.setBigUint64(0, difficulty, true) LOG: logger.log('INPUT', inputArray.buffer.slice(0)) @@ -311,7 +311,7 @@ function draw (seed: bigint, drawFbo: FBO, query: WebGLQuery): void { if (gl == null) throw new Error('WebGL 2 is required to draw') if (drawFbo == null) throw new Error('FBO is required to draw') if (query == null) throw new Error('Query is required to draw') - LOG: logger.log(bigintToHex(seed, 16)) + LOG: logger.log(bigHex(seed, 16)) // Upload work seed buffer inputSeedView.setBigUint64(0, seed, true) @@ -414,7 +414,7 @@ export async function generate (hash: bigint, difficulty: bigint, effort: number LOG: logger.log('timed out') }, 60_000) LOG: logger.groupStart('NanoPow WebGL work_generate') - LOG: logger.log(`generate('${hash.toString(16)}', '${difficulty.toString(16)}', ${effort}, ${debug})`) + LOG: logger.log(`generate('${bigHex(hash, 16)}', '${bigHex(difficulty, 16)}', ${effort}, ${debug})`) // Start drawing to calculate one nonce per pixel const seed = new BigUint64Array(4) @@ -427,7 +427,7 @@ export async function generate (hash: bigint, difficulty: bigint, effort: number if (isReady === false || effort !== drawEffort || isFirstRetry) { setup(effort) } - init(bigintToU32(hash, 8), difficulty) + init(bigToU32(hash, 8), difficulty) crypto.getRandomValues(seed) LOG: logger.log('drawing frame 0') draw(seed[0], drawFbos[0], queries[0]) @@ -460,8 +460,8 @@ export async function generate (hash: bigint, difficulty: bigint, effort: number } return { - hash: bigintToHex(hash, 64), - work: bigintToHex(result.work, 16), - difficulty: bigintToHex(result.difficulty, 16) + hash: bigHex(hash, 64), + work: bigHex(result.work, 16), + difficulty: bigHex(result.difficulty, 16) } } diff --git a/src/lib/generate/webgpu/index.ts b/src/lib/generate/webgpu/index.ts index caa6a9a..0eafc86 100644 --- a/src/lib/generate/webgpu/index.ts +++ b/src/lib/generate/webgpu/index.ts @@ -1,7 +1,7 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { Logger, Queue, bigintToHex, bigintToU64 } from '#utils' +import { bigHex, bigToU64, Logger, Queue } from '#utils' import { WorkGenerateResponse } from 'nano-pow' import { default as NanoPowGpuComputeShader } from './shaders/compute.wgsl' @@ -205,7 +205,7 @@ async function init (hash: BigUint64Array, difficulty: bigint): Promise { async function dispatch (dispatchIndex: number, seed: bigint, effort: number): Promise { LOG: logger.log('dispatching compute pass') try { - LOG: logger.log('seed', bigintToHex(seed, 16)) + LOG: logger.log('seed', bigHex(seed, 16)) // Copy seed into INPUT buffer inputDataView.setBigUint64(40, seed, true) @@ -268,8 +268,8 @@ function read (dispatchIndex: number): { work: bigint, difficulty: bigint } { } /** -* Nano proof-of-work using WebGPU. -*/ + * Nano proof-of-work using WebGPU. + */ export async function generate (hash: bigint, difficulty: bigint, effort: number, debug: boolean): Promise { logger.isEnabled = debug // Set up 60s timeout to prevent long-running calls @@ -294,7 +294,7 @@ export async function generate (hash: bigint, difficulty: bigint, effort: number throw new Error('failed to start') } } - await q.add(init, bigintToU64(hash, 4), difficulty) + await q.add(init, bigToU64(hash, 4), difficulty) // Dispatch initial workgroups and set index await dispatch(0, crypto.getRandomValues(seed)[0], effort) let dispatchIndex = 1 @@ -328,8 +328,8 @@ export async function generate (hash: bigint, difficulty: bigint, effort: number } return { - hash: bigintToHex(hash, 64), - work: bigintToHex(result.work, 16), - difficulty: bigintToHex(result.difficulty, 16) + hash: bigHex(hash, 64), + work: bigHex(result.work, 16), + difficulty: bigHex(result.difficulty, 16) } } diff --git a/src/lib/index.ts b/src/lib/index.ts index 0757d8b..660ee59 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -4,44 +4,43 @@ import { NanoPowConfig } from '#lib/config' import { NanoPowCpu, NanoPowWasm, NanoPowWebgl, NanoPowWebgpu } from '#lib/generate' import { NanoPowValidate } from '#lib/validate' -import { Cache, Logger, Queue, bigintFrom } from '#utils' +import { big, Cache, Logger, Queue } from '#utils' import { WorkErrorResponse, WorkGenerateResponse, WorkValidateResponse } from 'nano-pow' const logger = new Logger() const q = new Queue() export async function generate (hash: unknown, options?: unknown): Promise { + const { api, debug, difficulty, effort } = await NanoPowConfig(options) + LOG: logger.isEnabled = debug + const cached = Cache.search(hash, difficulty) + if (cached) { + LOG: logger.log('found work in cache') + const { valid } = NanoPowValidate(big(cached.work), big(cached.hash), difficulty, debug) + if (valid === '1') { + return cached + } else { + try { + Cache.delete(hash) + } catch (err) { + LOG: logger.log('error deleting invalid work from cache, continuing with generate', err) + } + } + } return q.add(async (): Promise => { try { - const { api, debug, difficulty, effort } = await NanoPowConfig(options) - LOG: logger.isEnabled = debug - const bigintHash = bigintFrom(hash, 'hex') - const cached = Cache.search(bigintHash, difficulty) - if (cached) { - LOG: logger.log('found work in cache') - const { valid } = NanoPowValidate(bigintFrom(cached.work, 'hex'), bigintFrom(cached.hash, 'hex'), bigintFrom(cached.difficulty, 'hex'), debug) - if (valid === '1') { - return cached - } else { - try { - Cache.delete(bigintHash) - } catch (err) { - LOG: logger.log('error deleting invalid work from cache, continuing with generate', err) - } - } - } switch (api) { case 'webgpu': { - return Cache.store(await NanoPowWebgpu(bigintHash, difficulty, effort, debug)) + return Cache.store(await NanoPowWebgpu(big(hash), difficulty, effort, debug)) } case 'webgl': { - return Cache.store(await NanoPowWebgl(bigintHash, difficulty, effort, debug)) + return Cache.store(await NanoPowWebgl(big(hash), difficulty, effort, debug)) } case 'wasm': { - return Cache.store(await NanoPowWasm(bigintHash, difficulty, effort, debug)) + return Cache.store(await NanoPowWasm(big(hash), difficulty, effort, debug)) } default: { - return Cache.store(await NanoPowCpu(bigintHash, difficulty, debug)) + return Cache.store(await NanoPowCpu(big(hash), difficulty, debug)) } } } catch (e: any) { @@ -52,10 +51,8 @@ export async function generate (hash: unknown, options?: unknown): Promise { try { - const bigintHash = bigintFrom(hash, 'hex') - const bigintWork = bigintFrom(work, 'hex') const { debug, difficulty } = await NanoPowConfig(options) - const result = await NanoPowValidate(bigintWork, bigintHash, difficulty, debug) + const result = await NanoPowValidate(big(work), big(hash), difficulty, debug) return result } catch (e: any) { return { error: (typeof e === 'string' ? e : (e?.message ?? '')) } diff --git a/src/lib/validate/index.ts b/src/lib/validate/index.ts index 1eb90b9..cf99606 100644 --- a/src/lib/validate/index.ts +++ b/src/lib/validate/index.ts @@ -1,7 +1,7 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { Logger, RECEIVE, SEND, bigintToHex, bigintToU64 } from '#utils' +import { Logger, RECEIVE, SEND, bigHex, bigToU64 } from '#utils' import { WorkValidateResponse } from 'nano-pow' const logger = new Logger() @@ -86,7 +86,7 @@ function init (seed: bigint, hash: BigUint64Array): void { } function blake2b (work: bigint, hash: bigint): void { - init(work, bigintToU64(hash, 4)) + init(work, bigToU64(hash, 4)) for (let i = 0; i < 12; i++) { ROUND(i) } @@ -95,10 +95,10 @@ function blake2b (work: bigint, hash: bigint): void { function log (work: bigint, hash: bigint, difficulty: bigint): void { LOG: logger.groupStart('NanoPow CPU work_validate') - LOG: logger.log('NanoPow CPU work_validate', 'work', bigintToHex(work, 16)) - LOG: logger.log('NanoPow CPU work_validate', 'hash', bigintToHex(hash, 64)) - LOG: logger.log('NanoPow CPU work_validate', 'difficulty', bigintToHex(difficulty, 16)) - LOG: logger.log('NanoPow CPU work_validate', 'result', bigintToHex(result, 16)) + LOG: logger.log('NanoPow CPU work_validate', 'work', bigHex(work, 16)) + LOG: logger.log('NanoPow CPU work_validate', 'hash', bigHex(hash, 64)) + LOG: logger.log('NanoPow CPU work_validate', 'difficulty', bigHex(difficulty, 16)) + LOG: logger.log('NanoPow CPU work_validate', 'result', bigHex(result, 16)) LOG: logger.groupEnd('NanoPow CPU work_validate') } @@ -107,9 +107,9 @@ function validate (work: bigint, hash: bigint, difficulty: bigint, debug: boolea blake2b(work, hash) log(work, hash, difficulty) return { - hash: bigintToHex(hash, 64), - work: bigintToHex(work, 16), - difficulty: bigintToHex(result, 16), + hash: bigHex(hash, 64), + work: bigHex(work, 16), + difficulty: bigHex(result, 16), valid: (result >= difficulty) ? '1' : '0', valid_all: (result >= SEND) ? '1' : '0', valid_receive: (result >= RECEIVE) ? '1' : '0' diff --git a/src/utils/bigint.ts b/src/utils/bigint.ts index 3b19e7e..cc7dd4e 100644 --- a/src/utils/bigint.ts +++ b/src/utils/bigint.ts @@ -1,7 +1,7 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -export function bigintFrom (value: bigint | boolean | number | string | unknown): bigint { +export function big (value: bigint | boolean | number | string | unknown): bigint { switch (typeof value) { case 'bigint': case 'boolean': @@ -18,20 +18,17 @@ export function bigintFrom (value: bigint | boolean | number | string | unknown) } } -export function bigintToHex (int: bigint, length: unknown = 0): string { - if (typeof length !== 'number') { - throw new TypeError('invalid length') - } +export function bigHex (int: bigint, length: number = 0): string { return int.toString(16).padStart(length, '0') } -export function bigintToU32 (int: bigint, length: number): Uint32Array { +export function bigToU32 (int: bigint, length: number): Uint32Array { const u32 = new Uint32Array(length) bigintToUintArray(u32, int) return u32 } -export function bigintToU64 (int: bigint, length: number): BigUint64Array { +export function bigToU64 (int: bigint, length: number): BigUint64Array { const u64 = new BigUint64Array(length) bigintToUintArray(u64, int) return u64 -- 2.52.0