nano-pow 4.1.5 → 4.1.7
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 +149 -71
- package/dist/bin/nano-pow.sh +2 -2
- package/dist/bin/server.js +219 -178
- package/dist/main.min.js +219 -267
- package/dist/types.d.ts +23 -6
- package/package.json +4 -4
package/dist/bin/cli.js
CHANGED
|
@@ -1,18 +1,78 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
|
|
3
|
+
// src/bin/cli.ts
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
5
|
import { getRandomValues } from "node:crypto";
|
|
6
6
|
import { createInterface } from "node:readline/promises";
|
|
7
|
+
|
|
8
|
+
// src/utils/index.ts
|
|
9
|
+
function average(times) {
|
|
10
|
+
if (times == null || times.length === 0) return {};
|
|
11
|
+
let count = times.length;
|
|
12
|
+
let min = Number.MAX_SAFE_INTEGER;
|
|
13
|
+
let logarithms, max, median, rate, reciprocals, total, truncated, truncatedCount;
|
|
14
|
+
logarithms = max = median = rate = reciprocals = total = truncated = truncatedCount = 0;
|
|
15
|
+
times.sort((a, b) => a - b);
|
|
16
|
+
for (let i = 0; i < count; i++) {
|
|
17
|
+
const time = times[i];
|
|
18
|
+
total += time;
|
|
19
|
+
reciprocals += 1 / time;
|
|
20
|
+
logarithms += Math.log(time);
|
|
21
|
+
min = Math.min(min, time);
|
|
22
|
+
max = Math.max(max, time);
|
|
23
|
+
if (i + 1 === Math.ceil(count / 2)) median = time;
|
|
24
|
+
if (count < 3 || i > 0.1 * count && i < 0.9 * (count - 1)) {
|
|
25
|
+
truncated += time;
|
|
26
|
+
truncatedCount++;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
count,
|
|
31
|
+
total,
|
|
32
|
+
min,
|
|
33
|
+
max,
|
|
34
|
+
median,
|
|
35
|
+
arithmetic: total / count,
|
|
36
|
+
harmonic: count / reciprocals,
|
|
37
|
+
geometric: Math.exp(logarithms / count),
|
|
38
|
+
truncated: truncated / truncatedCount,
|
|
39
|
+
rate: 1e3 * truncatedCount / (truncated || total)
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function isHex(input, min, max) {
|
|
43
|
+
if (typeof input !== "string") {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
if (typeof min !== "undefined" && typeof min !== "number") {
|
|
47
|
+
throw new Error(`Invalid argument for parameter 'min'`);
|
|
48
|
+
}
|
|
49
|
+
if (typeof max !== "undefined" && typeof max !== "number") {
|
|
50
|
+
throw new Error(`Invalid argument for parameter 'max'`);
|
|
51
|
+
}
|
|
52
|
+
const range = min === void 0 && max === void 0 ? "+" : `{${min ?? "0"},${max ?? ""}}`;
|
|
53
|
+
const regexp = new RegExp(`^[0-9A-Fa-f]${range}$`, "m");
|
|
54
|
+
return regexp.test(input);
|
|
55
|
+
}
|
|
56
|
+
function isNotHex(input, min, max) {
|
|
57
|
+
return !isHex(input, min, max);
|
|
58
|
+
}
|
|
59
|
+
function log(...args2) {
|
|
60
|
+
if (process?.env?.NANO_POW_DEBUG) {
|
|
61
|
+
const entry = `${new Date(Date.now()).toLocaleString(Intl.DateTimeFormat().resolvedOptions().locale ?? "en-US", { hour12: false, dateStyle: "medium", timeStyle: "medium" })} NanoPow[${process.pid}]: ${args2}`;
|
|
62
|
+
console.log(entry);
|
|
63
|
+
process.send?.({ type: "console", message: entry });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/bin/cli.ts
|
|
68
|
+
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
|
|
69
|
+
//! SPDX-License-Identifier: GPL-3.0-or-later
|
|
7
70
|
process.title = "NanoPow CLI";
|
|
8
71
|
delete process.env.NANO_POW_DEBUG;
|
|
9
72
|
delete process.env.NANO_POW_EFFORT;
|
|
10
73
|
delete process.env.NANO_POW_PORT;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
const hashes = [];
|
|
15
|
-
const stdinErrors = [];
|
|
74
|
+
var hashes = [];
|
|
75
|
+
var stdinErrors = [];
|
|
16
76
|
if (!process.stdin.isTTY) {
|
|
17
77
|
const stdin = createInterface({
|
|
18
78
|
input: process.stdin
|
|
@@ -20,14 +80,14 @@ if (!process.stdin.isTTY) {
|
|
|
20
80
|
let i = 0;
|
|
21
81
|
for await (const line of stdin) {
|
|
22
82
|
i++;
|
|
23
|
-
if (
|
|
83
|
+
if (isHex(line, 64)) {
|
|
24
84
|
hashes.push(line);
|
|
25
85
|
} else {
|
|
26
86
|
stdinErrors.push(`Skipping invalid stdin input line ${i}`);
|
|
27
87
|
}
|
|
28
88
|
}
|
|
29
89
|
}
|
|
30
|
-
|
|
90
|
+
var args = process.argv.slice(2);
|
|
31
91
|
if (hashes.length === 0 && args.length === 0 || args.some((v) => v === "--help" || v === "-h")) {
|
|
32
92
|
console.log(
|
|
33
93
|
`Usage: nano-pow [OPTION]... BLOCKHASH...
|
|
@@ -47,7 +107,7 @@ If using --validate, results will also include validity properties.
|
|
|
47
107
|
|
|
48
108
|
If validating a nonce, it must be a 16-character hexadecimal value.
|
|
49
109
|
Effort must be a decimal number between 1-32.
|
|
50
|
-
Difficulty must be a hexadecimal string between
|
|
110
|
+
Difficulty must be a hexadecimal string between 0-FFFFFFFFFFFFFFFF.
|
|
51
111
|
|
|
52
112
|
Report bugs: <bug-nano-pow@zoso.dev>
|
|
53
113
|
Full documentation: <https://www.npmjs.com/package/nano-pow>
|
|
@@ -55,48 +115,53 @@ Full documentation: <https://www.npmjs.com/package/nano-pow>
|
|
|
55
115
|
);
|
|
56
116
|
process.exit(0);
|
|
57
117
|
}
|
|
58
|
-
|
|
59
|
-
while (
|
|
118
|
+
var inArgs = [];
|
|
119
|
+
while (isHex(args[args.length - 1], 64)) {
|
|
60
120
|
inArgs.unshift(args.pop());
|
|
61
121
|
}
|
|
62
122
|
hashes.push(...inArgs);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
123
|
+
var isBatch = false;
|
|
124
|
+
var isBenchmark = false;
|
|
125
|
+
var body = {
|
|
66
126
|
action: "work_generate"
|
|
67
127
|
};
|
|
68
128
|
for (let i = 0; i < args.length; i++) {
|
|
69
129
|
switch (args[i]) {
|
|
70
130
|
case "--validate":
|
|
71
131
|
case "-v": {
|
|
72
|
-
|
|
73
|
-
if (
|
|
132
|
+
const v = args[i + 1];
|
|
133
|
+
if (v == null) throw new Error("Missing argument for work validation");
|
|
134
|
+
if (isNotHex(v, 16)) throw new Error("Invalid work to validate");
|
|
135
|
+
if (hashes.length !== 1) throw new Error("Validate accepts exactly one hash");
|
|
74
136
|
body.action = "work_validate";
|
|
75
|
-
body.work =
|
|
137
|
+
body.work = v;
|
|
76
138
|
break;
|
|
77
139
|
}
|
|
78
140
|
case "--difficulty":
|
|
79
141
|
case "-d": {
|
|
80
|
-
|
|
81
|
-
if (
|
|
82
|
-
|
|
142
|
+
const d = args[i + 1];
|
|
143
|
+
if (d == null) throw new Error("Missing argument for difficulty");
|
|
144
|
+
if (isNotHex(d, 1, 16)) throw new Error("Invalid difficulty");
|
|
145
|
+
body.difficulty = d;
|
|
83
146
|
break;
|
|
84
147
|
}
|
|
85
148
|
case "--effort":
|
|
86
149
|
case "-e": {
|
|
87
|
-
|
|
88
|
-
if (
|
|
89
|
-
|
|
150
|
+
const e = args[i + 1];
|
|
151
|
+
if (e == null) throw new Error("Missing argument for effort");
|
|
152
|
+
if (parseInt(e) < 1 || parseInt(e) > 32) throw new Error("Invalid effort");
|
|
153
|
+
process.env.NANO_POW_EFFORT = e;
|
|
90
154
|
break;
|
|
91
155
|
}
|
|
92
156
|
case "--benchmark": {
|
|
93
|
-
|
|
94
|
-
if (
|
|
157
|
+
const b = args[i + 1];
|
|
158
|
+
if (b == null) throw new Error("Missing argument for benchmark");
|
|
159
|
+
const count = +b;
|
|
160
|
+
if (count < 1) throw new Error("Invalid benchmark count");
|
|
95
161
|
const random = new Uint8Array(32);
|
|
96
|
-
while (hashes.length <
|
|
162
|
+
while (hashes.length < count) {
|
|
97
163
|
getRandomValues(random);
|
|
98
|
-
|
|
99
|
-
hashes.push(byteArray.join(""));
|
|
164
|
+
hashes.push(Buffer.from(random).toString("hex"));
|
|
100
165
|
}
|
|
101
166
|
isBenchmark = true;
|
|
102
167
|
break;
|
|
@@ -121,53 +186,66 @@ for (const stdinErr of stdinErrors) {
|
|
|
121
186
|
log(stdinErr);
|
|
122
187
|
}
|
|
123
188
|
log("Starting NanoPow CLI");
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
log(`Server listening on port ${msg.port}`);
|
|
133
|
-
resolve(msg.port);
|
|
134
|
-
} else {
|
|
135
|
-
reject("Server failed to provide port");
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
});
|
|
189
|
+
var server = spawn(
|
|
190
|
+
process.execPath,
|
|
191
|
+
[new URL(import.meta.resolve("./server.js")).pathname],
|
|
192
|
+
{ stdio: ["pipe", "pipe", "pipe", "ipc"] }
|
|
193
|
+
);
|
|
194
|
+
server.once("error", (err) => {
|
|
195
|
+
log(err);
|
|
196
|
+
process.exit(1);
|
|
139
197
|
});
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
clearTimeout(kill);
|
|
154
|
-
const result = await response.json();
|
|
155
|
-
if (isBatch || isBenchmark) {
|
|
156
|
-
results.push(result);
|
|
198
|
+
server.on("message", async (msg) => {
|
|
199
|
+
if (msg.type === "console") {
|
|
200
|
+
log(msg.message);
|
|
201
|
+
}
|
|
202
|
+
if (msg.type === "listening") {
|
|
203
|
+
const port = +msg.message;
|
|
204
|
+
if (port > -1) {
|
|
205
|
+
log(`CLI server listening on port ${port}`);
|
|
206
|
+
try {
|
|
207
|
+
await execute(port);
|
|
208
|
+
} catch {
|
|
209
|
+
log(`Error executing ${body.action}`);
|
|
210
|
+
}
|
|
157
211
|
} else {
|
|
158
|
-
|
|
212
|
+
log("Server failed to provide port");
|
|
159
213
|
}
|
|
160
|
-
} catch (err) {
|
|
161
|
-
log(err);
|
|
162
214
|
}
|
|
163
|
-
}
|
|
164
|
-
const end = performance.now();
|
|
165
|
-
if (isBatch && !isBenchmark) console.log(results);
|
|
166
|
-
if (process.env.NANO_POW_DEBUG || isBenchmark) {
|
|
167
|
-
console.log(end - start, "ms total |", (end - start) / hashes.length, "ms avg");
|
|
168
|
-
}
|
|
215
|
+
});
|
|
169
216
|
server.on("close", (code) => {
|
|
170
217
|
log(`Server closed with exit code ${code}`);
|
|
171
218
|
process.exit(code);
|
|
172
219
|
});
|
|
173
|
-
|
|
220
|
+
async function execute(port) {
|
|
221
|
+
const results = [];
|
|
222
|
+
if (isBenchmark) console.log("Running benchmark...");
|
|
223
|
+
let start = 0;
|
|
224
|
+
const times = [];
|
|
225
|
+
for (const hash of hashes) {
|
|
226
|
+
try {
|
|
227
|
+
const aborter = new AbortController();
|
|
228
|
+
const kill = setTimeout(() => aborter.abort(), 6e4);
|
|
229
|
+
body.hash = hash;
|
|
230
|
+
start = performance.now();
|
|
231
|
+
const response = await fetch(`http://localhost:${port}`, {
|
|
232
|
+
method: "POST",
|
|
233
|
+
body: JSON.stringify(body),
|
|
234
|
+
signal: aborter.signal
|
|
235
|
+
});
|
|
236
|
+
clearTimeout(kill);
|
|
237
|
+
const result = await response.json();
|
|
238
|
+
if (isBatch || isBenchmark) {
|
|
239
|
+
results.push(result);
|
|
240
|
+
times.push(performance.now() - start);
|
|
241
|
+
} else {
|
|
242
|
+
console.log(result);
|
|
243
|
+
}
|
|
244
|
+
} catch (err) {
|
|
245
|
+
log(err);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (isBatch && !isBenchmark) console.log(results);
|
|
249
|
+
if (process.env.NANO_POW_DEBUG || isBenchmark) console.log(average(times));
|
|
250
|
+
server.kill();
|
|
251
|
+
}
|
package/dist/bin/nano-pow.sh
CHANGED
|
@@ -10,11 +10,11 @@ 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 --max-http-header-size=1024 >> "$NANO_POW_LOGS"/nano-pow-server-$(date -I).log 2>&1 & echo "$!" > "$NANO_POW_HOME"/server.pid;
|
|
13
|
+
node "$SCRIPT_DIR"/server.js --max-http-header-size=1024 --max-old-space-size=256 >> "$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);
|
|
17
17
|
fi;
|
|
18
18
|
else
|
|
19
|
-
node "$SCRIPT_DIR"/cli.js "$@";
|
|
19
|
+
node "$SCRIPT_DIR"/cli.js --max-old-space-size=256 "$@";
|
|
20
20
|
fi;
|