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 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
@@ -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 { work } = await NanoPow.work_generate(hash);
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 { valid } = await NanoPow.work_validate(work, hash);
75
- // Result is a boolean
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
- #### Environment Variables
176
+ #### Configuration
173
177
 
174
- `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:
175
180
 
176
- `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
177
184
 
178
- `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
+ ```
179
208
 
180
209
  ```console
181
- # Launch the server and detach from the current session
182
- NANO_POW_PORT=8080 nano-pow --server
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.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/bin/cli.js CHANGED
@@ -1,325 +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 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
- var logger = new Logger();
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
- var hashes = [];
322
- var stdinErrors = [];
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
- var args = process.argv.slice(2);
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
- var inArgs = [];
366
- var isParsingHash = true;
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
- var isBatch = false;
377
- var isBenchmark = false;
378
- var runs = 1;
379
- var body = {
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
- var server = spawn(
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
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};