@totemsdk/txpow 1.0.2 → 1.1.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.
- package/dist/admission/challenge.js +14 -21
- package/dist/admission/commitment.js +9 -13
- package/dist/admission/index.js +6 -34
- package/dist/admission/mine.js +14 -17
- package/dist/admission/template.js +32 -47
- package/dist/admission/types.js +2 -5
- package/dist/admission/verify.js +12 -15
- package/dist/calibrate.js +4 -8
- package/dist/cjs/admission/challenge.d.ts +66 -0
- package/dist/cjs/admission/challenge.js +155 -0
- package/dist/cjs/admission/commitment.d.ts +34 -0
- package/dist/cjs/admission/commitment.js +73 -0
- package/dist/cjs/admission/index.d.ts +14 -0
- package/dist/cjs/admission/index.js +42 -0
- package/dist/cjs/admission/mine.d.ts +60 -0
- package/dist/cjs/admission/mine.js +146 -0
- package/dist/cjs/admission/template.d.ts +138 -0
- package/dist/cjs/admission/template.js +247 -0
- package/dist/cjs/admission/types.d.ts +224 -0
- package/dist/cjs/admission/types.js +24 -0
- package/dist/cjs/admission/verify.d.ts +50 -0
- package/dist/cjs/admission/verify.js +156 -0
- package/dist/cjs/calibrate.d.ts +35 -0
- package/dist/cjs/calibrate.js +68 -0
- package/dist/cjs/constants.d.ts +27 -0
- package/dist/cjs/constants.js +47 -0
- package/dist/cjs/difficulty.d.ts +44 -0
- package/dist/cjs/difficulty.js +111 -0
- package/dist/cjs/index.d.ts +28 -0
- package/dist/cjs/index.js +88 -0
- package/dist/cjs/magic.d.ts +19 -0
- package/dist/cjs/magic.js +35 -0
- package/dist/cjs/mine-wasm.d.ts +69 -0
- package/dist/cjs/mine-wasm.js +214 -0
- package/dist/cjs/mine.d.ts +131 -0
- package/dist/cjs/mine.js +407 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/serialization.d.ts +106 -0
- package/dist/cjs/serialization.js +160 -0
- package/dist/cjs/verify.d.ts +76 -0
- package/dist/cjs/verify.js +232 -0
- package/dist/cjs/wasm/miner.wasm +0 -0
- package/dist/cjs/workers/browser.worker.d.ts +26 -0
- package/dist/cjs/workers/browser.worker.js +63 -0
- package/dist/cjs/workers/node.worker.d.ts +33 -0
- package/dist/cjs/workers/node.worker.js +47 -0
- package/dist/constants.js +5 -8
- package/dist/difficulty.d.ts +24 -0
- package/dist/difficulty.js +54 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.js +9 -62
- package/dist/magic.js +12 -15
- package/dist/mine-wasm.js +8 -15
- package/dist/mine.js +23 -31
- package/dist/serialization.js +28 -34
- package/dist/verify.js +15 -20
- package/dist/workers/browser.worker.js +4 -6
- package/dist/workers/node.worker.js +2 -3
- package/package.json +31 -13
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* magic.ts — Serialize the Minima Magic struct.
|
|
4
|
+
*
|
|
5
|
+
* Ported from the extension's MinimaTransactionBuilder.ts::serializeMagic().
|
|
6
|
+
* Matches Magic.writeDataStream() in Java exactly.
|
|
7
|
+
*
|
|
8
|
+
* Magic contains two copies of 4 fields (current + desired parameters):
|
|
9
|
+
* maxTxPoWSize (MiniNumber)
|
|
10
|
+
* maxKISSVMOps (MiniNumber)
|
|
11
|
+
* maxTxnPerBlock(MiniNumber)
|
|
12
|
+
* minTxPoWWork (MiniData — 32 bytes)
|
|
13
|
+
*
|
|
14
|
+
* Default values from Magic.java:
|
|
15
|
+
* maxTxPoWSize = 65536
|
|
16
|
+
* maxKISSVMOps = 1024
|
|
17
|
+
* maxTxnPerBlock = 256
|
|
18
|
+
* minTxPoWWork = MAX_HASH (all 0xFF, 32 bytes) — placeholder in fresh TxPoW
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.serializeMagic = serializeMagic;
|
|
22
|
+
const core_1 = require("@totemsdk/core");
|
|
23
|
+
const constants_js_1 = require("./constants.js");
|
|
24
|
+
function serializeMagic() {
|
|
25
|
+
const parts = [];
|
|
26
|
+
parts.push((0, core_1.writeMiniNumber)(65536n, 0));
|
|
27
|
+
parts.push((0, core_1.writeMiniNumber)(1024n, 0));
|
|
28
|
+
parts.push((0, core_1.writeMiniNumber)(256n, 0));
|
|
29
|
+
parts.push((0, core_1.writeMiniData)(constants_js_1.MAX_HASH));
|
|
30
|
+
parts.push((0, core_1.writeMiniNumber)(65536n, 0));
|
|
31
|
+
parts.push((0, core_1.writeMiniNumber)(1024n, 0));
|
|
32
|
+
parts.push((0, core_1.writeMiniNumber)(256n, 0));
|
|
33
|
+
parts.push((0, core_1.writeMiniData)(constants_js_1.MAX_HASH));
|
|
34
|
+
return (0, core_1.concat)(...parts);
|
|
35
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mine-wasm.ts — WASM mining loop loader and wrapper.
|
|
3
|
+
*
|
|
4
|
+
* Loads the pre-compiled `miner.wasm` binary and provides `mineChunkWasm()`.
|
|
5
|
+
* Falls back gracefully when the binary is unavailable.
|
|
6
|
+
*
|
|
7
|
+
* ── Memory layout (must match miner.wat) ──
|
|
8
|
+
* [0 .. 31 ] — hash output buffer (host sha3_256 writes here)
|
|
9
|
+
* [32 .. 32+headerLen-1 ] — header buffer (set by caller before each call)
|
|
10
|
+
* [32+headerLen .. 32+headerLen+31] — target buffer (set once per mine)
|
|
11
|
+
*
|
|
12
|
+
* ── Runtime detection ──
|
|
13
|
+
* Node.js → reads dist/wasm/miner.wasm via fs.readFileSync
|
|
14
|
+
* Browser → fetches the URL supplied by setWasmUrl() (Task #114 supplies it)
|
|
15
|
+
*
|
|
16
|
+
* ── WASM binary compilation ──
|
|
17
|
+
* node scripts/compile-wasm.js (uses wabt npm package, no Emscripten needed)
|
|
18
|
+
* npm run build (postbuild copies miner.wasm → dist/wasm/)
|
|
19
|
+
*
|
|
20
|
+
* ── WASM module interface (miner.wat) ──
|
|
21
|
+
* import env.sha3_256(headerPtr, headerLen, outPtr) ← host provides via @totemsdk/core
|
|
22
|
+
* export mine(headerPtr, headerLen, nonceOffset, nonceLen,
|
|
23
|
+
* targetPtr, startNonce, chunkSize) → i32
|
|
24
|
+
* export memory
|
|
25
|
+
*
|
|
26
|
+
* mine() returns the found nonce, or -1 (0xFFFFFFFF) if no nonce found in chunk.
|
|
27
|
+
*/
|
|
28
|
+
/** First byte of the header region (after the 32-byte hash output buffer). */
|
|
29
|
+
export declare const WASM_HEADER_OFFSET = 32;
|
|
30
|
+
/**
|
|
31
|
+
* Configure the URL from which the browser loads `miner.wasm`.
|
|
32
|
+
*
|
|
33
|
+
* Call this once at app startup in browser contexts. The extension build
|
|
34
|
+
* (Task #114) resolves this URL from the bundler's output.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* import { setWasmUrl } from '@totemsdk/txpow';
|
|
38
|
+
* setWasmUrl(browser.runtime.getURL('miner.wasm'));
|
|
39
|
+
*/
|
|
40
|
+
export declare function setWasmUrl(url: string): void;
|
|
41
|
+
/**
|
|
42
|
+
* Return the current browser WASM URL, or null if not yet configured.
|
|
43
|
+
* Used by the main thread to pass the URL into spawned browser Web Workers.
|
|
44
|
+
*/
|
|
45
|
+
export declare function getBrowserWasmUrl(): string | null;
|
|
46
|
+
/**
|
|
47
|
+
* Returns true when the WASM binary is loaded and `mine` is ready to use.
|
|
48
|
+
* Cached after the first call; subsequent calls are synchronous (via memoised flag).
|
|
49
|
+
*/
|
|
50
|
+
export declare function isWasmAvailable(): Promise<boolean>;
|
|
51
|
+
/**
|
|
52
|
+
* Mine a chunk using the WASM binary.
|
|
53
|
+
*
|
|
54
|
+
* Copies `headerBuf` and `target` into WASM linear memory at the correct
|
|
55
|
+
* offsets, calls `mine()`, and returns the found nonce — or `null` if:
|
|
56
|
+
* - WASM binary is unavailable
|
|
57
|
+
* - No valid nonce was found within the specified chunk
|
|
58
|
+
*
|
|
59
|
+
* Grows WASM memory if needed (single-page default = 64 KB is ample for
|
|
60
|
+
* any realistic TxHeader, but growth is handled for safety).
|
|
61
|
+
*
|
|
62
|
+
* @param headerBuf Full TxHeader bytes for the current nonce encoding range.
|
|
63
|
+
* @param nonceOffset Byte offset of the nonce VALUE in the header (always 2).
|
|
64
|
+
* @param nonceLen Byte length of the nonce value (1 for 0–127, 2 for 128–32767, …).
|
|
65
|
+
* @param target 32-byte difficulty target (big-endian).
|
|
66
|
+
* @param startNonce First nonce value to try.
|
|
67
|
+
* @param chunkCount Number of consecutive nonce values to try.
|
|
68
|
+
*/
|
|
69
|
+
export declare function mineChunkWasm(headerBuf: Uint8Array, nonceOffset: number, nonceLen: number, target: Uint8Array, startNonce: bigint, chunkCount: bigint): Promise<bigint | null>;
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* mine-wasm.ts — WASM mining loop loader and wrapper.
|
|
4
|
+
*
|
|
5
|
+
* Loads the pre-compiled `miner.wasm` binary and provides `mineChunkWasm()`.
|
|
6
|
+
* Falls back gracefully when the binary is unavailable.
|
|
7
|
+
*
|
|
8
|
+
* ── Memory layout (must match miner.wat) ──
|
|
9
|
+
* [0 .. 31 ] — hash output buffer (host sha3_256 writes here)
|
|
10
|
+
* [32 .. 32+headerLen-1 ] — header buffer (set by caller before each call)
|
|
11
|
+
* [32+headerLen .. 32+headerLen+31] — target buffer (set once per mine)
|
|
12
|
+
*
|
|
13
|
+
* ── Runtime detection ──
|
|
14
|
+
* Node.js → reads dist/wasm/miner.wasm via fs.readFileSync
|
|
15
|
+
* Browser → fetches the URL supplied by setWasmUrl() (Task #114 supplies it)
|
|
16
|
+
*
|
|
17
|
+
* ── WASM binary compilation ──
|
|
18
|
+
* node scripts/compile-wasm.js (uses wabt npm package, no Emscripten needed)
|
|
19
|
+
* npm run build (postbuild copies miner.wasm → dist/wasm/)
|
|
20
|
+
*
|
|
21
|
+
* ── WASM module interface (miner.wat) ──
|
|
22
|
+
* import env.sha3_256(headerPtr, headerLen, outPtr) ← host provides via @totemsdk/core
|
|
23
|
+
* export mine(headerPtr, headerLen, nonceOffset, nonceLen,
|
|
24
|
+
* targetPtr, startNonce, chunkSize) → i32
|
|
25
|
+
* export memory
|
|
26
|
+
*
|
|
27
|
+
* mine() returns the found nonce, or -1 (0xFFFFFFFF) if no nonce found in chunk.
|
|
28
|
+
*/
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.WASM_HEADER_OFFSET = void 0;
|
|
31
|
+
exports.setWasmUrl = setWasmUrl;
|
|
32
|
+
exports.getBrowserWasmUrl = getBrowserWasmUrl;
|
|
33
|
+
exports.isWasmAvailable = isWasmAvailable;
|
|
34
|
+
exports.mineChunkWasm = mineChunkWasm;
|
|
35
|
+
const core_1 = require("@totemsdk/core");
|
|
36
|
+
/** Byte offset in WASM linear memory where the hash output is written. */
|
|
37
|
+
const HASH_OUT_OFFSET = 0;
|
|
38
|
+
/** First byte of the header region (after the 32-byte hash output buffer). */
|
|
39
|
+
exports.WASM_HEADER_OFFSET = 32;
|
|
40
|
+
/**
|
|
41
|
+
* Sentinel returned by WASM mine() when no nonce is found in the chunk.
|
|
42
|
+
* The WAT uses `i32.const -1` (= 0xFFFFFFFF bit pattern).
|
|
43
|
+
* WebAssembly i32 return values are sign-extended to JavaScript Number,
|
|
44
|
+
* so 0xFFFFFFFF arrives as -1, NOT as 4294967295.
|
|
45
|
+
*/
|
|
46
|
+
const NOT_FOUND = -1;
|
|
47
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
48
|
+
// Browser WASM URL configuration
|
|
49
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
50
|
+
let _browserWasmUrl = null;
|
|
51
|
+
/**
|
|
52
|
+
* Configure the URL from which the browser loads `miner.wasm`.
|
|
53
|
+
*
|
|
54
|
+
* Call this once at app startup in browser contexts. The extension build
|
|
55
|
+
* (Task #114) resolves this URL from the bundler's output.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* import { setWasmUrl } from '@totemsdk/txpow';
|
|
59
|
+
* setWasmUrl(browser.runtime.getURL('miner.wasm'));
|
|
60
|
+
*/
|
|
61
|
+
function setWasmUrl(url) {
|
|
62
|
+
_browserWasmUrl = url;
|
|
63
|
+
_loadAttempted = false;
|
|
64
|
+
_instance = null;
|
|
65
|
+
_memory = null;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Return the current browser WASM URL, or null if not yet configured.
|
|
69
|
+
* Used by the main thread to pass the URL into spawned browser Web Workers.
|
|
70
|
+
*/
|
|
71
|
+
function getBrowserWasmUrl() {
|
|
72
|
+
return _browserWasmUrl;
|
|
73
|
+
}
|
|
74
|
+
let _instance = null;
|
|
75
|
+
let _memory = null;
|
|
76
|
+
let _loadAttempted = false;
|
|
77
|
+
/** Build the WebAssembly import object, wiring sha3_256 from @totemsdk/core. */
|
|
78
|
+
function buildImports() {
|
|
79
|
+
return {
|
|
80
|
+
env: {
|
|
81
|
+
/**
|
|
82
|
+
* sha3_256(headerPtr, headerLen, outPtr)
|
|
83
|
+
* Reads header bytes from WASM linear memory, computes SHA3-256,
|
|
84
|
+
* writes 32-byte digest back into WASM linear memory at outPtr.
|
|
85
|
+
*/
|
|
86
|
+
sha3_256(headerPtr, headerLen, outPtr) {
|
|
87
|
+
if (!_memory)
|
|
88
|
+
return;
|
|
89
|
+
const memView = new Uint8Array(_memory.buffer);
|
|
90
|
+
// Slice to get a clean copy unaffected by future mutations
|
|
91
|
+
const input = memView.slice(headerPtr, headerPtr + headerLen);
|
|
92
|
+
const hash = (0, core_1.sha3_256)(input);
|
|
93
|
+
memView.set(hash, outPtr);
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Load the WASM binary once per process (idempotent).
|
|
100
|
+
* Returns the instantiated module, or null if unavailable.
|
|
101
|
+
*/
|
|
102
|
+
async function loadWasm() {
|
|
103
|
+
if (_loadAttempted)
|
|
104
|
+
return _instance;
|
|
105
|
+
_loadAttempted = true;
|
|
106
|
+
if (typeof WebAssembly === 'undefined')
|
|
107
|
+
return null;
|
|
108
|
+
try {
|
|
109
|
+
let wasmBytes;
|
|
110
|
+
if (typeof process !== 'undefined' && process.versions?.node) {
|
|
111
|
+
// ── Node.js path ──────────────────────────────────────────────────────
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
113
|
+
const fs = require('fs');
|
|
114
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
115
|
+
const path = require('path');
|
|
116
|
+
const wasmPath = path.join(__dirname, 'wasm', 'miner.wasm');
|
|
117
|
+
if (!fs.existsSync(wasmPath))
|
|
118
|
+
return null;
|
|
119
|
+
// Use new Uint8Array(nodeBuffer) — correct copy that respects
|
|
120
|
+
// Buffer byteOffset/byteLength, avoiding the shared pool pitfall
|
|
121
|
+
// of accessing .buffer directly on a pooled Node.js Buffer.
|
|
122
|
+
const nodeBuffer = fs.readFileSync(wasmPath);
|
|
123
|
+
wasmBytes = new Uint8Array(nodeBuffer);
|
|
124
|
+
}
|
|
125
|
+
else if (_browserWasmUrl !== null) {
|
|
126
|
+
// ── Browser path ──────────────────────────────────────────────────────
|
|
127
|
+
const resp = await globalThis.fetch(_browserWasmUrl);
|
|
128
|
+
if (!resp.ok)
|
|
129
|
+
return null;
|
|
130
|
+
const ab = await resp.arrayBuffer();
|
|
131
|
+
wasmBytes = new Uint8Array(ab);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
// Browser context but no URL configured yet.
|
|
135
|
+
// Call setWasmUrl() to enable WASM in the browser (Task #114).
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
// Compile and instantiate with host imports
|
|
139
|
+
const buf = wasmBytes.buffer.slice(wasmBytes.byteOffset, wasmBytes.byteOffset + wasmBytes.byteLength);
|
|
140
|
+
const wasmModule = await WebAssembly.compile(buf);
|
|
141
|
+
const instance = await WebAssembly.instantiate(wasmModule, buildImports());
|
|
142
|
+
const exports = instance.exports;
|
|
143
|
+
if (typeof exports.mine !== 'function')
|
|
144
|
+
return null;
|
|
145
|
+
if (!(exports.memory instanceof WebAssembly.Memory))
|
|
146
|
+
return null;
|
|
147
|
+
_instance = instance;
|
|
148
|
+
_memory = exports.memory;
|
|
149
|
+
return _instance;
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
156
|
+
// Public API
|
|
157
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
158
|
+
/**
|
|
159
|
+
* Returns true when the WASM binary is loaded and `mine` is ready to use.
|
|
160
|
+
* Cached after the first call; subsequent calls are synchronous (via memoised flag).
|
|
161
|
+
*/
|
|
162
|
+
async function isWasmAvailable() {
|
|
163
|
+
return (await loadWasm()) !== null;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Mine a chunk using the WASM binary.
|
|
167
|
+
*
|
|
168
|
+
* Copies `headerBuf` and `target` into WASM linear memory at the correct
|
|
169
|
+
* offsets, calls `mine()`, and returns the found nonce — or `null` if:
|
|
170
|
+
* - WASM binary is unavailable
|
|
171
|
+
* - No valid nonce was found within the specified chunk
|
|
172
|
+
*
|
|
173
|
+
* Grows WASM memory if needed (single-page default = 64 KB is ample for
|
|
174
|
+
* any realistic TxHeader, but growth is handled for safety).
|
|
175
|
+
*
|
|
176
|
+
* @param headerBuf Full TxHeader bytes for the current nonce encoding range.
|
|
177
|
+
* @param nonceOffset Byte offset of the nonce VALUE in the header (always 2).
|
|
178
|
+
* @param nonceLen Byte length of the nonce value (1 for 0–127, 2 for 128–32767, …).
|
|
179
|
+
* @param target 32-byte difficulty target (big-endian).
|
|
180
|
+
* @param startNonce First nonce value to try.
|
|
181
|
+
* @param chunkCount Number of consecutive nonce values to try.
|
|
182
|
+
*/
|
|
183
|
+
async function mineChunkWasm(headerBuf, nonceOffset, nonceLen, target, startNonce, chunkCount) {
|
|
184
|
+
const inst = await loadWasm();
|
|
185
|
+
if (!inst || !_memory)
|
|
186
|
+
return null;
|
|
187
|
+
// Renamed to wasmExports to avoid shadowing the CJS module-level `exports` object.
|
|
188
|
+
// If named `exports`, `exports.WASM_HEADER_OFFSET` would resolve to the WASM
|
|
189
|
+
// instance exports (which has no such property → undefined), making headerPtr=0.
|
|
190
|
+
const wasmExports = inst.exports;
|
|
191
|
+
// Memory layout: [0..31]=hash output, [32..32+headerLen-1]=header, [32+headerLen..32+headerLen+31]=target
|
|
192
|
+
const headerPtr = exports.WASM_HEADER_OFFSET;
|
|
193
|
+
const targetPtr = headerPtr + headerBuf.length;
|
|
194
|
+
const totalNeeded = targetPtr + 32;
|
|
195
|
+
// Grow memory if necessary
|
|
196
|
+
let memView = new Uint8Array(_memory.buffer);
|
|
197
|
+
if (memView.byteLength < totalNeeded) {
|
|
198
|
+
const pagesNeeded = Math.ceil((totalNeeded - memView.byteLength) / 65536) + 1;
|
|
199
|
+
try {
|
|
200
|
+
_memory.grow(pagesNeeded);
|
|
201
|
+
memView = new Uint8Array(_memory.buffer);
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// Write header and target into WASM memory
|
|
208
|
+
memView.set(headerBuf, headerPtr);
|
|
209
|
+
memView.set(target, targetPtr);
|
|
210
|
+
const result = wasmExports.mine(headerPtr, headerBuf.length, nonceOffset, nonceLen, targetPtr, Number(startNonce), Number(chunkCount));
|
|
211
|
+
// result === -1 → no nonce found (WASM i32 0xFFFFFFFF sign-extended to JS -1)
|
|
212
|
+
// result >= 0 → found nonce; use >>> 0 to treat as unsigned before BigInt
|
|
213
|
+
return result === NOT_FOUND ? null : BigInt(result >>> 0);
|
|
214
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mine.ts — Local TxPoW proof-of-work mining loop.
|
|
3
|
+
*
|
|
4
|
+
* Algorithm (from TxPoWChecker.java):
|
|
5
|
+
* txpowId = SHA3-256( serialize(TxHeader) )
|
|
6
|
+
* valid = txpowId < mTxnDifficulty (big-endian 256-bit comparison)
|
|
7
|
+
*
|
|
8
|
+
* Strategy:
|
|
9
|
+
* 1. The TxBody is fixed during mining — only mNonce in the header changes.
|
|
10
|
+
* 2. We precompute the "header tail" (everything after mNonce) once per mine.
|
|
11
|
+
* 3. Within each chunk (fixed nonce encoding length), we update only the nonce
|
|
12
|
+
* value bytes in place — no per-iteration allocation.
|
|
13
|
+
* 4. At each MiniNumber encoding boundary (nonce 128, 32768, 8388608, …) we
|
|
14
|
+
* re-allocate a new header buffer with the wider nonce field.
|
|
15
|
+
* 5. Between chunks we yield to the event loop so the calling thread is never blocked.
|
|
16
|
+
* 6. When the pre-compiled WASM binary is present (`dist/wasm/miner.wasm`), the
|
|
17
|
+
* inner loop runs in WASM for ~5-10x throughput. Falls back to pure JS otherwise.
|
|
18
|
+
* 7. In Node.js (main thread), mining runs inside a `worker_threads` Worker so the
|
|
19
|
+
* event loop is never blocked. In browser contexts the in-process loop is used
|
|
20
|
+
* until Task #114 wires up the Web Worker entry point.
|
|
21
|
+
*
|
|
22
|
+
* Control-flow invariant (IMPORTANT):
|
|
23
|
+
* WASM and JS are mutually exclusive per chunk — we never re-mine a chunk that
|
|
24
|
+
* WASM already scanned. When WASM returns null (nonce not found in chunk), we
|
|
25
|
+
* advance to the next chunk rather than falling back to JS for the same range.
|
|
26
|
+
* This means `source` is always accurate: 'wasm' when the binary was used for
|
|
27
|
+
* the winning chunk; 'js' when the JS path found the nonce.
|
|
28
|
+
*/
|
|
29
|
+
export interface MineResult {
|
|
30
|
+
/** Fully serialized TxHeader bytes with the winning nonce. */
|
|
31
|
+
minedHeaderBytes: Uint8Array;
|
|
32
|
+
/** SHA3-256(minedHeaderBytes) — the canonical TxPoW ID. */
|
|
33
|
+
txpowId: Uint8Array;
|
|
34
|
+
nonce: bigint;
|
|
35
|
+
elapsedMs: number;
|
|
36
|
+
/** 'wasm' when the pre-compiled WASM binary found the nonce; 'js' otherwise. */
|
|
37
|
+
source: 'wasm' | 'js';
|
|
38
|
+
}
|
|
39
|
+
export interface MineOptions {
|
|
40
|
+
/**
|
|
41
|
+
* Hash iterations per async yield (default: 10_000).
|
|
42
|
+
* Lower = more responsive UI; higher = slightly faster mining.
|
|
43
|
+
*/
|
|
44
|
+
chunkSize?: number;
|
|
45
|
+
/**
|
|
46
|
+
* Hard cap on total iterations (default: unlimited).
|
|
47
|
+
* Throws if exhausted without finding a valid nonce.
|
|
48
|
+
*/
|
|
49
|
+
maxIterations?: number;
|
|
50
|
+
/** AbortSignal — rejects the Promise when aborted. */
|
|
51
|
+
signal?: AbortSignal;
|
|
52
|
+
/**
|
|
53
|
+
* Override the header timestamp (milliseconds since epoch).
|
|
54
|
+
* Defaults to Date.now(). Set a fixed value for deterministic testing.
|
|
55
|
+
*/
|
|
56
|
+
timeMilli?: bigint;
|
|
57
|
+
/**
|
|
58
|
+
* Force the pure-JS mining path even when `miner.wasm` is present.
|
|
59
|
+
* Useful for testing the JS fallback or comparing JS vs WASM performance.
|
|
60
|
+
*/
|
|
61
|
+
forceJs?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Internal: skip spawning a Node.js worker_threads Worker.
|
|
64
|
+
* Set by node.worker.ts to prevent recursive worker creation.
|
|
65
|
+
* Also forces in-process execution when set programmatically.
|
|
66
|
+
* @internal
|
|
67
|
+
*/
|
|
68
|
+
_skipWorker?: boolean;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Big-endian 256-bit comparison: true if a < b.
|
|
72
|
+
* Used to check: txpowId < mTxnDifficulty.
|
|
73
|
+
*/
|
|
74
|
+
export declare function isLessThan(a: Uint8Array, b: Uint8Array): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Build the "header tail" — the part of TxHeader that follows mNonce.
|
|
77
|
+
*
|
|
78
|
+
* This is computed once at the start of a mine and never changes during it.
|
|
79
|
+
*
|
|
80
|
+
* This is the fresh-transaction header shape (blockNumber=0, MAX_HASH block
|
|
81
|
+
* difficulty, zero super-parents, zero MMR, zero customHash). Block-candidate
|
|
82
|
+
* mining (Machine Work Admission) builds its own tail via
|
|
83
|
+
* `admission/template.ts` with real chain state and a customHash commitment.
|
|
84
|
+
*/
|
|
85
|
+
export declare function buildHeaderTail(txBodyHash: Uint8Array, timeMilli: bigint): Uint8Array;
|
|
86
|
+
/**
|
|
87
|
+
* Configure the URL of the browser.worker.js bundle so that `mineTxPoW()`
|
|
88
|
+
* can spawn a Web Worker in browser contexts.
|
|
89
|
+
*
|
|
90
|
+
* Call this once at extension/dApp startup. The bundled worker file exposes
|
|
91
|
+
* the same message protocol as node.worker.ts.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* import { setBrowserWorkerUrl } from '@totemsdk/txpow';
|
|
95
|
+
* setBrowserWorkerUrl(browser.runtime.getURL('mine-worker.js'));
|
|
96
|
+
*/
|
|
97
|
+
export declare function setBrowserWorkerUrl(url: string): void;
|
|
98
|
+
/**
|
|
99
|
+
* Core mining loop over a pre-built header tail.
|
|
100
|
+
*
|
|
101
|
+
* Iterates the nonce in the serialized TxHeader (nonce value at offset 2,
|
|
102
|
+
* followed by `headerTail`) until `SHA3-256(header) < target`. Shared by the
|
|
103
|
+
* transaction miner (`mineTxPoWInProcess`) and the Machine Work Admission
|
|
104
|
+
* miner (`admission/mine.ts`), which supplies its own block-candidate tail.
|
|
105
|
+
*
|
|
106
|
+
* @param headerTail Serialized TxHeader bytes AFTER the nonce field.
|
|
107
|
+
* @param target 32-byte difficulty target (big-endian 256-bit).
|
|
108
|
+
* @param options Chunk size, max iterations, abort signal, timeMilli override.
|
|
109
|
+
*/
|
|
110
|
+
export declare function mineHeaderTail(headerTail: Uint8Array, target: Uint8Array, options?: MineOptions): Promise<MineResult>;
|
|
111
|
+
/**
|
|
112
|
+
* Run the mining loop in the current thread/task.
|
|
113
|
+
* Called directly by the Node.js worker, and by the browser code path.
|
|
114
|
+
*/
|
|
115
|
+
export declare function mineTxPoWInProcess(txBodyBytes: Uint8Array, txnDifficulty: Uint8Array, options?: MineOptions): Promise<MineResult>;
|
|
116
|
+
/**
|
|
117
|
+
* Mine a TxPoW locally by iterating the header nonce until
|
|
118
|
+
* SHA3-256( TxHeader ) < txnDifficulty
|
|
119
|
+
*
|
|
120
|
+
* In Node.js (main thread), delegates to a `worker_threads` Worker so the
|
|
121
|
+
* event loop is never blocked. In browsers or Jest, runs in-process with
|
|
122
|
+
* periodic `setImmediate`/`setTimeout(0)` yields between chunks.
|
|
123
|
+
*
|
|
124
|
+
* Uses the pre-compiled `miner.wasm` binary for inner-loop throughput when
|
|
125
|
+
* available. Falls back to pure JS automatically when the binary is absent.
|
|
126
|
+
*
|
|
127
|
+
* @param txBodyBytes Pre-serialized TxBody bytes (from serializeTxBody).
|
|
128
|
+
* @param txnDifficulty 32-byte target. MUST be ≤ TX_POW_MIN_DIFFICULTY.
|
|
129
|
+
* @param options Chunk size, max iterations, abort signal, timeMilli override.
|
|
130
|
+
*/
|
|
131
|
+
export declare function mineTxPoW(txBodyBytes: Uint8Array, txnDifficulty: Uint8Array, options?: MineOptions): Promise<MineResult>;
|