@aztec/pxe 0.0.1-commit.0dc957cde → 0.0.1-commit.0ec55a70b

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.
Files changed (35) hide show
  1. package/dest/block_synchronizer/block_stream_source.d.ts +10 -0
  2. package/dest/block_synchronizer/block_stream_source.d.ts.map +1 -0
  3. package/dest/block_synchronizer/block_stream_source.js +37 -0
  4. package/dest/block_synchronizer/block_synchronizer.d.ts +1 -1
  5. package/dest/block_synchronizer/block_synchronizer.d.ts.map +1 -1
  6. package/dest/block_synchronizer/block_synchronizer.js +11 -9
  7. package/dest/contract_function_simulator/contract_function_simulator.d.ts +1 -1
  8. package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
  9. package/dest/contract_function_simulator/contract_function_simulator.js +2 -1
  10. package/dest/contract_function_simulator/oracle/interfaces.d.ts +3 -1
  11. package/dest/contract_function_simulator/oracle/interfaces.d.ts.map +1 -1
  12. package/dest/contract_function_simulator/oracle/oracle.d.ts +2 -1
  13. package/dest/contract_function_simulator/oracle/oracle.d.ts.map +1 -1
  14. package/dest/contract_function_simulator/oracle/oracle.js +7 -0
  15. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +8 -10
  16. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  17. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +10 -12
  18. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +7 -1
  19. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  20. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +50 -1
  21. package/dest/oracle_version.d.ts +2 -2
  22. package/dest/oracle_version.js +2 -2
  23. package/dest/pxe.d.ts +15 -4
  24. package/dest/pxe.d.ts.map +1 -1
  25. package/dest/pxe.js +30 -8
  26. package/package.json +16 -16
  27. package/src/block_synchronizer/block_stream_source.ts +52 -0
  28. package/src/block_synchronizer/block_synchronizer.ts +11 -9
  29. package/src/contract_function_simulator/contract_function_simulator.ts +1 -0
  30. package/src/contract_function_simulator/oracle/interfaces.ts +10 -0
  31. package/src/contract_function_simulator/oracle/oracle.ts +14 -0
  32. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +17 -16
  33. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +79 -1
  34. package/src/oracle_version.ts +2 -2
  35. package/src/pxe.ts +40 -15
