@totemsdk/txpow 1.0.2 → 1.1.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.
Files changed (61) hide show
  1. package/LICENSE +202 -21
  2. package/NOTICE +60 -0
  3. package/dist/admission/challenge.js +14 -21
  4. package/dist/admission/commitment.js +9 -13
  5. package/dist/admission/index.js +6 -34
  6. package/dist/admission/mine.js +14 -17
  7. package/dist/admission/template.js +32 -47
  8. package/dist/admission/types.js +2 -5
  9. package/dist/admission/verify.js +12 -15
  10. package/dist/calibrate.js +4 -8
  11. package/dist/cjs/admission/challenge.d.ts +66 -0
  12. package/dist/cjs/admission/challenge.js +155 -0
  13. package/dist/cjs/admission/commitment.d.ts +34 -0
  14. package/dist/cjs/admission/commitment.js +73 -0
  15. package/dist/cjs/admission/index.d.ts +14 -0
  16. package/dist/cjs/admission/index.js +42 -0
  17. package/dist/cjs/admission/mine.d.ts +60 -0
  18. package/dist/cjs/admission/mine.js +146 -0
  19. package/dist/cjs/admission/template.d.ts +138 -0
  20. package/dist/cjs/admission/template.js +247 -0
  21. package/dist/cjs/admission/types.d.ts +224 -0
  22. package/dist/cjs/admission/types.js +24 -0
  23. package/dist/cjs/admission/verify.d.ts +50 -0
  24. package/dist/cjs/admission/verify.js +156 -0
  25. package/dist/cjs/calibrate.d.ts +35 -0
  26. package/dist/cjs/calibrate.js +68 -0
  27. package/dist/cjs/constants.d.ts +27 -0
  28. package/dist/cjs/constants.js +47 -0
  29. package/dist/cjs/difficulty.d.ts +44 -0
  30. package/dist/cjs/difficulty.js +111 -0
  31. package/dist/cjs/index.d.ts +28 -0
  32. package/dist/cjs/index.js +88 -0
  33. package/dist/cjs/magic.d.ts +19 -0
  34. package/dist/cjs/magic.js +35 -0
  35. package/dist/cjs/mine-wasm.d.ts +69 -0
  36. package/dist/cjs/mine-wasm.js +214 -0
  37. package/dist/cjs/mine.d.ts +131 -0
  38. package/dist/cjs/mine.js +407 -0
  39. package/dist/cjs/package.json +1 -0
  40. package/dist/cjs/serialization.d.ts +106 -0
  41. package/dist/cjs/serialization.js +160 -0
  42. package/dist/cjs/verify.d.ts +76 -0
  43. package/dist/cjs/verify.js +232 -0
  44. package/dist/cjs/wasm/miner.wasm +0 -0
  45. package/dist/cjs/workers/browser.worker.d.ts +26 -0
  46. package/dist/cjs/workers/browser.worker.js +63 -0
  47. package/dist/cjs/workers/node.worker.d.ts +33 -0
  48. package/dist/cjs/workers/node.worker.js +47 -0
  49. package/dist/constants.js +5 -8
  50. package/dist/difficulty.d.ts +24 -0
  51. package/dist/difficulty.js +54 -6
  52. package/dist/index.d.ts +1 -1
  53. package/dist/index.js +9 -62
  54. package/dist/magic.js +12 -15
  55. package/dist/mine-wasm.js +8 -15
  56. package/dist/mine.js +23 -31
  57. package/dist/serialization.js +28 -34
  58. package/dist/verify.js +15 -20
  59. package/dist/workers/browser.worker.js +4 -6
  60. package/dist/workers/node.worker.js +2 -3
  61. package/package.json +34 -15
