@aztec/simulator 0.0.1-commit.b1c78909e → 0.0.1-commit.b2a5d0dd1

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 (52) hide show
  1. package/dest/public/avm/avm_simulator.js +1 -1
  2. package/dest/public/avm/calldata.d.ts +1 -1
  3. package/dest/public/avm/calldata.d.ts.map +1 -1
  4. package/dest/public/avm/calldata.js +3 -2
  5. package/dest/public/contracts_db_checkpoint.d.ts +2 -2
  6. package/dest/public/contracts_db_checkpoint.d.ts.map +1 -1
  7. package/dest/public/contracts_db_checkpoint.js +1 -1
  8. package/dest/public/fixtures/bulk_test.d.ts +1 -1
  9. package/dest/public/fixtures/bulk_test.d.ts.map +1 -1
  10. package/dest/public/fixtures/bulk_test.js +4 -4
  11. package/dest/public/fixtures/public_tx_simulation_tester.d.ts +1 -1
  12. package/dest/public/fixtures/public_tx_simulation_tester.d.ts.map +1 -1
  13. package/dest/public/fixtures/public_tx_simulation_tester.js +3 -3
  14. package/dest/public/fixtures/utils.d.ts +1 -1
  15. package/dest/public/fixtures/utils.d.ts.map +1 -1
  16. package/dest/public/fixtures/utils.js +5 -5
  17. package/dest/public/hinting_db_sources.d.ts +4 -4
  18. package/dest/public/hinting_db_sources.d.ts.map +1 -1
  19. package/dest/public/hinting_db_sources.js +6 -5
  20. package/dest/public/public_db_sources.d.ts +3 -3
  21. package/dest/public/public_db_sources.d.ts.map +1 -1
  22. package/dest/public/public_db_sources.js +10 -10
  23. package/dest/public/public_processor/guarded_merkle_tree.d.ts +4 -4
  24. package/dest/public/public_processor/guarded_merkle_tree.d.ts.map +1 -1
  25. package/dest/public/public_processor/guarded_merkle_tree.js +4 -4
  26. package/dest/public/public_processor/public_processor.d.ts +1 -1
  27. package/dest/public/public_processor/public_processor.d.ts.map +1 -1
  28. package/dest/public/public_processor/public_processor.js +10 -12
  29. package/dest/public/public_tx_simulator/contract_provider_for_cpp.d.ts +1 -1
  30. package/dest/public/public_tx_simulator/contract_provider_for_cpp.d.ts.map +1 -1
  31. package/dest/public/public_tx_simulator/contract_provider_for_cpp.js +2 -1
  32. package/dest/public/public_tx_simulator/public_tx_context.d.ts +7 -3
  33. package/dest/public/public_tx_simulator/public_tx_context.d.ts.map +1 -1
  34. package/dest/public/public_tx_simulator/public_tx_context.js +8 -10
  35. package/dest/public/public_tx_simulator/public_tx_simulator.d.ts +6 -2
  36. package/dest/public/public_tx_simulator/public_tx_simulator.d.ts.map +1 -1
  37. package/dest/public/public_tx_simulator/public_tx_simulator.js +12 -7
  38. package/package.json +15 -16
  39. package/src/public/avm/avm_simulator.ts +1 -1
  40. package/src/public/avm/calldata.ts +3 -2
  41. package/src/public/avm/opcodes/external_calls.ts +1 -1
  42. package/src/public/contracts_db_checkpoint.ts +1 -1
  43. package/src/public/fixtures/bulk_test.ts +2 -4
  44. package/src/public/fixtures/public_tx_simulation_tester.ts +4 -9
  45. package/src/public/fixtures/utils.ts +12 -8
  46. package/src/public/hinting_db_sources.ts +8 -6
  47. package/src/public/public_db_sources.ts +12 -14
  48. package/src/public/public_processor/guarded_merkle_tree.ts +5 -5
  49. package/src/public/public_processor/public_processor.ts +11 -13
  50. package/src/public/public_tx_simulator/contract_provider_for_cpp.ts +2 -1
  51. package/src/public/public_tx_simulator/public_tx_context.ts +8 -10
  52. package/src/public/public_tx_simulator/public_tx_simulator.ts +11 -7
