zeldhash-miner 0.3.0 → 0.3.1
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/README.md +25 -16
- package/assets/worker.js +354 -0
- package/assets/zeldhash_miner_wasm.js +1404 -0
- package/assets/zeldhash_miner_wasm_bg.wasm +0 -0
- package/dist/index.js +420 -273
- package/dist/index.js.map +1 -1
- package/dist/worker.js +254 -106
- package/dist/worker.js.map +1 -1
- package/package.json +4 -2
- package/wasm/package.json +1 -1
- package/wasm/zeldhash_miner_wasm.d.ts +2 -2
- package/wasm/zeldhash_miner_wasm.js +4 -4
- package/wasm/zeldhash_miner_wasm_bg.wasm +0 -0
- package/wasm/zeldhash_miner_wasm_bg.wasm.d.ts +2 -2
- package/dist/nonce.js +0 -158
- package/dist/nonce.js.map +0 -1
- package/dist/worker.d.ts +0 -1
package/README.md
CHANGED
|
@@ -95,7 +95,7 @@ Creates a new miner instance.
|
|
|
95
95
|
interface MineParams {
|
|
96
96
|
inputs: TxInput[]; // UTXOs to spend
|
|
97
97
|
outputs: TxOutput[]; // Destinations (one must be change: true)
|
|
98
|
-
targetZeros: number; // Leading zero hex digits (
|
|
98
|
+
targetZeros: number; // Leading zero hex digits (0–32)
|
|
99
99
|
startNonce?: bigint; // Starting point (default 0n)
|
|
100
100
|
batchSize?: number; // Override instance batch size
|
|
101
101
|
distribution?: bigint[]; // Optional ZELD distribution values
|
|
@@ -207,34 +207,43 @@ Notes:
|
|
|
207
207
|
|
|
208
208
|
## Runtime Notes
|
|
209
209
|
|
|
210
|
-
###
|
|
210
|
+
### Asset Setup
|
|
211
211
|
|
|
212
|
-
The SDK
|
|
212
|
+
The SDK requires WASM and worker files to be served from your application's public folder. All assets are bundled in a single `assets/` folder for easy setup:
|
|
213
213
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
214
|
+
```bash
|
|
215
|
+
# Copy all required assets to your public folder
|
|
216
|
+
cp -r node_modules/zeldhash-miner/assets public/zeldhash-miner
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Or add a postinstall script to your `package.json`:
|
|
220
|
+
```json
|
|
221
|
+
{
|
|
222
|
+
"scripts": {
|
|
223
|
+
"postinstall": "cp -r node_modules/zeldhash-miner/assets public/zeldhash-miner"
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
218
227
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
228
|
+
This copies 3 files to `public/zeldhash-miner/`:
|
|
229
|
+
- `zeldhash_miner_wasm.js` - WASM JavaScript bindings
|
|
230
|
+
- `zeldhash_miner_wasm_bg.wasm` - WASM binary
|
|
231
|
+
- `worker.js` - Web Worker for mining
|
|
223
232
|
|
|
224
|
-
The SDK
|
|
233
|
+
The SDK automatically loads assets from `/zeldhash-miner/` on your application's origin.
|
|
225
234
|
|
|
226
|
-
### Custom
|
|
235
|
+
### Custom Asset Path
|
|
227
236
|
|
|
228
|
-
If you need to serve
|
|
237
|
+
If you need to serve assets from a different location, override the base path before importing:
|
|
229
238
|
|
|
230
239
|
```ts
|
|
231
240
|
// Set before importing ZeldMiner
|
|
232
|
-
globalThis.__ZELDMINER_WASM_BASE__ = "/custom/path/to/
|
|
241
|
+
globalThis.__ZELDMINER_WASM_BASE__ = "/custom/path/to/assets/";
|
|
233
242
|
```
|
|
234
243
|
|
|
235
244
|
Or use environment variables with Vite:
|
|
236
245
|
```bash
|
|
237
|
-
VITE_ZELDMINER_WASM_BASE=/custom/
|
|
246
|
+
VITE_ZELDMINER_WASM_BASE=/custom/assets/
|
|
238
247
|
```
|
|
239
248
|
|
|
240
249
|
### WebGPU
|
package/assets/worker.js
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
var u = /* @__PURE__ */ ((t) => (t.INVALID_ADDRESS = "INVALID_ADDRESS", t.UNSUPPORTED_ADDRESS_TYPE = "UNSUPPORTED_ADDRESS_TYPE", t.INSUFFICIENT_FUNDS = "INSUFFICIENT_FUNDS", t.MULTIPLE_CHANGE_OUTPUTS = "MULTIPLE_CHANGE_OUTPUTS", t.INVALID_INPUT = "INVALID_INPUT", t.WEBGPU_NOT_AVAILABLE = "WEBGPU_NOT_AVAILABLE", t.WORKER_ERROR = "WORKER_ERROR", t.MINING_ABORTED = "MINING_ABORTED", t.DUST_OUTPUT = "DUST_OUTPUT", t))(u || {});
|
|
2
|
+
const N = (1n << 64n) - 1n, C = (t) => {
|
|
3
|
+
if (t < 0n)
|
|
4
|
+
throw new Error("nonce must be non-negative");
|
|
5
|
+
if (t === 0n) return 1;
|
|
6
|
+
let e = 0, n = t;
|
|
7
|
+
for (; n > 0n; )
|
|
8
|
+
e += 1, n >>= 8n;
|
|
9
|
+
return e;
|
|
10
|
+
}, X = (t) => {
|
|
11
|
+
if (t < 0n)
|
|
12
|
+
throw new Error("nonce must be non-negative");
|
|
13
|
+
if (t <= 23n) return 1;
|
|
14
|
+
if (t <= 0xffn) return 2;
|
|
15
|
+
if (t <= 0xffffn) return 3;
|
|
16
|
+
if (t <= 0xffffffffn) return 5;
|
|
17
|
+
if (t <= N) return 9;
|
|
18
|
+
throw new Error("nonce range exceeds u64");
|
|
19
|
+
}, j = (t) => {
|
|
20
|
+
if (!Number.isInteger(t) || t <= 0 || t > 8)
|
|
21
|
+
throw new Error("nonceLength must be between 1 and 8");
|
|
22
|
+
return (1n << BigInt(t * 8)) - 1n;
|
|
23
|
+
}, H = (t) => {
|
|
24
|
+
switch (t) {
|
|
25
|
+
case 1:
|
|
26
|
+
return 23n;
|
|
27
|
+
case 2:
|
|
28
|
+
return 0xffn;
|
|
29
|
+
case 3:
|
|
30
|
+
return 0xffffn;
|
|
31
|
+
case 5:
|
|
32
|
+
return 0xffffffffn;
|
|
33
|
+
case 9:
|
|
34
|
+
return N;
|
|
35
|
+
default:
|
|
36
|
+
throw new Error("cbor nonceLength must be one of 1, 2, 3, 5, 9");
|
|
37
|
+
}
|
|
38
|
+
}, Y = (t, e) => {
|
|
39
|
+
if (t < 0n)
|
|
40
|
+
throw new Error("startNonce must be non-negative");
|
|
41
|
+
if (!Number.isInteger(e) || e <= 0)
|
|
42
|
+
throw new Error("batchSize must be a positive integer");
|
|
43
|
+
const n = t + BigInt(e - 1);
|
|
44
|
+
if (n > N)
|
|
45
|
+
throw new Error("nonce range exceeds u64");
|
|
46
|
+
const r = [];
|
|
47
|
+
let i = t;
|
|
48
|
+
for (; i <= n; ) {
|
|
49
|
+
const s = C(i), o = j(s), a = n < o ? n : o, l = a - i + 1n;
|
|
50
|
+
if (l > BigInt(Number.MAX_SAFE_INTEGER))
|
|
51
|
+
throw new Error("segment size exceeds safe integer range");
|
|
52
|
+
if (r.push({
|
|
53
|
+
start: i,
|
|
54
|
+
size: Number(l),
|
|
55
|
+
nonceLength: s
|
|
56
|
+
}), a === n)
|
|
57
|
+
break;
|
|
58
|
+
i = a + 1n;
|
|
59
|
+
}
|
|
60
|
+
return r;
|
|
61
|
+
}, J = (t, e) => {
|
|
62
|
+
if (t < 0n)
|
|
63
|
+
throw new Error("startNonce must be non-negative");
|
|
64
|
+
if (!Number.isInteger(e) || e <= 0)
|
|
65
|
+
throw new Error("batchSize must be a positive integer");
|
|
66
|
+
const n = t + BigInt(e - 1);
|
|
67
|
+
if (n > N)
|
|
68
|
+
throw new Error("nonce range exceeds u64");
|
|
69
|
+
const r = [];
|
|
70
|
+
let i = t;
|
|
71
|
+
for (; i <= n; ) {
|
|
72
|
+
const s = X(i), o = H(s), a = n < o ? n : o, l = a - i + 1n;
|
|
73
|
+
if (l > BigInt(Number.MAX_SAFE_INTEGER))
|
|
74
|
+
throw new Error("segment size exceeds safe integer range");
|
|
75
|
+
if (r.push({
|
|
76
|
+
start: i,
|
|
77
|
+
size: Number(l),
|
|
78
|
+
nonceLength: s
|
|
79
|
+
}), a === n)
|
|
80
|
+
break;
|
|
81
|
+
i = a + 1n;
|
|
82
|
+
}
|
|
83
|
+
return r;
|
|
84
|
+
}, Q = {};
|
|
85
|
+
if (typeof globalThis.__ZELDMINER_WASM_BASE__ > "u")
|
|
86
|
+
try {
|
|
87
|
+
const t = typeof window < "u" && window.location?.origin ? window.location.origin : typeof self < "u" && self.location?.origin ? self.location.origin : "http://localhost";
|
|
88
|
+
globalThis.__ZELDMINER_WASM_BASE__ = new URL("/zeldhash-miner/", t).href;
|
|
89
|
+
} catch {
|
|
90
|
+
globalThis.__ZELDMINER_WASM_BASE__ = "/zeldhash-miner/";
|
|
91
|
+
}
|
|
92
|
+
let T = null, w = null, W = !1;
|
|
93
|
+
const Z = () => {
|
|
94
|
+
if (W) return;
|
|
95
|
+
W = !0;
|
|
96
|
+
const t = globalThis.GPUAdapter?.prototype, e = t?.requestDevice;
|
|
97
|
+
!t || typeof e != "function" || (t.requestDevice = function(r) {
|
|
98
|
+
if (r?.requiredLimits && typeof this.limits == "object") {
|
|
99
|
+
const i = r.requiredLimits, s = this.limits;
|
|
100
|
+
for (const o of Object.keys(i))
|
|
101
|
+
(!(o in s) || s[o] === void 0) && delete i[o];
|
|
102
|
+
}
|
|
103
|
+
return e.call(this, r);
|
|
104
|
+
});
|
|
105
|
+
}, B = (t) => t.endsWith("/") ? t : `${t}/`, A = (t) => {
|
|
106
|
+
const e = t.trim();
|
|
107
|
+
return e && (typeof window < "u" && typeof window.location?.origin == "string" ? B(new URL(e, window.location.origin).href) : B(new URL(e, import.meta.url).href));
|
|
108
|
+
}, tt = () => {
|
|
109
|
+
const t = globalThis.__ZELDMINER_WASM_BASE__;
|
|
110
|
+
if (typeof t == "string" && t.trim())
|
|
111
|
+
return A(t);
|
|
112
|
+
const e = Q?.VITE_ZELDMINER_WASM_BASE;
|
|
113
|
+
if (typeof e == "string" && e.trim())
|
|
114
|
+
return A(e);
|
|
115
|
+
const n = "/";
|
|
116
|
+
return n.trim() ? A(`${B(n.trim())}zeldhash-miner/`) : A("/zeldhash-miner/");
|
|
117
|
+
}, x = tt(), z = `${x}zeldhash_miner_wasm.js`, et = `${x}zeldhash_miner_wasm_bg.wasm`, nt = async (t) => (0, eval)("s => import(s)")(t), O = (t) => t instanceof Error ? t.message : String(t), rt = async () => {
|
|
118
|
+
Z();
|
|
119
|
+
let t;
|
|
120
|
+
try {
|
|
121
|
+
t = await nt(
|
|
122
|
+
/* @vite-ignore */
|
|
123
|
+
z
|
|
124
|
+
);
|
|
125
|
+
} catch (r) {
|
|
126
|
+
throw new Error(
|
|
127
|
+
`Failed to import WASM bundle (${z}). Did you run ./scripts/build-wasm.sh? (${O(r)})`
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
const e = t.default;
|
|
131
|
+
if (typeof e != "function")
|
|
132
|
+
throw new Error("WASM init function is missing from the bundle.");
|
|
133
|
+
try {
|
|
134
|
+
const r = new URL(et, import.meta.url);
|
|
135
|
+
await e({ module_or_path: r });
|
|
136
|
+
} catch (r) {
|
|
137
|
+
throw new Error(
|
|
138
|
+
`Failed to initialize WASM bundle: ${O(r)}`
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
const n = t;
|
|
142
|
+
try {
|
|
143
|
+
n.init_panic_hook?.();
|
|
144
|
+
} catch {
|
|
145
|
+
}
|
|
146
|
+
return n;
|
|
147
|
+
}, it = async () => T || (w || (w = rt().then((t) => (T = t, t)).catch((t) => {
|
|
148
|
+
throw w = null, t;
|
|
149
|
+
})), w);
|
|
150
|
+
if (typeof globalThis.__ZELDMINER_WASM_BASE__ > "u")
|
|
151
|
+
try {
|
|
152
|
+
const t = typeof self < "u" && self.location?.origin ? self.location.origin : "http://localhost";
|
|
153
|
+
globalThis.__ZELDMINER_WASM_BASE__ = new URL("/zeldhash-miner/", t).href;
|
|
154
|
+
} catch {
|
|
155
|
+
globalThis.__ZELDMINER_WASM_BASE__ = "/zeldhash-miner/";
|
|
156
|
+
}
|
|
157
|
+
const U = self, ot = U.name ?? void 0, I = (t) => t instanceof Error ? t.message : String(t);
|
|
158
|
+
let R = "cpu", b = null;
|
|
159
|
+
const d = (t) => {
|
|
160
|
+
U.postMessage({ ...t, workerId: ot });
|
|
161
|
+
}, h = (t, e = u.WORKER_ERROR, n) => {
|
|
162
|
+
d({ type: "error", message: t, code: e, details: n });
|
|
163
|
+
}, st = (t) => typeof t == "object" && t !== null && "ok" in t, at = (t) => typeof t == "object" && t !== null && "nonce" in t && "txid" in t, ct = (t) => {
|
|
164
|
+
const e = BigInt(Number.MAX_SAFE_INTEGER);
|
|
165
|
+
return t > e ? Number.MAX_SAFE_INTEGER : t < -e ? -Number.MAX_SAFE_INTEGER : Number(t);
|
|
166
|
+
}, ut = (t) => ({
|
|
167
|
+
nonceLength: t.nonceLength,
|
|
168
|
+
prefix: new Uint8Array(t.prefix),
|
|
169
|
+
suffix: new Uint8Array(t.suffix),
|
|
170
|
+
useCborNonce: t.useCborNonce
|
|
171
|
+
}), F = (t, e) => {
|
|
172
|
+
t.set(e.nonceLength, ut(e));
|
|
173
|
+
}, lt = async (t, e, n, r, i) => {
|
|
174
|
+
const s = t.get(r.nonceLength);
|
|
175
|
+
if (s)
|
|
176
|
+
return s;
|
|
177
|
+
const o = e.build_mining_template(
|
|
178
|
+
n.inputs,
|
|
179
|
+
n.outputs,
|
|
180
|
+
i,
|
|
181
|
+
BigInt(n.satsPerVbyte),
|
|
182
|
+
r.start,
|
|
183
|
+
r.size,
|
|
184
|
+
n.distribution ?? null
|
|
185
|
+
), a = {
|
|
186
|
+
...o,
|
|
187
|
+
nonceLength: r.nonceLength,
|
|
188
|
+
useCborNonce: o.useCborNonce ?? n.useCborNonce
|
|
189
|
+
};
|
|
190
|
+
return F(t, a), a;
|
|
191
|
+
}, ft = async (t, e, n, r, i, s, o, a) => {
|
|
192
|
+
if (e === "gpu") {
|
|
193
|
+
if (!t.mine_batch_gpu)
|
|
194
|
+
throw new Error("GPU mining requested but mine_batch_gpu is unavailable");
|
|
195
|
+
return t.mine_batch_gpu(
|
|
196
|
+
n,
|
|
197
|
+
r,
|
|
198
|
+
i,
|
|
199
|
+
s,
|
|
200
|
+
o,
|
|
201
|
+
a
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
return t.mine_batch_wasm(
|
|
205
|
+
n,
|
|
206
|
+
r,
|
|
207
|
+
i,
|
|
208
|
+
s,
|
|
209
|
+
o,
|
|
210
|
+
a
|
|
211
|
+
);
|
|
212
|
+
}, _t = async (t, e) => {
|
|
213
|
+
let n;
|
|
214
|
+
try {
|
|
215
|
+
if (n = await it(), R === "gpu") {
|
|
216
|
+
if (!n.mine_batch_gpu) {
|
|
217
|
+
h(
|
|
218
|
+
"GPU mining requested but mine_batch_gpu is unavailable",
|
|
219
|
+
u.WEBGPU_NOT_AVAILABLE
|
|
220
|
+
);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
n.init_gpu && await n.init_gpu();
|
|
224
|
+
}
|
|
225
|
+
} catch (g) {
|
|
226
|
+
const m = I(g), E = R === "gpu" ? u.WEBGPU_NOT_AVAILABLE : u.WORKER_ERROR;
|
|
227
|
+
h(`Failed to initialize WASM: ${m}`, E);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const r = /* @__PURE__ */ new Map(), i = t.template.useCborNonce ?? !!(t.distribution && t.distribution.length > 0);
|
|
231
|
+
F(r, { ...t.template, useCborNonce: i });
|
|
232
|
+
const s = t.nonceStep ?? BigInt(t.batchSize), o = t.network === "signet" ? "testnet" : t.network;
|
|
233
|
+
let a = t.startNonce, l = 0n;
|
|
234
|
+
const G = performance.now();
|
|
235
|
+
for (; !e.signal.aborted; ) {
|
|
236
|
+
const g = a;
|
|
237
|
+
let m = t.batchSize, E = 0n;
|
|
238
|
+
for (; m > 0 && !e.signal.aborted; ) {
|
|
239
|
+
const D = g + E;
|
|
240
|
+
let c;
|
|
241
|
+
try {
|
|
242
|
+
c = (i ? J(D, m) : Y(D, m))[0];
|
|
243
|
+
} catch (_) {
|
|
244
|
+
h(
|
|
245
|
+
`Invalid nonce range: ${I(_)}`,
|
|
246
|
+
u.INVALID_INPUT
|
|
247
|
+
), e.abort();
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
let S;
|
|
251
|
+
try {
|
|
252
|
+
S = await lt(
|
|
253
|
+
r,
|
|
254
|
+
n,
|
|
255
|
+
{
|
|
256
|
+
inputs: t.inputs,
|
|
257
|
+
outputs: t.outputs,
|
|
258
|
+
satsPerVbyte: t.satsPerVbyte,
|
|
259
|
+
distribution: t.distribution,
|
|
260
|
+
useCborNonce: i
|
|
261
|
+
},
|
|
262
|
+
c,
|
|
263
|
+
o
|
|
264
|
+
);
|
|
265
|
+
} catch (_) {
|
|
266
|
+
h(
|
|
267
|
+
`Failed to build mining template: ${I(_)}`,
|
|
268
|
+
u.WORKER_ERROR
|
|
269
|
+
), e.abort();
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
let f;
|
|
273
|
+
const k = performance.now();
|
|
274
|
+
try {
|
|
275
|
+
f = await ft(
|
|
276
|
+
n,
|
|
277
|
+
R,
|
|
278
|
+
S.prefix,
|
|
279
|
+
S.suffix,
|
|
280
|
+
c.start,
|
|
281
|
+
c.size,
|
|
282
|
+
t.targetZeros,
|
|
283
|
+
i
|
|
284
|
+
);
|
|
285
|
+
} catch (_) {
|
|
286
|
+
const p = I(_);
|
|
287
|
+
h(
|
|
288
|
+
`Batch mining failed: ${p}`,
|
|
289
|
+
u.WORKER_ERROR
|
|
290
|
+
), e.abort();
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
const M = performance.now() - k;
|
|
294
|
+
if (st(f)) {
|
|
295
|
+
if (!f.ok) {
|
|
296
|
+
h(
|
|
297
|
+
f.error ?? "Validation failed",
|
|
298
|
+
u.INVALID_INPUT
|
|
299
|
+
), e.abort();
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
} else if (at(f)) {
|
|
303
|
+
const _ = l + E, p = BigInt(f.nonce) - c.start + 1n, L = _ + p, y = performance.now() - G, P = y > 0 ? ct(L) / (y / 1e3) : 0, q = c.start + p - 1n, K = {
|
|
304
|
+
psbt: "",
|
|
305
|
+
txid: f.txid,
|
|
306
|
+
nonce: BigInt(f.nonce),
|
|
307
|
+
attempts: L,
|
|
308
|
+
duration: y,
|
|
309
|
+
hashRate: P
|
|
310
|
+
};
|
|
311
|
+
d({
|
|
312
|
+
type: "found",
|
|
313
|
+
result: K,
|
|
314
|
+
hashesProcessed: L,
|
|
315
|
+
hashRate: P,
|
|
316
|
+
lastNonce: q
|
|
317
|
+
}), e.abort();
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
l += BigInt(c.size), E += BigInt(c.size), m -= c.size;
|
|
321
|
+
const v = M > 0 ? c.size / (M / 1e3) : c.size, $ = c.start + BigInt(c.size) - 1n;
|
|
322
|
+
d({ type: "progress", hashesProcessed: l, hashRate: v, lastNonce: $ });
|
|
323
|
+
}
|
|
324
|
+
if (e.signal.aborted)
|
|
325
|
+
break;
|
|
326
|
+
const V = g + BigInt(t.batchSize) - 1n;
|
|
327
|
+
d({ type: "batch_complete", lastNonce: V }), a = g + s;
|
|
328
|
+
}
|
|
329
|
+
}, ht = (t) => {
|
|
330
|
+
const e = new AbortController();
|
|
331
|
+
b?.abort(), b = e, _t(t, e).finally(() => {
|
|
332
|
+
b === e && (b = null);
|
|
333
|
+
});
|
|
334
|
+
};
|
|
335
|
+
U.addEventListener("message", (t) => {
|
|
336
|
+
const e = t.data;
|
|
337
|
+
switch (e.type) {
|
|
338
|
+
case "init":
|
|
339
|
+
R = e.mode, d({ type: "ready" });
|
|
340
|
+
break;
|
|
341
|
+
case "mine":
|
|
342
|
+
ht(e);
|
|
343
|
+
break;
|
|
344
|
+
case "stop":
|
|
345
|
+
b?.abort();
|
|
346
|
+
break;
|
|
347
|
+
default:
|
|
348
|
+
h(
|
|
349
|
+
`Unknown message type: ${e.type}`,
|
|
350
|
+
u.WORKER_ERROR
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
//# sourceMappingURL=worker.js.map
|