@aztec/txe 0.47.1 → 0.49.2

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.
@@ -68,6 +68,7 @@ import {
68
68
  toACVMWitness,
69
69
  witnessMapToFields,
70
70
  } from '@aztec/simulator';
71
+ import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
71
72
  import { type ContractInstance, type ContractInstanceWithAddress } from '@aztec/types/contracts';
72
73
  import { MerkleTreeSnapshotOperationsFacade, type MerkleTrees } from '@aztec/world-state';
73
74
 
@@ -103,6 +104,14 @@ export class TXE implements TypedOracle {
103
104
 
104
105
  // Utils
105
106
 
107
+ async #getTreesAt(blockNumber: number) {
108
+ const db =
109
+ blockNumber === (await this.getBlockNumber())
110
+ ? this.trees.asLatest()
111
+ : new MerkleTreeSnapshotOperationsFacade(this.trees, blockNumber);
112
+ return db;
113
+ }
114
+
106
115
  getChainId() {
107
116
  return Promise.resolve(this.chainId);
108
117
  }
@@ -174,11 +183,16 @@ export class TXE implements TypedOracle {
174
183
  isStaticCall = false,
175
184
  isDelegateCall = false,
176
185
  ) {
177
- const trees = this.getTrees();
178
- const stateReference = await trees.getStateReference(false);
186
+ const db = await this.#getTreesAt(blockNumber);
187
+ const previousBlockState = await this.#getTreesAt(blockNumber - 1);
188
+
189
+ const stateReference = await db.getStateReference();
179
190
  const inputs = PrivateContextInputs.empty();
180
191
  inputs.historicalHeader.globalVariables.blockNumber = new Fr(blockNumber);
181
192
  inputs.historicalHeader.state = stateReference;
193
+ inputs.historicalHeader.lastArchive.root = Fr.fromBuffer(
194
+ (await previousBlockState.getTreeInfo(MerkleTreeId.ARCHIVE)).root,
195
+ );
182
196
  inputs.callContext.msgSender = this.msgSender;
183
197
  inputs.callContext.storageContractAddress = this.contractAddress;
184
198
  inputs.callContext.isStaticCall = isStaticCall;
@@ -213,10 +227,10 @@ export class TXE implements TypedOracle {
213
227
  return Promise.resolve();
214
228
  }
215
229
 
216
- async avmOpcodeEmitNoteHash(innerNoteHash: Fr) {
230
+ async avmOpcodeEmitNoteHash(noteHash: Fr) {
217
231
  const db = this.trees.asLatest();
218
- const noteHash = siloNoteHash(this.contractAddress, innerNoteHash);
219
- await db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, [noteHash]);
232
+ const siloedNoteHash = siloNoteHash(this.contractAddress, noteHash);
233
+ await db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, [siloedNoteHash]);
220
234
  return Promise.resolve();
221
235
  }
222
236
 
@@ -240,9 +254,9 @@ export class TXE implements TypedOracle {
240
254
  await db.batchInsert(MerkleTreeId.NULLIFIER_TREE, siloedNullifiers, NULLIFIER_SUBTREE_HEIGHT);
241
255
  }
242
256
 
243
- async addNoteHashes(contractAddress: AztecAddress, innerNoteHashes: Fr[]) {
257
+ async addNoteHashes(contractAddress: AztecAddress, noteHashes: Fr[]) {
244
258
  const db = this.trees.asLatest();
245
- const siloedNoteHashes = innerNoteHashes.map(innerNoteHash => siloNoteHash(contractAddress, innerNoteHash));
259
+ const siloedNoteHashes = noteHashes.map(noteHash => siloNoteHash(contractAddress, noteHash));
246
260
  await db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, siloedNoteHashes);
247
261
  }
248
262
 
@@ -284,8 +298,14 @@ export class TXE implements TypedOracle {
284
298
  return contractInstance;
285
299
  }
286
300
 