@@ -0,0 +1,44 @@
1
+ /**
2
+ * difficulty.ts — Fetch and manage the TxPoW difficulty target.
3
+ *
4
+ * The live value comes from `GET /v1/wallet/txpow-params` on the Axia API.
5
+ * On any error (timeout, network failure, invalid response) we fall back to
6
+ * the hardcoded TX_POW_MIN_DIFFICULTY constant, which is the protocol floor.
7
+ */
8
+ export interface TxPowParams {
9
+ minTxPowWork: string;
10
+ }
11
+ /** Anything that can expose a node's live minimum TxPoW work (hex). */
12
+ export interface MinWorkSource {
13
+ getMinTxPowWork?(): Promise<string | null>;
14
+ }
15
+ /**
16
+ * Convert a live `currentmintxpowwork` value (32-byte hex target) into a mining
17
+ * target, applying the same 10% margin the node's own wallet uses
18
+ * (`minwork * 10 / 11`, see Java `TxPoWGenerator.generateTxPoW`).
19
+ *
20
+ * `TxPoWChecker.checkTxPoWSimple` rejects only when
21
+ * `txnDifficulty > magic.getMinTxPowWork()`, so a target that is harder than
22
+ * the live minimum is always accepted; the margin absorbs the tiny per-block
23
+ * Magic retarget.
24
+ */
25
+ export declare function targetFromMinWork(minWorkHex: string): Uint8Array;
26
+ /**
27
+ * Resolve the TxPoW mining target from a live node when it exposes
28
+ * `getMinTxPowWork()`, otherwise fall back to `TX_POW_MIN_DIFFICULTY`.
29
+ *
30
+ * Never throws: a node/protocol hiccup must not block transaction
31
+ * construction. The fallback is the protocol default target (MAX/1e6), which
32
+ * is harder than the network hard floor (`Magic.MIN_HASHES = 10000`).
33
+ */
34
+ export declare function resolveTxPowTarget(source?: MinWorkSource | null, fallback?: Uint8Array): Promise<Uint8Array>;
35
+ /**
36
+ * Fetch the current minimum TxPoW work from the Axia API.
37
+ *
38
+ * Falls back to TX_POW_MIN_DIFFICULTY (the hardcoded protocol floor) on any
39
+ * error: network failure, timeout, or malformed response.
40
+ *
41
+ * @param axiaBaseUrl Base URL of the Axia API, e.g. "https://api.axia.to"
42
+ * @param timeoutMs Request timeout in ms (default: 3000)
43
+ */
44
+ export declare function fetchTxPowTarget(axiaBaseUrl: string, timeoutMs?: number): Promise<Uint8Array>;
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ /**
3
+ * difficulty.ts — Fetch and manage the TxPoW difficulty target.
4
+ *
5
+ * The live value comes from `GET /v1/wallet/txpow-params` on the Axia API.
6
+ * On any error (timeout, network failure, invalid response) we fall back to
7
+ * the hardcoded TX_POW_MIN_DIFFICULTY constant, which is the protocol floor.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.targetFromMinWork = targetFromMinWork;
11
+ exports.resolveTxPowTarget = resolveTxPowTarget;
12
+ exports.fetchTxPowTarget = fetchTxPowTarget;
13
+ const constants_js_1 = require("./constants.js");
14
+ /**
15
+ * Convert a live `currentmintxpowwork` value (32-byte hex target) into a mining
16
+ * target, applying the same 10% margin the node's own wallet uses
17
+ * (`minwork * 10 / 11`, see Java `TxPoWGenerator.generateTxPoW`).
18
+ *
19
+ * `TxPoWChecker.checkTxPoWSimple` rejects only when
20
+ * `txnDifficulty > magic.getMinTxPowWork()`, so a target that is harder than
21
+ * the live minimum is always accepted; the margin absorbs the tiny per-block
22
+ * Magic retarget.
23
+ */
24
+ function targetFromMinWork(minWorkHex) {
25
+ const clean = minWorkHex.replace(/^0x/i, '').trim();
26
+ if (clean.length === 0 || clean.length > 64 || !/^[0-9a-fA-F]+$/.test(clean)) {
27
+ throw new Error(`Invalid minTxPowWork: ${minWorkHex}`);
28
+ }
29
+ const value = BigInt('0x' + clean);
30
+ const adjusted = (value * 10n) / 11n;
31
+ const target = adjusted > 0n ? adjusted : value;
32
+ let hex = target.toString(16);
33
+ if (hex.length % 2 !== 0)
34
+ hex = '0' + hex;
35
+ while (hex.length < 64)
36
+ hex = '0' + hex;
37
+ const out = new Uint8Array(32);
38
+ for (let i = 0; i < 32; i++) {
39
+ out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
40
+ }
41
+ return out;
42
+ }
43
+ /**
44
+ * Resolve the TxPoW mining target from a live node when it exposes
45
+ * `getMinTxPowWork()`, otherwise fall back to `TX_POW_MIN_DIFFICULTY`.
46
+ *
47
+ * Never throws: a node/protocol hiccup must not block transaction
48
+ * construction. The fallback is the protocol default target (MAX/1e6), which
49
+ * is harder than the network hard floor (`Magic.MIN_HASHES = 10000`).
50
+ */
51
+ async function resolveTxPowTarget(source, fallback = constants_js_1.TX_POW_MIN_DIFFICULTY) {
52
+ try {
53
+ const hex = await source?.getMinTxPowWork?.();
54
+ if (hex) {
55
+ const target = targetFromMinWork(hex);
56
+ if (target.some((b) => b !== 0))
57
+ return target;
58
+ }
59
+ }
60
+ catch {
61
+ // fall through to the constant
62
+ }
63
+ return new Uint8Array(fallback);
64
+ }
65
+ function hexToBytes(hex) {
66
+ const h = hex.startsWith('0x') ? hex.slice(2) : hex;
67
+ const out = new Uint8Array(h.length / 2);
68
+ for (let i = 0; i < h.length; i += 2) {
69
+ out[i / 2] = parseInt(h.slice(i, i + 2), 16);
70
+ }
71
+ return out;
72
+ }
73
+ /**
74
+ * Fetch the current minimum TxPoW work from the Axia API.
75
+ *
76
+ * Falls back to TX_POW_MIN_DIFFICULTY (the hardcoded protocol floor) on any
77
+ * error: network failure, timeout, or malformed response.
78
+ *
79
+ * @param axiaBaseUrl Base URL of the Axia API, e.g. "https://api.axia.to"
80
+ * @param timeoutMs Request timeout in ms (default: 3000)
81
+ */
82
+ async function fetchTxPowTarget(axiaBaseUrl, timeoutMs = 3000) {
83
+ try {
84
+ const base = axiaBaseUrl.replace(/\/$/, '');
85
+ const url = `${base}/v1/wallet/txpow-params`;
86
+ const controller = new AbortController();
87
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
88
+ let response;
89
+ try {
90
+ response = await fetch(url, { signal: controller.signal });
91
+ }
92
+ finally {
93
+ clearTimeout(timer);
94
+ }
95
+ if (!response.ok) {
96
+ throw new Error(`HTTP ${response.status}`);
97
+ }
98
+ const data = (await response.json());
99
+ if (typeof data.minTxPowWork !== 'string') {
100
+ throw new Error('Missing minTxPowWork field');
101
+ }
102
+ const clean = data.minTxPowWork.replace('0x', '').replace(/\s/g, '');
103
+ if (clean.length !== 64) {
104
+ throw new Error(`Invalid minTxPowWork length: ${clean.length} (expected 64 hex chars)`);
105
+ }
106
+ return hexToBytes(clean);
107
+ }
108
+ catch {
109
+ return new Uint8Array(constants_js_1.TX_POW_MIN_DIFFICULTY);
110
+ }
111
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @totemsdk/txpow
3
+ *
4
+ * TxPoW envelope serialization and proof-of-work mining for the Minima protocol.
5
+ *
6
+ * USAGE — MEG-side mining (byte-identical to extension current behaviour):
7
+ * const txpow = serializeTxPoW(txBytes, witnessBytes);
8
+ * // Submit to Axia: node re-mines with correct difficulty
9
+ *
10
+ * USAGE — Local mining:
11
+ * const target = await fetchTxPowTarget(axiaBaseUrl);
12
+ * const txBody = serializeTxBody(txBytes, witnessBytes, { txnDifficulty: target });
13
+ * const result = await mineTxPoW(txBody, target);
14
+ * const txpow = concat(result.minedHeaderBytes, new Uint8Array([0x01]), txBody);
15
+ *
16
+ * USAGE — Verify (relay nodes):
17
+ * const check = verifyProofOfWork(txpowId, mTxnDifficulty);
18
+ * if (!check.valid) drop(check.reason);
19
+ */
20
+ export { serializeTxHeader, serializeTxBody, serializeTxPoW, computeTxPoWId, type TxHeaderOptions, type TxBodyOptions, type TxPoWOptions, } from './serialization.js';
21
+ export { MAX_HASH, ZERO_HASH, TX_POW_MIN_DIFFICULTY, CASCADE_LEVELS, MAIN_NET_CHAIN_ID, } from './constants.js';
22
+ export { serializeMagic } from './magic.js';
23
+ export { mineTxPoW, mineTxPoWInProcess, mineHeaderTail, buildHeaderTail, isLessThan, setBrowserWorkerUrl, type MineResult, type MineOptions, } from './mine.js';
24
+ export { setWasmUrl, getBrowserWasmUrl, isWasmAvailable } from './mine-wasm.js';
25
+ export { fetchTxPowTarget, targetFromMinWork, resolveTxPowTarget, type TxPowParams, type MinWorkSource, } from './difficulty.js';
26
+ export { verifyProofOfWork, verifyTxPoWWork, verifyTxPoWParts, type VerifyResult } from './verify.js';
27
+ export { calibrateHashRate, estimateMiningCost, type MiningEstimate, } from './calibrate.js';
28
+ export { createWorkChallenge, validateWorkChallenge, challengeFingerprint, canonicalChallenge, computeActionCommitment, canonicalAction, mineWorkAdmission, verifyWorkAdmission, buildBlockHeaderTail, serializeSuperParents, isBlockWinner, computeSuperLevel, templateFreshness, computeBlockCandidateId, buildEmptyBlockBody, buildEmptyTransactionBytes, buildEmptyWitnessBytes, buildEmptyBurnTxBytes, buildEmptyBurnWitnessBytes, assembleTxPoWEnvelope, reconstructTxPoWEnvelope, MACHINE_WORK_ADMISSION_VERSION, MACHINE_WORK_DOMAIN, DEFAULT_CHALLENGE_TTL_MS, MAX_CHALLENGE_TTL_MS, type WorkChallenge, type MachineWorkAction, type MinimaWorkTemplate, type MinimaWorkTemplateProvider, type MinimaWorkRelay, type MachineWorkAdmissionProof, type WorkAdmissionVerification, type MineWorkAdmissionOptions, type VerifyWorkAdmissionOptions, } from './admission/index.js';
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ /**
3
+ * @totemsdk/txpow
4
+ *
5
+ * TxPoW envelope serialization and proof-of-work mining for the Minima protocol.
6
+ *
7
+ * USAGE — MEG-side mining (byte-identical to extension current behaviour):
8
+ * const txpow = serializeTxPoW(txBytes, witnessBytes);
9
+ * // Submit to Axia: node re-mines with correct difficulty
10
+ *
11
+ * USAGE — Local mining:
12
+ * const target = await fetchTxPowTarget(axiaBaseUrl);
13
+ * const txBody = serializeTxBody(txBytes, witnessBytes, { txnDifficulty: target });
14
+ * const result = await mineTxPoW(txBody, target);
15
+ * const txpow = concat(result.minedHeaderBytes, new Uint8Array([0x01]), txBody);
16
+ *
17
+ * USAGE — Verify (relay nodes):
18
+ * const check = verifyProofOfWork(txpowId, mTxnDifficulty);
19
+ * if (!check.valid) drop(check.reason);
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.MACHINE_WORK_DOMAIN = exports.MACHINE_WORK_ADMISSION_VERSION = exports.reconstructTxPoWEnvelope = exports.assembleTxPoWEnvelope = exports.buildEmptyBurnWitnessBytes = exports.buildEmptyBurnTxBytes = exports.buildEmptyWitnessBytes = exports.buildEmptyTransactionBytes = exports.buildEmptyBlockBody = exports.computeBlockCandidateId = exports.templateFreshness = exports.computeSuperLevel = exports.isBlockWinner = exports.serializeSuperParents = exports.buildBlockHeaderTail = exports.verifyWorkAdmission = exports.mineWorkAdmission = exports.canonicalAction = exports.computeActionCommitment = exports.canonicalChallenge = exports.challengeFingerprint = exports.validateWorkChallenge = exports.createWorkChallenge = exports.estimateMiningCost = exports.calibrateHashRate = exports.verifyTxPoWParts = exports.verifyTxPoWWork = exports.verifyProofOfWork = exports.resolveTxPowTarget = exports.targetFromMinWork = exports.fetchTxPowTarget = exports.isWasmAvailable = exports.getBrowserWasmUrl = exports.setWasmUrl = exports.setBrowserWorkerUrl = exports.isLessThan = exports.buildHeaderTail = exports.mineHeaderTail = exports.mineTxPoWInProcess = exports.mineTxPoW = exports.serializeMagic = exports.MAIN_NET_CHAIN_ID = exports.CASCADE_LEVELS = exports.TX_POW_MIN_DIFFICULTY = exports.ZERO_HASH = exports.MAX_HASH = exports.computeTxPoWId = exports.serializeTxPoW = exports.serializeTxBody = exports.serializeTxHeader = void 0;
23
+ exports.MAX_CHALLENGE_TTL_MS = exports.DEFAULT_CHALLENGE_TTL_MS = void 0;
24
+ var serialization_js_1 = require("./serialization.js");
25
+ Object.defineProperty(exports, "serializeTxHeader", { enumerable: true, get: function () { return serialization_js_1.serializeTxHeader; } });
26
+ Object.defineProperty(exports, "serializeTxBody", { enumerable: true, get: function () { return serialization_js_1.serializeTxBody; } });
27
+ Object.defineProperty(exports, "serializeTxPoW", { enumerable: true, get: function () { return serialization_js_1.serializeTxPoW; } });
28
+ Object.defineProperty(exports, "computeTxPoWId", { enumerable: true, get: function () { return serialization_js_1.computeTxPoWId; } });
29
+ var constants_js_1 = require("./constants.js");
30
+ Object.defineProperty(exports, "MAX_HASH", { enumerable: true, get: function () { return constants_js_1.MAX_HASH; } });
31
+ Object.defineProperty(exports, "ZERO_HASH", { enumerable: true, get: function () { return constants_js_1.ZERO_HASH; } });
32
+ Object.defineProperty(exports, "TX_POW_MIN_DIFFICULTY", { enumerable: true, get: function () { return constants_js_1.TX_POW_MIN_DIFFICULTY; } });
33
+ Object.defineProperty(exports, "CASCADE_LEVELS", { enumerable: true, get: function () { return constants_js_1.CASCADE_LEVELS; } });
34
+ Object.defineProperty(exports, "MAIN_NET_CHAIN_ID", { enumerable: true, get: function () { return constants_js_1.MAIN_NET_CHAIN_ID; } });
35
+ var magic_js_1 = require("./magic.js");
36
+ Object.defineProperty(exports, "serializeMagic", { enumerable: true, get: function () { return magic_js_1.serializeMagic; } });
37
+ var mine_js_1 = require("./mine.js");
38
+ Object.defineProperty(exports, "mineTxPoW", { enumerable: true, get: function () { return mine_js_1.mineTxPoW; } });
39
+ Object.defineProperty(exports, "mineTxPoWInProcess", { enumerable: true, get: function () { return mine_js_1.mineTxPoWInProcess; } });
40
+ Object.defineProperty(exports, "mineHeaderTail", { enumerable: true, get: function () { return mine_js_1.mineHeaderTail; } });
41
+ Object.defineProperty(exports, "buildHeaderTail", { enumerable: true, get: function () { return mine_js_1.buildHeaderTail; } });
42
+ Object.defineProperty(exports, "isLessThan", { enumerable: true, get: function () { return mine_js_1.isLessThan; } });
43
+ Object.defineProperty(exports, "setBrowserWorkerUrl", { enumerable: true, get: function () { return mine_js_1.setBrowserWorkerUrl; } });
44
+ var mine_wasm_js_1 = require("./mine-wasm.js");
45
+ Object.defineProperty(exports, "setWasmUrl", { enumerable: true, get: function () { return mine_wasm_js_1.setWasmUrl; } });
46
+ Object.defineProperty(exports, "getBrowserWasmUrl", { enumerable: true, get: function () { return mine_wasm_js_1.getBrowserWasmUrl; } });
47
+ Object.defineProperty(exports, "isWasmAvailable", { enumerable: true, get: function () { return mine_wasm_js_1.isWasmAvailable; } });
48
+ var difficulty_js_1 = require("./difficulty.js");
49
+ Object.defineProperty(exports, "fetchTxPowTarget", { enumerable: true, get: function () { return difficulty_js_1.fetchTxPowTarget; } });
50
+ Object.defineProperty(exports, "targetFromMinWork", { enumerable: true, get: function () { return difficulty_js_1.targetFromMinWork; } });
51
+ Object.defineProperty(exports, "resolveTxPowTarget", { enumerable: true, get: function () { return difficulty_js_1.resolveTxPowTarget; } });
52
+ var verify_js_1 = require("./verify.js");
53
+ Object.defineProperty(exports, "verifyProofOfWork", { enumerable: true, get: function () { return verify_js_1.verifyProofOfWork; } });
54
+ Object.defineProperty(exports, "verifyTxPoWWork", { enumerable: true, get: function () { return verify_js_1.verifyTxPoWWork; } });
55
+ Object.defineProperty(exports, "verifyTxPoWParts", { enumerable: true, get: function () { return verify_js_1.verifyTxPoWParts; } });
56
+ var calibrate_js_1 = require("./calibrate.js");
57
+ Object.defineProperty(exports, "calibrateHashRate", { enumerable: true, get: function () { return calibrate_js_1.calibrateHashRate; } });
58
+ Object.defineProperty(exports, "estimateMiningCost", { enumerable: true, get: function () { return calibrate_js_1.estimateMiningCost; } });
59
+ // ── Machine Work Admission ──────────────────────────────────────────────────
60
+ // Receiver-controlled computational admission bound to a real Minima block
61
+ // candidate. The same nonce search that admits a machine action also searches
62
+ // for Minima blocks (Super-0 … Super-31).
63
+ var index_js_1 = require("./admission/index.js");
64
+ Object.defineProperty(exports, "createWorkChallenge", { enumerable: true, get: function () { return index_js_1.createWorkChallenge; } });
65
+ Object.defineProperty(exports, "validateWorkChallenge", { enumerable: true, get: function () { return index_js_1.validateWorkChallenge; } });
66
+ Object.defineProperty(exports, "challengeFingerprint", { enumerable: true, get: function () { return index_js_1.challengeFingerprint; } });
67
+ Object.defineProperty(exports, "canonicalChallenge", { enumerable: true, get: function () { return index_js_1.canonicalChallenge; } });
68
+ Object.defineProperty(exports, "computeActionCommitment", { enumerable: true, get: function () { return index_js_1.computeActionCommitment; } });
69
+ Object.defineProperty(exports, "canonicalAction", { enumerable: true, get: function () { return index_js_1.canonicalAction; } });
70
+ Object.defineProperty(exports, "mineWorkAdmission", { enumerable: true, get: function () { return index_js_1.mineWorkAdmission; } });
71
+ Object.defineProperty(exports, "verifyWorkAdmission", { enumerable: true, get: function () { return index_js_1.verifyWorkAdmission; } });
72
+ Object.defineProperty(exports, "buildBlockHeaderTail", { enumerable: true, get: function () { return index_js_1.buildBlockHeaderTail; } });
73
+ Object.defineProperty(exports, "serializeSuperParents", { enumerable: true, get: function () { return index_js_1.serializeSuperParents; } });
74
+ Object.defineProperty(exports, "isBlockWinner", { enumerable: true, get: function () { return index_js_1.isBlockWinner; } });
75
+ Object.defineProperty(exports, "computeSuperLevel", { enumerable: true, get: function () { return index_js_1.computeSuperLevel; } });
76
+ Object.defineProperty(exports, "templateFreshness", { enumerable: true, get: function () { return index_js_1.templateFreshness; } });
77
+ Object.defineProperty(exports, "computeBlockCandidateId", { enumerable: true, get: function () { return index_js_1.computeBlockCandidateId; } });
78
+ Object.defineProperty(exports, "buildEmptyBlockBody", { enumerable: true, get: function () { return index_js_1.buildEmptyBlockBody; } });
79
+ Object.defineProperty(exports, "buildEmptyTransactionBytes", { enumerable: true, get: function () { return index_js_1.buildEmptyTransactionBytes; } });
80
+ Object.defineProperty(exports, "buildEmptyWitnessBytes", { enumerable: true, get: function () { return index_js_1.buildEmptyWitnessBytes; } });
81
+ Object.defineProperty(exports, "buildEmptyBurnTxBytes", { enumerable: true, get: function () { return index_js_1.buildEmptyBurnTxBytes; } });
82
+ Object.defineProperty(exports, "buildEmptyBurnWitnessBytes", { enumerable: true, get: function () { return index_js_1.buildEmptyBurnWitnessBytes; } });
83
+ Object.defineProperty(exports, "assembleTxPoWEnvelope", { enumerable: true, get: function () { return index_js_1.assembleTxPoWEnvelope; } });
84
+ Object.defineProperty(exports, "reconstructTxPoWEnvelope", { enumerable: true, get: function () { return index_js_1.reconstructTxPoWEnvelope; } });
85
+ Object.defineProperty(exports, "MACHINE_WORK_ADMISSION_VERSION", { enumerable: true, get: function () { return index_js_1.MACHINE_WORK_ADMISSION_VERSION; } });
86
+ Object.defineProperty(exports, "MACHINE_WORK_DOMAIN", { enumerable: true, get: function () { return index_js_1.MACHINE_WORK_DOMAIN; } });
87
+ Object.defineProperty(exports, "DEFAULT_CHALLENGE_TTL_MS", { enumerable: true, get: function () { return index_js_1.DEFAULT_CHALLENGE_TTL_MS; } });
88
+ Object.defineProperty(exports, "MAX_CHALLENGE_TTL_MS", { enumerable: true, get: function () { return index_js_1.MAX_CHALLENGE_TTL_MS; } });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * magic.ts — Serialize the Minima Magic struct.
3
+ *
4
+ * Ported from the extension's MinimaTransactionBuilder.ts::serializeMagic().
5
+ * Matches Magic.writeDataStream() in Java exactly.
6
+ *
7
+ * Magic contains two copies of 4 fields (current + desired parameters):
8
+ * maxTxPoWSize (MiniNumber)
9
+ * maxKISSVMOps (MiniNumber)
10
+ * maxTxnPerBlock(MiniNumber)
11
+ * minTxPoWWork (MiniData — 32 bytes)
12
+ *
13
+ * Default values from Magic.java:
14
+ * maxTxPoWSize = 65536
15
+ * maxKISSVMOps = 1024
16
+ * maxTxnPerBlock = 256
17
+ * minTxPoWWork = MAX_HASH (all 0xFF, 32 bytes) — placeholder in fresh TxPoW
18
+ */
19
+ export declare function serializeMagic(): Uint8Array;
@@ -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
+ }