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 +26 -10
- package/dist/bin/nano-pow.sh +1 -1
- package/dist/bin/server.js +48 -24
- package/docs/nano-pow.1 +9 -9
- package/package.json +9 -9
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
|
|
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
|
-
|
|
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:${
|
|
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
|
-
|
|
166
|
+
server.on("close", (code) => {
|
|
167
|
+
log(`Server closed with exit code ${code}`);
|
|
168
|
+
process.exit(code);
|
|
169
|
+
});
|
|
170
|
+
server.kill();
|
package/dist/bin/nano-pow.sh
CHANGED
|
@@ -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
|
|
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);
|
package/dist/bin/server.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 = +
|
|
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 = +
|
|
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
|
|
185
|
-
|
|
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.
|
|
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.
|
|
56
|
-
"@webgpu/types": "^0.1.
|
|
57
|
-
"esbuild": "^0.25.
|
|
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.
|
|
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
|
}
|