]> zoso.dev Git - libnemo.git/commitdiff
Rename and export PowGl for systems that don't support WebGPU. Update some other...
authorChris Duncan <chris@zoso.dev>
Tue, 7 Jan 2025 13:41:06 +0000 (05:41 -0800)
committerChris Duncan <chris@zoso.dev>
Tue, 7 Jan 2025 13:41:06 +0000 (05:41 -0800)
perf/block.perf.js
src/lib/block.ts
src/lib/workers.ts
src/lib/workers/powgl.ts
src/lib/workers/powgpu.ts
src/main.ts

index aacb70c11009634f4cef8f4292b90c8700b1f3e9..fae621baf6ec1c2a2ad31cd524fba69113020192 100644 (file)
@@ -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()
index 5b898c01811651e95b7a7b7cb28b6244c2635ff0..11b969f923a3074f11c9b934028b3800d601078c 100644 (file)
@@ -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
index b67290d29c7ba8b9ff83b97615fdcef292b49b0a..7271925c846059c4abe08f86fb90c47c31728a95 100644 (file)
@@ -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 }
index 97a9d8142de37b5e30142473d875bec3bda1835d..ef1683a2e7fb3b27108bf2a398a1f33544f2800e 100644 (file)
@@ -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<string> {
@@ -322,7 +322,7 @@ void main() {
        }
 
        static #calculate (hashHex: string, callback: (nonce: string | PromiseLike<string>) => 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}
 `
index 9c0e35b0b79c58a465b8157560689c88f500ddd3..62672592259392e3097613530f0209983ebd9f5d 100644 (file)
@@ -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<string> {
-               if (!/^[A-Fa-f0-9]{64}$/.test(hashHex)) throw new TypeError(`Invalid hash ${hashHex}`)
+       static async search (hash: string, threshold: number = 0xfffffff8): Promise<string> {
+               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)
                }
        }
 }
index 57e4ee7c807321fc53e1aaad7de6720acb8ac9a9..fc8e66dd5c7e027d8398b5f5067d46f5c6eeff69 100644 (file)
@@ -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 }