@aztec/txe 0.59.0 → 0.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,6 +7,7 @@ import {
7
7
  PublicDataWitness,
8
8
  PublicDataWrite,
9
9
  PublicExecutionRequest,
10
+ SimulationError,
10
11
  type UnencryptedL2Log,
11
12
  } from '@aztec/circuit-types';
12
13
  import { type CircuitWitnessGenerationStats } from '@aztec/circuit-types/stats';
@@ -46,7 +47,7 @@ import { Fr } from '@aztec/foundation/fields';
46
47
  import { type Logger, applyStringFormatting } from '@aztec/foundation/log';
47
48
  import { Timer } from '@aztec/foundation/timer';
48
49
  import { type KeyStore } from '@aztec/key-store';
49
- import { ContractDataOracle } from '@aztec/pxe';
50
+ import { ContractDataOracle, enrichPublicSimulationError } from '@aztec/pxe';
50
51
  import {
51
52
  ExecutionError,
52
53
  type ExecutionNoteCache,
@@ -78,9 +79,6 @@ export class TXE implements TypedOracle {
78
79
  private msgSender: AztecAddress;
79
80
  private functionSelector = FunctionSelector.fromField(new Fr(0));
80
81
  private isStaticCall = false;
81
- // This will hold the _real_ calldata. That is, the one without the PublicContextInputs.
82
- // TODO: Remove this comment once PublicContextInputs are removed.
83
- private calldata: Fr[] = [];
84
82
 
85
83
  private contractDataOracle: ContractDataOracle;
86
84
 
@@ -127,18 +125,10 @@ export class TXE implements TypedOracle {
127
125
  return this.functionSelector;
128
126
  }
129
127
 
130
- getCalldata() {
131
- return this.calldata;
132
- }
133
-
134
128
  setMsgSender(msgSender: Fr) {
135
129
  this.msgSender = msgSender;
136
130
  }
137
131
 
138
- setCalldata(calldata: Fr[]) {
139
- this.calldata = calldata;
140
- }
141
-
142
132
  setFunctionSelector(functionSelector: FunctionSelector) {
143
133
  this.functionSelector = functionSelector;
144
134
  }
@@ -188,48 +178,24 @@ export class TXE implements TypedOracle {
188
178
  blockNumber: number,
189
179
  sideEffectsCounter = this.sideEffectsCounter,
190
180
  isStaticCall = false,
191
- isDelegateCall = false,
192
181
  ) {
193
182
  const db = await this.#getTreesAt(blockNumber);
194
183
  const previousBlockState = await this.#getTreesAt(blockNumber - 1);
195
184
 
196
185
  const stateReference = await db.getStateReference();
197
186
  const inputs = PrivateContextInputs.empty();
187
+ inputs.txContext.chainId = this.chainId;
188
+ inputs.txContext.version = this.version;
198
189
  inputs.historicalHeader.globalVariables.blockNumber = new Fr(blockNumber);
199
190
  inputs.historicalHeader.state = stateReference;
200
191
  inputs.historicalHeader.lastArchive.root = Fr.fromBuffer(
201
192
  (await previousBlockState.getTreeInfo(MerkleTreeId.ARCHIVE)).root,
202
193
  );
203
- inputs.callContext.msgSender = this.msgSender;
204
- inputs.callContext.storageContractAddress = this.contractAddress;
205
- inputs.callContext.isStaticCall = isStaticCall;
206
- inputs.callContext.isDelegateCall = isDelegateCall;
194
+ inputs.callContext = new CallContext(this.msgSender, this.contractAddress, this.functionSelector, isStaticCall);
207
195
  inputs.startSideEffectCounter = sideEffectsCounter;
208
- inputs.callContext.functionSelector = this.functionSelector;
209
196
  return inputs;
210
197
  }
211
198
 
212
- async avmOpcodeNullifierExists(innerNullifier: Fr, targetAddress: AztecAddress): Promise<boolean> {
213
- const nullifier = siloNullifier(targetAddress, innerNullifier!);
214
- const db = await this.trees.getLatest();
215
- const index = await db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
216
- return index !== undefined;
217
- }
218
-
219
- async avmOpcodeEmitNullifier(nullifier: Fr) {
220
- const db = await this.trees.getLatest();
221
- const siloedNullifier = siloNullifier(this.contractAddress, nullifier);
222
- await db.batchInsert(MerkleTreeId.NULLIFIER_TREE, [siloedNullifier.toBuffer()], NULLIFIER_SUBTREE_HEIGHT);
223
- return Promise.resolve();
224
- }
225
-
226
- async avmOpcodeEmitNoteHash(noteHash: Fr) {
227
- const db = await this.trees.getLatest();
228
- const siloedNoteHash = siloNoteHash(this.contractAddress, noteHash);
229
- await db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, [siloedNoteHash]);
230
- return Promise.resolve();
231
- }
232
-
233
199
  deriveKeys(secret: Fr) {
234
200
  return deriveKeys(secret);
235
201
  }
@@ -468,24 +434,6 @@ export class TXE implements TypedOracle {
468
434
  throw new Error('Method not implemented.');
469
435
  }
470
436
 
471
- async avmOpcodeStorageRead(slot: Fr) {
472
- const db = await this.trees.getLatest();
473
-
474
- const leafSlot = computePublicDataTreeLeafSlot(this.contractAddress, slot);
475
-
476
- const lowLeafResult = await db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
477
- if (!lowLeafResult || !lowLeafResult.alreadyPresent) {
478
- return Fr.ZERO;
479
- }
480
-
481
- const preimage = (await db.getLeafPreimage(
482
- MerkleTreeId.PUBLIC_DATA_TREE,
483
- lowLeafResult.index,
484
- )) as PublicDataTreeLeafPreimage;
485
-
486
- return preimage.value;
487
- }
488
-
489
437
  async storageRead(
490
438
  contractAddress: Fr,
491
439
  startStorageSlot: Fr,
@@ -555,13 +503,12 @@ export class TXE implements TypedOracle {
555
503
  argsHash: Fr,
556
504
  sideEffectCounter: number,
557
505
  isStaticCall: boolean,
558
- isDelegateCall: boolean,
559
506
  ) {
560
507
  this.logger.verbose(
561
508
  `Executing external function ${await this.getDebugFunctionName(
562
509
  targetContractAddress,
563
510
  functionSelector,
564
- )}@${targetContractAddress} isStaticCall=${isStaticCall} isDelegateCall=${isDelegateCall}`,
511
+ )}@${targetContractAddress} isStaticCall=${isStaticCall}`,
565
512
  );
566
513
 
567
514
  // Store and modify env
@@ -575,13 +522,7 @@ export class TXE implements TypedOracle {
575
522
  const artifact = await this.contractDataOracle.getFunctionArtifact(targetContractAddress, functionSelector);
576
523
 
577
524
  const acir = artifact.bytecode;
578
- const initialWitness = await this.getInitialWitness(
579
- artifact,
580
- argsHash,
581
- sideEffectCounter,
582
- isStaticCall,
583
- isDelegateCall,
584
- );
525
+ const initialWitness = await this.getInitialWitness(artifact, argsHash, sideEffectCounter, isStaticCall);
585
526
  const acvmCallback = new Oracle(this);
586
527
  const timer = new Timer();
587
528
  try {
@@ -633,13 +574,7 @@ export class TXE implements TypedOracle {
633
574
  }
634
575
  }
635
576
 
636
- async getInitialWitness(
637
- abi: FunctionAbi,
638
- argsHash: Fr,
639
- sideEffectCounter: number,
640
- isStaticCall: boolean,
641
- isDelegateCall: boolean,
642
- ) {
577
+ async getInitialWitness(abi: FunctionAbi, argsHash: Fr, sideEffectCounter: number, isStaticCall: boolean) {
643
578
  const argumentsSize = countArgumentsSize(abi);
644
579
 
645
580
  const args = this.packedValuesCache.unpack(argsHash);
@@ -652,7 +587,6 @@ export class TXE implements TypedOracle {
652
587
  this.blockNumber - 1,
653
588
  sideEffectCounter,
654
589
  isStaticCall,
655
- isDelegateCall,
656
590
  );
657
591
 
658
592
  const fields = [...privateContextInputs.toFields(), ...args];
@@ -680,21 +614,34 @@ export class TXE implements TypedOracle {
680
614
  return `${artifact.name}:${f.name}`;
681
615
  }
682
616
 
683
- async executePublicFunction(
684
- targetContractAddress: AztecAddress,
685
- args: Fr[],
686
- callContext: CallContext,
687
- counter: number,
688
- ) {
617
+ private async executePublicFunction(args: Fr[], callContext: CallContext, counter: number) {
689
618
  const executor = new PublicExecutor(
690
619
  new TXEWorldStateDB(await this.trees.getLatest(), new TXEPublicContractDataSource(this)),
691
620
  new NoopTelemetryClient(),
692
621
  );
693
- const execution = new PublicExecutionRequest(targetContractAddress, callContext, args);
622
+ const execution = new PublicExecutionRequest(callContext, args);
623
+
624
+ const db = await this.trees.getLatest();
625
+ const previousBlockState = await this.#getTreesAt(this.blockNumber - 1);
626
+
627
+ const combinedConstantData = CombinedConstantData.empty();
628
+ combinedConstantData.globalVariables.chainId = this.chainId;
629
+ combinedConstantData.globalVariables.version = this.version;
630
+ combinedConstantData.globalVariables.blockNumber = new Fr(this.blockNumber);
631
+ combinedConstantData.historicalHeader.globalVariables.chainId = this.chainId;
632
+ combinedConstantData.historicalHeader.globalVariables.version = this.version;
633
+ combinedConstantData.historicalHeader.globalVariables.blockNumber = new Fr(this.blockNumber - 1);
634
+ combinedConstantData.historicalHeader.state = await db.getStateReference();
635
+ combinedConstantData.historicalHeader.lastArchive.root = Fr.fromBuffer(
636
+ (await previousBlockState.getTreeInfo(MerkleTreeId.ARCHIVE)).root,
637
+ );
638
+
639
+ combinedConstantData.txContext.chainId = this.chainId;
640
+ combinedConstantData.txContext.version = this.version;
694
641
 
695
642
  const executionResult = executor.simulate(
696
643
  execution,
697
- CombinedConstantData.empty(),
644
+ combinedConstantData,
698
645
  Gas.test(),
699
646
  TxContext.empty(),
700
647
  /* pendingNullifiers */ [],
@@ -704,54 +651,12 @@ export class TXE implements TypedOracle {
704
651
  return Promise.resolve(executionResult);
705
652
  }
706
653
 
707
- async avmOpcodeCall(
708
- targetContractAddress: AztecAddress,
709
- functionSelector: FunctionSelector,
710
- args: Fr[],
711
- isStaticCall: boolean,
712
- isDelegateCall: boolean,
713
- ) {
714
- // Store and modify env
715
- const currentContractAddress = AztecAddress.fromField(this.contractAddress);
716
- const currentMessageSender = AztecAddress.fromField(this.msgSender);
717
- const currentFunctionSelector = FunctionSelector.fromField(this.functionSelector.toField());
718
- this.setMsgSender(this.contractAddress);
719
- this.setContractAddress(targetContractAddress);
720
- this.setFunctionSelector(functionSelector);
721
- this.setCalldata(args);
722
-
723
- const callContext = CallContext.empty();
724
- callContext.msgSender = this.msgSender;
725
- callContext.functionSelector = this.functionSelector;
726
- callContext.storageContractAddress = targetContractAddress;
727
- callContext.isStaticCall = isStaticCall;
728
- callContext.isDelegateCall = isDelegateCall;
729
-
730
- const executionResult = await this.executePublicFunction(
731
- targetContractAddress,
732
- args,
733
- callContext,
734
- this.sideEffectsCounter,
735
- );
736
-
737
- // Apply side effects
738
- if (!executionResult.reverted) {
739
- this.sideEffectsCounter = executionResult.endSideEffectCounter.toNumber() + 1;
740
- }
741
- this.setContractAddress(currentContractAddress);
742
- this.setMsgSender(currentMessageSender);
743
- this.setFunctionSelector(currentFunctionSelector);
744
-
745
- return executionResult;
746
- }
747
-
748
654
  async enqueuePublicFunctionCall(
749
655
  targetContractAddress: AztecAddress,
750
656
  functionSelector: FunctionSelector,
751
657
  argsHash: Fr,
752
658
  sideEffectCounter: number,
753
659
  isStaticCall: boolean,
754
- isDelegateCall: boolean,
755
660
  ): Promise<Fr> {
756
661
  // Store and modify env
757
662
  const currentContractAddress = AztecAddress.fromField(this.contractAddress);
@@ -761,29 +666,44 @@ export class TXE implements TypedOracle {
761
666
  this.setContractAddress(targetContractAddress);
762
667
  this.setFunctionSelector(functionSelector);
763
668
 
764
- const callContext = CallContext.empty();
765
- callContext.msgSender = this.msgSender;
766
- callContext.functionSelector = FunctionSelector.fromField(new Fr(PUBLIC_DISPATCH_SELECTOR));
767
- callContext.storageContractAddress = targetContractAddress;
768
- callContext.isStaticCall = isStaticCall;
769
- callContext.isDelegateCall = isDelegateCall;
669
+ const callContext = new CallContext(
670
+ /* msgSender */ currentContractAddress,
671
+ targetContractAddress,
672
+ FunctionSelector.fromField(new Fr(PUBLIC_DISPATCH_SELECTOR)),
673
+ isStaticCall,
674
+ );
770
675
 
771
676
  const args = [this.functionSelector.toField(), ...this.packedValuesCache.unpack(argsHash)];
772
677
  const newArgsHash = this.packedValuesCache.pack(args);
773
678
 
774
- const executionResult = await this.executePublicFunction(
775
- targetContractAddress,
776
- args,
777
- callContext,
778
- sideEffectCounter,
779
- );
679
+ const executionResult = await this.executePublicFunction(args, callContext, sideEffectCounter);
780
680
 
681
+ // Poor man's revert handling
781
682
  if (executionResult.reverted) {
782
- throw new Error(`Execution reverted with reason: ${executionResult.revertReason}`);
683
+ if (executionResult.revertReason && executionResult.revertReason instanceof SimulationError) {
684
+ await enrichPublicSimulationError(
685
+ executionResult.revertReason,
686
+ this.contractDataOracle,
687
+ this.txeDatabase,
688
+ this.logger,
689
+ );
690
+ throw new Error(executionResult.revertReason.message);
691
+ } else {
692
+ throw new Error(`Enqueued public function call reverted: ${executionResult.revertReason}`);
693
+ }
783
694
  }
784
695
 
785
696
  // Apply side effects
786
697
  this.sideEffectsCounter = executionResult.endSideEffectCounter.toNumber() + 1;
698
+ await this.addNoteHashes(
699
+ targetContractAddress,
700
+ executionResult.noteHashes.map(noteHash => noteHash.value),
701
+ );
702
+ await this.addNullifiers(
703
+ targetContractAddress,
704
+ executionResult.nullifiers.map(nullifier => nullifier.value),
705
+ );
706
+
787
707
  this.setContractAddress(currentContractAddress);
788
708
  this.setMsgSender(currentMessageSender);
789
709
  this.setFunctionSelector(currentFunctionSelector);
@@ -797,7 +717,6 @@ export class TXE implements TypedOracle {
797
717
  argsHash: Fr,
798
718
  sideEffectCounter: number,
799
719
  isStaticCall: boolean,
800
- isDelegateCall: boolean,
801
720
  ): Promise<Fr> {
802
721
  // Definitely not right, in that the teardown should always be last.
803
722
  // But useful for executing flows.
@@ -807,7 +726,6 @@ export class TXE implements TypedOracle {
807
726
  argsHash,
808
727
  sideEffectCounter,
809
728
  isStaticCall,
810
- isDelegateCall,
811
729
  );
812
730
  }
813
731
 
@@ -828,4 +746,88 @@ export class TXE implements TypedOracle {
828
746
  this.sideEffectsCounter = counter + 1;
829
747
  return;
830
748
  }
749
+
750
+ // AVM oracles
751
+
752
+ async avmOpcodeCall(
753
+ targetContractAddress: AztecAddress,
754
+ functionSelector: FunctionSelector,
755
+ args: Fr[],
756
+ isStaticCall: boolean,
757
+ ) {
758
+ // Store and modify env
759
+ const currentContractAddress = AztecAddress.fromField(this.contractAddress);
760
+ const currentMessageSender = AztecAddress.fromField(this.msgSender);
761
+ const currentFunctionSelector = FunctionSelector.fromField(this.functionSelector.toField());
762
+ this.setMsgSender(this.contractAddress);
763
+ this.setContractAddress(targetContractAddress);
764
+ this.setFunctionSelector(functionSelector);
765
+
766
+ const callContext = new CallContext(
767
+ /* msgSender */ currentContractAddress,
768
+ targetContractAddress,
769
+ functionSelector,
770
+ isStaticCall,
771
+ );
772
+
773
+ const executionResult = await this.executePublicFunction(args, callContext, this.sideEffectsCounter);
774
+
775
+ // Apply side effects
776
+ if (!executionResult.reverted) {
777
+ this.sideEffectsCounter = executionResult.endSideEffectCounter.toNumber() + 1;
778
+ await this.addNoteHashes(
779
+ targetContractAddress,
780
+ executionResult.noteHashes.map(noteHash => noteHash.value),
781
+ );
782
+ await this.addNullifiers(
783
+ targetContractAddress,
784
+ executionResult.nullifiers.map(nullifier => nullifier.value),
785
+ );
786
+ }
787
+
788
+ this.setContractAddress(currentContractAddress);
789
+ this.setMsgSender(currentMessageSender);
790
+ this.setFunctionSelector(currentFunctionSelector);
791
+
792
+ return executionResult;
793
+ }
794
+
795
+ async avmOpcodeNullifierExists(innerNullifier: Fr, targetAddress: AztecAddress): Promise<boolean> {
796
+ const nullifier = siloNullifier(targetAddress, innerNullifier!);
797
+ const db = await this.trees.getLatest();
798
+ const index = await db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
799
+ return index !== undefined;
800
+ }
801
+
802
+ async avmOpcodeEmitNullifier(nullifier: Fr) {
803
+ const db = await this.trees.getLatest();
804
+ const siloedNullifier = siloNullifier(this.contractAddress, nullifier);
805
+ await db.batchInsert(MerkleTreeId.NULLIFIER_TREE, [siloedNullifier.toBuffer()], NULLIFIER_SUBTREE_HEIGHT);
806
+ return Promise.resolve();
807
+ }
808
+
809
+ async avmOpcodeEmitNoteHash(noteHash: Fr) {
810
+ const db = await this.trees.getLatest();
811
+ const siloedNoteHash = siloNoteHash(this.contractAddress, noteHash);
812
+ await db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, [siloedNoteHash]);
813
+ return Promise.resolve();
814
+ }
815
+
816
+ async avmOpcodeStorageRead(slot: Fr) {
817
+ const db = await this.trees.getLatest();
818
+
819
+ const leafSlot = computePublicDataTreeLeafSlot(this.contractAddress, slot);
820
+
821
+ const lowLeafResult = await db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
822
+ if (!lowLeafResult || !lowLeafResult.alreadyPresent) {
823
+ return Fr.ZERO;
824
+ }
825
+
826
+ const preimage = (await db.getLeafPreimage(
827
+ MerkleTreeId.PUBLIC_DATA_TREE,
828
+ lowLeafResult.index,
829
+ )) as PublicDataTreeLeafPreimage;
830
+
831
+ return preimage.value;
832
+ }
831
833
  }