@aztec/simulator 0.36.0 → 0.38.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 (118) 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/acvm.js +2 -2
  4. package/dest/acvm/oracle/oracle.d.ts +6 -4
  5. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  6. package/dest/acvm/oracle/oracle.js +39 -8
  7. package/dest/acvm/oracle/typed_oracle.d.ts +5 -3
  8. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  9. package/dest/acvm/oracle/typed_oracle.js +9 -3
  10. package/dest/avm/avm_gas.d.ts.map +1 -1
  11. package/dest/avm/avm_gas.js +2 -1
  12. package/dest/avm/avm_memory_types.d.ts +1 -1
  13. package/dest/avm/avm_memory_types.d.ts.map +1 -1
  14. package/dest/avm/avm_simulator.d.ts.map +1 -1
  15. package/dest/avm/avm_simulator.js +3 -1
  16. package/dest/avm/journal/journal.d.ts +20 -1
  17. package/dest/avm/journal/journal.d.ts.map +1 -1
  18. package/dest/avm/journal/journal.js +69 -9
  19. package/dest/avm/journal/nullifiers.d.ts +3 -1
  20. package/dest/avm/journal/nullifiers.d.ts.map +1 -1
  21. package/dest/avm/journal/nullifiers.js +14 -6
  22. package/dest/avm/journal/public_storage.d.ts +10 -1
  23. package/dest/avm/journal/public_storage.d.ts.map +1 -1
  24. package/dest/avm/journal/public_storage.js +17 -2
  25. package/dest/avm/journal/trace.d.ts +1 -4
  26. package/dest/avm/journal/trace.d.ts.map +1 -1
  27. package/dest/avm/journal/trace.js +4 -5
  28. package/dest/avm/journal/trace_types.d.ts +1 -0
  29. package/dest/avm/journal/trace_types.d.ts.map +1 -1
  30. package/dest/avm/journal/trace_types.js +1 -1
  31. package/dest/avm/opcodes/bitwise.d.ts +4 -1
  32. package/dest/avm/opcodes/bitwise.d.ts.map +1 -1
  33. package/dest/avm/opcodes/bitwise.js +14 -2
  34. package/dest/avm/opcodes/environment_getters.d.ts +5 -0
  35. package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
  36. package/dest/avm/opcodes/environment_getters.js +8 -1
  37. package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
  38. package/dest/avm/opcodes/external_calls.js +14 -13
  39. package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
  40. package/dest/avm/serialization/bytecode_serialization.js +3 -2
  41. package/dest/avm/serialization/instruction_serialization.d.ts +39 -38
  42. package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
  43. package/dest/avm/serialization/instruction_serialization.js +40 -39
  44. package/dest/client/client_execution_context.d.ts +31 -18
  45. package/dest/client/client_execution_context.d.ts.map +1 -1
  46. package/dest/client/client_execution_context.js +48 -31
  47. package/dest/client/db_oracle.d.ts +11 -4
  48. package/dest/client/db_oracle.d.ts.map +1 -1
  49. package/dest/client/execution_result.d.ts +19 -15
  50. package/dest/client/execution_result.d.ts.map +1 -1
  51. package/dest/client/execution_result.js +45 -12
  52. package/dest/client/logs_cache.d.ts +33 -0
  53. package/dest/client/logs_cache.d.ts.map +1 -0
  54. package/dest/client/logs_cache.js +59 -0
  55. package/dest/client/private_execution.d.ts +2 -2
  56. package/dest/client/private_execution.d.ts.map +1 -1
  57. package/dest/client/private_execution.js +3 -7
  58. package/dest/client/simulator.d.ts +3 -3
  59. package/dest/client/simulator.d.ts.map +1 -1
  60. package/dest/client/simulator.js +3 -2
  61. package/dest/client/unconstrained_execution.d.ts +2 -2
  62. package/dest/client/unconstrained_execution.d.ts.map +1 -1
  63. package/dest/client/unconstrained_execution.js +1 -1
  64. package/dest/client/view_data_oracle.d.ts +7 -0
  65. package/dest/client/view_data_oracle.d.ts.map +1 -1
  66. package/dest/client/view_data_oracle.js +10 -1
  67. package/dest/mocks/fixtures.d.ts.map +1 -1
  68. package/dest/mocks/fixtures.js +3 -1
  69. package/dest/public/abstract_phase_manager.d.ts +2 -0
  70. package/dest/public/abstract_phase_manager.d.ts.map +1 -1
  71. package/dest/public/abstract_phase_manager.js +13 -6
  72. package/dest/public/execution.d.ts +9 -0
  73. package/dest/public/execution.d.ts.map +1 -1
  74. package/dest/public/execution.js +1 -1
  75. package/dest/public/executor.d.ts +2 -2
  76. package/dest/public/executor.d.ts.map +1 -1
  77. package/dest/public/executor.js +34 -14
  78. package/dest/public/public_execution_context.d.ts +10 -4
  79. package/dest/public/public_execution_context.d.ts.map +1 -1
  80. package/dest/public/public_execution_context.js +19 -6
  81. package/dest/public/tail_phase_manager.d.ts +0 -1
  82. package/dest/public/tail_phase_manager.d.ts.map +1 -1
  83. package/dest/public/tail_phase_manager.js +3 -26
  84. package/dest/public/transitional_adaptors.d.ts +4 -17
  85. package/dest/public/transitional_adaptors.d.ts.map +1 -1
  86. package/dest/public/transitional_adaptors.js +27 -119
  87. package/package.json +8 -8
  88. package/src/acvm/acvm.ts +2 -2
  89. package/src/acvm/oracle/oracle.ts +63 -10
  90. package/src/acvm/oracle/typed_oracle.ts +12 -3
  91. package/src/avm/avm_gas.ts +1 -0
  92. package/src/avm/avm_memory_types.ts +1 -1
  93. package/src/avm/avm_simulator.ts +2 -0
  94. package/src/avm/journal/journal.ts +133 -9
  95. package/src/avm/journal/nullifiers.ts +19 -8
  96. package/src/avm/journal/public_storage.ts +23 -2
  97. package/src/avm/journal/trace.ts +3 -4
  98. package/src/avm/journal/trace_types.ts +1 -0
  99. package/src/avm/opcodes/bitwise.ts +18 -7
  100. package/src/avm/opcodes/environment_getters.ts +9 -0
  101. package/src/avm/opcodes/external_calls.ts +21 -16
  102. package/src/avm/serialization/bytecode_serialization.ts +2 -0
  103. package/src/avm/serialization/instruction_serialization.ts +1 -0
  104. package/src/client/client_execution_context.ts +55 -31
  105. package/src/client/db_oracle.ts +12 -10
  106. package/src/client/execution_result.ts +55 -24
  107. package/src/client/logs_cache.ts +65 -0
  108. package/src/client/private_execution.ts +4 -10
  109. package/src/client/simulator.ts +6 -4
  110. package/src/client/unconstrained_execution.ts +2 -2
  111. package/src/client/view_data_oracle.ts +10 -0
  112. package/src/mocks/fixtures.ts +2 -0
  113. package/src/public/abstract_phase_manager.ts +13 -5
  114. package/src/public/execution.ts +9 -0
  115. package/src/public/executor.ts +47 -10
  116. package/src/public/public_execution_context.ts +18 -4
  117. package/src/public/tail_phase_manager.ts +2 -34
  118. package/src/public/transitional_adaptors.ts +39 -178
