nano-pow 4.1.2 → 4.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/cli.js CHANGED
@@ -1,12 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
3
3
  //! SPDX-License-Identifier: GPL-3.0-or-later
4
+ import { spawn } from "node:child_process";
4
5
  import { getRandomValues } from "node:crypto";
5
6
  import { createInterface } from "node:readline/promises";
6
7
  process.title = "NanoPow CLI";
7
8
  delete process.env.NANO_POW_DEBUG;
8
- process.env.NANO_POW_EFFORT = "";
9
- process.env.NANO_POW_PORT = "5041";
9
+ delete process.env.NANO_POW_EFFORT;
10
+ delete process.env.NANO_POW_PORT;
10
11
  function log(...args2) {
11
12
  if (process.env.NANO_POW_DEBUG) console.log(new Date(Date.now()).toLocaleString(), "NanoPow", args2);
12
13
  }
@@ -35,16 +36,15 @@ BLOCKHASH is a 64-character hexadecimal string. Multiple blockhashes must be sep
35
36
  Prints the result as a Javascript object to standard output as soon as it is calculated.
36
37
  If using --batch, results are printed only after all BLOCKHASH(es) have be processed.
37
38
  If using --validate, results will also include validity properties.
38
-
39
- -h, --help show this dialog
40
- --debug enable additional logging output
41
- --benchmark <value> generate work for specified number of random hashes
42
-
43
39
  -b, --batch process all data before returning final results as array
44
40
  -d, --difficulty <value> override the minimum difficulty value
45
41
  -e, --effort <value> increase demand on GPU processing
46
42
  -v, --validate <value> check an existing work value instead of searching for one
47
43
 
44
+ -h, --help show this dialog
45
+ --debug enable additional logging output
46
+ --benchmark <value> generate work for specified number of random hashes
47
+
48
48
  If validating a nonce, it must be a 16-character hexadecimal value.
49
49
  Effort must be a decimal number between 1-32.
50
50
  Difficulty must be a hexadecimal string between 1-FFFFFFFFFFFFFFFF.
@@ -121,7 +121,19 @@ for (const stdinErr of stdinErrors) {
121
121
  log(stdinErr);
122
122
  }
123
123
  log("Starting NanoPow CLI");
124
- await import("./server.js");
124
+ const server = spawn(process.execPath, [new URL(import.meta.resolve("./server.js")).pathname], { stdio: ["pipe", "pipe", "pipe", "ipc"] });
125
+ const port = await new Promise((resolve, reject) => {
126
+ server.on("message", (msg) => {
127
+ if (msg.type === "listening") {
128
+ if (msg.port != null) {
129
+ log(`Server listening on port ${msg.port}`);
130
+ resolve(msg.port);
131
+ } else {
132
+ reject("Server failed to provide port");
133
+ }
134
+ }
135
+ });
136
+ });
125
137
  const results = [];
126
138
  const aborter = new AbortController();
127
139
  if (isBenchmark) console.log("Starting benchmark...");
