From: Chris Duncan Date: Tue, 7 Jan 2025 13:41:06 +0000 (-0800) Subject: Rename and export PowGl for systems that don't support WebGPU. Update some other... X-Git-Url: https://zoso.dev/?a=commitdiff_plain;h=3cc31b9d9527aeccbcf4b0d7bb8bf277be1bef5e;p=libnemo.git Rename and export PowGl for systems that don't support WebGPU. Update some other names. --- diff --git a/perf/block.perf.js b/perf/block.perf.js index aacb70c..fae621b 100644 --- a/perf/block.perf.js +++ b/perf/block.perf.js @@ -5,13 +5,13 @@ import { assert, average, skip, suite, test } from '#GLOBALS.mjs' import { NANO_TEST_VECTORS } from '#test/TEST_VECTORS.js' -import { PowGpu, SendBlock } from '#dist/main.js' +import { PowGl, PowGpu, SendBlock } from '#dist/main.js' import 'nano-webgl-pow' await suite('Block performance', async () => { const COUNT = 0x20 - await skip(`Customized PoW: Time to calculate proof-of-work for a block hash ${COUNT} times`, async () => { + await skip(`PowGpu: Time to calculate proof-of-work for a block hash ${COUNT} times`, async () => { const times = [] const hashes = [ NANO_TEST_VECTORS.PRIVATE_0, @@ -37,7 +37,33 @@ await suite('Block performance', async () => { console.log(`Maximum: ${max} ms`) }) - await test(`Customized PoW: Time to calculate proof-of-work for a send block ${COUNT} times`, async () => { + await skip(`PowGl: Time to calculate proof-of-work for a block hash ${COUNT} times`, async () => { + const times = [] + const hashes = [ + NANO_TEST_VECTORS.PRIVATE_0, + NANO_TEST_VECTORS.PRIVATE_1, + NANO_TEST_VECTORS.PRIVATE_2, + NANO_TEST_VECTORS.PUBLIC_0, + NANO_TEST_VECTORS.PUBLIC_1, + NANO_TEST_VECTORS.PUBLIC_2 + ] + for (let i = 0; i < 6; i++) { + const start = performance.now() + const work = await PowGl.find(hashes[i]) + const end = performance.now() + times.push(end - start) + console.log(`${work} (${end - start} ms) ${hashes[i]}`) + } + const { total, arithmetic, harmonic, geometric, min, max } = average(times) + console.log(`Total: ${total} ms`) + console.log(`Average: ${arithmetic} ms`) + console.log(`Harmonic: ${harmonic} ms`) + console.log(`Geometric: ${geometric} ms`) + console.log(`Minimum: ${min} ms`) + console.log(`Maximum: ${max} ms`) + }) + + await test(`PowGpu: Time to calculate proof-of-work for a send block ${COUNT} times`, async () => { const times = [] const block = new SendBlock( NANO_TEST_VECTORS.SEND_BLOCK.account, @@ -63,7 +89,7 @@ await suite('Block performance', async () => { console.log(`Maximum: ${max} ms`) }) - await skip(`Original PoW module: Time to calculate proof-of-work for a send block ${COUNT} times`, async () => { + await skip(`nano-webgl-pow: Time to calculate proof-of-work for a send block ${COUNT} times`, async () => { const times = [] for (let i = 0; i < COUNT; i++) { const start = performance.now() diff --git a/src/lib/block.ts b/src/lib/block.ts index 5b898c0..11b969f 100644 --- a/src/lib/block.ts +++ b/src/lib/block.ts @@ -8,7 +8,7 @@ import { dec, hex } from './convert.js' import { NanoNaCl } from './workers/nano-nacl.js' import { Pool } from './pool.js' import { Rpc } from './rpc.js' -import { Pow, PowGpu } from './workers.js' +import { PowGl, PowGpu } from './workers.js' /** * Represents a block as defined by the Nano cryptocurrency protocol. The Block diff --git a/src/lib/workers.ts b/src/lib/workers.ts index b67290d..7271925 100644 --- a/src/lib/workers.ts +++ b/src/lib/workers.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later import { default as Bip44Ckd } from './workers/bip44-ckd.js' import { default as NanoNaCl } from './workers/nano-nacl.js' -import { default as Pow } from './workers/powgl.js' +import { default as PowGl } from './workers/powgl.js' import { default as PowGpu } from './workers/powgpu.js' -export { Bip44Ckd, NanoNaCl, Pow, PowGpu } +export { Bip44Ckd, NanoNaCl, PowGl, PowGpu } diff --git a/src/lib/workers/powgl.ts b/src/lib/workers/powgl.ts index 97a9d81..ef1683a 100644 --- a/src/lib/workers/powgl.ts +++ b/src/lib/workers/powgl.ts @@ -4,9 +4,9 @@ // https://github.com/numtel/nano-webgl-pow import { WorkerInterface } from '../pool.js' -export class Pow extends WorkerInterface { +export class PowGl extends WorkerInterface { static { - Pow.listen() + PowGl.listen() } /** * Calculates proof-of-work as described by the Nano cryptocurrency protocol. @@ -30,7 +30,7 @@ export class Pow extends WorkerInterface { /** * Finds a nonce that satisfies the Nano proof-of-work requirements. * - * @param {string} hashHex - Hexadecimal hash of previous block, or public key for new accounts + * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation */ static async find (hash: string, threshold: number = 0xfffffff8): Promise { @@ -322,7 +322,7 @@ void main() { } static #calculate (hashHex: string, callback: (nonce: string | PromiseLike) => any, threshold: number): void { - if (Pow.#gl == null) throw new Error('WebGL 2 is required') + if (PowGl.#gl == null) throw new Error('WebGL 2 is required') if (!/^[A-F-a-f0-9]{64}$/.test(hashHex)) throw new Error(`invalid_hash ${hashHex}`) if (typeof threshold !== 'number') throw new TypeError(`Invalid threshold ${threshold}`) if (this.#gl == null) throw new Error('WebGL 2 is required') @@ -334,40 +334,40 @@ void main() { uboView.setUint32(i * 2, parseInt(uint32, 16)) } uboView.setUint32(128, threshold, true) - uboView.setFloat32(132, Pow.#WORKLOAD - 1, true) - Pow.#gl.bindBuffer(Pow.#gl.UNIFORM_BUFFER, Pow.#uboBuffer) - Pow.#gl.bufferSubData(Pow.#gl.UNIFORM_BUFFER, 0, uboView) - Pow.#gl.bindBuffer(Pow.#gl.UNIFORM_BUFFER, null) + uboView.setFloat32(132, PowGl.#WORKLOAD - 1, true) + PowGl.#gl.bindBuffer(PowGl.#gl.UNIFORM_BUFFER, PowGl.#uboBuffer) + PowGl.#gl.bufferSubData(PowGl.#gl.UNIFORM_BUFFER, 0, uboView) + PowGl.#gl.bindBuffer(PowGl.#gl.UNIFORM_BUFFER, null) // Draw output until success or progressCallback says to stop const work = new Uint8Array(8) let start: DOMHighResTimeStamp const draw = (): void => { start = performance.now() - if (Pow.#gl == null) throw new Error('WebGL 2 is required') - if (Pow.#query == null) throw new Error('WebGL 2 is required to run queries') - Pow.#gl.clear(Pow.#gl.COLOR_BUFFER_BIT) + if (PowGl.#gl == null) throw new Error('WebGL 2 is required') + if (PowGl.#query == null) throw new Error('WebGL 2 is required to run queries') + PowGl.#gl.clear(PowGl.#gl.COLOR_BUFFER_BIT) // Upload work buffer crypto.getRandomValues(work) - Pow.#gl.bindBuffer(Pow.#gl.UNIFORM_BUFFER, Pow.#workBuffer) - Pow.#gl.bufferSubData(Pow.#gl.UNIFORM_BUFFER, 0, Uint32Array.from(work)) - Pow.#gl.bindBuffer(Pow.#gl.UNIFORM_BUFFER, null) + PowGl.#gl.bindBuffer(PowGl.#gl.UNIFORM_BUFFER, PowGl.#workBuffer) + PowGl.#gl.bufferSubData(PowGl.#gl.UNIFORM_BUFFER, 0, Uint32Array.from(work)) + PowGl.#gl.bindBuffer(PowGl.#gl.UNIFORM_BUFFER, null) - Pow.#gl.beginQuery(Pow.#gl.ANY_SAMPLES_PASSED_CONSERVATIVE, Pow.#query) - Pow.#gl.drawArrays(Pow.#gl.TRIANGLES, 0, 6) - Pow.#gl.endQuery(Pow.#gl.ANY_SAMPLES_PASSED_CONSERVATIVE) + PowGl.#gl.beginQuery(PowGl.#gl.ANY_SAMPLES_PASSED_CONSERVATIVE, PowGl.#query) + PowGl.#gl.drawArrays(PowGl.#gl.TRIANGLES, 0, 6) + PowGl.#gl.endQuery(PowGl.#gl.ANY_SAMPLES_PASSED_CONSERVATIVE) requestAnimationFrame(checkQueryResult) } function checkQueryResult () { - if (Pow.#gl == null) throw new Error('WebGL 2 is required to check query results') - if (Pow.#query == null) throw new Error('Query not found') + if (PowGl.#gl == null) throw new Error('WebGL 2 is required to check query results') + if (PowGl.#query == null) throw new Error('Query not found') console.log(`checking (${performance.now() - start} ms)`) - if (Pow.#gl.getQueryParameter(Pow.#query, Pow.#gl.QUERY_RESULT_AVAILABLE)) { + if (PowGl.#gl.getQueryParameter(PowGl.#query, PowGl.#gl.QUERY_RESULT_AVAILABLE)) { console.log(`AVAILABLE (${performance.now() - start} ms)`) - const anySamplesPassed = Pow.#gl.getQueryParameter(Pow.#query, Pow.#gl.QUERY_RESULT) + const anySamplesPassed = PowGl.#gl.getQueryParameter(PowGl.#query, PowGl.#gl.QUERY_RESULT) if (anySamplesPassed) { // A valid nonce was found readBackResult() @@ -383,17 +383,17 @@ void main() { } } function readBackResult () { - if (Pow.#gl == null) throw new Error('WebGL 2 is required to check read results') - Pow.#gl.readPixels(0, 0, Pow.#gl.drawingBufferWidth, Pow.#gl.drawingBufferHeight, Pow.#gl.RGBA, Pow.#gl.UNSIGNED_BYTE, Pow.#pixels) + if (PowGl.#gl == null) throw new Error('WebGL 2 is required to check read results') + PowGl.#gl.readPixels(0, 0, PowGl.#gl.drawingBufferWidth, PowGl.#gl.drawingBufferHeight, PowGl.#gl.RGBA, PowGl.#gl.UNSIGNED_BYTE, PowGl.#pixels) // Check the pixels for any success - for (let i = 0; i < Pow.#pixels.length; i += 4) { - if (Pow.#pixels[i] !== 0) { + for (let i = 0; i < PowGl.#pixels.length; i += 4) { + if (PowGl.#pixels[i] !== 0) { console.log(`FOUND (${performance.now() - start} ms)`) - const hex = Pow.#hexify(work.subarray(4, 8)) + Pow.#hexify([ - Pow.#pixels[i + 2], - Pow.#pixels[i + 3], - work[2] ^ (Pow.#pixels[i] - 1), - work[3] ^ (Pow.#pixels[i + 1] - 1) + const hex = PowGl.#hexify(work.subarray(4, 8)) + PowGl.#hexify([ + PowGl.#pixels[i + 2], + PowGl.#pixels[i + 3], + work[2] ^ (PowGl.#pixels[i] - 1), + work[3] ^ (PowGl.#pixels[i + 1] - 1) ]) // Return the work value with the custom bits typeof callback === 'function' && callback(hex) @@ -407,5 +407,5 @@ void main() { export default ` const WorkerInterface = ${WorkerInterface} - const Pow = ${Pow} + const PowGl = ${PowGl} ` diff --git a/src/lib/workers/powgpu.ts b/src/lib/workers/powgpu.ts index 9c0e35b..6267259 100644 --- a/src/lib/workers/powgpu.ts +++ b/src/lib/workers/powgpu.ts @@ -463,8 +463,8 @@ export class PowGpu extends WorkerInterface { * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation */ - static async search (hashHex: string, threshold: number = 0xfffffff8): Promise { - if (!/^[A-Fa-f0-9]{64}$/.test(hashHex)) throw new TypeError(`Invalid hash ${hashHex}`) + static async search (hash: string, threshold: number = 0xfffffff8): Promise { + if (!/^[A-Fa-f0-9]{64}$/.test(hash)) throw new TypeError(`Invalid hash ${hash}`) if (typeof threshold !== 'number') throw new TypeError(`Invalid threshold ${threshold}`) // Ensure WebGPU is initialized before calculating, up to a max time frame @@ -474,7 +474,7 @@ export class PowGpu extends WorkerInterface { } return await new Promise(resolve => { setTimeout(() => { - resolve(this.search(hashHex, threshold)) + resolve(this.search(hash, threshold)) }, 100) }) } @@ -484,7 +484,7 @@ export class PowGpu extends WorkerInterface { // Note: u32 size is 4, but total alignment must be multiple of 16 const uboView = new DataView(new ArrayBuffer(48)) for (let i = 0; i < 64; i += 8) { - const uint32 = hashHex.slice(i, i + 8) + const uint32 = hash.slice(i, i + 8) uboView.setUint32(i / 2, parseInt(uint32, 16)) } const random = Math.floor((Math.random() * 0xffffffff)) @@ -548,7 +548,7 @@ export class PowGpu extends WorkerInterface { const hex = nonce.toString(16).padStart(16, '0') return hex } else { - return await this.search(hashHex, threshold) + return await this.search(hash, threshold) } } } diff --git a/src/main.ts b/src/main.ts index 57e4ee7..fc8e66d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,7 +4,7 @@ import { Account } from './lib/account.js' import { Blake2b } from './lib/blake2b.js' import { SendBlock, ReceiveBlock, ChangeBlock } from './lib/block.js' -import { Pow } from './lib/workers/powgl.js' +import { PowGl } from './lib/workers/powgl.js' import { PowGpu } from './lib/workers/powgpu.js' import { Rpc } from './lib/rpc.js' import { Rolodex } from './lib/rolodex.js' @@ -12,4 +12,4 @@ import { Safe } from './lib/safe.js' import { Tools } from './lib/tools.js' import { Bip44Wallet, Blake2bWallet, LedgerWallet } from './lib/wallet.js' -export { Account, Blake2b, SendBlock, ReceiveBlock, ChangeBlock, Pow, PowGpu, Rpc, Rolodex, Safe, Tools, Bip44Wallet, Blake2bWallet, LedgerWallet } +export { Account, Blake2b, SendBlock, ReceiveBlock, ChangeBlock, PowGl, PowGpu, Rpc, Rolodex, Safe, Tools, Bip44Wallet, Blake2bWallet, LedgerWallet }