this.#gl.clear(this.#gl.COLOR_BUFFER_BIT)
/** Upload work buffer */
- crypto.getRandomValues(work)
this.#gl.bindBuffer(this.#gl.UNIFORM_BUFFER, this.#workBuffer)
this.#gl.bufferSubData(this.#gl.UNIFORM_BUFFER, 0, Uint32Array.from(work))
this.#gl.bindBuffer(this.#gl.UNIFORM_BUFFER, null)
/** Start drawing to calculate one nonce per pixel */
let nonce = null
- const work = new Uint8Array(8)
+ const seed = new Uint8Array(8)
while (nonce == null) {
- this.#draw(work)
+ crypto.getRandomValues(seed)
+ this.#draw(seed)
const found = await this.#checkQueryResult()
if (found) {
- nonce = this.#readResult(work)
+ nonce = this.#readResult(seed)
}
}
return nonce
}
+
+ /**
+ * Validates that a nonce satisfies Nano proof-of-work requirements.
+ *
+ * @param {string} work - Hexadecimal proof-of-work value to validate
+ * @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 validate (work: string, hash: string, threshold: number = 0xfffffff8): Promise<boolean> {
+ if (NanoPowGl.#gl == null) throw new Error('WebGL 2 is required')
+ if (!/^[A-F-a-f0-9]{16}$/.test(hash)) throw new Error(`invalid_hash ${work}`)
+ if (!/^[A-F-a-f0-9]{64}$/.test(hash)) throw new Error(`invalid_hash ${hash}`)
+ if (typeof threshold !== 'number') throw new TypeError(`Invalid threshold ${threshold}`)
+ if (this.#gl == null) throw new Error('WebGL 2 is required')
+
+ /** Set up uniform buffer object */
+ const uboView = new DataView(new ArrayBuffer(144))
+ for (let i = 0; i < 64; i += 8) {
+ const uint32 = hash.slice(i, i + 8)
+ uboView.setUint32(i * 2, parseInt(uint32, 16))
+ }
+ uboView.setUint32(128, threshold, true)
+ uboView.setFloat32(132, NanoPowGl.#WORKLOAD - 1, true)
+ NanoPowGl.#gl.bindBuffer(NanoPowGl.#gl.UNIFORM_BUFFER, NanoPowGl.#uboBuffer)
+ NanoPowGl.#gl.bufferSubData(NanoPowGl.#gl.UNIFORM_BUFFER, 0, uboView)
+ NanoPowGl.#gl.bindBuffer(NanoPowGl.#gl.UNIFORM_BUFFER, null)
+
+ /** Start drawing to calculate one nonce per pixel */
+ let nonce = null
+ const data = new DataView(new ArrayBuffer(8))
+ data.setBigUint64(0, BigInt(`0x${work}`), true)
+ const seed = new Uint8Array(data.buffer)
+ this.#draw(seed)
+ const found = await this.#checkQueryResult()
+ if (found) {
+ nonce = this.#readResult(seed)
+ }
+ if (found && nonce !== work) throw new Error(`Nonce found but does not match work`)
+ return found
+ }
}
// SPDX-License-Identifier: GPL-3.0-or-later
import { NanoPowGl } from "./gl.js"
-import { NanoPowGpu as gpu } from "./gpu.js"
-console.log(`export barrel`)
-let NanoPowGpu = null
+import { NanoPowGpu } from "./gpu.js"
+
+let isGlSupported, isGpuSupported = false
+try {
+ await NanoPowGl.init()
+ isGlSupported = true
+} catch (err) {
+ console.warn(`WebGL is not supported in this environment.`)
+ isGlSupported = false
+}
try {
- NanoPowGpu = await gpu.init()
+ await NanoPowGpu.init()
+ isGpuSupported = true
} catch (err) {
console.warn(`WebGPU is not supported in this environment.`)
+ isGpuSupported = false
+}
+
+const NanoPow = {
+ search: isGpuSupported ? NanoPowGpu.search : isGlSupported ? NanoPowGl.search : null,
+ validate: isGpuSupported ? NanoPowGpu.validate : isGlSupported ? NanoPowGl.validate : null,
}
-console.log(`barrel`)
-export { NanoPowGl, NanoPowGpu }
+export { NanoPowGl, NanoPowGpu, NanoPow }
+export default NanoPow