@aztec/simulator 0.71.0 → 0.73.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 (137) hide show
  1. package/README.md +1 -1
  2. package/dest/acvm/oracle/oracle.d.ts +0 -1
  3. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  4. package/dest/acvm/oracle/oracle.js +1 -5
  5. package/dest/acvm/oracle/typed_oracle.d.ts +0 -1
  6. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  7. package/dest/acvm/oracle/typed_oracle.js +1 -4
  8. package/dest/avm/avm_simulator.d.ts +0 -1
  9. package/dest/avm/avm_simulator.d.ts.map +1 -1
  10. package/dest/avm/avm_simulator.js +4 -19
  11. package/dest/avm/avm_tree.d.ts +9 -8
  12. package/dest/avm/avm_tree.d.ts.map +1 -1
  13. package/dest/avm/avm_tree.js +35 -30
  14. package/dest/avm/errors.d.ts +6 -0
  15. package/dest/avm/errors.d.ts.map +1 -1
  16. package/dest/avm/errors.js +10 -1
  17. package/dest/avm/fixtures/avm_simulation_tester.d.ts +21 -0
  18. package/dest/avm/fixtures/avm_simulation_tester.d.ts.map +1 -0
  19. package/dest/avm/fixtures/avm_simulation_tester.js +74 -0
  20. package/dest/avm/fixtures/base_avm_simulation_tester.d.ts +35 -0
  21. package/dest/avm/fixtures/base_avm_simulation_tester.d.ts.map +1 -0
  22. package/dest/avm/fixtures/base_avm_simulation_tester.js +76 -0
  23. package/dest/avm/fixtures/index.d.ts +6 -2
  24. package/dest/avm/fixtures/index.d.ts.map +1 -1
  25. package/dest/avm/fixtures/index.js +28 -14
  26. package/dest/avm/fixtures/simple_contract_data_source.d.ts +31 -0
  27. package/dest/avm/fixtures/simple_contract_data_source.d.ts.map +1 -0
  28. package/dest/avm/fixtures/simple_contract_data_source.js +75 -0
  29. package/dest/avm/journal/journal.d.ts +5 -6
  30. package/dest/avm/journal/journal.d.ts.map +1 -1
  31. package/dest/avm/journal/journal.js +28 -26
  32. package/dest/avm/opcodes/accrued_substate.d.ts.map +1 -1
  33. package/dest/avm/opcodes/accrued_substate.js +4 -3
  34. package/dest/avm/opcodes/conversion.d.ts.map +1 -1
  35. package/dest/avm/opcodes/conversion.js +10 -7
  36. package/dest/avm/opcodes/ec_add.js +2 -2
  37. package/dest/avm/opcodes/hashing.js +2 -2
  38. package/dest/avm/opcodes/multi_scalar_mul.d.ts.map +1 -1
  39. package/dest/avm/opcodes/multi_scalar_mul.js +9 -7
  40. package/dest/avm/test_utils.d.ts +1 -1
  41. package/dest/avm/test_utils.d.ts.map +1 -1
  42. package/dest/avm/test_utils.js +4 -3
  43. package/dest/client/client_execution_context.d.ts +2 -6
  44. package/dest/client/client_execution_context.d.ts.map +1 -1
  45. package/dest/client/client_execution_context.js +23 -26
  46. package/dest/client/execution_note_cache.d.ts +3 -3
  47. package/dest/client/execution_note_cache.d.ts.map +1 -1
  48. package/dest/client/execution_note_cache.js +10 -10
  49. package/dest/client/pick_notes.js +5 -5
  50. package/dest/client/simulator.js +4 -4
  51. package/dest/client/view_data_oracle.js +2 -2
  52. package/dest/common/hashed_values_cache.d.ts +1 -1
  53. package/dest/common/hashed_values_cache.d.ts.map +1 -1
  54. package/dest/common/hashed_values_cache.js +5 -5
  55. package/dest/providers/acvm_wasm.d.ts +2 -0
  56. package/dest/providers/acvm_wasm.d.ts.map +1 -1
  57. package/dest/providers/acvm_wasm.js +15 -2
  58. package/dest/public/execution.d.ts +8 -26
  59. package/dest/public/execution.d.ts.map +1 -1
  60. package/dest/public/execution.js +3 -3
  61. package/dest/public/fee_payment.d.ts +2 -2
  62. package/dest/public/fee_payment.d.ts.map +1 -1
  63. package/dest/public/fee_payment.js +3 -3
  64. package/dest/public/fixtures/index.d.ts +2 -37
  65. package/dest/public/fixtures/index.d.ts.map +1 -1
  66. package/dest/public/fixtures/index.js +3 -247
  67. package/dest/public/fixtures/public_tx_simulation_tester.d.ts +21 -0
  68. package/dest/public/fixtures/public_tx_simulation_tester.d.ts.map +1 -0
  69. package/dest/public/fixtures/public_tx_simulation_tester.js +89 -0
  70. package/dest/public/fixtures/utils.d.ts +17 -0
  71. package/dest/public/fixtures/utils.d.ts.map +1 -0
  72. package/dest/public/fixtures/utils.js +66 -0
  73. package/dest/public/index.d.ts +1 -1
  74. package/dest/public/index.d.ts.map +1 -1
  75. package/dest/public/index.js +2 -2
  76. package/dest/public/public_db_sources.d.ts +2 -1
  77. package/dest/public/public_db_sources.d.ts.map +1 -1
  78. package/dest/public/public_db_sources.js +27 -21
  79. package/dest/public/public_processor.d.ts +4 -5
  80. package/dest/public/public_processor.d.ts.map +1 -1
  81. package/dest/public/public_processor.js +28 -28
  82. package/dest/public/public_tx_context.d.ts +5 -5
  83. package/dest/public/public_tx_context.d.ts.map +1 -1
  84. package/dest/public/public_tx_context.js +44 -18
  85. package/dest/public/public_tx_simulator.d.ts.map +1 -1
  86. package/dest/public/public_tx_simulator.js +9 -12
  87. package/dest/public/{enqueued_call_side_effect_trace.d.ts → side_effect_trace.d.ts} +12 -15
  88. package/dest/public/side_effect_trace.d.ts.map +1 -0
  89. package/dest/public/side_effect_trace.js +350 -0
  90. package/dest/public/side_effect_trace_interface.d.ts +4 -5
  91. package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
  92. package/dest/test/utils.d.ts +1 -1
  93. package/dest/test/utils.d.ts.map +1 -1
  94. package/dest/test/utils.js +3 -3
  95. package/package.json +10 -10
  96. package/src/acvm/oracle/oracle.ts +0 -5
  97. package/src/acvm/oracle/typed_oracle.ts +0 -4
  98. package/src/avm/avm_simulator.ts +3 -27
  99. package/src/avm/avm_tree.ts +39 -37
  100. package/src/avm/errors.ts +10 -0
  101. package/src/avm/fixtures/avm_simulation_tester.ts +105 -0
  102. package/src/avm/fixtures/base_avm_simulation_tester.ts +104 -0
  103. package/src/avm/fixtures/index.ts +46 -17
  104. package/src/avm/fixtures/simple_contract_data_source.ts +98 -0
  105. package/src/avm/journal/journal.ts +28 -26
  106. package/src/avm/opcodes/accrued_substate.ts +3 -2
  107. package/src/avm/opcodes/conversion.ts +15 -6
  108. package/src/avm/opcodes/ec_add.ts +1 -1
  109. package/src/avm/opcodes/hashing.ts +1 -1
  110. package/src/avm/opcodes/multi_scalar_mul.ts +8 -6
  111. package/src/avm/test_utils.ts +3 -4
  112. package/src/client/client_execution_context.ts +29 -30
  113. package/src/client/execution_note_cache.ts +19 -14
  114. package/src/client/pick_notes.ts +4 -4
  115. package/src/client/simulator.ts +3 -3
  116. package/src/client/view_data_oracle.ts +1 -1
  117. package/src/common/hashed_values_cache.ts +4 -4
  118. package/src/providers/acvm_wasm.ts +13 -2
  119. package/src/public/execution.ts +10 -34
  120. package/src/public/fee_payment.ts +2 -2
  121. package/src/public/fixtures/index.ts +2 -381
  122. package/src/public/fixtures/public_tx_simulation_tester.ts +174 -0
  123. package/src/public/fixtures/utils.ts +110 -0
  124. package/src/public/index.ts +1 -1
  125. package/src/public/public_db_sources.ts +31 -20
  126. package/src/public/public_processor.ts +32 -30
  127. package/src/public/public_tx_context.ts +87 -28
  128. package/src/public/public_tx_simulator.ts +7 -14
  129. package/src/public/{enqueued_call_side_effect_trace.ts → side_effect_trace.ts} +29 -41
  130. package/src/public/side_effect_trace_interface.ts +4 -4
  131. package/src/test/utils.ts +2 -2
  132. package/dest/public/enqueued_call_side_effect_trace.d.ts.map +0 -1
  133. package/dest/public/enqueued_call_side_effect_trace.js +0 -357
  134. package/dest/public/transitional_adapters.d.ts +0 -4
  135. package/dest/public/transitional_adapters.d.ts.map +0 -1
  136. package/dest/public/transitional_adapters.js +0 -29
  137. package/src/public/transitional_adapters.ts +0 -113
