@totemsdk/txpow 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -0
- package/dist/admission/challenge.d.ts +66 -0
- package/dist/admission/challenge.js +155 -0
- package/dist/admission/commitment.d.ts +34 -0
- package/dist/admission/commitment.js +73 -0
- package/dist/admission/index.d.ts +14 -0
- package/dist/admission/index.js +42 -0
- package/dist/admission/mine.d.ts +60 -0
- package/dist/admission/mine.js +146 -0
- package/dist/admission/template.d.ts +138 -0
- package/dist/admission/template.js +247 -0
- package/dist/admission/types.d.ts +224 -0
- package/dist/admission/types.js +24 -0
- package/dist/admission/verify.d.ts +50 -0
- package/dist/admission/verify.js +144 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +33 -1
- package/dist/mine.d.ts +24 -0
- package/dist/mine.js +30 -8
- package/package.json +9 -4
|
@@ -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>;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* admission/verify.ts — Machine Work Admission verification.
|
|
4
|
+
*
|
|
5
|
+
* Verification NEVER trusts sender-reported hardware speed or self-reported
|
|
6
|
+
* block metadata (`isBlock`, `superLevel`, `qualifiesAsMinimaBlock`,
|
|
7
|
+
* `broadcastable`). It recomputes the canonical action commitment, re-derives
|
|
8
|
+
* the TxPoW ID from the mined header, and checks `txpowId < challenge.target`.
|
|
9
|
+
* It also checks challenge validity (expiry, recipient, domain) and template
|
|
10
|
+
* freshness.
|
|
11
|
+
*
|
|
12
|
+
* Three distinct claims, never to be confused:
|
|
13
|
+
* A. valid — the hash satisfies the challenge target.
|
|
14
|
+
* B. superLevel/isBlock — the exact Minima Super level (-1 or 0..31)
|
|
15
|
+
* computed from blockDifficulty / txpowId.
|
|
16
|
+
* C. broadcastable — isBlock AND the template is current AND a live
|
|
17
|
+
* template provider was supplied.
|
|
18
|
+
*
|
|
19
|
+
* A stale candidate may remain valid = true (and superLevel >= 0) while
|
|
20
|
+
* broadcastable = false. Offline verification (no provider) must NOT claim
|
|
21
|
+
* Minima block contribution — `broadcastable` is left undefined.
|
|
22
|
+
*/
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.verifyWorkAdmission = verifyWorkAdmission;
|
|
25
|
+
const core_1 = require("@totemsdk/core");
|
|
26
|
+
const commitment_js_1 = require("./commitment.js");
|
|
27
|
+
const challenge_js_1 = require("./challenge.js");
|
|
28
|
+
const template_js_1 = require("./template.js");
|
|
29
|
+
const types_js_1 = require("./types.js");
|
|
30
|
+
function hexToBytes(hex) {
|
|
31
|
+
const h = hex.startsWith('0x') ? hex.slice(2) : hex;
|
|
32
|
+
const out = new Uint8Array(h.length / 2);
|
|
33
|
+
for (let i = 0; i < h.length; i += 2) {
|
|
34
|
+
out[i / 2] = parseInt(h.slice(i, i + 2), 16);
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
/** Big-endian 256-bit comparison: true if a < b. */
|
|
39
|
+
function isLessThan(a, b) {
|
|
40
|
+
for (let i = 0; i < 32; i++) {
|
|
41
|
+
if (a[i] < b[i])
|
|
42
|
+
return true;
|
|
43
|
+
if (a[i] > b[i])
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Verify a Machine Work Admission proof.
|
|
50
|
+
*
|
|
51
|
+
* The admission target is taken from the validated challenge — never from the
|
|
52
|
+
* proof. `proof.qualifiesAsMinimaBlock`, `proof.superLevel`, and
|
|
53
|
+
* `proof.isBlock` are treated as derived metadata and are NOT trusted; the
|
|
54
|
+
* Super level is recomputed from the re-derived txpowId and the template's
|
|
55
|
+
* block difficulty.
|
|
56
|
+
*
|
|
57
|
+
* @param action The application action the proof claims to commit.
|
|
58
|
+
* @param challenge The challenge the proof claims to satisfy.
|
|
59
|
+
* @param proof The mined proof.
|
|
60
|
+
* @param templateProvider Optional live provider. When supplied, template
|
|
61
|
+
* freshness and broadcastability are checked and
|
|
62
|
+
* `broadcastable` is set. When omitted, verification
|
|
63
|
+
* runs in offline mode and does NOT claim Minima
|
|
64
|
+
* block contribution (`broadcastable` is undefined).
|
|
65
|
+
* @param options Verification options.
|
|
66
|
+
*/
|
|
67
|
+
async function verifyWorkAdmission(action, challenge, proof, templateProvider, options) {
|
|
68
|
+
// 1. Structural checks
|
|
69
|
+
if (!proof || typeof proof !== 'object') {
|
|
70
|
+
return { valid: false, reason: 'proof is not an object' };
|
|
71
|
+
}
|
|
72
|
+
if (proof.version !== types_js_1.MACHINE_WORK_ADMISSION_VERSION) {
|
|
73
|
+
return { valid: false, reason: `unsupported proof version ${proof.version}` };
|
|
74
|
+
}
|
|
75
|
+
if (proof.challengeId !== challenge.challengeId) {
|
|
76
|
+
return { valid: false, reason: 'proof challengeId does not match challenge' };
|
|
77
|
+
}
|
|
78
|
+
if (proof.qualifiesForAdmission !== true) {
|
|
79
|
+
return { valid: false, reason: 'proof does not claim admission' };
|
|
80
|
+
}
|
|
81
|
+
// Target manipulation guard: the proof must have been mined against the
|
|
82
|
+
// challenge's exact target. A sender must not be able to mine against a
|
|
83
|
+
// trivially easy target and present it as satisfying a harder challenge.
|
|
84
|
+
if (proof.admissionTarget !== challenge.target) {
|
|
85
|
+
return { valid: false, reason: 'proof admissionTarget does not match challenge target' };
|
|
86
|
+
}
|
|
87
|
+
// 2. Challenge validity (expiry, recipient, domain)
|
|
88
|
+
const challengeCheck = (0, challenge_js_1.validateWorkChallenge)(challenge, {
|
|
89
|
+
recipient: action.recipient,
|
|
90
|
+
domain: action.domain,
|
|
91
|
+
now: options?.now,
|
|
92
|
+
});
|
|
93
|
+
if (!challengeCheck.valid) {
|
|
94
|
+
return { valid: false, reason: challengeCheck.reason };
|
|
95
|
+
}
|
|
96
|
+
// 3. Recompute the canonical commitment — must match the proof
|
|
97
|
+
const expectedCommitment = (0, commitment_js_1.computeActionCommitment)(action, challenge);
|
|
98
|
+
if (expectedCommitment !== proof.actionCommitment) {
|
|
99
|
+
return { valid: false, reason: 'action commitment mismatch' };
|
|
100
|
+
}
|
|
101
|
+
// 4. Re-derive the TxPoW ID from the mined header and check the target
|
|
102
|
+
const headerBytes = hexToBytes(proof.txpow);
|
|
103
|
+
const txpowId = (0, core_1.sha3_256)(headerBytes);
|
|
104
|
+
const txpowIdHex = toHex(txpowId);
|
|
105
|
+
if (txpowIdHex !== proof.txpowId) {
|
|
106
|
+
return { valid: false, reason: 'txpowId does not match mined header' };
|
|
107
|
+
}
|
|
108
|
+
const admissionTarget = hexToBytes(proof.admissionTarget);
|
|
109
|
+
if (!isLessThan(txpowId, admissionTarget)) {
|
|
110
|
+
return { valid: false, reason: 'txpowId does not beat admission target' };
|
|
111
|
+
}
|
|
112
|
+
// 5. Template freshness for admission
|
|
113
|
+
const freshness = (0, template_js_1.templateFreshness)(proof.template, options?.latestTemplate ?? null, {
|
|
114
|
+
admissionWindowMs: options?.admissionWindowMs,
|
|
115
|
+
now: options?.now,
|
|
116
|
+
});
|
|
117
|
+
if (!freshness.admissionValid) {
|
|
118
|
+
return { valid: false, reason: 'proof template is stale for admission' };
|
|
119
|
+
}
|
|
120
|
+
// 6. Level B: independently recompute the exact Minima Super level. Never
|
|
121
|
+
// trust proof.superLevel / proof.isBlock / proof.qualifiesAsMinimaBlock.
|
|
122
|
+
const superLevel = (0, template_js_1.computeSuperLevel)(txpowId, proof.template.blockDifficulty);
|
|
123
|
+
const isBlock = superLevel >= 0;
|
|
124
|
+
// 7. Level C: broadcastability requires a live template provider AND a
|
|
125
|
+
// current template. Offline mode leaves broadcastable undefined.
|
|
126
|
+
let broadcastable;
|
|
127
|
+
if (templateProvider) {
|
|
128
|
+
let latest;
|
|
129
|
+
if (templateProvider.getLatestTemplate) {
|
|
130
|
+
latest = await templateProvider.getLatestTemplate();
|
|
131
|
+
}
|
|
132
|
+
else if (options?.latestTemplate) {
|
|
133
|
+
latest = options.latestTemplate;
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
latest = await templateProvider.getCurrentTemplate();
|
|
137
|
+
}
|
|
138
|
+
broadcastable = isBlock && latest.templateId === proof.template.templateId;
|
|
139
|
+
}
|
|
140
|
+
return { valid: true, superLevel, isBlock, broadcastable };
|
|
141
|
+
}
|
|
142
|
+
function toHex(bytes) {
|
|
143
|
+
return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
144
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -20,8 +20,9 @@
|
|
|
20
20
|
export { serializeTxHeader, serializeTxBody, serializeTxPoW, computeTxPoWId, type TxHeaderOptions, type TxBodyOptions, type TxPoWOptions, } from './serialization.js';
|
|
21
21
|
export { MAX_HASH, ZERO_HASH, TX_POW_MIN_DIFFICULTY, CASCADE_LEVELS, MAIN_NET_CHAIN_ID, } from './constants.js';
|
|
22
22
|
export { serializeMagic } from './magic.js';
|
|
23
|
-
export { mineTxPoW, mineTxPoWInProcess, isLessThan, setBrowserWorkerUrl, type MineResult, type MineOptions, } from './mine.js';
|
|
23
|
+
export { mineTxPoW, mineTxPoWInProcess, mineHeaderTail, buildHeaderTail, isLessThan, setBrowserWorkerUrl, type MineResult, type MineOptions, } from './mine.js';
|
|
24
24
|
export { setWasmUrl, getBrowserWasmUrl, isWasmAvailable } from './mine-wasm.js';
|
|
25
25
|
export { fetchTxPowTarget, type TxPowParams } from './difficulty.js';
|
|
26
26
|
export { verifyProofOfWork, verifyTxPoWWork, verifyTxPoWParts, type VerifyResult } from './verify.js';
|
|
27
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';
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* if (!check.valid) drop(check.reason);
|
|
20
20
|
*/
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
-
exports.estimateMiningCost = exports.calibrateHashRate = exports.verifyTxPoWParts = exports.verifyTxPoWWork = exports.verifyProofOfWork = exports.fetchTxPowTarget = exports.isWasmAvailable = exports.getBrowserWasmUrl = exports.setWasmUrl = exports.setBrowserWorkerUrl = exports.isLessThan = 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;
|
|
22
|
+
exports.MAX_CHALLENGE_TTL_MS = exports.DEFAULT_CHALLENGE_TTL_MS = 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.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
23
|
var serialization_js_1 = require("./serialization.js");
|
|
24
24
|
Object.defineProperty(exports, "serializeTxHeader", { enumerable: true, get: function () { return serialization_js_1.serializeTxHeader; } });
|
|
25
25
|
Object.defineProperty(exports, "serializeTxBody", { enumerable: true, get: function () { return serialization_js_1.serializeTxBody; } });
|
|
@@ -36,6 +36,8 @@ Object.defineProperty(exports, "serializeMagic", { enumerable: true, get: functi
|
|
|
36
36
|
var mine_js_1 = require("./mine.js");
|
|
37
37
|
Object.defineProperty(exports, "mineTxPoW", { enumerable: true, get: function () { return mine_js_1.mineTxPoW; } });
|
|
38
38
|
Object.defineProperty(exports, "mineTxPoWInProcess", { enumerable: true, get: function () { return mine_js_1.mineTxPoWInProcess; } });
|
|
39
|
+
Object.defineProperty(exports, "mineHeaderTail", { enumerable: true, get: function () { return mine_js_1.mineHeaderTail; } });
|
|
40
|
+
Object.defineProperty(exports, "buildHeaderTail", { enumerable: true, get: function () { return mine_js_1.buildHeaderTail; } });
|
|
39
41
|
Object.defineProperty(exports, "isLessThan", { enumerable: true, get: function () { return mine_js_1.isLessThan; } });
|
|
40
42
|
Object.defineProperty(exports, "setBrowserWorkerUrl", { enumerable: true, get: function () { return mine_js_1.setBrowserWorkerUrl; } });
|
|
41
43
|
var mine_wasm_js_1 = require("./mine-wasm.js");
|
|
@@ -51,3 +53,33 @@ Object.defineProperty(exports, "verifyTxPoWParts", { enumerable: true, get: func
|
|
|
51
53
|
var calibrate_js_1 = require("./calibrate.js");
|
|
52
54
|
Object.defineProperty(exports, "calibrateHashRate", { enumerable: true, get: function () { return calibrate_js_1.calibrateHashRate; } });
|
|
53
55
|
Object.defineProperty(exports, "estimateMiningCost", { enumerable: true, get: function () { return calibrate_js_1.estimateMiningCost; } });
|
|
56
|
+
// ── Machine Work Admission ──────────────────────────────────────────────────
|
|
57
|
+
// Receiver-controlled computational admission bound to a real Minima block
|
|
58
|
+
// candidate. The same nonce search that admits a machine action also searches
|
|
59
|
+
// for Minima blocks (Super-0 … Super-31).
|
|
60
|
+
var index_js_1 = require("./admission/index.js");
|
|
61
|
+
Object.defineProperty(exports, "createWorkChallenge", { enumerable: true, get: function () { return index_js_1.createWorkChallenge; } });
|
|
62
|
+
Object.defineProperty(exports, "validateWorkChallenge", { enumerable: true, get: function () { return index_js_1.validateWorkChallenge; } });
|
|
63
|
+
Object.defineProperty(exports, "challengeFingerprint", { enumerable: true, get: function () { return index_js_1.challengeFingerprint; } });
|
|
64
|
+
Object.defineProperty(exports, "canonicalChallenge", { enumerable: true, get: function () { return index_js_1.canonicalChallenge; } });
|
|
65
|
+
Object.defineProperty(exports, "computeActionCommitment", { enumerable: true, get: function () { return index_js_1.computeActionCommitment; } });
|
|
66
|
+
Object.defineProperty(exports, "canonicalAction", { enumerable: true, get: function () { return index_js_1.canonicalAction; } });
|
|
67
|
+
Object.defineProperty(exports, "mineWorkAdmission", { enumerable: true, get: function () { return index_js_1.mineWorkAdmission; } });
|
|
68
|
+
Object.defineProperty(exports, "verifyWorkAdmission", { enumerable: true, get: function () { return index_js_1.verifyWorkAdmission; } });
|
|
69
|
+
Object.defineProperty(exports, "buildBlockHeaderTail", { enumerable: true, get: function () { return index_js_1.buildBlockHeaderTail; } });
|
|
70
|
+
Object.defineProperty(exports, "serializeSuperParents", { enumerable: true, get: function () { return index_js_1.serializeSuperParents; } });
|
|
71
|
+
Object.defineProperty(exports, "isBlockWinner", { enumerable: true, get: function () { return index_js_1.isBlockWinner; } });
|
|
72
|
+
Object.defineProperty(exports, "computeSuperLevel", { enumerable: true, get: function () { return index_js_1.computeSuperLevel; } });
|
|
73
|
+
Object.defineProperty(exports, "templateFreshness", { enumerable: true, get: function () { return index_js_1.templateFreshness; } });
|
|
74
|
+
Object.defineProperty(exports, "computeBlockCandidateId", { enumerable: true, get: function () { return index_js_1.computeBlockCandidateId; } });
|
|
75
|
+
Object.defineProperty(exports, "buildEmptyBlockBody", { enumerable: true, get: function () { return index_js_1.buildEmptyBlockBody; } });
|
|
76
|
+
Object.defineProperty(exports, "buildEmptyTransactionBytes", { enumerable: true, get: function () { return index_js_1.buildEmptyTransactionBytes; } });
|
|
77
|
+
Object.defineProperty(exports, "buildEmptyWitnessBytes", { enumerable: true, get: function () { return index_js_1.buildEmptyWitnessBytes; } });
|
|
78
|
+
Object.defineProperty(exports, "buildEmptyBurnTxBytes", { enumerable: true, get: function () { return index_js_1.buildEmptyBurnTxBytes; } });
|
|
79
|
+
Object.defineProperty(exports, "buildEmptyBurnWitnessBytes", { enumerable: true, get: function () { return index_js_1.buildEmptyBurnWitnessBytes; } });
|
|
80
|
+
Object.defineProperty(exports, "assembleTxPoWEnvelope", { enumerable: true, get: function () { return index_js_1.assembleTxPoWEnvelope; } });
|
|
81
|
+
Object.defineProperty(exports, "reconstructTxPoWEnvelope", { enumerable: true, get: function () { return index_js_1.reconstructTxPoWEnvelope; } });
|
|
82
|
+
Object.defineProperty(exports, "MACHINE_WORK_ADMISSION_VERSION", { enumerable: true, get: function () { return index_js_1.MACHINE_WORK_ADMISSION_VERSION; } });
|
|
83
|
+
Object.defineProperty(exports, "MACHINE_WORK_DOMAIN", { enumerable: true, get: function () { return index_js_1.MACHINE_WORK_DOMAIN; } });
|
|
84
|
+
Object.defineProperty(exports, "DEFAULT_CHALLENGE_TTL_MS", { enumerable: true, get: function () { return index_js_1.DEFAULT_CHALLENGE_TTL_MS; } });
|
|
85
|
+
Object.defineProperty(exports, "MAX_CHALLENGE_TTL_MS", { enumerable: true, get: function () { return index_js_1.MAX_CHALLENGE_TTL_MS; } });
|
package/dist/mine.d.ts
CHANGED
|
@@ -72,6 +72,17 @@ export interface MineOptions {
|
|
|
72
72
|
* Used to check: txpowId < mTxnDifficulty.
|
|
73
73
|
*/
|
|
74
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;
|
|
75
86
|
/**
|
|
76
87
|
* Configure the URL of the browser.worker.js bundle so that `mineTxPoW()`
|
|
77
88
|
* can spawn a Web Worker in browser contexts.
|
|
@@ -84,6 +95,19 @@ export declare function isLessThan(a: Uint8Array, b: Uint8Array): boolean;
|
|
|
84
95
|
* setBrowserWorkerUrl(browser.runtime.getURL('mine-worker.js'));
|
|
85
96
|
*/
|
|
86
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>;
|
|
87
111
|
/**
|
|
88
112
|
* Run the mining loop in the current thread/task.
|
|
89
113
|
* Called directly by the Node.js worker, and by the browser code path.
|
package/dist/mine.js
CHANGED
|
@@ -29,7 +29,9 @@
|
|
|
29
29
|
*/
|
|
30
30
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
31
|
exports.isLessThan = isLessThan;
|
|
32
|
+
exports.buildHeaderTail = buildHeaderTail;
|
|
32
33
|
exports.setBrowserWorkerUrl = setBrowserWorkerUrl;
|
|
34
|
+
exports.mineHeaderTail = mineHeaderTail;
|
|
33
35
|
exports.mineTxPoWInProcess = mineTxPoWInProcess;
|
|
34
36
|
exports.mineTxPoW = mineTxPoW;
|
|
35
37
|
const core_1 = require("@totemsdk/core");
|
|
@@ -70,6 +72,11 @@ function nextNonceBoundary(nonce) {
|
|
|
70
72
|
* Build the "header tail" — the part of TxHeader that follows mNonce.
|
|
71
73
|
*
|
|
72
74
|
* This is computed once at the start of a mine and never changes during it.
|
|
75
|
+
*
|
|
76
|
+
* This is the fresh-transaction header shape (blockNumber=0, MAX_HASH block
|
|
77
|
+
* difficulty, zero super-parents, zero MMR, zero customHash). Block-candidate
|
|
78
|
+
* mining (Machine Work Admission) builds its own tail via
|
|
79
|
+
* `admission/template.ts` with real chain state and a customHash commitment.
|
|
73
80
|
*/
|
|
74
81
|
function buildHeaderTail(txBodyHash, timeMilli) {
|
|
75
82
|
return (0, core_2.concat)((0, core_2.writeMiniData)(constants_js_1.MAIN_NET_CHAIN_ID), (0, core_2.writeMiniNumber)(timeMilli, 0), (0, core_2.writeMiniNumber)(0n, 0), (0, core_2.writeMiniData)(constants_js_1.MAX_HASH), new Uint8Array([constants_js_1.CASCADE_LEVELS]), (0, core_2.writeHashToStream)(constants_js_1.ZERO_HASH), (0, core_2.writeHashToStream)(constants_js_1.ZERO_HASH), (0, core_2.writeMiniNumber)(0n, 0), (0, magic_js_1.serializeMagic)(), (0, core_2.writeHashToStream)(constants_js_1.ZERO_HASH), (0, core_2.writeHashToStream)(txBodyHash));
|
|
@@ -283,19 +290,24 @@ async function mineTxPoWViaNodeWorker(txBodyBytes, txnDifficulty, options) {
|
|
|
283
290
|
// In-process mining loop
|
|
284
291
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
285
292
|
/**
|
|
286
|
-
*
|
|
287
|
-
*
|
|
293
|
+
* Core mining loop over a pre-built header tail.
|
|
294
|
+
*
|
|
295
|
+
* Iterates the nonce in the serialized TxHeader (nonce value at offset 2,
|
|
296
|
+
* followed by `headerTail`) until `SHA3-256(header) < target`. Shared by the
|
|
297
|
+
* transaction miner (`mineTxPoWInProcess`) and the Machine Work Admission
|
|
298
|
+
* miner (`admission/mine.ts`), which supplies its own block-candidate tail.
|
|
299
|
+
*
|
|
300
|
+
* @param headerTail Serialized TxHeader bytes AFTER the nonce field.
|
|
301
|
+
* @param target 32-byte difficulty target (big-endian 256-bit).
|
|
302
|
+
* @param options Chunk size, max iterations, abort signal, timeMilli override.
|
|
288
303
|
*/
|
|
289
|
-
async function
|
|
304
|
+
async function mineHeaderTail(headerTail, target, options) {
|
|
290
305
|
const chunkSize = BigInt(options?.chunkSize ?? 10000);
|
|
291
306
|
const maxIterations = options?.maxIterations !== undefined
|
|
292
307
|
? BigInt(options.maxIterations)
|
|
293
308
|
: undefined;
|
|
294
309
|
const signal = options?.signal;
|
|
295
|
-
const timeMilli = options?.timeMilli ?? BigInt(Date.now());
|
|
296
310
|
const forceJs = options?.forceJs ?? false;
|
|
297
|
-
const bodyHash = (0, core_1.sha3_256)(txBodyBytes);
|
|
298
|
-
const headerTail = buildHeaderTail(bodyHash, timeMilli);
|
|
299
311
|
const useWasm = !forceJs && (await (0, mine_wasm_js_1.isWasmAvailable)());
|
|
300
312
|
const startTime = Date.now();
|
|
301
313
|
let totalIterations = 0n;
|
|
@@ -319,10 +331,10 @@ async function mineTxPoWInProcess(txBodyBytes, txnDifficulty, options) {
|
|
|
319
331
|
let found;
|
|
320
332
|
if (useWasm) {
|
|
321
333
|
found = await (0, mine_wasm_js_1.mineChunkWasm)(headerBuf.slice(), // WASM gets its own copy to avoid aliasing
|
|
322
|
-
2, nonceValueLen,
|
|
334
|
+
2, nonceValueLen, target, nonce, chunkEnd - nonce);
|
|
323
335
|
}
|
|
324
336
|
else {
|
|
325
|
-
found = mineChunkJs(headerBuf, nonceValueLen,
|
|
337
|
+
found = mineChunkJs(headerBuf, nonceValueLen, target, nonce, chunkEnd);
|
|
326
338
|
}
|
|
327
339
|
// ── End mutually exclusive section ───────────────────────────────────────
|
|
328
340
|
if (found !== null) {
|
|
@@ -349,6 +361,16 @@ async function mineTxPoWInProcess(txBodyBytes, txnDifficulty, options) {
|
|
|
349
361
|
});
|
|
350
362
|
}
|
|
351
363
|
}
|
|
364
|
+
/**
|
|
365
|
+
* Run the mining loop in the current thread/task.
|
|
366
|
+
* Called directly by the Node.js worker, and by the browser code path.
|
|
367
|
+
*/
|
|
368
|
+
async function mineTxPoWInProcess(txBodyBytes, txnDifficulty, options) {
|
|
369
|
+
const timeMilli = options?.timeMilli ?? BigInt(Date.now());
|
|
370
|
+
const bodyHash = (0, core_1.sha3_256)(txBodyBytes);
|
|
371
|
+
const headerTail = buildHeaderTail(bodyHash, timeMilli);
|
|
372
|
+
return mineHeaderTail(headerTail, txnDifficulty, options);
|
|
373
|
+
}
|
|
352
374
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
353
375
|
// Public API
|
|
354
376
|
// ─────────────────────────────────────────────────────────────────────────────
|