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 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
- Chris Duncan <chris@codecow.com> (codecow.com)
7
- Ben Green <ben@latenightsketches.com> (numtel.github.io)
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
- #### Environment Variables
176
+ #### Configuration
177
177
 
178
- `NANO_POW_DEBUG`: enable additional logging saved to the HOME directory
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
- `NANO_POW_EFFORT`: increase or decrease demand on the GPU
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
- `NANO_POW_PORT`: override the default port 5040
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
- # Launch the server and detach from the current session
186
- NANO_POW_PORT=8080 nano-pow --server
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.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/bin/cli.js CHANGED
@@ -1,337 +1,17 @@
1
1
  #!/usr/bin/env node
2
-
3
- // src/bin/cli.ts
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
- var logger = new Logger();
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
- var hashes = [];
334
- var stdinErrors = [];
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
- var args = process.argv.slice(2);
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
- var inArgs = [];
378
- var isParsingHash = true;
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
- var isBatch = false;
389
- var isBenchmark = false;
390
- var runs = 1;
391
- var body = {
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
- var server = spawn(
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
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};