@@ -306,6 +306,9 @@ export class PublicProcessor implements Traceable {
306
306
  totalBlockGas = totalBlockGas.add(processedTx.gasUsed.totalGas);
307
307
  totalSizeInBytes += txSize;
308
308
  totalBlobFields += txBlobFields;
309
+
310
+ // Commit the tx-level contracts checkpoint on success
311
+ this.contractsDB.commitCheckpoint();
309
312
  } catch (err: any) {
310
313
  if (err?.name === 'PublicProcessorTimeoutError') {
311
314
  this.log.warn(`Stopping tx processing due to timeout.`);
@@ -325,14 +328,10 @@ export class PublicProcessor implements Traceable {
325
328
  // 1. At least one outstanding checkpoint that has not been committed (the one created before we processed the tx).
326
329
  // 2. Possible state updates on that checkpoint or any others created during execution.
327
330
 
328
- // First we revert a checkpoint as managed by the ForkCheckpoint. This will revert whatever is the current checkpoint
329
- // which may not be the one originally created by this object. But that is ok, we do this to fulfil the ForkCheckpoint
330
- // lifecycle expectations and ensure it doesn't attempt to commit later on.
331
- await checkpoint.revert();
332
-
333
- // Now we want to revert any/all remaining checkpoints, destroying any outstanding state updates.
334
- // This needs to be done directly on the underlying fork as the guarded fork has been stopped.
335
- await this.guardedMerkleTree.getUnderlyingFork().revertAllCheckpoints();
331
+ // Revert all checkpoints at or above this checkpoint's depth (inclusive), destroying any outstanding state
332
+ // updates from this tx and any nested checkpoints created during execution. This preserves any checkpoints
333
+ // created by callers below our depth.
334
+ await checkpoint.revertToCheckpoint();
336
335
 
337
336
  // Revert any contracts added to the DB for the tx.
338
337
  this.contractsDB.revertCheckpoint();
@@ -344,9 +343,9 @@ export class PublicProcessor implements Traceable {
344
343
  break;
345
344
  }
346
345
 
347
- // Roll back state to start of TX before proceeding to next TX
348
- await checkpoint.revert();
349
- await this.guardedMerkleTree.getUnderlyingFork().revertAllCheckpoints();
346
+ // Roll back state to start of TX before proceeding to next TX.
347
+ // Reverts all checkpoints at or above this checkpoint's depth, preserving any caller checkpoints below.
348
+ await checkpoint.revertToCheckpoint();
350
349
  this.contractsDB.revertCheckpoint();
351
350
  const errorMessage = err instanceof Error || err instanceof AssertionError ? err.message : 'Unknown error';
352
351
  this.log.warn(`Failed to process tx ${txHash.toString()}: ${errorMessage} ${err?.stack}`);
@@ -358,7 +357,6 @@ export class PublicProcessor implements Traceable {
358
357
  } finally {
359
358
  // Base case is we always commit the checkpoint. Using the ForkCheckpoint means this has no effect if the tx was previously reverted
360
359
  await checkpoint.commit();
361
- this.contractsDB.commitCheckpointOkIfNone();
362
360
  }
363
361
  }
364
362
 
@@ -550,7 +548,7 @@ export class PublicProcessor implements Traceable {
550
548
  // Fee payment insertion has already been done. Do the rest.
551
549
  await this.doTreeInsertionsForPrivateOnlyTx(processedTx);
552
550
 
553
- await this.contractsDB.addNewContracts(tx);
551
+ this.contractsDB.addNewContracts(tx);
554
552
 
555
553
  return [processedTx, undefined, []];
556
554
  }
@@ -52,6 +52,7 @@ export class ContractProviderForCpp implements ContractProvider {
52
52
  return serializeWithMessagePack(contractClass);
53
53
  };
54
54
 
55
+ // eslint-disable-next-line require-await
55
56
  public addContracts = async (contractDeploymentDataBuffer: Buffer): Promise<void> => {
56
57
  this.log.trace(`Contract provider callback: addContracts`);
57
58
 
@@ -62,7 +63,7 @@ export class ContractProviderForCpp implements ContractProvider {
62
63
 
63
64
  // Add contracts to the contracts DB
64
65
  this.log.trace(`Calling contractsDB.addContracts`);
65
- await this.contractsDB.addContracts(contractDeploymentData);
66
+ this.contractsDB.addContracts(contractDeploymentData);
66
67
  };
67
68
 
68
69
  public getBytecodeCommitment = async (classId: string): Promise<Buffer | undefined> => {
@@ -174,14 +174,8 @@ export class PublicTxContext {
174
174
  }
175
175
  if (phase === TxExecutionPhase.SETUP) {
176
176
  this.log.warn(`Setup phase reverted! The transaction will be thrown out.`);
177
- } else if (phase === TxExecutionPhase.APP_LOGIC) {
178
- this.revertCode = RevertCode.APP_LOGIC_REVERTED;
179
- } else if (phase === TxExecutionPhase.TEARDOWN) {
180
- if (this.revertCode.equals(RevertCode.APP_LOGIC_REVERTED)) {
181
- this.revertCode = RevertCode.BOTH_REVERTED;
182
- } else {
183
- this.revertCode = RevertCode.TEARDOWN_REVERTED;
184
- }
177
+ } else if (phase === TxExecutionPhase.APP_LOGIC || phase === TxExecutionPhase.TEARDOWN) {
178
+ this.revertCode = RevertCode.REVERTED;
185
179
  }
186
180
  }
187
181
 
@@ -247,8 +241,12 @@ export class PublicTxContext {
247
241
  }
248
242
 
249
243
  /**
250
- * The gasUsed by public and private,
251
- * as if the entire teardown gas limit was consumed.
244
+ * The gasUsed by public and private, as if the entire teardown gas limit was consumed.
245
+ *
246
+ * This is intentional: teardown is used for gas accounting and refunds, so the transaction
247
+ * fee must be deterministic _before_ teardown executes. If fees depended on teardown's actual
248
+ * consumption there would be a circular dependency. Billing the full teardown gas limit
249
+ * (set by the user) makes the fee known in advance and available to the teardown function.
252
250
  */
253
251
  getTotalGasUsed(): Gas {
254
252
  return this.gasUsedByPrivate.add(this.gasUsedByPublic);
@@ -27,7 +27,6 @@ import { type PublicContractsDB, PublicTreesDB } from '../public_db_sources.js';
27
27
  import {
28
28
  L2ToL1MessageLimitReachedError,
29
29
  NoteHashLimitReachedError,
30
- NullifierCollisionError,
31
30
  NullifierLimitReachedError,
32
31
  } from '../side_effect_errors.js';
33
32
  import type { PublicPersistableStateManager } from '../state_manager/state_manager.js';
@@ -147,7 +146,8 @@ export class PublicTxSimulator implements PublicTxSimulatorInterface {
147
146
  hintingContractsDB.createCheckpoint();
148
147
 
149
148
  try {
150
- // This will throw if there is a nullifier collision or other insertion error (limit reached).
149
+ // This may throw: a side-effect limit error triggers a soft revert (caught below), while a
150
+ // nullifier collision is unrecoverable and propagates out of simulate() to throw out the tx.
151
151
  await this.insertRevertiblesFromPrivate(context);
152
152
 
153
153
  // Only proceed with app logic if there was no revert during revertible insertion.
@@ -401,7 +401,7 @@ export class PublicTxSimulator implements PublicTxSimulatorInterface {
401
401
  // However, things work as expected because later calls to getters on the hintingContractsDB
402
402
  // will pick up the new contracts and will generate the necessary hints.
403
403
  // So, a consumer of the hints will always see the new contracts.
404
- await this.contractsDB.addContracts(context.nonRevertibleContractDeploymentData);
404
+ this.contractsDB.addContracts(context.nonRevertibleContractDeploymentData);
405
405
  }
406
406
 
407
407
  /**
@@ -409,9 +409,13 @@ export class PublicTxSimulator implements PublicTxSimulatorInterface {
409
409
  * Throws TxSimRevertibleInsertionsRevert if there is some checked error during revertible insertions.
410
410
  * This function checks for the following errors:
411
411
  * - NullifierLimitReachedError
412
- * - NullifierCollisionError
413
412
  * - NoteHashLimitReachedError
414
413
  * - L2ToL1MessageLimitReachedError
414
+ *
415
+ * Note: NullifierCollisionError is intentionally NOT caught here. A nullifier collision
416
+ * during revertible insertions is unprovable (the nullifier originated from private, so
417
+ * a collision indicates the tx should never have been proposed). It propagates as-is to
418
+ * make the transaction unrecoverable, matching the AVM circuit behavior.
415
419
  */
416
420
  protected async insertRevertiblesFromPrivate(context: PublicTxContext) {
417
421
  const stateManager = context.state.getActiveStateManager();
@@ -421,7 +425,7 @@ export class PublicTxSimulator implements PublicTxSimulatorInterface {
421
425
  await stateManager.writeSiloedNullifier(siloedNullifier);
422
426
  }
423
427
  } catch (e: any) {
424
- if (e instanceof NullifierLimitReachedError || e instanceof NullifierCollisionError) {
428
+ if (e instanceof NullifierLimitReachedError) {
425
429
  context.revert(
426
430
  TxExecutionPhase.APP_LOGIC,
427
431
  new SimulationError(
@@ -431,7 +435,7 @@ export class PublicTxSimulator implements PublicTxSimulatorInterface {
431
435
  );
432
436
  throw new TxSimRevertibleInsertionsRevert();
433
437
  } else {
434
- // Unchecked/unknown error - re-throw as-is
438
+ // Unchecked/unknown error or NullifierCollisionError (unrecoverable) - re-throw as-is
435
439
  throw e;
436
440
  }
437
441
  }
@@ -486,7 +490,7 @@ export class PublicTxSimulator implements PublicTxSimulatorInterface {
486
490
  // However, things work as expected because later calls to getters on the hintingContractsDB
487
491
  // will pick up the new contracts and will generate the necessary hints.
488
492
  // So, a consumer of the hints will always see the new contracts.
489
- await this.contractsDB.addContracts(context.revertibleContractDeploymentData);
493
+ this.contractsDB.addContracts(context.revertibleContractDeploymentData);
490
494
  }
491
495
 
492
496
  private async payFee(context: PublicTxContext) {