]> zoso.dev Git - libnemo.git/commitdiff
Define class members as private except for public find() function intended for enduser.
authorChris Duncan <chris@zoso.dev>
Sun, 15 Dec 2024 07:48:34 +0000 (23:48 -0800)
committerChris Duncan <chris@zoso.dev>
Sun, 15 Dec 2024 07:48:34 +0000 (23:48 -0800)
src/lib/workers/pow.ts

index 27083b8c2b0dee14433cdba73d3bb4605814f3bd..a8752aed73f7b97b0d494557831c35490e3badc5 100644 (file)
@@ -2,14 +2,13 @@
 // SPDX-License-Identifier: GPL-3.0-or-later
 
 export class Pow {
-
        /**
        * 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 {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
        */
-       static async find (hash: string, threshold: number = this.SEND_THRESHOLD): Promise<string> {
+       static async find (hash: string, threshold: number = 0xfffffff8): Promise<string> {
                return new Promise<string>(resolve => {
                        this.#calculate(hash, resolve, threshold)
                })
@@ -22,7 +21,7 @@ export class Pow {
        * License: MIT
        */
        // Vertext Shader
-       static vsSource = `#version 300 es
+       static #vsSource = `#version 300 es
 precision highp float;
 layout (location=0) in vec4 position;
 layout (location=1) in vec2 uv;
@@ -35,7 +34,7 @@ void main() {
 }`
 
        // Fragment shader
-       static fsSource = `#version 300 es
+       static #fsSource = `#version 300 es
 precision highp float;
 precision highp int;
 
@@ -199,12 +198,11 @@ void main() {
        }
 }`
 
-       static SEND_THRESHOLD = 0xFFFFFFF8
        /** Used to set canvas size. Must be a multiple of 256. */
-       static WORKLOAD: number = 256 * Math.max(1, Math.floor(navigator.hardwareConcurrency / 2))
-       static work0 = new Uint8Array(4)
-       static work1 = new Uint8Array(4)
-       static SIGMA82: number[] = [
+       static #WORKLOAD: number = 256 * Math.max(1, Math.floor(navigator.hardwareConcurrency / 2))
+       static #work0 = new Uint8Array(4)
+       static #work1 = new Uint8Array(4)
+       static #SIGMA82: number[] = [
                0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 28, 20, 8, 16, 18, 30, 26, 12, 2, 24,
                0, 4, 22, 14, 10, 6, 22, 16, 24, 0, 10, 4, 30, 26, 20, 28, 6, 12, 14, 2, 18, 8, 14, 18, 6, 2, 26,
                24, 22, 28, 4, 12, 10, 20, 8, 0, 30, 16, 18, 0, 10, 14, 4, 8, 20, 30, 28, 2, 22, 24, 12, 16, 6,
@@ -214,30 +212,29 @@ void main() {
                26, 0, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 28, 20, 8, 16, 18, 30, 26, 12,
                2, 24, 0, 4, 22, 14, 10, 6
        ]
-       static B2B_G_params: number[] = []
+       static #B2B_G_params: number[] = []
        static {
                for (let i = 0; i < 12; i++) {
-                       this.B2B_G_params.push(this.SIGMA82[i * 16 + 0])
-                       this.B2B_G_params.push(this.SIGMA82[i * 16 + 1])
-                       this.B2B_G_params.push(this.SIGMA82[i * 16 + 2])
-                       this.B2B_G_params.push(this.SIGMA82[i * 16 + 3])
-                       this.B2B_G_params.push(this.SIGMA82[i * 16 + 4])
-                       this.B2B_G_params.push(this.SIGMA82[i * 16 + 5])
-                       this.B2B_G_params.push(this.SIGMA82[i * 16 + 6])
-                       this.B2B_G_params.push(this.SIGMA82[i * 16 + 7])
-                       this.B2B_G_params.push(this.SIGMA82[i * 16 + 8])
-                       this.B2B_G_params.push(this.SIGMA82[i * 16 + 9])
-                       this.B2B_G_params.push(this.SIGMA82[i * 16 + 10])
-                       this.B2B_G_params.push(this.SIGMA82[i * 16 + 11])
-                       this.B2B_G_params.push(this.SIGMA82[i * 16 + 12])
-                       this.B2B_G_params.push(this.SIGMA82[i * 16 + 13])
-                       this.B2B_G_params.push(this.SIGMA82[i * 16 + 14])
-                       this.B2B_G_params.push(this.SIGMA82[i * 16 + 15])
+                       this.#B2B_G_params.push(this.#SIGMA82[i * 16 + 0])
+                       this.#B2B_G_params.push(this.#SIGMA82[i * 16 + 1])
+                       this.#B2B_G_params.push(this.#SIGMA82[i * 16 + 2])
+                       this.#B2B_G_params.push(this.#SIGMA82[i * 16 + 3])
+                       this.#B2B_G_params.push(this.#SIGMA82[i * 16 + 4])
+                       this.#B2B_G_params.push(this.#SIGMA82[i * 16 + 5])
+                       this.#B2B_G_params.push(this.#SIGMA82[i * 16 + 6])
+                       this.#B2B_G_params.push(this.#SIGMA82[i * 16 + 7])
+                       this.#B2B_G_params.push(this.#SIGMA82[i * 16 + 8])
+                       this.#B2B_G_params.push(this.#SIGMA82[i * 16 + 9])
+                       this.#B2B_G_params.push(this.#SIGMA82[i * 16 + 10])
+                       this.#B2B_G_params.push(this.#SIGMA82[i * 16 + 11])
+                       this.#B2B_G_params.push(this.#SIGMA82[i * 16 + 12])
+                       this.#B2B_G_params.push(this.#SIGMA82[i * 16 + 13])
+                       this.#B2B_G_params.push(this.#SIGMA82[i * 16 + 14])
+                       this.#B2B_G_params.push(this.#SIGMA82[i * 16 + 15])
                }
        }
 
-
-       static hexify (arr: number[] | Uint8Array): string {
+       static #hexify (arr: number[] | Uint8Array): string {
                let out = ''
                for (let i = arr.length - 1; i >= 0; i--) {
                        out += arr[i].toString(16).padStart(2, '0')
@@ -245,7 +242,7 @@ void main() {
                return out
        }
 
-       static processHash (hashHex: string): Uint32Array {
+       static #processHash (hashHex: string): Uint32Array {
                if (!/^[A-F-a-f0-9]{64}$/.test(hashHex)) {
                        throw new Error(`invalid_hash ${hashHex}`)
                }
@@ -264,105 +261,105 @@ void main() {
        B2B_G(0, 8, 16, 24, SIGMA82[i * 16 + 0], SIGMA82[i * 16 + 1]);
        */
 
-       static gl: WebGL2RenderingContext | null
-       static program: WebGLProgram | null
-       static work0Location: WebGLUniformLocation | null
-       static work1Location: WebGLUniformLocation | null
-       static blockHashLocation: WebGLUniformLocation | null
-       static thresholdLocation: WebGLUniformLocation | null
-       static workloadLocation: WebGLUniformLocation | null
-       static vertexShader: WebGLShader | null
-       static fragmentShader: WebGLShader | null
-       static positionBuffer: WebGLBuffer | null
-       static uvBuffer: WebGLBuffer | null
+       static #gl: WebGL2RenderingContext | null
+       static #program: WebGLProgram | null
+       static #work0Location: WebGLUniformLocation | null
+       static #work1Location: WebGLUniformLocation | null
+       static #blockHashLocation: WebGLUniformLocation | null
+       static #thresholdLocation: WebGLUniformLocation | null
+       static #workloadLocation: WebGLUniformLocation | null
+       static #vertexShader: WebGLShader | null
+       static #fragmentShader: WebGLShader | null
+       static #positionBuffer: WebGLBuffer | null
+       static #uvBuffer: WebGLBuffer | null
        // Vertex Positions, 2 triangles
-       static positions = new Float32Array([
+       static #positions = new Float32Array([
                -1, -1, 0, -1, 1, 0, 1, 1, 0,
                1, -1, 0, 1, 1, 0, -1, -1, 0
        ])
        // Texture Positions
-       static uvPosArray = new Float32Array([
+       static #uvPosArray = new Float32Array([
                1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1
        ])
 
        // Compile
        static {
-               this.gl = new OffscreenCanvas(this.WORKLOAD, this.WORKLOAD).getContext('webgl2')
-               if (this.gl == null) throw new Error('WebGL 2 is required')
-
-               this.program = this.gl.createProgram()
-               if (this.program == null) throw new Error('Failed to create shader program')
-
-               this.vertexShader = this.gl.createShader(this.gl.VERTEX_SHADER)
-               if (this.vertexShader == null) throw new Error('Failed to create vertex shader')
-               this.gl.shaderSource(this.vertexShader, this.vsSource)
-               this.gl.compileShader(this.vertexShader)
-               if (!this.gl.getShaderParameter(this.vertexShader, this.gl.COMPILE_STATUS))
-                       throw new Error(this.gl.getShaderInfoLog(this.vertexShader) ?? `Failed to compile vertex shader`)
-
-               this.fragmentShader = this.gl.createShader(this.gl.FRAGMENT_SHADER)
-               if (this.fragmentShader == null) throw new Error('Failed to create fragment shader')
-               this.gl.shaderSource(this.fragmentShader, this.fsSource)
-               this.gl.compileShader(this.fragmentShader)
-               if (!this.gl.getShaderParameter(this.fragmentShader, this.gl.COMPILE_STATUS))
-                       throw new Error(this.gl.getShaderInfoLog(this.fragmentShader) ?? `Failed to compile fragment shader`)
-
-               this.gl.attachShader(this.program, this.vertexShader)
-               this.gl.attachShader(this.program, this.fragmentShader)
-               this.gl.linkProgram(this.program)
-               if (!this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS))
-                       throw new Error(this.gl.getProgramInfoLog(this.program) ?? `Failed to link program`)
+               this.#gl = new OffscreenCanvas(this.#WORKLOAD, this.#WORKLOAD).getContext('webgl2')
+               if (this.#gl == null) throw new Error('WebGL 2 is required')
+
+               this.#program = this.#gl.createProgram()
+               if (this.#program == null) throw new Error('Failed to create shader program')
+
+               this.#vertexShader = this.#gl.createShader(this.#gl.VERTEX_SHADER)
+               if (this.#vertexShader == null) throw new Error('Failed to create vertex shader')
+               this.#gl.shaderSource(this.#vertexShader, this.#vsSource)
+               this.#gl.compileShader(this.#vertexShader)
+               if (!this.#gl.getShaderParameter(this.#vertexShader, this.#gl.COMPILE_STATUS))
+                       throw new Error(this.#gl.getShaderInfoLog(this.#vertexShader) ?? `Failed to compile vertex shader`)
+
+               this.#fragmentShader = this.#gl.createShader(this.#gl.FRAGMENT_SHADER)
+               if (this.#fragmentShader == null) throw new Error('Failed to create fragment shader')
+               this.#gl.shaderSource(this.#fragmentShader, this.#fsSource)
+               this.#gl.compileShader(this.#fragmentShader)
+               if (!this.#gl.getShaderParameter(this.#fragmentShader, this.#gl.COMPILE_STATUS))
+                       throw new Error(this.#gl.getShaderInfoLog(this.#fragmentShader) ?? `Failed to compile fragment shader`)
+
+               this.#gl.attachShader(this.#program, this.#vertexShader)
+               this.#gl.attachShader(this.#program, this.#fragmentShader)
+               this.#gl.linkProgram(this.#program)
+               if (!this.#gl.getProgramParameter(this.#program, this.#gl.LINK_STATUS))
+                       throw new Error(this.#gl.getProgramInfoLog(this.#program) ?? `Failed to link program`)
 
                // Construct simple 2D geometry
-               this.gl.useProgram(this.program)
-               const triangleArray = this.gl.createVertexArray()
-               this.gl.bindVertexArray(triangleArray)
-
-               this.positionBuffer = this.gl.createBuffer()
-               this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer)
-               this.gl.bufferData(this.gl.ARRAY_BUFFER, this.positions, this.gl.STATIC_DRAW)
-               this.gl.vertexAttribPointer(0, 3, this.gl.FLOAT, false, 0, 0)
-               this.gl.enableVertexAttribArray(0)
-
-               const uvBuffer = this.gl.createBuffer()
-               this.gl.bindBuffer(this.gl.ARRAY_BUFFER, uvBuffer)
-               this.gl.bufferData(this.gl.ARRAY_BUFFER, this.uvPosArray, this.gl.STATIC_DRAW)
-               this.gl.vertexAttribPointer(1, 2, this.gl.FLOAT, false, 0, 0)
-               this.gl.enableVertexAttribArray(1)
-
-               this.work0Location = this.gl.getUniformLocation(this.program, 'u_work0')
-               this.work1Location = this.gl.getUniformLocation(this.program, 'u_work1')
-               this.blockHashLocation = this.gl.getUniformLocation(this.program, "blockHash")
-               this.thresholdLocation = this.gl.getUniformLocation(this.program, "threshold")
-               this.workloadLocation = this.gl.getUniformLocation(this.program, "workload")
+               this.#gl.useProgram(this.#program)
+               const triangleArray = this.#gl.createVertexArray()
+               this.#gl.bindVertexArray(triangleArray)
+
+               this.#positionBuffer = this.#gl.createBuffer()
+               this.#gl.bindBuffer(this.#gl.ARRAY_BUFFER, this.#positionBuffer)
+               this.#gl.bufferData(this.#gl.ARRAY_BUFFER, this.#positions, this.#gl.STATIC_DRAW)
+               this.#gl.vertexAttribPointer(0, 3, this.#gl.FLOAT, false, 0, 0)
+               this.#gl.enableVertexAttribArray(0)
+
+               this.#uvBuffer = this.#gl.createBuffer()
+               this.#gl.bindBuffer(this.#gl.ARRAY_BUFFER, this.#uvBuffer)
+               this.#gl.bufferData(this.#gl.ARRAY_BUFFER, this.#uvPosArray, this.#gl.STATIC_DRAW)
+               this.#gl.vertexAttribPointer(1, 2, this.#gl.FLOAT, false, 0, 0)
+               this.#gl.enableVertexAttribArray(1)
+
+               this.#work0Location = this.#gl.getUniformLocation(this.#program, 'u_work0')
+               this.#work1Location = this.#gl.getUniformLocation(this.#program, 'u_work1')
+               this.#blockHashLocation = this.#gl.getUniformLocation(this.#program, "blockHash")
+               this.#thresholdLocation = this.#gl.getUniformLocation(this.#program, "threshold")
+               this.#workloadLocation = this.#gl.getUniformLocation(this.#program, "workload")
        }
 
-       static #calculate (hashHex: string, callback: (nonce: string | PromiseLike<string>) => any, threshold: number = this.SEND_THRESHOLD): void {
+       static #calculate (hashHex: string, callback: (nonce: string | PromiseLike<string>) => any, threshold: number): void {
                if (typeof threshold !== 'number') throw new TypeError(`Invalid threshold ${threshold}`)
-               if (this.gl == null) throw new Error('WebGL 2 is required')
-               this.gl.clearColor(0, 0, 0, 1)
-               const hashBytes: Uint32Array = this.processHash(hashHex)
+               if (this.#gl == null) throw new Error('WebGL 2 is required')
+               this.#gl.clearColor(0, 0, 0, 1)
+               const hashBytes: Uint32Array = this.#processHash(hashHex)
 
                // Draw output until success or progressCallback says to stop
                let n = 0
                const frameTimes: number[] = []
                const draw = (): void => {
                        n++
-                       if (Pow.gl == null) throw new Error('webgl2_required')
+                       if (Pow.#gl == null) throw new Error('WebGL 2 is required')
                        performance.mark('start')
-                       crypto.getRandomValues(Pow.work0)
-                       crypto.getRandomValues(Pow.work1)
-
-                       Pow.gl.uniform4uiv(Pow.work0Location, this.work0)
-                       Pow.gl.uniform4uiv(Pow.work1Location, this.work1)
-                       Pow.gl.uniform1uiv(Pow.blockHashLocation, hashBytes)
-                       Pow.gl.uniform1ui(Pow.thresholdLocation, threshold)
-                       Pow.gl.uniform1f(Pow.workloadLocation, this.WORKLOAD - 1)
-
-                       Pow.gl.clear(Pow.gl.COLOR_BUFFER_BIT)
-                       Pow.gl.drawArrays(Pow.gl.TRIANGLES, 0, 6)
-                       const pixels = new Uint8Array(Pow.gl.drawingBufferWidth * Pow.gl.drawingBufferHeight * 4)
-                       Pow.gl.readPixels(0, 0, Pow.gl.drawingBufferWidth, Pow.gl.drawingBufferHeight, Pow.gl.RGBA, Pow.gl.UNSIGNED_BYTE, pixels)
+                       crypto.getRandomValues(Pow.#work0)
+                       crypto.getRandomValues(Pow.#work1)
+
+                       Pow.#gl.uniform4uiv(Pow.#work0Location, this.#work0)
+                       Pow.#gl.uniform4uiv(Pow.#work1Location, this.#work1)
+                       Pow.#gl.uniform1uiv(Pow.#blockHashLocation, hashBytes)
+                       Pow.#gl.uniform1ui(Pow.#thresholdLocation, threshold)
+                       Pow.#gl.uniform1f(Pow.#workloadLocation, this.#WORKLOAD - 1)
+
+                       Pow.#gl.clear(Pow.#gl.COLOR_BUFFER_BIT)
+                       Pow.#gl.drawArrays(Pow.#gl.TRIANGLES, 0, 6)
+                       const pixels = new Uint8Array(Pow.#gl.drawingBufferWidth * Pow.#gl.drawingBufferHeight * 4)
+                       Pow.#gl.readPixels(0, 0, Pow.#gl.drawingBufferWidth, Pow.#gl.drawingBufferHeight, Pow.#gl.RGBA, Pow.#gl.UNSIGNED_BYTE, pixels)
                        // Check the pixels for any success
                        for (let i = 0; i < pixels.length; i += 4) {
                                if (pixels[i] !== 0) {
@@ -371,11 +368,11 @@ void main() {
                                        performance.clearMarks()
                                        console.log(`average frame time: ${(frameTimes.reduce((a, b) => a + b)) / frameTimes.length} ms`)
                                        console.log(`frames calculated: ${n}`)
-                                       const hex = this.hexify(this.work1) + this.hexify([
+                                       const hex = this.#hexify(this.#work1) + this.#hexify([
                                                pixels[i + 2],
                                                pixels[i + 3],
-                                               this.work0[2] ^ (pixels[i] - 1),
-                                               this.work0[3] ^ (pixels[i + 1] - 1)
+                                               this.#work0[2] ^ (pixels[i] - 1),
+                                               this.#work0[3] ^ (pixels[i + 1] - 1)
                                        ])
                                        // Return the work value with the custom bits
                                        typeof callback === 'function' && callback(hex)