@@ -130,7 +142,7 @@ for (const hash of hashes) {
130
142
  try {
131
143
  body.hash = hash;
132
144
  const kill = setTimeout(() => aborter.abort(), 6e4);
133
- const response = await fetch(`http://localhost:${process.env.NANO_POW_PORT}`, {
145
+ const response = await fetch(`http://localhost:${port}`, {
134
146
  method: "POST",
135
147
  body: JSON.stringify(body),
136
148
  signal: aborter.signal
@@ -151,4 +163,8 @@ if (isBatch && !isBenchmark) console.log(results);
151
163
  if (process.env.NANO_POW_DEBUG || isBenchmark) {
152
164
  console.log(end - start, "ms total |", (end - start) / hashes.length, "ms avg");
153
165
  }
154
- process.exit(0);
166
+ server.on("close", (code) => {
167
+ log(`Server closed with exit code ${code}`);
168
+ process.exit(code);
169
+ });
170
+ server.kill();
@@ -10,7 +10,7 @@ NANO_POW_LOGS="$NANO_POW_HOME"/logs;
10
10
  mkdir -p "$NANO_POW_LOGS";
11
11
  if [ "$1" = '--server' ]; then
12
12
  shift;
13
- node "$SCRIPT_DIR"/server.js > "$NANO_POW_LOGS"/nano-pow-server-$(date -u -Iseconds).log 2>&1 & echo "$!" > "$NANO_POW_HOME"/server.pid;
13
+ node "$SCRIPT_DIR"/server.js >> "$NANO_POW_LOGS"/nano-pow-server-$(date -I).log 2>&1 & echo "$!" > "$NANO_POW_HOME"/server.pid;
14
14
  sleep 0.1;
15
15
  if [ "$(ps | grep $(cat $NANO_POW_HOME/server.pid))" = '' ]; then
16
16
  cat $(ls -td "$NANO_POW_LOGS"/* | head -n1);
@@ -3,43 +3,61 @@
3
3
  //! SPDX-License-Identifier: GPL-3.0-or-later
4
4
  import { launch } from "puppeteer";
5
5
  import { subtle } from "node:crypto";
6
- import { lookup } from "node:dns/promises";
7
6
  import { readFile, unlink, writeFile } from "node:fs/promises";
8
7
  import * as http from "node:http";
9
- import { homedir, hostname } from "node:os";
8
+ import { homedir } from "node:os";
10
9
  import { join } from "node:path";
10
+ function log(...args) {
11
+ if (CONFIG.DEBUG) {
12
+ const d = new Date(Date.now());
13
+ const opts = {
14
+ hour12: false,
15
+ dateStyle: "medium",
16
+ timeStyle: "medium"
17
+ };
18
+ console.log(d.toLocaleString(navigator.language, opts), `NanoPow[${process.pid}]:`, args);
19
+ }
20
+ }
11
21
  process.title = "NanoPow Server";
12
22
  const MAX_REQUEST_SIZE = 1024;
13
23
  const MAX_BODY_SIZE = 158;
14
- let DEBUG = !!(process.env.NANO_POW_DEBUG || false);
15
- let EFFORT = +(process.env.NANO_POW_EFFORT || 8);
16
- let PORT = +(process.env.NANO_POW_PORT || 5040);
17
- let browser;
18
- let page;
19
- function log(...args) {
20
- if (DEBUG) console.log(new Date(Date.now()).toLocaleString(), "NanoPow", args);
21
- }
24
+ const CONFIG = {
25
+ DEBUG: false,
26
+ EFFORT: 8,
27
+ PORT: 5040
28
+ };
22
29
  async function loadConfig() {
23
- const contents = await readFile(join(homedir(), ".nano-pow", "config"), "utf-8");
30
+ let contents = null;
31
+ try {
32
+ contents = await readFile(join(homedir(), ".nano-pow", "config"), "utf-8");
33
+ } catch (err) {
34
+ log("Config file not found");
35
+ }
24
36
  if (typeof contents === "string") {
25
- const config = contents.split("\n");
26
- for (const line of config) {
37
+ for (const line of contents.split("\n")) {
27
38
  const debugMatch = line.match(/^[ \t]*debug[ \t]*(true|false)[ \t]*(#.*)?$/i);
28
39
  if (Array.isArray(debugMatch)) {
29
- DEBUG = !!process.env.NANO_POW_DEBUG || debugMatch?.[1] === "true" || false;
40
+ CONFIG.DEBUG = debugMatch[1] === "true";
30
41
  }
31
42
  const effortMatch = line.match(/^[ \t]*effort[ \t]*(\d{1,2})[ \t]*(#.*)?$/i);
32
43
  if (Array.isArray(effortMatch)) {
33
- EFFORT = +(process.env.NANO_POW_EFFORT || effortMatch?.[1] || 8);
44
+ CONFIG.EFFORT = +effortMatch[1];
34
45
  }
35
46
  const portMatch = line.match(/^[ \t]*port[ \t]*(\d{1,5})[ \t]*(#.*)?$/i);
36
47
  if (Array.isArray(portMatch)) {
37
- PORT = +(process.env.NANO_POW_PORT || portMatch?.[1] || 5040);
48
+ CONFIG.PORT = +portMatch[1];
38
49
  }
39
50
  }
40
51
  }
52
+ CONFIG.DEBUG = !!process.env.NANO_POW_DEBUG || CONFIG.DEBUG;
53
+ CONFIG.EFFORT = +(process.env.NANO_POW_EFFORT ?? "") || CONFIG.EFFORT;
54
+ CONFIG.PORT = process.send ? 0 : +(process.env.NANO_POW_PORT ?? "") || CONFIG.PORT;
41
55
  }
42
56
  await loadConfig();
57
+ process.on("SIGHUP", async () => {
58
+ log("Reloading configuration");
59
+ await loadConfig();
60
+ });
43
61
  async function respond(res, data) {
44
62
  let statusCode = 500;
45
63
  let headers = { "Content-Type": "application/json" };
@@ -64,8 +82,8 @@ async function respond(res, data) {
64
82
  }
65
83
  response = `${action} failed`;
66
84
  const options = {
67
- debug: DEBUG,
68
- effort: EFFORT,
85
+ debug: CONFIG.DEBUG,
86
+ effort: CONFIG.EFFORT,
69
87
  difficulty
70
88
  };
71
89
  const args = [];
@@ -139,7 +157,8 @@ function shutdown() {
139
157
  log("Server unresponsive, forcefully stopped");
140
158
  process.exit(1);
141
159
  }, 1e4);
142
- server.close(() => {
160
+ server.close(async () => {
161
+ await browser.close();
143
162
  clearTimeout(kill);
144
163
  log("Server stopped");
145
164
  process.exit(0);
@@ -149,7 +168,10 @@ process.on("SIGINT", shutdown);
149
168
  process.on("SIGTERM", shutdown);
150
169
  log("Starting NanoPow work server");
151
170
  const NanoPow = await readFile(new URL("../main.min.js", import.meta.url), "utf-8");
152
- browser = await launch({
171
+ const browser = await launch({
172
+ handleSIGHUP: false,
173
+ handleSIGINT: false,
174
+ handleSIGTERM: false,
153
175
  headless: true,
154
176
  args: [
155
177
  "--headless=new",
@@ -159,7 +181,7 @@ browser = await launch({
159
181
  "--enable-unsafe-webgpu"
160
182
  ]
161
183
  });
162
- page = await browser.newPage();
184
+ const page = await browser.newPage();
163
185
  page.on("console", (msg) => log(msg.text()));
164
186
  const path = new URL(import.meta.url).pathname;
165
187
  const dir = path.slice(0, path.lastIndexOf("/"));
@@ -180,7 +202,9 @@ await page.setContent(`
180
202
  `);
181
203
  await unlink(filename);
182
204
  log("Puppeteer initialized");
183
- server.listen(PORT, async () => {
184
- const ip = await lookup(hostname(), { family: 4 });
185
- log(`Server process ${process.pid} running at ${ip.address}:${PORT}/`);
205
+ server.listen(CONFIG.PORT, async () => {
206
+ const { port } = server.address();
207
+ CONFIG.PORT = port;
208
+ log(`Server listening on port ${port}`);
209
+ process.send?.({ type: "listening", port });
186
210
  });
package/docs/nano-pow.1 CHANGED
@@ -25,15 +25,6 @@ If \fB--validate\fR is used, the original work value is returned instead along w
25
25
  \fB--server\fR
26
26
  Start work server (see SERVER below). Must be the first argument in order to be recognized.
27
27
  .TP
28
- \fB\-h\fR, \fB\-\-help\fR
29
- Show this help dialog and exit.
30
- .TP
31
- \fB\-\-debug\fR
32
- Enable additional logging output.
33
- .TP
34
- \fB\-\-benchmark\fR \fICOUNT\fR
35
- Generate work for the specified number of random hashes.
36
- .TP
37
28
  \fB\-b\fR, \fB\-\-batch\fR
38
29
  Format final output of all hashes as a JSON array instead of incrementally returning an object for each result as soon as it is calculated.
39
30
  .TP
@@ -45,6 +36,15 @@ Increase demand on GPU processing. Must be between 1 and 32 inclusive.
45
36
  .TP
46
37
  \fB\-v\fR, \fB\-\-validate\fR \fIWORK\fR
47
38
  Check an existing work value instead of searching for one. If you pass multiple blockhashes, the work value will be validated against each one.
39
+ .TP
40
+ \fB\-h\fR, \fB\-\-help\fR
41
+ Show this help dialog and exit.
42
+ .TP
43
+ \fB\-\-debug\fR
44
+ Enable additional logging output.
45
+ .TP
46
+ \fB\-\-benchmark\fR \fICOUNT\fR
47
+ Generate work for the specified number of random hashes.
48
48
 
49
49
  .SH SERVER
50
50
  Calling \fBnano-pow\fR with the \fI--server\fR option will start the NanoPow work server in a detached process.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nano-pow",
3
- "version": "4.1.2",
3
+ "version": "4.1.4",
4
4
  "description": "Proof-of-work generation and validation with WebGPU/WebGL for Nano cryptocurrency.",
5
5
  "keywords": [
6
6
  "nemo",
@@ -52,11 +52,14 @@
52
52
  "test": "npm run build && ./test/script.sh"
53
53
  },
54
54
  "devDependencies": {
55
- "@types/node": "^22.13.11",
56
- "@webgpu/types": "^0.1.57",
57
- "esbuild": "^0.25.1",
55
+ "@types/node": "^22.14.1",
56
+ "@webgpu/types": "^0.1.60",
57
+ "esbuild": "^0.25.2",
58
58
  "esbuild-plugin-glsl": "^1.4.0",
59
- "typescript": "^5.8.2"
59
+ "typescript": "^5.8.3"
60
+ },
61
+ "optionalDependencies": {
62
+ "puppeteer": "^24.6.1"
60
63
  },
61
64
  "type": "module",
62
65
  "exports": {
@@ -66,8 +69,5 @@
66
69
  }
67
70
  },
68
71
  "types": "./dist/types.d.ts",
69
- "unpkg": "./dist/main.min.js",
70
- "optionalDependencies": {
71
- "puppeteer": "^24.4.0"
72
- }
72
+ "unpkg": "./dist/main.min.js"
73
73
  }