@aztec/txe 3.0.0-nightly.20250926 → 3.0.0-nightly.20250928

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.
@@ -1,462 +0,0 @@
1
- import { L1_TO_L2_MSG_TREE_HEIGHT } from '@aztec/constants';
2
- import { Aes128 } from '@aztec/foundation/crypto';
3
- import { Fr, Point } from '@aztec/foundation/fields';
4
- import { type Logger, applyStringFormatting, createLogger } from '@aztec/foundation/log';
5
- import { PXEOracleInterface } from '@aztec/pxe/server';
6
- import {
7
- ExecutionNoteCache,
8
- HashedValuesCache,
9
- type IPrivateExecutionOracle,
10
- type IUtilityExecutionOracle,
11
- MessageLoadOracleInputs,
12
- type NoteData,
13
- UtilityContext,
14
- pickNotes,
15
- } from '@aztec/pxe/simulator';
16
- import type { FunctionSelector, NoteSelector } from '@aztec/stdlib/abi';
17
- import { AztecAddress } from '@aztec/stdlib/aztec-address';
18
- import { Body, L2Block } from '@aztec/stdlib/block';
19
- import type { ContractInstance } from '@aztec/stdlib/contract';
20
- import { computeNoteHashNonce, computeUniqueNoteHash, siloNoteHash, siloNullifier } from '@aztec/stdlib/hash';
21
- import type { MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
22
- import type { KeyValidationRequest } from '@aztec/stdlib/kernel';
23
- import { ContractClassLog, IndexedTaggingSecret } from '@aztec/stdlib/logs';
24
- import { Note, type NoteStatus } from '@aztec/stdlib/note';
25
- import { makeAppendOnlyTreeSnapshot } from '@aztec/stdlib/testing';
26
- import { MerkleTreeId, NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees';
27
- import { BlockHeader, GlobalVariables, TxEffect, TxHash } from '@aztec/stdlib/tx';
28
-
29
- import { insertTxEffectIntoWorldTrees, makeTXEBlockHeader } from '../utils/block_creation.js';
30
-
31
- export class TXE implements IUtilityExecutionOracle, IPrivateExecutionOracle {
32
- isMisc = true as const;
33
- isUtility = true as const;
34
- isPrivate = true as const;
35
-
36
- private logger: Logger;
37
-
38
- private executionCache = new HashedValuesCache();
39
- private senderForTags?: AztecAddress;
40
-
41
- public noteCache: ExecutionNoteCache;
42
-
43
- private constructor(
44
- private contractAddress: AztecAddress,
45
- private pxeOracleInterface: PXEOracleInterface,
46
- private forkedWorldTrees: MerkleTreeWriteOperations,
47
- private anchorBlockGlobalVariables: GlobalVariables,
48
- private nextBlockGlobalVariables: GlobalVariables,
49
- private txRequestHash: Fr,
50
- ) {
51
- this.logger = createLogger('txe:oracle');
52
- this.logger.debug('Entering Private/Utility context');
53
-
54
- this.noteCache = new ExecutionNoteCache(txRequestHash);
55
- }
56
-
57
- static async create(
58
- contractAddress: AztecAddress,
59
- pxeOracleInterface: PXEOracleInterface,
60
- forkedWorldTrees: MerkleTreeWriteOperations,
61
- anchorBlockGlobalVariables: GlobalVariables,
62
- nextBlockGlobalVariables: GlobalVariables,
63
- txRequestHash: Fr,
64
- ) {
65
- // There is no automatic message discovery and contract-driven syncing process in inlined private or utility
66
- // contexts, which means that known nullifiers are also not searched for, since it is during the tagging sync that
67
- // we perform this. We therefore search for known nullifiers now, as otherwise notes that were nullified would not
68
- // be removed from the database.
69
- await pxeOracleInterface.removeNullifiedNotes(contractAddress);
70
-
71
- return new TXE(
72
- contractAddress,
73
- pxeOracleInterface,
74
- forkedWorldTrees,
75
- anchorBlockGlobalVariables,
76
- nextBlockGlobalVariables,
77
- txRequestHash,
78
- );
79
- }
80
-
81
- // Utils
82
-
83
- async checkNullifiersNotInTree(contractAddress: AztecAddress, nullifiers: Fr[]) {
84
- const siloedNullifiers = await Promise.all(nullifiers.map(nullifier => siloNullifier(contractAddress, nullifier)));
85
- const db = this.forkedWorldTrees;
86
- const nullifierIndexesInTree = await db.findLeafIndices(
87
- MerkleTreeId.NULLIFIER_TREE,
88
- siloedNullifiers.map(n => n.toBuffer()),
89
- );
90
- if (nullifierIndexesInTree.some(index => index !== undefined)) {
91
- throw new Error(`Rejecting tx for emitting duplicate nullifiers`);
92
- }
93
- }
94
-
95
- utilityGetRandomField() {
96
- return Fr.random();
97
- }
98
-
99
- utilityGetUtilityContext() {
100
- return Promise.resolve(
101
- UtilityContext.from({
102
- blockNumber: this.anchorBlockGlobalVariables.blockNumber,
103
- timestamp: this.anchorBlockGlobalVariables.timestamp,
104
- contractAddress: this.contractAddress,
105
- version: this.anchorBlockGlobalVariables.version,
106
- chainId: this.anchorBlockGlobalVariables.chainId,
107
- }),
108
- );
109
- }
110
-
111
- privateStoreInExecutionCache(values: Fr[], hash: Fr) {
112
- return this.executionCache.store(values, hash);
113
- }
114
-
115
- privateLoadFromExecutionCache(hash: Fr) {
116
- const preimage = this.executionCache.getPreimage(hash);
117
- if (!preimage) {
118
- throw new Error(`Preimage for hash ${hash.toString()} not found in cache`);
119
- }
120
- return Promise.resolve(preimage);
121
- }
122
-
123
- utilityGetKeyValidationRequest(pkMHash: Fr): Promise<KeyValidationRequest> {
124
- return this.pxeOracleInterface.getKeyValidationRequest(pkMHash, this.contractAddress);
125
- }
126
-
127
- utilityGetContractInstance(address: AztecAddress): Promise<ContractInstance> {
128
- return this.pxeOracleInterface.getContractInstance(address);
129
- }
130
-
131
- utilityGetMembershipWitness(blockNumber: number, treeId: MerkleTreeId, leafValue: Fr): Promise<Fr[] | undefined> {
132
- return this.pxeOracleInterface.getMembershipWitness(blockNumber, treeId, leafValue);
133
- }
134
-
135
- utilityGetNullifierMembershipWitness(
136
- blockNumber: number,
137
- nullifier: Fr,
138
- ): Promise<NullifierMembershipWitness | undefined> {
139
- return this.pxeOracleInterface.getNullifierMembershipWitness(blockNumber, nullifier);
140
- }
141
-
142
- utilityGetPublicDataWitness(blockNumber: number, leafSlot: Fr): Promise<PublicDataWitness | undefined> {
143
- return this.pxeOracleInterface.getPublicDataWitness(blockNumber, leafSlot);
144
- }
145
-
146
- utilityGetLowNullifierMembershipWitness(
147
- blockNumber: number,
148
- nullifier: Fr,
149
- ): Promise<NullifierMembershipWitness | undefined> {
150
- return this.pxeOracleInterface.getLowNullifierMembershipWitness(blockNumber, nullifier);
151
- }
152
-
153
- async utilityGetBlockHeader(blockNumber: number): Promise<BlockHeader | undefined> {
154
- return (await this.pxeOracleInterface.getBlock(blockNumber))?.header.toBlockHeader();
155
- }
156
-
157
- utilityGetPublicKeysAndPartialAddress(account: AztecAddress) {
158
- return this.pxeOracleInterface.getCompleteAddress(account);
159
- }
160
-
161
- async utilityGetNotes(
162
- storageSlot: Fr,
163
- numSelects: number,
164
- selectByIndexes: number[],
165
- selectByOffsets: number[],
166
- selectByLengths: number[],
167
- selectValues: Fr[],
168
- selectComparators: number[],
169
- sortByIndexes: number[],
170
- sortByOffsets: number[],
171
- sortByLengths: number[],
172
- sortOrder: number[],
173
- limit: number,
174
- offset: number,
175
- status: NoteStatus,
176
- ) {
177
- // Nullified pending notes are already removed from the list.
178
- const pendingNotes = this.noteCache.getNotes(this.contractAddress, storageSlot);
179
-
180
- const pendingNullifiers = this.noteCache.getNullifiers(this.contractAddress);
181
- const dbNotes = await this.pxeOracleInterface.getNotes(this.contractAddress, storageSlot, status);
182
- const dbNotesFiltered = dbNotes.filter(n => !pendingNullifiers.has((n.siloedNullifier as Fr).value));
183
-
184
- const notes = pickNotes<NoteData>([...dbNotesFiltered, ...pendingNotes], {
185
- selects: selectByIndexes.slice(0, numSelects).map((index, i) => ({
186
- selector: { index, offset: selectByOffsets[i], length: selectByLengths[i] },
187
- value: selectValues[i],
188
- comparator: selectComparators[i],
189
- })),
190
- sorts: sortByIndexes.map((index, i) => ({
191
- selector: { index, offset: sortByOffsets[i], length: sortByLengths[i] },
192
- order: sortOrder[i],
193
- })),
194
- limit,
195
- offset,
196
- });
197
-
198
- this.logger.debug(
199
- `Returning ${notes.length} notes for ${this.contractAddress} at ${storageSlot}: ${notes
200
- .map(n => `${n.noteNonce.toString()}:[${n.note.items.map(i => i.toString()).join(',')}]`)
201
- .join(', ')}`,
202
- );
203
-
204
- if (notes.length > 0) {
205
- const noteLength = notes[0].note.items.length;
206
- if (!notes.every(({ note }) => noteLength === note.items.length)) {
207
- throw new Error('Notes should all be the same length.');
208
- }
209
- }
210
-
211
- return notes;
212
- }
213
-
214
- privateNotifyCreatedNote(storageSlot: Fr, _noteTypeId: NoteSelector, noteItems: Fr[], noteHash: Fr, counter: number) {
215
- const note = new Note(noteItems);
216
- this.noteCache.addNewNote(
217
- {
218
- contractAddress: this.contractAddress,
219
- storageSlot,
220
- noteNonce: Fr.ZERO, // Nonce cannot be known during private execution.
221
- note,
222
- siloedNullifier: undefined, // Siloed nullifier cannot be known for newly created note.
223
- noteHash,
224
- },
225
- counter,
226
- );
227
- }
228
-
229
- async privateNotifyNullifiedNote(innerNullifier: Fr, noteHash: Fr, _counter: number) {
230
- await this.checkNullifiersNotInTree(this.contractAddress, [innerNullifier]);
231
- await this.noteCache.nullifyNote(this.contractAddress, innerNullifier, noteHash);
232
- }
233
-
234
- async privateNotifyCreatedNullifier(innerNullifier: Fr): Promise<void> {
235
- await this.checkNullifiersNotInTree(this.contractAddress, [innerNullifier]);
236
- await this.noteCache.nullifierCreated(this.contractAddress, innerNullifier);
237
- }
238
-
239
- async utilityCheckNullifierExists(innerNullifier: Fr): Promise<boolean> {
240
- const nullifier = await siloNullifier(this.contractAddress, innerNullifier!);
241
- const index = await this.pxeOracleInterface.getNullifierIndex(nullifier);
242
- return index !== undefined;
243
- }
244
-
245
- async utilityStorageRead(
246
- contractAddress: AztecAddress,
247
- startStorageSlot: Fr,
248
- blockNumber: number,
249
- numberOfElements: number,
250
- ): Promise<Fr[]> {
251
- const values = [];
252
- for (let i = 0n; i < numberOfElements; i++) {
253
- const storageSlot = startStorageSlot.add(new Fr(i));
254
- const value = await this.pxeOracleInterface.getPublicStorageAt(blockNumber, contractAddress, storageSlot);
255
- values.push(value);
256
- }
257
- return values;
258
- }
259
-
260
- utilityDebugLog(message: string, fields: Fr[]): void {
261
- this.logger.verbose(`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
262
- }
263
-
264
- async privateIncrementAppTaggingSecretIndexAsSender(sender: AztecAddress, recipient: AztecAddress): Promise<void> {
265
- await this.pxeOracleInterface.incrementAppTaggingSecretIndexAsSender(this.contractAddress, sender, recipient);
266
- }
267
-
268
- async utilityGetIndexedTaggingSecretAsSender(
269
- sender: AztecAddress,
270
- recipient: AztecAddress,
271
- ): Promise<IndexedTaggingSecret> {
272
- return await this.pxeOracleInterface.getIndexedTaggingSecretAsSender(this.contractAddress, sender, recipient);
273
- }
274
-
275
- async utilityFetchTaggedLogs(pendingTaggedLogArrayBaseSlot: Fr) {
276
- await this.pxeOracleInterface.syncTaggedLogs(this.contractAddress, pendingTaggedLogArrayBaseSlot);
277
-
278
- await this.pxeOracleInterface.removeNullifiedNotes(this.contractAddress);
279
-
280
- return Promise.resolve();
281
- }
282
-
283
- public async utilityValidateEnqueuedNotesAndEvents(
284
- contractAddress: AztecAddress,
285
- noteValidationRequestsArrayBaseSlot: Fr,
286
- eventValidationRequestsArrayBaseSlot: Fr,
287
- ): Promise<void> {
288
- await this.pxeOracleInterface.validateEnqueuedNotesAndEvents(
289
- contractAddress,
290
- noteValidationRequestsArrayBaseSlot,
291
- eventValidationRequestsArrayBaseSlot,
292
- );
293
- }
294
-
295
- async utilityBulkRetrieveLogs(
296
- contractAddress: AztecAddress,
297
- logRetrievalRequestsArrayBaseSlot: Fr,
298
- logRetrievalResponsesArrayBaseSlot: Fr,
299
- ): Promise<void> {
300
- return await this.pxeOracleInterface.bulkRetrieveLogs(
301
- contractAddress,
302
- logRetrievalRequestsArrayBaseSlot,
303
- logRetrievalResponsesArrayBaseSlot,
304
- );
305
- }
306
-
307
- utilityStoreCapsule(contractAddress: AztecAddress, slot: Fr, capsule: Fr[]): Promise<void> {
308
- if (!contractAddress.equals(this.contractAddress)) {
309
- // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
310
- throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
311
- }
312
- return this.pxeOracleInterface.storeCapsule(this.contractAddress, slot, capsule);
313
- }
314
-
315
- utilityLoadCapsule(contractAddress: AztecAddress, slot: Fr): Promise<Fr[] | null> {
316
- if (!contractAddress.equals(this.contractAddress)) {
317
- // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
318
- throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
319
- }
320
- return this.pxeOracleInterface.loadCapsule(this.contractAddress, slot);
321
- }
322
-
323
- utilityDeleteCapsule(contractAddress: AztecAddress, slot: Fr): Promise<void> {
324
- if (!contractAddress.equals(this.contractAddress)) {
325
- // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
326
- throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
327
- }
328
- return this.pxeOracleInterface.deleteCapsule(this.contractAddress, slot);
329
- }
330
-
331
- utilityCopyCapsule(contractAddress: AztecAddress, srcSlot: Fr, dstSlot: Fr, numEntries: number): Promise<void> {
332
- if (!contractAddress.equals(this.contractAddress)) {
333
- // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
334
- throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
335
- }
336
- return this.pxeOracleInterface.copyCapsule(this.contractAddress, srcSlot, dstSlot, numEntries);
337
- }
338
-
339
- utilityAes128Decrypt(ciphertext: Buffer, iv: Buffer, symKey: Buffer): Promise<Buffer> {
340
- const aes128 = new Aes128();
341
- return aes128.decryptBufferCBC(ciphertext, iv, symKey);
342
- }
343
-
344
- utilityGetSharedSecret(address: AztecAddress, ephPk: Point): Promise<Point> {
345
- return this.pxeOracleInterface.getSharedSecret(address, ephPk);
346
- }
347
-
348
- privateGetSenderForTags(): Promise<AztecAddress | undefined> {
349
- return Promise.resolve(this.senderForTags);
350
- }
351
-
352
- privateSetSenderForTags(senderForTags: AztecAddress): Promise<void> {
353
- this.senderForTags = senderForTags;
354
- return Promise.resolve();
355
- }
356
-
357
- async close(): Promise<L2Block> {
358
- this.logger.debug('Exiting Private Context, building block with collected side effects', {
359
- blockNumber: this.nextBlockGlobalVariables.blockNumber,
360
- });
361
-
362
- const txEffect = await this.makeTxEffect();
363
-
364
- await insertTxEffectIntoWorldTrees(txEffect, this.forkedWorldTrees);
365
-
366
- const block = new L2Block(
367
- makeAppendOnlyTreeSnapshot(),
368
- await makeTXEBlockHeader(this.forkedWorldTrees, this.nextBlockGlobalVariables),
369
- new Body([txEffect]),
370
- );
371
-
372
- await this.forkedWorldTrees.close();
373
-
374
- this.logger.debug('Exited PublicContext with built block', {
375
- blockNumber: block.number,
376
- txEffects: block.body.txEffects,
377
- });
378
-
379
- return block;
380
- }
381
-
382
- private async makeTxEffect(): Promise<TxEffect> {
383
- const txEffect = TxEffect.empty();
384
-
385
- const { usedTxRequestHashForNonces } = this.noteCache.finish();
386
- const nonceGenerator = usedTxRequestHashForNonces ? this.txRequestHash : this.noteCache.getAllNullifiers()[0];
387
-
388
- txEffect.noteHashes = await Promise.all(
389
- this.noteCache
390
- .getAllNotes()
391
- .map(async (pendingNote, i) =>
392
- computeUniqueNoteHash(
393
- await computeNoteHashNonce(nonceGenerator, i),
394
- await siloNoteHash(pendingNote.note.contractAddress, pendingNote.noteHashForConsumption),
395
- ),
396
- ),
397
- );
398
-
399
- // Nullifiers are already siloed
400
- txEffect.nullifiers = this.noteCache.getAllNullifiers();
401
-
402
- if (usedTxRequestHashForNonces) {
403
- txEffect.nullifiers.unshift(this.txRequestHash);
404
- }
405
-
406
- txEffect.txHash = new TxHash(new Fr(this.nextBlockGlobalVariables.blockNumber));
407
-
408
- return txEffect;
409
- }
410
-
411
- // TODO: this class will soon be replaced with the real UtilityExecutionOracle and PrivateExecutionOracle classes. The
412
- // functions below are not currently used in Noir tests, and in most cases they're caught beforehand by the RPC
413
- // translator - we just have a temporary empty implementation until we finalize the migration.
414
-
415
- utilityAssertCompatibleOracleVersion(_version: number): void {
416
- throw new Error('Method not implemented.');
417
- }
418
- utilityGetAuthWitness(_messageHash: Fr): Promise<Fr[] | undefined> {
419
- throw new Error('Method not implemented.');
420
- }
421
- utilityGetL1ToL2MembershipWitness(
422
- _contractAddress: AztecAddress,
423
- _messageHash: Fr,
424
- _secret: Fr,
425
- ): Promise<MessageLoadOracleInputs<typeof L1_TO_L2_MSG_TREE_HEIGHT>> {
426
- throw new Error('Method not implemented.');
427
- }
428
- utilityEmitOffchainEffect(_data: Fr[]): Promise<void> {
429
- throw new Error('Method not implemented.');
430
- }
431
- privateNotifyCreatedContractClassLog(_log: ContractClassLog, _counter: number): void {
432
- throw new Error('Method not implemented.');
433
- }
434
- privateCallPrivateFunction(
435
- _targetContractAddress: AztecAddress,
436
- _functionSelector: FunctionSelector,
437
- _argsHash: Fr,
438
- _sideEffectCounter: number,
439
- _isStaticCall: boolean,
440
- ): Promise<{ endSideEffectCounter: Fr; returnsHash: Fr }> {
441
- throw new Error('Method not implemented.');
442
- }
443
- privateNotifyEnqueuedPublicFunctionCall(
444
- _targetContractAddress: AztecAddress,
445
- _calldataHash: Fr,
446
- _sideEffectCounter: number,
447
- _isStaticCall: boolean,
448
- ): Promise<void> {
449
- throw new Error('Method not implemented.');
450
- }
451
- privateNotifySetPublicTeardownFunctionCall(
452
- _targetContractAddress: AztecAddress,
453
- _calldataHash: Fr,
454
- _sideEffectCounter: number,
455
- _isStaticCall: boolean,
456
- ): Promise<void> {
457
- throw new Error('Method not implemented.');
458
- }
459
- privateNotifySetMinRevertibleSideEffectCounter(_minRevertibleSideEffectCounter: number): Promise<void> {
460
- throw new Error('Method not implemented.');
461
- }
462
- }