@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.
Files changed (59) hide show
  1. package/dist/admission/challenge.js +14 -21
  2. package/dist/admission/commitment.js +9 -13
  3. package/dist/admission/index.js +6 -34
  4. package/dist/admission/mine.js +14 -17
  5. package/dist/admission/template.js +32 -47
  6. package/dist/admission/types.js +2 -5
  7. package/dist/admission/verify.js +12 -15
  8. package/dist/calibrate.js +4 -8
  9. package/dist/cjs/admission/challenge.d.ts +66 -0
  10. package/dist/cjs/admission/challenge.js +155 -0
  11. package/dist/cjs/admission/commitment.d.ts +34 -0
  12. package/dist/cjs/admission/commitment.js +73 -0
  13. package/dist/cjs/admission/index.d.ts +14 -0
  14. package/dist/cjs/admission/index.js +42 -0
  15. package/dist/cjs/admission/mine.d.ts +60 -0
  16. package/dist/cjs/admission/mine.js +146 -0
  17. package/dist/cjs/admission/template.d.ts +138 -0
  18. package/dist/cjs/admission/template.js +247 -0
  19. package/dist/cjs/admission/types.d.ts +224 -0
  20. package/dist/cjs/admission/types.js +24 -0
  21. package/dist/cjs/admission/verify.d.ts +50 -0
  22. package/dist/cjs/admission/verify.js +156 -0
  23. package/dist/cjs/calibrate.d.ts +35 -0
  24. package/dist/cjs/calibrate.js +68 -0
  25. package/dist/cjs/constants.d.ts +27 -0
  26. package/dist/cjs/constants.js +47 -0
  27. package/dist/cjs/difficulty.d.ts +44 -0
  28. package/dist/cjs/difficulty.js +111 -0
  29. package/dist/cjs/index.d.ts +28 -0
  30. package/dist/cjs/index.js +88 -0
  31. package/dist/cjs/magic.d.ts +19 -0
  32. package/dist/cjs/magic.js +35 -0
  33. package/dist/cjs/mine-wasm.d.ts +69 -0
  34. package/dist/cjs/mine-wasm.js +214 -0
  35. package/dist/cjs/mine.d.ts +131 -0
  36. package/dist/cjs/mine.js +407 -0
  37. package/dist/cjs/package.json +1 -0
  38. package/dist/cjs/serialization.d.ts +106 -0
  39. package/dist/cjs/serialization.js +160 -0
  40. package/dist/cjs/verify.d.ts +76 -0
  41. package/dist/cjs/verify.js +232 -0
  42. package/dist/cjs/wasm/miner.wasm +0 -0
  43. package/dist/cjs/workers/browser.worker.d.ts +26 -0
  44. package/dist/cjs/workers/browser.worker.js +63 -0
  45. package/dist/cjs/workers/node.worker.d.ts +33 -0
  46. package/dist/cjs/workers/node.worker.js +47 -0
  47. package/dist/constants.js +5 -8
  48. package/dist/difficulty.d.ts +24 -0
  49. package/dist/difficulty.js +54 -6
  50. package/dist/index.d.ts +1 -1
  51. package/dist/index.js +9 -62
  52. package/dist/magic.js +12 -15
  53. package/dist/mine-wasm.js +8 -15
  54. package/dist/mine.js +23 -31
  55. package/dist/serialization.js +28 -34
  56. package/dist/verify.js +15 -20
  57. package/dist/workers/browser.worker.js +4 -6
  58. package/dist/workers/node.worker.js +2 -3
  59. package/package.json +31 -13
