@aztec/simulator 0.43.0 → 0.44.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 (110) hide show
  1. package/dest/acvm/oracle/oracle.d.ts +2 -0
  2. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  3. package/dest/acvm/oracle/oracle.js +10 -4
  4. package/dest/acvm/oracle/typed_oracle.d.ts +5 -3
  5. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  6. package/dest/acvm/oracle/typed_oracle.js +7 -1
  7. package/dest/avm/avm_execution_environment.d.ts +2 -0
  8. package/dest/avm/avm_execution_environment.d.ts.map +1 -1
  9. package/dest/avm/avm_execution_environment.js +9 -4
  10. package/dest/avm/avm_simulator.d.ts.map +1 -1
  11. package/dest/avm/avm_simulator.js +2 -3
  12. package/dest/avm/fixtures/index.d.ts +10 -6
  13. package/dest/avm/fixtures/index.d.ts.map +1 -1
  14. package/dest/avm/fixtures/index.js +8 -15
  15. package/dest/avm/journal/journal.d.ts +56 -65
  16. package/dest/avm/journal/journal.d.ts.map +1 -1
  17. package/dest/avm/journal/journal.js +76 -115
  18. package/dest/avm/journal/nullifiers.d.ts +21 -8
  19. package/dest/avm/journal/nullifiers.d.ts.map +1 -1
  20. package/dest/avm/journal/nullifiers.js +26 -8
  21. package/dest/avm/journal/public_storage.d.ts +4 -0
  22. package/dest/avm/journal/public_storage.d.ts.map +1 -1
  23. package/dest/avm/journal/public_storage.js +10 -1
  24. package/dest/avm/opcodes/accrued_substate.d.ts.map +1 -1
  25. package/dest/avm/opcodes/accrued_substate.js +4 -4
  26. package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
  27. package/dest/avm/opcodes/external_calls.js +12 -27
  28. package/dest/avm/test_utils.d.ts +14 -0
  29. package/dest/avm/test_utils.d.ts.map +1 -0
  30. package/dest/avm/test_utils.js +36 -0
  31. package/dest/client/client_execution_context.d.ts +3 -3
  32. package/dest/client/client_execution_context.d.ts.map +1 -1
  33. package/dest/client/client_execution_context.js +3 -3
  34. package/dest/client/execution_note_cache.d.ts.map +1 -1
  35. package/dest/client/execution_note_cache.js +1 -1
  36. package/dest/client/execution_result.d.ts +2 -1
  37. package/dest/client/execution_result.d.ts.map +1 -1
  38. package/dest/client/execution_result.js +1 -1
  39. package/dest/client/index.d.ts +2 -0
  40. package/dest/client/index.d.ts.map +1 -1
  41. package/dest/client/index.js +3 -1
  42. package/dest/client/simulator.d.ts +3 -3
  43. package/dest/client/simulator.d.ts.map +1 -1
  44. package/dest/client/simulator.js +1 -1
  45. package/dest/client/view_data_oracle.d.ts +2 -0
  46. package/dest/client/view_data_oracle.d.ts.map +1 -1
  47. package/dest/client/view_data_oracle.js +7 -1
  48. package/dest/mocks/fixtures.d.ts.map +1 -1
  49. package/dest/mocks/fixtures.js +3 -2
  50. package/dest/public/abstract_phase_manager.d.ts +1 -0
  51. package/dest/public/abstract_phase_manager.d.ts.map +1 -1
  52. package/dest/public/abstract_phase_manager.js +11 -8
  53. package/dest/public/app_logic_phase_manager.d.ts.map +1 -1
  54. package/dest/public/app_logic_phase_manager.js +2 -1
  55. package/dest/public/execution.d.ts +27 -25
  56. package/dest/public/execution.d.ts.map +1 -1
  57. package/dest/public/execution.js +1 -1
  58. package/dest/public/executor.d.ts +9 -4
  59. package/dest/public/executor.d.ts.map +1 -1
  60. package/dest/public/executor.js +29 -25
  61. package/dest/public/public_processor.d.ts +5 -2
  62. package/dest/public/public_processor.d.ts.map +1 -1
  63. package/dest/public/public_processor.js +142 -123
  64. package/dest/public/side_effect_trace.d.ts +86 -0
  65. package/dest/public/side_effect_trace.d.ts.map +1 -0
  66. package/dest/public/side_effect_trace.js +222 -0
  67. package/dest/public/side_effect_trace_interface.d.ts +36 -0
  68. package/dest/public/side_effect_trace_interface.d.ts.map +1 -0
  69. package/dest/public/side_effect_trace_interface.js +2 -0
  70. package/dest/public/teardown_phase_manager.d.ts.map +1 -1
  71. package/dest/public/teardown_phase_manager.js +2 -1
  72. package/dest/public/transitional_adaptors.d.ts +2 -6
  73. package/dest/public/transitional_adaptors.d.ts.map +1 -1
  74. package/dest/public/transitional_adaptors.js +1 -49
  75. package/package.json +18 -9
  76. package/src/acvm/oracle/oracle.ts +11 -3
  77. package/src/acvm/oracle/typed_oracle.ts +17 -3
  78. package/src/avm/avm_execution_environment.ts +10 -3
  79. package/src/avm/avm_simulator.ts +2 -3
  80. package/src/avm/fixtures/index.ts +18 -17
  81. package/src/avm/journal/journal.ts +114 -223
  82. package/src/avm/journal/nullifiers.ts +30 -13
  83. package/src/avm/journal/public_storage.ts +10 -0
  84. package/src/avm/opcodes/accrued_substate.ts +7 -3
  85. package/src/avm/opcodes/external_calls.ts +12 -34
  86. package/src/avm/test_utils.ts +53 -0
  87. package/src/client/client_execution_context.ts +10 -4
  88. package/src/client/execution_note_cache.ts +0 -1
  89. package/src/client/execution_result.ts +2 -1
  90. package/src/client/index.ts +2 -0
  91. package/src/client/simulator.ts +8 -2
  92. package/src/client/view_data_oracle.ts +8 -0
  93. package/src/mocks/fixtures.ts +2 -1
  94. package/src/public/abstract_phase_manager.ts +22 -11
  95. package/src/public/app_logic_phase_manager.ts +1 -0
  96. package/src/public/execution.ts +35 -25
  97. package/src/public/executor.ts +44 -37
  98. package/src/public/public_processor.ts +11 -2
  99. package/src/public/side_effect_trace.ts +323 -0
  100. package/src/public/side_effect_trace_interface.ts +41 -0
  101. package/src/public/teardown_phase_manager.ts +1 -0
  102. package/src/public/transitional_adaptors.ts +2 -100
  103. package/dest/avm/journal/trace.d.ts +0 -33
  104. package/dest/avm/journal/trace.d.ts.map +0 -1
  105. package/dest/avm/journal/trace.js +0 -152
  106. package/dest/avm/journal/trace_types.d.ts +0 -55
  107. package/dest/avm/journal/trace_types.d.ts.map +0 -1
  108. package/dest/avm/journal/trace_types.js +0 -2
  109. package/src/avm/journal/trace.ts +0 -181
  110. package/src/avm/journal/trace_types.ts +0 -91
