@miden-sdk/miden-sdk 0.15.0-alpha.4 → 0.15.0-alpha.6
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 +139 -9
- package/dist/mt/Cargo-C9UbiAcT.js +26202 -0
- package/dist/mt/Cargo-C9UbiAcT.js.map +1 -0
- package/dist/{api-types.d.ts → mt/api-types.d.ts} +160 -6
- package/dist/mt/assets/miden_client_web.wasm +0 -0
- package/dist/mt/crates/miden_client_web.d.ts +4821 -0
- package/dist/mt/eager.js +38 -0
- package/dist/mt/eager.js.map +1 -0
- package/dist/{index.d.ts → mt/index.d.ts} +6 -3
- package/dist/mt/index.js +3811 -0
- package/dist/mt/index.js.map +1 -0
- package/dist/{wasm.js → mt/wasm.js} +1 -1
- package/dist/mt/wasm.js.map +1 -0
- package/dist/mt/workerHelpers.js +28 -0
- package/dist/mt/workers/Cargo-C9UbiAcT-Z344cyB1.js +26203 -0
- package/dist/mt/workers/Cargo-C9UbiAcT-Z344cyB1.js.map +1 -0
- package/dist/mt/workers/assets/miden_client_web.wasm +0 -0
- package/dist/mt/workers/web-client-methods-worker.js +26996 -0
- package/dist/mt/workers/web-client-methods-worker.js.map +1 -0
- package/dist/{workers → mt/workers}/web-client-methods-worker.module.js +71 -2
- package/dist/mt/workers/web-client-methods-worker.module.js.map +1 -0
- package/dist/mt/workers/workerHelpers.js +28 -0
- package/dist/{Cargo-CVlXCH_2.js → st/Cargo-OZMlHpic.js} +721 -496
- package/dist/st/Cargo-OZMlHpic.js.map +1 -0
- package/dist/st/api-types.d.ts +1144 -0
- package/dist/{workers → st}/assets/miden_client_web.wasm +0 -0
- package/dist/{crates → st/crates}/miden_client_web.d.ts +357 -197
- package/dist/st/docs-entry.d.ts +38 -0
- package/dist/{eager.js → st/eager.js} +2 -2
- package/dist/st/eager.js.map +1 -0
- package/dist/st/index.d.ts +183 -0
- package/dist/{index.js → st/index.js} +723 -284
- package/dist/st/index.js.map +1 -0
- package/dist/st/wasm.js +23 -0
- package/dist/st/wasm.js.map +1 -0
- package/dist/{workers/Cargo-CVlXCH_2-CWA-5vlh.js → st/workers/Cargo-OZMlHpic-DZjvJlWc.js} +721 -496
- package/dist/st/workers/Cargo-OZMlHpic-DZjvJlWc.js.map +1 -0
- package/dist/{assets → st/workers/assets}/miden_client_web.wasm +0 -0
- package/dist/{workers → st/workers}/web-client-methods-worker.js +792 -498
- package/dist/st/workers/web-client-methods-worker.js.map +1 -0
- package/dist/st/workers/web-client-methods-worker.module.js +628 -0
- package/dist/st/workers/web-client-methods-worker.module.js.map +1 -0
- package/js/client.js +190 -7
- package/js/node/napi-compat.js +22 -3
- package/js/node-index.js +0 -1
- package/js/resources/accounts.js +4 -6
- package/js/resources/transactions.js +138 -1
- package/lazy/package.json +2 -2
- package/mt/lazy/package.json +4 -0
- package/mt/package.json +4 -0
- package/package.json +30 -15
- package/dist/Cargo-CVlXCH_2.js.map +0 -1
- package/dist/eager.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/wasm.js.map +0 -1
- package/dist/workers/Cargo-CVlXCH_2-CWA-5vlh.js.map +0 -1
- package/dist/workers/web-client-methods-worker.js.map +0 -1
- package/dist/workers/web-client-methods-worker.module.js.map +0 -1
- /package/dist/{docs-entry.d.ts → mt/docs-entry.d.ts} +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import loadWasm from './wasm.js';
|
|
2
|
-
export { Account, AccountArray, AccountBuilder, AccountBuilderResult, AccountCode, AccountComponent, AccountComponentCode, AccountDelta, AccountFile, AccountHeader, AccountId, AccountIdArray, AccountInterface, AccountProof, AccountReader, AccountStatus, AccountStorage, AccountStorageDelta, AccountStorageMode, AccountStorageRequirements, AccountVaultDelta, Address, AdviceInputs, AdviceMap, AssetVault, AuthFalcon512RpoMultisigConfig, AuthSecretKey, BasicFungibleFaucetComponent, BlockHeader, CodeBuilder, CommittedNote, ConsumableNoteRecord, Endpoint, ExecutedTransaction, Felt, FeltArray, FetchedAccount, FetchedNote, FlattenedU8Vec, ForeignAccount, ForeignAccountArray, FungibleAsset, FungibleAssetDelta, FungibleAssetDeltaItem, GetProceduresResultItem, InputNote, InputNoteRecord, InputNoteState, InputNotes, IntoUnderlyingByteSource, IntoUnderlyingSink, IntoUnderlyingSource, JsAccountUpdate, JsStateSyncUpdate, JsStorageMapEntry, JsStorageSlot, JsVaultAsset, Library, MerklePath, NetworkId, NetworkNoteStatusInfo, NetworkType, Note, NoteAndArgs, NoteAndArgsArray, NoteArray, NoteAssets, NoteAttachment,
|
|
2
|
+
export { Account, AccountArray, AccountBuilder, AccountBuilderResult, AccountCode, AccountComponent, AccountComponentCode, AccountDelta, AccountFile, AccountHeader, AccountId, AccountIdArray, AccountInterface, AccountProof, AccountReader, AccountStatus, AccountStorage, AccountStorageDelta, AccountStorageMode, AccountStorageRequirements, AccountVaultDelta, Address, AdviceInputs, AdviceMap, AssetVault, AuthFalcon512RpoMultisigConfig, AuthSecretKey, BasicFungibleFaucetComponent, BlockHeader, CodeBuilder, CommittedNote, ConsumableNoteRecord, Endpoint, ExecutedTransaction, Felt, FeltArray, FetchedAccount, FetchedNote, FlattenedU8Vec, ForeignAccount, ForeignAccountArray, FungibleAsset, FungibleAssetDelta, FungibleAssetDeltaItem, GetProceduresResultItem, InputNote, InputNoteRecord, InputNoteState, InputNotes, IntoUnderlyingByteSource, IntoUnderlyingSink, IntoUnderlyingSource, JsAccountUpdate, JsStateSyncUpdate, JsStorageMapEntry, JsStorageSlot, JsVaultAsset, Library, MerklePath, NetworkId, NetworkNoteStatusInfo, NetworkType, Note, NoteAndArgs, NoteAndArgsArray, NoteArray, NoteAssets, NoteAttachment, NoteAttachmentScheme, NoteConsumability, NoteConsumptionStatus, NoteDetails, NoteDetailsAndTag, NoteDetailsAndTagArray, NoteExecutionHint, NoteExportFormat, NoteFile, NoteFilter, NoteFilterTypes, NoteHeader, NoteId, NoteIdAndArgs, NoteIdAndArgsArray, NoteInclusionProof, NoteLocation, NoteMetadata, NoteRecipient, NoteRecipientArray, NoteScript, NoteStorage, NoteSyncBlock, NoteSyncInfo, NoteTag, NoteType, OutputNote, OutputNoteArray, OutputNoteRecord, OutputNoteState, OutputNotes, Package, PartialNote, Poseidon2, ProcedureThreshold, Program, ProvenTransaction, PublicKey, RpcClient, Rpo256, SerializedInputNoteData, SerializedOutputNoteData, SerializedTransactionData, Signature, SigningInputs, SigningInputsType, SlotAndKeys, SparseMerklePath, StorageMap, StorageMapEntry, StorageMapEntryJs, StorageMapInfo, StorageMapUpdate, StorageSlot, StorageSlotArray, SyncSummary, TestUtils, TokenSymbol, TransactionArgs, TransactionFilter, TransactionId, TransactionProver, TransactionRecord, TransactionRequest, TransactionRequestBuilder, TransactionResult, TransactionScript, TransactionScriptInputPair, TransactionScriptInputPairArray, TransactionStatus, TransactionStoreUpdate, TransactionSummary, WebClient, WebKeystoreApi, Word, createAuthFalcon512RpoMultisig, exportStore, importStore, initSync, sequentialSumBench, setupLogging } from './Cargo-OZMlHpic.js';
|
|
3
3
|
|
|
4
4
|
const WorkerAction = Object.freeze({
|
|
5
5
|
INIT: "init",
|
|
6
6
|
INIT_MOCK: "initMock",
|
|
7
|
+
INIT_THREAD_POOL: "initThreadPool",
|
|
7
8
|
CALL_METHOD: "callMethod",
|
|
8
9
|
EXECUTE_CALLBACK: "executeCallback",
|
|
9
10
|
});
|
|
@@ -25,20 +26,24 @@ const MethodName = Object.freeze({
|
|
|
25
26
|
SUBMIT_NEW_TRANSACTION_WITH_PROVER_MOCK: "submitNewTransactionWithProverMock",
|
|
26
27
|
SYNC_STATE: "syncState",
|
|
27
28
|
SYNC_STATE_MOCK: "syncStateMock",
|
|
29
|
+
SYNC_CHAIN: "syncChain",
|
|
30
|
+
SYNC_CHAIN_MOCK: "syncChainMock",
|
|
31
|
+
SYNC_NOTE_TRANSPORT: "syncNoteTransport",
|
|
32
|
+
SYNC_NOTE_TRANSPORT_MOCK: "syncNoteTransportMock",
|
|
28
33
|
});
|
|
29
34
|
|
|
30
35
|
/**
|
|
31
36
|
* Sync Lock Module
|
|
32
37
|
*
|
|
33
|
-
*
|
|
34
|
-
* with an in-process mutex fallback for older browsers.
|
|
38
|
+
* Coordinates concurrent sync calls using the Web Locks API.
|
|
35
39
|
*
|
|
36
40
|
* Behavior:
|
|
37
|
-
* -
|
|
38
|
-
*
|
|
39
|
-
* -
|
|
40
|
-
*
|
|
41
|
-
* -
|
|
41
|
+
* - Same-method coalescing: if a sync of the same method is in progress,
|
|
42
|
+
* subsequent callers share its result promise
|
|
43
|
+
* - Different-method serialization: different methods (e.g. syncState vs
|
|
44
|
+
* syncNoteTransport) wait for each other via the Web Lock, or via an
|
|
45
|
+
* in-process per-dbId promise chain when Web Locks are unavailable
|
|
46
|
+
* - Web Locks also serialize across tabs (Chrome 69+, Safari 15.4+)
|
|
42
47
|
*/
|
|
43
48
|
|
|
44
49
|
/**
|
|
@@ -52,195 +57,86 @@ function hasWebLocks() {
|
|
|
52
57
|
);
|
|
53
58
|
}
|
|
54
59
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
*/
|
|
58
|
-
const syncStates = new Map();
|
|
60
|
+
// Coalesce map keyed by `${dbId}:${methodId}` -> in-flight promise.
|
|
61
|
+
const inFlight = new Map();
|
|
59
62
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
let state = syncStates.get(dbId);
|
|
65
|
-
if (!state) {
|
|
66
|
-
state = {
|
|
67
|
-
inProgress: false,
|
|
68
|
-
result: null,
|
|
69
|
-
error: null,
|
|
70
|
-
waiters: [],
|
|
71
|
-
releaseLock: null,
|
|
72
|
-
syncGeneration: 0,
|
|
73
|
-
};
|
|
74
|
-
syncStates.set(dbId, state);
|
|
75
|
-
}
|
|
76
|
-
return state;
|
|
77
|
-
}
|
|
63
|
+
// Per-dbId promise tail used to serialize cross-method calls when Web Locks
|
|
64
|
+
// are unavailable. Each new task chains onto the current tail so different
|
|
65
|
+
// methods on the same dbId run sequentially within the tab.
|
|
66
|
+
const fallbackTails = new Map();
|
|
78
67
|
|
|
79
68
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* If a sync is already in progress:
|
|
83
|
-
* - Returns { acquired: false, coalescedResult } after waiting for the result
|
|
84
|
-
*
|
|
85
|
-
* If no sync is in progress:
|
|
86
|
-
* - Returns { acquired: true } and the caller should perform the sync,
|
|
87
|
-
* then call releaseSyncLock() or releaseSyncLockWithError()
|
|
69
|
+
* Build the coalesce-map key for an in-flight sync of `(dbId, methodId)`.
|
|
88
70
|
*
|
|
89
|
-
* @param {string} dbId
|
|
90
|
-
* @param {
|
|
91
|
-
* @returns {
|
|
71
|
+
* @param {string} dbId
|
|
72
|
+
* @param {string} methodId
|
|
73
|
+
* @returns {string}
|
|
92
74
|
*/
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
// If a sync is already in progress, wait for it to complete (coalescing)
|
|
97
|
-
if (state.inProgress) {
|
|
98
|
-
return new Promise((resolve, reject) => {
|
|
99
|
-
let timeoutId;
|
|
100
|
-
if (timeoutMs > 0) {
|
|
101
|
-
timeoutId = setTimeout(() => {
|
|
102
|
-
const idx = state.waiters.findIndex((w) => w.resolve === onResult);
|
|
103
|
-
if (idx !== -1) {
|
|
104
|
-
state.waiters.splice(idx, 1);
|
|
105
|
-
}
|
|
106
|
-
reject(new Error("Sync lock acquisition timed out"));
|
|
107
|
-
}, timeoutMs);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const onResult = (result) => {
|
|
111
|
-
/* v8 ignore next 1 -- timeoutId only set when timeoutMs>0 AND another sync is in progress; combo rare in tests */
|
|
112
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
113
|
-
resolve({ acquired: false, coalescedResult: result });
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
const onError = (error) => {
|
|
117
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
118
|
-
reject(error);
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
state.waiters.push({ resolve: onResult, reject: onError });
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Mark sync as in progress and increment generation
|
|
126
|
-
state.inProgress = true;
|
|
127
|
-
state.result = null;
|
|
128
|
-
state.error = null;
|
|
129
|
-
state.syncGeneration++;
|
|
130
|
-
const currentGeneration = state.syncGeneration;
|
|
131
|
-
|
|
132
|
-
// Try to acquire Web Lock if available
|
|
133
|
-
if (hasWebLocks()) {
|
|
134
|
-
const lockName = `miden-sync-${dbId}`;
|
|
135
|
-
|
|
136
|
-
return new Promise((resolve, reject) => {
|
|
137
|
-
let timeoutId;
|
|
138
|
-
let timedOut = false;
|
|
139
|
-
|
|
140
|
-
if (timeoutMs > 0) {
|
|
141
|
-
timeoutId = setTimeout(() => {
|
|
142
|
-
timedOut = true;
|
|
143
|
-
if (state.syncGeneration === currentGeneration) {
|
|
144
|
-
state.inProgress = false;
|
|
145
|
-
const error = new Error("Sync lock acquisition timed out");
|
|
146
|
-
for (const waiter of state.waiters) {
|
|
147
|
-
waiter.reject(error);
|
|
148
|
-
}
|
|
149
|
-
state.waiters = [];
|
|
150
|
-
}
|
|
151
|
-
reject(new Error("Sync lock acquisition timed out"));
|
|
152
|
-
}, timeoutMs);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
navigator.locks
|
|
156
|
-
.request(lockName, { mode: "exclusive" }, async () => {
|
|
157
|
-
/* v8 ignore next 3 -- race: lock granted after timeout or newer generation */
|
|
158
|
-
if (timedOut || state.syncGeneration !== currentGeneration) {
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
163
|
-
|
|
164
|
-
return new Promise((releaseLock) => {
|
|
165
|
-
state.releaseLock = releaseLock;
|
|
166
|
-
resolve({ acquired: true });
|
|
167
|
-
});
|
|
168
|
-
})
|
|
169
|
-
.catch((err) => {
|
|
170
|
-
/* v8 ignore next 5 -- catch path requires Web Locks rejection combined with
|
|
171
|
-
optional timeout; tested via "rejects when Web Locks request rejects" but
|
|
172
|
-
the timeoutId-set branch needs Web Locks + timeout simultaneously */
|
|
173
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
174
|
-
if (state.syncGeneration === currentGeneration) {
|
|
175
|
-
state.inProgress = false;
|
|
176
|
-
}
|
|
177
|
-
reject(err instanceof Error ? err : new Error(String(err)));
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
} else {
|
|
181
|
-
// Fallback: no Web Locks, just use in-process state
|
|
182
|
-
return { acquired: true };
|
|
183
|
-
}
|
|
75
|
+
function coalesceKey(dbId, methodId) {
|
|
76
|
+
return `${dbId}:${methodId}`;
|
|
184
77
|
}
|
|
185
78
|
|
|
186
79
|
/**
|
|
187
|
-
*
|
|
80
|
+
* Run `fn` while holding the per-db Web Lock. When Web Locks are unavailable,
|
|
81
|
+
* serializes `fn` against any other in-flight call on the same `dbId` via an
|
|
82
|
+
* in-process promise chain — the wasm-bindgen `WebClient` uses a synchronous
|
|
83
|
+
* `RefCell` for interior mutability in the browser, so overlapping
|
|
84
|
+
* cross-method borrows would throw "recursive use of an object detected
|
|
85
|
+
* which would lead to unsafe aliasing in rust".
|
|
188
86
|
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
* @
|
|
192
|
-
* @
|
|
87
|
+
* @param {string} dbId
|
|
88
|
+
* @param {() => Promise<T>} fn
|
|
89
|
+
* @returns {Promise<T>}
|
|
90
|
+
* @template T
|
|
193
91
|
*/
|
|
194
|
-
function
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
for (const waiter of state.waiters) {
|
|
206
|
-
waiter.resolve(result);
|
|
207
|
-
}
|
|
208
|
-
state.waiters = [];
|
|
209
|
-
|
|
210
|
-
if (state.releaseLock) {
|
|
211
|
-
state.releaseLock();
|
|
212
|
-
state.releaseLock = null;
|
|
92
|
+
function runUnderLock(dbId, fn) {
|
|
93
|
+
if (!hasWebLocks()) {
|
|
94
|
+
const prev = fallbackTails.get(dbId) ?? Promise.resolve();
|
|
95
|
+
const next = prev.catch(() => {}).then(fn);
|
|
96
|
+
const guarded = next.catch(() => {});
|
|
97
|
+
fallbackTails.set(dbId, guarded);
|
|
98
|
+
guarded.then(() => {
|
|
99
|
+
// Drop the slot only if no successor chained onto this tail.
|
|
100
|
+
if (fallbackTails.get(dbId) === guarded) fallbackTails.delete(dbId);
|
|
101
|
+
});
|
|
102
|
+
return next;
|
|
213
103
|
}
|
|
104
|
+
return navigator.locks.request(
|
|
105
|
+
`miden-sync-${dbId}`,
|
|
106
|
+
{ mode: "exclusive" },
|
|
107
|
+
fn
|
|
108
|
+
);
|
|
214
109
|
}
|
|
215
110
|
|
|
216
111
|
/**
|
|
217
|
-
*
|
|
112
|
+
* Run `fn` under the sync lock for (dbId, methodId).
|
|
218
113
|
*
|
|
219
|
-
*
|
|
114
|
+
* Concurrent calls with the same (dbId, methodId) share the same promise
|
|
115
|
+
* (coalescing). Concurrent calls on the same dbId with different methodIds
|
|
116
|
+
* serialize via the Web Lock.
|
|
220
117
|
*
|
|
221
|
-
* @param {string} dbId -
|
|
222
|
-
* @param {
|
|
118
|
+
* @param {string} dbId - Database ID
|
|
119
|
+
* @param {string} methodId - Method identifier (see MethodName constants)
|
|
120
|
+
* @param {() => Promise<T>} fn - Work to run under the lock
|
|
121
|
+
* @returns {Promise<T>}
|
|
223
122
|
*/
|
|
224
|
-
function
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
state.releaseLock();
|
|
242
|
-
state.releaseLock = null;
|
|
243
|
-
}
|
|
123
|
+
function withSyncLock(dbId, methodId, fn) {
|
|
124
|
+
const key = coalesceKey(dbId, methodId);
|
|
125
|
+
|
|
126
|
+
let work = inFlight.get(key);
|
|
127
|
+
if (!work) {
|
|
128
|
+
work = runUnderLock(dbId, fn);
|
|
129
|
+
inFlight.set(key, work);
|
|
130
|
+
// Swallow on the derived promise so a rejection here doesn't surface as
|
|
131
|
+
// an unhandled rejection; the caller still sees the error through `work`.
|
|
132
|
+
work
|
|
133
|
+
.finally(() => {
|
|
134
|
+
if (inFlight.get(key) === work) inFlight.delete(key);
|
|
135
|
+
})
|
|
136
|
+
.catch(() => {});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return work;
|
|
244
140
|
}
|
|
245
141
|
|
|
246
142
|
/**
|
|
@@ -504,6 +400,7 @@ class AccountsResource {
|
|
|
504
400
|
return await this.#inner.newFaucet(
|
|
505
401
|
storageMode,
|
|
506
402
|
type === 1 || type === "NonFungibleFaucet",
|
|
403
|
+
opts.name ?? opts.symbol,
|
|
507
404
|
opts.symbol,
|
|
508
405
|
opts.decimals,
|
|
509
406
|
BigInt(opts.maxSupply),
|
|
@@ -536,11 +433,9 @@ class AccountsResource {
|
|
|
536
433
|
if (!opts.auth)
|
|
537
434
|
throw new Error("Contract creation requires an 'auth' (AuthSecretKey)");
|
|
538
435
|
|
|
539
|
-
//
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
? wasm.AccountType.RegularAccountUpdatableCode
|
|
543
|
-
: wasm.AccountType.RegularAccountImmutableCode;
|
|
436
|
+
// The 0.15 protocol has no code-mutability distinction, so the `type`
|
|
437
|
+
// ("ImmutableContract" / "MutableContract") only steers routing here; the
|
|
438
|
+
// account's on-chain visibility is set entirely by `storageMode`.
|
|
544
439
|
const storageMode = resolveStorageMode(opts.storage ?? "public", wasm);
|
|
545
440
|
const authComponent =
|
|
546
441
|
wasm.AccountComponent.createAuthComponentFromSecretKey(opts.auth);
|
|
@@ -555,7 +450,6 @@ class AccountsResource {
|
|
|
555
450
|
}
|
|
556
451
|
|
|
557
452
|
let builder = new wasm.AccountBuilder(opts.seed)
|
|
558
|
-
.accountType(accountTypeEnum)
|
|
559
453
|
.storageMode(storageMode)
|
|
560
454
|
.withAuthComponent(authComponent);
|
|
561
455
|
|
|
@@ -866,6 +760,72 @@ class TransactionsResource {
|
|
|
866
760
|
return { txId, result };
|
|
867
761
|
}
|
|
868
762
|
|
|
763
|
+
/** Create a partial-swap (PSWAP) note. See {@link PswapCreateOptions}. */
|
|
764
|
+
async pswapCreate(opts) {
|
|
765
|
+
this.#client.assertNotTerminated();
|
|
766
|
+
const wasm = await this.#getWasm();
|
|
767
|
+
const { accountId, request } = await this.#buildPswapCreateRequest(
|
|
768
|
+
opts,
|
|
769
|
+
wasm
|
|
770
|
+
);
|
|
771
|
+
|
|
772
|
+
const { txId, result } = await this.#submitOrSubmitWithProver(
|
|
773
|
+
accountId,
|
|
774
|
+
request,
|
|
775
|
+
opts.prover
|
|
776
|
+
);
|
|
777
|
+
|
|
778
|
+
if (opts.waitForConfirmation) {
|
|
779
|
+
await this.waitFor(txId.toHex(), { timeout: opts.timeout });
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
return { txId, result };
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/** Consume (fully or partially fill) a PSWAP note. See {@link PswapConsumeOptions}. */
|
|
786
|
+
async pswapConsume(opts) {
|
|
787
|
+
this.#client.assertNotTerminated();
|
|
788
|
+
const wasm = await this.#getWasm();
|
|
789
|
+
const { accountId, request } = await this.#buildPswapConsumeRequest(
|
|
790
|
+
opts,
|
|
791
|
+
wasm
|
|
792
|
+
);
|
|
793
|
+
|
|
794
|
+
const { txId, result } = await this.#submitOrSubmitWithProver(
|
|
795
|
+
accountId,
|
|
796
|
+
request,
|
|
797
|
+
opts.prover
|
|
798
|
+
);
|
|
799
|
+
|
|
800
|
+
if (opts.waitForConfirmation) {
|
|
801
|
+
await this.waitFor(txId.toHex(), { timeout: opts.timeout });
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
return { txId, result };
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/** Cancel a PSWAP note as its creator and reclaim the offered asset. See {@link PswapCancelOptions}. */
|
|
808
|
+
async pswapCancel(opts) {
|
|
809
|
+
this.#client.assertNotTerminated();
|
|
810
|
+
const wasm = await this.#getWasm();
|
|
811
|
+
const { accountId, request } = await this.#buildPswapCancelRequest(
|
|
812
|
+
opts,
|
|
813
|
+
wasm
|
|
814
|
+
);
|
|
815
|
+
|
|
816
|
+
const { txId, result } = await this.#submitOrSubmitWithProver(
|
|
817
|
+
accountId,
|
|
818
|
+
request,
|
|
819
|
+
opts.prover
|
|
820
|
+
);
|
|
821
|
+
|
|
822
|
+
if (opts.waitForConfirmation) {
|
|
823
|
+
await this.waitFor(txId.toHex(), { timeout: opts.timeout });
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
return { txId, result };
|
|
827
|
+
}
|
|
828
|
+
|
|
869
829
|
async preview(opts) {
|
|
870
830
|
this.#client.assertNotTerminated();
|
|
871
831
|
const wasm = await this.#getWasm();
|
|
@@ -890,6 +850,27 @@ class TransactionsResource {
|
|
|
890
850
|
({ accountId, request } = await this.#buildSwapRequest(opts, wasm));
|
|
891
851
|
break;
|
|
892
852
|
}
|
|
853
|
+
case "pswapCreate": {
|
|
854
|
+
({ accountId, request } = await this.#buildPswapCreateRequest(
|
|
855
|
+
opts,
|
|
856
|
+
wasm
|
|
857
|
+
));
|
|
858
|
+
break;
|
|
859
|
+
}
|
|
860
|
+
case "pswapConsume": {
|
|
861
|
+
({ accountId, request } = await this.#buildPswapConsumeRequest(
|
|
862
|
+
opts,
|
|
863
|
+
wasm
|
|
864
|
+
));
|
|
865
|
+
break;
|
|
866
|
+
}
|
|
867
|
+
case "pswapCancel": {
|
|
868
|
+
({ accountId, request } = await this.#buildPswapCancelRequest(
|
|
869
|
+
opts,
|
|
870
|
+
wasm
|
|
871
|
+
));
|
|
872
|
+
break;
|
|
873
|
+
}
|
|
893
874
|
case "custom": {
|
|
894
875
|
accountId = resolveAccountRef(opts.account, wasm);
|
|
895
876
|
request = opts.request;
|
|
@@ -1042,7 +1023,10 @@ class TransactionsResource {
|
|
|
1042
1023
|
}
|
|
1043
1024
|
|
|
1044
1025
|
try {
|
|
1045
|
-
|
|
1026
|
+
// Chain-only sync is sufficient: confirmation only needs on-chain
|
|
1027
|
+
// state, and skipping NTL keeps polling alive when the note
|
|
1028
|
+
// transport endpoint is unavailable.
|
|
1029
|
+
await this.#inner.syncChain();
|
|
1046
1030
|
} catch {
|
|
1047
1031
|
// Sync may fail transiently; continue polling
|
|
1048
1032
|
}
|
|
@@ -1176,6 +1160,53 @@ class TransactionsResource {
|
|
|
1176
1160
|
return { accountId, request };
|
|
1177
1161
|
}
|
|
1178
1162
|
|
|
1163
|
+
async #buildPswapCreateRequest(opts, wasm) {
|
|
1164
|
+
const accountId = resolveAccountRef(opts.account, wasm);
|
|
1165
|
+
const offeredFaucetId = resolveAccountRef(opts.offer.token, wasm);
|
|
1166
|
+
const requestedFaucetId = resolveAccountRef(opts.request.token, wasm);
|
|
1167
|
+
const noteType = resolveNoteType(opts.type, wasm);
|
|
1168
|
+
const paybackNoteType = resolveNoteType(
|
|
1169
|
+
opts.paybackType ?? opts.type,
|
|
1170
|
+
wasm
|
|
1171
|
+
);
|
|
1172
|
+
|
|
1173
|
+
const request = await this.#inner.newPswapCreateTransactionRequest(
|
|
1174
|
+
accountId,
|
|
1175
|
+
offeredFaucetId,
|
|
1176
|
+
BigInt(opts.offer.amount),
|
|
1177
|
+
requestedFaucetId,
|
|
1178
|
+
BigInt(opts.request.amount),
|
|
1179
|
+
noteType,
|
|
1180
|
+
paybackNoteType
|
|
1181
|
+
);
|
|
1182
|
+
return { accountId, request };
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
async #buildPswapConsumeRequest(opts, wasm) {
|
|
1186
|
+
const accountId = resolveAccountRef(opts.account, wasm);
|
|
1187
|
+
const note = await this.#resolveNoteInput(opts.note);
|
|
1188
|
+
const noteFillAmount = opts.noteFillAmount ?? 0n;
|
|
1189
|
+
|
|
1190
|
+
const request = await this.#inner.newPswapConsumeTransactionRequest(
|
|
1191
|
+
note,
|
|
1192
|
+
accountId,
|
|
1193
|
+
BigInt(opts.fillAmount),
|
|
1194
|
+
BigInt(noteFillAmount)
|
|
1195
|
+
);
|
|
1196
|
+
return { accountId, request };
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
async #buildPswapCancelRequest(opts, wasm) {
|
|
1200
|
+
const accountId = resolveAccountRef(opts.account, wasm);
|
|
1201
|
+
const note = await this.#resolveNoteInput(opts.note);
|
|
1202
|
+
|
|
1203
|
+
const request = await this.#inner.newPswapCancelTransactionRequest(
|
|
1204
|
+
note,
|
|
1205
|
+
accountId
|
|
1206
|
+
);
|
|
1207
|
+
return { accountId, request };
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1179
1210
|
async #resolveNoteInput(input) {
|
|
1180
1211
|
if (typeof input === "string") {
|
|
1181
1212
|
const record = await this.#inner.getInputNote(input);
|
|
@@ -1565,6 +1596,80 @@ class MidenClient {
|
|
|
1565
1596
|
this.keystore = new KeystoreResource(inner, this);
|
|
1566
1597
|
}
|
|
1567
1598
|
|
|
1599
|
+
/**
|
|
1600
|
+
* Escape hatch: runs `fn` with exclusive access to the proxied JS
|
|
1601
|
+
* WebClient that backs this MidenClient.
|
|
1602
|
+
*
|
|
1603
|
+
* The proxy forwards missing properties to the underlying wasm-bindgen
|
|
1604
|
+
* `WebClient`, so `fn` can reach lower-level methods like
|
|
1605
|
+
* `executeTransaction`, `proveTransaction[WithProver]`,
|
|
1606
|
+
* `submitProvenTransaction`, `applyTransaction`,
|
|
1607
|
+
* `newSendTransactionRequest`, `newConsumeTransactionRequest`, etc.
|
|
1608
|
+
*
|
|
1609
|
+
* Intended for advanced consumers that need to split the bundled
|
|
1610
|
+
* execute → prove → submit → apply pipeline across contexts — for example,
|
|
1611
|
+
* a Chrome MV3 extension that runs `executeTransaction` in its service
|
|
1612
|
+
* worker, dispatches the prove step to a `chrome.offscreen` document
|
|
1613
|
+
* (where wasm-bindgen-rayon can spawn a real thread pool), then runs
|
|
1614
|
+
* `submitProvenTransaction` + `applyTransaction` back in the SW.
|
|
1615
|
+
*
|
|
1616
|
+
* The callback runs inside `_serializeWasmCall`, so the WASM RefCell is
|
|
1617
|
+
* held for the duration of `fn`. Concurrent SDK calls (sync, other
|
|
1618
|
+
* transactions, etc.) queue on the same chain and run after `fn`
|
|
1619
|
+
* settles. Without this serialization, raw inner-client access would
|
|
1620
|
+
* race the proxy's chain and trip wasm-bindgen's "recursive use of an
|
|
1621
|
+
* object detected" panic.
|
|
1622
|
+
*
|
|
1623
|
+
* Re-entrancy: while `fn` is running, the underlying client's
|
|
1624
|
+
* `_withInnerLockDepth` counter is bumped so that `_serializeWasmCall`
|
|
1625
|
+
* invocations made BY `fn` (or any proxy-dispatched method it calls)
|
|
1626
|
+
* run inline rather than enqueuing on the chain. Without this, every
|
|
1627
|
+
* `await inner.X(...)` inside `fn` would enqueue behind the outer
|
|
1628
|
+
* `_withInnerWebClient` slot which is itself awaiting `fn` —
|
|
1629
|
+
* a classic re-entrant-lock deadlock. The depth counter restores the
|
|
1630
|
+
* intent of the docstring above: the lock is held for the duration
|
|
1631
|
+
* of `fn`, and inner-client calls "borrow" that already-held lock
|
|
1632
|
+
* instead of trying to re-acquire it.
|
|
1633
|
+
*
|
|
1634
|
+
* SAFETY CONTRACT for re-entrancy: callers MUST hold an external
|
|
1635
|
+
* mutex preventing concurrent access to this same client instance
|
|
1636
|
+
* via other code paths during `fn`. The chain still serializes
|
|
1637
|
+
* against external callers — they queue behind the outer slot — but
|
|
1638
|
+
* if an external task runs during one of `fn`'s awaits and calls
|
|
1639
|
+
* into the SDK, it will see `_withInnerLockDepth > 0` and run
|
|
1640
|
+
* inline, racing wasm-bindgen's borrow check. The wallet pattern
|
|
1641
|
+
* (own outer mutex around `_withInnerWebClient`) satisfies this.
|
|
1642
|
+
*
|
|
1643
|
+
* Stability: marked `@internal`. The shape of the proxied client is
|
|
1644
|
+
* intentionally not part of the documented public API and may change
|
|
1645
|
+
* between SDK versions. If you depend on this method, pin the SDK
|
|
1646
|
+
* version and test the lower-level surface carefully on each upgrade.
|
|
1647
|
+
* If your use case is common enough to warrant a stable public API,
|
|
1648
|
+
* file an issue.
|
|
1649
|
+
*
|
|
1650
|
+
* @internal
|
|
1651
|
+
* @template T
|
|
1652
|
+
* @param {(inner: object) => Promise<T>} fn - Async callback receiving
|
|
1653
|
+
* the proxied JS WebClient. Must not return references that escape
|
|
1654
|
+
* the callback's lifetime (the lock is released on settle).
|
|
1655
|
+
* @returns {Promise<T>} The resolved value of `fn`.
|
|
1656
|
+
*/
|
|
1657
|
+
_withInnerWebClient(fn) {
|
|
1658
|
+
this.assertNotTerminated();
|
|
1659
|
+
if (typeof fn !== "function") {
|
|
1660
|
+
throw new TypeError("_withInnerWebClient: fn must be a function");
|
|
1661
|
+
}
|
|
1662
|
+
const inner = this.#inner;
|
|
1663
|
+
return inner._serializeWasmCall(async () => {
|
|
1664
|
+
inner._withInnerLockDepth = (inner._withInnerLockDepth || 0) + 1;
|
|
1665
|
+
try {
|
|
1666
|
+
return await fn(inner);
|
|
1667
|
+
} finally {
|
|
1668
|
+
inner._withInnerLockDepth--;
|
|
1669
|
+
}
|
|
1670
|
+
});
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1568
1673
|
/**
|
|
1569
1674
|
* Creates and initializes a new MidenClient.
|
|
1570
1675
|
*
|
|
@@ -1593,6 +1698,13 @@ class MidenClient {
|
|
|
1593
1698
|
const rpcUrl = resolveRpcUrl(options?.rpcUrl);
|
|
1594
1699
|
const noteTransportUrl = resolveNoteTransportUrl(options?.noteTransportUrl);
|
|
1595
1700
|
|
|
1701
|
+
// `useWorker: false` opts out of the Web Worker shim that wraps every
|
|
1702
|
+
// WASM call. The shim exists to keep the main thread responsive in
|
|
1703
|
+
// browser/extension contexts, but it serializes the prover via
|
|
1704
|
+
// `TransactionProver.serialize()` — a format that has no encoding for
|
|
1705
|
+
// `newCallbackProver(jsFn)` and silently downgrades it to `"local"`.
|
|
1706
|
+
// Mobile/Tauri/native-prover consumers must pass `useWorker: false`.
|
|
1707
|
+
const useWorker = options?.useWorker;
|
|
1596
1708
|
let inner;
|
|
1597
1709
|
if (options?.keystore) {
|
|
1598
1710
|
inner = await WebClientClass.createClientWithExternalKeystore(
|
|
@@ -1603,7 +1715,8 @@ class MidenClient {
|
|
|
1603
1715
|
options.keystore.getKey,
|
|
1604
1716
|
options.keystore.insertKey,
|
|
1605
1717
|
options.keystore.sign,
|
|
1606
|
-
options?.debugMode
|
|
1718
|
+
options?.debugMode,
|
|
1719
|
+
useWorker
|
|
1607
1720
|
);
|
|
1608
1721
|
} else {
|
|
1609
1722
|
inner = await WebClientClass.createClient(
|
|
@@ -1611,7 +1724,8 @@ class MidenClient {
|
|
|
1611
1724
|
noteTransportUrl,
|
|
1612
1725
|
seed,
|
|
1613
1726
|
options?.storeName,
|
|
1614
|
-
options?.debugMode
|
|
1727
|
+
options?.debugMode,
|
|
1728
|
+
useWorker
|
|
1615
1729
|
);
|
|
1616
1730
|
}
|
|
1617
1731
|
|
|
@@ -1668,6 +1782,32 @@ class MidenClient {
|
|
|
1668
1782
|
});
|
|
1669
1783
|
}
|
|
1670
1784
|
|
|
1785
|
+
/**
|
|
1786
|
+
* Resolves once the WASM module is initialized and safe to use.
|
|
1787
|
+
*
|
|
1788
|
+
* Idempotent and shared across callers: the underlying loader memoizes the
|
|
1789
|
+
* in-flight promise, so concurrent `ready()` calls await the same
|
|
1790
|
+
* initialization and post-init callers resolve immediately from a cached
|
|
1791
|
+
* module. Safe to call from `MidenProvider`, tutorial helpers, and any
|
|
1792
|
+
* other consumer simultaneously.
|
|
1793
|
+
*
|
|
1794
|
+
* Useful on the `/lazy` entry (e.g. Next.js / Capacitor), where no
|
|
1795
|
+
* top-level await runs at import time. On the default (eager) entry this
|
|
1796
|
+
* is redundant — importing the module already awaits WASM — but calling it
|
|
1797
|
+
* is still harmless.
|
|
1798
|
+
*
|
|
1799
|
+
* @returns {Promise<void>} Resolves when WASM is initialized.
|
|
1800
|
+
*/
|
|
1801
|
+
static async ready() {
|
|
1802
|
+
const getWasm = MidenClient._getWasmOrThrow;
|
|
1803
|
+
if (!getWasm) {
|
|
1804
|
+
throw new Error(
|
|
1805
|
+
"MidenClient not initialized. Import from the SDK package entry point."
|
|
1806
|
+
);
|
|
1807
|
+
}
|
|
1808
|
+
await getWasm();
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1671
1811
|
/**
|
|
1672
1812
|
* Creates a mock client for testing.
|
|
1673
1813
|
*
|
|
@@ -1703,15 +1843,34 @@ class MidenClient {
|
|
|
1703
1843
|
}
|
|
1704
1844
|
|
|
1705
1845
|
/**
|
|
1706
|
-
* Syncs the client
|
|
1846
|
+
* Syncs the client: fetches private notes from the Note Transport Layer, then syncs on-chain
|
|
1847
|
+
* state with the Miden node. Fails fast on either.
|
|
1707
1848
|
*
|
|
1708
|
-
* @param {object} [opts] - Sync options.
|
|
1709
|
-
* @param {number} [opts.timeout] - Timeout in milliseconds (0 = no timeout).
|
|
1710
1849
|
* @returns {Promise<SyncSummary>} The sync summary.
|
|
1711
1850
|
*/
|
|
1712
|
-
async sync(
|
|
1851
|
+
async sync() {
|
|
1713
1852
|
this.assertNotTerminated();
|
|
1714
|
-
return await this.#inner.
|
|
1853
|
+
return await this.#inner.syncState();
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
/**
|
|
1857
|
+
* Syncs on-chain state only (no NTL fetch).
|
|
1858
|
+
*
|
|
1859
|
+
* @returns {Promise<SyncSummary>}
|
|
1860
|
+
*/
|
|
1861
|
+
async syncChain() {
|
|
1862
|
+
this.assertNotTerminated();
|
|
1863
|
+
return await this.#inner.syncChain();
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
/**
|
|
1867
|
+
* Fetches private notes from the Note Transport Layer.
|
|
1868
|
+
*
|
|
1869
|
+
* @returns {Promise<void>}
|
|
1870
|
+
*/
|
|
1871
|
+
async syncNoteTransport() {
|
|
1872
|
+
this.assertNotTerminated();
|
|
1873
|
+
return await this.#inner.syncNoteTransport();
|
|
1715
1874
|
}
|
|
1716
1875
|
|
|
1717
1876
|
/**
|
|
@@ -1724,6 +1883,61 @@ class MidenClient {
|
|
|
1724
1883
|
return await this.#inner.getSyncHeight();
|
|
1725
1884
|
}
|
|
1726
1885
|
|
|
1886
|
+
/**
|
|
1887
|
+
* Resolves once every serialized WASM call that was already on the
|
|
1888
|
+
* internal `_serializeWasmCall` chain when `waitForIdle()` was called
|
|
1889
|
+
* (execute, submit, prove, apply, sync, or account creation) has
|
|
1890
|
+
* settled. Use this from callers that need to perform a non-WASM-side
|
|
1891
|
+
* action — e.g. clearing an in-memory auth key on wallet lock — after
|
|
1892
|
+
* the kernel finishes, so its auth callback doesn't race with the key
|
|
1893
|
+
* being cleared.
|
|
1894
|
+
*
|
|
1895
|
+
* Does NOT wait for calls enqueued after `waitForIdle()` returns —
|
|
1896
|
+
* intentional, so a caller can drain and proceed without being blocked
|
|
1897
|
+
* indefinitely by concurrent workload.
|
|
1898
|
+
*
|
|
1899
|
+
* Caveat for `syncState`: `syncStateWithTimeout` awaits the sync lock
|
|
1900
|
+
* (`acquireSyncLock`, which uses Web Locks) BEFORE putting its WASM
|
|
1901
|
+
* call onto the chain, so a `syncState` that is queued on the sync
|
|
1902
|
+
* lock — but has not yet begun its WASM phase — is not visible to
|
|
1903
|
+
* `waitForIdle` and will not be awaited. Other methods (`newWallet`,
|
|
1904
|
+
* `executeTransaction`, etc.) route through the chain synchronously
|
|
1905
|
+
* on call and are always observed.
|
|
1906
|
+
*
|
|
1907
|
+
* Safe to call at any time; returns immediately if nothing was in
|
|
1908
|
+
* flight.
|
|
1909
|
+
*
|
|
1910
|
+
* @returns {Promise<void>}
|
|
1911
|
+
*/
|
|
1912
|
+
async waitForIdle() {
|
|
1913
|
+
this.assertNotTerminated();
|
|
1914
|
+
await this.#inner.waitForIdle();
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
/**
|
|
1918
|
+
* Returns the raw JS value that the most recent sign-callback invocation
|
|
1919
|
+
* threw, or `null` if the last sign call succeeded (or no call has
|
|
1920
|
+
* happened yet).
|
|
1921
|
+
*
|
|
1922
|
+
* Useful for recovering structured metadata (e.g. a `reason: 'locked'`
|
|
1923
|
+
* property) that the kernel-level `auth::request` diagnostic would
|
|
1924
|
+
* otherwise erase. Call immediately after catching a failed
|
|
1925
|
+
* `transactions.submit` / `transactions.send` / `transactions.consume`.
|
|
1926
|
+
*
|
|
1927
|
+
* Meaningful only with `useWorker: false`: under the worker shim the
|
|
1928
|
+
* sign callback fires against the worker's WASM keystore, while this
|
|
1929
|
+
* accessor reads the main-thread instance — which never signed — so it
|
|
1930
|
+
* returns `null`. Consumers that need this signal (e.g. external
|
|
1931
|
+
* keystores with lock-aware sign callbacks) already require
|
|
1932
|
+
* `useWorker: false` for the callback to be reachable at all.
|
|
1933
|
+
*
|
|
1934
|
+
* @returns {any} The raw thrown value, or `null`.
|
|
1935
|
+
*/
|
|
1936
|
+
lastAuthError() {
|
|
1937
|
+
this.assertNotTerminated();
|
|
1938
|
+
return this.#inner.lastAuthError();
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1727
1941
|
/**
|
|
1728
1942
|
* Terminates the underlying Web Worker. After this, all method calls will throw.
|
|
1729
1943
|
*/
|
|
@@ -2319,7 +2533,6 @@ const NoteVisibility = Object.freeze({
|
|
|
2319
2533
|
const StorageMode = Object.freeze({
|
|
2320
2534
|
Public: "public",
|
|
2321
2535
|
Private: "private",
|
|
2322
|
-
Network: "network",
|
|
2323
2536
|
});
|
|
2324
2537
|
|
|
2325
2538
|
const Linking = Object.freeze({
|
|
@@ -2513,6 +2726,15 @@ class WebClient {
|
|
|
2513
2726
|
* @param {string | undefined} [logLevel] - Optional log verbosity level
|
|
2514
2727
|
* ("error", "warn", "info", "debug", "trace", "off", or "none").
|
|
2515
2728
|
* When set, Rust tracing output is routed to the browser console.
|
|
2729
|
+
* @param {boolean} [useWorker=true] - When `false`, skip the Web Worker shim
|
|
2730
|
+
* and call the wasm-bindgen `WebClient` directly on the current thread.
|
|
2731
|
+
* The worker exists to keep the main thread responsive during WASM work
|
|
2732
|
+
* in browser/extension contexts, but it serializes the prover argument
|
|
2733
|
+
* via `TransactionProver.serialize()` — a format that has no encoding
|
|
2734
|
+
* for `newCallbackProver(jsFn)` and silently downgrades it to `"local"`.
|
|
2735
|
+
* Consumers that hand a `CallbackProver` (e.g. native iOS/Android plug-in
|
|
2736
|
+
* provers in Capacitor apps, or any other JS-side prover bridge) need
|
|
2737
|
+
* `useWorker: false` so the prover handle reaches the WASM binding intact.
|
|
2516
2738
|
*/
|
|
2517
2739
|
constructor(
|
|
2518
2740
|
rpcUrl,
|
|
@@ -2522,7 +2744,8 @@ class WebClient {
|
|
|
2522
2744
|
getKeyCb,
|
|
2523
2745
|
insertKeyCb,
|
|
2524
2746
|
signCb,
|
|
2525
|
-
logLevel
|
|
2747
|
+
logLevel,
|
|
2748
|
+
useWorker = true
|
|
2526
2749
|
) {
|
|
2527
2750
|
this.rpcUrl = rpcUrl;
|
|
2528
2751
|
this.noteTransportUrl = noteTransportUrl;
|
|
@@ -2532,9 +2755,12 @@ class WebClient {
|
|
|
2532
2755
|
this.insertKeyCb = insertKeyCb;
|
|
2533
2756
|
this.signCb = signCb;
|
|
2534
2757
|
this.logLevel = logLevel;
|
|
2758
|
+
this.useWorker = useWorker !== false;
|
|
2535
2759
|
|
|
2536
|
-
// Check if Web Workers are available
|
|
2537
|
-
|
|
2760
|
+
// Check if Web Workers are available AND the caller didn't opt out via
|
|
2761
|
+
// `useWorker: false`. The opt-out is load-bearing for `CallbackProver`
|
|
2762
|
+
// consumers — see the constructor doc above.
|
|
2763
|
+
if (this.useWorker && typeof Worker !== "undefined") {
|
|
2538
2764
|
console.log("WebClient: Web Workers are available.");
|
|
2539
2765
|
// Pick between the module and classic worker variants at runtime — see
|
|
2540
2766
|
// `WebClient.workerMode` below. Both branches keep the
|
|
@@ -2575,10 +2801,19 @@ class WebClient {
|
|
|
2575
2801
|
this.loadedResolver = resolve;
|
|
2576
2802
|
});
|
|
2577
2803
|
|
|
2578
|
-
// Create a promise that resolves when the worker signals that it is
|
|
2579
|
-
|
|
2804
|
+
// Create a promise that resolves when the worker signals that it is
|
|
2805
|
+
// fully initialized, and rejects if initialization fails. Every
|
|
2806
|
+
// worker-forwarded method awaits `ready` first, so an init failure must
|
|
2807
|
+
// reject it — otherwise those calls would await a promise that never
|
|
2808
|
+
// settles and hang forever.
|
|
2809
|
+
this.ready = new Promise((resolve, reject) => {
|
|
2580
2810
|
this.readyResolver = resolve;
|
|
2811
|
+
this.readyRejecter = reject;
|
|
2581
2812
|
});
|
|
2813
|
+
// Init can fail before any caller awaits `ready`; this no-op handler
|
|
2814
|
+
// suppresses the unhandledrejection event without consuming the
|
|
2815
|
+
// rejection for real awaiters.
|
|
2816
|
+
this.ready.catch(() => {});
|
|
2582
2817
|
|
|
2583
2818
|
// Listen for messages from the worker.
|
|
2584
2819
|
this.worker.addEventListener("message", async (event) => {
|
|
@@ -2642,14 +2877,33 @@ class WebClient {
|
|
|
2642
2877
|
} else {
|
|
2643
2878
|
resolve(result);
|
|
2644
2879
|
}
|
|
2880
|
+
return;
|
|
2881
|
+
}
|
|
2882
|
+
|
|
2883
|
+
// An error with no request attached comes from worker initialization
|
|
2884
|
+
// (INIT is the only requestId-less action that can fail). Reject
|
|
2885
|
+
// `ready` so queued and future method calls fail with the real cause
|
|
2886
|
+
// instead of awaiting forever.
|
|
2887
|
+
if (error && !requestId) {
|
|
2888
|
+
const workerError =
|
|
2889
|
+
error instanceof Error ? error : deserializeError(error);
|
|
2890
|
+
console.error(
|
|
2891
|
+
"WebClient: worker initialization failed:",
|
|
2892
|
+
workerError
|
|
2893
|
+
);
|
|
2894
|
+
this.readyRejecter(workerError);
|
|
2645
2895
|
}
|
|
2646
2896
|
});
|
|
2647
2897
|
|
|
2648
2898
|
// Once the worker script has loaded, initialize the worker.
|
|
2649
2899
|
this.loaded.then(() => this.initializeWorker());
|
|
2650
2900
|
} else {
|
|
2651
|
-
console.log(
|
|
2652
|
-
|
|
2901
|
+
console.log(
|
|
2902
|
+
this.useWorker
|
|
2903
|
+
? "WebClient: Web Workers are not available."
|
|
2904
|
+
: "WebClient: Web Worker shim disabled by caller (useWorker=false)."
|
|
2905
|
+
);
|
|
2906
|
+
// Worker not available or explicitly disabled; set up fallback values.
|
|
2653
2907
|
this.worker = null;
|
|
2654
2908
|
this.pendingRequests = null;
|
|
2655
2909
|
this.loaded = Promise.resolve();
|
|
@@ -2665,25 +2919,99 @@ class WebClient {
|
|
|
2665
2919
|
// would panic with "recursive use of an object detected" due to
|
|
2666
2920
|
// wasm-bindgen's internal RefCell.
|
|
2667
2921
|
this._wasmCallChain = Promise.resolve();
|
|
2922
|
+
// Depth counter for `_withInnerWebClient` re-entrancy. While > 0,
|
|
2923
|
+
// `_serializeWasmCall` runs its callback inline instead of queueing
|
|
2924
|
+
// it on the chain — see the comment on `_serializeWasmCall` for the
|
|
2925
|
+
// safety contract.
|
|
2926
|
+
this._withInnerLockDepth = 0;
|
|
2668
2927
|
}
|
|
2669
2928
|
|
|
2670
2929
|
/**
|
|
2671
2930
|
* Serialize a WASM call that requires exclusive (&mut self) access.
|
|
2672
2931
|
* Concurrent calls are queued and executed one at a time.
|
|
2673
2932
|
*
|
|
2933
|
+
* Wraps both the direct (in-thread) path and the worker-dispatched path.
|
|
2934
|
+
* On the worker path this is redundant with the worker's own message queue,
|
|
2935
|
+
* but harmless (the chain resolves immediately on the main thread once the
|
|
2936
|
+
* worker's postMessage returns). On the direct path it is load-bearing —
|
|
2937
|
+
* without it, concurrent main-thread callers would panic with
|
|
2938
|
+
* "recursive use of an object detected" (wasm-bindgen's internal RefCell).
|
|
2939
|
+
*
|
|
2940
|
+
* Re-entrancy: when invoked from inside a `_withInnerWebClient(fn)`
|
|
2941
|
+
* callback — detected via `_withInnerLockDepth > 0` — `fn` runs inline
|
|
2942
|
+
* (no chain enqueue). The outer `_withInnerWebClient` invocation
|
|
2943
|
+
* already holds the chain via its own wrapping `_serializeWasmCall`,
|
|
2944
|
+
* so enqueueing the inner call would deadlock (the inner queues
|
|
2945
|
+
* behind the outer; the outer awaits the inner). The inline run is
|
|
2946
|
+
* safe because the chain still serializes against external callers
|
|
2947
|
+
* — they queue behind the outer call's chain slot, which only resolves
|
|
2948
|
+
* after `fn` (including all inline re-entries) settles. Callers of
|
|
2949
|
+
* `_withInnerWebClient` MUST hold an external mutex preventing
|
|
2950
|
+
* concurrent access via other code paths on this same instance during
|
|
2951
|
+
* the callback; without that, an external task running between two
|
|
2952
|
+
* awaits inside `fn` would race wasm-bindgen's borrow check.
|
|
2953
|
+
*
|
|
2674
2954
|
* @param {() => Promise<any>} fn - The async function to execute.
|
|
2675
2955
|
* @returns {Promise<any>} The result of fn.
|
|
2676
2956
|
*/
|
|
2677
2957
|
_serializeWasmCall(fn) {
|
|
2958
|
+
if (this._withInnerLockDepth > 0) {
|
|
2959
|
+
return Promise.resolve().then(fn);
|
|
2960
|
+
}
|
|
2678
2961
|
const result = this._wasmCallChain.catch(() => {}).then(fn);
|
|
2679
2962
|
this._wasmCallChain = result.catch(() => {});
|
|
2680
2963
|
return result;
|
|
2681
2964
|
}
|
|
2682
2965
|
|
|
2966
|
+
/**
|
|
2967
|
+
* Returns a promise that resolves once every serialized WASM call that
|
|
2968
|
+
* was already on `_wasmCallChain` when `waitForIdle()` was called has
|
|
2969
|
+
* settled. Use this from callers that need to perform a non-WASM-side
|
|
2970
|
+
* action (e.g. clear an in-memory auth key) AFTER any in-flight
|
|
2971
|
+
* execute / submit / sync has completed, so the WASM kernel's auth
|
|
2972
|
+
* callback doesn't race with the key being cleared.
|
|
2973
|
+
*
|
|
2974
|
+
* Does NOT wait for calls enqueued after `waitForIdle()` returns —
|
|
2975
|
+
* this is intentional, so a caller can drain and then proceed without
|
|
2976
|
+
* being blocked indefinitely by a concurrent workload.
|
|
2977
|
+
*
|
|
2978
|
+
* Caveat for `syncState`: `syncStateWithTimeout` awaits
|
|
2979
|
+
* `acquireSyncLock` (Web Locks) BEFORE wrapping its WASM call in
|
|
2980
|
+
* `_serializeWasmCall`, so a sync that is queued on the sync lock but
|
|
2981
|
+
* has not yet reached its WASM phase is not on the chain and will not
|
|
2982
|
+
* be awaited. Every other serialized method (`executeTransaction`,
|
|
2983
|
+
* `newWallet`, `submitNewTransaction`, `proveTransaction`,
|
|
2984
|
+
* `applyTransaction`, and the proxy-fallback reads) routes through
|
|
2985
|
+
* the chain synchronously on call and is always observed.
|
|
2986
|
+
*
|
|
2987
|
+
* @returns {Promise<void>}
|
|
2988
|
+
*/
|
|
2989
|
+
async waitForIdle() {
|
|
2990
|
+
// Chain on `_wasmCallChain`; by the time this resolves, any in-flight
|
|
2991
|
+
// serialized call has settled. Catch so the chain state doesn't leak.
|
|
2992
|
+
await this._wasmCallChain.catch(() => {});
|
|
2993
|
+
}
|
|
2994
|
+
|
|
2683
2995
|
// TODO: This will soon conflict with some changes in main.
|
|
2684
2996
|
// More context here:
|
|
2685
2997
|
// https://github.com/0xMiden/miden-client/pull/1645?notification_referrer_id=NT_kwHOA1yg7NoAJVJlcG9zaXRvcnk7NjU5MzQzNzAyO0lzc3VlOzM3OTY4OTU1Nzk¬ifications_query=is%3Aunread#discussion_r2696075480
|
|
2686
2998
|
initializeWorker() {
|
|
2999
|
+
// Pass `numThreads` to the worker so it can call `wasm.initThreadPool(n)`
|
|
3000
|
+
// inside its OWN WASM instance — the SDK worker's instance is separate
|
|
3001
|
+
// from the main thread's, and rayon's global pool is per-instance.
|
|
3002
|
+
// Default: navigator.hardwareConcurrency (or 1 if unavailable for any
|
|
3003
|
+
// reason — e.g. the page isn't crossOriginIsolated, in which case the
|
|
3004
|
+
// worker will skip pool init and parallelism falls back to sequential).
|
|
3005
|
+
let numThreads = 1;
|
|
3006
|
+
try {
|
|
3007
|
+
if (
|
|
3008
|
+
typeof self !== "undefined" &&
|
|
3009
|
+
self.crossOriginIsolated &&
|
|
3010
|
+
navigator?.hardwareConcurrency
|
|
3011
|
+
) {
|
|
3012
|
+
numThreads = navigator.hardwareConcurrency;
|
|
3013
|
+
}
|
|
3014
|
+
} catch {}
|
|
2687
3015
|
this.worker.postMessage({
|
|
2688
3016
|
action: WorkerAction.INIT,
|
|
2689
3017
|
args: [
|
|
@@ -2695,6 +3023,7 @@ class WebClient {
|
|
|
2695
3023
|
!!this.insertKeyCb,
|
|
2696
3024
|
!!this.signCb,
|
|
2697
3025
|
this.logLevel,
|
|
3026
|
+
numThreads,
|
|
2698
3027
|
],
|
|
2699
3028
|
});
|
|
2700
3029
|
}
|
|
@@ -2723,9 +3052,19 @@ class WebClient {
|
|
|
2723
3052
|
* @param {string} seed - The seed for the account.
|
|
2724
3053
|
* @param {string | undefined} network - Optional name for the store. Setting this allows multiple clients to be used in the same browser.
|
|
2725
3054
|
* @param {string | undefined} logLevel - Optional log verbosity level ("error", "warn", "info", "debug", "trace", "off", or "none").
|
|
3055
|
+
* @param {boolean} [useWorker=true] - When `false`, bypass the Web Worker shim
|
|
3056
|
+
* and run WASM calls on the current thread. Required for `CallbackProver`
|
|
3057
|
+
* consumers (the worker path serializes the prover and loses the callback).
|
|
2726
3058
|
* @returns {Promise<WebClient>} The fully initialized WebClient.
|
|
2727
3059
|
*/
|
|
2728
|
-
static async createClient(
|
|
3060
|
+
static async createClient(
|
|
3061
|
+
rpcUrl,
|
|
3062
|
+
noteTransportUrl,
|
|
3063
|
+
seed,
|
|
3064
|
+
network,
|
|
3065
|
+
logLevel,
|
|
3066
|
+
useWorker = true
|
|
3067
|
+
) {
|
|
2729
3068
|
// Construct the instance (synchronously).
|
|
2730
3069
|
const instance = new WebClient(
|
|
2731
3070
|
rpcUrl,
|
|
@@ -2735,7 +3074,8 @@ class WebClient {
|
|
|
2735
3074
|
undefined,
|
|
2736
3075
|
undefined,
|
|
2737
3076
|
undefined,
|
|
2738
|
-
logLevel
|
|
3077
|
+
logLevel,
|
|
3078
|
+
useWorker
|
|
2739
3079
|
);
|
|
2740
3080
|
|
|
2741
3081
|
// Set up logging on the main thread before creating the client.
|
|
@@ -2766,6 +3106,9 @@ class WebClient {
|
|
|
2766
3106
|
* @param {Function | undefined} insertKeyCb - The insert key callback.
|
|
2767
3107
|
* @param {Function | undefined} signCb - The sign callback.
|
|
2768
3108
|
* @param {string | undefined} logLevel - Optional log verbosity level ("error", "warn", "info", "debug", "trace", "off", or "none").
|
|
3109
|
+
* @param {boolean} [useWorker=true] - When `false`, bypass the Web Worker shim
|
|
3110
|
+
* and run WASM calls on the current thread. Required for `CallbackProver`
|
|
3111
|
+
* consumers (the worker path serializes the prover and loses the callback).
|
|
2769
3112
|
* @returns {Promise<WebClient>} The fully initialized WebClient.
|
|
2770
3113
|
*/
|
|
2771
3114
|
static async createClientWithExternalKeystore(
|
|
@@ -2776,7 +3119,8 @@ class WebClient {
|
|
|
2776
3119
|
getKeyCb,
|
|
2777
3120
|
insertKeyCb,
|
|
2778
3121
|
signCb,
|
|
2779
|
-
logLevel
|
|
3122
|
+
logLevel,
|
|
3123
|
+
useWorker = true
|
|
2780
3124
|
) {
|
|
2781
3125
|
// Construct the instance (synchronously).
|
|
2782
3126
|
const instance = new WebClient(
|
|
@@ -2787,7 +3131,8 @@ class WebClient {
|
|
|
2787
3131
|
getKeyCb,
|
|
2788
3132
|
insertKeyCb,
|
|
2789
3133
|
signCb,
|
|
2790
|
-
logLevel
|
|
3134
|
+
logLevel,
|
|
3135
|
+
useWorker
|
|
2791
3136
|
);
|
|
2792
3137
|
|
|
2793
3138
|
// Set up logging on the main thread before creating the client.
|
|
@@ -2852,6 +3197,7 @@ class WebClient {
|
|
|
2852
3197
|
async newFaucet(
|
|
2853
3198
|
storageMode,
|
|
2854
3199
|
nonFungible,
|
|
3200
|
+
tokenName,
|
|
2855
3201
|
tokenSymbol,
|
|
2856
3202
|
decimals,
|
|
2857
3203
|
maxSupply,
|
|
@@ -2862,6 +3208,7 @@ class WebClient {
|
|
|
2862
3208
|
return await wasmWebClient.newFaucet(
|
|
2863
3209
|
storageMode,
|
|
2864
3210
|
nonFungible,
|
|
3211
|
+
tokenName,
|
|
2865
3212
|
tokenSymbol,
|
|
2866
3213
|
decimals,
|
|
2867
3214
|
maxSupply,
|
|
@@ -3029,7 +3376,7 @@ class WebClient {
|
|
|
3029
3376
|
}
|
|
3030
3377
|
|
|
3031
3378
|
/**
|
|
3032
|
-
* Syncs the client
|
|
3379
|
+
* Syncs the client (NTL followed by chain sync, failing fast on either).
|
|
3033
3380
|
*
|
|
3034
3381
|
* This method coordinates concurrent sync calls using the Web Locks API when available,
|
|
3035
3382
|
* with an in-process mutex fallback for older browsers. If a sync is already in progress,
|
|
@@ -3038,58 +3385,76 @@ class WebClient {
|
|
|
3038
3385
|
* @returns {Promise<SyncSummary>} The sync summary
|
|
3039
3386
|
*/
|
|
3040
3387
|
async syncState() {
|
|
3041
|
-
|
|
3388
|
+
const dbId = this.storeName || "default";
|
|
3389
|
+
const methodId = MethodName.SYNC_STATE;
|
|
3390
|
+
|
|
3391
|
+
try {
|
|
3392
|
+
return await withSyncLock(dbId, methodId, async () => {
|
|
3393
|
+
if (!this.worker) {
|
|
3394
|
+
const wasmWebClient = await this.getWasmWebClient();
|
|
3395
|
+
return await wasmWebClient.syncStateImpl();
|
|
3396
|
+
}
|
|
3397
|
+
const wasm = await getWasmOrThrow();
|
|
3398
|
+
const serializedSyncSummaryBytes =
|
|
3399
|
+
await this.callMethodWithWorker(methodId);
|
|
3400
|
+
return wasm.SyncSummary.deserialize(
|
|
3401
|
+
new Uint8Array(serializedSyncSummaryBytes)
|
|
3402
|
+
);
|
|
3403
|
+
});
|
|
3404
|
+
} catch (error) {
|
|
3405
|
+
console.error("INDEX.JS: Error in syncState:", error);
|
|
3406
|
+
throw error;
|
|
3407
|
+
}
|
|
3042
3408
|
}
|
|
3043
3409
|
|
|
3044
3410
|
/**
|
|
3045
|
-
*
|
|
3046
|
-
*
|
|
3047
|
-
* This method coordinates concurrent sync calls using the Web Locks API when available,
|
|
3048
|
-
* with an in-process mutex fallback for older browsers. If a sync is already in progress,
|
|
3049
|
-
* subsequent callers will wait and receive the same result (coalescing behavior).
|
|
3411
|
+
* Fetches private notes from the Note Transport Layer.
|
|
3050
3412
|
*
|
|
3051
|
-
* @
|
|
3052
|
-
* @returns {Promise<SyncSummary>} The sync summary
|
|
3413
|
+
* @returns {Promise<void>}
|
|
3053
3414
|
*/
|
|
3054
|
-
async
|
|
3055
|
-
// Use storeName as the database ID for lock coordination
|
|
3415
|
+
async syncNoteTransport() {
|
|
3056
3416
|
const dbId = this.storeName || "default";
|
|
3417
|
+
const methodId = MethodName.SYNC_NOTE_TRANSPORT;
|
|
3057
3418
|
|
|
3058
3419
|
try {
|
|
3059
|
-
|
|
3060
|
-
const lockHandle = await acquireSyncLock(dbId, timeoutMs);
|
|
3061
|
-
|
|
3062
|
-
if (!lockHandle.acquired) {
|
|
3063
|
-
// We're coalescing - return the result from the in-progress sync
|
|
3064
|
-
return lockHandle.coalescedResult;
|
|
3065
|
-
}
|
|
3066
|
-
|
|
3067
|
-
// We acquired the lock - perform the sync
|
|
3068
|
-
try {
|
|
3069
|
-
let result;
|
|
3420
|
+
await withSyncLock(dbId, methodId, async () => {
|
|
3070
3421
|
if (!this.worker) {
|
|
3071
3422
|
const wasmWebClient = await this.getWasmWebClient();
|
|
3072
|
-
|
|
3423
|
+
await wasmWebClient.syncNoteTransportImpl();
|
|
3073
3424
|
} else {
|
|
3074
|
-
|
|
3075
|
-
const serializedSyncSummaryBytes = await this.callMethodWithWorker(
|
|
3076
|
-
MethodName.SYNC_STATE
|
|
3077
|
-
);
|
|
3078
|
-
result = wasm.SyncSummary.deserialize(
|
|
3079
|
-
new Uint8Array(serializedSyncSummaryBytes)
|
|
3080
|
-
);
|
|
3425
|
+
await this.callMethodWithWorker(methodId);
|
|
3081
3426
|
}
|
|
3427
|
+
});
|
|
3428
|
+
} catch (error) {
|
|
3429
|
+
console.error("INDEX.JS: Error in syncNoteTransport:", error);
|
|
3430
|
+
throw error;
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
3082
3433
|
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3434
|
+
/**
|
|
3435
|
+
* Syncs on-chain state only (no NTL fetch).
|
|
3436
|
+
*
|
|
3437
|
+
* @returns {Promise<SyncSummary>}
|
|
3438
|
+
*/
|
|
3439
|
+
async syncChain() {
|
|
3440
|
+
const dbId = this.storeName || "default";
|
|
3441
|
+
const methodId = MethodName.SYNC_CHAIN;
|
|
3442
|
+
|
|
3443
|
+
try {
|
|
3444
|
+
return await withSyncLock(dbId, methodId, async () => {
|
|
3445
|
+
if (!this.worker) {
|
|
3446
|
+
const wasmWebClient = await this.getWasmWebClient();
|
|
3447
|
+
return await wasmWebClient.syncChainImpl();
|
|
3448
|
+
}
|
|
3449
|
+
const wasm = await getWasmOrThrow();
|
|
3450
|
+
const serializedSyncSummaryBytes =
|
|
3451
|
+
await this.callMethodWithWorker(methodId);
|
|
3452
|
+
return wasm.SyncSummary.deserialize(
|
|
3453
|
+
new Uint8Array(serializedSyncSummaryBytes)
|
|
3454
|
+
);
|
|
3455
|
+
});
|
|
3091
3456
|
} catch (error) {
|
|
3092
|
-
console.error("INDEX.JS: Error in
|
|
3457
|
+
console.error("INDEX.JS: Error in syncChain:", error);
|
|
3093
3458
|
throw error;
|
|
3094
3459
|
}
|
|
3095
3460
|
}
|
|
@@ -3125,9 +3490,23 @@ class MockWebClient extends WebClient {
|
|
|
3125
3490
|
}
|
|
3126
3491
|
|
|
3127
3492
|
initializeWorker() {
|
|
3493
|
+
// Pass `numThreads` exactly like the real INIT path: every prove runs
|
|
3494
|
+
// inside the worker's own WASM instance, and rayon's pool is
|
|
3495
|
+
// per-instance — without this, mock-client proving (including the
|
|
3496
|
+
// integration suite) silently runs single-threaded.
|
|
3497
|
+
let numThreads = 1;
|
|
3498
|
+
try {
|
|
3499
|
+
if (
|
|
3500
|
+
typeof self !== "undefined" &&
|
|
3501
|
+
self.crossOriginIsolated &&
|
|
3502
|
+
navigator?.hardwareConcurrency
|
|
3503
|
+
) {
|
|
3504
|
+
numThreads = navigator.hardwareConcurrency;
|
|
3505
|
+
}
|
|
3506
|
+
} catch {}
|
|
3128
3507
|
this.worker.postMessage({
|
|
3129
3508
|
action: WorkerAction.INIT_MOCK,
|
|
3130
|
-
args: [this.seed, this.logLevel],
|
|
3509
|
+
args: [this.seed, this.logLevel, numThreads],
|
|
3131
3510
|
});
|
|
3132
3511
|
}
|
|
3133
3512
|
|
|
@@ -3178,59 +3557,119 @@ class MockWebClient extends WebClient {
|
|
|
3178
3557
|
* @returns {Promise<SyncSummary>} The sync summary
|
|
3179
3558
|
*/
|
|
3180
3559
|
async syncState() {
|
|
3181
|
-
|
|
3560
|
+
const dbId = this.storeName || "mock";
|
|
3561
|
+
const methodId = MethodName.SYNC_STATE;
|
|
3562
|
+
|
|
3563
|
+
try {
|
|
3564
|
+
return await withSyncLock(dbId, methodId, async () => {
|
|
3565
|
+
const wasmWebClient = await this.getWasmWebClient();
|
|
3566
|
+
|
|
3567
|
+
if (!this.worker) {
|
|
3568
|
+
return await wasmWebClient.syncStateImpl();
|
|
3569
|
+
}
|
|
3570
|
+
|
|
3571
|
+
const serializedMockChain = (await wasmWebClient.serializeMockChain())
|
|
3572
|
+
.buffer;
|
|
3573
|
+
const serializedMockNoteTransportNode = (
|
|
3574
|
+
await wasmWebClient.serializeMockNoteTransportNode()
|
|
3575
|
+
).buffer;
|
|
3576
|
+
|
|
3577
|
+
const wasm = await getWasmOrThrow();
|
|
3578
|
+
const serializedSyncSummaryBytes = await this.callMethodWithWorker(
|
|
3579
|
+
MethodName.SYNC_STATE_MOCK,
|
|
3580
|
+
serializedMockChain,
|
|
3581
|
+
serializedMockNoteTransportNode
|
|
3582
|
+
);
|
|
3583
|
+
return wasm.SyncSummary.deserialize(
|
|
3584
|
+
new Uint8Array(serializedSyncSummaryBytes)
|
|
3585
|
+
);
|
|
3586
|
+
});
|
|
3587
|
+
} catch (error) {
|
|
3588
|
+
console.error("INDEX.JS: Error in syncState:", error);
|
|
3589
|
+
throw error;
|
|
3590
|
+
}
|
|
3182
3591
|
}
|
|
3183
3592
|
|
|
3184
3593
|
/**
|
|
3185
|
-
* Syncs the mock
|
|
3594
|
+
* Syncs only the on-chain mock state (no note transport fetch).
|
|
3186
3595
|
*
|
|
3187
|
-
*
|
|
3188
|
-
*
|
|
3596
|
+
* In worker mode, the main-thread mock chain + note-transport-node state
|
|
3597
|
+
* is serialized and shipped to the worker before the sync, so a prior
|
|
3598
|
+
* `proveBlock()` on the main thread is reflected in the worker's WASM
|
|
3599
|
+
* client. The no-worker path uses the main-thread WASM client directly.
|
|
3600
|
+
*
|
|
3601
|
+
* @returns {Promise<SyncSummary>}
|
|
3189
3602
|
*/
|
|
3190
|
-
async
|
|
3603
|
+
async syncChain() {
|
|
3191
3604
|
const dbId = this.storeName || "mock";
|
|
3605
|
+
const methodId = MethodName.SYNC_CHAIN;
|
|
3192
3606
|
|
|
3193
3607
|
try {
|
|
3194
|
-
|
|
3608
|
+
return await withSyncLock(dbId, methodId, async () => {
|
|
3609
|
+
const wasmWebClient = await this.getWasmWebClient();
|
|
3195
3610
|
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3611
|
+
if (!this.worker) {
|
|
3612
|
+
return await wasmWebClient.syncChainImpl();
|
|
3613
|
+
}
|
|
3199
3614
|
|
|
3200
|
-
|
|
3201
|
-
|
|
3615
|
+
const serializedMockChain = (await wasmWebClient.serializeMockChain())
|
|
3616
|
+
.buffer;
|
|
3617
|
+
const serializedMockNoteTransportNode = (
|
|
3618
|
+
await wasmWebClient.serializeMockNoteTransportNode()
|
|
3619
|
+
).buffer;
|
|
3620
|
+
|
|
3621
|
+
const wasm = await getWasmOrThrow();
|
|
3622
|
+
const serializedSyncSummaryBytes = await this.callMethodWithWorker(
|
|
3623
|
+
MethodName.SYNC_CHAIN_MOCK,
|
|
3624
|
+
serializedMockChain,
|
|
3625
|
+
serializedMockNoteTransportNode
|
|
3626
|
+
);
|
|
3627
|
+
return wasm.SyncSummary.deserialize(
|
|
3628
|
+
new Uint8Array(serializedSyncSummaryBytes)
|
|
3629
|
+
);
|
|
3630
|
+
});
|
|
3631
|
+
} catch (error) {
|
|
3632
|
+
console.error("INDEX.JS: Error in syncChain:", error);
|
|
3633
|
+
throw error;
|
|
3634
|
+
}
|
|
3635
|
+
}
|
|
3636
|
+
|
|
3637
|
+
/**
|
|
3638
|
+
* Syncs only the mock note-transport state (no chain fetch).
|
|
3639
|
+
*
|
|
3640
|
+
* Mirrors {@link MockWebClient#syncChain}: in worker mode, the
|
|
3641
|
+
* main-thread mock chain + note-transport-node state is serialized
|
|
3642
|
+
* and shipped to the worker first.
|
|
3643
|
+
*
|
|
3644
|
+
* @returns {Promise<void>}
|
|
3645
|
+
*/
|
|
3646
|
+
async syncNoteTransport() {
|
|
3647
|
+
const dbId = this.storeName || "mock";
|
|
3648
|
+
const methodId = MethodName.SYNC_NOTE_TRANSPORT;
|
|
3649
|
+
|
|
3650
|
+
try {
|
|
3651
|
+
await withSyncLock(dbId, methodId, async () => {
|
|
3202
3652
|
const wasmWebClient = await this.getWasmWebClient();
|
|
3203
3653
|
|
|
3204
3654
|
if (!this.worker) {
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
let serializedMockChain = (await wasmWebClient.serializeMockChain())
|
|
3208
|
-
.buffer;
|
|
3209
|
-
let serializedMockNoteTransportNode = (
|
|
3210
|
-
await wasmWebClient.serializeMockNoteTransportNode()
|
|
3211
|
-
).buffer;
|
|
3212
|
-
|
|
3213
|
-
const wasm = await getWasmOrThrow();
|
|
3214
|
-
|
|
3215
|
-
const serializedSyncSummaryBytes = await this.callMethodWithWorker(
|
|
3216
|
-
MethodName.SYNC_STATE_MOCK,
|
|
3217
|
-
serializedMockChain,
|
|
3218
|
-
serializedMockNoteTransportNode
|
|
3219
|
-
);
|
|
3220
|
-
|
|
3221
|
-
result = wasm.SyncSummary.deserialize(
|
|
3222
|
-
new Uint8Array(serializedSyncSummaryBytes)
|
|
3223
|
-
);
|
|
3655
|
+
await wasmWebClient.syncNoteTransportImpl();
|
|
3656
|
+
return;
|
|
3224
3657
|
}
|
|
3225
3658
|
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3659
|
+
const serializedMockChain = (await wasmWebClient.serializeMockChain())
|
|
3660
|
+
.buffer;
|
|
3661
|
+
const serializedMockNoteTransportNode = (
|
|
3662
|
+
await wasmWebClient.serializeMockNoteTransportNode()
|
|
3663
|
+
).buffer;
|
|
3664
|
+
|
|
3665
|
+
await this.callMethodWithWorker(
|
|
3666
|
+
MethodName.SYNC_NOTE_TRANSPORT_MOCK,
|
|
3667
|
+
serializedMockChain,
|
|
3668
|
+
serializedMockNoteTransportNode
|
|
3669
|
+
);
|
|
3670
|
+
});
|
|
3232
3671
|
} catch (error) {
|
|
3233
|
-
console.error("INDEX.JS: Error in
|
|
3672
|
+
console.error("INDEX.JS: Error in syncNoteTransport:", error);
|
|
3234
3673
|
throw error;
|
|
3235
3674
|
}
|
|
3236
3675
|
}
|
|
@@ -3368,5 +3807,5 @@ MidenClient._MockWasmWebClient = MockWebClient;
|
|
|
3368
3807
|
MidenClient._getWasmOrThrow = getWasmOrThrow;
|
|
3369
3808
|
_setWebClient(WebClient);
|
|
3370
3809
|
|
|
3371
|
-
export { AccountType, AuthScheme, CompilerResource, Linking, MidenArrays, MidenClient, MockWebClient as MockWasmWebClient, MockWebClient, NoteVisibility, StorageMode, StorageResult, StorageView, WebClient as WasmWebClient, buildSwapTag, createP2IDENote, createP2IDNote, getWasmOrThrow, wordToBigInt };
|
|
3810
|
+
export { AccountType, AuthScheme, CompilerResource, Linking, MidenArrays, MidenClient, MockWebClient as MockWasmWebClient, MockWebClient, NoteVisibility, StorageMode, StorageResult, StorageView, WebClient as WasmWebClient, buildSwapTag, createP2IDENote, createP2IDNote, getWasmOrThrow, withSyncLock, wordToBigInt };
|
|
3372
3811
|
//# sourceMappingURL=index.js.map
|