@@ -0,0 +1,138 @@
1
+ /**
2
+ * admission/template.ts — Minima block-candidate template handling.
3
+ *
4
+ * Builds a TxHeader tail that is structurally capable of becoming a legitimate
5
+ * Minima block. The fields (block number, block difficulty, super-parents, MMR
6
+ * root/total, magic, time) come from the current chain tip via an injected
7
+ * MinimaWorkTemplateProvider — mirroring TxPoWGenerator.generateTxPoW in
8
+ * Minima. The action commitment is placed in the header's customHash field.
9
+ *
10
+ * The TxPoW package stays transport/node-client agnostic: callers inject the
11
+ * template provider. A real Minima node / Axia integration supplies live chain
12
+ * state; tests supply fixtures.
13
+ */
14
+ import type { MinimaWorkTemplate } from './types.js';
15
+ /**
16
+ * Serialize the super-parent RLE runs per TxHeader.writeDataStream.
17
+ *
18
+ * Consecutive equal hashes are coalesced into (count: MiniByte, hash) runs.
19
+ * A fresh candidate with all-distinct parents serializes as 32 runs.
20
+ */
21
+ export declare function serializeSuperParents(superParents: string[]): Uint8Array;
22
+ /**
23
+ * Build the empty burn transaction bytes (TxBody.writeDataStream fields 5-6).
24
+ *
25
+ * Equivalent to serializeTransaction({ linkHash: [0x00], inputs: [], outputs: [],
26
+ * state: [] }): 0 inputs, 0 outputs, 0 state, linkHash = ZERO_TXPOWID (1 byte).
27
+ */
28
+ export declare function buildEmptyBurnTxBytes(): Uint8Array;
29
+ /**
30
+ * Build the empty burn witness bytes (TxBody.writeDataStream field 6).
31
+ * 0 signatures, 0 coinproofs, 0 scriptproofs.
32
+ */
33
+ export declare function buildEmptyBurnWitnessBytes(): Uint8Array;
34
+ /**
35
+ * Build the empty transaction bytes (TxBody.writeDataStream field 3).
36
+ * 0 inputs, 0 outputs, 0 state, linkHash = ZERO_TXPOWID (1 byte).
37
+ */
38
+ export declare function buildEmptyTransactionBytes(): Uint8Array;
39
+ /**
40
+ * Build the empty witness bytes (TxBody.writeDataStream field 4).
41
+ * 0 signatures, 0 coinproofs, 0 scriptproofs.
42
+ */
43
+ export declare function buildEmptyWitnessBytes(): Uint8Array;
44
+ /**
45
+ * Build the serialized TxBody for a fresh block candidate.
46
+ *
47
+ * Mirrors TxBody.writeDataStream with an empty transaction and witness (the
48
+ * same shape Minima's MINEPULSE automine uses for block candidates):
49
+ * mPRNG | mTxnDifficulty | mTransaction | mWitness |
50
+ * mBurnTransaction | mBurnWitness | mTxPowIDList
51
+ *
52
+ * @param prng 32-byte PRNG (deterministic for tests; random otherwise).
53
+ * @param txnDifficulty Transaction difficulty (32-byte hex). For a block
54
+ * candidate this is typically the block difficulty.
55
+ */
56
+ export declare function buildEmptyBlockBody(prng: Uint8Array, txnDifficulty: string): Uint8Array;
57
+ /**
58
+ * Assemble the complete Minima TxPoW wire format:
59
+ * TxHeader | 0x01 (hasBody) | TxBody
60
+ *
61
+ * This is the representation required for network submission of a genuine L1
62
+ * block candidate. A mined header alone is NOT sufficient.
63
+ *
64
+ * @param headerBytes Serialized TxHeader bytes (with the winning nonce).
65
+ * @param bodyBytes Serialized TxBody bytes.
66
+ */
67
+ export declare function assembleTxPoWEnvelope(headerBytes: Uint8Array, bodyBytes: Uint8Array): Uint8Array;
68
+ /**
69
+ * Build the TxHeader tail (everything after the nonce field) for a block
70
+ * candidate with the given customHash commitment.
71
+ *
72
+ * Field order (TxHeader.writeDataStream):
73
+ * mNonce | mChainID | mTimeMilli | mBlockNumber | mBlockDifficulty |
74
+ * super-parents RLE | mMMRRoot | mMMRTotal | mMagic | mCustomHash | mTxBodyHash
75
+ *
76
+ * @param template The current Minima work template.
77
+ * @param customHash The action commitment (32-byte hex) to place in mCustomHash.
78
+ * @param txBodyHash SHA3-256 of the serialized TxBody (32-byte hex).
79
+ */
80
+ export declare function buildBlockHeaderTail(template: MinimaWorkTemplate, customHash: string, txBodyHash: string): Uint8Array;
81
+ /**
82
+ * Compute the TxPoW ID for a mined block-candidate header.
83
+ * txpowId = SHA3-256(serialized TxHeader).
84
+ */
85
+ export declare function computeBlockCandidateId(headerBytes: Uint8Array): Uint8Array;
86
+ /**
87
+ * Check whether a txpowId beats the block target (i.e. is a genuine Minima block).
88
+ * valid = txpowId < blockDifficulty (big-endian 256-bit comparison).
89
+ */
90
+ export declare function isBlockWinner(txpowId: Uint8Array, blockDifficulty: string): boolean;
91
+ /**
92
+ * Compute the Minima Super level for a TxPoW ID against a block difficulty,
93
+ * with Minima's exact integer semantics.
94
+ *
95
+ * From TxPoW.calculateTXPOWID() / getSuperLevel():
96
+ * quot = blockDifficulty / txpowId (unsigned BigInteger division)
97
+ * super = quot.bitLength() - 1 (floor(log2(quot)))
98
+ * if super >= MINIMA_CASCADE_LEVELS (32) → clamp to 31
99
+ *
100
+ * When the TxPoW is NOT a block (txpowId >= blockDifficulty), quot = 0,
101
+ * bitLength(0) = 0, so super = -1.
102
+ *
103
+ * Result:
104
+ * -1 — not a Minima block
105
+ * 0 — ordinary/base Minima block (Super-0)
106
+ * 1..31 — Super-1 … Super-31 (stronger blocks; 31 is the maximum represented)
107
+ *
108
+ * @param txpowId SHA3-256(header), 32 bytes.
109
+ * @param blockDifficulty 32-byte hex block difficulty target.
110
+ */
111
+ export declare function computeSuperLevel(txpowId: Uint8Array, blockDifficulty: string): number;
112
+ /**
113
+ * Default staleness policy: a template is "current enough" for admission if it
114
+ * was captured within the window, and "current" for L1 broadcast if it matches
115
+ * the latest template id.
116
+ */
117
+ export declare function templateFreshness(template: MinimaWorkTemplate, latest: MinimaWorkTemplate | null, options?: {
118
+ admissionWindowMs?: number;
119
+ now?: number;
120
+ }): {
121
+ admissionValid: boolean;
122
+ broadcastable: boolean;
123
+ };
124
+ /**
125
+ * Reconstruct the complete Minima TxPoW envelope for a proof.
126
+ *
127
+ * Rebuilds the empty block TxBody deterministically, recomputes the body hash,
128
+ * and reassembles header | 0x01 | body. Used by verification to confirm the
129
+ * proof corresponds to a complete, Minima-serializable candidate.
130
+ *
131
+ * @param proofTemplate The template the proof was mined against.
132
+ * @param headerBytes The mined TxHeader bytes.
133
+ * @param prng The PRNG used when the proof was mined (32 bytes).
134
+ */
135
+ export declare function reconstructTxPoWEnvelope(proofTemplate: MinimaWorkTemplate, headerBytes: Uint8Array, prng: Uint8Array): {
136
+ envelope: Uint8Array;
137
+ bodyHash: string;
138
+ };
@@ -0,0 +1,247 @@
1
+ "use strict";
2
+ /**
3
+ * admission/template.ts — Minima block-candidate template handling.
4
+ *
5
+ * Builds a TxHeader tail that is structurally capable of becoming a legitimate
6
+ * Minima block. The fields (block number, block difficulty, super-parents, MMR
7
+ * root/total, magic, time) come from the current chain tip via an injected
8
+ * MinimaWorkTemplateProvider — mirroring TxPoWGenerator.generateTxPoW in
9
+ * Minima. The action commitment is placed in the header's customHash field.
10
+ *
11
+ * The TxPoW package stays transport/node-client agnostic: callers inject the
12
+ * template provider. A real Minima node / Axia integration supplies live chain
13
+ * state; tests supply fixtures.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.serializeSuperParents = serializeSuperParents;
17
+ exports.buildEmptyBurnTxBytes = buildEmptyBurnTxBytes;
18
+ exports.buildEmptyBurnWitnessBytes = buildEmptyBurnWitnessBytes;
19
+ exports.buildEmptyTransactionBytes = buildEmptyTransactionBytes;
20
+ exports.buildEmptyWitnessBytes = buildEmptyWitnessBytes;
21
+ exports.buildEmptyBlockBody = buildEmptyBlockBody;
22
+ exports.assembleTxPoWEnvelope = assembleTxPoWEnvelope;
23
+ exports.buildBlockHeaderTail = buildBlockHeaderTail;
24
+ exports.computeBlockCandidateId = computeBlockCandidateId;
25
+ exports.isBlockWinner = isBlockWinner;
26
+ exports.computeSuperLevel = computeSuperLevel;
27
+ exports.templateFreshness = templateFreshness;
28
+ exports.reconstructTxPoWEnvelope = reconstructTxPoWEnvelope;
29
+ const core_1 = require("@totemsdk/core");
30
+ const core_2 = require("@totemsdk/core");
31
+ const constants_js_1 = require("../constants.js");
32
+ function hexToBytes(hex) {
33
+ const h = hex.startsWith('0x') ? hex.slice(2) : hex;
34
+ const out = new Uint8Array(h.length / 2);
35
+ for (let i = 0; i < h.length; i += 2) {
36
+ out[i / 2] = parseInt(h.slice(i, i + 2), 16);
37
+ }
38
+ return out;
39
+ }
40
+ function toHex(bytes) {
41
+ return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
42
+ }
43
+ /**
44
+ * Serialize the super-parent RLE runs per TxHeader.writeDataStream.
45
+ *
46
+ * Consecutive equal hashes are coalesced into (count: MiniByte, hash) runs.
47
+ * A fresh candidate with all-distinct parents serializes as 32 runs.
48
+ */
49
+ function serializeSuperParents(superParents) {
50
+ if (superParents.length !== constants_js_1.CASCADE_LEVELS) {
51
+ throw new Error(`superParents must have ${constants_js_1.CASCADE_LEVELS} entries, got ${superParents.length}`);
52
+ }
53
+ const parts = [];
54
+ let runHash = superParents[0];
55
+ let runCount = 1;
56
+ for (let i = 1; i < superParents.length; i++) {
57
+ if (superParents[i] === runHash) {
58
+ runCount++;
59
+ }
60
+ else {
61
+ parts.push(new Uint8Array([runCount]));
62
+ parts.push((0, core_2.writeHashToStream)(hexToBytes(runHash)));
63
+ runHash = superParents[i];
64
+ runCount = 1;
65
+ }
66
+ }
67
+ parts.push(new Uint8Array([runCount]));
68
+ parts.push((0, core_2.writeHashToStream)(hexToBytes(runHash)));
69
+ return (0, core_2.concat)(...parts);
70
+ }
71
+ /**
72
+ * Build the empty burn transaction bytes (TxBody.writeDataStream fields 5-6).
73
+ *
74
+ * Equivalent to serializeTransaction({ linkHash: [0x00], inputs: [], outputs: [],
75
+ * state: [] }): 0 inputs, 0 outputs, 0 state, linkHash = ZERO_TXPOWID (1 byte).
76
+ */
77
+ function buildEmptyBurnTxBytes() {
78
+ return (0, core_2.concat)((0, core_2.writeMiniNumber)(0n, 0), (0, core_2.writeMiniNumber)(0n, 0), (0, core_2.writeMiniNumber)(0n, 0), (0, core_2.writeHashToStream)(new Uint8Array([0x00])));
79
+ }
80
+ /**
81
+ * Build the empty burn witness bytes (TxBody.writeDataStream field 6).
82
+ * 0 signatures, 0 coinproofs, 0 scriptproofs.
83
+ */
84
+ function buildEmptyBurnWitnessBytes() {
85
+ return (0, core_2.concat)((0, core_2.writeMiniNumber)(0n, 0), (0, core_2.writeMiniNumber)(0n, 0), (0, core_2.writeMiniNumber)(0n, 0));
86
+ }
87
+ /**
88
+ * Build the empty transaction bytes (TxBody.writeDataStream field 3).
89
+ * 0 inputs, 0 outputs, 0 state, linkHash = ZERO_TXPOWID (1 byte).
90
+ */
91
+ function buildEmptyTransactionBytes() {
92
+ return (0, core_2.concat)((0, core_2.writeMiniNumber)(0n, 0), (0, core_2.writeMiniNumber)(0n, 0), (0, core_2.writeMiniNumber)(0n, 0), (0, core_2.writeHashToStream)(new Uint8Array([0x00])));
93
+ }
94
+ /**
95
+ * Build the empty witness bytes (TxBody.writeDataStream field 4).
96
+ * 0 signatures, 0 coinproofs, 0 scriptproofs.
97
+ */
98
+ function buildEmptyWitnessBytes() {
99
+ return (0, core_2.concat)((0, core_2.writeMiniNumber)(0n, 0), (0, core_2.writeMiniNumber)(0n, 0), (0, core_2.writeMiniNumber)(0n, 0));
100
+ }
101
+ /**
102
+ * Build the serialized TxBody for a fresh block candidate.
103
+ *
104
+ * Mirrors TxBody.writeDataStream with an empty transaction and witness (the
105
+ * same shape Minima's MINEPULSE automine uses for block candidates):
106
+ * mPRNG | mTxnDifficulty | mTransaction | mWitness |
107
+ * mBurnTransaction | mBurnWitness | mTxPowIDList
108
+ *
109
+ * @param prng 32-byte PRNG (deterministic for tests; random otherwise).
110
+ * @param txnDifficulty Transaction difficulty (32-byte hex). For a block
111
+ * candidate this is typically the block difficulty.
112
+ */
113
+ function buildEmptyBlockBody(prng, txnDifficulty) {
114
+ return (0, core_2.concat)((0, core_2.writeHashToStream)(prng), (0, core_2.writeMiniData)(hexToBytes(txnDifficulty)), buildEmptyTransactionBytes(), buildEmptyWitnessBytes(), buildEmptyBurnTxBytes(), buildEmptyBurnWitnessBytes(), (0, core_2.writeMiniNumber)(0n, 0));
115
+ }
116
+ /**
117
+ * Assemble the complete Minima TxPoW wire format:
118
+ * TxHeader | 0x01 (hasBody) | TxBody
119
+ *
120
+ * This is the representation required for network submission of a genuine L1
121
+ * block candidate. A mined header alone is NOT sufficient.
122
+ *
123
+ * @param headerBytes Serialized TxHeader bytes (with the winning nonce).
124
+ * @param bodyBytes Serialized TxBody bytes.
125
+ */
126
+ function assembleTxPoWEnvelope(headerBytes, bodyBytes) {
127
+ return (0, core_2.concat)(headerBytes, new Uint8Array([0x01]), bodyBytes);
128
+ }
129
+ /**
130
+ * Build the TxHeader tail (everything after the nonce field) for a block
131
+ * candidate with the given customHash commitment.
132
+ *
133
+ * Field order (TxHeader.writeDataStream):
134
+ * mNonce | mChainID | mTimeMilli | mBlockNumber | mBlockDifficulty |
135
+ * super-parents RLE | mMMRRoot | mMMRTotal | mMagic | mCustomHash | mTxBodyHash
136
+ *
137
+ * @param template The current Minima work template.
138
+ * @param customHash The action commitment (32-byte hex) to place in mCustomHash.
139
+ * @param txBodyHash SHA3-256 of the serialized TxBody (32-byte hex).
140
+ */
141
+ function buildBlockHeaderTail(template, customHash, txBodyHash) {
142
+ return (0, core_2.concat)((0, core_2.writeMiniData)(hexToBytes(template.chainId)), (0, core_2.writeMiniNumber)(template.timeMilli, 0), (0, core_2.writeMiniNumber)(template.blockNumber, 0), (0, core_2.writeMiniData)(hexToBytes(template.blockDifficulty)), serializeSuperParents(template.superParents), (0, core_2.writeHashToStream)(hexToBytes(template.mmrRoot)), (0, core_2.writeMiniNumber)(template.mmrTotal, 0), hexToBytes(template.magic), (0, core_2.writeHashToStream)(hexToBytes(customHash)), (0, core_2.writeHashToStream)(hexToBytes(txBodyHash)));
143
+ }
144
+ /**
145
+ * Compute the TxPoW ID for a mined block-candidate header.
146
+ * txpowId = SHA3-256(serialized TxHeader).
147
+ */
148
+ function computeBlockCandidateId(headerBytes) {
149
+ return (0, core_1.sha3_256)(headerBytes);
150
+ }
151
+ /**
152
+ * Check whether a txpowId beats the block target (i.e. is a genuine Minima block).
153
+ * valid = txpowId < blockDifficulty (big-endian 256-bit comparison).
154
+ */
155
+ function isBlockWinner(txpowId, blockDifficulty) {
156
+ const target = hexToBytes(blockDifficulty);
157
+ for (let i = 0; i < 32; i++) {
158
+ if (txpowId[i] < target[i])
159
+ return true;
160
+ if (txpowId[i] > target[i])
161
+ return false;
162
+ }
163
+ return false;
164
+ }
165
+ /** Java BigInteger.bitLength() for non-negative values. bitLength(0) = 0. */
166
+ function bigIntBitLength(x) {
167
+ if (x <= 0n)
168
+ return 0;
169
+ let bits = 0;
170
+ let v = x;
171
+ while (v > 0n) {
172
+ v >>= 1n;
173
+ bits++;
174
+ }
175
+ return bits;
176
+ }
177
+ function bytesToBigInt(bytes) {
178
+ let v = 0n;
179
+ for (let i = 0; i < bytes.length; i++) {
180
+ v = (v << 8n) | BigInt(bytes[i]);
181
+ }
182
+ return v;
183
+ }
184
+ /**
185
+ * Compute the Minima Super level for a TxPoW ID against a block difficulty,
186
+ * with Minima's exact integer semantics.
187
+ *
188
+ * From TxPoW.calculateTXPOWID() / getSuperLevel():
189
+ * quot = blockDifficulty / txpowId (unsigned BigInteger division)
190
+ * super = quot.bitLength() - 1 (floor(log2(quot)))
191
+ * if super >= MINIMA_CASCADE_LEVELS (32) → clamp to 31
192
+ *
193
+ * When the TxPoW is NOT a block (txpowId >= blockDifficulty), quot = 0,
194
+ * bitLength(0) = 0, so super = -1.
195
+ *
196
+ * Result:
197
+ * -1 — not a Minima block
198
+ * 0 — ordinary/base Minima block (Super-0)
199
+ * 1..31 — Super-1 … Super-31 (stronger blocks; 31 is the maximum represented)
200
+ *
201
+ * @param txpowId SHA3-256(header), 32 bytes.
202
+ * @param blockDifficulty 32-byte hex block difficulty target.
203
+ */
204
+ function computeSuperLevel(txpowId, blockDifficulty) {
205
+ const diffBigInt = bytesToBigInt(hexToBytes(blockDifficulty));
206
+ const idBigInt = bytesToBigInt(txpowId);
207
+ // Not a block: quot = 0 → super = -1
208
+ if (idBigInt >= diffBigInt)
209
+ return -1;
210
+ const quot = diffBigInt / idBigInt;
211
+ let superLevel = bigIntBitLength(quot) - 1;
212
+ // Clamp to the maximum represented Super level, exactly as Minima does.
213
+ if (superLevel >= constants_js_1.CASCADE_LEVELS) {
214
+ superLevel = constants_js_1.CASCADE_LEVELS - 1;
215
+ }
216
+ return superLevel;
217
+ }
218
+ /**
219
+ * Default staleness policy: a template is "current enough" for admission if it
220
+ * was captured within the window, and "current" for L1 broadcast if it matches
221
+ * the latest template id.
222
+ */
223
+ function templateFreshness(template, latest, options) {
224
+ const now = options?.now ?? Date.now();
225
+ const windowMs = options?.admissionWindowMs ?? 5 * 60 * 1000;
226
+ const age = now - template.capturedAt;
227
+ const admissionValid = age >= 0 && age <= windowMs;
228
+ const broadcastable = latest !== null && template.templateId === latest.templateId;
229
+ return { admissionValid, broadcastable };
230
+ }
231
+ /**
232
+ * Reconstruct the complete Minima TxPoW envelope for a proof.
233
+ *
234
+ * Rebuilds the empty block TxBody deterministically, recomputes the body hash,
235
+ * and reassembles header | 0x01 | body. Used by verification to confirm the
236
+ * proof corresponds to a complete, Minima-serializable candidate.
237
+ *
238
+ * @param proofTemplate The template the proof was mined against.
239
+ * @param headerBytes The mined TxHeader bytes.
240
+ * @param prng The PRNG used when the proof was mined (32 bytes).
241
+ */
242
+ function reconstructTxPoWEnvelope(proofTemplate, headerBytes, prng) {
243
+ const body = buildEmptyBlockBody(prng, proofTemplate.blockDifficulty);
244
+ const bodyHash = toHex((0, core_1.sha3_256)(body));
245
+ const envelope = assembleTxPoWEnvelope(headerBytes, body);
246
+ return { envelope, bodyHash };
247
+ }
@@ -0,0 +1,224 @@
1
+ /**
2
+ * admission/types.ts — Machine Work Admission core types.
3
+ *
4
+ * Machine Work Admission lets a receiver require a sender to perform bounded
5
+ * computational work before scarce machine resources are allocated. The work
6
+ * searches the nonce space of a real current Minima block candidate, so the
7
+ * same hashes that admit the machine action also search for Minima L1 blocks.
8
+ *
9
+ * The three distinct concepts:
10
+ * - WorkChallenge — the receiver-controlled admission requirement
11
+ * - MachineWorkAction — the domain-separated application action commitment
12
+ * - MachineWorkAdmissionProof — the mined result
13
+ *
14
+ * The TxPoW package knows only "there is an application action represented by
15
+ * canonical bytes". It does NOT know about negotiation, compute, storage, or
16
+ * any particular Edge resource. Domain-specific packages supply the action.
17
+ */
18
+ /** Current Machine Work Admission protocol version. */
19
+ export declare const MACHINE_WORK_ADMISSION_VERSION = 1;
20
+ /** Canonical protocol domain prefix for the commitment hash. */
21
+ export declare const MACHINE_WORK_DOMAIN = "totem.machine-work-admission";
22
+ /**
23
+ * The receiver controls the admission requirement.
24
+ *
25
+ * A challenge must be unique enough to prevent useful pre-mining, must expire,
26
+ * must bind to the intended receiver, and must bind to an application domain.
27
+ * `target` is an absolute cryptographic target: verification is `hash < target`.
28
+ */
29
+ export interface WorkChallenge {
30
+ /** Protocol version. */
31
+ version: number;
32
+ /** Unique challenge identifier (receiver-generated, prevents pre-mining). */
33
+ challengeId: string;
34
+ /** The intended receiver this challenge is bound to. */
35
+ recipient: string;
36
+ /** Application domain (e.g. "totem.negotiation.proposal"). Open-ended. */
37
+ domain: string;
38
+ /** Absolute 32-byte cryptographic target (big-endian 256-bit). */
39
+ target: string;
40
+ /** Receiver-generated random nonce to prevent pre-mining. */
41
+ nonce: string;
42
+ /** Epoch milliseconds when the challenge was issued. */
43
+ issuedAt: number;
44
+ /** Epoch milliseconds after which the challenge is invalid. */
45
+ expiresAt: number;
46
+ /** Optional network identifier (e.g. "mainnet", "testnet"). */
47
+ network?: string;
48
+ }
49
+ /**
50
+ * The application action, represented in a generic domain-separated form.
51
+ *
52
+ * Only a commitment to this action enters the TxPoW header — never the
53
+ * application payload itself. The application remains off-chain.
54
+ */
55
+ export interface MachineWorkAction {
56
+ /** Protocol version. */
57
+ version: number;
58
+ /** Application domain (e.g. "totem.compute.reserve"). Open-ended. */
59
+ domain: string;
60
+ /** The sender performing the work. */
61
+ sender: string;
62
+ /** The intended recipient. */
63
+ recipient: string;
64
+ /** Unique action identifier. */
65
+ actionId: string;
66
+ /** SHA3-256 hex commitment to the application payload (off-chain). */
67
+ payloadHash: string;
68
+ /** Optional domain-specific context (canonicalized into the commitment). */
69
+ context?: Record<string, string>;
70
+ }
71
+ /**
72
+ * A Minima block-candidate work template.
73
+ *
74
+ * This is the chain state a candidate is mined against. It is structurally
75
+ * capable of becoming a legitimate Minima block: block number, block
76
+ * difficulty, super-parents, MMR root/total, magic, and time are all taken
77
+ * from the current chain tip (see TxPoWGenerator.generateTxPoW in Minima).
78
+ */
79
+ export interface MinimaWorkTemplate {
80
+ /** Chain ID (MAIN_NET = 0x00). */
81
+ chainId: string;
82
+ /** Block number = current tip + 1. */
83
+ blockNumber: bigint;
84
+ /** Current block difficulty target (32-byte hex). */
85
+ blockDifficulty: string;
86
+ /** Super-parent hashes at each cascade level (RLE-serialized). */
87
+ superParents: string[];
88
+ /** Current MMR root (32-byte hex). */
89
+ mmrRoot: string;
90
+ /** Current MMR total (sum of all coins). */
91
+ mmrTotal: bigint;
92
+ /** Serialized Magic struct (hex). */
93
+ magic: string;
94
+ /** Candidate timestamp in epoch milliseconds. */
95
+ timeMilli: bigint;
96
+ /** Template identifier (e.g. tip txpowId) for staleness checks. */
97
+ templateId: string;
98
+ /** Epoch milliseconds when the template was captured. */
99
+ capturedAt: number;
100
+ }
101
+ /**
102
+ * Provider abstraction for the current Minima block-candidate template.
103
+ *
104
+ * The TxPoW package remains transport/node-client agnostic: callers inject a
105
+ * provider that fetches the current template from a Minima node, Axia, or a
106
+ * test fixture.
107
+ *
108
+ * `MinimaWorkRelay` is the preferred long-term relay boundary. The legacy
109
+ * `broadcastBlockCandidate` callback is retained as a compatibility/fallback
110
+ * path only — new consumers should use `relay` via `MinimaWorkRelay` and not
111
+ * build around the lossy `candidate: unknown` shape.
112
+ */
113
+ export interface MinimaWorkTemplateProvider {
114
+ /** Fetch the current block-candidate template. */
115
+ getCurrentTemplate(): Promise<MinimaWorkTemplate>;
116
+ /** Optional: fetch the latest template for freshness checks. Falls back to getCurrentTemplate. */
117
+ getLatestTemplate?(): Promise<MinimaWorkTemplate>;
118
+ /** Optional: validate a template before mining against it. */
119
+ validateTemplate?(template: MinimaWorkTemplate): Promise<boolean>;
120
+ /**
121
+ * @deprecated Prefer `MinimaWorkRelay.submitBlock` (complete envelope).
122
+ * Retained for compatibility; only invoked for genuine Minima blocks
123
+ * (Super-0 … Super-31) when no relay is configured.
124
+ */
125
+ broadcastBlockCandidate?(candidate: MachineWorkAdmissionProof): Promise<void>;
126
+ }
127
+ /**
128
+ * Relay boundary for a complete Minima TxPoW envelope.
129
+ *
130
+ * Keeps Minima networking outside core mining logic. A future
131
+ * @totemsdk/minima-rpc or chain-provider adapter may implement this port.
132
+ * Duplicate relay attempts must be safe/idempotent at the integration boundary.
133
+ */
134
+ export interface MinimaWorkRelay {
135
+ /** Submit a complete Minima TxPoW envelope for block relay. */
136
+ submitBlock(envelope: Uint8Array): Promise<void>;
137
+ }
138
+ /**
139
+ * The mined Machine Work Admission proof.
140
+ *
141
+ * Reuses the existing TxPoW types where possible:
142
+ * - `txpow` — serialized TxHeader bytes (SHA3-256 of these is `txpowId`)
143
+ * - `txpowEnvelope` — the COMPLETE Minima TxPoW wire format
144
+ * (header | 0x01 hasBody | body), required for network
145
+ * submission of a genuine Minima block
146
+ * - `txpowId` — SHA3-256(header)
147
+ *
148
+ * `qualifiesAsMinimaBlock`, `isBlock`, and `superLevel` are DERIVED METADATA
149
+ * recorded at mining time. They are never trusted by verification —
150
+ * verification recomputes all of them from the re-derived txpowId and the
151
+ * template's block difficulty.
152
+ */
153
+ export interface MachineWorkAdmissionProof {
154
+ /** Protocol version. */
155
+ version: number;
156
+ /** Hex commitment placed in the TxPoW header's customHash field. */
157
+ actionCommitment: string;
158
+ /** The challenge this proof was mined against. */
159
+ challengeId: string;
160
+ /** The admission target (32-byte hex) the proof satisfies. */
161
+ admissionTarget: string;
162
+ /** Serialized TxHeader bytes (SHA3-256 of these is the TxPoW ID). */
163
+ txpow: string;
164
+ /** Complete Minima TxPoW envelope (header | 0x01 | body) for block relay. */
165
+ txpowEnvelope: string;
166
+ /** SHA3-256(header) — the canonical TxPoW ID. */
167
+ txpowId: string;
168
+ /** The winning nonce. */
169
+ nonce: string;
170
+ /** Epoch milliseconds when the proof was mined. */
171
+ minedAt: number;
172
+ /** Always true for a valid admission proof. */
173
+ qualifiesForAdmission: true;
174
+ /**
175
+ * DERIVED METADATA: true when the mined hash also beats the block difficulty
176
+ * encoded by the candidate template (i.e. a genuine Minima block). Never
177
+ * trusted by verification — it is recomputed from the re-derived txpowId.
178
+ */
179
+ qualifiesAsMinimaBlock: boolean;
180
+ /**
181
+ * DERIVED METADATA: Minima Super level (-1 = not a block, 0..31 = block
182
+ * strength). Never trusted by verification.
183
+ */
184
+ superLevel: number;
185
+ /** DERIVED METADATA: superLevel >= 0. Never trusted by verification. */
186
+ isBlock: boolean;
187
+ /** Template the proof was mined against (for staleness policy). */
188
+ template: MinimaWorkTemplate;
189
+ }
190
+ /**
191
+ * Result of verifying a Machine Work Admission proof.
192
+ *
193
+ * Three distinct claims, never to be confused:
194
+ * A. `valid` — the hash satisfies the challenge target (admission proof).
195
+ * B. `superLevel` / `isBlock` — the hash ALSO satisfies the block difficulty
196
+ * encoded by the candidate template, yielding an exact Minima Super level.
197
+ * C. `broadcastable` — the candidate still corresponds to sufficiently
198
+ * current live Minima state AND can be submitted through the relay.
199
+ *
200
+ * A stale candidate may remain `valid = true` (and `superLevel >= 0`) while
201
+ * `broadcastable = false`.
202
+ *
203
+ * `superLevel === -1 ⇔ isBlock === false`, and
204
+ * `superLevel >= 0 ⇔ isBlock === true`. Verification recomputes these — it
205
+ * never trusts sender-supplied `isBlock`/`superLevel` metadata.
206
+ */
207
+ export interface WorkAdmissionVerification {
208
+ /** Level A: the hash satisfies the challenge target. */
209
+ valid: boolean;
210
+ reason?: string;
211
+ /**
212
+ * Level B: exact Minima Super level of the candidate hash.
213
+ * -1 = not a Minima block; 0..31 = Super-0 … Super-31 block strength.
214
+ */
215
+ superLevel?: number;
216
+ /** Level B: superLevel >= 0 (a genuine Minima block). */
217
+ isBlock?: boolean;
218
+ /**
219
+ * Level C: isBlock AND the template is current AND a live template provider
220
+ * was supplied. Undefined in offline mode (no provider) — offline
221
+ * verification must NOT claim Minima block contribution.
222
+ */
223
+ broadcastable?: boolean;
224
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ /**
3
+ * admission/types.ts — Machine Work Admission core types.
4
+ *
5
+ * Machine Work Admission lets a receiver require a sender to perform bounded
6
+ * computational work before scarce machine resources are allocated. The work
7
+ * searches the nonce space of a real current Minima block candidate, so the
8
+ * same hashes that admit the machine action also search for Minima L1 blocks.
9
+ *
10
+ * The three distinct concepts:
11
+ * - WorkChallenge — the receiver-controlled admission requirement
12
+ * - MachineWorkAction — the domain-separated application action commitment
13
+ * - MachineWorkAdmissionProof — the mined result
14
+ *
15
+ * The TxPoW package knows only "there is an application action represented by
16
+ * canonical bytes". It does NOT know about negotiation, compute, storage, or
17
+ * any particular Edge resource. Domain-specific packages supply the action.
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.MACHINE_WORK_DOMAIN = exports.MACHINE_WORK_ADMISSION_VERSION = void 0;
21
+ /** Current Machine Work Admission protocol version. */
22
+ exports.MACHINE_WORK_ADMISSION_VERSION = 1;
23
+ /** Canonical protocol domain prefix for the commitment hash. */
24
+ exports.MACHINE_WORK_DOMAIN = 'totem.machine-work-admission';
@@ -0,0 +1,50 @@
1
+ /**
2
+ * admission/verify.ts — Machine Work Admission verification.
3
+ *
4
+ * Verification NEVER trusts sender-reported hardware speed or self-reported
5
+ * block metadata (`isBlock`, `superLevel`, `qualifiesAsMinimaBlock`,
6
+ * `broadcastable`). It recomputes the canonical action commitment, re-derives
7
+ * the TxPoW ID from the mined header, and checks `txpowId < challenge.target`.
8
+ * It also checks challenge validity (expiry, recipient, domain) and template
9
+ * freshness.
10
+ *
11
+ * Three distinct claims, never to be confused:
12
+ * A. valid — the hash satisfies the challenge target.
13
+ * B. superLevel/isBlock — the exact Minima Super level (-1 or 0..31)
14
+ * computed from blockDifficulty / txpowId.
15
+ * C. broadcastable — isBlock AND the template is current AND a live
16
+ * template provider was supplied.
17
+ *
18
+ * A stale candidate may remain valid = true (and superLevel >= 0) while
19
+ * broadcastable = false. Offline verification (no provider) must NOT claim
20
+ * Minima block contribution — `broadcastable` is left undefined.
21
+ */
22
+ import { type MachineWorkAction, type MachineWorkAdmissionProof, type MinimaWorkTemplate, type MinimaWorkTemplateProvider, type WorkChallenge, type WorkAdmissionVerification } from './types.js';
23
+ export interface VerifyWorkAdmissionOptions {
24
+ /** Override the current time for deterministic testing. */
25
+ now?: number;
26
+ /** Staleness window (ms) within which a template is acceptable for admission. */
27
+ admissionWindowMs?: number;
28
+ /** The latest template, for broadcastability checks. */
29
+ latestTemplate?: MinimaWorkTemplate | null;
30
+ }
31
+ /**
32
+ * Verify a Machine Work Admission proof.
33
+ *
34
+ * The admission target is taken from the validated challenge — never from the
35
+ * proof. `proof.qualifiesAsMinimaBlock`, `proof.superLevel`, and
36
+ * `proof.isBlock` are treated as derived metadata and are NOT trusted; the
37
+ * Super level is recomputed from the re-derived txpowId and the template's
38
+ * block difficulty.
39
+ *
40
+ * @param action The application action the proof claims to commit.
41
+ * @param challenge The challenge the proof claims to satisfy.
42
+ * @param proof The mined proof.
43
+ * @param templateProvider Optional live provider. When supplied, template
44
+ * freshness and broadcastability are checked and
45
+ * `broadcastable` is set. When omitted, verification
46
+ * runs in offline mode and does NOT claim Minima
47
+ * block contribution (`broadcastable` is undefined).
48
+ * @param options Verification options.
49
+ */
50
+ export declare function verifyWorkAdmission(action: MachineWorkAction, challenge: WorkChallenge, proof: MachineWorkAdmissionProof, templateProvider?: MinimaWorkTemplateProvider, options?: VerifyWorkAdmissionOptions): Promise<WorkAdmissionVerification>;