nano-pow 5.1.15 → 5.2.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/AUTHORS.md +16 -2
- package/README.md +33 -12
- package/dist/bin/cli.d.ts +2 -0
- package/dist/bin/cli.js +15 -334
- package/dist/bin/cli.js.map +7 -0
- package/dist/bin/server.d.ts +2 -0
- package/dist/bin/server.js +35 -320
- package/dist/bin/server.js.map +7 -0
- package/dist/index.d.ts +73 -0
- package/dist/{main.min.js → index.js} +182 -270
- package/dist/index.js.map +7 -0
- package/dist/lib/config/index.d.ts +49 -0
- package/dist/lib/generate/cpu/index.d.ts +2 -0
- package/dist/lib/generate/index.d.ts +4 -0
- package/dist/lib/generate/wasm/index.d.ts +5 -0
- package/dist/lib/generate/wasm/worker.d.ts +1 -0
- package/dist/lib/generate/webgl/index.d.ts +5 -0
- package/dist/lib/generate/webgl/shaders/index.d.ts +4 -0
- package/dist/lib/generate/webgpu/index.d.ts +5 -0
- package/dist/lib/index.d.ts +3 -0
- package/dist/lib/validate/index.d.ts +3 -0
- package/dist/utils/api-support/index.d.ts +14 -0
- package/dist/utils/api-support/wasm.d.ts +4 -0
- package/dist/utils/api-support/webgl.d.ts +4 -0
- package/dist/utils/api-support/webgpu.d.ts +4 -0
- package/dist/utils/bigint.d.ts +4 -0
- package/dist/utils/cache.d.ts +7 -0
- package/dist/utils/index.d.ts +56 -0
- package/dist/utils/index.js +379 -0
- package/dist/utils/index.js.map +7 -0
- package/dist/utils/logger.d.ts +11 -0
- package/dist/utils/queue.d.ts +9 -0
- package/docs/nano-pow.1 +7 -6
- package/package.json +15 -13
- package/dist/types.d.ts +0 -90
package/AUTHORS.md
CHANGED
|
@@ -3,5 +3,19 @@ SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
|
|
|
3
3
|
SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
4
|
-->
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
# Authors
|
|
7
|
+
|
|
8
|
+
[nano-pow](https://codecow.com/nano-pow.git)
|
|
9
|
+
|
|
10
|
+
- Chris Duncan <chris@codecow.com> ([codecow.com](codecow.com))
|
|
11
|
+
|
|
12
|
+
[nano-webgl-pow](https://github.com/numtel/nano-webgl-pow)
|
|
13
|
+
|
|
14
|
+
- Ben Green <ben@latenightsketches.com> ([numtel.github.io](numtel.github.io))
|
|
15
|
+
|
|
16
|
+
[BLAKE2](https://blake2.net)
|
|
17
|
+
|
|
18
|
+
- Jean-Philippe Aumasson [@veorq](https://twitter.com/aumasson) (https://131002.net)
|
|
19
|
+
- Samuel Neves [@sevenps](https://twitter.com/sevenps) (http://eden.dei.uc.pt/~sneves/)
|
|
20
|
+
- Zooko Wilcox-O'Hearn [@zooko](https://twitter.com/zooko) (https://LeastAuthority.com)
|
|
21
|
+
- Christian Winnerlein [@codesinchaos](https://twitter.com/codesinchaos) (https://codesinchaos.wordpress.com/)
|
package/README.md
CHANGED
|
@@ -173,25 +173,46 @@ official Nano node software. The installed command will launch the server in a
|
|
|
173
173
|
detached process, and it can also be started manually to customize behavior by
|
|
174
174
|
executing the server script directly.
|
|
175
175
|
|
|
176
|
-
####
|
|
176
|
+
#### Configuration
|
|
177
177
|
|
|
178
|
-
|
|
178
|
+
NanoPow will look for a configuration file in the user home directory at the
|
|
179
|
+
location `${HOME}/.nano-pow/config` and read the following variables:
|
|
179
180
|
|
|
180
|
-
`
|
|
181
|
+
- `DEBUG`: enable additional logging saved to the HOME directory
|
|
182
|
+
- `EFFORT`: increase or decrease demand on the GPU
|
|
183
|
+
- `PORT`: override the default port 5040
|
|
181
184
|
|
|
182
|
-
|
|
185
|
+
It will then fall back to environment variables for any values not found in the
|
|
186
|
+
config file. The same variable names are used, prefixed with `NANO_POW_`:
|
|
187
|
+
|
|
188
|
+
- `NANO_POW_DEBUG`: enable additional logging saved to the HOME directory
|
|
189
|
+
- `NANO_POW_EFFORT`: increase or decrease demand on the GPU
|
|
190
|
+
- `NANO_POW_PORT`: override the default port 5040
|
|
191
|
+
|
|
192
|
+
Environment variables can also be specified inline at time of execution.
|
|
193
|
+
|
|
194
|
+
```console
|
|
195
|
+
$ # Launch the server and detach from the current session to run in the background
|
|
196
|
+
$ NANO_POW_PORT=8080 nano-pow --server
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
```console
|
|
200
|
+
$ # View process ID for "NanoPow Server"
|
|
201
|
+
$ cat ~/.nano-pow/server.pid
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
```console
|
|
205
|
+
$ # Display list of server logs
|
|
206
|
+
$ ls ~/.nano-pow/logs/
|
|
207
|
+
```
|
|
183
208
|
|
|
184
209
|
```console
|
|
185
|
-
#
|
|
186
|
-
|
|
187
|
-
# View process ID for "NanoPow Server"
|
|
188
|
-
cat ~/.nano-pow/server.pid
|
|
189
|
-
# Display list of server logs
|
|
190
|
-
ls ~/.nano-pow/logs/
|
|
191
|
-
# Find process ID manually
|
|
192
|
-
pgrep NanoPow
|
|
210
|
+
$ # Find process ID manually
|
|
211
|
+
$ pgrep NanoPow
|
|
193
212
|
```
|
|
194
213
|
|
|
214
|
+
#### Usage
|
|
215
|
+
|
|
195
216
|
Work is generated or validated by sending an HTTP `POST` request to the
|
|
196
217
|
configured hostname or IP address of the machine. Some basic help is available
|
|
197
218
|
via `GET` request.
|
package/dist/bin/cli.js
CHANGED
|
@@ -1,337 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
|
|
3
|
+
//! SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
import { Logger, isHex32, isHex8, stats } from "nano-pow/utils";
|
|
4
5
|
import { spawn } from "node:child_process";
|
|
5
6
|
import { getRandomValues } from "node:crypto";
|
|
6
7
|
import { createInterface } from "node:readline/promises";
|
|
7
|
-
|
|
8
|
-
// src/utils/api-support/wasm.ts
|
|
9
|
-
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
|
|
10
|
-
//! SPDX-License-Identifier: GPL-3.0-or-later
|
|
11
|
-
var wasm = { isSupported: false };
|
|
12
|
-
Object.defineProperty(wasm, "isSupported", {
|
|
13
|
-
get: async function() {
|
|
14
|
-
let isWasmSupported = false;
|
|
15
|
-
try {
|
|
16
|
-
const wasmBuffer = new Uint8Array([
|
|
17
|
-
0,
|
|
18
|
-
97,
|
|
19
|
-
115,
|
|
20
|
-
109,
|
|
21
|
-
1,
|
|
22
|
-
0,
|
|
23
|
-
0,
|
|
24
|
-
0,
|
|
25
|
-
// WASM magic header and version
|
|
26
|
-
1,
|
|
27
|
-
4,
|
|
28
|
-
// Type section, 4 byte descriptor
|
|
29
|
-
1,
|
|
30
|
-
96,
|
|
31
|
-
0,
|
|
32
|
-
0,
|
|
33
|
-
// 1 type, type function, 0 params, 0 returns
|
|
34
|
-
3,
|
|
35
|
-
2,
|
|
36
|
-
// Function section, 2 byte descriptor
|
|
37
|
-
1,
|
|
38
|
-
0,
|
|
39
|
-
// 1 function, ID 0
|
|
40
|
-
10,
|
|
41
|
-
23,
|
|
42
|
-
// Code section, 23 bytes
|
|
43
|
-
1,
|
|
44
|
-
21,
|
|
45
|
-
// 1 function body, 21 bytes
|
|
46
|
-
0,
|
|
47
|
-
// 0 local variables
|
|
48
|
-
253,
|
|
49
|
-
12,
|
|
50
|
-
// v128.const
|
|
51
|
-
0,
|
|
52
|
-
0,
|
|
53
|
-
0,
|
|
54
|
-
0,
|
|
55
|
-
0,
|
|
56
|
-
0,
|
|
57
|
-
0,
|
|
58
|
-
0,
|
|
59
|
-
0,
|
|
60
|
-
0,
|
|
61
|
-
0,
|
|
62
|
-
0,
|
|
63
|
-
0,
|
|
64
|
-
0,
|
|
65
|
-
0,
|
|
66
|
-
0,
|
|
67
|
-
// assign i64x2 values
|
|
68
|
-
26,
|
|
69
|
-
11
|
|
70
|
-
// Drop result, end function
|
|
71
|
-
]);
|
|
72
|
-
const module = await WebAssembly.compile(wasmBuffer);
|
|
73
|
-
const instance = await WebAssembly.instantiate(module);
|
|
74
|
-
isWasmSupported = instance instanceof WebAssembly.Instance;
|
|
75
|
-
} catch (err) {
|
|
76
|
-
console.warn("WASM is not supported in this environment.\n", err.message ?? err);
|
|
77
|
-
isWasmSupported = false;
|
|
78
|
-
} finally {
|
|
79
|
-
delete this.isSupported;
|
|
80
|
-
this.isSupported = isWasmSupported;
|
|
81
|
-
return this.isSupported;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
// src/utils/api-support/webgl.ts
|
|
87
|
-
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
|
|
88
|
-
//! SPDX-License-Identifier: GPL-3.0-or-later
|
|
89
|
-
var webgl = { isSupported: false };
|
|
90
|
-
Object.defineProperty(webgl, "isSupported", {
|
|
91
|
-
get: async function() {
|
|
92
|
-
let isWebglSupported = false;
|
|
93
|
-
try {
|
|
94
|
-
const gl = new OffscreenCanvas(0, 0)?.getContext?.("webgl2");
|
|
95
|
-
isWebglSupported = gl instanceof WebGL2RenderingContext && !gl.isContextLost();
|
|
96
|
-
} catch (err) {
|
|
97
|
-
console.warn("WebGL is not supported in this environment.\n", err);
|
|
98
|
-
isWebglSupported = false;
|
|
99
|
-
} finally {
|
|
100
|
-
delete this.isSupported;
|
|
101
|
-
this.isSupported = isWebglSupported;
|
|
102
|
-
return this.isSupported;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// src/utils/api-support/webgpu.ts
|
|
108
|
-
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
|
|
109
|
-
//! SPDX-License-Identifier: GPL-3.0-or-later
|
|
110
|
-
var webgpu = { isSupported: false };
|
|
111
|
-
Object.defineProperty(webgpu, "isSupported", {
|
|
112
|
-
get: async function() {
|
|
113
|
-
let isWebgpuSupported = false;
|
|
114
|
-
try {
|
|
115
|
-
const adapter = await navigator?.gpu?.requestAdapter?.();
|
|
116
|
-
isWebgpuSupported = adapter instanceof GPUAdapter;
|
|
117
|
-
} catch (err) {
|
|
118
|
-
console.warn("WebGPU is not supported in this environment.\n", err);
|
|
119
|
-
isWebgpuSupported = false;
|
|
120
|
-
} finally {
|
|
121
|
-
delete this.isSupported;
|
|
122
|
-
this.isSupported = isWebgpuSupported;
|
|
123
|
-
return this.isSupported;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// src/utils/api-support/index.ts
|
|
129
|
-
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
|
|
130
|
-
//! SPDX-License-Identifier: GPL-3.0-or-later
|
|
131
|
-
|
|
132
|
-
// src/utils/bigint.ts
|
|
133
|
-
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
|
|
134
|
-
//! SPDX-License-Identifier: GPL-3.0-or-later
|
|
135
|
-
function bigintFrom(value, type) {
|
|
136
|
-
if (typeof value === "bigint") {
|
|
137
|
-
return value;
|
|
138
|
-
} else if (typeof value === "boolean" || typeof value === "number") {
|
|
139
|
-
return BigInt(value);
|
|
140
|
-
} else if (typeof value === "string") {
|
|
141
|
-
const v = value.trim().replace(/n$/, "");
|
|
142
|
-
if (/^0[Bb][01]+$/.test(v) || /^0[Oo][0-7]+$/.test(v) || /^0[Xx][A-Fa-f\d]+$/.test(v) || /^\d+$/.test(v)) {
|
|
143
|
-
return BigInt(v);
|
|
144
|
-
}
|
|
145
|
-
if (type === "bin" && /^[01]+$/.test(v)) {
|
|
146
|
-
return BigInt(`0b${v}`);
|
|
147
|
-
}
|
|
148
|
-
if (type === "oct" && /^[0-7]+$/.test(v)) {
|
|
149
|
-
return BigInt(`0o${v}`);
|
|
150
|
-
}
|
|
151
|
-
if (type === "hex" || /^\d*[A-Fa-f]+\d*$/.test(v)) {
|
|
152
|
-
return BigInt(`0x${v}`);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
throw new TypeError(`can't convert string to BigInt`);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// src/utils/cache.ts
|
|
159
|
-
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
|
|
160
|
-
//! SPDX-License-Identifier: GPL-3.0-or-later
|
|
161
|
-
var Cache = class {
|
|
162
|
-
static clear() {
|
|
163
|
-
this.#removeItem("NanoPowCache");
|
|
164
|
-
}
|
|
165
|
-
static delete(hash) {
|
|
166
|
-
const bigintHash = bigintFrom(hash, "hex");
|
|
167
|
-
const item = this.#getItem("NanoPowCache");
|
|
168
|
-
if (item == null) return;
|
|
169
|
-
const cache = JSON.parse(item);
|
|
170
|
-
for (let i = 0; i < cache.length; i++) {
|
|
171
|
-
if (bigintFrom(cache[i].hash, "hex") === bigintHash) {
|
|
172
|
-
cache.splice(i, 1);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
this.#setItem("NanoPowCache", JSON.stringify(cache));
|
|
176
|
-
}
|
|
177
|
-
static search(hash, difficulty) {
|
|
178
|
-
const bigintHash = bigintFrom(hash, "hex");
|
|
179
|
-
const item = this.#getItem("NanoPowCache");
|
|
180
|
-
if (item) {
|
|
181
|
-
const cache = JSON.parse(item);
|
|
182
|
-
for (const c of cache) {
|
|
183
|
-
if (bigintFrom(c.hash, "hex") === bigintHash && bigintFrom(c.difficulty, "hex") >= difficulty) {
|
|
184
|
-
return c;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
return null;
|
|
189
|
-
}
|
|
190
|
-
static store(result) {
|
|
191
|
-
const item = this.#getItem("NanoPowCache");
|
|
192
|
-
const cache = JSON.parse(item ?? "[]");
|
|
193
|
-
if (cache.push(result) > 1e3) cache.shift();
|
|
194
|
-
this.#setItem("NanoPowCache", JSON.stringify(cache));
|
|
195
|
-
return result;
|
|
196
|
-
}
|
|
197
|
-
static #storage = {};
|
|
198
|
-
static #getItem(key) {
|
|
199
|
-
if (globalThis?.localStorage) return globalThis.localStorage.getItem(key);
|
|
200
|
-
return this.#storage[key];
|
|
201
|
-
}
|
|
202
|
-
static #removeItem(key) {
|
|
203
|
-
if (globalThis?.localStorage) return globalThis.localStorage.removeItem(key);
|
|
204
|
-
this.#storage = {};
|
|
205
|
-
}
|
|
206
|
-
static #setItem(key, item) {
|
|
207
|
-
if (globalThis?.localStorage) return globalThis.localStorage.setItem(key, item);
|
|
208
|
-
this.#storage[key] = item;
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
// src/utils/logger.ts
|
|
213
|
-
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
|
|
214
|
-
//! SPDX-License-Identifier: GPL-3.0-or-later
|
|
215
|
-
var Logger = class {
|
|
216
|
-
isEnabled = false;
|
|
217
|
-
groups = {};
|
|
218
|
-
groupStart(name) {
|
|
219
|
-
if (this.isEnabled) {
|
|
220
|
-
console.groupCollapsed(name);
|
|
221
|
-
this.groups[name] = true;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
groupEnd(name) {
|
|
225
|
-
if (this.groups[name]) {
|
|
226
|
-
console.groupEnd();
|
|
227
|
-
delete this.groups[name];
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
log(...args2) {
|
|
231
|
-
if (this.isEnabled) {
|
|
232
|
-
const datetime = new Date(Date.now()).toLocaleString(Intl.DateTimeFormat().resolvedOptions().locale ?? "en-US", { hour12: false, dateStyle: "medium", timeStyle: "medium" });
|
|
233
|
-
for (let i = 0; i < args2.length; i++) {
|
|
234
|
-
if (typeof args2[i] === "string") {
|
|
235
|
-
args2[i] = args2[i].replace(datetime, "").trimStart();
|
|
236
|
-
}
|
|
237
|
-
if (args2[i] instanceof Error) {
|
|
238
|
-
if ("stack" in args2[i]) {
|
|
239
|
-
args2.splice(i + 1, 0, args2[i].stack);
|
|
240
|
-
} else if ("message" in args2[i]) {
|
|
241
|
-
args2.splice(i + 1, 0, args2[i].message);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
const entry = `${datetime} ${globalThis.process?.title ?? "NanoPow"}[${globalThis.process?.pid ?? "browser"}]:`;
|
|
246
|
-
console.log(entry, ...args2);
|
|
247
|
-
globalThis.process?.send?.({ type: "console", data: `${entry} ${args2}` });
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
// src/utils/queue.ts
|
|
253
|
-
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
|
|
254
|
-
//! SPDX-License-Identifier: GPL-3.0-or-later
|
|
255
|
-
|
|
256
|
-
// src/utils/index.ts
|
|
257
|
-
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
|
|
258
|
-
//! SPDX-License-Identifier: GPL-3.0-or-later
|
|
259
|
-
var clearCache = Cache.clear;
|
|
260
|
-
function isHexN(value, byteLength) {
|
|
261
|
-
if (typeof value !== "string") return false;
|
|
262
|
-
const v = value.replace(/^0[Xx]/, "");
|
|
263
|
-
const length = byteLength === null ? "+" : `{${2 * byteLength}}`;
|
|
264
|
-
const r = new RegExp(`^[A-Fa-f\\d]${length}$`);
|
|
265
|
-
return r.test(v);
|
|
266
|
-
}
|
|
267
|
-
function isHex8(value) {
|
|
268
|
-
return isHexN(value, 8);
|
|
269
|
-
}
|
|
270
|
-
function isHex32(value) {
|
|
271
|
-
return isHexN(value, 32);
|
|
272
|
-
}
|
|
273
|
-
function stats(times) {
|
|
274
|
-
if (times == null || times.length === 0) return null;
|
|
275
|
-
const count = times.length;
|
|
276
|
-
const truncatedStart = Math.floor(count * 0.1);
|
|
277
|
-
const truncatedEnd = count - truncatedStart;
|
|
278
|
-
const truncatedCount = truncatedEnd - truncatedStart;
|
|
279
|
-
let min = Number.MAX_SAFE_INTEGER;
|
|
280
|
-
let logarithms, max, median, reciprocals, total;
|
|
281
|
-
logarithms = max = median = reciprocals = total = 0;
|
|
282
|
-
let truncatedMin = Number.MAX_SAFE_INTEGER;
|
|
283
|
-
let truncatedLogarithms, truncatedMax, truncatedReciprocals, truncatedTotal;
|
|
284
|
-
truncatedLogarithms = truncatedMax = truncatedReciprocals = truncatedTotal = 0;
|
|
285
|
-
times.sort((a, b) => a - b);
|
|
286
|
-
for (let i = 0; i < count; i++) {
|
|
287
|
-
const time = times[i];
|
|
288
|
-
total += time;
|
|
289
|
-
logarithms += Math.log(time);
|
|
290
|
-
reciprocals += 1 / time;
|
|
291
|
-
min = Math.min(min, time);
|
|
292
|
-
max = Math.max(max, time);
|
|
293
|
-
if (i === Math.floor((count - 1) / 2)) median = time;
|
|
294
|
-
if (i === Math.floor(count / 2) && count % 2 === 0) median = (median + time) / 2;
|
|
295
|
-
}
|
|
296
|
-
for (let i = truncatedStart; i < truncatedEnd; i++) {
|
|
297
|
-
const time = times[i];
|
|
298
|
-
truncatedTotal += time;
|
|
299
|
-
truncatedLogarithms += Math.log(time);
|
|
300
|
-
truncatedReciprocals += 1 / time;
|
|
301
|
-
truncatedMin = Math.min(truncatedMin, time);
|
|
302
|
-
truncatedMax = Math.max(truncatedMax, time);
|
|
303
|
-
}
|
|
304
|
-
return {
|
|
305
|
-
count,
|
|
306
|
-
total,
|
|
307
|
-
rate: 1e3 * count / total,
|
|
308
|
-
min,
|
|
309
|
-
max,
|
|
310
|
-
median,
|
|
311
|
-
arithmetic: total / count,
|
|
312
|
-
geometric: Math.exp(logarithms / count),
|
|
313
|
-
harmonic: count / reciprocals,
|
|
314
|
-
truncatedCount,
|
|
315
|
-
truncatedTotal,
|
|
316
|
-
truncatedRate: 1e3 * truncatedCount / truncatedTotal,
|
|
317
|
-
truncatedMin,
|
|
318
|
-
truncatedMax,
|
|
319
|
-
truncatedArithmetic: truncatedTotal / truncatedCount,
|
|
320
|
-
truncatedGeometric: Math.exp(truncatedLogarithms / truncatedCount),
|
|
321
|
-
truncatedHarmonic: truncatedCount / truncatedReciprocals
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// src/bin/cli.ts
|
|
326
|
-
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
|
|
327
|
-
//! SPDX-License-Identifier: GPL-3.0-or-later
|
|
328
8
|
process.title = "NanoPow CLI";
|
|
329
|
-
|
|
9
|
+
const logger = new Logger();
|
|
330
10
|
delete process.env.NANO_POW_DEBUG;
|
|
331
11
|
delete process.env.NANO_POW_EFFORT;
|
|
332
12
|
delete process.env.NANO_POW_PORT;
|
|
333
|
-
|
|
334
|
-
|
|
13
|
+
const hashes = [];
|
|
14
|
+
const stdinErrors = [];
|
|
335
15
|
if (!process.stdin.isTTY) {
|
|
336
16
|
const stdin = createInterface({
|
|
337
17
|
input: process.stdin
|
|
@@ -346,7 +26,7 @@ if (!process.stdin.isTTY) {
|
|
|
346
26
|
}
|
|
347
27
|
}
|
|
348
28
|
}
|
|
349
|
-
|
|
29
|
+
const args = process.argv.slice(2);
|
|
350
30
|
if (hashes.length === 0 && args.length === 0 || args.some((v) => v === "--help" || v === "-h")) {
|
|
351
31
|
console.log(`Usage: nano-pow [OPTION]... BLOCKHASH...
|
|
352
32
|
Generate work for BLOCKHASH, or multiple work values for BLOCKHASH(es)
|
|
@@ -374,8 +54,8 @@ Full documentation: <https://www.npmjs.com/package/nano-pow>
|
|
|
374
54
|
`);
|
|
375
55
|
process.exit(0);
|
|
376
56
|
}
|
|
377
|
-
|
|
378
|
-
|
|
57
|
+
const inArgs = [];
|
|
58
|
+
let isParsingHash = true;
|
|
379
59
|
while (isParsingHash) {
|
|
380
60
|
if (!isHex32(args[args.length - 1])) break;
|
|
381
61
|
try {
|
|
@@ -385,10 +65,10 @@ while (isParsingHash) {
|
|
|
385
65
|
}
|
|
386
66
|
}
|
|
387
67
|
hashes.push(...inArgs);
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
68
|
+
let isBatch = false;
|
|
69
|
+
let isBenchmark = false;
|
|
70
|
+
let runs = 1;
|
|
71
|
+
const body = {
|
|
392
72
|
action: "work_generate"
|
|
393
73
|
};
|
|
394
74
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -457,7 +137,7 @@ for (const stdinErr of stdinErrors) {
|
|
|
457
137
|
logger.log(stdinErr);
|
|
458
138
|
}
|
|
459
139
|
logger.log("launching server");
|
|
460
|
-
|
|
140
|
+
const server = spawn(
|
|
461
141
|
process.execPath,
|
|
462
142
|
[new URL(import.meta.resolve("./server.js")).pathname],
|
|
463
143
|
{ stdio: ["pipe", "pipe", "pipe", "ipc"] }
|
|
@@ -580,3 +260,4 @@ async function score() {
|
|
|
580
260
|
}
|
|
581
261
|
console.log(stats(rates)?.truncatedHarmonic, "wps");
|
|
582
262
|
}
|
|
263
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/bin/cli.ts"],
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\n//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>\n//! SPDX-License-Identifier: GPL-3.0-or-later\n\nimport { WorkErrorResponse, WorkGenerateResponse, WorkValidateResponse } from 'nano-pow'\nimport { Logger, isHex32, isHex8, stats } from 'nano-pow/utils'\nimport { Serializable, spawn } from 'node:child_process'\nimport { getRandomValues } from 'node:crypto'\nimport { createInterface } from 'node:readline/promises'\n\nprocess.title = 'NanoPow CLI'\nconst logger = new Logger()\n\ndelete process.env.NANO_POW_DEBUG\ndelete process.env.NANO_POW_EFFORT\ndelete process.env.NANO_POW_PORT\n\nconst hashes: string[] = []\nconst stdinErrors: string[] = []\n\nif (!process.stdin.isTTY) {\n\tconst stdin = createInterface({\n\t\tinput: process.stdin\n\t})\n\tlet i = 0\n\tfor await (const line of stdin) {\n\t\ti++\n\t\tif (isHex32(line)) {\n\t\t\thashes.push(line)\n\t\t} else {\n\t\t\tstdinErrors.push(`Skipping invalid stdin input line ${i}`)\n\t\t}\n\t}\n}\n\nconst args = process.argv.slice(2)\nif ((hashes.length === 0 && args.length === 0) || (args.some(v => v === '--help' || v === '-h'))) {\n\tconsole.log(`Usage: nano-pow [OPTION]... BLOCKHASH...\nGenerate work for BLOCKHASH, or multiple work values for BLOCKHASH(es)\nBLOCKHASH is a 64-character hexadecimal string. Multiple blockhashes must be separated by whitespace or line breaks.\nPrints the result as a Javascript object to standard output as soon as it is calculated.\nIf using --batch, results are printed only after all BLOCKHASH(es) have be processed.\nIf using --validate, results will also include validity properties.\n\n -b, --batch process all data before returning final results as array\n -d, --difficulty <value> override the minimum difficulty value\n -e, --effort <value> increase demand on GPU processing\n -v, --validate <value> check an existing work value instead of searching for one\n\n -h, --help show this dialog\n --debug enable additional logging output\n --benchmark <value> generate work for specified number of random hashes\n --score <value> used with --benchmark to run specified number of times and calculate work-per-second\n\nIf validating a nonce, it must be a 16-character hexadecimal value.\nEffort must be a decimal number between 1-32.\nDifficulty must be a hexadecimal string between 0-FFFFFFFFFFFFFFFF.\n\nReport bugs: <bug-nano-pow@codecow.com>\nFull documentation: <https://www.npmjs.com/package/nano-pow>\n`)\n\tprocess.exit(0)\n}\n\nconst inArgs: string[] = []\nlet isParsingHash: boolean = true\nwhile (isParsingHash) {\n\tif (!isHex32(args[args.length - 1])) break\n\ttry {\n\t\tinArgs.unshift(args.pop() as string)\n\t} catch {\n\t\tisParsingHash = false\n\t}\n}\nhashes.push(...inArgs)\n\nlet isBatch = false\nlet isBenchmark = false\nlet runs = 1\nconst body: Record<string, any> = {\n\taction: 'work_generate'\n}\n\nfor (let i = 0; i < args.length; i++) {\n\tswitch (args[i]) {\n\t\tcase ('--batch'):\n\t\tcase ('-b'): {\n\t\t\tisBatch = true\n\t\t\tbreak\n\t\t}\n\t\tcase ('--benchmark'): {\n\t\t\tconst b = args[i + 1]\n\t\t\tif (b == null) throw new Error('Missing argument for benchmark')\n\t\t\tconst count = +b\n\t\t\tif (count < 1) throw new Error('Invalid benchmark count')\n\t\t\tgenerateHashes(count)\n\t\t\tisBenchmark = true\n\t\t\tbreak\n\t\t}\n\t\tcase ('--debug'): {\n\t\t\tlogger.isEnabled = true\n\t\t\tprocess.env.NANO_POW_DEBUG = 'true'\n\t\t\tbreak\n\t\t}\n\t\tcase ('--difficulty'):\n\t\tcase ('-d'): {\n\t\t\tconst d = args[i + 1]\n\t\t\tif (d == null) throw new Error('Missing argument for difficulty')\n\t\t\tif (!isHex8(d)) throw new Error('Invalid argument for difficulty')\n\t\t\tbody.difficulty = d\n\t\t\tbreak\n\t\t}\n\t\tcase ('--effort'):\n\t\tcase ('-e'): {\n\t\t\tconst e = args[i + 1]\n\t\t\tif (e == null) throw new Error('Missing argument for effort')\n\t\t\tif (parseInt(e) < 1 || parseInt(e) > 32) throw new Error('Invalid effort')\n\t\t\tprocess.env.NANO_POW_EFFORT = e\n\t\t\tbreak\n\t\t}\n\t\tcase ('--score'): {\n\t\t\tconst s = args[i + 1]\n\t\t\tif (s == null) throw new Error('Missing argument for score')\n\t\t\tconst count = +s\n\t\t\tif (count < 1) throw new Error('Invalid score runs count')\n\t\t\truns = count\n\t\t\tbreak\n\t\t}\n\t\tcase ('--validate'):\n\t\tcase ('-v'): {\n\t\t\tconst v = args[i + 1]\n\t\t\tif (v == null) throw new Error('Missing argument for work validation')\n\t\t\tif (!isHex8(v)) throw new Error('Invalid argument for work validation')\n\t\t\tif (hashes.length !== 1) throw new Error('Validate accepts exactly one hash')\n\t\t\tbody.action = 'work_validate'\n\t\t\tbody.work = v\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nif (hashes.length === 0) {\n\tconsole.error('Invalid block hash input')\n\tprocess.exit(1)\n}\n\nlogger.log('CLI args: ', ...args)\nfor (const stdinErr of stdinErrors) {\n\tlogger.log(stdinErr)\n}\n\n// Initialize server\nlogger.log('launching server')\n\nconst server = spawn(\n\tprocess.execPath,\n\t[new URL(import.meta.resolve('./server.js')).pathname],\n\t{ stdio: ['pipe', 'pipe', 'pipe', 'ipc'] }\n)\n\nserver.once('error', err => {\n\tlogger.log(err)\n\tprocess.exit(1)\n})\n\nserver.on('message', async (msg: Serializable): Promise<void> => {\n\tif (typeof msg === 'object' && msg != null\n\t\t&& 'type' in msg && typeof msg.type === 'string'\n\t\t&& 'data' in msg && typeof msg.data === 'string'\n\t) {\n\t\tif (msg.type === 'console') {\n\t\t\tlogger.log(msg.data)\n\t\t}\n\t\tif (msg.type === 'listening') {\n\t\t\tif (msg.data === 'ipc') {\n\t\t\t\tlogger.log(`CLI connected to server over IPC`)\n\t\t\t\ttry {\n\t\t\t\t\tif (isBenchmark) {\n\t\t\t\t\t\tif (runs > 1) {\n\t\t\t\t\t\t\tawait score()\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tawait benchmark()\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait execute()\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\tlogger.log(`Error executing ${body.action}`)\n\t\t\t\t} finally {\n\t\t\t\t\tserver.kill()\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlogger.log('CLI server failed to connect over IPC')\n\t\t\t}\n\t\t}\n\t} else {\n\t\tlogger.log('received invalid message from server', msg)\n\t}\n})\n\nserver.on('close', code => {\n\tlogger.log(`Server closed with exit code ${code}`)\n\tprocess.exit(code)\n})\n\nasync function benchmark () {\n\tconsole.log('Running benchmark...')\n\tlet start = 0, end = 0\n\tconst times: number[] = []\n\tfor (const hash of hashes) {\n\t\tconst kill = setTimeout(() => {\n\t\t\tthrow new Error('cli execution timed out')\n\t\t}, 60_000)\n\t\tbody.hash = hash\n\t\ttry {\n\t\t\tstart = performance.now()\n\t\t\tawait request(body)\n\t\t\tend = performance.now()\n\t\t\ttimes.push(end - start)\n\t\t} catch (err) {\n\t\t\tlogger.log(err)\n\t\t} finally {\n\t\t\tclearTimeout(kill)\n\t\t}\n\t}\n\tconsole.log(stats(times))\n\treturn stats(times)\n}\n\nasync function execute (): Promise<void> {\n\tconst results: (WorkErrorResponse | WorkGenerateResponse | WorkValidateResponse)[] = []\n\tfor (const hash of hashes) {\n\t\tconst kill = setTimeout(() => {\n\t\t\tthrow new Error('cli execution timed out')\n\t\t}, 60_000)\n\t\tbody.hash = hash\n\t\ttry {\n\t\t\tconst result = await request(body)\n\t\t\tisBatch ? results.push(result) : console.log(result)\n\t\t} catch (err) {\n\t\t\tlogger.log(err)\n\t\t} finally {\n\t\t\tclearTimeout(kill)\n\t\t}\n\t}\n\tif (isBatch) console.log(results)\n}\n\nfunction generateHashes (count: number) {\n\tconst random = new Uint8Array(32)\n\twhile (hashes.length < count) {\n\t\tgetRandomValues(random)\n\t\thashes.push(Buffer.from(random).toString('hex'))\n\t}\n}\n\nasync function request (body: Record<string, any>): Promise<WorkGenerateResponse | WorkValidateResponse | WorkErrorResponse> {\n\treturn new Promise((resolve, reject): void => {\n\t\tconst listener = async (msg: Serializable): Promise<void> => {\n\t\t\tif (typeof msg === 'object' && msg != null\n\t\t\t\t&& 'type' in msg && typeof msg.type === 'string'\n\t\t\t\t&& 'data' in msg && typeof msg.data === 'string'\n\t\t\t) {\n\t\t\t\tif (msg.type === 'ipc') {\n\t\t\t\t\tresolve(JSON.parse(msg.data))\n\t\t\t\t\tserver.off('message', listener)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tserver.on('message', listener)\n\t\tserver.send({ type: 'ipc', data: JSON.stringify(body) }, cb => cb ? reject(cb) : logger.log('cli ipc request to server'))\n\t})\n}\n\nasync function score (): Promise<void> {\n\tconsole.log('Calculating work per second...')\n\tconst rates: number[] = []\n\tfor (let i = 0; i < runs; i++) {\n\t\ttry {\n\t\t\tconst result = await benchmark()\n\t\t\tlogger.log(result)\n\t\t\tif (result != null) rates.push(result.truncatedRate)\n\t\t\tconst count = hashes.length\n\t\t\thashes.splice(0, hashes.length)\n\t\t\tgenerateHashes(count)\n\t\t} catch (err) {\n\t\t\tlogger.log(err)\n\t\t}\n\t}\n\tconsole.log(stats(rates)?.truncatedHarmonic, 'wps')\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["body"]
|
|
7
|
+
}
|