@aztec/simulator 0.47.0 → 0.48.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.
Files changed (113) hide show
  1. package/dest/acvm/acvm.d.ts +1 -1
  2. package/dest/acvm/acvm.d.ts.map +1 -1
  3. package/dest/acvm/oracle/oracle.d.ts +5 -5
  4. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  5. package/dest/acvm/oracle/oracle.js +13 -16
  6. package/dest/acvm/oracle/typed_oracle.d.ts +12 -9
  7. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  8. package/dest/acvm/oracle/typed_oracle.js +6 -6
  9. package/dest/acvm/serialize.d.ts +0 -11
  10. package/dest/acvm/serialize.d.ts.map +1 -1
  11. package/dest/acvm/serialize.js +1 -26
  12. package/dest/avm/avm_gas.d.ts.map +1 -1
  13. package/dest/avm/avm_gas.js +2 -1
  14. package/dest/avm/fixtures/index.d.ts.map +1 -1
  15. package/dest/avm/fixtures/index.js +2 -2
  16. package/dest/avm/opcodes/commitment.d.ts +16 -0
  17. package/dest/avm/opcodes/commitment.d.ts.map +1 -0
  18. package/dest/avm/opcodes/commitment.js +50 -0
  19. package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
  20. package/dest/avm/serialization/bytecode_serialization.js +3 -1
  21. package/dest/avm/serialization/instruction_serialization.d.ts +4 -3
  22. package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
  23. package/dest/avm/serialization/instruction_serialization.js +6 -5
  24. package/dest/client/client_execution_context.d.ts +20 -17
  25. package/dest/client/client_execution_context.d.ts.map +1 -1
  26. package/dest/client/client_execution_context.js +42 -45
  27. package/dest/client/db_oracle.d.ts +4 -3
  28. package/dest/client/db_oracle.d.ts.map +1 -1
  29. package/dest/client/execution_note_cache.d.ts +17 -13
  30. package/dest/client/execution_note_cache.d.ts.map +1 -1
  31. package/dest/client/execution_note_cache.js +65 -26
  32. package/dest/client/execution_result.d.ts +15 -8
  33. package/dest/client/execution_result.d.ts.map +1 -1
  34. package/dest/client/execution_result.js +40 -16
  35. package/dest/client/private_execution.js +3 -3
  36. package/dest/client/simulator.d.ts +7 -6
  37. package/dest/client/simulator.d.ts.map +1 -1
  38. package/dest/client/simulator.js +14 -12
  39. package/dest/client/test_utils.d.ts +9 -0
  40. package/dest/client/test_utils.d.ts.map +1 -0
  41. package/dest/client/test_utils.js +21 -0
  42. package/dest/client/view_data_oracle.d.ts +2 -1
  43. package/dest/client/view_data_oracle.d.ts.map +1 -1
  44. package/dest/client/view_data_oracle.js +4 -3
  45. package/dest/index.d.ts +0 -1
  46. package/dest/index.d.ts.map +1 -1
  47. package/dest/index.js +1 -2
  48. package/dest/mocks/fixtures.d.ts +5 -5
  49. package/dest/mocks/fixtures.d.ts.map +1 -1
  50. package/dest/mocks/fixtures.js +6 -9
  51. package/dest/public/abstract_phase_manager.d.ts +4 -5
  52. package/dest/public/abstract_phase_manager.d.ts.map +1 -1
  53. package/dest/public/abstract_phase_manager.js +17 -84
  54. package/dest/public/execution.d.ts +8 -10
  55. package/dest/public/execution.d.ts.map +1 -1
  56. package/dest/public/execution.js +10 -1
  57. package/dest/public/executor.d.ts +6 -2
  58. package/dest/public/executor.d.ts.map +1 -1
  59. package/dest/public/executor.js +12 -4
  60. package/dest/public/executor_metrics.d.ts +10 -0
  61. package/dest/public/executor_metrics.d.ts.map +1 -0
  62. package/dest/public/executor_metrics.js +32 -0
  63. package/dest/public/fee_payment.d.ts +2 -2
  64. package/dest/public/fee_payment.d.ts.map +1 -1
  65. package/dest/public/fee_payment.js +9 -10
  66. package/dest/public/hints_builder.d.ts.map +1 -1
  67. package/dest/public/hints_builder.js +1 -1
  68. package/dest/public/index.d.ts +1 -1
  69. package/dest/public/index.d.ts.map +1 -1
  70. package/dest/public/index.js +1 -1
  71. package/dest/public/public_processor.d.ts +3 -3
  72. package/dest/public/public_processor.d.ts.map +1 -1
  73. package/dest/public/public_processor.js +33 -14
  74. package/dest/public/public_processor_metrics.d.ts +19 -0
  75. package/dest/public/public_processor_metrics.d.ts.map +1 -0
  76. package/dest/public/public_processor_metrics.js +57 -0
  77. package/dest/public/side_effect_trace.d.ts +1 -0
  78. package/dest/public/side_effect_trace.d.ts.map +1 -1
  79. package/dest/public/side_effect_trace.js +9 -9
  80. package/package.json +9 -9
  81. package/src/acvm/acvm.ts +1 -1
  82. package/src/acvm/oracle/oracle.ts +13 -30
  83. package/src/acvm/oracle/typed_oracle.ts +12 -31
  84. package/src/acvm/serialize.ts +0 -29
  85. package/src/avm/avm_gas.ts +1 -0
  86. package/src/avm/fixtures/index.ts +1 -0
  87. package/src/avm/opcodes/commitment.ts +66 -0
  88. package/src/avm/serialization/bytecode_serialization.ts +2 -0
  89. package/src/avm/serialization/instruction_serialization.ts +2 -1
  90. package/src/client/client_execution_context.ts +51 -49
  91. package/src/client/db_oracle.ts +9 -3
  92. package/src/client/execution_note_cache.ts +76 -25
  93. package/src/client/execution_result.ts +54 -19
  94. package/src/client/private_execution.ts +2 -2
  95. package/src/client/simulator.ts +18 -14
  96. package/src/client/test_utils.ts +30 -0
  97. package/src/client/view_data_oracle.ts +2 -1
  98. package/src/index.ts +0 -1
  99. package/src/mocks/fixtures.ts +13 -11
  100. package/src/public/abstract_phase_manager.ts +23 -104
  101. package/src/public/execution.ts +30 -14
  102. package/src/public/executor.ts +18 -4
  103. package/src/public/executor_metrics.ts +48 -0
  104. package/src/public/fee_payment.ts +8 -10
  105. package/src/public/hints_builder.ts +2 -2
  106. package/src/public/index.ts +1 -1
  107. package/src/public/public_processor.ts +46 -15
  108. package/src/public/public_processor_metrics.ts +90 -0
  109. package/src/public/side_effect_trace.ts +13 -7
  110. package/dest/utils.d.ts +0 -12
  111. package/dest/utils.d.ts.map +0 -1
  112. package/dest/utils.js +0 -11
  113. package/src/utils.ts +0 -18
