nano-pow 4.1.1 → 4.1.3

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
- process.env.NANO_POW_DEBUG = "";
8
- process.env.NANO_POW_EFFORT = "";
9
- process.env.NANO_POW_PORT = "5041";
8
+ delete process.env.NANO_POW_DEBUG;
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();
@@ -3,22 +3,53 @@
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 { 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) console.log(new Date(Date.now()).toLocaleString(), "NanoPow", args);
12
+ }
11
13
  process.title = "NanoPow Server";
12
14
  const MAX_REQUEST_SIZE = 1024;
13
15
  const MAX_BODY_SIZE = 158;
14
- const DEBUG = !!(process.env.NANO_POW_DEBUG || false);
15
- const EFFORT = +(process.env.NANO_POW_EFFORT || 8);
16
- const 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);
16
+ const CONFIG = {
17
+ DEBUG: false,
18
+ EFFORT: 8,
19
+ PORT: 5040
20
+ };
21
+ async function loadConfig() {
22
+ let contents = null;
23
+ try {
24
+ contents = await readFile(join(homedir(), ".nano-pow", "config"), "utf-8");
25
+ } catch (err) {
26
+ log("Config file not found");
27
+ }
28
+ if (typeof contents === "string") {
29
+ for (const line of contents.split("\n")) {
30
+ const debugMatch = line.match(/^[ \t]*debug[ \t]*(true|false)[ \t]*(#.*)?$/i);
31
+ if (Array.isArray(debugMatch)) {
32
+ CONFIG.DEBUG = debugMatch[1] === "true";
33
+ }
34
+ const effortMatch = line.match(/^[ \t]*effort[ \t]*(\d{1,2})[ \t]*(#.*)?$/i);
35
+ if (Array.isArray(effortMatch)) {
36
+ CONFIG.EFFORT = +effortMatch[1];
37
+ }
38
+ const portMatch = line.match(/^[ \t]*port[ \t]*(\d{1,5})[ \t]*(#.*)?$/i);
39
+ if (Array.isArray(portMatch)) {
40
+ CONFIG.PORT = +portMatch[1];
41
+ }
42
+ }
43
+ }
44
+ CONFIG.DEBUG = !!process.env.NANO_POW_DEBUG || CONFIG.DEBUG;
45
+ CONFIG.EFFORT = +(process.env.NANO_POW_EFFORT ?? "") || CONFIG.EFFORT;
46
+ CONFIG.PORT = process.send ? 0 : +(process.env.NANO_POW_PORT ?? "") || CONFIG.PORT;
21
47
  }
48
+ await loadConfig();
49
+ process.on("SIGHUP", async () => {
50
+ log("Reloading configuration");
51
+ await loadConfig();
52
+ });
22
53
  async function respond(res, data) {
23
54
  let statusCode = 500;
24
55
  let headers = { "Content-Type": "application/json" };
@@ -43,8 +74,8 @@ async function respond(res, data) {
43
74
  }
44
75
  response = `${action} failed`;
45
76
  const options = {
46
- debug: DEBUG,
47
- effort: EFFORT,
77
+ debug: CONFIG.DEBUG,
78
+ effort: CONFIG.EFFORT,
48
79
  difficulty
49
80
  };
50
81
  const args = [];
@@ -118,7 +149,8 @@ function shutdown() {
118
149
  log("Server unresponsive, forcefully stopped");
119
150
  process.exit(1);
120
151
  }, 1e4);
121
- server.close(() => {
152
+ server.close(async () => {
153
+ await browser.close();
122
154
  clearTimeout(kill);
123
155
  log("Server stopped");
124
156
  process.exit(0);
@@ -128,7 +160,10 @@ process.on("SIGINT", shutdown);
128
160
  process.on("SIGTERM", shutdown);
129
161
  log("Starting NanoPow work server");
130
162
  const NanoPow = await readFile(new URL("../main.min.js", import.meta.url), "utf-8");
131
- browser = await launch({
163
+ const browser = await launch({
164
+ handleSIGHUP: false,
165
+ handleSIGINT: false,
166
+ handleSIGTERM: false,
132
167
  headless: true,
133
168
  args: [
134
169
  "--headless=new",
@@ -138,7 +173,7 @@ browser = await launch({
138
173
  "--enable-unsafe-webgpu"
139
174
  ]
140
175
  });
141
- page = await browser.newPage();
176
+ const page = await browser.newPage();
142
177
  page.on("console", (msg) => log(msg.text()));
143
178
  const path = new URL(import.meta.url).pathname;
144
179
  const dir = path.slice(0, path.lastIndexOf("/"));
@@ -159,7 +194,8 @@ await page.setContent(`
159
194
  `);
160
195
  await unlink(filename);
161
196
  log("Puppeteer initialized");
162
- server.listen(PORT, async () => {
163
- const ip = await lookup(hostname(), { family: 4 });
164
- log(`Server process ${process.pid} running at ${ip.address}:${PORT}/`);
197
+ server.listen(CONFIG.PORT, async () => {
198
+ const { port } = server.address();
199
+ log(`Server process ${process.pid} listening on port ${port}`);
200
+ process.send?.({ type: "listening", port });
165
201
  });
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.1",
3
+ "version": "4.1.3",
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
  }