nano-pow 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/types.d.ts CHANGED
@@ -3,12 +3,29 @@
3
3
 
4
4
  import "@webgpu/types"
5
5
 
6
- export declare const NanoPowGlFragmentShader: string
6
+ export declare const NanoPowGlDownsampleShader: string
7
+ export declare const NanoPowGlDrawShader: string
7
8
  export declare const NanoPowGlVertexShader: string
8
9
  export declare const NanoPowGpuComputeShader: any
9
10
 
10
11
  declare const NanoPow: typeof NanoPowGl | typeof NanoPowGpu | null
11
12
 
13
+ /**
14
+ * Used to create WebGL framebuffer objects.
15
+ *
16
+ * @param {WebGLTexture} - Defines storage size
17
+ * @param {WebGLFramebuffer} - Holds texture data
18
+ * @param {size} - 2D lengths of texture
19
+ */
20
+ export type FBO = {
21
+ texture: WebGLTexture
22
+ framebuffer: WebGLFramebuffer
23
+ size: {
24
+ x: number
25
+ y: number
26
+ }
27
+ }
28
+
12
29
  /**
13
30
  * Used to configure NanoPow.
14
31
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nano-pow",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "Proof-of-work generation and validation with WebGPU/WebGL for Nano cryptocurrency.",
5
5
  "keywords": [
6
6
  "nemo",
@@ -43,11 +43,11 @@
43
43
  "build": "rm -rf types && tsc && node esbuild.mjs && cp types.d.ts dist"
44
44
  },
45
45
  "devDependencies": {
46
- "@types/node": "^22.10.5",
47
- "@webgpu/types": "^0.1.52",
48
- "esbuild": "^0.24.2",
46
+ "@types/node": "^22.13.8",
47
+ "@webgpu/types": "^0.1.54",
48
+ "esbuild": "^0.25.0",
49
49
  "esbuild-plugin-glsl": "^1.2.2",
50
- "typescript": "^5.7.3"
50
+ "typescript": "^5.8.2"
51
51
  },
52
52
  "type": "module",
53
53
  "exports": [
@@ -1,20 +0,0 @@
1
- export declare class NanoPowGl {
2
- #private;
3
- /** Compile */
4
- static init(): Promise<void>;
5
- /**
6
- * Finds a nonce that satisfies the Nano proof-of-work requirements.
7
- *
8
- * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
9
- * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
10
- */
11
- static search(hash: string, threshold?: number): Promise<string>;
12
- /**
13
- * Validates that a nonce satisfies Nano proof-of-work requirements.
14
- *
15
- * @param {string} work - Hexadecimal proof-of-work value to validate
16
- * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
17
- * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
18
- */
19
- static validate(work: string, hash: string, threshold?: number): Promise<boolean>;
20
- }
@@ -1,232 +0,0 @@
1
- // SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
2
- // SPDX-FileContributor: Ben Green <ben@latenightsketches.com>
3
- // SPDX-License-Identifier: GPL-3.0-or-later AND MIT
4
- import { NanoPowGlFragmentShader, NanoPowGlVertexShader } from '#shaders';
5
- export class NanoPowGl {
6
- /** Used to set canvas size. Must be a multiple of 256. */
7
- static #WORKLOAD = 256 * Math.max(1, Math.floor(navigator.hardwareConcurrency));
8
- static #hexify(arr) {
9
- let out = '';
10
- for (let i = arr.length - 1; i >= 0; i--) {
11
- out += arr[i].toString(16).padStart(2, '0');
12
- }
13
- return out;
14
- }
15
- static #gl;
16
- static #program;
17
- static #vertexShader;
18
- static #fragmentShader;
19
- static #positionBuffer;
20
- static #uvBuffer;
21
- static #uboBuffer;
22
- static #workBuffer;
23
- static #query;
24
- static #pixels;
25
- /**Vertex Positions, 2 triangles */
26
- static #positions = new Float32Array([
27
- -1, -1, 0, -1, 1, 0, 1, 1, 0,
28
- 1, -1, 0, 1, 1, 0, -1, -1, 0
29
- ]);
30
- /** Texture Positions */
31
- static #uvPosArray = new Float32Array([
32
- 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1
33
- ]);
34
- /** Compile */
35
- static async init() {
36
- this.#gl = new OffscreenCanvas(this.#WORKLOAD, this.#WORKLOAD).getContext('webgl2');
37
- if (this.#gl == null)
38
- throw new Error('WebGL 2 is required');
39
- this.#gl.clearColor(0, 0, 0, 1);
40
- this.#program = this.#gl.createProgram();
41
- if (this.#program == null)
42
- throw new Error('Failed to create shader program');
43
- this.#vertexShader = this.#gl.createShader(this.#gl.VERTEX_SHADER);
44
- if (this.#vertexShader == null)
45
- throw new Error('Failed to create vertex shader');
46
- this.#gl.shaderSource(this.#vertexShader, NanoPowGlVertexShader);
47
- this.#gl.compileShader(this.#vertexShader);
48
- if (!this.#gl.getShaderParameter(this.#vertexShader, this.#gl.COMPILE_STATUS))
49
- throw new Error(this.#gl.getShaderInfoLog(this.#vertexShader) ?? `Failed to compile vertex shader`);
50
- this.#fragmentShader = this.#gl.createShader(this.#gl.FRAGMENT_SHADER);
51
- if (this.#fragmentShader == null)
52
- throw new Error('Failed to create fragment shader');
53
- this.#gl.shaderSource(this.#fragmentShader, NanoPowGlFragmentShader);
54
- this.#gl.compileShader(this.#fragmentShader);
55
- if (!this.#gl.getShaderParameter(this.#fragmentShader, this.#gl.COMPILE_STATUS))
56
- throw new Error(this.#gl.getShaderInfoLog(this.#fragmentShader) ?? `Failed to compile fragment shader`);
57
- this.#gl.attachShader(this.#program, this.#vertexShader);
58
- this.#gl.attachShader(this.#program, this.#fragmentShader);
59
- this.#gl.linkProgram(this.#program);
60
- if (!this.#gl.getProgramParameter(this.#program, this.#gl.LINK_STATUS))
61
- throw new Error(this.#gl.getProgramInfoLog(this.#program) ?? `Failed to link program`);
62
- /** Construct simple 2D geometry */
63
- this.#gl.useProgram(this.#program);
64
- const triangleArray = this.#gl.createVertexArray();
65
- this.#gl.bindVertexArray(triangleArray);
66
- this.#positionBuffer = this.#gl.createBuffer();
67
- this.#gl.bindBuffer(this.#gl.ARRAY_BUFFER, this.#positionBuffer);
68
- this.#gl.bufferData(this.#gl.ARRAY_BUFFER, this.#positions, this.#gl.STATIC_DRAW);
69
- this.#gl.vertexAttribPointer(0, 3, this.#gl.FLOAT, false, 0, 0);
70
- this.#gl.enableVertexAttribArray(0);
71
- this.#uvBuffer = this.#gl.createBuffer();
72
- this.#gl.bindBuffer(this.#gl.ARRAY_BUFFER, this.#uvBuffer);
73
- this.#gl.bufferData(this.#gl.ARRAY_BUFFER, this.#uvPosArray, this.#gl.STATIC_DRAW);
74
- this.#gl.vertexAttribPointer(1, 2, this.#gl.FLOAT, false, 0, 0);
75
- this.#gl.enableVertexAttribArray(1);
76
- this.#uboBuffer = this.#gl.createBuffer();
77
- this.#gl.bindBuffer(this.#gl.UNIFORM_BUFFER, this.#uboBuffer);
78
- this.#gl.bufferData(this.#gl.UNIFORM_BUFFER, 144, this.#gl.DYNAMIC_DRAW);
79
- this.#gl.bindBuffer(this.#gl.UNIFORM_BUFFER, null);
80
- this.#gl.bindBufferBase(this.#gl.UNIFORM_BUFFER, 0, this.#uboBuffer);
81
- this.#gl.uniformBlockBinding(this.#program, this.#gl.getUniformBlockIndex(this.#program, 'UBO'), 0);
82
- this.#workBuffer = this.#gl.createBuffer();
83
- this.#gl.bindBuffer(this.#gl.UNIFORM_BUFFER, this.#workBuffer);
84
- this.#gl.bufferData(this.#gl.UNIFORM_BUFFER, 32, this.#gl.STREAM_DRAW);
85
- this.#gl.bindBuffer(this.#gl.UNIFORM_BUFFER, null);
86
- this.#gl.bindBufferBase(this.#gl.UNIFORM_BUFFER, 1, this.#workBuffer);
87
- this.#gl.uniformBlockBinding(this.#program, this.#gl.getUniformBlockIndex(this.#program, 'WORK'), 1);
88
- this.#pixels = new Uint8Array(this.#gl.drawingBufferWidth * this.#gl.drawingBufferHeight * 4);
89
- this.#query = this.#gl.createQuery();
90
- }
91
- static #draw(work) {
92
- if (this.#gl == null || this.#query == null)
93
- throw new Error('WebGL 2 is required to draw and query pixels');
94
- if (this.#workBuffer == null)
95
- throw new Error('Work buffer is required to draw');
96
- this.#gl.clear(this.#gl.COLOR_BUFFER_BIT);
97
- /** Upload work buffer */
98
- this.#gl.bindBuffer(this.#gl.UNIFORM_BUFFER, this.#workBuffer);
99
- this.#gl.bufferSubData(this.#gl.UNIFORM_BUFFER, 0, Uint32Array.from(work));
100
- this.#gl.bindBuffer(this.#gl.UNIFORM_BUFFER, null);
101
- this.#gl.beginQuery(this.#gl.ANY_SAMPLES_PASSED_CONSERVATIVE, this.#query);
102
- this.#gl.drawArrays(this.#gl.TRIANGLES, 0, 6);
103
- this.#gl.endQuery(this.#gl.ANY_SAMPLES_PASSED_CONSERVATIVE);
104
- }
105
- static async #checkQueryResult() {
106
- if (this.#gl == null || this.#query == null)
107
- throw new Error('WebGL 2 is required to check query results');
108
- if (this.#gl.getQueryParameter(this.#query, this.#gl.QUERY_RESULT_AVAILABLE)) {
109
- return !!(this.#gl.getQueryParameter(this.#query, this.#gl.QUERY_RESULT));
110
- }
111
- /** Query result not yet available, check again in the next frame */
112
- return new Promise((resolve, reject) => {
113
- try {
114
- requestAnimationFrame(async () => {
115
- const result = await NanoPowGl.#checkQueryResult();
116
- resolve(result);
117
- });
118
- }
119
- catch (err) {
120
- reject(err);
121
- }
122
- });
123
- }
124
- /**
125
- * Reads pixels into the work buffer, checks every 4th pixel for the 'found'
126
- * byte, converts the subsequent 3 pixels with the nonce byte values to a hex
127
- * string, and returns the result.
128
- *
129
- * @param work - Buffer with the original random nonce value
130
- * @returns Nonce as an 8-byte (16-char) hexadecimal string
131
- */
132
- static #readResult(work) {
133
- if (this.#gl == null)
134
- throw new Error('WebGL 2 is required to read pixels');
135
- this.#gl.readPixels(0, 0, this.#gl.drawingBufferWidth, this.#gl.drawingBufferHeight, this.#gl.RGBA, this.#gl.UNSIGNED_BYTE, this.#pixels);
136
- for (let i = 0; i < this.#pixels.length; i += 4) {
137
- if (this.#pixels[i] !== 0) {
138
- /** Return the work value with the custom bits */
139
- const hex = this.#hexify(work.subarray(4, 8)) + this.#hexify([
140
- this.#pixels[i + 2],
141
- this.#pixels[i + 3],
142
- work[2] ^ (this.#pixels[i] - 1),
143
- work[3] ^ (this.#pixels[i + 1] - 1)
144
- ]);
145
- return hex;
146
- }
147
- }
148
- throw new Error('Query reported result but nonce value not found');
149
- }
150
- /**
151
- * Finds a nonce that satisfies the Nano proof-of-work requirements.
152
- *
153
- * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
154
- * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
155
- */
156
- static async search(hash, threshold = 0xfffffff8) {
157
- if (NanoPowGl.#gl == null)
158
- throw new Error('WebGL 2 is required');
159
- if (!/^[A-Fa-f0-9]{64}$/.test(hash))
160
- throw new Error(`Invalid hash ${hash}`);
161
- if (typeof threshold !== 'number')
162
- throw new TypeError(`Invalid threshold ${threshold}`);
163
- if (this.#gl == null)
164
- throw new Error('WebGL 2 is required');
165
- /** Set up uniform buffer object */
166
- const uboView = new DataView(new ArrayBuffer(144));
167
- for (let i = 0; i < 64; i += 8) {
168
- const uint32 = hash.slice(i, i + 8);
169
- uboView.setUint32(i * 2, parseInt(uint32, 16));
170
- }
171
- uboView.setUint32(128, threshold, true);
172
- uboView.setFloat32(132, NanoPowGl.#WORKLOAD - 1, true);
173
- NanoPowGl.#gl.bindBuffer(NanoPowGl.#gl.UNIFORM_BUFFER, NanoPowGl.#uboBuffer);
174
- NanoPowGl.#gl.bufferSubData(NanoPowGl.#gl.UNIFORM_BUFFER, 0, uboView);
175
- NanoPowGl.#gl.bindBuffer(NanoPowGl.#gl.UNIFORM_BUFFER, null);
176
- /** Start drawing to calculate one nonce per pixel */
177
- let nonce = null;
178
- const seed = new Uint8Array(8);
179
- while (nonce == null) {
180
- crypto.getRandomValues(seed);
181
- this.#draw(seed);
182
- const found = await this.#checkQueryResult();
183
- if (found) {
184
- nonce = this.#readResult(seed);
185
- }
186
- }
187
- return nonce;
188
- }
189
- /**
190
- * Validates that a nonce satisfies Nano proof-of-work requirements.
191
- *
192
- * @param {string} work - Hexadecimal proof-of-work value to validate
193
- * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
194
- * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
195
- */
196
- static async validate(work, hash, threshold = 0xfffffff8) {
197
- if (NanoPowGl.#gl == null)
198
- throw new Error('WebGL 2 is required');
199
- if (!/^[A-Fa-f0-9]{16}$/.test(work))
200
- throw new Error(`Invalid work ${work}`);
201
- if (!/^[A-Fa-f0-9]{64}$/.test(hash))
202
- throw new Error(`Invalid hash ${hash}`);
203
- if (typeof threshold !== 'number')
204
- throw new TypeError(`Invalid threshold ${threshold}`);
205
- if (this.#gl == null)
206
- throw new Error('WebGL 2 is required');
207
- /** Set up uniform buffer object */
208
- const uboView = new DataView(new ArrayBuffer(144));
209
- for (let i = 0; i < 64; i += 8) {
210
- const uint32 = hash.slice(i, i + 8);
211
- uboView.setUint32(i * 2, parseInt(uint32, 16));
212
- }
213
- uboView.setUint32(128, threshold, true);
214
- uboView.setFloat32(132, NanoPowGl.#WORKLOAD - 1, true);
215
- NanoPowGl.#gl.bindBuffer(NanoPowGl.#gl.UNIFORM_BUFFER, NanoPowGl.#uboBuffer);
216
- NanoPowGl.#gl.bufferSubData(NanoPowGl.#gl.UNIFORM_BUFFER, 0, uboView);
217
- NanoPowGl.#gl.bindBuffer(NanoPowGl.#gl.UNIFORM_BUFFER, null);
218
- /** Start drawing to calculate one nonce per pixel */
219
- let nonce = null;
220
- const data = new DataView(new ArrayBuffer(8));
221
- data.setBigUint64(0, BigInt(`0x${work}`), true);
222
- const seed = new Uint8Array(data.buffer);
223
- this.#draw(seed);
224
- const found = await this.#checkQueryResult();
225
- if (found) {
226
- nonce = this.#readResult(seed);
227
- }
228
- if (found && nonce !== work)
229
- throw new Error(`Nonce found but does not match work`);
230
- return found;
231
- }
232
- }
@@ -1,24 +0,0 @@
1
- /**
2
- * Nano proof-of-work using WebGPU.
3
- */
4
- export declare class NanoPowGpu {
5
- #private;
6
- static init(): Promise<void>;
7
- static setup(): void;
8
- static reset(): void;
9
- /**
10
- * Finds a nonce that satisfies the Nano proof-of-work requirements.
11
- *
12
- * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
13
- * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
14
- */
15
- static search(hash: string, threshold?: number): Promise<string>;
16
- /**
17
- * Validates that a nonce satisfies Nano proof-of-work requirements.
18
- *
19
- * @param {string} work - Hexadecimal proof-of-work value to validate
20
- * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
21
- * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
22
- */
23
- static validate(work: string, hash: string, threshold?: number): Promise<boolean>;
24
- }
@@ -1,236 +0,0 @@
1
- // SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
2
- // SPDX-License-Identifier: GPL-3.0-or-later
3
- /// <reference types="@webgpu/types" />
4
- import { NanoPowGpuComputeShader } from '#shaders';
5
- /**
6
- * Nano proof-of-work using WebGPU.
7
- */
8
- export class NanoPowGpu {
9
- // Initialize WebGPU
10
- static #busy = false;
11
- static #device = null;
12
- static #uboBuffer;
13
- static #gpuBuffer;
14
- static #cpuBuffer;
15
- static #bindGroupLayout;
16
- static #pipeline;
17
- // Initialize WebGPU
18
- static async init() {
19
- if (this.#busy)
20
- return;
21
- this.#busy = true;
22
- // Request device and adapter
23
- if (navigator.gpu == null)
24
- throw new Error('WebGPU is not supported in this browser.');
25
- try {
26
- const adapter = await navigator.gpu.requestAdapter();
27
- if (adapter == null)
28
- throw new Error('WebGPU adapter refused by browser.');
29
- const device = await adapter.requestDevice();
30
- if (!(device instanceof GPUDevice))
31
- throw new Error('WebGPU device failed to load.');
32
- device.lost.then(this.reset);
33
- this.#device = device;
34
- this.setup();
35
- }
36
- catch (err) {
37
- throw new Error(`WebGPU initialization failed. ${err}`);
38
- }
39
- finally {
40
- this.#busy = false;
41
- }
42
- }
43
- static setup() {
44
- if (this.#device == null)
45
- throw new Error(`WebGPU device failed to load.`);
46
- // Create buffers for writing GPU calculations and reading from Javascript
47
- this.#uboBuffer = this.#device.createBuffer({
48
- size: 48,
49
- usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
50
- });
51
- this.#gpuBuffer = this.#device.createBuffer({
52
- size: 16,
53
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC
54
- });
55
- this.#cpuBuffer = this.#device.createBuffer({
56
- size: 16,
57
- usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
58
- });
59
- // Create binding group data structure and use it later once UBO is known
60
- this.#bindGroupLayout = this.#device.createBindGroupLayout({
61
- entries: [
62
- {
63
- binding: 0,
64
- visibility: GPUShaderStage.COMPUTE,
65
- buffer: { type: 'uniform' },
66
- },
67
- {
68
- binding: 1,
69
- visibility: GPUShaderStage.COMPUTE,
70
- buffer: { type: 'storage' },
71
- }
72
- ]
73
- });
74
- // Create pipeline to connect compute shader to binding layout
75
- this.#pipeline = this.#device.createComputePipeline({
76
- layout: this.#device.createPipelineLayout({
77
- bindGroupLayouts: [this.#bindGroupLayout]
78
- }),
79
- compute: {
80
- entryPoint: 'main',
81
- module: this.#device.createShaderModule({
82
- code: NanoPowGpuComputeShader
83
- })
84
- }
85
- });
86
- }
87
- static reset() {
88
- console.warn(`GPU device lost. Reinitializing...`);
89
- NanoPowGpu.#cpuBuffer?.destroy();
90
- NanoPowGpu.#gpuBuffer?.destroy();
91
- NanoPowGpu.#uboBuffer?.destroy();
92
- NanoPowGpu.#busy = false;
93
- NanoPowGpu.init();
94
- }
95
- static async #dispatch(seed, hash, threshold, passes) {
96
- if (this.#device == null)
97
- throw new Error(`WebGPU device failed to load.`);
98
- // Set up uniform buffer object
99
- // Note: u32 size is 4, but total alignment must be multiple of 16
100
- const uboView = new DataView(new ArrayBuffer(48));
101
- for (let i = 0; i < 64; i += 8) {
102
- const uint32 = hash.slice(i, i + 8);
103
- uboView.setUint32(i / 2, parseInt(uint32, 16));
104
- }
105
- uboView.setBigUint64(32, seed, true);
106
- uboView.setUint32(40, threshold, true);
107
- this.#device.queue.writeBuffer(this.#uboBuffer, 0, uboView);
108
- // Reset `nonce` and `found` to 0u in WORK before each calculation
109
- this.#device.queue.writeBuffer(this.#gpuBuffer, 0, new Uint32Array([0, 0, 0]));
110
- // Bind UBO read and GPU write buffers
111
- const bindGroup = this.#device.createBindGroup({
112
- layout: this.#bindGroupLayout,
113
- entries: [
114
- {
115
- binding: 0,
116
- resource: {
117
- buffer: this.#uboBuffer
118
- },
119
- },
120
- {
121
- binding: 1,
122
- resource: {
123
- buffer: this.#gpuBuffer
124
- },
125
- },
126
- ],
127
- });
128
- // Create command encoder to issue commands to GPU and initiate computation
129
- const commandEncoder = this.#device.createCommandEncoder();
130
- const passEncoder = commandEncoder.beginComputePass();
131
- // Issue commands and end compute pass structure
132
- passEncoder.setPipeline(this.#pipeline);
133
- passEncoder.setBindGroup(0, bindGroup);
134
- passEncoder.dispatchWorkgroups(passes, passes);
135
- passEncoder.end();
136
- // Copy 8-byte nonce and 4-byte found flag from GPU to CPU for reading
137
- commandEncoder.copyBufferToBuffer(this.#gpuBuffer, 0, this.#cpuBuffer, 0, 12);
138
- // End computation by passing array of command buffers to command queue for execution
139
- this.#device.queue.submit([commandEncoder.finish()]);
140
- // Read results back to Javascript and then unmap buffer after reading
141
- let data = null;
142
- try {
143
- await this.#cpuBuffer.mapAsync(GPUMapMode.READ);
144
- await this.#device.queue.onSubmittedWorkDone();
145
- data = new DataView(this.#cpuBuffer.getMappedRange().slice(0));
146
- this.#cpuBuffer.unmap();
147
- }
148
- catch (err) {
149
- console.warn(`Error getting data from GPU. ${err}`);
150
- return this.#dispatch(seed, hash, threshold, passes);
151
- }
152
- if (data == null)
153
- throw new Error(`Failed to get data from buffer.`);
154
- return data;
155
- }
156
- /**
157
- * Finds a nonce that satisfies the Nano proof-of-work requirements.
158
- *
159
- * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
160
- * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
161
- */
162
- static async search(hash, threshold = 0xfffffff8) {
163
- if (this.#busy) {
164
- return new Promise(resolve => {
165
- setTimeout(async () => {
166
- const result = this.search(hash, threshold);
167
- resolve(result);
168
- }, 100);
169
- });
170
- }
171
- this.#busy = true;
172
- if (!/^[A-Fa-f0-9]{64}$/.test(hash))
173
- throw new TypeError(`Invalid hash ${hash}`);
174
- if (typeof threshold !== 'number')
175
- throw new TypeError(`Invalid threshold ${threshold}`);
176
- // Ensure WebGPU is initialized before calculating
177
- let loads = 0;
178
- while (this.#device == null && loads < 20) {
179
- await new Promise(resolve => {
180
- setTimeout(resolve, 500);
181
- });
182
- }
183
- if (this.#device == null)
184
- throw new Error(`WebGPU device failed to load.`);
185
- let nonce = 0n;
186
- do {
187
- const random = Math.floor(Math.random() * 0xffffffff);
188
- const seed = (BigInt(random) << 32n) | BigInt(random);
189
- const data = await this.#dispatch(seed, hash, threshold, 0xff);
190
- nonce = data.getBigUint64(0, true);
191
- this.#busy = !data.getUint32(8);
192
- } while (this.#busy);
193
- return nonce.toString(16).padStart(16, '0');
194
- }
195
- /**
196
- * Validates that a nonce satisfies Nano proof-of-work requirements.
197
- *
198
- * @param {string} work - Hexadecimal proof-of-work value to validate
199
- * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
200
- * @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
201
- */
202
- static async validate(work, hash, threshold = 0xfffffff8) {
203
- if (this.#busy) {
204
- return new Promise(resolve => {
205
- setTimeout(async () => {
206
- const result = this.validate(work, hash, threshold);
207
- resolve(result);
208
- }, 100);
209
- });
210
- }
211
- this.#busy = true;
212
- if (!/^[A-Fa-f0-9]{16}$/.test(work))
213
- throw new TypeError(`Invalid work ${work}`);
214
- if (!/^[A-Fa-f0-9]{64}$/.test(hash))
215
- throw new TypeError(`Invalid hash ${hash}`);
216
- if (typeof threshold !== 'number')
217
- throw new TypeError(`Invalid threshold ${threshold}`);
218
- // Ensure WebGPU is initialized before calculating
219
- let loads = 0;
220
- while (this.#device == null && loads < 20) {
221
- await new Promise(resolve => {
222
- setTimeout(resolve, 500);
223
- });
224
- }
225
- if (this.#device == null)
226
- throw new Error(`WebGPU device failed to load.`);
227
- const seed = BigInt(`0x${work}`);
228
- const data = await this.#dispatch(seed, hash, threshold, 1);
229
- const nonce = data.getBigUint64(0, true).toString(16).padStart(16, '0');
230
- const found = !!data.getUint32(8);
231
- this.#busy = false;
232
- if (found && work !== nonce)
233
- throw new Error(`Nonce found but does not match work`);
234
- return found;
235
- }
236
- }
@@ -1,4 +0,0 @@
1
- import { NanoPowGl } from "./gl.js";
2
- import { NanoPowGpu } from "./gpu.js";
3
- declare const NanoPow: typeof NanoPowGl | null;
4
- export { NanoPow, NanoPowGl, NanoPowGpu };
@@ -1,23 +0,0 @@
1
- // SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
2
- // SPDX-License-Identifier: GPL-3.0-or-later
3
- import { NanoPowGl } from "./gl.js";
4
- import { NanoPowGpu } from "./gpu.js";
5
- let isGlSupported, isGpuSupported = false;
6
- try {
7
- await NanoPowGl.init();
8
- isGlSupported = true;
9
- }
10
- catch (err) {
11
- console.warn(`WebGL is not supported in this environment.`);
12
- isGlSupported = false;
13
- }
14
- try {
15
- await NanoPowGpu.init();
16
- isGpuSupported = true;
17
- }
18
- catch (err) {
19
- console.warn(`WebGPU is not supported in this environment.`);
20
- isGpuSupported = false;
21
- }
22
- const NanoPow = isGpuSupported ? NanoPowGpu : isGlSupported ? NanoPowGl : null;
23
- export { NanoPow, NanoPowGl, NanoPowGpu };
package/dist/global.d.ts DELETED
@@ -1 +0,0 @@
1
- export {};
package/dist/global.js DELETED
@@ -1,6 +0,0 @@
1
- // SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
2
- // SPDX-License-Identifier: GPL-3.0-or-later
3
- import { NanoPow as np, NanoPowGl as gl, NanoPowGpu as gpu } from './main.js';
4
- globalThis.NanoPow ??= np;
5
- globalThis.NanoPowGl ??= gl;
6
- globalThis.NanoPowGpu ??= gpu;