@@ -15,10 +15,8 @@ import {
15
15
  FunctionData,
16
16
  FunctionSelector,
17
17
  type Header,
18
- NoteHashReadRequestMembershipWitness,
19
18
  PrivateContextInputs,
20
19
  PublicCallRequest,
21
- type SideEffect,
22
20
  type TxContext,
23
21
  } from '@aztec/circuits.js';
24
22
  import { Aes128 } from '@aztec/circuits.js/barretenberg';
@@ -32,7 +30,8 @@ import { type NoteData, toACVMWitness } from '../acvm/index.js';
32
30
  import { type PackedValuesCache } from '../common/packed_values_cache.js';
33
31
  import { type DBOracle } from './db_oracle.js';
34
32
  import { type ExecutionNoteCache } from './execution_note_cache.js';
35
- import { type ExecutionResult, type NoteAndSlot, type NullifiedNoteHashCounter } from './execution_result.js';
33
+ import { CountedLog, type ExecutionResult, type NoteAndSlot } from './execution_result.js';
34
+ import { type LogsCache } from './logs_cache.js';
36
35
  import { pickNotes } from './pick_notes.js';
37
36
  import { executePrivateFunction } from './private_execution.js';
38
37
  import { ViewDataOracle } from './view_data_oracle.js';
@@ -58,10 +57,10 @@ export class ClientExecutionContext extends ViewDataOracle {
58
57
  * because these notes are meant to be maintained on a per-call basis
59
58
  * They should act as references for the read requests output by an app circuit via public inputs.
60
59
  */
61
- private gotNotes: Map<bigint, bigint> = new Map();
62
- private nullifiedNoteHashCounters: NullifiedNoteHashCounter[] = [];
63
- private encryptedLogs: EncryptedL2Log[] = [];
64
- private unencryptedLogs: UnencryptedL2Log[] = [];
60
+ private noteHashLeafIndexMap: Map<bigint, bigint> = new Map();
61
+ private nullifiedNoteHashCounters: Map<number, number> = new Map();
62
+ private encryptedLogs: CountedLog<EncryptedL2Log>[] = [];
63
+ private unencryptedLogs: CountedLog<UnencryptedL2Log>[] = [];
65
64
  private nestedExecutions: ExecutionResult[] = [];
66
65
  private enqueuedPublicFunctionCalls: PublicCallRequest[] = [];
67
66
 
@@ -76,6 +75,7 @@ export class ClientExecutionContext extends ViewDataOracle {
76
75
  authWitnesses: AuthWitness[],
77
76
  private readonly packedValuesCache: PackedValuesCache,
78
77
  private readonly noteCache: ExecutionNoteCache,
78
+ private readonly logsCache: LogsCache,
79
79
  db: DBOracle,
80
80
  private node: AztecNode,
81
81
  protected sideEffectCounter: number = 0,
@@ -112,23 +112,11 @@ export class ClientExecutionContext extends ViewDataOracle {
112
112
  }
113
113
 
114
114
  /**
115
- * This function will populate readRequestPartialWitnesses which
116
- * here is just used to flag reads as "transient" for new notes created during this execution
117
- * or to flag non-transient reads with their leafIndex.
118
- * The KernelProver will use this to fully populate witnesses and provide hints to
119
- * the kernel regarding which commitments each transient read request corresponds to.
120
- * @param noteHashReadRequests - SideEffect containing Note hashed of the notes being read and counter.
121
- * @returns An array of partially filled in read request membership witnesses.
115
+ * The KernelProver will use this to fully populate witnesses and provide hints to the kernel circuit
116
+ * regarding which note hash each settled read request corresponds to.
122
117
  */
123
- public getNoteHashReadRequestPartialWitnesses(noteHashReadRequests: SideEffect[]) {
124
- return noteHashReadRequests
125
- .filter(r => !r.isEmpty())
126
- .map(r => {
127
- const index = this.gotNotes.get(r.value.toBigInt());
128
- return index !== undefined
129
- ? NoteHashReadRequestMembershipWitness.empty(index)
130
- : NoteHashReadRequestMembershipWitness.emptyTransient();
131
- });
118
+ public getNoteHashLeafIndexMap() {
119
+ return this.noteHashLeafIndexMap;
132
120
  }
133
121
 
134
122
  /**
@@ -147,14 +135,28 @@ export class ClientExecutionContext extends ViewDataOracle {
147
135
  * Return the encrypted logs emitted during this execution.
148
136
  */
149
137
  public getEncryptedLogs() {
150
- return new EncryptedFunctionL2Logs(this.encryptedLogs);
138
+ return this.encryptedLogs;
139
+ }
140
+
141
+ /**
142
+ * Return the encrypted logs emitted during this execution and nested executions.
143
+ */
144
+ public getAllEncryptedLogs() {
145
+ return new EncryptedFunctionL2Logs(this.logsCache.getEncryptedLogs());
151
146
  }
152
147
 
153
148
  /**
154
149
  * Return the encrypted logs emitted during this execution.
155
150
  */
156
151
  public getUnencryptedLogs() {
157
- return new UnencryptedFunctionL2Logs(this.unencryptedLogs);
152
+ return this.unencryptedLogs;
153
+ }
154
+
155
+ /**
156
+ * Return the unencrypted logs emitted during this execution and nested executions.
157
+ */
158
+ public getAllUnencryptedLogs() {
159
+ return new UnencryptedFunctionL2Logs(this.logsCache.getUnencryptedLogs());
158
160
  }
159
161
 
160
162
  /**
@@ -265,7 +267,7 @@ export class ClientExecutionContext extends ViewDataOracle {
265
267
  // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1386)
266
268
  // Should always be uniqueSiloedNoteHash when publicly created notes include nonces.
267
269
  const noteHashForReadRequest = n.nonce.isZero() ? siloedNoteHash : uniqueSiloedNoteHash;
268
- this.gotNotes.set(noteHashForReadRequest.value, n.index);
270
+ this.noteHashLeafIndexMap.set(noteHashForReadRequest.toBigInt(), n.index);
269
271
  }
270
272
  });
271
273
 
@@ -321,7 +323,7 @@ export class ClientExecutionContext extends ViewDataOracle {
321
323
  innerNoteHash,
322
324
  );
323
325
  if (nullifiedNoteHashCounter !== undefined) {
324
- this.nullifiedNoteHashCounters.push({ noteHashCounter: nullifiedNoteHashCounter, nullifierCounter: counter });
326
+ this.nullifiedNoteHashCounters.set(nullifiedNoteHashCounter, counter);
325
327
  }
326
328
  return Promise.resolve();
327
329
  }
@@ -340,24 +342,45 @@ export class ClientExecutionContext extends ViewDataOracle {
340
342
  noteTypeId: Fr,
341
343
  publicKey: Point,
342
344
  log: Fr[],
345
+ counter: number,
343
346
  ) {
344
347
  const note = new Note(log);
345
348
  const l1NotePayload = new L1NotePayload(note, contractAddress, storageSlot, noteTypeId);
346
349
  const taggedNote = new TaggedNote(l1NotePayload);
347
350
  const encryptedNote = taggedNote.toEncryptedBuffer(publicKey);
348
351
  const encryptedLog = new EncryptedL2Log(encryptedNote);
349
- this.encryptedLogs.push(encryptedLog);
350
- return Fr.fromBuffer(encryptedLog.hash());
352
+ this.encryptedLogs.push(new CountedLog(encryptedLog, counter));
353
+ this.logsCache.addEncryptedLog(encryptedLog);
354
+ return encryptedNote;
351
355
  }
352
356
 
353
357
  /**
354
358
  * Emit an unencrypted log.
355
359
  * @param log - The unencrypted log to be emitted.
356
360
  */
357
- public override emitUnencryptedLog(log: UnencryptedL2Log) {
358
- this.unencryptedLogs.push(log);
361
+ public override emitUnencryptedLog(log: UnencryptedL2Log, counter: number) {
362
+ this.unencryptedLogs.push(new CountedLog(log, counter));
363
+ this.logsCache.addUnencryptedLog(log);
359
364
  const text = log.toHumanReadable();
360
365
  this.log.verbose(`Emitted unencrypted log: "${text.length > 100 ? text.slice(0, 100) + '...' : text}"`);
366
+ }
367
+
368
+ /**
369
+ * Emit a contract class unencrypted log.
370
+ * This fn exists separately from emitUnencryptedLog because sha hashing the preimage
371
+ * is too large to compile (16,200 fields, 518,400 bytes) => the oracle hashes it.
372
+ * See private_context.nr
373
+ * @param log - The unencrypted log to be emitted.
374
+ */
375
+ public override emitContractClassUnencryptedLog(log: UnencryptedL2Log, counter: number) {
376
+ this.unencryptedLogs.push(new CountedLog(log, counter));
377
+ this.logsCache.addUnencryptedLog(log);
378
+ const text = log.toHumanReadable();
379
+ this.log.verbose(
380
+ `Emitted unencrypted log from ContractClassRegisterer: "${
381
+ text.length > 100 ? text.slice(0, 100) + '...' : text
382
+ }"`,
383
+ );
361
384
  return Fr.fromBuffer(log.hash());
362
385
  }
363
386
 
@@ -419,6 +442,7 @@ export class ClientExecutionContext extends ViewDataOracle {
419
442
  this.authWitnesses,
420
443
  this.packedValuesCache,
421
444
  this.noteCache,
445
+ this.logsCache,
422
446
  this.db,
423
447
  this.node,
424
448
  sideEffectCounter,
@@ -6,9 +6,9 @@ import {
6
6
  type PublicDataWitness,
7
7
  } from '@aztec/circuit-types';
8
8
  import { type CompleteAddress, type Header } from '@aztec/circuits.js';
9
- import { type FunctionArtifactWithDebugMetadata, type FunctionSelector } from '@aztec/foundation/abi';
9
+ import { type FunctionArtifact, type FunctionSelector } from '@aztec/foundation/abi';
10
10
  import { type AztecAddress } from '@aztec/foundation/aztec-address';
11
- import { type Fr } from '@aztec/foundation/fields';
11
+ import { type Fr, type Point } from '@aztec/foundation/fields';
12
12
  import { type ContractInstance } from '@aztec/types/contracts';
13
13
 
14
14
  import { type NoteData, type NullifierKeys } from '../acvm/index.js';
@@ -64,6 +64,14 @@ export interface DBOracle extends CommitmentsDB {
64
64
  */
65
65
  popCapsule(): Promise<Fr[]>;
66
66
 
67
+ /**
68
+ * Gets public keys for an address.
69
+ * @param The address to look up
70
+ * @returns The public keys for a specific address
71
+ * TODO(#5834): Replace with `getCompleteAddress`.
72
+ */
73
+ getPublicKeysForAddress(address: AztecAddress): Promise<Point[]>;
74
+
67
75
  /**
68
76
  * Retrieve nullifier keys associated with a specific account and app/contract address.
69
77
  *
@@ -94,10 +102,7 @@ export interface DBOracle extends CommitmentsDB {
94
102
  * @param selector - The corresponding function selector.
95
103
  * @returns A Promise that resolves to a FunctionArtifact object.
96
104
  */
97
- getFunctionArtifact(
98
- contractAddress: AztecAddress,
99
- selector: FunctionSelector,
100
- ): Promise<FunctionArtifactWithDebugMetadata>;
105
+ getFunctionArtifact(contractAddress: AztecAddress, selector: FunctionSelector): Promise<FunctionArtifact>;
101
106
 
102
107
  /**
103
108
  * Retrieves the artifact of a specified function within a given contract.
@@ -107,10 +112,7 @@ export interface DBOracle extends CommitmentsDB {
107
112
  * @param functionName - The name of the function.
108
113
  * @returns The corresponding function's artifact as an object.
109
114
  */
110
- getFunctionArtifactByName(
111
- contractAddress: AztecAddress,
112
- functionName: string,
113
- ): Promise<FunctionArtifactWithDebugMetadata | undefined>;
115
+ getFunctionArtifactByName(contractAddress: AztecAddress, functionName: string): Promise<FunctionArtifact | undefined>;
114
116
 
115
117
  /**
116
118
  * Gets the index of a nullifier in the nullifier tree.
@@ -1,9 +1,11 @@
1
- import { type EncryptedFunctionL2Logs, type Note, type UnencryptedFunctionL2Logs } from '@aztec/circuit-types';
2
1
  import {
3
- type NoteHashReadRequestMembershipWitness,
4
- type PrivateCallStackItem,
5
- type PublicCallRequest,
6
- } from '@aztec/circuits.js';
2
+ EncryptedFunctionL2Logs,
3
+ type EncryptedL2Log,
4
+ type Note,
5
+ UnencryptedFunctionL2Logs,
6
+ type UnencryptedL2Log,
7
+ } from '@aztec/circuit-types';
8
+ import { type IsEmpty, type PrivateCallStackItem, type PublicCallRequest, sortByCounter } from '@aztec/circuits.js';
7
9
  import { type Fr } from '@aztec/foundation/fields';
8
10
 
9
11
  import { type ACVMField } from '../acvm/index.js';
@@ -20,9 +22,12 @@ export interface NoteAndSlot {
20
22
  noteTypeId: Fr;
21
23
  }
22
24
 
23
- export interface NullifiedNoteHashCounter {
24
- noteHashCounter: number;
25
- nullifierCounter: number;
25
+ export class CountedLog<TLog extends UnencryptedL2Log | EncryptedL2Log> implements IsEmpty {
26
+ constructor(public log: TLog, public counter: number) {}
27
+
28
+ isEmpty(): boolean {
29
+ return !this.log.data.length && !this.counter;
30
+ }
26
31
  }
27
32
 
28
33
  /**
@@ -39,11 +44,12 @@ export interface ExecutionResult {
39
44
  // Needed for the verifier (kernel)
40
45
  /** The call stack item. */
41
46
  callStackItem: PrivateCallStackItem;
42
- /** The partially filled-in read request membership witnesses for commitments being read. */
43
- noteHashReadRequestPartialWitnesses: NoteHashReadRequestMembershipWitness[];
47
+ /** Mapping of note hash to its index in the note hash tree. Used for building hints for note hash read requests. */
48
+ noteHashLeafIndexMap: Map<bigint, bigint>;
44
49
  /** The notes created in the executed function. */
45
50
  newNotes: NoteAndSlot[];
46
- nullifiedNoteHashCounters: NullifiedNoteHashCounter[];
51
+ /** Mapping of note hash counter to the counter of its nullifier. */
52
+ nullifiedNoteHashCounters: Map<number, number>;
47
53
  /** The raw return values of the executed function. */
48
54
  returnValues: Fr[];
49
55
  /** The nested executions. */
@@ -54,19 +60,24 @@ export interface ExecutionResult {
54
60
  * Encrypted logs emitted during execution of this function call.
55
61
  * Note: These are preimages to `encryptedLogsHashes`.
56
62
  */
57
- encryptedLogs: EncryptedFunctionL2Logs;
63
+ encryptedLogs: CountedLog<EncryptedL2Log>[];
58
64
  /**
59
65
  * Unencrypted logs emitted during execution of this function call.
60
66
  * Note: These are preimages to `unencryptedLogsHashes`.
61
67
  */
62
- unencryptedLogs: UnencryptedFunctionL2Logs;
68
+ unencryptedLogs: CountedLog<UnencryptedL2Log>[];
63
69
  }
64
70
 
65
- export function collectNullifiedNoteHashCounters(execResult: ExecutionResult): NullifiedNoteHashCounter[] {
66
- return [
67
- execResult.nullifiedNoteHashCounters,
68
- ...execResult.nestedExecutions.flatMap(collectNullifiedNoteHashCounters),
69
- ].flat();
71
+ export function collectNoteHashLeafIndexMap(execResult: ExecutionResult, accum: Map<bigint, bigint> = new Map()) {
72
+ execResult.noteHashLeafIndexMap.forEach((value, key) => accum.set(key, value));
73
+ execResult.nestedExecutions.forEach(nested => collectNoteHashLeafIndexMap(nested, accum));
74
+ return accum;
75
+ }
76
+
77
+ export function collectNullifiedNoteHashCounters(execResult: ExecutionResult, accum: Map<number, number> = new Map()) {
78
+ execResult.nullifiedNoteHashCounters.forEach((value, key) => accum.set(key, value));
79
+ execResult.nestedExecutions.forEach(nested => collectNullifiedNoteHashCounters(nested, accum));
80
+ return accum;
70
81
  }
71
82
 
72
83
  /**
@@ -74,9 +85,19 @@ export function collectNullifiedNoteHashCounters(execResult: ExecutionResult): N
74
85
  * @param execResult - The topmost execution result.
75
86
  * @returns All encrypted logs.
76
87
  */
77
- export function collectEncryptedLogs(execResult: ExecutionResult): EncryptedFunctionL2Logs[] {
78
- // without the .reverse(), the logs will be in a queue like fashion which is wrong as the kernel processes it like a stack.
79
- return [execResult.encryptedLogs, ...[...execResult.nestedExecutions].reverse().flatMap(collectEncryptedLogs)];
88
+ function collectEncryptedLogs(execResult: ExecutionResult): CountedLog<EncryptedL2Log>[] {
89
+ return [execResult.encryptedLogs, ...[...execResult.nestedExecutions].flatMap(collectEncryptedLogs)].flat();
90
+ }
91
+
92
+ /**
93
+ * Collect all encrypted logs across all nested executions and sorts by counter.
94
+ * @param execResult - The topmost execution result.
95
+ * @returns All encrypted logs.
96
+ */
97
+ export function collectSortedEncryptedLogs(execResult: ExecutionResult): EncryptedFunctionL2Logs {
98
+ const allLogs = collectEncryptedLogs(execResult);
99
+ const sortedLogs = sortByCounter(allLogs);
100
+ return new EncryptedFunctionL2Logs(sortedLogs.map(l => l.log));
80
101
  }
81
102
 
82
103
  /**
@@ -84,9 +105,19 @@ export function collectEncryptedLogs(execResult: ExecutionResult): EncryptedFunc
84
105
  * @param execResult - The topmost execution result.
85
106
  * @returns All unencrypted logs.
86
107
  */
87
- export function collectUnencryptedLogs(execResult: ExecutionResult): UnencryptedFunctionL2Logs[] {
88
- // without the .reverse(), the logs will be in a queue like fashion which is wrong as the kernel processes it like a stack.
89
- return [execResult.unencryptedLogs, ...[...execResult.nestedExecutions].reverse().flatMap(collectUnencryptedLogs)];
108
+ function collectUnencryptedLogs(execResult: ExecutionResult): CountedLog<UnencryptedL2Log>[] {
109
+ return [execResult.unencryptedLogs, ...[...execResult.nestedExecutions].flatMap(collectUnencryptedLogs)].flat();
110
+ }
111
+
112
+ /**
113
+ * Collect all unencrypted logs across all nested executions and sorts by counter.
114
+ * @param execResult - The topmost execution result.
115
+ * @returns All unencrypted logs.
116
+ */
117
+ export function collectSortedUnencryptedLogs(execResult: ExecutionResult): UnencryptedFunctionL2Logs {
118
+ const allLogs = collectUnencryptedLogs(execResult);
119
+ const sortedLogs = sortByCounter(allLogs);
120
+ return new UnencryptedFunctionL2Logs(sortedLogs.map(l => l.log));
90
121
  }
91
122
 
92
123
  /**
@@ -0,0 +1,65 @@
1
+ import { type EncryptedL2Log, type UnencryptedL2Log } from '@aztec/circuit-types';
2
+
3
+ /**
4
+ * Log data that's accessible by all the function calls in an execution.
5
+ * This class exists to:
6
+ * 1. Keep track of logs emitted through nested calls in the correct order.
7
+ * 2. TODO(1641): Remove encrypted logs based on notes nullified in the same scope.
8
+ */
9
+ export class LogsCache {
10
+ /**
11
+ * Logs notes created in this transaction.
12
+ */
13
+ private encryptedLogs: EncryptedL2Log[] = [];
14
+ private unencryptedLogs: UnencryptedL2Log[] = [];
15
+
16
+ // TODO Separate encrypted logs linked to note hashes and arbitrary logs:
17
+
18
+ // Maps from note hash to encrypted log - useful for removing transient logs
19
+ // private encryptedLogsLinkedToNotes: Map<bigint, EncryptedL2Log> = new Map();
20
+
21
+ // /**
22
+ // * Remove the encrypted log for a nullified note.
23
+ // * This fn should only be called if the note's innerNoteHash != 0.
24
+ // * @param noteHashCounter - Side effect counter of the note.
25
+ // */
26
+ // public nullifyNote(noteHashCounter: Fr) {
27
+ // // Find and remove the matching new note if the emitted innerNoteHash is not empty.
28
+ // const log = this.encryptedLogsLinkedToNotes.get(noteHashCounter.toBigInt()) ?? false;
29
+ // // TODO: throw here? Will the log always be here?
30
+ // if (!log) {
31
+ // throw new Error('Attempt to remove a pending note log that does not exist.');
32
+ // }
33
+ // this.encryptedLogsLinkedToNotes.delete(noteHashCounter.toBigInt());
34
+ // }
35
+
36
+ /**
37
+ * Add a new encrypted log to cache.
38
+ * @param log - New log created during execution.
39
+ */
40
+ public addEncryptedLog(log: EncryptedL2Log) {
41
+ this.encryptedLogs.push(log);
42
+ }
43
+
44
+ /**
45
+ * Add a new unencrypted log to cache.
46
+ * @param log - New log created during execution.
47
+ */
48
+ public addUnencryptedLog(log: UnencryptedL2Log) {
49
+ this.unencryptedLogs.push(log);
50
+ }
51
+
52
+ /**
53
+ * Return the encrypted logs.
54
+ */
55
+ public getEncryptedLogs() {
56
+ return this.encryptedLogs;
57
+ }
58
+
59
+ /**
60
+ * Return the encrypted logs.
61
+ */
62
+ public getUnencryptedLogs() {
63
+ return this.unencryptedLogs;
64
+ }
65
+ }
@@ -1,7 +1,6 @@
1
1
  import { type FunctionData, PrivateCallStackItem, PrivateCircuitPublicInputs } from '@aztec/circuits.js';
2
- import { type FunctionArtifactWithDebugMetadata } from '@aztec/foundation/abi';
2
+ import { type FunctionArtifact } from '@aztec/foundation/abi';
3
3
  import { type AztecAddress } from '@aztec/foundation/aztec-address';
4
- import { Fr } from '@aztec/foundation/fields';
5
4
  import { createDebugLogger } from '@aztec/foundation/log';
6
5
 
7
6
  import { witnessMapToFields } from '../acvm/deserialize.js';
@@ -16,7 +15,7 @@ import { AcirSimulator } from './simulator.js';
16
15
  */
17
16
  export async function executePrivateFunction(
18
17
  context: ClientExecutionContext,
19
- artifact: FunctionArtifactWithDebugMetadata,
18
+ artifact: FunctionArtifact,
20
19
  contractAddress: AztecAddress,
21
20
  functionData: FunctionData,
22
21
  log = createDebugLogger('aztec:simulator:secret_execution'),
@@ -45,17 +44,12 @@ export async function executePrivateFunction(
45
44
 
46
45
  const encryptedLogs = context.getEncryptedLogs();
47
46
  const unencryptedLogs = context.getUnencryptedLogs();
48
- // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) --> set this in Noir
49
- publicInputs.encryptedLogPreimagesLength = new Fr(encryptedLogs.getSerializedLength());
50
- publicInputs.unencryptedLogPreimagesLength = new Fr(unencryptedLogs.getSerializedLength());
51
47
 
52
48
  const callStackItem = new PrivateCallStackItem(contractAddress, functionData, publicInputs);
53
49
 
54
50
  const rawReturnValues = await context.unpackReturns(publicInputs.returnsHash);
55
51
 
56
- const noteHashReadRequestPartialWitnesses = context.getNoteHashReadRequestPartialWitnesses(
57
- publicInputs.noteHashReadRequests,
58
- );
52
+ const noteHashLeafIndexMap = context.getNoteHashLeafIndexMap();
59
53
  const newNotes = context.getNewNotes();
60
54
  const nullifiedNoteHashCounters = context.getNullifiedNoteHashCounters();
61
55
  const nestedExecutions = context.getNestedExecutions();
@@ -68,7 +62,7 @@ export async function executePrivateFunction(
68
62
  partialWitness,
69
63
  callStackItem,
70
64
  returnValues: rawReturnValues,
71
- noteHashReadRequestPartialWitnesses,
65
+ noteHashLeafIndexMap,
72
66
  newNotes,
73
67
  nullifiedNoteHashCounters,
74
68
  vk: Buffer.from(artifact.verificationKey!, 'hex'),
@@ -2,7 +2,7 @@ import { type AztecNode, type FunctionCall, type Note, type TxExecutionRequest }
2
2
  import { CallContext, FunctionData } from '@aztec/circuits.js';
3
3
  import {
4
4
  type ArrayType,
5
- type FunctionArtifactWithDebugMetadata,
5
+ type FunctionArtifact,
6
6
  FunctionSelector,
7
7
  FunctionType,
8
8
  encodeArguments,
@@ -19,6 +19,7 @@ import { ClientExecutionContext } from './client_execution_context.js';
19
19
  import { type DBOracle } from './db_oracle.js';
20
20
  import { ExecutionNoteCache } from './execution_note_cache.js';
21
21
  import { type ExecutionResult } from './execution_result.js';
22
+ import { LogsCache } from './logs_cache.js';
22
23
  import { executePrivateFunction } from './private_execution.js';
23
24
  import { executeUnconstrainedFunction } from './unconstrained_execution.js';
24
25
  import { ViewDataOracle } from './view_data_oracle.js';
@@ -64,7 +65,7 @@ export class AcirSimulator {
64
65
  */
65
66
  public async run(
66
67
  request: TxExecutionRequest,
67
- entryPointArtifact: FunctionArtifactWithDebugMetadata,
68
+ entryPointArtifact: FunctionArtifact,
68
69
  contractAddress: AztecAddress,
69
70
  msgSender = AztecAddress.ZERO,
70
71
  ): Promise<ExecutionResult> {
@@ -100,6 +101,7 @@ export class AcirSimulator {
100
101
  request.authWitnesses,
101
102
  PackedValuesCache.create(request.argsOfCalls),
102
103
  new ExecutionNoteCache(),
104
+ new LogsCache(),
103
105
  this.db,
104
106
  this.node,
105
107
  startSideEffectCounter,
@@ -127,7 +129,7 @@ export class AcirSimulator {
127
129
  */
128
130
  public async runUnconstrained(
129
131
  request: FunctionCall,
130
- entryPointArtifact: FunctionArtifactWithDebugMetadata,
132
+ entryPointArtifact: FunctionArtifact,
131
133
  contractAddress: AztecAddress,
132
134
  ) {
133
135
  if (entryPointArtifact.functionType !== FunctionType.UNCONSTRAINED) {
@@ -165,7 +167,7 @@ export class AcirSimulator {
165
167
  noteTypeId: Fr,
166
168
  note: Note,
167
169
  ) {
168
- const artifact: FunctionArtifactWithDebugMetadata | undefined = await this.db.getFunctionArtifactByName(
170
+ const artifact: FunctionArtifact | undefined = await this.db.getFunctionArtifactByName(
169
171
  contractAddress,
170
172
  'compute_note_hash_and_nullifier',
171
173
  );
@@ -1,5 +1,5 @@
1
1
  import { type FunctionData } from '@aztec/circuits.js';
2
- import { type DecodedReturn, type FunctionArtifactWithDebugMetadata, decodeReturnValues } from '@aztec/foundation/abi';
2
+ import { type DecodedReturn, type FunctionArtifact, decodeReturnValues } from '@aztec/foundation/abi';
3
3
  import { type AztecAddress } from '@aztec/foundation/aztec-address';
4
4
  import { type Fr } from '@aztec/foundation/fields';
5
5
  import { createDebugLogger } from '@aztec/foundation/log';
@@ -16,7 +16,7 @@ import { type ViewDataOracle } from './view_data_oracle.js';
16
16
  */
17
17
  export async function executeUnconstrainedFunction(
18
18
  oracle: ViewDataOracle,
19
- artifact: FunctionArtifactWithDebugMetadata,
19
+ artifact: FunctionArtifact,
20
20
  contractAddress: AztecAddress,
21
21
  functionData: FunctionData,
22
22
  args: Fr[],
@@ -166,6 +166,16 @@ export class ViewDataOracle extends TypedOracle {
166
166
  return this.db.popCapsule();
167
167
  }
168
168
 
169
+ /**
170
+ * Gets public keys for an address.
171
+ * @param The address to look up
172
+ * @returns The public keys for a specific address
173
+ * TODO(#5834): Replace with `getCompleteAddress`.
174
+ */
175
+ public override getPublicKeysForAddress(address: AztecAddress) {
176
+ return this.db.getPublicKeysForAddress(address);
177
+ }
178
+
169
179
  /**
170
180
  * Gets some notes for a contract address and storage slot.
171
181
  * Returns a flattened array containing filtered notes.
@@ -116,6 +116,8 @@ export class PublicExecutionResultBuilder {
116
116
  contractStorageReads: [],
117
117
  unencryptedLogsHashes: [],
118
118
  unencryptedLogs: UnencryptedFunctionL2Logs.empty(),
119
+ unencryptedLogPreimagesLength: new Fr(4n), // empty logs have len 4
120
+ allUnencryptedLogs: UnencryptedFunctionL2Logs.empty(),
119
121
  startSideEffectCounter: Fr.ZERO,
120
122
  endSideEffectCounter: Fr.ZERO,
121
123
  reverted: this._reverted,
@@ -246,8 +246,10 @@ export abstract class AbstractPhaseManager {
246
246
  while (executionStack.length) {
247
247
  const current = executionStack.pop()!;
248
248
  const isExecutionRequest = !isPublicExecutionResult(current);
249
+ // TODO(6052): Extract correct new counter from nested calls
249
250
  const sideEffectCounter = lastSideEffectCounter(tx) + 1;
250
- const availableGas = this.getAvailableGas(tx, previousPublicKernelOutput);
251
+ const availableGas = this.getAvailableGas(tx, kernelOutput);
252
+ const pendingNullifiers = this.getSiloedPendingNullifiers(kernelOutput);
251
253
 
252
254
  const result = isExecutionRequest
253
255
  ? await this.publicExecutor.simulate(
@@ -255,6 +257,7 @@ export abstract class AbstractPhaseManager {
255
257
  this.globalVariables,
256
258
  availableGas,
257
259
  tx.data.constants.txContext,
260
+ pendingNullifiers,
258
261
  transactionFee,
259
262
  sideEffectCounter,
260
263
  )
@@ -270,7 +273,9 @@ export abstract class AbstractPhaseManager {
270
273
  throw result.revertReason;
271
274
  }
272
275
 
273
- newUnencryptedFunctionLogs.push(result.unencryptedLogs);
276
+ if (isExecutionRequest) {
277
+ newUnencryptedFunctionLogs.push(result.allUnencryptedLogs);
278
+ }
274
279
 
275
280
  this.log.debug(
276
281
  `Running public kernel circuit for ${result.execution.contractAddress.toString()}:${functionSelector}`,
@@ -320,6 +325,11 @@ export abstract class AbstractPhaseManager {
320
325
  return [publicKernelInputs, kernelOutput, kernelProof, newUnencryptedFunctionLogs, undefined, returns];
321
326
  }
322
327
 
328
+ /** Returns all pending private and public nullifiers. */
329
+ private getSiloedPendingNullifiers(ko: PublicKernelCircuitPublicInputs) {
330
+ return [...ko.end.newNullifiers, ...ko.endNonRevertibleData.newNullifiers].filter(n => !n.isEmpty());
331
+ }
332
+
323
333
  protected getAvailableGas(tx: Tx, previousPublicKernelOutput: PublicKernelCircuitPublicInputs) {
324
334
  return tx.data.constants.txContext.gasSettings
325
335
  .getLimits() // No need to subtract teardown limits since they are already included in end.gasUsed
@@ -382,8 +392,6 @@ export abstract class AbstractPhaseManager {
382
392
  MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL,
383
393
  );
384
394
 
385
- const unencryptedLogPreimagesLength = new Fr(result.unencryptedLogs.getSerializedLength());
386
-
387
395
  const publicCircuitPublicInputs = PublicCircuitPublicInputs.from({
388
396
  callContext: result.execution.callContext,
389
397
  proverAddress: AztecAddress.ZERO,
@@ -420,7 +428,7 @@ export abstract class AbstractPhaseManager {
420
428
  SideEffect.empty(),
421
429
  MAX_UNENCRYPTED_LOGS_PER_CALL,
422
430
  ),
423
- unencryptedLogPreimagesLength,
431
+ unencryptedLogPreimagesLength: result.unencryptedLogPreimagesLength,
424
432
  historicalHeader: this.historicalHeader,
425
433
  globalVariables: this.globalVariables,
426
434
  startGasLeft: Gas.from(result.startGasLeft),
@@ -54,6 +54,15 @@ export interface PublicExecutionResult {
54
54
  * Note: These are preimages to `unencryptedLogsHashes`.
55
55
  */
56
56
  unencryptedLogs: UnencryptedFunctionL2Logs;
57
+ /**
58
+ * Length of the unencrypted log preimages emitted in this function call.
59
+ */
60
+ unencryptedLogPreimagesLength: Fr;
61
+ /**
62
+ * Unencrypted logs emitted during this call AND any nested calls.
63
+ * Useful for maintaining correct ordering in ts.
64
+ */
65
+ allUnencryptedLogs: UnencryptedFunctionL2Logs;
57
66
  /**
58
67
  * Whether the execution reverted.
59
68
  */