@@ -164,6 +164,11 @@ export interface IUtilityExecutionOracle {
164
164
  getSharedSecret(address: AztecAddress, ephPk: Point, contractAddress: AztecAddress): Promise<Fr>;
165
165
  setContractSyncCacheInvalid(contractAddress: AztecAddress, scopes: AztecAddress[]): void;
166
166
  emitOffchainEffect(data: Fr[]): Promise<void>;
167
+ callUtilityFunction(
168
+ targetContractAddress: AztecAddress,
169
+ functionSelector: FunctionSelector,
170
+ args: Fr[],
171
+ ): Promise<Fr[]>;
167
172
 
168
173
  // Ephemeral array methods
169
174
  pushEphemeral(slot: Fr, elements: Fr[]): number;
@@ -204,6 +209,11 @@ export interface IPrivateExecutionOracle {
204
209
  sideEffectCounter: number,
205
210
  isStaticCall: boolean,
206
211
  ): Promise<{ endSideEffectCounter: Fr; returnsHash: Fr }>;
212
+ callUtilityFunction(
213
+ targetContractAddress: AztecAddress,
214
+ functionSelector: FunctionSelector,
215
+ args: Fr[],
216
+ ): Promise<Fr[]>;
207
217
  assertValidPublicCalldata(calldataHash: Fr): Promise<void>;
208
218
  notifyRevertiblePhaseStart(minRevertibleSideEffectCounter: number): Promise<void>;
209
219
  isExecutionInRevertiblePhase(sideEffectCounter: number): Promise<boolean>;
@@ -490,6 +490,20 @@ export class Oracle {
490
490
  return [values.map(toACVMField)];
491
491
  }
492
492
 
493
+ // eslint-disable-next-line camelcase
494
+ async aztec_utl_callUtilityFunction(
495
+ [contractAddress]: ACVMField[],
496
+ [functionSelector]: ACVMField[],
497
+ args: ACVMField[],
498
+ ): Promise<ACVMField[][]> {
499
+ const result = await this.handlerAsUtility().callUtilityFunction(
500
+ AztecAddress.fromField(Fr.fromString(contractAddress)),
501
+ FunctionSelector.fromField(Fr.fromString(functionSelector)),
502
+ args.map(Fr.fromString),
503
+ );
504
+ return [result.map(toACVMField)];
505
+ }
506
+
493
507
  // eslint-disable-next-line camelcase
494
508
  aztec_prv_notifyCreatedContractClassLog(
495
509
  [contractAddress]: ACVMField[],
@@ -2,7 +2,7 @@ import { MAX_FR_CALLDATA_TO_ALL_ENQUEUED_CALLS, PRIVATE_CONTEXT_INPUTS_LENGTH }
2
2
  import { Fr } from '@aztec/foundation/curves/bn254';
3
3
  import { createLogger } from '@aztec/foundation/log';
4
4
  import { Timer } from '@aztec/foundation/timer';
5
- import { type CircuitSimulator, toACVMWitness } from '@aztec/simulator/client';
5
+ import { toACVMWitness } from '@aztec/simulator/client';
6
6
  import {
7
7
  type FunctionAbi,
8
8
  type FunctionArtifact,
@@ -50,7 +50,6 @@ export type PrivateExecutionOracleArgs = Omit<UtilityExecutionOracleArgs, 'contr
50
50
  totalPublicCalldataCount?: number;
51
51
  sideEffectCounter?: number;
52
52
  senderForTags?: AztecAddress;
53
- simulator?: CircuitSimulator;
54
53
  };
55
54
 
56
55
  /**
@@ -82,8 +81,10 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
82
81
  private readonly senderTaggingStore: SenderTaggingStore;
83
82
  private totalPublicCalldataCount: number;
84
83
  private readonly initialSideEffectCounter: number;
85
- private senderForTags?: AztecAddress;
86
- private readonly simulator?: CircuitSimulator;
84
+ /** Sender for tags passed in at oracle construction time. Returned by `getSenderForTags` unless overridden. */
85
+ private readonly defaultSenderForTags: AztecAddress | undefined;
86
+ /** Per-call sender-for-tags override, set by `setSenderForTags`. Takes precedence over `defaultSenderForTags`. */
87
+ private currentSenderForTags: AztecAddress | undefined;
87
88
 
88
89
  constructor(args: PrivateExecutionOracleArgs) {
89
90
  super({
@@ -101,8 +102,7 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
101
102
  this.senderTaggingStore = args.senderTaggingStore;
102
103
  this.totalPublicCalldataCount = args.totalPublicCalldataCount ?? 0;
103
104
  this.initialSideEffectCounter = args.sideEffectCounter ?? 0;
104
- this.senderForTags = args.senderForTags;
105
- this.simulator = args.simulator;
105
+ this.defaultSenderForTags = args.senderForTags;
106
106
  }
107
107
 
108
108
  public getPrivateContextInputs(): PrivateContextInputs {
@@ -178,11 +178,10 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
178
178
  * for a tag in order to emit a log. Constrained tagging should not use this as there is no
179
179
  * guarantee that the recipient knows about the sender, and hence about the shared secret.
180
180
  *
181
- * The value persists through nested calls, meaning all calls down the stack will use the same
182
- * 'senderForTags' value (unless it is replaced).
181
+ * Returns `currentSenderForTags` if set (via `setSenderForTags`), otherwise `defaultSenderForTags`.
183
182
  */
184
183
  public getSenderForTags(): Promise<AztecAddress | undefined> {
185
- return Promise.resolve(this.senderForTags);
184
+ return Promise.resolve(this.currentSenderForTags ?? this.defaultSenderForTags);
186
185
  }
187
186
 
188
187
  /**
@@ -192,12 +191,14 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
192
191
  * for a tag in order to emit a log. Constrained tagging should not use this as there is no
193
192
  * guarantee that the recipient knows about the sender, and hence about the shared secret.
194
193
  *
195
- * Account contracts typically set this value before calling other contracts. The value persists
196
- * through nested calls, meaning all calls down the stack will use the same 'senderForTags'
197
- * value (unless it is replaced by another call to this setter).
194
+ * Overrides `defaultSenderForTags` for the remainder of this call. Each oracle instance is
195
+ * independent, so this has no effect on any other call in the execution.
198
196
  */
199
197
  public setSenderForTags(senderForTags: AztecAddress): Promise<void> {
200
- this.senderForTags = senderForTags;
198
+ this.logger.debug(
199
+ `Sender for tags switched to ${senderForTags} by contract ${this.contractAddress} (default was ${this.defaultSenderForTags})`,
200
+ );
201
+ this.currentSenderForTags = senderForTags;
201
202
  return Promise.resolve();
202
203
  }
203
204
 
@@ -578,15 +579,15 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
578
579
  sideEffectCounter,
579
580
  log: this.logger,
580
581
  scopes: this.scopes,
581
- senderForTags: this.senderForTags,
582
- simulator: this.simulator!,
582
+ senderForTags: this.defaultSenderForTags,
583
+ simulator: this.simulator,
583
584
  l2TipsStore: this.l2TipsStore,
584
585
  });
585
586
 
586
587
  const setupTime = simulatorSetupTimer.ms();
587
588
 
588
589
  const childExecutionResult = await executePrivateFunction(
589
- this.simulator!,
590
+ this.simulator,
590
591
  privateExecutionOracle,
591
592
  targetArtifact,
592
593
  targetContractAddress,
@@ -7,6 +7,15 @@ import { LogLevels, type Logger, createLogger } from '@aztec/foundation/log';
7
7
  import type { MembershipWitness } from '@aztec/foundation/trees';
8
8
  import type { KeyStore } from '@aztec/key-store';
9
9
  import { isProtocolContract } from '@aztec/protocol-contracts';
10
+ import {
11
+ type CircuitSimulator,
12
+ ExecutionError,
13
+ extractCallStack,
14
+ resolveAssertionMessageFromError,
15
+ toACVMWitness,
16
+ witnessMapToFields,
17
+ } from '@aztec/simulator/client';
18
+ import { FunctionSelector } from '@aztec/stdlib/abi';
10
19
  import type { AuthWitness } from '@aztec/stdlib/auth-witness';
11
20
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
12
21
  import { BlockHash, type L2TipsProvider } from '@aztec/stdlib/block';
@@ -44,6 +53,7 @@ import { UtilityContext } from '../noir-structs/utility_context.js';
44
53
  import { pickNotes } from '../pick_notes.js';
45
54
  import type { IMiscOracle, IUtilityExecutionOracle, NoteData } from './interfaces.js';
46
55
  import { MessageLoadOracleInputs } from './message_load_oracle_inputs.js';
56
+ import { Oracle } from './oracle.js';
47
57
 
48
58
  /** Args for UtilityExecutionOracle constructor. */
49
59
  export type UtilityExecutionOracleArgs = {
@@ -67,6 +77,7 @@ export type UtilityExecutionOracleArgs = {
67
77
  jobId: string;
68
78
  log?: ReturnType<typeof createLogger>;
69
79
  scopes: AztecAddress[];
80
+ simulator: CircuitSimulator;
70
81
  };
71
82
 
72
83
  /**
@@ -103,6 +114,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
103
114
  protected readonly jobId: string;
104
115
  protected logger: ReturnType<typeof createLogger>;
105
116
  protected readonly scopes: AztecAddress[];
117
+ protected readonly simulator: CircuitSimulator;
106
118
 
107
119
  constructor(args: UtilityExecutionOracleArgs) {
108
120
  this.contractAddress = args.contractAddress;
@@ -124,6 +136,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
124
136
  this.jobId = args.jobId;
125
137
  this.logger = args.log ?? createLogger('simulator:client_view_context');
126
138
  this.scopes = args.scopes;
139
+ this.simulator = args.simulator;
127
140
  }
128
141
 
129
142
  public assertCompatibleOracleVersion(major: number, minor: number): void {
@@ -894,6 +907,70 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
894
907
  return Promise.resolve();
895
908
  }
896
909
 
910
+ /** Executes another utility function from within this one and returns its serialized return values. */
911
+ public async callUtilityFunction(
912
+ targetContractAddress: AztecAddress,
913
+ functionSelector: FunctionSelector,
914
+ args: Fr[],
915
+ ): Promise<Fr[]> {
916
+ // TODO(F-29): We want to support cross-contract utility calls, but doing so safely requires wallets to have
917
+ // a way to authorize which contracts can be called transitively, since those calls may expose private state.
918
+ // Until that is in place, restrict nested utility calls to the same contract only.
919
+ if (!targetContractAddress.equals(this.contractAddress)) {
920
+ throw new Error(
921
+ `Cross-contract utility calls are not yet supported: cannot call ${targetContractAddress} from utility function on ${this.contractAddress}.`,
922
+ );
923
+ }
924
+
925
+ this.logger.debug(
926
+ `Calling nested utility function ${targetContractAddress}:${functionSelector} from ${this.contractAddress}`,
927
+ );
928
+
929
+ const targetArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(
930
+ targetContractAddress,
931
+ functionSelector,
932
+ );
933
+
934
+ const nestedOracle = new UtilityExecutionOracle({
935
+ contractAddress: targetContractAddress,
936
+ authWitnesses: this.authWitnesses,
937
+ capsules: this.capsules,
938
+ anchorBlockHeader: this.anchorBlockHeader,
939
+ contractStore: this.contractStore,
940
+ noteStore: this.noteStore,
941
+ keyStore: this.keyStore,
942
+ addressStore: this.addressStore,
943
+ aztecNode: this.aztecNode,
944
+ recipientTaggingStore: this.recipientTaggingStore,
945
+ senderAddressBookStore: this.senderAddressBookStore,
946
+ capsuleService: this.capsuleService,
947
+ privateEventStore: this.privateEventStore,
948
+ messageContextService: this.messageContextService,
949
+ contractSyncService: this.contractSyncService,
950
+ l2TipsStore: this.l2TipsStore,
951
+ jobId: this.jobId,
952
+ scopes: this.scopes,
953
+ simulator: this.simulator,
954
+ log: this.logger,
955
+ });
956
+
957
+ const initialWitness = toACVMWitness(0, args);
958
+ const acvmCallback = new Oracle(nestedOracle);
959
+ const acirExecutionResult = await this.simulator
960
+ .executeUserCircuit(initialWitness, targetArtifact, acvmCallback.toACIRCallback())
961
+ .catch((err: Error) => {
962
+ err.message = resolveAssertionMessageFromError(err, targetArtifact);
963
+ throw new ExecutionError(
964
+ err.message,
965
+ { contractAddress: targetContractAddress, functionSelector },
966
+ extractCallStack(err, targetArtifact.debug),
967
+ { cause: err },
968
+ );
969
+ });
970
+
971
+ return witnessMapToFields(acirExecutionResult.returnWitness);
972
+ }
973
+
897
974
  /** Returns offchain effects collected during execution. */
898
975
  public getOffchainEffects(): OffchainEffect[] {
899
976
  return this.offchainEffects;
@@ -904,7 +981,8 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
904
981
  const [response] = await Promise.all([
905
982
  query(),
906
983
  (async () => {
907
- const header = await this.aztecNode.getBlockHeader(blockHash);
984
+ const block = await this.aztecNode.getBlock(blockHash);
985
+ const header = block?.header;
908
986
  if (!header) {
909
987
  throw new Error(`Could not find block header for block hash ${blockHash}`);
910
988
  }
@@ -11,7 +11,7 @@
11
11
  /// if AZTEC_NR_MINOR > PXE_MINOR because if a contract is updated to use a newer Aztec.nr dependency without actually
12
12
  /// using any of the new oracles then there is no reason to throw.
13
13
  export const ORACLE_VERSION_MAJOR = 22;
14
- export const ORACLE_VERSION_MINOR = 1;
14
+ export const ORACLE_VERSION_MINOR = 2;
15
15
 
16
16
  /// This hash is computed from the Oracle interface and is used to detect when that interface changes. When it does,
17
17
  /// you need to either:
@@ -19,4 +19,4 @@ export const ORACLE_VERSION_MINOR = 1;
19
19
  /// - increment only `ORACLE_VERSION_MINOR` if the change is additive (a new oracle was added).
20
20
  ///
21
21
  /// These constants must be kept in sync between this file and `noir-projects/aztec-nr/aztec/src/oracle/version.nr`.
22
- export const ORACLE_INTERFACE_HASH = 'efafa0db2cc1f94e26d794d0079c8f71115261df0c3d0fa8cb5b64f17a12db92';
22
+ export const ORACLE_INTERFACE_HASH = '193fe3f9fee6a84d26803e636c9746dd805a4f389d44a0618de75c2c5eb4912e';
package/src/pxe.ts CHANGED
@@ -89,6 +89,14 @@ export type PackedPrivateEvent = InTx & {
89
89
  eventSelector: EventSelector;
90
90
  };
91
91
 
92
+ /** Options for PXE.proveTx. */
93
+ export type ProveTxOpts = {
94
+ /** Addresses whose private state and keys are accessible during private execution. */
95
+ scopes: AztecAddress[];
96
+ /** Sender address used to derive discovery tags for private messages (notes, events, logs) this tx emits. */
97
+ senderForTags?: AztecAddress;
98
+ };
99
+
92
100
  /** Options for PXE.profileTx. */
93
101
  export type ProfileTxOpts = {
94
102
  /** The profiling mode to use. */
@@ -97,6 +105,8 @@ export type ProfileTxOpts = {
97
105
  skipProofGeneration?: boolean;
98
106
  /** Addresses whose private state and keys are accessible during private execution. */
99
107
  scopes: AztecAddress[];
108
+ /** Sender address used to derive discovery tags for private messages (notes, events, logs) this tx emits. */
109
+ senderForTags?: AztecAddress;
100
110
  };
101
111
 
102
112
  /** Options for PXE.simulateTx. */
@@ -113,6 +123,8 @@ export type SimulateTxOpts = {
113
123
  overrides?: SimulationOverrides;
114
124
  /** Addresses whose private state and keys are accessible during private execution */
115
125
  scopes: AztecAddress[];
126
+ /** Sender address used to derive discovery tags for private messages (notes, events, logs) this tx emits. */
127
+ senderForTags?: AztecAddress;
116
128
  };
117
129
 
118
130
  /** Options for PXE.executeUtility. */
@@ -368,13 +380,21 @@ export class PXE {
368
380
 
369
381
  // Executes the entrypoint private function, as well as all nested private
370
382
  // functions that might arise.
371
- async #executePrivate(
372
- contractFunctionSimulator: ContractFunctionSimulator,
373
- txRequest: TxExecutionRequest,
374
- anchorBlockHeader: BlockHeader,
375
- scopes: AztecAddress[],
376
- jobId: string,
377
- ): Promise<PrivateExecutionResult> {
383
+ async #executePrivate({
384
+ contractFunctionSimulator,
385
+ txRequest,
386
+ anchorBlockHeader,
387
+ scopes,
388
+ jobId,
389
+ senderForTags,
390
+ }: {
391
+ contractFunctionSimulator: ContractFunctionSimulator;
392
+ txRequest: TxExecutionRequest;
393
+ anchorBlockHeader: BlockHeader;
394
+ scopes: AztecAddress[];
395
+ jobId: string;
396
+ senderForTags?: AztecAddress;
397
+ }): Promise<PrivateExecutionResult> {
378
398
  const { origin: contractAddress, functionSelector } = txRequest;
379
399
 
380
400
  try {
@@ -394,6 +414,7 @@ export class PXE {
394
414
  anchorBlockHeader,
395
415
  scopes,
396
416
  jobId,
417
+ senderForTags,
397
418
  });
398
419
  this.log.debug(`Private simulation completed for ${contractAddress.toString()}:${functionSelector}`);
399
420
  return result;
@@ -740,7 +761,7 @@ export class PXE {
740
761
  * @throws If contract code not found, or public simulation reverts.
741
762
  * Also throws if simulatePublic is true and public simulation reverts.
742
763
  */
743
- public proveTx(txRequest: TxExecutionRequest, scopes: AztecAddress[]): Promise<TxProvingResult> {
764
+ public proveTx(txRequest: TxExecutionRequest, { scopes, senderForTags }: ProveTxOpts): Promise<TxProvingResult> {
744
765
  let privateExecutionResult: PrivateExecutionResult;
745
766
  // We disable proving concurrently mostly out of caution, since it accesses some of our stores. Proving is so
746
767
  // computationally demanding that it'd be rare for someone to try to do it concurrently regardless.
@@ -752,13 +773,14 @@ export class PXE {
752
773
  const anchorBlockHeader = await this.anchorBlockStore.getBlockHeader();
753
774
  const syncTime = syncTimer.ms();
754
775
  const contractFunctionSimulator = this.#getSimulatorForTx();
755
- privateExecutionResult = await this.#executePrivate(
776
+ privateExecutionResult = await this.#executePrivate({
756
777
  contractFunctionSimulator,
757
778
  txRequest,
758
779
  anchorBlockHeader,
759
780
  scopes,
760
781
  jobId,
761
- );
782
+ senderForTags,
783
+ });
762
784
 
763
785
  const {
764
786
  publicInputs,
@@ -828,7 +850,7 @@ export class PXE {
828
850
  */
829
851
  public profileTx(
830
852
  txRequest: TxExecutionRequest,
831
- { profileMode, skipProofGeneration = true, scopes }: ProfileTxOpts,
853
+ { profileMode, skipProofGeneration = true, scopes, senderForTags }: ProfileTxOpts,
832
854
  ): Promise<TxProfileResult> {
833
855
  // We disable concurrent profiles for consistency with simulateTx.
834
856
  return this.#putInJobQueue(async jobId => {
@@ -852,13 +874,14 @@ export class PXE {
852
874
  const syncTime = syncTimer.ms();
853
875
 
854
876
  const contractFunctionSimulator = this.#getSimulatorForTx();
855
- const privateExecutionResult = await this.#executePrivate(
877
+ const privateExecutionResult = await this.#executePrivate({
856
878
  contractFunctionSimulator,
857
879
  txRequest,
858
880
  anchorBlockHeader,
859
881
  scopes,
860
882
  jobId,
861
- );
883
+ senderForTags,
884
+ });
862
885
 
863
886
  const { executionSteps, timings: { proving } = {} } = await this.#prove(
864
887
  txRequest,
@@ -932,6 +955,7 @@ export class PXE {
932
955
  skipKernels = true,
933
956
  overrides,
934
957
  scopes,
958
+ senderForTags,
935
959
  }: SimulateTxOpts,
936
960
  ): Promise<TxSimulationResult> {
937
961
  // We disable concurrent simulations since those might execute oracles which read and write to the PXE stores (e.g.
@@ -974,13 +998,14 @@ export class PXE {
974
998
  }
975
999
 
976
1000
  // Execution of private functions only; no proving, and no kernel logic.
977
- const privateExecutionResult = await this.#executePrivate(
1001
+ const privateExecutionResult = await this.#executePrivate({
978
1002
  contractFunctionSimulator,
979
1003
  txRequest,
980
1004
  anchorBlockHeader,
981
1005
  scopes,
982
1006
  jobId,
983
- );
1007
+ senderForTags,
1008
+ });
984
1009
 
985
1010
  let publicInputs: PrivateKernelTailCircuitPublicInputs | undefined;
986
1011
  let executionSteps: PrivateExecutionStep[] = [];