@aztec/simulator 0.37.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 (114) 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 +5 -4
  5. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  6. package/dest/acvm/oracle/oracle.js +19 -8
  7. package/dest/acvm/oracle/typed_oracle.d.ts +3 -2
  8. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  9. package/dest/acvm/oracle/typed_oracle.js +6 -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 +3 -3
  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/mocks/fixtures.d.ts.map +1 -1
  65. package/dest/mocks/fixtures.js +3 -1
  66. package/dest/public/abstract_phase_manager.d.ts +2 -0
  67. package/dest/public/abstract_phase_manager.d.ts.map +1 -1
  68. package/dest/public/abstract_phase_manager.js +13 -6
  69. package/dest/public/execution.d.ts +9 -0
  70. package/dest/public/execution.d.ts.map +1 -1
  71. package/dest/public/execution.js +1 -1
  72. package/dest/public/executor.d.ts +2 -2
  73. package/dest/public/executor.d.ts.map +1 -1
  74. package/dest/public/executor.js +34 -14
  75. package/dest/public/public_execution_context.d.ts +10 -4
  76. package/dest/public/public_execution_context.d.ts.map +1 -1
  77. package/dest/public/public_execution_context.js +19 -6
  78. package/dest/public/tail_phase_manager.d.ts +0 -1
  79. package/dest/public/tail_phase_manager.d.ts.map +1 -1
  80. package/dest/public/tail_phase_manager.js +3 -26
  81. package/dest/public/transitional_adaptors.d.ts +4 -17
  82. package/dest/public/transitional_adaptors.d.ts.map +1 -1
  83. package/dest/public/transitional_adaptors.js +27 -119
  84. package/package.json +8 -8
  85. package/src/acvm/acvm.ts +2 -2
  86. package/src/acvm/oracle/oracle.ts +39 -9
  87. package/src/acvm/oracle/typed_oracle.ts +7 -2
  88. package/src/avm/avm_gas.ts +1 -0
  89. package/src/avm/avm_memory_types.ts +1 -1
  90. package/src/avm/avm_simulator.ts +2 -0
  91. package/src/avm/journal/journal.ts +133 -9
  92. package/src/avm/journal/nullifiers.ts +19 -8
  93. package/src/avm/journal/public_storage.ts +23 -2
  94. package/src/avm/journal/trace.ts +3 -4
  95. package/src/avm/journal/trace_types.ts +1 -0
  96. package/src/avm/opcodes/bitwise.ts +18 -7
  97. package/src/avm/opcodes/environment_getters.ts +9 -0
  98. package/src/avm/opcodes/external_calls.ts +21 -16
  99. package/src/avm/serialization/bytecode_serialization.ts +2 -0
  100. package/src/avm/serialization/instruction_serialization.ts +1 -0
  101. package/src/client/client_execution_context.ts +55 -31
  102. package/src/client/db_oracle.ts +3 -9
  103. package/src/client/execution_result.ts +55 -24
  104. package/src/client/logs_cache.ts +65 -0
  105. package/src/client/private_execution.ts +4 -10
  106. package/src/client/simulator.ts +6 -4
  107. package/src/client/unconstrained_execution.ts +2 -2
  108. package/src/mocks/fixtures.ts +2 -0
  109. package/src/public/abstract_phase_manager.ts +13 -5
  110. package/src/public/execution.ts +9 -0
  111. package/src/public/executor.ts +47 -10
  112. package/src/public/public_execution_context.ts +18 -4
  113. package/src/public/tail_phase_manager.ts +2 -34
  114. package/src/public/transitional_adaptors.ts +39 -178
@@ -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[],
@@ -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
  */
@@ -4,6 +4,7 @@ import {
4
4
  Gas,
5
5
  type GlobalVariables,
6
6
  type Header,
7
+ type Nullifier,
7
8
  PublicCircuitPublicInputs,
8
9
  type TxContext,
9
10
  } from '@aztec/circuits.js';
@@ -26,7 +27,7 @@ import { PackedValuesCache } from '../common/packed_values_cache.js';
26
27
  import { type CommitmentsDB, type PublicContractsDB, type PublicStateDB } from './db.js';
27
28
  import { type PublicExecution, type PublicExecutionResult, checkValidStaticCall } from './execution.js';
28
29
  import { PublicExecutionContext } from './public_execution_context.js';
29
- import { convertAvmResults, createAvmExecutionEnvironment, isAvmBytecode } from './transitional_adaptors.js';
30
+ import { convertAvmResultsToPxResult, createAvmExecutionEnvironment, isAvmBytecode } from './transitional_adaptors.js';
30
31
 