@@ -3,6 +3,7 @@ import {
3
3
  type AvmProvingRequest,
4
4
  MerkleTreeId,
5
5
  type NestedProcessReturnValues,
6
+ type PublicExecutionRequest,
6
7
  type PublicKernelNonTailRequest,
7
8
  PublicKernelType,
8
9
  type PublicProvingRequest,
@@ -13,8 +14,6 @@ import {
13
14
  import {
14
15
  type AvmExecutionHints,
15
16
  AztecAddress,
16
- CallRequest,
17
- ClientIvcProof,
18
17
  ContractStorageRead,
19
18
  ContractStorageUpdateRequest,
20
19
  Fr,
@@ -40,7 +39,7 @@ import {
40
39
  NoteHash,
41
40
  Nullifier,
42
41
  PublicCallData,
43
- type PublicCallRequest,
42
+ PublicCallRequest,
44
43
  PublicCallStackItem,
45
44
  PublicCircuitPublicInputs,
46
45
  PublicKernelCircuitPrivateInputs,
@@ -62,7 +61,6 @@ import {
62
61
  getVKSiblingPath,
63
62
  } from '@aztec/noir-protocol-circuits-types';
64
63
  import {
65
- type PublicExecutionRequest,
66
64
  type PublicExecutionResult,
67
65
  type PublicExecutor,
68
66
  accumulateReturnValues,
@@ -165,76 +163,18 @@ export abstract class AbstractPhaseManager {
165
163
  previousKernelArtifact: ProtocolArtifact,
166
164
  ): Promise<PhaseResult>;
167
165
 
168
- public static extractEnqueuedPublicCallsByPhase(tx: Tx): Record<PublicKernelType, PublicCallRequest[]> {
169
- const data = tx.data.forPublic;
170
- if (!data) {
171
- return {
172
- [PublicKernelType.NON_PUBLIC]: [],
173
- [PublicKernelType.SETUP]: [],
174
- [PublicKernelType.APP_LOGIC]: [],
175
- [PublicKernelType.TEARDOWN]: [],
176
- [PublicKernelType.TAIL]: [],
177
- };
178
- }
179
- const publicCallsStack = tx.enqueuedPublicFunctionCalls.slice().reverse();
180
- const nonRevertibleCallStack = data.endNonRevertibleData.publicCallStack.filter(i => !i.isEmpty());
181
- const revertibleCallStack = data.end.publicCallStack.filter(i => !i.isEmpty());
182
-
183
- const callRequestsStack = publicCallsStack
184
- .map(call => call.toCallRequest())
185
- .filter(
186
- // filter out enqueued calls that are not in the public call stack
187
- // TODO mitch left a question about whether this is only needed when unit testing
188
- // with mock data
189
- call => revertibleCallStack.find(p => p.equals(call)) || nonRevertibleCallStack.find(p => p.equals(call)),
190
- );
191
-
192
- const teardownCallStack = tx.publicTeardownFunctionCall.isEmpty() ? [] : [tx.publicTeardownFunctionCall];
193
-
194
- if (callRequestsStack.length === 0) {
195
- return {
196
- [PublicKernelType.NON_PUBLIC]: [],
197
- [PublicKernelType.SETUP]: [],
198
- [PublicKernelType.APP_LOGIC]: [],
199
- [PublicKernelType.TEARDOWN]: teardownCallStack,
200
- [PublicKernelType.TAIL]: [],
201
- };
202
- }
203
-
204
- // find the first call that is revertible
205
- const firstRevertibleCallIndex = callRequestsStack.findIndex(
206
- c => revertibleCallStack.findIndex(p => p.equals(c)) !== -1,
207
- );
208
-
209
- if (firstRevertibleCallIndex === 0) {
210
- return {
211
- [PublicKernelType.NON_PUBLIC]: [],
212
- [PublicKernelType.SETUP]: [],
213
- [PublicKernelType.APP_LOGIC]: publicCallsStack,
214
- [PublicKernelType.TEARDOWN]: teardownCallStack,
215
- [PublicKernelType.TAIL]: [],
216
- };
217
- } else if (firstRevertibleCallIndex === -1) {
218
- // there's no app logic, split the functions between setup (many) and teardown (just one function call)
219
- return {
220
- [PublicKernelType.NON_PUBLIC]: [],
221
- [PublicKernelType.SETUP]: publicCallsStack,
222
- [PublicKernelType.APP_LOGIC]: [],
223
- [PublicKernelType.TEARDOWN]: teardownCallStack,
224
- [PublicKernelType.TAIL]: [],
225
- };
226
- } else {
227
- return {
228
- [PublicKernelType.NON_PUBLIC]: [],
229
- [PublicKernelType.SETUP]: publicCallsStack.slice(0, firstRevertibleCallIndex),
230
- [PublicKernelType.APP_LOGIC]: publicCallsStack.slice(firstRevertibleCallIndex),
231
- [PublicKernelType.TEARDOWN]: teardownCallStack,
232
- [PublicKernelType.TAIL]: [],
233
- };
234
- }
166
+ public static extractEnqueuedPublicCallsByPhase(tx: Tx): Record<PublicKernelType, PublicExecutionRequest[]> {
167
+ const teardownRequest = tx.getPublicTeardownExecutionRequest();
168
+ return {
169
+ [PublicKernelType.NON_PUBLIC]: [],
170
+ [PublicKernelType.SETUP]: tx.getNonRevertiblePublicExecutionRequests(),
171
+ [PublicKernelType.APP_LOGIC]: tx.getRevertiblePublicExecutionRequests(),
172
+ [PublicKernelType.TEARDOWN]: teardownRequest ? [teardownRequest] : [],
173
+ [PublicKernelType.TAIL]: [],
174
+ };
235
175
  }
236
176
 
237
- protected extractEnqueuedPublicCalls(tx: Tx): PublicCallRequest[] {
177
+ protected extractEnqueuedPublicCalls(tx: Tx): PublicExecutionRequest[] {
238
178
  const calls = AbstractPhaseManager.extractEnqueuedPublicCallsByPhase(tx)[this.phase];
239
179
 
240
180
  return calls;
@@ -245,7 +185,7 @@ export abstract class AbstractPhaseManager {
245
185
  previousPublicKernelOutput: PublicKernelCircuitPublicInputs,
246
186
  previousKernelArtifact: ProtocolArtifact,
247
187
  ): Promise<TxPublicCallsResult> {
248
- const enqueuedCalls = this.extractEnqueuedPublicCalls(tx);
188
+ const enqueuedCalls = [...this.extractEnqueuedPublicCalls(tx)].reverse();
249
189
 
250
190
  if (!enqueuedCalls || !enqueuedCalls.length) {
251
191
  return {
@@ -299,7 +239,7 @@ export abstract class AbstractPhaseManager {
299
239
 
300
240
  // Sanity check for a current upstream assumption.
301
241
  // Consumers of the result seem to expect "reverted <=> revertReason !== undefined".
302
- const functionSelector = result.executionRequest.functionSelector.toString();
242
+ const functionSelector = result.executionRequest.callContext.functionSelector.toString();
303
243
  if (result.reverted && !result.revertReason) {
304
244
  throw new Error(
305
245
  `Simulation of ${result.executionRequest.contractAddress.toString()}:${functionSelector}(${
@@ -420,7 +360,7 @@ export abstract class AbstractPhaseManager {
420
360
  const previousKernel = this.getPreviousKernelData(previousOutput, previousCircuit);
421
361
 
422
362
  // We take a deep copy (clone) of these inputs to be passed to the prover
423
- const inputs = new PublicKernelCircuitPrivateInputs(previousKernel, ClientIvcProof.empty(), callData);
363
+ const inputs = new PublicKernelCircuitPrivateInputs(previousKernel, callData);
424
364
  switch (this.phase) {
425
365
  case PublicKernelType.SETUP:
426
366
  return [inputs.clone(), await this.publicKernel.publicKernelCircuitSetup(inputs), 'PublicKernelSetupArtifact'];
@@ -460,13 +400,6 @@ export abstract class AbstractPhaseManager {
460
400
  const publicDataTreeInfo = await this.db.getTreeInfo(MerkleTreeId.PUBLIC_DATA_TREE);
461
401
  this.historicalHeader.state.partial.publicDataTree.root = Fr.fromBuffer(publicDataTreeInfo.root);
462
402
 
463
- const callStackPreimages = await this.getPublicCallStackPreimages(result);
464
- const publicCallStackHashes = padArrayEnd(
465
- callStackPreimages.map(c => c.getCompressed().hash()),
466
- Fr.ZERO,
467
- MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL,
468
- );
469
-
470
403
  const publicCircuitPublicInputs = PublicCircuitPublicInputs.from({
471
404
  callContext: result.executionRequest.callContext,
472
405
  proverAddress: AztecAddress.ZERO,
@@ -507,7 +440,11 @@ export abstract class AbstractPhaseManager {
507
440
  ContractStorageUpdateRequest.empty(),
508
441
  MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL,
509
442
  ),
510
- publicCallStackHashes,
443
+ publicCallRequests: padArrayEnd(
444
+ result.publicCallRequests,
445
+ PublicCallRequest.empty(),
446
+ MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL,
447
+ ),
511
448
  unencryptedLogsHashes: padArrayEnd(result.unencryptedLogsHashes, LogHash.empty(), MAX_UNENCRYPTED_LOGS_PER_CALL),
512
449
  historicalHeader: this.historicalHeader,
513
450
  globalVariables: this.globalVariables,
@@ -520,23 +457,12 @@ export abstract class AbstractPhaseManager {
520
457
 
521
458
  return new PublicCallStackItem(
522
459
  result.executionRequest.contractAddress,
523
- new FunctionData(result.executionRequest.functionSelector, false),
460
+ new FunctionData(result.executionRequest.callContext.functionSelector, false),
524
461
  publicCircuitPublicInputs,
525
462
  isExecutionRequest,
526
463
  );
527
464
  }
528
465
 
529
- protected async getPublicCallStackPreimages(result: PublicExecutionResult): Promise<PublicCallStackItem[]> {
530
- const nested = result.nestedExecutions;
531
- if (nested.length > MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL) {
532
- throw new Error(
533
- `Public call stack size exceeded (max ${MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL}, got ${nested.length})`,
534
- );
535
- }
536
-
537
- return await Promise.all(nested.map(n => this.getPublicCallStackItem(n)));
538
- }
539
-
540
466
  /**
541
467
  * Looks at the side effects of a transaction and returns the highest counter
542
468
  * @param tx - A transaction
@@ -562,10 +488,7 @@ export abstract class AbstractPhaseManager {
562
488
 
563
489
  let max = 0;
564
490
  for (const sideEffect of sideEffectCounters) {
565
- if ('startSideEffectCounter' in sideEffect) {
566
- // look at both start and end counters because for enqueued public calls start > 0 while end === 0
567
- max = Math.max(max, sideEffect.startSideEffectCounter.toNumber(), sideEffect.endSideEffectCounter.toNumber());
568
- } else if ('counter' in sideEffect) {
491
+ if ('counter' in sideEffect) {
569
492
  max = Math.max(max, sideEffect.counter);
570
493
  } else {
571
494
  throw new Error('Unknown side effect type');
@@ -593,10 +516,6 @@ export abstract class AbstractPhaseManager {
593
516
  protected async getPublicCallData(result: PublicExecutionResult, isExecutionRequest = false) {
594
517
  const bytecodeHash = await this.getBytecodeHash(result);
595
518
  const callStackItem = await this.getPublicCallStackItem(result, isExecutionRequest);
596
- const publicCallRequests = (await this.getPublicCallStackPreimages(result)).map(c =>
597
- c.toCallRequest(callStackItem.publicInputs.callContext),
598
- );
599
- const publicCallStack = padArrayEnd(publicCallRequests, CallRequest.empty(), MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL);
600
- return new PublicCallData(callStackItem, publicCallStack, makeEmptyProof(), bytecodeHash);
519
+ return new PublicCallData(callStackItem, makeEmptyProof(), bytecodeHash);
601
520
  }
602
521
  }
@@ -1,18 +1,26 @@
1
- import { type SimulationError, type UnencryptedFunctionL2Logs } from '@aztec/circuit-types';
1
+ import {
2
+ type PublicExecutionRequest,
3
+ type SimulationError,
4
+ type UnencryptedFunctionL2Logs,
5
+ } from '@aztec/circuit-types';
2
6
  import {
3
7
  type AvmExecutionHints,
4
8
  type ContractStorageRead,
5
9
  type ContractStorageUpdateRequest,
6
10
  type Fr,
11
+ Gas,
7
12
  type L2ToL1Message,
8
13
  type LogHash,
9
14
  type NoteHash,
10
15
  type Nullifier,
11
- type PublicCallRequest,
16
+ PublicCallRequest,
17
+ PublicCallStackItemCompressed,
12
18
  type ReadRequest,
19
+ RevertCode,
13
20
  } from '@aztec/circuits.js';
21
+ import { computeVarArgsHash } from '@aztec/circuits.js/hash';
14
22
 
15
- import { type Gas } from '../avm/avm_gas.js';
23
+ import { type Gas as AvmGas } from '../avm/avm_gas.js';
16
24
 
17
25
  /**
18
26
  * The public function execution result.
@@ -26,9 +34,9 @@ export interface PublicExecutionResult {
26
34
  /** The side effect counter after executing this function call */
27
35
  endSideEffectCounter: Fr;
28
36
  /** How much gas was available for this public execution. */
29
- startGasLeft: Gas;
37
+ startGasLeft: AvmGas;
30
38
  /** How much gas was left after this public execution. */
31
- endGasLeft: Gas;
39
+ endGasLeft: AvmGas;
32
40
  /** Transaction fee set for this tx. */
33
41
  transactionFee: Fr;
34
42
 
@@ -79,6 +87,8 @@ export interface PublicExecutionResult {
79
87
 
80
88
  // TODO(dbanks12): add contract instance read requests
81
89
 
90
+ /** The requests to call public functions made by this call. */
91
+ publicCallRequests: PublicCallRequest[];
82
92
  /** The results of nested calls. */
83
93
  nestedExecutions: this[];
84
94
 
@@ -89,15 +99,6 @@ export interface PublicExecutionResult {
89
99
  functionName: string;
90
100
  }
91
101
 
92
- /**
93
- * The execution request of a public function.
94
- * A subset of PublicCallRequest
95
- */
96
- export type PublicExecutionRequest = Pick<
97
- PublicCallRequest,
98
- 'contractAddress' | 'functionSelector' | 'callContext' | 'args'
99
- >;
100
-
101
102
  /**
102
103
  * Returns if the input is a public execution result and not just a public execution.
103
104
  * @param input - Public execution or public execution result.
@@ -131,3 +132,18 @@ export function checkValidStaticCall(
131
132
  throw new Error('Static call cannot update the state, emit L2->L1 messages or generate logs');
132
133
  }
133
134
  }
135
+
136
+ export function resultToPublicCallRequest(result: PublicExecutionResult) {
137
+ const request = result.executionRequest;
138
+ const item = new PublicCallStackItemCompressed(
139
+ request.contractAddress,
140
+ request.callContext,
141
+ computeVarArgsHash(request.args),
142
+ computeVarArgsHash(result.returnValues),
143
+ // TODO(@just-mitch): need better mapping from simulator to revert code.
144
+ result.reverted ? RevertCode.APP_LOGIC_REVERTED : RevertCode.OK,
145
+ Gas.from(result.startGasLeft),
146
+ Gas.from(result.endGasLeft),
147
+ );
148
+ return new PublicCallRequest(item, result.startSideEffectCounter.toNumber());
149
+ }
@@ -1,7 +1,9 @@
1
+ import { type PublicExecutionRequest } from '@aztec/circuit-types';
1
2
  import { type AvmSimulationStats } from '@aztec/circuit-types/stats';
2
3
  import { Fr, Gas, type GlobalVariables, type Header, type Nullifier, type TxContext } from '@aztec/circuits.js';
3
4
  import { createDebugLogger } from '@aztec/foundation/log';
4
5
  import { Timer } from '@aztec/foundation/timer';
6
+ import { type TelemetryClient } from '@aztec/telemetry-client';
5
7
 
6
8
  import { AvmContext } from '../avm/avm_context.js';
7
9
  import { AvmExecutionEnvironment } from '../avm/avm_execution_environment.js';
@@ -10,19 +12,25 @@ import { AvmSimulator } from '../avm/avm_simulator.js';
10
12
  import { HostStorage } from '../avm/journal/host_storage.js';
11
13
  import { AvmPersistableStateManager } from '../avm/journal/index.js';
12
14
  import { type CommitmentsDB, type PublicContractsDB, type PublicStateDB } from './db_interfaces.js';
13
- import { type PublicExecutionRequest, type PublicExecutionResult } from './execution.js';
15
+ import { type PublicExecutionResult } from './execution.js';
16
+ import { ExecutorMetrics } from './executor_metrics.js';
14
17
  import { PublicSideEffectTrace } from './side_effect_trace.js';
15
18
 
16
19
  /**
17
20
  * Handles execution of public functions.
18
21
  */
19
22
  export class PublicExecutor {
23
+ metrics: ExecutorMetrics;
24
+
20
25
  constructor(
21
26
  private readonly publicStorageDB: PublicStateDB,
22
27
  private readonly contractsDb: PublicContractsDB,
23
28
  private readonly commitmentsDb: CommitmentsDB,
24
29
  private readonly header: Header,
25
- ) {}
30
+ client: TelemetryClient,
31
+ ) {
32
+ this.metrics = new ExecutorMetrics(client, 'PublicExecutor');
33
+ }
26
34
 
27
35
  static readonly log = createDebugLogger('aztec:simulator:public_executor');
28
36
 
@@ -47,7 +55,7 @@ export class PublicExecutor {
47
55
  startSideEffectCounter: number = 0,
48
56
  ): Promise<PublicExecutionResult> {
49
57
  const address = executionRequest.contractAddress;
50
- const selector = executionRequest.functionSelector;
58
+ const selector = executionRequest.callContext.functionSelector;
51
59
  const fnName = (await this.contractsDb.getDebugFunctionName(address, selector)) ?? `${address}:${selector}`;
52
60
 
53
61
  PublicExecutor.log.verbose(`[AVM] Executing public external function ${fnName}.`);
@@ -101,6 +109,12 @@ export class PublicExecutor {
101
109
  fnName,
102
110
  );
103
111
 
112
+ if (publicExecutionResult.reverted) {
113
+ this.metrics.recordFunctionSimulationFailure();
114
+ } else {
115
+ this.metrics.recordFunctionSimulation(bytecode.length, timer.ms());
116
+ }
117
+
104
118
  return publicExecutionResult;
105
119
  }
106
120
  }
@@ -122,7 +136,7 @@ function createAvmExecutionEnvironment(
122
136
  executionRequest.contractAddress,
123
137
  executionRequest.callContext.storageContractAddress,
124
138
  executionRequest.callContext.msgSender,
125
- executionRequest.functionSelector,
139
+ executionRequest.callContext.functionSelector,
126
140
  /*contractCallDepth=*/ Fr.zero(),
127
141
  transactionFee,
128
142
  header,
@@ -0,0 +1,48 @@
1
+ import {
2
+ Attributes,
3
+ type Histogram,
4
+ Metrics,
5
+ type TelemetryClient,
6
+ type UpDownCounter,
7
+ ValueType,
8
+ } from '@aztec/telemetry-client';
9
+
10
+ export class ExecutorMetrics {
11
+ private fnCount: UpDownCounter;
12
+ private fnDuration: Histogram;
13
+ private bytecodeSize: Histogram;
14
+
15
+ constructor(client: TelemetryClient, name = 'PublicExecutor') {
16
+ const meter = client.getMeter(name);
17
+
18
+ this.fnCount = meter.createUpDownCounter(Metrics.PUBLIC_EXECUTOR_SIMULATION_COUNT, {
19
+ description: 'Number of functions executed',
20
+ });
21
+
22
+ this.fnDuration = meter.createHistogram(Metrics.PUBLIC_EXECUTOR_SIMULATION_DURATION, {
23
+ description: 'How long it takes to execute a function',
24
+ unit: 'ms',
25
+ valueType: ValueType.INT,
26
+ });
27
+
28
+ this.bytecodeSize = meter.createHistogram(Metrics.PUBLIC_EXECUTION_SIMULATION_BYTECODE_SIZE, {
29
+ description: 'Size of the function bytecode',
30
+ unit: 'By',
31
+ valueType: ValueType.INT,
32
+ });
33
+ }
34
+
35
+ recordFunctionSimulation(bytecodeSize: number, durationMs: number) {
36
+ this.fnCount.add(1, {
37
+ [Attributes.OK]: true,
38
+ });
39
+ this.bytecodeSize.record(bytecodeSize);
40
+ this.fnDuration.record(Math.ceil(durationMs));
41
+ }
42
+
43
+ recordFunctionSimulationFailure() {
44
+ this.fnCount.add(1, {
45
+ [Attributes.OK]: false,
46
+ });
47
+ }
48
+ }
@@ -1,26 +1,24 @@
1
- import { GAS_TOKEN_ADDRESS } from '@aztec/circuits.js';
2
- import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash';
1
+ import { FEE_JUICE_ADDRESS } from '@aztec/circuits.js';
2
+ import { computePublicDataTreeLeafSlot, deriveStorageSlotInMap } from '@aztec/circuits.js/hash';
3
3
  import { AztecAddress } from '@aztec/foundation/aztec-address';
4
4
  import { Fr } from '@aztec/foundation/fields';
5
- import { GasTokenArtifact } from '@aztec/protocol-contracts/gas-token';
6
-
7
- import { computeSlotForMapping } from '../utils.js';
5
+ import { FeeJuiceArtifact } from '@aztec/protocol-contracts/fee-juice';
8
6
 
9
7
  /**
10
- * Computes the storage slot within the gas token contract for the balance of the fee payer.
8
+ * Computes the storage slot within the Fee Juice contract for the balance of the fee payer.
11
9
  */
12
10
  export function computeFeePayerBalanceStorageSlot(feePayer: AztecAddress) {
13
- return computeSlotForMapping(GasTokenArtifact.storageLayout.balances.slot, feePayer);
11
+ return deriveStorageSlotInMap(FeeJuiceArtifact.storageLayout.balances.slot, feePayer);
14
12
  }
15
13
 
16
14
  /**
17
- * Computes the leaf slot in the public data tree for the balance of the fee payer in the gas token.
15
+ * Computes the leaf slot in the public data tree for the balance of the fee payer in the Fee Juice.
18
16
  */
19
17
  export function computeFeePayerBalanceLeafSlot(feePayer: AztecAddress): Fr {
20
18
  if (feePayer.isZero()) {
21
19
  return Fr.ZERO;
22
20
  }
23
- const gasToken = AztecAddress.fromBigInt(GAS_TOKEN_ADDRESS);
21
+ const feeJuice = AztecAddress.fromBigInt(FEE_JUICE_ADDRESS);
24
22
  const balanceSlot = computeFeePayerBalanceStorageSlot(feePayer);
25
- return computePublicDataTreeLeafSlot(gasToken, balanceSlot);
23
+ return computePublicDataTreeLeafSlot(feeJuice, balanceSlot);
26
24
  }
@@ -1,4 +1,4 @@
1
- import { MerkleTreeId } from '@aztec/circuit-types';
1
+ import { type IndexedTreeId, MerkleTreeId } from '@aztec/circuit-types';
2
2
  import {
3
3
  type Fr,
4
4
  type MAX_NULLIFIERS_PER_TX,
@@ -23,7 +23,7 @@ import {
23
23
  buildSiloedNullifierReadRequestHints,
24
24
  } from '@aztec/circuits.js';
25
25
  import { type Tuple } from '@aztec/foundation/serialize';
26
- import { type IndexedTreeId, type MerkleTreeOperations } from '@aztec/world-state';
26
+ import { type MerkleTreeOperations } from '@aztec/world-state';
27
27
 
28
28
  export class HintsBuilder {
29
29
  constructor(private db: MerkleTreeOperations) {}
@@ -1,6 +1,6 @@
1
1
  export * from './abstract_phase_manager.js';
2
2
  export * from './db_interfaces.js';
3
- export { isPublicExecutionResult, type PublicExecutionRequest, type PublicExecutionResult } from './execution.js';
3
+ export { isPublicExecutionResult, type PublicExecutionResult } from './execution.js';
4
4
  export { PublicExecutor } from './executor.js';
5
5
  export * from './fee_payment.js';
6
6
  export { HintsBuilder } from './hints_builder.js';
@@ -13,7 +13,8 @@ import {
13
13
  } from '@aztec/circuit-types';
14
14
  import {
15
15
  AztecAddress,
16
- GAS_TOKEN_ADDRESS,
16
+ ContractClassRegisteredEvent,
17
+ FEE_JUICE_ADDRESS,
17
18
  type GlobalVariables,
18
19
  type Header,
19
20
  type KernelCircuitPublicInputs,
@@ -23,7 +24,9 @@ import {
23
24
  } from '@aztec/circuits.js';
24
25
  import { times } from '@aztec/foundation/collection';
25
26
  import { createDebugLogger } from '@aztec/foundation/log';
27
+ import { Timer } from '@aztec/foundation/timer';
26
28
  import { type ProtocolArtifact } from '@aztec/noir-protocol-circuits-types';
29
+ import { ClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer';
27
30
  import {
28
31
  PublicExecutor,
29
32
  type PublicStateDB,
@@ -40,6 +43,7 @@ import { PhaseManagerFactory } from './phase_manager_factory.js';
40
43
  import { ContractsDataSourcePublicDB, WorldStateDB, WorldStatePublicDB } from './public_db_sources.js';
41
44
  import { RealPublicKernelCircuitSimulator } from './public_kernel.js';
42
45
  import { type PublicKernelCircuitSimulator } from './public_kernel_circuit_simulator.js';
46
+ import { PublicProcessorMetrics } from './public_processor_metrics.js';
43
47
 
44
48
  /**
45
49
  * Creates new instances of PublicProcessor given the provided merkle tree db and contract data source.
@@ -56,18 +60,24 @@ export class PublicProcessorFactory {
56
60
  * Creates a new instance of a PublicProcessor.
57
61
  * @param historicalHeader - The header of a block previous to the one in which the tx is included.
58
62
  * @param globalVariables - The global variables for the block being processed.
59
- * @param newContracts - Provides access to contract bytecode for public executions.
60
63
  * @returns A new instance of a PublicProcessor.
61
64
  */
62
- public create(historicalHeader: Header | undefined, globalVariables: GlobalVariables): PublicProcessor {
63
- historicalHeader = historicalHeader ?? this.merkleTree.getInitialHeader();
64
-
65
+ public create(maybeHistoricalHeader: Header | undefined, globalVariables: GlobalVariables): PublicProcessor {
66
+ const { merkleTree, telemetryClient } = this;
67
+ const historicalHeader = maybeHistoricalHeader ?? merkleTree.getInitialHeader();
65
68
  const publicContractsDB = new ContractsDataSourcePublicDB(this.contractDataSource);
66
- const worldStatePublicDB = new WorldStatePublicDB(this.merkleTree);
67
- const worldStateDB = new WorldStateDB(this.merkleTree);
68
- const publicExecutor = new PublicExecutor(worldStatePublicDB, publicContractsDB, worldStateDB, historicalHeader);
69
+
70
+ const worldStatePublicDB = new WorldStatePublicDB(merkleTree);
71
+ const worldStateDB = new WorldStateDB(merkleTree);
72
+ const publicExecutor = new PublicExecutor(
73
+ worldStatePublicDB,
74
+ publicContractsDB,
75
+ worldStateDB,
76
+ historicalHeader,
77
+ telemetryClient,
78
+ );
69
79
  return new PublicProcessor(
70
- this.merkleTree,
80
+ merkleTree,
71
81
  publicExecutor,
72
82
  new RealPublicKernelCircuitSimulator(this.simulator),
73
83
  globalVariables,
@@ -84,7 +94,7 @@ export class PublicProcessorFactory {
84
94
  * any public function calls in them. Txs with private calls only are unaffected.
85
95
  */
86
96
  export class PublicProcessor {
87
- public readonly tracer: Tracer;
97
+ private metrics: PublicProcessorMetrics;
88
98
  constructor(
89
99
  protected db: MerkleTreeOperations,
90
100
  protected publicExecutor: PublicExecutor,
@@ -96,7 +106,11 @@ export class PublicProcessor {
96
106
  telemetryClient: TelemetryClient,
97
107
  private log = createDebugLogger('aztec:sequencer:public-processor'),
98
108
  ) {
99
- this.tracer = telemetryClient.getTracer('PublicProcessor');
109
+ this.metrics = new PublicProcessorMetrics(telemetryClient, 'PublicProcessor');
110
+ }
111
+
112
+ get tracer(): Tracer {
113
+ return this.metrics.tracer;
100
114
  }
101
115
 
102
116
  /**
@@ -188,12 +202,12 @@ export class PublicProcessor {
188
202
  return finalPublicDataUpdateRequests;
189
203
  }
190
204
 
191
- const gasToken = AztecAddress.fromBigInt(GAS_TOKEN_ADDRESS);
205
+ const feeJuiceAddress = AztecAddress.fromBigInt(FEE_JUICE_ADDRESS);
192
206
  const balanceSlot = computeFeePayerBalanceStorageSlot(feePayer);
193
207
  const leafSlot = computeFeePayerBalanceLeafSlot(feePayer);
194
208
  const txFee = tx.data.getTransactionFee(this.globalVariables.gasFees);
195
209
 
196
- this.log.debug(`Deducting ${txFee} balance in gas tokens for ${feePayer}`);
210
+ this.log.debug(`Deducting ${txFee} balance in Fee Juice for ${feePayer}`);
197
211
 
198
212
  const existingBalanceWriteIndex = finalPublicDataUpdateRequests.findIndex(request =>
199
213
  request.leafSlot.equals(leafSlot),
@@ -202,14 +216,14 @@ export class PublicProcessor {
202
216
  const balance =
203
217
  existingBalanceWriteIndex > -1
204
218
  ? finalPublicDataUpdateRequests[existingBalanceWriteIndex].newValue
205
- : await this.publicStateDB.storageRead(gasToken, balanceSlot);
219
+ : await this.publicStateDB.storageRead(feeJuiceAddress, balanceSlot);
206
220
 
207
221
  if (balance.lt(txFee)) {
208
222
  throw new Error(`Not enough balance for fee payer to pay for transaction (got ${balance} needs ${txFee})`);
209
223
  }
210
224
 
211
225
  const updatedBalance = balance.sub(txFee);
212
- await this.publicStateDB.storageWrite(gasToken, balanceSlot, updatedBalance);
226
+ await this.publicStateDB.storageWrite(feeJuiceAddress, balanceSlot, updatedBalance);
213
227
 
214
228
  finalPublicDataUpdateRequests[
215
229
  existingBalanceWriteIndex > -1 ? existingBalanceWriteIndex : MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX
@@ -222,6 +236,7 @@ export class PublicProcessor {
222
236
  [Attributes.TX_HASH]: tx.getTxHash().toString(),
223
237
  }))
224
238
  private async processTxWithPublicCalls(tx: Tx): Promise<[ProcessedTx, NestedProcessReturnValues[]]> {
239
+ const timer = new Timer();
225
240
  let returnValues: NestedProcessReturnValues[] = [];
226
241
  const publicProvingRequests: PublicProvingRequest[] = [];
227
242
  let phase: AbstractPhaseManager | undefined = PhaseManagerFactory.phaseFromTx(
@@ -240,8 +255,18 @@ export class PublicProcessor {
240
255
  let finalKernelOutput: KernelCircuitPublicInputs | undefined;
241
256
  let revertReason: SimulationError | undefined;
242
257
  const gasUsed: ProcessedTx['gasUsed'] = {};
258
+ let phaseCount = 0;
243
259
  while (phase) {
260
+ phaseCount++;
261
+ const phaseTimer = new Timer();
244
262
  const output = await phase.handle(tx, publicKernelPublicInput, lastKernelArtifact);
263
+
264
+ if (output.revertReason) {
265
+ this.metrics.recordRevertedPhase(phase.phase);
266
+ } else {
267
+ this.metrics.recordPhaseDuration(phase.phase, phaseTimer.ms());
268
+ }
269
+
245
270
  gasUsed[phase.phase] = output.gasUsed;
246
271
  if (phase.phase === PublicKernelType.APP_LOGIC) {
247
272
  returnValues = output.returnValues;
@@ -265,9 +290,15 @@ export class PublicProcessor {
265
290
  }
266
291
 
267
292
  if (!finalKernelOutput) {
293
+ this.metrics.recordFailedTx();
268
294
  throw new Error('Final public kernel was not executed.');
269
295
  }
270
296
 
297
+ this.metrics.recordClassRegistration(
298
+ ...ContractClassRegisteredEvent.fromLogs(tx.unencryptedLogs.unrollLogs(), ClassRegistererAddress),
299
+ );
300
+
301
+ this.metrics.recordTx(phaseCount, timer.ms());
271
302
  const processedTx = makeProcessedTx(tx, finalKernelOutput, publicProvingRequests, revertReason, gasUsed);
272
303
  return [processedTx, returnValues];
273
304
  }