]> zoso.dev Git - libnemo.git/commitdiff
Convert IIFE to regular set of functions called from worker implementation. Use worke...
authorChris Duncan <chris@zoso.dev>
Tue, 3 Dec 2024 20:25:23 +0000 (12:25 -0800)
committerChris Duncan <chris@zoso.dev>
Tue, 3 Dec 2024 20:25:23 +0000 (12:25 -0800)
src/lib/pow.ts

index 28f7eb39a5d6573e109727c264bd17367cb2c872..24489d44e254f4df78d1b5d6f2a71b1f78015bcb 100644 (file)
 // SPDX-License-Identifier: GPL-3.0-or-later
 //@ts-nocheck
 import { Blake2b } from './blake2b.js'
-// nano-webgl-pow
-// Nano Currency Proof of Work Value generation using WebGL2
-// Author:  numtel <ben@latenightsketches.com>
-// License: MIT
-
-// window.NanoWebglPow(hashHex, callback, progressCallback, threshold);
-// @param hashHex           String   Previous Block Hash as Hex String
-// @param callback          Function Called when work value found
-//   Receives single string argument, work value as hex
-// @param progressCallback  Function Optional
-//   Receives single argument: n, number of frames so far
-//   Return true to abort
-// @param threshold         Number|String   Optional difficulty threshold (default=0xFFFFFFF8 since v21)
-
-(function () {
-
-  function array_hex (arr, index, length) {
-    let out = ''
-    for (let i = length - 1; i > -1; i--) {
-      out += (arr[i] > 15 ? '' : '0') + arr[i].toString(16)
-    }
-    return out
-  }
-
-  function hex_reverse (hex) {
-    let out = ''
-    for (let i = hex.length; i > 0; i -= 2) {
-      out += hex.slice(i - 2, i)
-    }
-    return out
-  }
-
-  function calculate (hashHex, callback, progressCallback, threshold = '0xFFFFFFF8') {
-    if (typeof threshold === 'number') threshold = '0x' + threshold.toString(16)
-
-    const canvas = document.createElement('canvas')
-
-    canvas.width = window.NanoWebglPow.width
-    canvas.height = window.NanoWebglPow.height
-
-    const gl = canvas.getContext('webgl2')
-
-    if (!gl)
-      throw new Error('webgl2_required')
-
-    if (!/^[A-F-a-f0-9]{64}$/.test(hashHex))
-      throw new Error('invalid_hash')
-
-    gl.clearColor(0, 0, 0, 1)
-
-    const reverseHex = hex_reverse(hashHex)
 
-    // Vertext Shader
-    const vsSource = `#version 300 es
+const p = () => {
+       const NONCE_BYTES = 8
+       const RECEIVE_THRESHOLD = '0xfffffe'
+       const SEND_THRESHOLD = '0xfffffff8'
+
+       /**
+       * Listens for messages from a calling function.
+       */
+       addEventListener('message', (message) => {
+               const data = JSON.parse(new TextDecoder().decode(message.data ?? message))
+               for (const d of data) {
+                       if (d === 'stop') {
+                               close()
+                               postMessage(new ArrayBuffer(0))
+                       } else {
+                               find(d.hash, d.threshold ?? SEND_THRESHOLD).then(nonce => {
+                                       console.log(`pow found: ${nonce}`)
+                                       d.work = nonce
+                                       const buf = new TextEncoder().encode(JSON.stringify(data)).buffer
+                                       //@ts-expect-error
+                                       postMessage(buf, [buf])
+                               })
+                       }
+               }
+       })
+
+       async function find (hash: string, threshold: string = SEND_THRESHOLD): Promise<void> {
+               console.log(`hash: ${hash}`)
+               return new Promise(resolve => {
+                       calculate(hash, resolve, console.log, threshold)
+               })
+               // let result = null
+               // let count = 0
+               // do {
+               //   count++
+               //   const nonce: Uint8Array = new Uint8Array(NONCE_BYTES)
+               //   crypto.getRandomValues(nonce)
+               //   const test: string = new Blake2b(NONCE_BYTES)
+               //     .update(nonce)
+               //     .update(parseHex(hash))
+               //     .digest('hex') as string
+               //   if (count % 1000 === 0) console.log(`${count} hashes...`)
+               //   if (BigInt(`0x${test}`) >= BigInt(`0x${threshold}`)) {
+               //     result = nonce
+               //   }
+               // } while (result == null)
+               // return result
+       }
+
+       /**
+       * nano-webgl-pow
+       * Nano Currency Proof of Work Value generation using WebGL2
+       * Author:  numtel <ben@latenightsketches.com>
+       * License: MIT
+
+       * self.NanoWebglPow(hashHex, callback, progressCallback, threshold);
+       * @param hashHex           String   Previous Block Hash as Hex String
+       * @param callback          Function Called when work value found
+       *   Receives single string argument, work value as hex
+       * @param progressCallback  Function Optional
+       *   Receives single argument: n, number of frames so far
+       *   Return true to abort
+       * @param threshold         Number|String   Optional difficulty threshold (default=0xFFFFFFF8 since v21)
+       */
+
+       // Both width and height must be multiple of 256, (one byte)
+       // but do not need to be the same,
+       // matching GPU capabilities is the aim
+       const webglWidth = 256 * 2
+       const webglHeight = 256 * 2
+
+       function hexify (arr: number[] | Uint8Array): string {
+               let out = ''
+               for (let i = arr.length - 1; i >= 0; i--) {
+                       out += arr[i].toString(16).padStart(2, '0')
+               }
+               return out
+       }
+
+       function hex_reverse (hex: string): string {
+               let out = ''
+               for (let i = hex.length; i > 0; i -= 2) {
+                       out += hex.slice(i - 2, i)
+               }
+               return out
+       }
+
+       function calculate (hashHex, callback, progressCallback, threshold = '0xFFFFFFF8') {
+               if (typeof threshold === 'number') threshold = '0x' + threshold.toString(16)
+
+               const canvas = new OffscreenCanvas(webglWidth, webglHeight)
+               const gl = canvas.getContext('webgl2')
+
+               if (!gl)
+                       throw new Error('webgl2_required')
+
+               if (!/^[A-F-a-f0-9]{64}$/.test(hashHex))
+                       throw new Error(`invalid_hash ${hashHex}`)
+
+               gl.clearColor(0, 0, 0, 1)
+
+               const reverseHex = hex_reverse(hashHex)
+
+               // Vertext Shader
+               const vsSource = `#version 300 es
     precision highp float;
     layout (location=0) in vec4 position;
     layout (location=1) in vec2 uv;
@@ -67,8 +119,8 @@ import { Blake2b } from './blake2b.js'
       gl_Position = position;
     }`
 
-    // Fragment shader
-    const fsSource = `#version 300 es
+               // Fragment shader
+               const fsSource = `#version 300 es
     precision highp float;
     precision highp int;
 
@@ -230,166 +282,105 @@ import { Blake2b } from './blake2b.js'
       }
     }`
 
-    const vertexShader = gl.createShader(gl.VERTEX_SHADER)
-    gl.shaderSource(vertexShader, vsSource)
-    gl.compileShader(vertexShader)
-
-    if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS))
-      throw gl.getShaderInfoLog(vertexShader)
-
-    const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
-    gl.shaderSource(fragmentShader, fsSource)
-    gl.compileShader(fragmentShader)
-
-    if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS))
-      throw gl.getShaderInfoLog(fragmentShader)
-
-    const program = gl.createProgram()
-    gl.attachShader(program, vertexShader)
-    gl.attachShader(program, fragmentShader)
-    gl.linkProgram(program)
-
-    if (!gl.getProgramParameter(program, gl.LINK_STATUS))
-      throw gl.getProgramInfoLog(program)
-
-    gl.useProgram(program)
-
-    // Construct simple 2D geometry
-    const triangleArray = gl.createVertexArray()
-    gl.bindVertexArray(triangleArray)
-
-    // Vertex Positions, 2 triangles
-    const positions = new Float32Array([
-      -1, -1, 0, -1, 1, 0, 1, 1, 0,
-      1, -1, 0, 1, 1, 0, -1, -1, 0
-    ])
-    const positionBuffer = gl.createBuffer()
-    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)
-    gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW)
-    gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0)
-    gl.enableVertexAttribArray(0)
-
-    // Texture Positions
-    const uvPosArray = new Float32Array([
-      1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1
-    ])
-    const uvBuffer = gl.createBuffer()
-    gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer)
-    gl.bufferData(gl.ARRAY_BUFFER, uvPosArray, gl.STATIC_DRAW)
-    gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0)
-    gl.enableVertexAttribArray(1)
-
-    const work0Location = gl.getUniformLocation(program, 'u_work0')
-    const work1Location = gl.getUniformLocation(program, 'u_work1')
-
-    // Draw output until success or progressCallback says to stop
-    const work0 = new Uint8Array(4)
-    const work1 = new Uint8Array(4)
-    let n = 0
-
-    function draw () {
-      n++
-      window.crypto.getRandomValues(work0)
-      window.crypto.getRandomValues(work1)
-
-      gl.uniform4uiv(work0Location, Array.from(work0))
-      gl.uniform4uiv(work1Location, Array.from(work1))
-
-      // Check with progressCallback every 100 frames
-      if (n % 100 === 0 && typeof progressCallback === 'function' && progressCallback(n))
-        return
-
-      gl.clear(gl.COLOR_BUFFER_BIT)
-      gl.drawArrays(gl.TRIANGLES, 0, 6)
-      const pixels = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4)
-      gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels)
-
-      // Check the pixels for any success
-      for (let i = 0; i < pixels.length; i += 4) {
-        if (pixels[i] !== 0) {
-          // Return the work value with the custom bits
-          typeof callback === 'function' &&
-            callback(
-              array_hex(work1, 0, 4) +
-              array_hex([
-                pixels[i + 2],
-                pixels[i + 3],
-                work0[2] ^ (pixels[i] - 1),
-                work0[3] ^ (pixels[i + 1] - 1)
-              ], 0, 4), n)
-          return
-        }
-      }
-      // Nothing found yet, try again
-      window.requestAnimationFrame(draw)
-    }
-
-    // Begin generation
-    window.requestAnimationFrame(draw)
-  }
-
-  window.NanoWebglPow = calculate
-  // Both width and height must be multiple of 256, (one byte)
-  // but do not need to be the same,
-  // matching GPU capabilities is the aim
-  window.NanoWebglPow.width = 256 * 2
-  window.NanoWebglPow.height = 256 * 2
-
-})()
-
-
-const p = () => {
-  const NONCE_BYTES = 8
-  const RECEIVE_THRESHOLD = 'fffffe0000000000'
-  const SEND_THRESHOLD = 'fffffff800000000'
-
-  /**
-  * Listens for messages from a calling function.
-  */
-  addEventListener('message', (message) => {
-    const data = JSON.parse(new TextDecoder().decode(message.data ?? message))
-    if (data === 'stop') close()
-    for (const d of data) {
-      find(d.hash, d.threshold).then(nonce => {
-        console.log('pow found')
-        d.work = nonce
-        const buf = new TextEncoder().encode(JSON.stringify(data)).buffer
-        //@ts-expect-error
-        postMessage(buf, [buf])
-      })
-    }
-  })
-
-  async function find (hash: string, threshold: string = SEND_THRESHOLD) {
-    return new Promise((resolve, reject) => {
-      window.NanoWebglPow(hash, resolve, console.log)
-
-    })
-    // let result = null
-    // let count = 0
-    // do {
-    //   count++
-    //   const nonce: Uint8Array = new Uint8Array(NONCE_BYTES)
-    //   crypto.getRandomValues(nonce)
-    //   const test: string = new Blake2b(NONCE_BYTES)
-    //     .update(nonce)
-    //     .update(parseHex(hash))
-    //     .digest('hex') as string
-    //   if (count % 1000 === 0) console.log(`${count} hashes...`)
-    //   if (BigInt(`0x${test}`) >= BigInt(`0x${threshold}`)) {
-    //     result = nonce
-    //   }
-    // } while (result == null)
-    // return result
-  }
-
-  function parseHex (hex: string) {
-    if (hex.length % 2 === 1) hex = `0${hex}`
-    const arr = hex.match(/.{1,2}/g)?.map(byte => parseInt(byte, 16))
-    return Uint8Array.from(arr ?? [])
-  }
-
-  return { find }
+               const vertexShader = gl.createShader(gl.VERTEX_SHADER)
+               gl.shaderSource(vertexShader, vsSource)
+               gl.compileShader(vertexShader)
+
+               if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS))
+                       throw gl.getShaderInfoLog(vertexShader)
+
+               const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
+               gl.shaderSource(fragmentShader, fsSource)
+               gl.compileShader(fragmentShader)
+
+               if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS))
+                       throw gl.getShaderInfoLog(fragmentShader)
+
+               const program = gl.createProgram()
+               gl.attachShader(program, vertexShader)
+               gl.attachShader(program, fragmentShader)
+               gl.linkProgram(program)
+
+               if (!gl.getProgramParameter(program, gl.LINK_STATUS))
+                       throw gl.getProgramInfoLog(program)
+
+               gl.useProgram(program)
+
+               // Construct simple 2D geometry
+               const triangleArray = gl.createVertexArray()
+               gl.bindVertexArray(triangleArray)
+
+               // Vertex Positions, 2 triangles
+               const positions = new Float32Array([
+                       -1, -1, 0, -1, 1, 0, 1, 1, 0,
+                       1, -1, 0, 1, 1, 0, -1, -1, 0
+               ])
+               const positionBuffer = gl.createBuffer()
+               gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)
+               gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW)
+               gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0)
+               gl.enableVertexAttribArray(0)
+
+               // Texture Positions
+               const uvPosArray = new Float32Array([
+                       1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1
+               ])
+               const uvBuffer = gl.createBuffer()
+               gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer)
+               gl.bufferData(gl.ARRAY_BUFFER, uvPosArray, gl.STATIC_DRAW)
+               gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0)
+               gl.enableVertexAttribArray(1)
+
+               const work0Location = gl.getUniformLocation(program, 'u_work0')
+               const work1Location = gl.getUniformLocation(program, 'u_work1')
+
+               // Draw output until success or progressCallback says to stop
+               const work0 = new Uint8Array(4)
+               const work1 = new Uint8Array(4)
+               let n = 0
+
+               function draw () {
+                       n++
+                       crypto.getRandomValues(work0)
+                       crypto.getRandomValues(work1)
+
+                       gl.uniform4uiv(work0Location, Array.from(work0))
+                       gl.uniform4uiv(work1Location, Array.from(work1))
+
+                       // Check with progressCallback every 100 frames
+                       if (n % 100 === 0 && typeof progressCallback === 'function' && progressCallback(n))
+                               return
+
+                       gl.clear(gl.COLOR_BUFFER_BIT)
+                       gl.drawArrays(gl.TRIANGLES, 0, 6)
+                       const pixels = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4)
+                       gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels)
+
+                       // Check the pixels for any success
+                       for (let i = 0; i < pixels.length; i += 4) {
+                               if (pixels[i] !== 0) {
+                                       // Return the work value with the custom bits
+                                       typeof callback === 'function' &&
+                                               callback(
+                                                       hexify(work1) +
+                                                       hexify([
+                                                               pixels[i + 2],
+                                                               pixels[i + 3],
+                                                               work0[2] ^ (pixels[i] - 1),
+                                                               work0[3] ^ (pixels[i + 1] - 1)
+                                                       ]), n)
+                                       return
+                               }
+                       }
+                       // Nothing found yet, try again
+                       self.requestAnimationFrame(draw)
+               }
+
+               // Begin generation
+               self.requestAnimationFrame(draw)
+       }
+
+       return { find }
 }
 
 export const Pow = p()