31
32
  /**
32
33
  * Execute a public function and return the execution result.
@@ -46,15 +47,23 @@ export async function executePublicFunction(
46
47
  }
47
48
 
48
49
  if (isAvmBytecode(bytecode)) {
49
- return await executePublicFunctionAvm(context);
50
+ return await executeTopLevelPublicFunctionAvm(context, bytecode);
50
51
  } else {
51
52
  return await executePublicFunctionAcvm(context, bytecode, nested);
52
53
  }
53
54
  }
54
55
 
55
- async function executePublicFunctionAvm(executionContext: PublicExecutionContext): Promise<PublicExecutionResult> {
56
+ /**
57
+ * Execute a top-level public function call (the first call in an enqueued-call/execution-request) in the AVM.
58
+ * Translate the results back to the PublicExecutionResult format.
59
+ */
60
+ async function executeTopLevelPublicFunctionAvm(
61
+ executionContext: PublicExecutionContext,
62
+ bytecode: Buffer,
63
+ ): Promise<PublicExecutionResult> {
56
64
  const address = executionContext.execution.contractAddress;
57
65
  const selector = executionContext.execution.functionData.selector;
66
+ const startGas = executionContext.availableGas;
58
67
  const log = createDebugLogger('aztec:simulator:public_execution');
59
68
  log.verbose(`[AVM] Executing public external function ${address.toString()}:${selector}.`);
60
69
 
@@ -65,7 +74,15 @@ async function executePublicFunctionAvm(executionContext: PublicExecutionContext
65
74
  executionContext.contractsDb,
66
75
  executionContext.commitmentsDb,
67
76
  );
77
+
78
+ // TODO(6207): add sideEffectCounter to persistableState construction
79
+ // or modify the PersistableStateManager to manage rollbacks across enqueued-calls and transactions.
68
80
  const worldStateJournal = new AvmPersistableStateManager(hostStorage);
81
+ const startSideEffectCounter = executionContext.execution.callContext.sideEffectCounter;
82
+ for (const nullifier of executionContext.pendingNullifiers) {
83
+ worldStateJournal.nullifiers.cache.appendSiloed(nullifier.value);
84
+ }
85
+ worldStateJournal.trace.accessCounter = startSideEffectCounter;
69
86
 
70
87
  const executionEnv = createAvmExecutionEnvironment(
71
88
  executionContext.execution,
@@ -75,18 +92,30 @@ async function executePublicFunctionAvm(executionContext: PublicExecutionContext
75
92
  executionContext.transactionFee,
76
93
  );
77
94
 
78
- const machineState = new AvmMachineState(executionContext.availableGas);
79
- const context = new AvmContext(worldStateJournal, executionEnv, machineState);
80
- const simulator = new AvmSimulator(context);
95
+ const machineState = new AvmMachineState(startGas);
96
+ const avmContext = new AvmContext(worldStateJournal, executionEnv, machineState);
97
+ const simulator = new AvmSimulator(avmContext);
81
98
 
82
- const result = await simulator.execute();
83
- const newWorldState = context.persistableState.flush();
99
+ const avmResult = await simulator.executeBytecode(bytecode);
100
+
101
+ // Commit the journals state to the DBs since this is a top-level execution.
102
+ // Observe that this will write all the state changes to the DBs, not only the latest for each slot.
103
+ // However, the underlying DB keep a cache and will only write the latest state to disk.
104
+ await avmContext.persistableState.publicStorage.commitToDB();
84
105
 
85
106
  log.verbose(
86
- `[AVM] ${address.toString()}:${selector} returned, reverted: ${result.reverted}, reason: ${result.revertReason}.`,
107
+ `[AVM] ${address.toString()}:${selector} returned, reverted: ${avmResult.reverted}, reason: ${
108
+ avmResult.revertReason
109
+ }.`,
87
110
  );
88
111
 
89
- return await convertAvmResults(executionContext, newWorldState, result, machineState);
112
+ return convertAvmResultsToPxResult(
113
+ avmResult,
114
+ startSideEffectCounter,
115
+ executionContext.execution,
116
+ startGas,
117
+ avmContext,
118
+ );
90
119
  }
91
120
 
92
121
  async function executePublicFunctionAcvm(
@@ -159,6 +188,8 @@ async function executePublicFunctionAcvm(
159
188
  nestedExecutions: [],
160
189
  unencryptedLogsHashes: [],
161
190
  unencryptedLogs: UnencryptedFunctionL2Logs.empty(),
191
+ unencryptedLogPreimagesLength: new Fr(4n), // empty logs have len 4
192
+ allUnencryptedLogs: UnencryptedFunctionL2Logs.empty(),
162
193
  reverted,
163
194
  revertReason,
164
195
  startGasLeft: context.availableGas,
@@ -182,6 +213,7 @@ async function executePublicFunctionAcvm(
182
213
  startSideEffectCounter,
183
214
  endSideEffectCounter,
184
215
  unencryptedLogsHashes: unencryptedLogsHashesPadded,
216
+ unencryptedLogPreimagesLength,
185
217
  } = PublicCircuitPublicInputs.fromFields(returnWitness);
186
218
  const returnValues = await context.unpackReturns(returnsHash);
187
219
 
@@ -207,6 +239,7 @@ async function executePublicFunctionAcvm(
207
239
 
208
240
  const nestedExecutions = context.getNestedExecutions();
209
241
  const unencryptedLogs = context.getUnencryptedLogs();
242
+ const allUnencryptedLogs = context.getAllUnencryptedLogs();
210
243
 
211
244
  // TODO(palla/gas): We should be loading these values from the returned PublicCircuitPublicInputs
212
245
  const startGasLeft = context.availableGas;
@@ -227,6 +260,8 @@ async function executePublicFunctionAcvm(
227
260
  nestedExecutions,
228
261
  unencryptedLogsHashes,
229
262
  unencryptedLogs,
263
+ unencryptedLogPreimagesLength,
264
+ allUnencryptedLogs,
230
265
  reverted: false,
231
266
  revertReason: undefined,
232
267
  startGasLeft,
@@ -258,6 +293,7 @@ export class PublicExecutor {
258
293
  globalVariables: GlobalVariables,
259
294
  availableGas: Gas,
260
295
  txContext: TxContext,
296
+ pendingNullifiers: Nullifier[],
261
297
  transactionFee: Fr = Fr.ZERO,
262
298
  sideEffectCounter: number = 0,
263
299
  ): Promise<PublicExecutionResult> {
@@ -277,6 +313,7 @@ export class PublicExecutor {
277
313
  availableGas,
278
314
  transactionFee,
279
315
  txContext.gasSettings,
316
+ pendingNullifiers,
280
317
  );
281
318
 
282
319
  const executionResult = await executePublicFunction(context, /*nested=*/ false);
@@ -7,6 +7,7 @@ import {
7
7
  type GasSettings,
8
8
  type GlobalVariables,
9
9
  type Header,
10
+ type Nullifier,
10
11
  PublicContextInputs,
11
12
  } from '@aztec/circuits.js';
12
13
  import { type AztecAddress } from '@aztec/foundation/aztec-address';
@@ -37,13 +38,18 @@ export class PublicExecutionContext extends TypedOracle {
37
38
  public readonly header: Header,
38
39
  public readonly globalVariables: GlobalVariables,
39
40
  private readonly packedValuesCache: PackedValuesCache,
40
- private readonly sideEffectCounter: SideEffectCounter,
41
+ // TRANSITIONAL: once AVM-ACVM interoperability is removed (fully functional AVM), sideEffectCounter can be made private
42
+ public readonly sideEffectCounter: SideEffectCounter,
41
43
  public readonly stateDb: PublicStateDB,
42
44
  public readonly contractsDb: PublicContractsDB,
43
45
  public readonly commitmentsDb: CommitmentsDB,
44
46
  public readonly availableGas: Gas,
45
47
  public readonly transactionFee: Fr,
46
48
  public readonly gasSettings: GasSettings,
49
+ public readonly pendingNullifiers: Nullifier[],
50
+ // Unencrypted logs emitted during this call AND any nested calls
51
+ // Useful for maintaining correct ordering in ts
52
+ private allUnencryptedLogs: UnencryptedL2Log[] = [],
47
53
  private log = createDebugLogger('aztec:simulator:public_execution_context'),
48
54
  ) {
49
55
  super();
@@ -87,6 +93,13 @@ export class PublicExecutionContext extends TypedOracle {
87
93
  return new UnencryptedFunctionL2Logs(this.unencryptedLogs);
88
94
  }
89
95
 
96
+ /**
97
+ * Return the encrypted logs emitted during this execution, including nested calls.
98
+ */
99
+ public getAllUnencryptedLogs() {
100
+ return new UnencryptedFunctionL2Logs(this.allUnencryptedLogs);
101
+ }
102
+
90
103
  /**
91
104
  * Return the data read and updated during this execution.
92
105
  */
@@ -135,11 +148,10 @@ export class PublicExecutionContext extends TypedOracle {
135
148
  * Emit an unencrypted log.
136
149
  * @param log - The unencrypted log to be emitted.
137
150
  */
138
- public override emitUnencryptedLog(log: UnencryptedL2Log) {
139
- // TODO(https://github.com/AztecProtocol/aztec-packages/issues/885)
151
+ public override emitUnencryptedLog(log: UnencryptedL2Log, _counter: number) {
140
152
  this.unencryptedLogs.push(log);
153
+ this.allUnencryptedLogs.push(log);
141
154
  this.log.verbose(`Emitted unencrypted log: "${log.toHumanReadable()}"`);
142
- return Fr.fromBuffer(log.hash());
143
155
  }
144
156
 
145
157
  /**
@@ -229,6 +241,8 @@ export class PublicExecutionContext extends TypedOracle {
229
241
  this.availableGas,
230
242
  this.transactionFee,
231
243
  this.gasSettings,
244
+ /*pendingNullifiers=*/ [],
245
+ this.allUnencryptedLogs,
232
246
  this.log,
233
247
  );
234
248
 
@@ -1,10 +1,4 @@
1
- import {
2
- type PublicKernelRequest,
3
- PublicKernelType,
4
- type Tx,
5
- UnencryptedFunctionL2Logs,
6
- type UnencryptedL2Log,
7
- } from '@aztec/circuit-types';
1
+ import { type PublicKernelRequest, PublicKernelType, type Tx } from '@aztec/circuit-types';
8
2
  import {
9
3
  Fr,
10
4
  type GlobalVariables,
@@ -57,8 +51,6 @@ export class TailPhaseManager extends AbstractPhaseManager {
57
51
  throw err;
58
52
  },
59
53
  );
60
- // Temporary hack. Should sort them in the tail circuit.
61
- this.patchLogsOrdering(tx, previousPublicKernelOutput);
62
54
  // commit the state updates from this transaction
63
55
  await this.publicStateDB.commit();
64
56
 
@@ -163,33 +155,9 @@ export class TailPhaseManager extends AbstractPhaseManager {
163
155
  }
164
156
 
165
157
  private sortLogsHashes<N extends number>(unencryptedLogsHashes: Tuple<SideEffect, N>): Tuple<SideEffect, N> {
158
+ // TODO(6052): logs here may have duplicate counters from nested calls
166
159
  return sortByCounter(
167
160
  unencryptedLogsHashes.map(n => ({ ...n, counter: n.counter.toNumber(), isEmpty: () => n.isEmpty() })),
168
161
  ).map(h => new SideEffect(h.value, new Fr(h.counter))) as Tuple<SideEffect, N>;
169
162
  }
170
-
171
- // As above, this is a hack for unencrypted logs ordering, now they are sorted. Since the public kernel
172
- // cannot keep track of side effects that happen after or before a nested call, we override the gathered logs.
173
- // As a sanity check, we at least verify that the elements are the same, so we are only tweaking their ordering.
174
- // See same fn in pxe_service.ts
175
- // Added as part of resolving #5017
176
- private patchLogsOrdering(tx: Tx, publicInputs: PublicKernelCircuitPublicInputs) {
177
- const unencLogs = tx.unencryptedLogs.unrollLogs();
178
- const sortedUnencLogs = publicInputs.end.unencryptedLogsHashes;
179
-
180
- const finalUnencLogs: UnencryptedL2Log[] = [];
181
- sortedUnencLogs.forEach((sideEffect: SideEffect) => {
182
- if (!sideEffect.isEmpty()) {
183
- const isLog = (log: UnencryptedL2Log) => Fr.fromBuffer(log.hash()).equals(sideEffect.value);
184
- const thisLogIndex = unencLogs.findIndex(isLog);
185
- finalUnencLogs.push(unencLogs[thisLogIndex]);
186
- }
187
- });
188
- const unencryptedLogs = new UnencryptedFunctionL2Logs(finalUnencLogs);
189
-
190
- tx.unencryptedLogs.functionLogs[0] = unencryptedLogs;
191
- for (let i = 1; i < tx.unencryptedLogs.functionLogs.length; i++) {
192
- tx.unencryptedLogs.functionLogs[i] = UnencryptedFunctionL2Logs.empty();
193
- }
194
- }
195
163
  }