nano-pow 5.1.14 → 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 +40 -15
- package/dist/bin/cli.d.ts +2 -0
- package/dist/bin/cli.js +15 -322
- package/dist/bin/cli.js.map +7 -0
- package/dist/bin/server.d.ts +2 -0
- package/dist/bin/server.js +35 -308
- package/dist/bin/server.js.map +7 -0
- package/dist/index.d.ts +73 -0
- package/dist/{main.min.js → index.js} +307 -375
- 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
|
@@ -60,7 +60,9 @@ Use it directly on a webpage with a script module:
|
|
|
60
60
|
```javascript
|
|
61
61
|
// `hash` is a 64-char hex string
|
|
62
62
|
const hash = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
|
|
63
|
-
const
|
|
63
|
+
const result = await NanoPow.work_generate(hash);
|
|
64
|
+
const { hash, work, difficulty } = result;
|
|
65
|
+
console.log(work);
|
|
64
66
|
// Result is a 16-char hex string
|
|
65
67
|
```
|
|
66
68
|
|
|
@@ -71,8 +73,10 @@ const { work } = await NanoPow.work_generate(hash);
|
|
|
71
73
|
const work = "fedcba0987654321";
|
|
72
74
|
// `hash` is a 64-char hex string
|
|
73
75
|
const hash = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
+
const result = await NanoPow.work_validate(work, hash);
|
|
77
|
+
const { hash, work, difficulty, valid_all, valid_receive, valid } = result;
|
|
78
|
+
console.log(valid);
|
|
79
|
+
// Result is string '0' or '1'
|
|
76
80
|
```
|
|
77
81
|
|
|
78
82
|
### Options
|
|
@@ -169,25 +173,46 @@ official Nano node software. The installed command will launch the server in a
|
|
|
169
173
|
detached process, and it can also be started manually to customize behavior by
|
|
170
174
|
executing the server script directly.
|
|
171
175
|
|
|
172
|
-
####
|
|
176
|
+
#### Configuration
|
|
173
177
|
|
|
174
|
-
|
|
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:
|
|
175
180
|
|
|
176
|
-
`
|
|
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
|
|
177
184
|
|
|
178
|
-
|
|
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
|
+
```
|
|
179
208
|
|
|
180
209
|
```console
|
|
181
|
-
#
|
|
182
|
-
|
|
183
|
-
# View process ID for "NanoPow Server"
|
|
184
|
-
cat ~/.nano-pow/server.pid
|
|
185
|
-
# Display list of server logs
|
|
186
|
-
ls ~/.nano-pow/logs/
|
|
187
|
-
# Find process ID manually
|
|
188
|
-
pgrep NanoPow
|
|
210
|
+
$ # Find process ID manually
|
|
211
|
+
$ pgrep NanoPow
|
|
189
212
|
```
|
|
190
213
|
|
|
214
|
+
#### Usage
|
|
215
|
+
|
|
191
216
|
Work is generated or validated by sending an HTTP `POST` request to the
|
|
192
217
|
configured hostname or IP address of the machine. Some basic help is available
|
|
193
218
|
via `GET` request.
|
package/dist/bin/cli.js
CHANGED
|
@@ -1,325 +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 search(hash, difficulty) {
|
|
166
|
-
const bigintHash = bigintFrom(hash, "hex");
|
|
167
|
-
const item = this.#getItem("NanoPowCache");
|
|
168
|
-
if (item) {
|
|
169
|
-
const cache = JSON.parse(item);
|
|
170
|
-
for (const c of cache) {
|
|
171
|
-
if (bigintFrom(c.hash, "hex") === bigintHash && bigintFrom(c.difficulty, "hex") >= difficulty) {
|
|
172
|
-
return c;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
return null;
|
|
177
|
-
}
|
|
178
|
-
static store(result) {
|
|
179
|
-
const item = this.#getItem("NanoPowCache");
|
|
180
|
-
const cache = JSON.parse(item ?? "[]");
|
|
181
|
-
if (cache.push(result) > 1e3) cache.shift();
|
|
182
|
-
this.#setItem("NanoPowCache", JSON.stringify(cache));
|
|
183
|
-
return result;
|
|
184
|
-
}
|
|
185
|
-
static #storage = {};
|
|
186
|
-
static #getItem(key) {
|
|
187
|
-
if (globalThis?.localStorage) return globalThis.localStorage.getItem(key);
|
|
188
|
-
return this.#storage[key];
|
|
189
|
-
}
|
|
190
|
-
static #removeItem(key) {
|
|
191
|
-
if (globalThis?.localStorage) return globalThis.localStorage.removeItem(key);
|
|
192
|
-
this.#storage = {};
|
|
193
|
-
}
|
|
194
|
-
static #setItem(key, item) {
|
|
195
|
-
if (globalThis?.localStorage) return globalThis.localStorage.setItem(key, item);
|
|
196
|
-
this.#storage[key] = item;
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
// src/utils/logger.ts
|
|
201
|
-
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
|
|
202
|
-
//! SPDX-License-Identifier: GPL-3.0-or-later
|
|
203
|
-
var Logger = class {
|
|
204
|
-
isEnabled = false;
|
|
205
|
-
groups = {};
|
|
206
|
-
groupStart(name) {
|
|
207
|
-
if (this.isEnabled) {
|
|
208
|
-
console.groupCollapsed(name);
|
|
209
|
-
this.groups[name] = true;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
groupEnd(name) {
|
|
213
|
-
if (this.groups[name]) {
|
|
214
|
-
console.groupEnd();
|
|
215
|
-
delete this.groups[name];
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
log(...args2) {
|
|
219
|
-
if (this.isEnabled) {
|
|
220
|
-
const datetime = new Date(Date.now()).toLocaleString(Intl.DateTimeFormat().resolvedOptions().locale ?? "en-US", { hour12: false, dateStyle: "medium", timeStyle: "medium" });
|
|
221
|
-
for (let i = 0; i < args2.length; i++) {
|
|
222
|
-
if (typeof args2[i] === "string") {
|
|
223
|
-
args2[i] = args2[i].replace(datetime, "").trimStart();
|
|
224
|
-
}
|
|
225
|
-
if (args2[i] instanceof Error) {
|
|
226
|
-
if ("stack" in args2[i]) {
|
|
227
|
-
args2.splice(i + 1, 0, args2[i].stack);
|
|
228
|
-
} else if ("message" in args2[i]) {
|
|
229
|
-
args2.splice(i + 1, 0, args2[i].message);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
const entry = `${datetime} ${globalThis.process?.title ?? "NanoPow"}[${globalThis.process?.pid ?? "browser"}]:`;
|
|
234
|
-
console.log(entry, ...args2);
|
|
235
|
-
globalThis.process?.send?.({ type: "console", data: `${entry} ${args2}` });
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
// src/utils/queue.ts
|
|
241
|
-
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
|
|
242
|
-
//! SPDX-License-Identifier: GPL-3.0-or-later
|
|
243
|
-
|
|
244
|
-
// src/utils/index.ts
|
|
245
|
-
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
|
|
246
|
-
//! SPDX-License-Identifier: GPL-3.0-or-later
|
|
247
|
-
var clearCache = Cache.clear;
|
|
248
|
-
function isHexN(value, byteLength) {
|
|
249
|
-
if (typeof value !== "string") return false;
|
|
250
|
-
const v = value.replace(/^0[Xx]/, "");
|
|
251
|
-
const length = byteLength === null ? "+" : `{${2 * byteLength}}`;
|
|
252
|
-
const r = new RegExp(`^[A-Fa-f\\d]${length}$`);
|
|
253
|
-
return r.test(v);
|
|
254
|
-
}
|
|
255
|
-
function isHex8(value) {
|
|
256
|
-
return isHexN(value, 8);
|
|
257
|
-
}
|
|
258
|
-
function isHex32(value) {
|
|
259
|
-
return isHexN(value, 32);
|
|
260
|
-
}
|
|
261
|
-
function stats(times) {
|
|
262
|
-
if (times == null || times.length === 0) return null;
|
|
263
|
-
const count = times.length;
|
|
264
|
-
const truncatedStart = Math.floor(count * 0.1);
|
|
265
|
-
const truncatedEnd = count - truncatedStart;
|
|
266
|
-
const truncatedCount = truncatedEnd - truncatedStart;
|
|
267
|
-
let min = Number.MAX_SAFE_INTEGER;
|
|
268
|
-
let logarithms, max, median, reciprocals, total;
|
|
269
|
-
logarithms = max = median = reciprocals = total = 0;
|
|
270
|
-
let truncatedMin = Number.MAX_SAFE_INTEGER;
|
|
271
|
-
let truncatedLogarithms, truncatedMax, truncatedReciprocals, truncatedTotal;
|
|
272
|
-
truncatedLogarithms = truncatedMax = truncatedReciprocals = truncatedTotal = 0;
|
|
273
|
-
times.sort((a, b) => a - b);
|
|
274
|
-
for (let i = 0; i < count; i++) {
|
|
275
|
-
const time = times[i];
|
|
276
|
-
total += time;
|
|
277
|
-
logarithms += Math.log(time);
|
|
278
|
-
reciprocals += 1 / time;
|
|
279
|
-
min = Math.min(min, time);
|
|
280
|
-
max = Math.max(max, time);
|
|
281
|
-
if (i === Math.floor((count - 1) / 2)) median = time;
|
|
282
|
-
if (i === Math.floor(count / 2) && count % 2 === 0) median = (median + time) / 2;
|
|
283
|
-
}
|
|
284
|
-
for (let i = truncatedStart; i < truncatedEnd; i++) {
|
|
285
|
-
const time = times[i];
|
|
286
|
-
truncatedTotal += time;
|
|
287
|
-
truncatedLogarithms += Math.log(time);
|
|
288
|
-
truncatedReciprocals += 1 / time;
|
|
289
|
-
truncatedMin = Math.min(truncatedMin, time);
|
|
290
|
-
truncatedMax = Math.max(truncatedMax, time);
|
|
291
|
-
}
|
|
292
|
-
return {
|
|
293
|
-
count,
|
|
294
|
-
total,
|
|
295
|
-
rate: 1e3 * count / total,
|
|
296
|
-
min,
|
|
297
|
-
max,
|
|
298
|
-
median,
|
|
299
|
-
arithmetic: total / count,
|
|
300
|
-
geometric: Math.exp(logarithms / count),
|
|
301
|
-
harmonic: count / reciprocals,
|
|
302
|
-
truncatedCount,
|
|
303
|
-
truncatedTotal,
|
|
304
|
-
truncatedRate: 1e3 * truncatedCount / truncatedTotal,
|
|
305
|
-
truncatedMin,
|
|
306
|
-
truncatedMax,
|
|
307
|
-
truncatedArithmetic: truncatedTotal / truncatedCount,
|
|
308
|
-
truncatedGeometric: Math.exp(truncatedLogarithms / truncatedCount),
|
|
309
|
-
truncatedHarmonic: truncatedCount / truncatedReciprocals
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// src/bin/cli.ts
|
|
314
|
-
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
|
|
315
|
-
//! SPDX-License-Identifier: GPL-3.0-or-later
|
|
316
8
|
process.title = "NanoPow CLI";
|
|
317
|
-
|
|
9
|
+
const logger = new Logger();
|
|
318
10
|
delete process.env.NANO_POW_DEBUG;
|
|
319
11
|
delete process.env.NANO_POW_EFFORT;
|
|
320
12
|
delete process.env.NANO_POW_PORT;
|
|
321
|
-
|
|
322
|
-
|
|
13
|
+
const hashes = [];
|
|
14
|
+
const stdinErrors = [];
|
|
323
15
|
if (!process.stdin.isTTY) {
|
|
324
16
|
const stdin = createInterface({
|
|
325
17
|
input: process.stdin
|
|
@@ -334,7 +26,7 @@ if (!process.stdin.isTTY) {
|
|
|
334
26
|
}
|
|
335
27
|
}
|
|
336
28
|
}
|
|
337
|
-
|
|
29
|
+
const args = process.argv.slice(2);
|
|
338
30
|
if (hashes.length === 0 && args.length === 0 || args.some((v) => v === "--help" || v === "-h")) {
|
|
339
31
|
console.log(`Usage: nano-pow [OPTION]... BLOCKHASH...
|
|
340
32
|
Generate work for BLOCKHASH, or multiple work values for BLOCKHASH(es)
|
|
@@ -362,8 +54,8 @@ Full documentation: <https://www.npmjs.com/package/nano-pow>
|
|
|
362
54
|
`);
|
|
363
55
|
process.exit(0);
|
|
364
56
|
}
|
|
365
|
-
|
|
366
|
-
|
|
57
|
+
const inArgs = [];
|
|
58
|
+
let isParsingHash = true;
|
|
367
59
|
while (isParsingHash) {
|
|
368
60
|
if (!isHex32(args[args.length - 1])) break;
|
|
369
61
|
try {
|
|
@@ -373,10 +65,10 @@ while (isParsingHash) {
|
|
|
373
65
|
}
|
|
374
66
|
}
|
|
375
67
|
hashes.push(...inArgs);
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
68
|
+
let isBatch = false;
|
|
69
|
+
let isBenchmark = false;
|
|
70
|
+
let runs = 1;
|
|
71
|
+
const body = {
|
|
380
72
|
action: "work_generate"
|
|
381
73
|
};
|
|
382
74
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -445,7 +137,7 @@ for (const stdinErr of stdinErrors) {
|
|
|
445
137
|
logger.log(stdinErr);
|
|
446
138
|
}
|
|
447
139
|
logger.log("launching server");
|
|
448
|
-
|
|
140
|
+
const server = spawn(
|
|
449
141
|
process.execPath,
|
|
450
142
|
[new URL(import.meta.resolve("./server.js")).pathname],
|
|
451
143
|
{ stdio: ["pipe", "pipe", "pipe", "ipc"] }
|
|
@@ -568,3 +260,4 @@ async function score() {
|
|
|
568
260
|
}
|
|
569
261
|
console.log(stats(rates)?.truncatedHarmonic, "wps");
|
|
570
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
|
+
}
|