nano-pow 3.1.3 → 3.2.0

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.
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env node
2
+ //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
3
+ //! SPDX-License-Identifier: GPL-3.0-or-later
4
+ import * as fs from "node:fs/promises";
5
+ import * as readline from "node:readline/promises";
6
+ import * as puppeteer from "puppeteer";
7
+ const hashes = [];
8
+ const stdinErrors = [];
9
+ if (!process.stdin.isTTY) {
10
+ const stdin = readline.createInterface({
11
+ input: process.stdin
12
+ });
13
+ for await (const line of stdin) {
14
+ if (/^[0-9A-Fa-f]{64}$/.test(line)) {
15
+ hashes.push(line);
16
+ } else {
17
+ stdinErrors.push(`Skipping invalid stdin input: ${line}`);
18
+ }
19
+ }
20
+ }
21
+ const args = process.argv.slice(2);
22
+ if (hashes.length === 0 && args.length === 0 || args.some((v) => v === "--help" || v === "-h")) {
23
+ console.log(`Usage: nano-pow [OPTION]... BLOCKHASH...
24
+ Generate work for BLOCKHASH, or multiple work values for BLOCKHASH(es)
25
+ BLOCKHASH is a 64-character hexadecimal string. Multiple blockhashes must be separated by whitespace or line breaks.
26
+ Prints a 16-character hexadecimal work value to standard output. If using --validate, prints 'true' or 'false' to standard output instead.
27
+
28
+ -h, --help show this dialog
29
+ -d, --debug enable additional logging output
30
+ -j, --json format output as JSON
31
+ -e, --effort=<value> increase demand on GPU processing
32
+ -t, --threshold=<value> override the minimum threshold value
33
+ -v, --validate=<value> check an existing work value instead of searching for one
34
+
35
+ If validating a nonce, it must be a 16-character hexadecimal value.
36
+ Effort must be a decimal number between 1-32.
37
+ Threshold must be a hexadecimal string between 0-FFFFFFFF.
38
+
39
+ Report bugs: <bug-nano-pow@zoso.dev>
40
+ Full documentation: <https://www.npmjs.com/package/nano-pow>
41
+ `);
42
+ process.exit();
43
+ }
44
+ const inArgs = [];
45
+ while (/^[0-9A-Fa-f]{64}$/.test(args[args.length - 1] ?? "")) {
46
+ inArgs.unshift(args.pop());
47
+ }
48
+ hashes.push(...inArgs);
49
+ let fn = "search";
50
+ let work = "";
51
+ let isJson = false;
52
+ const options = {};
53
+ for (let i = 0; i < args.length; i++) {
54
+ switch (args[i]) {
55
+ case "--validate":
56
+ case "-v": {
57
+ if (args[i + 1] == null) throw new Error("Missing argument for work validation");
58
+ if (!/^[0-9A-Fa-f]{16}$/.test(args[i + 1])) throw new Error("Invalid work to validate");
59
+ fn = "validate";
60
+ work = `'${args[i + 1]}', `;
61
+ break;
62
+ }
63
+ case "--threshold":
64
+ case "-t": {
65
+ if (args[i + 1] == null) throw new Error("Missing argument for threshold");
66
+ if (!/^[0-9A-Fa-f]{0,8}$/.test(args[i + 1])) throw new Error("Invalid threshold");
67
+ options["threshold"] = parseInt(args[i + 1], 16);
68
+ break;
69
+ }
70
+ case "--effort":
71
+ case "-e": {
72
+ if (args[i + 1] == null) throw new Error("Missing argument for effort");
73
+ if (!/^[0-9]{0,2}$/.test(args[i + 1])) throw new Error("Invalid effort");
74
+ options["effort"] = parseInt(args[i + 1], 10);
75
+ break;
76
+ }
77
+ case "--debug":
78
+ case "-d": {
79
+ options["debug"] = true;
80
+ break;
81
+ }
82
+ case "--json":
83
+ case "-j": {
84
+ isJson = true;
85
+ break;
86
+ }
87
+ }
88
+ }
89
+ if (options["debug"]) {
90
+ console.log(`NanoPowCli.${fn}()`);
91
+ console.log(`${fn} options`, JSON.stringify(options));
92
+ for (const stdinErr of stdinErrors) {
93
+ console.warn(stdinErr);
94
+ }
95
+ }
96
+ if (hashes.length === 0) {
97
+ console.error("Invalid block hash input");
98
+ process.exit(1);
99
+ }
100
+ (async () => {
101
+ const NanoPow = await fs.readFile(new URL("../main.min.js", import.meta.url), "utf-8");
102
+ const browser = await puppeteer.launch({
103
+ headless: true,
104
+ args: [
105
+ "--headless=new",
106
+ "--use-angle=vulkan",
107
+ "--enable-features=Vulkan",
108
+ "--disable-vulkan-surface",
109
+ "--enable-unsafe-webgpu"
110
+ ]
111
+ });
112
+ const page = await browser.newPage();
113
+ await page.setBypassCSP(true);
114
+ await page.goto("chrome://terms");
115
+ let start = performance.now();
116
+ page.on("console", async (msg) => {
117
+ const output = msg.text().split(" ");
118
+ if (output[0] === "cli") {
119
+ if (output[1] === "exit") {
120
+ if (isJson) {
121
+ const results = await page.evaluate(() => {
122
+ return window.results;
123
+ });
124
+ for (let i = 0; i < results.length; i++) {
125
+ results[i] = {
126
+ blockhash: hashes[i],
127
+ work: results[i]
128
+ };
129
+ }
130
+ console.log(JSON.stringify(results, null, 4));
131
+ }
132
+ const end = performance.now();
133
+ if (options["debug"]) console.log(end - start, "ms total |", (end - start) / hashes.length, "ms avg");
134
+ await browser.close();
135
+ } else if (!isJson) {
136
+ console.log(output[1]);
137
+ }
138
+ } else if (options["debug"]) {
139
+ console.log(msg.text());
140
+ }
141
+ });
142
+ await page.waitForFunction(async () => {
143
+ return await navigator.gpu.requestAdapter();
144
+ });
145
+ start = performance.now();
146
+ await page.addScriptTag({
147
+ type: "module",
148
+ content: `
149
+ window.trustedTypes?.createPolicy?.('default', {
150
+ createHTML: string => string,
151
+ createScriptURL: string => string,
152
+ createScript: string => string,
153
+ })
154
+ ${NanoPow}
155
+ window.results = []
156
+ const hashes = ["${hashes.join('","')}"]
157
+ for (const hash of hashes) {
158
+ try {
159
+ const work = await NanoPow.${fn}(${work}hash, ${JSON.stringify(options)})
160
+ window.results.push(work)
161
+ console.log(\`cli \${work}\`)
162
+ } catch (err) {
163
+ console.error(\`cli \${err}\`)
164
+ }
165
+ }
166
+ console.log('cli exit')
167
+ `
168
+ });
169
+ })();