nano-pow 4.1.4 → 4.1.6
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 -68
- package/dist/bin/nano-pow.sh +2 -2
- package/dist/bin/server.js +237 -139
- package/dist/main.min.js +224 -266
- package/dist/types.d.ts +23 -6
- package/package.json +2 -2
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,50 +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
|
-
reject("Server failed to provide port");
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
});
|
|
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);
|
|
136
197
|
});
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
clearTimeout(kill);
|
|
151
|
-
const result = await response.json();
|
|
152
|
-
if (isBatch || isBenchmark) {
|
|
153
|
-
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
|
+
}
|
|
154
211
|
} else {
|
|
155
|
-
|
|
212
|
+
log("Server failed to provide port");
|
|
156
213
|
}
|
|
157
|
-
} catch (err) {
|
|
158
|
-
log(err);
|
|
159
214
|
}
|
|
160
|
-
}
|
|
161
|
-
const end = performance.now();
|
|
162
|
-
if (isBatch && !isBenchmark) console.log(results);
|
|
163
|
-
if (process.env.NANO_POW_DEBUG || isBenchmark) {
|
|
164
|
-
console.log(end - start, "ms total |", (end - start) / hashes.length, "ms avg");
|
|
165
|
-
}
|
|
215
|
+
});
|
|
166
216
|
server.on("close", (code) => {
|
|
167
217
|
log(`Server closed with exit code ${code}`);
|
|
168
218
|
process.exit(code);
|
|
169
219
|
});
|
|
170
|
-
|
|
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 >> "$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;
|