@@ -1,4 +1,5 @@
1
1
  import {
2
+ ContractClassTxL2Logs,
2
3
  MerkleTreeId,
3
4
  type MerkleTreeReadOperations,
4
5
  type MerkleTreeWriteOperations,
@@ -44,16 +45,18 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB {
44
45
  * Add new contracts from a transaction
45
46
  * @param tx - The transaction to add contracts from.
46
47
  */
47
- public addNewContracts(tx: Tx): Promise<void> {
48
+ public async addNewContracts(tx: Tx): Promise<void> {
48
49
  // Extract contract class and instance data from logs and add to cache for this block
49
50
  const logs = tx.contractClassLogs.unrollLogs();
50
- logs
51
+ const contractClassRegisteredEvents = logs
51
52
  .filter(log => ContractClassRegisteredEvent.isContractClassRegisteredEvent(log.data))
52
- .forEach(log => {
53
- const event = ContractClassRegisteredEvent.fromLog(log.data);
53
+ .map(log => ContractClassRegisteredEvent.fromLog(log.data));
54
+ await Promise.all(
55
+ contractClassRegisteredEvents.map(async event => {
54
56
  this.log.debug(`Adding class ${event.contractClassId.toString()} to public execution contract cache`);
55
- this.classCache.set(event.contractClassId.toString(), event.toContractClassPublic());
56
- });
57
+ this.classCache.set(event.contractClassId.toString(), await event.toContractClassPublic());
58
+ }),
59
+ );
57
60
 
58
61
  // We store the contract instance deployed event log in private logs, contract_instance_deployer_contract/src/main.nr
59
62
  const contractInstanceEvents = tx.data
@@ -66,20 +69,26 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB {
66
69
  );
67
70
  this.instanceCache.set(e.address.toString(), e.toContractInstance());
68
71
  });
69
-
70
- return Promise.resolve();
71
72
  }
72
73
 
73
74
  /**
74
75
  * Removes new contracts added from transactions
75
76
  * @param tx - The tx's contracts to be removed
77
+ * @param onlyRevertible - Whether to only remove contracts added from revertible contract class logs
76
78
  */
77
- public removeNewContracts(tx: Tx): Promise<void> {
79
+ public removeNewContracts(tx: Tx, onlyRevertible: boolean = false): Promise<void> {
78
80
  // TODO(@spalladino): Can this inadvertently delete a valid contract added by another tx?
79
81
  // Let's say we have two txs adding the same contract on the same block. If the 2nd one reverts,
80
82
  // wouldn't that accidentally remove the contract added on the first one?
81
- const logs = tx.contractClassLogs.unrollLogs();
82
- logs
83
+ const contractClassLogs = onlyRevertible
84
+ ? tx.contractClassLogs
85
+ .filterScoped(
86
+ tx.data.forPublic!.revertibleAccumulatedData.contractClassLogsHashes,
87
+ ContractClassTxL2Logs.empty(),
88
+ )
89
+ .unrollLogs()
90
+ : tx.contractClassLogs.unrollLogs();
91
+ contractClassLogs
83
92
  .filter(log => ContractClassRegisteredEvent.isContractClassRegisteredEvent(log.data))
84
93
  .forEach(log => {
85
94
  const event = ContractClassRegisteredEvent.fromLog(log.data);
@@ -87,8 +96,10 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB {
87
96
  });
88
97
 
89
98
  // We store the contract instance deployed event log in private logs, contract_instance_deployer_contract/src/main.nr
90
- const contractInstanceEvents = tx.data
91
- .getNonEmptyPrivateLogs()
99
+ const privateLogs = onlyRevertible
100
+ ? tx.data.forPublic!.revertibleAccumulatedData.privateLogs.filter(l => !l.isEmpty())
101
+ : tx.data.getNonEmptyPrivateLogs();
102
+ const contractInstanceEvents = privateLogs
92
103
  .filter(log => ContractInstanceDeployedEvent.isContractInstanceDeployedEvent(log))
93
104
  .map(ContractInstanceDeployedEvent.fromLog);
94
105
  contractInstanceEvents.forEach(e => this.instanceCache.delete(e.address.toString()));
@@ -124,7 +135,7 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB {
124
135
  return undefined;
125
136
  }
126
137
 
127
- const value = computePublicBytecodeCommitment(contractClass.packedBytecode);
138
+ const value = await computePublicBytecodeCommitment(contractClass.packedBytecode);
128
139
  this.bytecodeCommitmentCache.set(key, value);
129
140
  return value;
130
141
  }
@@ -171,7 +182,7 @@ export class WorldStateDB extends ContractsDataSourcePublicDB implements PublicS
171
182
  * @returns The current value in the storage slot.
172
183
  */
173
184
  public async storageRead(contract: AztecAddress, slot: Fr): Promise<Fr> {
174
- const leafSlot = computePublicDataTreeLeafSlot(contract, slot).value;
185
+ const leafSlot = (await computePublicDataTreeLeafSlot(contract, slot)).toBigInt();
175
186
  const uncommitted = this.publicUncommittedWriteCache.get(leafSlot);
176
187
  if (uncommitted !== undefined) {
177
188
  return uncommitted;
@@ -195,10 +206,10 @@ export class WorldStateDB extends ContractsDataSourcePublicDB implements PublicS
195
206
  * @param newValue - The new value to store.
196
207
  * @returns The slot of the written leaf in the public data tree.
197
208
  */
198
- public storageWrite(contract: AztecAddress, slot: Fr, newValue: Fr): Promise<bigint> {
199
- const index = computePublicDataTreeLeafSlot(contract, slot).value;
209
+ public async storageWrite(contract: AztecAddress, slot: Fr, newValue: Fr): Promise<bigint> {
210
+ const index = (await computePublicDataTreeLeafSlot(contract, slot)).toBigInt();
200
211
  this.publicUncommittedWriteCache.set(index, newValue);
201
- return Promise.resolve(index);
212
+ return index;
202
213
  }
203
214
 
204
215
  public async getNullifierMembershipWitnessAtLatestBlock(
@@ -243,7 +254,7 @@ export class WorldStateDB extends ContractsDataSourcePublicDB implements PublicS
243
254
  throw new Error(`No L1 to L2 message found for message hash ${messageHash.toString()}`);
244
255
  }
245
256
 
246
- const messageNullifier = computeL1ToL2MessageNullifier(contractAddress, messageHash, secret);
257
+ const messageNullifier = await computeL1ToL2MessageNullifier(contractAddress, messageHash, secret);
247
258
  const nullifierIndex = await this.getNullifierIndex(messageNullifier);
248
259
 
249
260
  if (nullifierIndex !== undefined) {
@@ -348,7 +359,7 @@ export class WorldStateDB extends ContractsDataSourcePublicDB implements PublicS
348
359
  }
349
360
 
350
361
  export async function readPublicState(db: MerkleTreeReadOperations, contract: AztecAddress, slot: Fr): Promise<Fr> {
351
- const leafSlot = computePublicDataTreeLeafSlot(contract, slot).toBigInt();
362
+ const leafSlot = (await computePublicDataTreeLeafSlot(contract, slot)).toBigInt();
352
363
 
353
364
  const lowLeafResult = await db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot);
354
365
  if (!lowLeafResult || !lowLeafResult.alreadyPresent) {
@@ -12,7 +12,6 @@ import {
12
12
  } from '@aztec/circuit-types';
13
13
  import {
14
14
  type AztecAddress,
15
- type BlockHeader,
16
15
  type ContractDataSource,
17
16
  Fr,
18
17
  Gas,
@@ -60,12 +59,9 @@ export class PublicProcessorFactory {
60
59
  */
61
60
  public create(
62
61
  merkleTree: MerkleTreeWriteOperations,
63
- maybeHistoricalHeader: BlockHeader | undefined,
64
62
  globalVariables: GlobalVariables,
65
63
  enforceFeePayment: boolean,
66
64
  ): PublicProcessor {
67
- const historicalHeader = maybeHistoricalHeader ?? merkleTree.getInitialHeader();
68
-
69
65
  const worldStateDB = new WorldStateDB(merkleTree, this.contractDataSource);
70
66
  const publicTxSimulator = this.createPublicTxSimulator(
71
67
  merkleTree,
@@ -79,7 +75,6 @@ export class PublicProcessorFactory {
79
75
  return new PublicProcessor(
80
76
  merkleTree,
81
77
  globalVariables,
82
- historicalHeader,
83
78
  worldStateDB,
84
79
  publicTxSimulator,
85
80
  this.dateProvider,
@@ -122,7 +117,6 @@ export class PublicProcessor implements Traceable {
122
117
  constructor(
123
118
  protected db: MerkleTreeWriteOperations,
124
119
  protected globalVariables: GlobalVariables,
125
- protected historicalHeader: BlockHeader,
126
120
  protected worldStateDB: WorldStateDB,
127
121
  protected publicTxSimulator: PublicTxSimulator,
128
122
  private dateProvider: DateProvider,
@@ -143,7 +137,7 @@ export class PublicProcessor implements Traceable {
143
137
  * @returns The list of processed txs with their circuit simulation outputs.
144
138
  */
145
139
  public async process(
146
- txs: Iterable<Tx>,
140
+ txs: Iterable<Tx> | AsyncIterable<Tx>,
147
141
  limits: {
148
142
  maxTransactions?: number;
149
143
  maxBlockSize?: number;
@@ -167,7 +161,7 @@ export class PublicProcessor implements Traceable {
167
161
  let totalPublicGas = new Gas(0, 0);
168
162
  let totalBlockGas = new Gas(0, 0);
169
163
 
170
- for (const origTx of txs) {
164
+ for await (const origTx of txs) {
171
165
  // Only process up to the max tx limit
172
166
  if (maxTransactions !== undefined && result.length >= maxTransactions) {
173
167
  this.log.debug(`Stopping tx processing due to reaching the max tx limit.`);
@@ -181,7 +175,7 @@ export class PublicProcessor implements Traceable {
181
175
  }
182
176
 
183
177
  // Skip this tx if it'd exceed max block size
184
- const txHash = origTx.getTxHash().toString();
178
+ const txHash = (await origTx.getTxHash()).toString();
185
179
  const preTxSizeInBytes = origTx.getEstimatedPrivateTxEffectsSize();
186
180
  if (maxBlockSize !== undefined && totalSizeInBytes + preTxSizeInBytes > maxBlockSize) {
187
181
  this.log.warn(`Skipping processing of tx ${txHash} sized ${preTxSizeInBytes} bytes due to block size limit`, {
@@ -211,19 +205,20 @@ export class PublicProcessor implements Traceable {
211
205
  // We validate the tx before processing it, to avoid unnecessary work.
212
206
  if (preprocessValidator) {
213
207
  const result = await preprocessValidator.validateTx(tx);
208
+ const txHash = await tx.getTxHash();
214
209
  if (result.result === 'invalid') {
215
210
  const reason = result.reason.join(', ');
216
- this.log.warn(`Rejecting tx ${tx.getTxHash().toString()} due to pre-process validation fail: ${reason}`);
211
+ this.log.warn(`Rejecting tx ${txHash.toString()} due to pre-process validation fail: ${reason}`);
217
212
  failed.push({ tx, error: new Error(`Tx failed preprocess validation: ${reason}`) });
218
213
  returns.push(new NestedProcessReturnValues([]));
219
214
  continue;
220
215
  } else if (result.result === 'skipped') {
221
216
  const reason = result.reason.join(', ');
222
- this.log.warn(`Skipping tx ${tx.getTxHash().toString()} due to pre-process validation: ${reason}`);
217
+ this.log.warn(`Skipping tx ${txHash.toString()} due to pre-process validation: ${reason}`);
223
218
  returns.push(new NestedProcessReturnValues([]));
224
219
  continue;
225
220
  } else {
226
- this.log.trace(`Tx ${tx.getTxHash().toString()} is valid before processing.`);
221
+ this.log.trace(`Tx ${txHash.toString()} is valid before processing.`);
227
222
  }
228
223
  }
229
224
 
@@ -256,7 +251,7 @@ export class PublicProcessor implements Traceable {
256
251
  failed.push({ tx, error: new Error(`Tx failed post-process validation: ${reason}`) });
257
252
  continue;
258
253
  } else {
259
- this.log.trace(`Tx ${tx.getTxHash().toString()} is valid post processing.`);
254
+ this.log.trace(`Tx ${(await tx.getTxHash()).toString()} is valid post processing.`);
260
255
  }
261
256
  }
262
257
 
@@ -286,7 +281,7 @@ export class PublicProcessor implements Traceable {
286
281
  const rate = duration > 0 ? totalPublicGas.l2Gas / duration : 0;
287
282
  this.metrics.recordAllTxs(totalPublicGas, rate);
288
283
 
289
- this.log.info(`Processed ${result.length} succesful txs and ${failed.length} txs in ${duration}ms`, {
284
+ this.log.info(`Processed ${result.length} successful txs and ${failed.length} txs in ${duration}s`, {
290
285
  duration,
291
286
  rate,
292
287
  totalPublicGas,
@@ -297,7 +292,7 @@ export class PublicProcessor implements Traceable {
297
292
  return [result, failed, returns];
298
293
  }
299
294
 
300
- @trackSpan('PublicProcessor.processTx', tx => ({ [Attributes.TX_HASH]: tx.getTxHash().toString() }))
295
+ @trackSpan('PublicProcessor.processTx', async tx => ({ [Attributes.TX_HASH]: (await tx.getTxHash()).toString() }))
301
296
  private async processTx(tx: Tx, deadline?: Date): Promise<[ProcessedTx, NestedProcessReturnValues[]]> {
302
297
  const [time, [processedTx, returnValues]] = await elapsed(() => this.processTxWithinDeadline(tx, deadline));
303
298
 
@@ -315,7 +310,7 @@ export class PublicProcessor implements Traceable {
315
310
  nullifierCount: processedTx.txEffect.nullifiers.length,
316
311
  noteHashCount: processedTx.txEffect.noteHashes.length,
317
312
  contractClassLogCount: processedTx.txEffect.contractClassLogs.getTotalLogCount(),
318
- unencryptedLogCount: processedTx.txEffect.unencryptedLogs.getTotalLogCount(),
313
+ publicLogCount: processedTx.txEffect.publicLogs.length,
319
314
  privateLogCount: processedTx.txEffect.privateLogs.length,
320
315
  l2ToL1MessageCount: processedTx.txEffect.l2ToL1Msgs.length,
321
316
  durationMs: time,
@@ -378,17 +373,18 @@ export class PublicProcessor implements Traceable {
378
373
  return await processFn();
379
374
  }
380
375
 
376
+ const txHash = await tx.getTxHash();
381
377
  const timeout = +deadline - this.dateProvider.now();
382
- this.log.debug(`Processing tx ${tx.getTxHash().toString()} within ${timeout}ms`, {
378
+ if (timeout <= 0) {
379
+ throw new PublicProcessorTimeoutError();
380
+ }
381
+
382
+ this.log.debug(`Processing tx ${txHash.toString()} within ${timeout}ms`, {
383
383
  deadline: deadline.toISOString(),
384
384
  now: new Date(this.dateProvider.now()).toISOString(),
385
- txHash: tx.getTxHash().toString(),
385
+ txHash,
386
386
  });
387
387
 
388
- if (timeout < 0) {
389
- throw new PublicProcessorTimeoutError();
390
- }
391
-
392
388
  return await executeTimeout(
393
389
  () => processFn(),
394
390
  timeout,
@@ -408,8 +404,8 @@ export class PublicProcessor implements Traceable {
408
404
  }
409
405
 
410
406
  const feeJuiceAddress = ProtocolContractAddress.FeeJuice;
411
- const balanceSlot = computeFeePayerBalanceStorageSlot(feePayer);
412
- const leafSlot = computeFeePayerBalanceLeafSlot(feePayer);
407
+ const balanceSlot = await computeFeePayerBalanceStorageSlot(feePayer);
408
+ const leafSlot = await computeFeePayerBalanceLeafSlot(feePayer);
413
409
 
414
410
  this.log.debug(`Deducting ${txFee.toBigInt()} balance in Fee Juice for ${feePayer}`);
415
411
 
@@ -427,8 +423,8 @@ export class PublicProcessor implements Traceable {
427
423
  return new PublicDataWrite(leafSlot, updatedBalance);
428
424
  }
429
425
 
430
- @trackSpan('PublicProcessor.processPrivateOnlyTx', (tx: Tx) => ({
431
- [Attributes.TX_HASH]: tx.getTxHash().toString(),
426
+ @trackSpan('PublicProcessor.processPrivateOnlyTx', async (tx: Tx) => ({
427
+ [Attributes.TX_HASH]: (await tx.getTxHash()).toString(),
432
428
  }))
433
429
  private async processPrivateOnlyTx(tx: Tx): Promise<[ProcessedTx, undefined]> {
434
430
  const gasFees = this.globalVariables.gasFees;
@@ -436,7 +432,7 @@ export class PublicProcessor implements Traceable {
436
432
 
437
433
  const feePaymentPublicDataWrite = await this.getFeePaymentPublicDataWrite(transactionFee, tx.data.feePayer);
438
434
 
439
- const processedTx = makeProcessedTxFromPrivateOnlyTx(
435
+ const processedTx = await makeProcessedTxFromPrivateOnlyTx(
440
436
  tx,
441
437
  transactionFee,
442
438
  feePaymentPublicDataWrite,
@@ -452,8 +448,8 @@ export class PublicProcessor implements Traceable {
452
448
  return [processedTx, undefined];
453
449
  }
454
450
 
455
- @trackSpan('PublicProcessor.processTxWithPublicCalls', tx => ({
456
- [Attributes.TX_HASH]: tx.getTxHash().toString(),
451
+ @trackSpan('PublicProcessor.processTxWithPublicCalls', async tx => ({
452
+ [Attributes.TX_HASH]: (await tx.getTxHash()).toString(),
457
453
  }))
458
454
  private async processTxWithPublicCalls(tx: Tx): Promise<[ProcessedTx, NestedProcessReturnValues[]]> {
459
455
  const timer = new Timer();
@@ -485,7 +481,13 @@ export class PublicProcessor implements Traceable {
485
481
  const durationMs = timer.ms();
486
482
  this.metrics.recordTx(phaseCount, durationMs, gasUsed.publicGas);
487
483
 
488
- const processedTx = makeProcessedTxFromTxWithPublicCalls(tx, avmProvingRequest, gasUsed, revertCode, revertReason);
484
+ const processedTx = await makeProcessedTxFromTxWithPublicCalls(
485
+ tx,
486
+ avmProvingRequest,
487
+ gasUsed,
488
+ revertCode,
489
+ revertReason,
490
+ );
489
491
 
490
492
  const returnValues = processedPhases.find(({ phase }) => phase === TxExecutionPhase.APP_LOGIC)?.returnValues ?? [];
491
493
 
@@ -18,26 +18,32 @@ import {
18
18
  type GasSettings,
19
19
  type GlobalVariables,
20
20
  MAX_L2_GAS_PER_TX_PUBLIC_PORTION,
21
+ MAX_L2_TO_L1_MSGS_PER_TX,
21
22
  MAX_NOTE_HASHES_PER_TX,
22
23
  MAX_NULLIFIERS_PER_TX,
24
+ MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
25
+ PrivateToAvmAccumulatedData,
26
+ PrivateToAvmAccumulatedDataArrayLengths,
23
27
  type PrivateToPublicAccumulatedData,
24
- type PublicCallRequest,
25
- PublicCircuitPublicInputs,
28
+ PublicCallRequest,
29
+ PublicDataWrite,
26
30
  RevertCode,
27
31
  type StateReference,
28
32
  TreeSnapshots,
29
33
  computeTransactionFee,
30
34
  countAccumulatedItems,
35
+ mergeAccumulatedData,
31
36
  } from '@aztec/circuits.js';
37
+ import { padArrayEnd } from '@aztec/foundation/collection';
32
38
  import { type Logger, createLogger } from '@aztec/foundation/log';
39
+ import { assertLength } from '@aztec/foundation/serialize';
33
40
 
34
41
  import { strict as assert } from 'assert';
35
42
  import { inspect } from 'util';
36
43
 
37
44
  import { AvmPersistableStateManager } from '../avm/index.js';
38
- import { PublicEnqueuedCallSideEffectTrace, SideEffectArrayLengths } from './enqueued_call_side_effect_trace.js';
39
45
  import { type WorldStateDB } from './public_db_sources.js';
40
- import { generateAvmCircuitPublicInputs } from './transitional_adapters.js';
46
+ import { SideEffectArrayLengths, SideEffectTrace } from './side_effect_trace.js';
41
47
  import { getCallRequestsByPhase, getExecutionRequestsByPhase } from './utils.js';
42
48
 
43
49
  /**
@@ -77,7 +83,7 @@ export class PublicTxContext {
77
83
  public readonly nonRevertibleAccumulatedDataFromPrivate: PrivateToPublicAccumulatedData,
78
84
  public readonly revertibleAccumulatedDataFromPrivate: PrivateToPublicAccumulatedData,
79
85
  public readonly feePayer: AztecAddress,
80
- public trace: PublicEnqueuedCallSideEffectTrace, // FIXME(dbanks12): should be private
86
+ public trace: SideEffectTrace, // FIXME(dbanks12): should be private
81
87
  ) {
82
88
  this.log = createLogger(`simulator:public_tx_context`);
83
89
  }
@@ -97,19 +103,17 @@ export class PublicTxContext {
97
103
  /*noteHashes*/ 0,
98
104
  /*nullifiers=*/ 0,
99
105
  countAccumulatedItems(nonRevertibleAccumulatedDataFromPrivate.l2ToL1Msgs),
100
- /*unencryptedLogsHashes*/ 0,
101
- );
102
- const enqueuedCallTrace = new PublicEnqueuedCallSideEffectTrace(
103
- /*startSideEffectCounter=*/ 0,
104
- previousAccumulatedDataArrayLengths,
106
+ /*publicLogs*/ 0,
105
107
  );
106
108
 
109
+ const trace = new SideEffectTrace(/*startSideEffectCounter=*/ 0, previousAccumulatedDataArrayLengths);
110
+
107
111
  const firstNullifier = nonRevertibleAccumulatedDataFromPrivate.nullifiers[0];
108
112
 
109
113
  // Transaction level state manager that will be forked for revertible phases.
110
114
  const txStateManager = await AvmPersistableStateManager.create(
111
115
  worldStateDB,
112
- enqueuedCallTrace,
116
+ trace,
113
117
  doMerkleOperations,
114
118
  firstNullifier,
115
119
  );
@@ -120,7 +124,7 @@ export class PublicTxContext {
120
124
  const gasAllocatedToPublic = applyMaxToAvailableGas(gasSettings.gasLimits.sub(gasUsedByPrivate));
121
125
 
122
126
  return new PublicTxContext(
123
- tx.getTxHash(),
127
+ await tx.getTxHash(),
124
128
  new PhaseStateManager(txStateManager),
125
129
  globalVariables,
126
130
  await db.getStateReference(),
@@ -136,7 +140,7 @@ export class PublicTxContext {
136
140
  tx.data.forPublic!.nonRevertibleAccumulatedData,
137
141
  tx.data.forPublic!.revertibleAccumulatedData,
138
142
  tx.data.feePayer,
139
- enqueuedCallTrace,
143
+ trace,
140
144
  );
141
145
  }
142
146
 
@@ -319,13 +323,14 @@ export class PublicTxContext {
319
323
  /**
320
324
  * Generate the public inputs for the AVM circuit.
321
325
  */
322
- private generateAvmCircuitPublicInputs(endStateReference: StateReference): AvmCircuitPublicInputs {
326
+ private async generateAvmCircuitPublicInputs(endStateReference: StateReference): Promise<AvmCircuitPublicInputs> {
323
327
  assert(this.halted, 'Can only get AvmCircuitPublicInputs after tx execution ends');
324
328
  const ephemeralTrees = this.state.getActiveStateManager().merkleTrees;
325
329
 
326
- const noteHashTree = ephemeralTrees.getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE);
327
- const nullifierTree = ephemeralTrees.getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE);
328
- const publicDataTree = ephemeralTrees.getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE);
330
+ const noteHashTree = await ephemeralTrees.getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE);
331
+ const nullifierTree = await ephemeralTrees.getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE);
332
+ const publicDataTree = await ephemeralTrees.getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE);
333
+
329
334
  // Pad the note hash and nullifier trees
330
335
  const paddedNoteHashTreeSize =
331
336
  this.startStateReference.partial.noteHashTree.nextAvailableLeafIndex + MAX_NOTE_HASHES_PER_TX;
@@ -352,38 +357,92 @@ export class PublicTxContext {
352
357
  publicDataTree,
353
358
  );
354
359
 
355
- return generateAvmCircuitPublicInputs(
356
- this.trace,
360
+ const startTreeSnapshots = new TreeSnapshots(
361
+ this.startStateReference.l1ToL2MessageTree,
362
+ this.startStateReference.partial.noteHashTree,
363
+ this.startStateReference.partial.nullifierTree,
364
+ this.startStateReference.partial.publicDataTree,
365
+ );
366
+
367
+ const avmCircuitPublicInputs = this.trace.toAvmCircuitPublicInputs(
357
368
  this.globalVariables,
358
- this.startStateReference,
369
+ startTreeSnapshots,
359
370
  /*startGasUsed=*/ this.gasUsedByPrivate,
360
371
  this.gasSettings,
361
372
  this.feePayer,
362
373
  this.setupCallRequests,
363
374
  this.appLogicCallRequests,
364
- this.teardownCallRequests,
365
- this.nonRevertibleAccumulatedDataFromPrivate,
366
- this.revertibleAccumulatedDataFromPrivate,
375
+ /*teardownCallRequest=*/ this.teardownCallRequests.length
376
+ ? this.teardownCallRequests[0]
377
+ : PublicCallRequest.empty(),
367
378
  endTreeSnapshots,
368
379
  /*endGasUsed=*/ this.getTotalGasUsed(),
369
- this.getTransactionFeeUnsafe(),
370
- this.revertCode,
380
+ /*transactionFee=*/ this.getTransactionFeeUnsafe(),
381
+ /*reverted=*/ !this.revertCode.isOK(),
382
+ );
383
+
384
+ const getArrayLengths = (from: PrivateToPublicAccumulatedData) =>
385
+ new PrivateToAvmAccumulatedDataArrayLengths(
386
+ countAccumulatedItems(from.noteHashes),
387
+ countAccumulatedItems(from.nullifiers),
388
+ countAccumulatedItems(from.l2ToL1Msgs),
389
+ );
390
+ const convertAccumulatedData = (from: PrivateToPublicAccumulatedData) =>
391
+ new PrivateToAvmAccumulatedData(from.noteHashes, from.nullifiers, from.l2ToL1Msgs);
392
+ // Temporary overrides as these entries aren't yet populated in trace
393
+ avmCircuitPublicInputs.previousNonRevertibleAccumulatedDataArrayLengths = getArrayLengths(
394
+ this.nonRevertibleAccumulatedDataFromPrivate,
395
+ );
396
+ avmCircuitPublicInputs.previousRevertibleAccumulatedDataArrayLengths = getArrayLengths(
397
+ this.revertibleAccumulatedDataFromPrivate,
398
+ );
399
+ avmCircuitPublicInputs.previousNonRevertibleAccumulatedData = convertAccumulatedData(
400
+ this.nonRevertibleAccumulatedDataFromPrivate,
401
+ );
402
+ avmCircuitPublicInputs.previousRevertibleAccumulatedData = convertAccumulatedData(
403
+ this.revertibleAccumulatedDataFromPrivate,
404
+ );
405
+
406
+ const msgsFromPrivate = this.revertCode.isOK()
407
+ ? mergeAccumulatedData(
408
+ avmCircuitPublicInputs.previousNonRevertibleAccumulatedData.l2ToL1Msgs,
409
+ avmCircuitPublicInputs.previousRevertibleAccumulatedData.l2ToL1Msgs,
410
+ )
411
+ : avmCircuitPublicInputs.previousNonRevertibleAccumulatedData.l2ToL1Msgs;
412
+ avmCircuitPublicInputs.accumulatedData.l2ToL1Msgs = assertLength(
413
+ mergeAccumulatedData(msgsFromPrivate, avmCircuitPublicInputs.accumulatedData.l2ToL1Msgs),
414
+ MAX_L2_TO_L1_MSGS_PER_TX,
415
+ );
416
+
417
+ // Maps slot to value. Maps in TS are iterable in insertion order, which is exactly what we want for
418
+ // squashing "to the left", where the first occurrence of a slot uses the value of the last write to it,
419
+ // and the rest occurrences are omitted
420
+ const squashedPublicDataWrites: Map<bigint, Fr> = new Map();
421
+ for (const publicDataWrite of avmCircuitPublicInputs.accumulatedData.publicDataWrites) {
422
+ squashedPublicDataWrites.set(publicDataWrite.leafSlot.toBigInt(), publicDataWrite.value);
423
+ }
424
+
425
+ avmCircuitPublicInputs.accumulatedData.publicDataWrites = padArrayEnd(
426
+ Array.from(squashedPublicDataWrites.entries()).map(([slot, value]) => new PublicDataWrite(new Fr(slot), value)),
427
+ PublicDataWrite.empty(),
428
+ MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
371
429
  );
430
+
431
+ return avmCircuitPublicInputs;
372
432
  }
373
433
 
374
434
  /**
375
435
  * Generate the proving request for the AVM circuit.
376
436
  */
377
- generateProvingRequest(endStateReference: StateReference): AvmProvingRequest {
437
+ async generateProvingRequest(endStateReference: StateReference): Promise<AvmProvingRequest> {
378
438
  const hints = this.trace.getAvmCircuitHints();
379
439
  return {
380
440
  type: ProvingRequestType.PUBLIC_VM,
381
441
  inputs: new AvmCircuitInputs(
382
442
  'public_dispatch',
383
443
  [],
384
- PublicCircuitPublicInputs.empty(),
385
444
  hints,
386
- this.generateAvmCircuitPublicInputs(endStateReference),
445
+ await this.generateAvmCircuitPublicInputs(endStateReference),
387
446
  ),
388
447
  };
389
448
  }
@@ -7,7 +7,6 @@ import {
7
7
  type SimulationError,
8
8
  type Tx,
9
9
  TxExecutionPhase,
10
- UnencryptedFunctionL2Logs,
11
10
  } from '@aztec/circuit-types';
12
11
  import { type AvmSimulationStats } from '@aztec/circuit-types/stats';
13
12
  import { type Fr, type Gas, type GlobalVariables, type PublicCallRequest, type RevertCode } from '@aztec/circuits.js';
@@ -71,7 +70,7 @@ export class PublicTxSimulator {
71
70
  * @returns The result of the transaction's public execution.
72
71
  */
73
72
  public async simulate(tx: Tx): Promise<PublicTxResult> {
74
- const txHash = tx.getTxHash();
73
+ const txHash = await tx.getTxHash();
75
74
  this.log.debug(`Simulating ${tx.enqueuedPublicFunctionCalls.length} public calls for tx ${txHash}`, { txHash });
76
75
 
77
76
  const context = await PublicTxContext.create(
@@ -120,8 +119,7 @@ export class PublicTxSimulator {
120
119
 
121
120
  const endStateReference = await this.db.getStateReference();
122
121
 
123
- const avmProvingRequest = context.generateProvingRequest(endStateReference);
124
- const avmCircuitPublicInputs = avmProvingRequest.inputs.output!;
122
+ const avmProvingRequest = await context.generateProvingRequest(endStateReference);
125
123
 
126
124
  const revertCode = context.getFinalRevertCode();
127
125
  if (!revertCode.isOK()) {
@@ -129,15 +127,10 @@ export class PublicTxSimulator {
129
127
  // if so, this is removing contracts deployed in private setup
130
128
  // You can't submit contracts in public, so this is only relevant for private-created side effects
131
129
  // FIXME: we shouldn't need to directly modify worldStateDb here!
132
- await this.worldStateDB.removeNewContracts(tx);
130
+ await this.worldStateDB.removeNewContracts(tx, true);
133
131
  // FIXME(dbanks12): should not be changing immutable tx
134
- tx.filterRevertedLogs(
135
- tx.data.forPublic!.nonRevertibleAccumulatedData,
136
- avmCircuitPublicInputs.accumulatedData.unencryptedLogsHashes,
137
- );
132
+ tx.filterRevertedLogs(tx.data.forPublic!.nonRevertibleAccumulatedData);
138
133
  }
139
- // FIXME(dbanks12): should not be changing immutable tx
140
- tx.unencryptedLogs.addFunctionLogs([new UnencryptedFunctionL2Logs(context.trace.getUnencryptedLogs())]);
141
134
 
142
135
  return {
143
136
  avmProvingRequest,
@@ -391,7 +384,7 @@ export class PublicTxSimulator {
391
384
  }
392
385
  for (const noteHash of context.nonRevertibleAccumulatedDataFromPrivate.noteHashes) {
393
386
  if (!noteHash.isEmpty()) {
394
- stateManager.writeUniqueNoteHash(noteHash);
387
+ await stateManager.writeUniqueNoteHash(noteHash);
395
388
  }
396
389
  }
397
390
  }
@@ -416,7 +409,7 @@ export class PublicTxSimulator {
416
409
  for (const noteHash of context.revertibleAccumulatedDataFromPrivate.noteHashes) {
417
410
  if (!noteHash.isEmpty()) {
418
411
  // Revertible note hashes from private are not hashed with nonce, since private can't know their final position, only we can.
419
- stateManager.writeSiloedNoteHash(noteHash);
412
+ await stateManager.writeSiloedNoteHash(noteHash);
420
413
  }
421
414
  }
422
415
  }
@@ -430,7 +423,7 @@ export class PublicTxSimulator {
430
423
  }
431
424
 
432
425
  const feeJuiceAddress = ProtocolContractAddress.FeeJuice;
433
- const balanceSlot = computeFeePayerBalanceStorageSlot(context.feePayer);
426
+ const balanceSlot = await computeFeePayerBalanceStorageSlot(context.feePayer);
434
427
 
435
428
  this.log.debug(`Deducting ${txFee.toBigInt()} balance in Fee Juice for ${context.feePayer}`);
436
429
  const stateManager = context.state.getActiveStateManager();