@@ -4,20 +4,21 @@ import { AztecAddress } from '@aztec/foundation/aztec-address';
4
4
  import { EthAddress } from '@aztec/foundation/eth-address';
5
5
  import { Fr } from '@aztec/foundation/fields';
6
6
  import { AvmTestContractArtifact } from '@aztec/noir-contracts.js';
7
- import { SerializableContractInstance } from '@aztec/types/contracts';
8
7
 
9
8
  import { strict as assert } from 'assert';
10
9
  import { mock } from 'jest-mock-extended';
11
10
  import merge from 'lodash.merge';
12
11
 
13
12
  import { type CommitmentsDB, type PublicContractsDB, type PublicStateDB } from '../../index.js';
13
+ import { type PublicSideEffectTraceInterface } from '../../public/side_effect_trace_interface.js';
14
14
  import { AvmContext } from '../avm_context.js';
15
15
  import { AvmContextInputs, AvmExecutionEnvironment } from '../avm_execution_environment.js';
16
16
  import { AvmMachineState } from '../avm_machine_state.js';
17
17
  import { Field, Uint8 } from '../avm_memory_types.js';
18
18
  import { HostStorage } from '../journal/host_storage.js';
19
19
  import { AvmPersistableStateManager } from '../journal/journal.js';
20
- import { type TracedContractInstance } from '../journal/trace_types.js';
20
+ import { NullifierManager } from '../journal/nullifiers.js';
21
+ import { PublicStorage } from '../journal/public_storage.js';
21
22
 