287
- getMembershipWitness(_blockNumber: number, _treeId: MerkleTreeId, _leafValue: Fr): Promise<Fr[] | undefined> {
288
- throw new Error('Method not implemented.');
301
+ async getMembershipWitness(blockNumber: number, treeId: MerkleTreeId, leafValue: Fr): Promise<Fr[] | undefined> {
302
+ const db = await this.#getTreesAt(blockNumber);
303
+ const index = await db.findLeafIndex(treeId, leafValue.toBuffer());
304
+ if (!index) {
305
+ throw new Error(`Leaf value: ${leafValue} not found in ${MerkleTreeId[treeId]} at block ${blockNumber}`);
306
+ }
307
+ const siblingPath = await db.getSiblingPath(treeId, index);
308
+ return [new Fr(index), ...siblingPath.toFields()];
289
309
  }
290
310
 
291
311
  async getSiblingPath(blockNumber: number, treeId: MerkleTreeId, leafIndex: Fr) {
@@ -298,14 +318,14 @@ export class TXE implements TypedOracle {
298
318
  blockNumber: number,
299
319
  nullifier: Fr,
300
320
  ): Promise<NullifierMembershipWitness | undefined> {
301
- const committedDb = new MerkleTreeSnapshotOperationsFacade(this.trees, blockNumber);
302
- const index = await committedDb.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
321
+ const db = await this.#getTreesAt(blockNumber);
322
+ const index = await db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
303
323
  if (!index) {
304
324
  return undefined;
305
325
  }
306
326
 
307
- const leafPreimagePromise = committedDb.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index);
308
- const siblingPathPromise = committedDb.getSiblingPath<typeof NULLIFIER_TREE_HEIGHT>(
327
+ const leafPreimagePromise = db.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index);
328
+ const siblingPathPromise = db.getSiblingPath<typeof NULLIFIER_TREE_HEIGHT>(
309
329
  MerkleTreeId.NULLIFIER_TREE,
310
330
  BigInt(index),
311
331
  );
@@ -344,8 +364,12 @@ export class TXE implements TypedOracle {
344
364
  throw new Error('Method not implemented.');
345
365
  }
346
366
 
347
- getHeader(_blockNumber: number): Promise<Header | undefined> {
348
- throw new Error('Method not implemented.');
367
+ async getHeader(blockNumber: number): Promise<Header | undefined> {
368
+ const header = Header.empty();
369
+ const db = await this.#getTreesAt(blockNumber);
370
+ header.state = await db.getStateReference();
371
+ header.globalVariables.blockNumber = new Fr(blockNumber);
372
+ return header;
349
373
  }
350
374
 
351
375
  getCompleteAddress(account: AztecAddress) {
@@ -402,7 +426,7 @@ export class TXE implements TypedOracle {
402
426
  return Promise.resolve(notes);
403
427
  }
404
428
 
405
- notifyCreatedNote(storageSlot: Fr, noteTypeId: NoteSelector, noteItems: Fr[], innerNoteHash: Fr, counter: number) {
429
+ notifyCreatedNote(storageSlot: Fr, noteTypeId: NoteSelector, noteItems: Fr[], noteHash: Fr, counter: number) {
406
430
  const note = new Note(noteItems);
407
431
  this.noteCache.addNewNote(
408
432
  {
@@ -411,15 +435,17 @@ export class TXE implements TypedOracle {
411
435
  nonce: Fr.ZERO, // Nonce cannot be known during private execution.
412
436
  note,
413
437
  siloedNullifier: undefined, // Siloed nullifier cannot be known for newly created note.
414
- innerNoteHash,
438
+ noteHash,
415
439
  },
416
440
  counter,
417
441
  );
442
+ this.sideEffectsCounter = counter + 1;
418
443
  return Promise.resolve();
419
444
  }
420
445
 
421
- notifyNullifiedNote(innerNullifier: Fr, innerNoteHash: Fr, _counter: number) {
422
- this.noteCache.nullifyNote(this.contractAddress, innerNullifier, innerNoteHash);
446
+ notifyNullifiedNote(innerNullifier: Fr, noteHash: Fr, counter: number) {
447
+ this.noteCache.nullifyNote(this.contractAddress, innerNullifier, noteHash);
448
+ this.sideEffectsCounter = counter + 1;
423
449
  return Promise.resolve();
424
450
  }
425
451
 
@@ -468,11 +494,7 @@ export class TXE implements TypedOracle {
468
494
  blockNumber: number,
469
495
  numberOfElements: number,
470
496
  ): Promise<Fr[]> {
471
- const db =
472
- blockNumber === (await this.getBlockNumber())
473
- ? this.trees.asLatest()
474
- : new MerkleTreeSnapshotOperationsFacade(this.trees, blockNumber);
475
-
497
+ const db = await this.#getTreesAt(blockNumber);
476
498
  const values = [];
477
499
  for (let i = 0n; i < numberOfElements; i++) {
478
500
  const storageSlot = startStorageSlot.add(new Fr(i));
@@ -510,11 +532,13 @@ export class TXE implements TypedOracle {
510
532
  return publicDataWrites.map(write => write.newValue);
511
533
  }
512
534
 
513
- emitEncryptedLog(_contractAddress: AztecAddress, _randomness: Fr, _encryptedNote: Buffer, _counter: number): void {
535
+ emitEncryptedLog(_contractAddress: AztecAddress, _randomness: Fr, _encryptedNote: Buffer, counter: number): void {
536
+ this.sideEffectsCounter = counter + 1;
514
537
  return;
515
538
  }
516
539
 
517
- emitEncryptedNoteLog(_noteHashCounter: number, _encryptedNote: Buffer, _counter: number): void {
540
+ emitEncryptedNoteLog(_noteHashCounter: number, _encryptedNote: Buffer, counter: number): void {
541
+ this.sideEffectsCounter = counter + 1;
518
542
  return;
519
543
  }
520
544
 
@@ -536,7 +560,8 @@ export class TXE implements TypedOracle {
536
560
  return taggedNote.encrypt(ephSk, recipient, ivpkM, ovKeys);
537
561
  }
538
562
 
539
- emitUnencryptedLog(_log: UnencryptedL2Log, _counter: number): void {
563
+ emitUnencryptedLog(_log: UnencryptedL2Log, counter: number): void {
564
+ this.sideEffectsCounter = counter + 1;
540
565
  return;
541
566
  }
542
567
 
@@ -609,7 +634,7 @@ export class TXE implements TypedOracle {
609
634
 
610
635
  // Apply side effects
611
636
  const endSideEffectCounter = publicInputs.endSideEffectCounter;
612
- this.sideEffectsCounter = endSideEffectCounter.toNumber();
637
+ this.sideEffectsCounter = endSideEffectCounter.toNumber() + 1;
613
638
 
614
639
  await this.addNullifiers(
615
640
  targetContractAddress,
@@ -676,27 +701,21 @@ export class TXE implements TypedOracle {
676
701
  return `${artifact.name}:${f.name}`;
677
702
  }
678
703
 
679
- async executePublicFunction(targetContractAddress: AztecAddress, args: Fr[], callContext: CallContext) {
704
+ async executePublicFunction(
705
+ targetContractAddress: AztecAddress,
706
+ args: Fr[],
707
+ callContext: CallContext,
708
+ counter: number,
709
+ ) {
680
710
  const header = Header.empty();
681
711
  header.state = await this.trees.getStateReference(true);
682
712
  header.globalVariables.blockNumber = new Fr(await this.getBlockNumber());
683
- header.state.partial.nullifierTree.root = Fr.fromBuffer(
684
- (await this.trees.getTreeInfo(MerkleTreeId.NULLIFIER_TREE, true)).root,
685
- );
686
- header.state.partial.noteHashTree.root = Fr.fromBuffer(
687
- (await this.trees.getTreeInfo(MerkleTreeId.NOTE_HASH_TREE, true)).root,
688
- );
689
- header.state.partial.publicDataTree.root = Fr.fromBuffer(
690
- (await this.trees.getTreeInfo(MerkleTreeId.PUBLIC_DATA_TREE, true)).root,
691
- );
692
- header.state.l1ToL2MessageTree.root = Fr.fromBuffer(
693
- (await this.trees.getTreeInfo(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, true)).root,
694
- );
695
713
  const executor = new PublicExecutor(
696
714
  new TXEPublicStateDB(this),
697
715
  new ContractsDataSourcePublicDB(new TXEPublicContractDataSource(this)),
698
716
  new WorldStateDB(this.trees.asLatest()),
699
717
  header,
718
+ new NoopTelemetryClient(),
700
719
  );
701
720
  const execution = new PublicExecutionRequest(targetContractAddress, callContext, args);
702
721
 
@@ -707,6 +726,7 @@ export class TXE implements TypedOracle {
707
726
  TxContext.empty(),
708
727
  /* pendingNullifiers */ [],
709
728
  /* transactionFee */ Fr.ONE,
729
+ counter,
710
730
  );
711
731
  }
712
732
 
@@ -732,11 +752,16 @@ export class TXE implements TypedOracle {
732
752
  callContext.isStaticCall = isStaticCall;
733
753
  callContext.isDelegateCall = isDelegateCall;
734
754
 
735
- const executionResult = await this.executePublicFunction(targetContractAddress, args, callContext);
755
+ const executionResult = await this.executePublicFunction(
756
+ targetContractAddress,
757
+ args,
758
+ callContext,
759
+ this.sideEffectsCounter,
760
+ );
736
761
 
737
762
  // Apply side effects
738
763
  if (!executionResult.reverted) {
739
- this.sideEffectsCounter += executionResult.endSideEffectCounter.toNumber();
764
+ this.sideEffectsCounter = executionResult.endSideEffectCounter.toNumber() + 1;
740
765
  }
741
766
  this.setContractAddress(currentContractAddress);
742
767
  this.setMsgSender(currentMessageSender);
@@ -745,47 +770,11 @@ export class TXE implements TypedOracle {
745
770
  return executionResult;
746
771
  }
747
772
 
748
- async callPublicFunction(
749
- targetContractAddress: AztecAddress,
750
- functionSelector: FunctionSelector,
751
- argsHash: Fr,
752
- _sideEffectCounter: number,
753
- isStaticCall: boolean,
754
- isDelegateCall: boolean,
755
- ): Promise<Fr[]> {
756
- // Store and modify env
757
- const currentContractAddress = AztecAddress.fromField(this.contractAddress);
758
- const currentMessageSender = AztecAddress.fromField(this.msgSender);
759
- const currentFunctionSelector = FunctionSelector.fromField(this.functionSelector.toField());
760
- this.setMsgSender(this.contractAddress);
761
- this.setContractAddress(targetContractAddress);
762
- this.setFunctionSelector(functionSelector);
763
-
764
- const callContext = CallContext.empty();
765
- callContext.msgSender = this.msgSender;
766
- callContext.functionSelector = this.functionSelector;
767
- callContext.storageContractAddress = targetContractAddress;
768
- callContext.isStaticCall = isStaticCall;
769
- callContext.isDelegateCall = isDelegateCall;
770
-
771
- const args = this.packedValuesCache.unpack(argsHash);
772
-
773
- const executionResult = await this.executePublicFunction(targetContractAddress, args, callContext);
774
-
775
- // Apply side effects
776
- this.sideEffectsCounter = executionResult.endSideEffectCounter.toNumber();
777
- this.setContractAddress(currentContractAddress);
778
- this.setMsgSender(currentMessageSender);
779
- this.setFunctionSelector(currentFunctionSelector);
780
-
781
- return executionResult.returnValues;
782
- }
783
-
784
773
  async enqueuePublicFunctionCall(
785
774
  targetContractAddress: AztecAddress,
786
775
  functionSelector: FunctionSelector,
787
776
  argsHash: Fr,
788
- _sideEffectCounter: number,
777
+ sideEffectCounter: number,
789
778
  isStaticCall: boolean,
790
779
  isDelegateCall: boolean,
791
780
  ) {
@@ -806,10 +795,19 @@ export class TXE implements TypedOracle {
806
795
 
807
796
  const args = this.packedValuesCache.unpack(argsHash);
808
797
 
809
- const executionResult = await this.executePublicFunction(targetContractAddress, args, callContext);
798
+ const executionResult = await this.executePublicFunction(
799
+ targetContractAddress,
800
+ args,
801
+ callContext,
802
+ sideEffectCounter,
803
+ );
804
+
805
+ if (executionResult.reverted) {
806
+ throw new Error(`Execution reverted with reason: ${executionResult.revertReason}`);
807
+ }
810
808
 
811
809
  // Apply side effects
812
- this.sideEffectsCounter += executionResult.endSideEffectCounter.toNumber();
810
+ this.sideEffectsCounter = executionResult.endSideEffectCounter.toNumber() + 1;
813
811
  this.setContractAddress(currentContractAddress);
814
812
  this.setMsgSender(currentMessageSender);
815
813
  this.setFunctionSelector(currentFunctionSelector);
@@ -835,6 +833,10 @@ export class TXE implements TypedOracle {
835
833
  );
836
834
  }
837
835
 
836
+ notifySetMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter: number) {
837
+ this.noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
838
+ }
839
+
838
840
  aes128Encrypt(input: Buffer, initializationVector: Buffer, key: Buffer): Buffer {
839
841
  const aes128 = new Aes128();
840
842
  return aes128.encryptBufferCBC(input, initializationVector, key);
@@ -848,8 +850,9 @@ export class TXE implements TypedOracle {
848
850
  _contractAddress: AztecAddress,
849
851
  _randomness: Fr,
850
852
  _encryptedEvent: Buffer,
851
- _counter: number,
853
+ counter: number,
852
854
  ): void {
855
+ this.sideEffectsCounter = counter + 1;
853
856
  return;
854
857
  }
855
858
 
@@ -40,7 +40,8 @@ export class TXEService {
40
40
  const store = openTmpStore(true);
41
41
  const trees = await MerkleTrees.new(store, logger);
42
42
  const packedValuesCache = new PackedValuesCache();
43
- const noteCache = new ExecutionNoteCache();
43
+ const txHash = new Fr(1); // The txHash is used for computing the revertible nullifiers for non-revertible note hashes. It can be any value for testing.
44
+ const noteCache = new ExecutionNoteCache(txHash);
44
45
  const keyStore = new KeyStore(store);
45
46
  const txeDatabase = new TXEDatabase(store);
46
47
  logger.info(`TXE service initialized`);
@@ -66,16 +67,16 @@ export class TXEService {
66
67
  const nBlocks = fromSingle(blocks).toNumber();
67
68
  this.logger.debug(`time traveling ${nBlocks} blocks`);
68
69
  const trees = (this.typedOracle as TXE).getTrees();
69
- const header = Header.empty();
70
- const l2Block = L2Block.empty();
71
- header.state = await trees.getStateReference(true);
72
- const blockNumber = await this.typedOracle.getBlockNumber();
73
- header.globalVariables.blockNumber = new Fr(blockNumber);
74
- l2Block.archive.root = Fr.fromBuffer((await trees.getTreeInfo(MerkleTreeId.ARCHIVE, true)).root);
75
- l2Block.header = header;
76
70
  for (let i = 0; i < nBlocks; i++) {
77
71
  const blockNumber = await this.typedOracle.getBlockNumber();
72
+ const header = Header.empty();
73
+ const l2Block = L2Block.empty();
74
+ header.state = await trees.getStateReference(true);
78
75
  header.globalVariables.blockNumber = new Fr(blockNumber);
76
+ await trees.appendLeaves(MerkleTreeId.ARCHIVE, [header.hash()]);
77
+ l2Block.archive.root = Fr.fromBuffer((await trees.getTreeInfo(MerkleTreeId.ARCHIVE, true)).root);
78
+ l2Block.header = header;
79
+ this.logger.debug(`Block ${blockNumber} created, header hash ${header.hash().toString()}`);
79
80
  await trees.handleL2BlockAndMessages(l2Block, []);
80
81
  (this.typedOracle as TXE).setBlockNumber(blockNumber + 1);
81
82
  }
@@ -442,14 +443,14 @@ export class TXEService {
442
443
  storageSlot: ForeignCallSingle,
443
444
  noteTypeId: ForeignCallSingle,
444
445
  note: ForeignCallArray,
445
- innerNoteHash: ForeignCallSingle,
446
+ noteHash: ForeignCallSingle,
446
447
  counter: ForeignCallSingle,
447
448
  ) {
448
449
  this.typedOracle.notifyCreatedNote(
449
450
  fromSingle(storageSlot),
450
451
  NoteSelector.fromField(fromSingle(noteTypeId)),
451
452
  fromArray(note),
452
- fromSingle(innerNoteHash),
453
+ fromSingle(noteHash),
453
454
  fromSingle(counter).toNumber(),
454
455
  );
455
456
  return toForeignCallResult([toSingle(new Fr(0))]);
@@ -457,12 +458,12 @@ export class TXEService {
457
458
 
458
459
  async notifyNullifiedNote(
459
460
  innerNullifier: ForeignCallSingle,
460
- innerNoteHash: ForeignCallSingle,
461
+ noteHash: ForeignCallSingle,
461
462
  counter: ForeignCallSingle,
462
463
  ) {
463
464
  await this.typedOracle.notifyNullifiedNote(
464
465
  fromSingle(innerNullifier),
465
- fromSingle(innerNoteHash),
466
+ fromSingle(noteHash),
466
467
  fromSingle(counter).toNumber(),
467
468
  );
468
469
  return toForeignCallResult([toSingle(new Fr(0))]);
@@ -511,8 +512,8 @@ export class TXEService {
511
512
  return toForeignCallResult([]);
512
513
  }
513
514
 
514
- async avmOpcodeEmitNoteHash(innerNoteHash: ForeignCallSingle) {
515
- await (this.typedOracle as TXE).avmOpcodeEmitNoteHash(fromSingle(innerNoteHash));
515
+ async avmOpcodeEmitNoteHash(noteHash: ForeignCallSingle) {
516
+ await (this.typedOracle as TXE).avmOpcodeEmitNoteHash(fromSingle(noteHash));
516
517
  return toForeignCallResult([]);
517
518
  }
518
519
 
@@ -711,6 +712,10 @@ export class TXEService {
711
712
  return toForeignCallResult([]);
712
713
  }
713
714
 
715
+ public notifySetMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter: ForeignCallSingle) {
716
+ this.typedOracle.notifySetMinRevertibleSideEffectCounter(fromSingle(minRevertibleSideEffectCounter).toNumber());
717
+ }
718
+
714
719
  async getChainId() {
715
720
  return toForeignCallResult([toSingle(await this.typedOracle.getChainId())]);
716
721
  }
@@ -728,4 +733,25 @@ export class TXEService {
728
733
  await (this.typedOracle as TXE).addNoteHashes(fromSingle(contractAddress), fromArray(noteHashes));
729
734
  return toForeignCallResult([]);
730
735
  }
736
+
737
+ async getHeader(blockNumber: ForeignCallSingle) {
738
+ const header = await this.typedOracle.getHeader(fromSingle(blockNumber).toNumber());
739
+ if (!header) {
740
+ throw new Error(`Block header not found for block ${blockNumber}.`);
741
+ }
742
+ return toForeignCallResult([toArray(header.toFields())]);
743
+ }
744
+
745
+ async getMembershipWitness(blockNumber: ForeignCallSingle, treeId: ForeignCallSingle, leafValue: ForeignCallSingle) {
746
+ const parsedBlockNumber = fromSingle(blockNumber).toNumber();
747
+ const parsedTreeId = fromSingle(treeId).toNumber();
748
+ const parsedLeafValue = fromSingle(leafValue);
749
+ const witness = await this.typedOracle.getMembershipWitness(parsedBlockNumber, parsedTreeId, parsedLeafValue);
750
+ if (!witness) {
751
+ throw new Error(
752
+ `Membership witness in tree ${MerkleTreeId[parsedTreeId]} not found for value ${parsedLeafValue} at block ${parsedBlockNumber}.`,
753
+ );
754
+ }
755
+ return toForeignCallResult([toArray(witness)]);
756
+ }
731
757
  }