22
23
  /**
23
24
  * Create a new AVM context with default values.
@@ -28,7 +29,7 @@ export function initContext(overrides?: {
28
29
  machineState?: AvmMachineState;
29
30
  }): AvmContext {
30
31
  return new AvmContext(
31
- overrides?.persistableState || initMockPersistableStateManager(),
32
+ overrides?.persistableState || initPersistableStateManager(),
32
33
  overrides?.env || initExecutionEnvironment(),
33
34
  overrides?.machineState || initMachineState(),
34
35
  );
@@ -47,9 +48,20 @@ export function initHostStorage(overrides?: {
47
48
  );
48
49
  }
49
50
 
50
- /** Creates an empty state manager with mocked storage. */
51
- export function initMockPersistableStateManager(): AvmPersistableStateManager {
52
- return new AvmPersistableStateManager(initHostStorage());
51
+ /** Creates an empty state manager with mocked host storage. */
52
+ export function initPersistableStateManager(overrides?: {
53
+ hostStorage?: HostStorage;
54
+ trace?: PublicSideEffectTraceInterface;
55
+ publicStorage?: PublicStorage;
56
+ nullifiers?: NullifierManager;
57
+ }): AvmPersistableStateManager {
58
+ const hostStorage = overrides?.hostStorage || initHostStorage();
59
+ return new AvmPersistableStateManager(
60
+ hostStorage,
61
+ overrides?.trace || mock<PublicSideEffectTraceInterface>(),
62
+ overrides?.publicStorage || new PublicStorage(hostStorage.publicStateDb),
63
+ overrides?.nullifiers || new NullifierManager(hostStorage.commitmentsDb),
64
+ );
53
65
  }
54
66
 
55
67
  /**
@@ -138,14 +150,3 @@ export function getAvmTestContractBytecode(functionName: string): Buffer {
138
150
  );
139
151
  return artifact.bytecode;
140
152
  }
141
-
142
- export function randomTracedContractInstance(): TracedContractInstance {
143
- const instance = SerializableContractInstance.random();
144
- const address = AztecAddress.random();
145
- return { exists: true, ...instance, address };
146
- }
147
-
148
- export function emptyTracedContractInstance(withAddress?: AztecAddress): TracedContractInstance {
149
- const instance = SerializableContractInstance.empty().withAddress(withAddress ?? AztecAddress.zero());
150
- return { exists: false, ...instance };
151
- }
@@ -1,139 +1,69 @@
1
- // TODO(5818): Rename file and all uses of "journal"
2
- import { UnencryptedL2Log } from '@aztec/circuit-types';
3
- import {
4
- AztecAddress,
5
- ContractStorageRead,
6
- ContractStorageUpdateRequest,
7
- EthAddress,
8
- L2ToL1Message,
9
- LogHash,
10
- NoteHash,
11
- Nullifier,
12
- ReadRequest,
13
- } from '@aztec/circuits.js';
14
- import { EventSelector } from '@aztec/foundation/abi';
15
- import { Fr } from '@aztec/foundation/fields';
1
+ import { AztecAddress, type FunctionSelector, type Gas } from '@aztec/circuits.js';
2
+ import { type Fr } from '@aztec/foundation/fields';
16
3
  import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';
17
4
  import { SerializableContractInstance } from '@aztec/types/contracts';
18
5
 
19
- import { type PublicExecutionResult } from '../../index.js';
6
+ import { type TracedContractInstance } from '../../public/side_effect_trace.js';
7
+ import { type PublicSideEffectTraceInterface } from '../../public/side_effect_trace_interface.js';
8
+ import { type AvmExecutionEnvironment } from '../avm_execution_environment.js';
9
+ import { type AvmContractCallResults } from '../avm_message_call_result.js';
20
10
  import { type HostStorage } from './host_storage.js';
21
- import { Nullifiers } from './nullifiers.js';
11
+ import { NullifierManager } from './nullifiers.js';
22
12
  import { PublicStorage } from './public_storage.js';
23
- import { WorldStateAccessTrace } from './trace.js';
24
- import {
25
- type TracedContractInstance,
26
- type TracedL1toL2MessageCheck,
27
- type TracedNoteHash,
28
- type TracedNoteHashCheck,
29
- type TracedNullifier,
30
- type TracedNullifierCheck,
31
- type TracedPublicStorageRead,
32
- type TracedPublicStorageWrite,
33
- type TracedUnencryptedL2Log,
34
- } from './trace_types.js';
35
-
36
- // TODO:(5818): do we need this type anymore?
37
- /**
38
- * Data held within the journal
39
- */
40
- export type JournalData = {
41
- storageWrites: TracedPublicStorageWrite[];
42
- storageReads: TracedPublicStorageRead[];
43
-
44
- noteHashChecks: TracedNoteHashCheck[];
45
- newNoteHashes: TracedNoteHash[];
46
- nullifierChecks: TracedNullifierCheck[];
47
- newNullifiers: TracedNullifier[];
48
- l1ToL2MessageChecks: TracedL1toL2MessageCheck[];
49
-
50
- newL1Messages: L2ToL1Message[];
51
- newLogs: UnencryptedL2Log[];
52
- newLogsHashes: TracedUnencryptedL2Log[];
53
- /** contract address -\> key -\> value */
54
- currentStorageValue: Map<bigint, Map<bigint, Fr>>;
55
-
56
- sideEffectCounter: number;
57
- };
58
-
59
- // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
60
- export type PartialPublicExecutionResult = {
61
- noteHashReadRequests: ReadRequest[];
62
- nullifierReadRequests: ReadRequest[];
63
- nullifierNonExistentReadRequests: ReadRequest[];
64
- l1ToL2MsgReadRequests: ReadRequest[];
65
- newNoteHashes: NoteHash[];
66
- newL2ToL1Messages: L2ToL1Message[];
67
- startSideEffectCounter: number;
68
- newNullifiers: Nullifier[];
69
- contractStorageReads: ContractStorageRead[];
70
- contractStorageUpdateRequests: ContractStorageUpdateRequest[];
71
- unencryptedLogsHashes: LogHash[];
72
- unencryptedLogs: UnencryptedL2Log[];
73
- allUnencryptedLogs: UnencryptedL2Log[];
74
- nestedExecutions: PublicExecutionResult[];
75
- };
76
13
 
77
14
  /**
78
15
  * A class to manage persistable AVM state for contract calls.
79
16
  * Maintains a cache of the current world state,
80
- * a trace of all world state accesses, and a list of accrued substate items.
17
+ * a trace of all side effects.
81
18
  *
82
- * The simulator should make any world state and accrued substate queries through this object.
19
+ * The simulator should make any world state / tree queries through this object.
83
20
  *
84
21
  * Manages merging of successful/reverted child state into current state.
85
22
  */
86
23
  export class AvmPersistableStateManager {
87
24
  private readonly log: DebugLogger = createDebugLogger('aztec:avm_simulator:state_manager');
88
- /** Reference to node storage */
89
- public readonly hostStorage: HostStorage;
90
-
91
- // TODO(5818): make members private once this is not used in transitional_adaptors.ts.
92
- /** World State */
93
- /** Public storage, including cached writes */
94
- public publicStorage: PublicStorage;
95
- /** Nullifier set, including cached/recently-emitted nullifiers */
96
- public nullifiers: Nullifiers;
97
25
 
98
- /** World State Access Trace */
99
- public trace: WorldStateAccessTrace;
26
+ constructor(
27
+ /** Reference to node storage */
28
+ private hostStorage: HostStorage,
29
+ /** Side effect trace */
30
+ private trace: PublicSideEffectTraceInterface,
31
+ /** Public storage, including cached writes */
32
+ public readonly publicStorage: PublicStorage,
33
+ /** Nullifier set, including cached/recently-emitted nullifiers */
34
+ private readonly nullifiers: NullifierManager,
35
+ ) {}
100
36
 
101
- /** Accrued Substate **/
102
- public newL1Messages: L2ToL1Message[] = [];
103
- public newLogs: UnencryptedL2Log[] = [];
104
-
105
- // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
106
- public transitionalExecutionResult: PartialPublicExecutionResult;
107
-
108
- constructor(hostStorage: HostStorage, parent?: AvmPersistableStateManager) {
109
- this.hostStorage = hostStorage;
110
- this.publicStorage = new PublicStorage(hostStorage.publicStateDb, parent?.publicStorage);
111
- this.nullifiers = new Nullifiers(hostStorage.commitmentsDb, parent?.nullifiers);
112
- this.trace = new WorldStateAccessTrace(parent?.trace);
113
-
114
- this.transitionalExecutionResult = {
115
- noteHashReadRequests: [],
116
- nullifierReadRequests: [],
117
- nullifierNonExistentReadRequests: [],
118
- l1ToL2MsgReadRequests: [],
119
- newNoteHashes: [],
120
- newL2ToL1Messages: [],
121
- startSideEffectCounter: this.trace.accessCounter,
122
- newNullifiers: [],
123
- contractStorageReads: [],
124
- contractStorageUpdateRequests: [],
125
- unencryptedLogsHashes: [],
126
- unencryptedLogs: [],
127
- allUnencryptedLogs: [],
128
- nestedExecutions: [],
129
- };
37
+ /**
38
+ * Create a new state manager with some preloaded pending siloed nullifiers
39
+ */
40
+ public static newWithPendingSiloedNullifiers(
41
+ hostStorage: HostStorage,
42
+ trace: PublicSideEffectTraceInterface,
43
+ pendingSiloedNullifiers: Fr[],
44
+ ) {
45
+ const parentNullifiers = NullifierManager.newWithPendingSiloedNullifiers(
46
+ hostStorage.commitmentsDb,
47
+ pendingSiloedNullifiers,
48
+ );
49
+ return new AvmPersistableStateManager(
50
+ hostStorage,
51
+ trace,
52
+ /*publicStorage=*/ new PublicStorage(hostStorage.publicStateDb),
53
+ /*nullifiers=*/ parentNullifiers.fork(),
54
+ );
130
55
  }
131
56
 
132
57
  /**
133
58
  * Create a new state manager forked from this one
134
59
  */
135
60
  public fork() {
136
- return new AvmPersistableStateManager(this.hostStorage, this);
61
+ return new AvmPersistableStateManager(
62
+ this.hostStorage,
63
+ this.trace.fork(),
64
+ this.publicStorage.fork(),
65
+ this.nullifiers.fork(),
66
+ );
137
67
  }
138
68
 
139
69
  /**
@@ -147,13 +77,6 @@ export class AvmPersistableStateManager {
147
77
  this.log.debug(`Storage write (address=${storageAddress}, slot=${slot}): value=${value}`);
148
78
  // Cache storage writes for later reference/reads
149
79
  this.publicStorage.write(storageAddress, slot, value);
150
-
151
- // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
152
- this.transitionalExecutionResult.contractStorageUpdateRequests.push(
153
- new ContractStorageUpdateRequest(slot, value, this.trace.accessCounter, storageAddress),
154
- );
155
-
156
- // Trace all storage writes (even reverted ones)
157
80
  this.trace.tracePublicStorageWrite(storageAddress, slot, value);
158
81
  }
159
82
 
@@ -169,14 +92,22 @@ export class AvmPersistableStateManager {
169
92
  this.log.debug(
170
93
  `Storage read (address=${storageAddress}, slot=${slot}): value=${value}, exists=${exists}, cached=${cached}`,
171
94
  );
95
+ this.trace.tracePublicStorageRead(storageAddress, slot, value, exists, cached);
96
+ return Promise.resolve(value);
97
+ }
172
98
 
173
- // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
174
- this.transitionalExecutionResult.contractStorageReads.push(
175
- new ContractStorageRead(slot, value, this.trace.accessCounter, storageAddress),
99
+ /**
100
+ * Read from public storage, don't trace the read.
101
+ *
102
+ * @param storageAddress - the address of the contract whose storage is being read from
103
+ * @param slot - the slot in the contract's storage being read from
104
+ * @returns the latest value written to slot, or 0 if never written to before
105
+ */
106
+ public async peekStorage(storageAddress: Fr, slot: Fr): Promise<Fr> {
107
+ const { value, exists, cached } = await this.publicStorage.read(storageAddress, slot);
108
+ this.log.debug(
109
+ `Storage peek (address=${storageAddress}, slot=${slot}): value=${value}, exists=${exists}, cached=${cached}`,
176
110
  );
177
-
178
- // We want to keep track of all performed reads (even reverted ones)
179
- this.trace.tracePublicStorageRead(storageAddress, slot, value, exists, cached);
180
111
  return Promise.resolve(value);
181
112
  }
182
113
 
@@ -193,11 +124,7 @@ export class AvmPersistableStateManager {
193
124
  const gotLeafIndex = await this.hostStorage.commitmentsDb.getCommitmentIndex(noteHash);
194
125
  const exists = gotLeafIndex === leafIndex.toBigInt();
195
126
  this.log.debug(`noteHashes(${storageAddress})@${noteHash} ?? leafIndex: ${leafIndex}, exists: ${exists}.`);
196
-
197
- // TODO: include exists here also - This can for sure come from the trace???
198
- this.transitionalExecutionResult.noteHashReadRequests.push(new ReadRequest(noteHash, this.trace.accessCounter));
199
-
200
- this.trace.traceNoteHashCheck(storageAddress, noteHash, exists, leafIndex);
127
+ this.trace.traceNoteHashCheck(storageAddress, noteHash, leafIndex, exists);
201
128
  return Promise.resolve(exists);
202
129
  }
203
130
 
@@ -206,9 +133,6 @@ export class AvmPersistableStateManager {
206
133
  * @param noteHash - the unsiloed note hash to write
207
134
  */
208
135
  public writeNoteHash(storageAddress: Fr, noteHash: Fr) {
209
- // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
210
- this.transitionalExecutionResult.newNoteHashes.push(new NoteHash(noteHash, this.trace.accessCounter));
211
-
212
136
  this.log.debug(`noteHashes(${storageAddress}) += @${noteHash}.`);
213
137
  this.trace.traceNewNoteHash(storageAddress, noteHash);
214
138
  }
@@ -222,19 +146,9 @@ export class AvmPersistableStateManager {
222
146
  public async checkNullifierExists(storageAddress: Fr, nullifier: Fr): Promise<boolean> {
223
147
  const [exists, isPending, leafIndex] = await this.nullifiers.checkExists(storageAddress, nullifier);
224
148
  this.log.debug(
225
- `nullifiers(${storageAddress})@${nullifier} ?? leafIndex: ${leafIndex}, pending: ${isPending}, exists: ${exists}.`,
149
+ `nullifiers(${storageAddress})@${nullifier} ?? leafIndex: ${leafIndex}, exists: ${exists}, pending: ${isPending}.`,
226
150
  );
227
-
228
- // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
229
- if (exists) {
230
- this.transitionalExecutionResult.nullifierReadRequests.push(new ReadRequest(nullifier, this.trace.accessCounter));
231
- } else {
232
- this.transitionalExecutionResult.nullifierNonExistentReadRequests.push(
233
- new ReadRequest(nullifier, this.trace.accessCounter),
234
- );
235
- }
236
-
237
- this.trace.traceNullifierCheck(storageAddress, nullifier, exists, isPending, leafIndex);
151
+ this.trace.traceNullifierCheck(storageAddress, nullifier, leafIndex, exists, isPending);
238
152
  return Promise.resolve(exists);
239
153
  }
240
154
 
@@ -244,11 +158,6 @@ export class AvmPersistableStateManager {
244
158
  * @param nullifier - the unsiloed nullifier to write
245
159
  */
246
160
  public async writeNullifier(storageAddress: Fr, nullifier: Fr) {
247
- // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
248
- this.transitionalExecutionResult.newNullifiers.push(
249
- new Nullifier(nullifier, this.trace.accessCounter, /*noteHash=*/ Fr.ZERO),
250
- );
251
-
252
161
  this.log.debug(`nullifiers(${storageAddress}) += ${nullifier}.`);
253
162
  // Cache pending nullifiers for later access
254
163
  await this.nullifiers.append(storageAddress, nullifier);
@@ -262,16 +171,13 @@ export class AvmPersistableStateManager {
262
171
  * @param msgLeafIndex - the message leaf index to use in the check
263
172
  * @returns exists - whether the message exists in the L1 to L2 Messages tree
264
173
  */
265
- public async checkL1ToL2MessageExists(msgHash: Fr, msgLeafIndex: Fr): Promise<boolean> {
174
+ public async checkL1ToL2MessageExists(contractAddress: Fr, msgHash: Fr, msgLeafIndex: Fr): Promise<boolean> {
266
175
  const valueAtIndex = await this.hostStorage.commitmentsDb.getL1ToL2LeafValue(msgLeafIndex.toBigInt());
267
176
  const exists = valueAtIndex?.equals(msgHash) ?? false;
268
177
  this.log.debug(
269
178
  `l1ToL2Messages(@${msgLeafIndex}) ?? exists: ${exists}, expected: ${msgHash}, found: ${valueAtIndex}.`,
270
179
  );
271
-
272
- this.transitionalExecutionResult.l1ToL2MsgReadRequests.push(new ReadRequest(msgHash, this.trace.accessCounter));
273
-
274
- this.trace.traceL1ToL2MessageCheck(msgHash, msgLeafIndex, exists);
180
+ this.trace.traceL1ToL2MessageCheck(contractAddress, msgHash, msgLeafIndex, exists);
275
181
  return Promise.resolve(exists);
276
182
  }
277
183
 
@@ -280,40 +186,27 @@ export class AvmPersistableStateManager {
280
186
  * @param recipient - L1 contract address to send the message to.
281
187
  * @param content - Message content.
282
188
  */
283
- public writeL1Message(recipient: EthAddress | Fr, content: Fr) {
189
+ public writeL2ToL1Message(recipient: Fr, content: Fr) {
284
190
  this.log.debug(`L1Messages(${recipient}) += ${content}.`);
285
- const recipientAddress = recipient instanceof EthAddress ? recipient : EthAddress.fromField(recipient);
286
- const message = new L2ToL1Message(recipientAddress, content, 0);
287
- this.newL1Messages.push(message);
288
-
289
- // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
290
- this.transitionalExecutionResult.newL2ToL1Messages.push(message);
191
+ this.trace.traceNewL2ToL1Message(recipient, content);
291
192
  }
292
193
 
293
- public writeLog(contractAddress: Fr, event: Fr, log: Fr[]) {
194
+ /**
195
+ * Write an unencrypted log
196
+ * @param contractAddress - address of the contract that emitted the log
197
+ * @param event - log event selector
198
+ * @param log - log contents
199
+ */
200
+ public writeUnencryptedLog(contractAddress: Fr, event: Fr, log: Fr[]) {
294
201
  this.log.debug(`UnencryptedL2Log(${contractAddress}) += event ${event} with ${log.length} fields.`);
295
- const ulog = new UnencryptedL2Log(
296
- AztecAddress.fromField(contractAddress),
297
- EventSelector.fromField(event),
298
- Buffer.concat(log.map(f => f.toBuffer())),
299
- );
300
- const logHash = Fr.fromBuffer(ulog.hash());
301
-
302
- // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
303
- this.transitionalExecutionResult.unencryptedLogs.push(ulog);
304
- this.transitionalExecutionResult.allUnencryptedLogs.push(ulog);
305
- // this duplicates exactly what happens in the trace just for the purpose of transitional integration with the kernel
306
- this.transitionalExecutionResult.unencryptedLogsHashes.push(
307
- // TODO(6578): explain magic number 4 here
308
- new LogHash(logHash, this.trace.accessCounter, new Fr(ulog.length + 4)),
309
- );
310
- // TODO(6206): likely need to track this here and not just in the transitional logic.
311
-
312
- // TODO(6205): why are logs pushed here but logs hashes are traced?
313
- this.newLogs.push(ulog);
314
- this.trace.traceNewLog(logHash);
202
+ this.trace.traceUnencryptedLog(contractAddress, event, log);
315
203
  }
316
204
 
205
+ /**
206
+ * Get a contract instance.
207
+ * @param contractAddress - address of the contract instance to retrieve.
208
+ * @returns the contract instance with an "exists" flag
209
+ */
317
210
  public async getContractInstance(contractAddress: Fr): Promise<TracedContractInstance> {
318
211
  let exists = true;
319
212
  const aztecAddress = AztecAddress.fromField(contractAddress);
@@ -322,59 +215,57 @@ export class AvmPersistableStateManager {
322
215
  instance = SerializableContractInstance.empty().withAddress(aztecAddress);
323
216
  exists = false;
324
217
  }
218
+ this.log.debug(
219
+ `Get Contract instance (address=${contractAddress}): exists=${exists}, instance=${JSON.stringify(instance)}`,
220
+ );
325
221
  const tracedInstance = { ...instance, exists };
326
222
  this.trace.traceGetContractInstance(tracedInstance);
327
223
  return Promise.resolve(tracedInstance);
328
224
  }
329
225
 
330
226
  /**
331
- * Accept nested world state modifications, merging in its trace and accrued substate
227
+ * Accept nested world state modifications
332
228
  */
333
- public acceptNestedCallState(nestedJournal: AvmPersistableStateManager) {
334
- // Merge Public Storage
335
- this.publicStorage.acceptAndMerge(nestedJournal.publicStorage);
336
-
337
- // Merge World State Access Trace
338
- this.trace.acceptAndMerge(nestedJournal.trace);
339
-
340
- // Accrued Substate
341
- this.newL1Messages.push(...nestedJournal.newL1Messages);
342
- this.newLogs.push(...nestedJournal.newLogs);
343
-
344
- // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
345
- this.transitionalExecutionResult.allUnencryptedLogs.push(
346
- ...nestedJournal.transitionalExecutionResult.allUnencryptedLogs,
347
- );
229
+ public acceptNestedCallState(nestedState: AvmPersistableStateManager) {
230
+ this.publicStorage.acceptAndMerge(nestedState.publicStorage);
231
+ this.nullifiers.acceptAndMerge(nestedState.nullifiers);
348
232
  }
349
233
 
350
234
  /**
351
- * Reject nested world state, merging in its trace, but not accepting any state modifications
235
+ * Get a contract's bytecode from the contracts DB
352
236
  */
353
- public rejectNestedCallState(nestedJournal: AvmPersistableStateManager) {
354
- // Merge World State Access Trace
355
- this.trace.acceptAndMerge(nestedJournal.trace);
237
+ public async getBytecode(contractAddress: AztecAddress, selector: FunctionSelector): Promise<Buffer | undefined> {
238
+ return await this.hostStorage.contractsDb.getBytecode(contractAddress, selector);
356
239
  }
357
240
 
358
- // TODO:(5818): do we need this type anymore?
359
241
  /**
360
- * Access the current state of the journal
361
- *
362
- * @returns a JournalData object
242
+ * Accept the nested call's state and trace the nested call
363
243
  */
364
- public flush(): JournalData {
365
- return {
366
- noteHashChecks: this.trace.noteHashChecks,
367
- newNoteHashes: this.trace.newNoteHashes,
368
- nullifierChecks: this.trace.nullifierChecks,
369
- newNullifiers: this.trace.newNullifiers,
370
- l1ToL2MessageChecks: this.trace.l1ToL2MessageChecks,
371
- newL1Messages: this.newL1Messages,
372
- newLogs: this.newLogs,
373
- newLogsHashes: this.trace.newLogsHashes,
374
- currentStorageValue: this.publicStorage.getCache().cachePerContract,
375
- storageReads: this.trace.publicStorageReads,
376
- storageWrites: this.trace.publicStorageWrites,
377
- sideEffectCounter: this.trace.accessCounter,
378
- };
244
+ public async processNestedCall(
245
+ nestedState: AvmPersistableStateManager,
246
+ success: boolean,
247
+ nestedEnvironment: AvmExecutionEnvironment,
248
+ startGasLeft: Gas,
249
+ endGasLeft: Gas,
250
+ bytecode: Buffer,
251
+ avmCallResults: AvmContractCallResults,
252
+ ) {
253
+ if (success) {
254
+ this.acceptNestedCallState(nestedState);
255
+ }
256
+ const functionName =
257
+ (await nestedState.hostStorage.contractsDb.getDebugFunctionName(
258
+ nestedEnvironment.address,
259
+ nestedEnvironment.temporaryFunctionSelector,
260
+ )) ?? `${nestedEnvironment.address}:${nestedEnvironment.temporaryFunctionSelector}`;
261
+ this.trace.traceNestedCall(
262
+ nestedState.trace,
263
+ nestedEnvironment,
264
+ startGasLeft,
265
+ endGasLeft,
266
+ bytecode,
267
+ avmCallResults,
268
+ functionName,
269
+ );
379
270
  }
380
271
  }
@@ -9,17 +9,29 @@ import type { CommitmentsDB } from '../../index.js';
9
9
  * Maintains a nullifier cache, and ensures that existence checks fall back to the correct source.
10
10
  * When a contract call completes, its cached nullifier set can be merged into its parent's.
11
11
  */
12
- export class Nullifiers {
13
- /** Cached nullifiers. */
14
- public cache: NullifierCache;
15
-
12
+ export class NullifierManager {
16
13
  constructor(
17
14
  /** Reference to node storage. Checked on parent cache-miss. */
18
15
  private readonly hostNullifiers: CommitmentsDB,
19
- /** Parent's nullifiers. Checked on this' cache-miss. */
20
- private readonly parent?: Nullifiers | undefined,
21
- ) {
22
- this.cache = new NullifierCache();
16
+ /** Cached nullifiers. */
17
+ private readonly cache: NullifierCache = new NullifierCache(),
18
+ /** Parent nullifier manager to fall back on */
19
+ private readonly parent?: NullifierManager,
20
+ ) {}
21
+
22
+ /**
23
+ * Create a new nullifiers manager with some preloaded pending siloed nullifiers
24
+ */
25
+ public static newWithPendingSiloedNullifiers(hostNullifiers: CommitmentsDB, pendingSiloedNullifiers: Fr[]) {
26
+ const cache = new NullifierCache(pendingSiloedNullifiers);
27
+ return new NullifierManager(hostNullifiers, cache);
28
+ }
29
+
30
+ /**
31
+ * Create a new nullifiers manager forked from this one
32
+ */
33
+ public fork() {
34
+ return new NullifierManager(this.hostNullifiers, new NullifierCache(), this);
23
35
  }
24
36
 
25
37
  /**
@@ -92,7 +104,7 @@ export class Nullifiers {
92
104
  *
93
105
  * @param incomingNullifiers - the incoming cached nullifiers to merge into this instance's
94
106
  */
95
- public acceptAndMerge(incomingNullifiers: Nullifiers) {
107
+ public acceptAndMerge(incomingNullifiers: NullifierManager) {
96
108
  this.cache.acceptAndMerge(incomingNullifiers.cache);
97
109
  }
98
110
  }
@@ -111,6 +123,15 @@ export class NullifierCache {
111
123
  private cachePerContract: Map<bigint, Set<bigint>> = new Map();
112
124
  private siloedNullifiers: Set<bigint> = new Set();
113
125
 
126
+ /**
127
+ * @parem siloedNullifierFrs: optional list of pending siloed nullifiers to initialize this cache with
128
+ */
129
+ constructor(siloedNullifierFrs?: Fr[]) {
130
+ if (siloedNullifierFrs !== undefined) {
131
+ siloedNullifierFrs.forEach(nullifier => this.siloedNullifiers.add(nullifier.toBigInt()));
132
+ }
133
+ }
134
+
114
135
  /**
115
136
  * Check whether a nullifier exists in the cache.
116
137
  *
@@ -147,10 +168,6 @@ export class NullifierCache {
147
168
  nullifiersForContract.add(nullifier.toBigInt());
148
169
  }
149
170
 
150
- public appendSiloed(siloedNullifier: Fr) {
151
- this.siloedNullifiers.add(siloedNullifier.toBigInt());
152
- }
153
-
154
171
  /**
155
172
  * Merge another cache's nullifiers into this instance's.
156
173
  *
@@ -27,6 +27,13 @@ export class PublicStorage {
27
27
  this.cache = new PublicStorageCache();
28
28
  }
29
29
 
30
+ /**
31
+ * Create a new public storage manager forked from this one
32
+ */
33
+ public fork() {
34
+ return new PublicStorage(this.hostPublicStorage, this);
35
+ }
36
+
30
37
  /**
31
38
  * Get the pending storage.
32
39
  */
@@ -71,6 +78,9 @@ export class PublicStorage {
71
78
  // Finally try the host's Aztec state (a trip to the database)
72
79
  if (!value) {
73
80
  value = await this.hostPublicStorage.storageRead(storageAddress, slot);
81
+ // TODO(dbanks12): if value retrieved from host storage, we can cache it here
82
+ // any future reads to the same slot can read from cache instead of more expensive
83
+ // DB access
74
84
  } else {
75
85
  cached = true;
76
86
  }
@@ -201,7 +201,11 @@ export class L1ToL2MessageExists extends Instruction {
201
201
 
202
202
  const msgHash = memory.get(msgHashOffset).toFr();
203
203
  const msgLeafIndex = memory.get(msgLeafIndexOffset).toFr();
204
- const exists = await context.persistableState.checkL1ToL2MessageExists(msgHash, msgLeafIndex);
204
+ const exists = await context.persistableState.checkL1ToL2MessageExists(
205
+ context.environment.address,
206
+ msgHash,
207
+ msgLeafIndex,
208
+ );
205
209
  memory.set(existsOffset, exists ? new Uint8(1) : new Uint8(0));
206
210
 
207
211
  memory.assert(memoryOperations);
@@ -252,7 +256,7 @@ export class EmitUnencryptedLog extends Instruction {
252
256
  const memoryOperations = { reads: 2 + logSize, indirect: this.indirect };
253
257
  context.machineState.consumeGas(this.gasCost(memoryOperations));
254
258
  const log = memory.getSlice(logOffset, logSize).map(f => f.toFr());
255
- context.persistableState.writeLog(contractAddress, event, log);
259
+ context.persistableState.writeUnencryptedLog(contractAddress, event, log);
256
260
 
257
261
  memory.assert(memoryOperations);
258
262
  context.machineState.incrementPc();
@@ -285,7 +289,7 @@ export class SendL2ToL1Message extends Instruction {
285
289
 
286
290
  const recipient = memory.get(recipientOffset).toFr();
287
291
  const content = memory.get(contentOffset).toFr();
288
- context.persistableState.writeL1Message(recipient, content);
292
+ context.persistableState.writeL2ToL1Message(recipient, content);
289
293
 
290
294
  memory.assert(memoryOperations);
291
295
  context.machineState.incrementPc();