@aztec/simulator 0.40.1 → 0.41.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 (122) hide show
  1. package/dest/acvm/oracle/oracle.d.ts +4 -2
  2. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  3. package/dest/acvm/oracle/oracle.js +21 -18
  4. package/dest/acvm/oracle/typed_oracle.d.ts +6 -11
  5. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  6. package/dest/acvm/oracle/typed_oracle.js +11 -5
  7. package/dest/avm/avm_execution_environment.d.ts +4 -3
  8. package/dest/avm/avm_execution_environment.d.ts.map +1 -1
  9. package/dest/avm/avm_execution_environment.js +7 -5
  10. package/dest/avm/avm_simulator.d.ts.map +1 -1
  11. package/dest/avm/avm_simulator.js +5 -4
  12. package/dest/avm/errors.d.ts +6 -0
  13. package/dest/avm/errors.d.ts.map +1 -1
  14. package/dest/avm/errors.js +10 -1
  15. package/dest/avm/fixtures/index.js +3 -3
  16. package/dest/avm/journal/journal.d.ts +2 -3
  17. package/dest/avm/journal/journal.d.ts.map +1 -1
  18. package/dest/avm/journal/journal.js +6 -11
  19. package/dest/avm/journal/nullifiers.d.ts +17 -5
  20. package/dest/avm/journal/nullifiers.d.ts.map +1 -1
  21. package/dest/avm/journal/nullifiers.js +27 -10
  22. package/dest/avm/journal/public_storage.d.ts +19 -6
  23. package/dest/avm/journal/public_storage.d.ts.map +1 -1
  24. package/dest/avm/journal/public_storage.js +30 -12
  25. package/dest/avm/opcodes/accrued_substate.d.ts.map +1 -1
  26. package/dest/avm/opcodes/accrued_substate.js +6 -7
  27. package/dest/avm/opcodes/external_calls.d.ts +2 -2
  28. package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
  29. package/dest/avm/opcodes/external_calls.js +22 -11
  30. package/dest/avm/opcodes/storage.d.ts +0 -7
  31. package/dest/avm/opcodes/storage.d.ts.map +1 -1
  32. package/dest/avm/opcodes/storage.js +3 -12
  33. package/dest/client/client_execution_context.d.ts +35 -17
  34. package/dest/client/client_execution_context.d.ts.map +1 -1
  35. package/dest/client/client_execution_context.js +70 -33
  36. package/dest/client/db_oracle.d.ts +10 -11
  37. package/dest/client/db_oracle.d.ts.map +1 -1
  38. package/dest/client/execution_note_cache.d.ts +17 -0
  39. package/dest/client/execution_note_cache.d.ts.map +1 -1
  40. package/dest/client/execution_note_cache.js +25 -2
  41. package/dest/client/execution_result.d.ts +11 -0
  42. package/dest/client/execution_result.d.ts.map +1 -1
  43. package/dest/client/execution_result.js +21 -3
  44. package/dest/client/private_execution.d.ts.map +1 -1
  45. package/dest/client/private_execution.js +4 -1
  46. package/dest/client/simulator.d.ts.map +1 -1
  47. package/dest/client/simulator.js +6 -6
  48. package/dest/client/view_data_oracle.d.ts +10 -10
  49. package/dest/client/view_data_oracle.d.ts.map +1 -1
  50. package/dest/client/view_data_oracle.js +11 -11
  51. package/dest/common/index.d.ts +1 -0
  52. package/dest/common/index.d.ts.map +1 -1
  53. package/dest/common/index.js +2 -1
  54. package/dest/common/return_values.d.ts +11 -0
  55. package/dest/common/return_values.d.ts.map +1 -0
  56. package/dest/common/return_values.js +13 -0
  57. package/dest/mocks/fixtures.d.ts +2 -1
  58. package/dest/mocks/fixtures.d.ts.map +1 -1
  59. package/dest/mocks/fixtures.js +2 -3
  60. package/dest/public/abstract_phase_manager.d.ts +3 -3
  61. package/dest/public/abstract_phase_manager.d.ts.map +1 -1
  62. package/dest/public/abstract_phase_manager.js +17 -10
  63. package/dest/public/app_logic_phase_manager.d.ts +1 -1
  64. package/dest/public/execution.d.ts +2 -6
  65. package/dest/public/execution.d.ts.map +1 -1
  66. package/dest/public/execution.js +1 -1
  67. package/dest/public/executor.d.ts.map +1 -1
  68. package/dest/public/executor.js +11 -8
  69. package/dest/public/hints_builder.d.ts +2 -2
  70. package/dest/public/hints_builder.d.ts.map +1 -1
  71. package/dest/public/hints_builder.js +4 -4
  72. package/dest/public/public_processor.d.ts +2 -2
  73. package/dest/public/public_processor.d.ts.map +1 -1
  74. package/dest/public/public_processor.js +5 -5
  75. package/dest/public/setup_phase_manager.d.ts +1 -1
  76. package/dest/public/setup_phase_manager.js +2 -2
  77. package/dest/public/tail_phase_manager.d.ts +1 -1
  78. package/dest/public/tail_phase_manager.d.ts.map +1 -1
  79. package/dest/public/tail_phase_manager.js +4 -4
  80. package/dest/public/teardown_phase_manager.d.ts +1 -1
  81. package/dest/public/teardown_phase_manager.js +2 -2
  82. package/dest/public/transitional_adaptors.d.ts +2 -1
  83. package/dest/public/transitional_adaptors.d.ts.map +1 -1
  84. package/dest/public/transitional_adaptors.js +17 -3
  85. package/dest/public/utils.js +3 -3
  86. package/package.json +8 -8
  87. package/src/acvm/oracle/oracle.ts +26 -23
  88. package/src/acvm/oracle/typed_oracle.ts +15 -15
  89. package/src/avm/avm_execution_environment.ts +9 -5
  90. package/src/avm/avm_simulator.ts +5 -3
  91. package/src/avm/errors.ts +10 -0
  92. package/src/avm/fixtures/index.ts +2 -2
  93. package/src/avm/journal/journal.ts +10 -14
  94. package/src/avm/journal/nullifiers.ts +27 -14
  95. package/src/avm/journal/public_storage.ts +30 -16
  96. package/src/avm/opcodes/accrued_substate.ts +5 -6
  97. package/src/avm/opcodes/external_calls.ts +23 -9
  98. package/src/avm/opcodes/storage.ts +2 -12
  99. package/src/client/client_execution_context.ts +75 -37
  100. package/src/client/db_oracle.ts +10 -11
  101. package/src/client/execution_note_cache.ts +29 -1
  102. package/src/client/execution_result.ts +26 -2
  103. package/src/client/private_execution.ts +3 -0
  104. package/src/client/simulator.ts +4 -5
  105. package/src/client/view_data_oracle.ts +12 -12
  106. package/src/common/index.ts +1 -0
  107. package/src/common/return_values.ts +18 -0
  108. package/src/mocks/fixtures.ts +2 -2
  109. package/src/public/abstract_phase_manager.ts +21 -15
  110. package/src/public/execution.ts +2 -6
  111. package/src/public/executor.ts +14 -7
  112. package/src/public/hints_builder.ts +11 -3
  113. package/src/public/public_processor.ts +7 -7
  114. package/src/public/setup_phase_manager.ts +1 -1
  115. package/src/public/tail_phase_manager.ts +5 -7
  116. package/src/public/teardown_phase_manager.ts +1 -1
  117. package/src/public/transitional_adaptors.ts +17 -2
  118. package/src/public/utils.ts +2 -2
  119. package/dest/client/logs_cache.d.ts +0 -33
  120. package/dest/client/logs_cache.d.ts.map +0 -1
  121. package/dest/client/logs_cache.js +0 -59
  122. package/src/client/logs_cache.ts +0 -65
@@ -6,10 +6,10 @@ import {
6
6
  ContractStorageUpdateRequest,
7
7
  EthAddress,
8
8
  L2ToL1Message,
9
+ LogHash,
9
10
  NoteHash,
10
11
  Nullifier,
11
12
  ReadRequest,
12
- SideEffect,
13
13
  } from '@aztec/circuits.js';
14
14
  import { EventSelector } from '@aztec/foundation/abi';
15
15
  import { Fr } from '@aztec/foundation/fields';
@@ -64,9 +64,8 @@ type PartialPublicExecutionResult = {
64
64
  newNullifiers: Nullifier[];
65
65
  contractStorageReads: ContractStorageRead[];
66
66
  contractStorageUpdateRequests: ContractStorageUpdateRequest[];
67
- unencryptedLogsHashes: SideEffect[];
67
+ unencryptedLogsHashes: LogHash[];
68
68
  unencryptedLogs: UnencryptedL2Log[];
69
- unencryptedLogPreimagesLength: Fr;
70
69
  allUnencryptedLogs: UnencryptedL2Log[];
71
70
  nestedExecutions: PublicExecutionResult[];
72
71
  };
@@ -119,8 +118,6 @@ export class AvmPersistableStateManager {
119
118
  contractStorageUpdateRequests: [],
120
119
  unencryptedLogsHashes: [],
121
120
  unencryptedLogs: [],
122
- // The length starts at 4 because it will always include the size.
123
- unencryptedLogPreimagesLength: new Fr(4),
124
121
  allUnencryptedLogs: [],
125
122
  nestedExecutions: [],
126
123
  };
@@ -141,7 +138,7 @@ export class AvmPersistableStateManager {
141
138
  * @param value - the value being written to the slot
142
139
  */
143
140
  public writeStorage(storageAddress: Fr, slot: Fr, value: Fr) {
144
- this.log.debug(`storage(${storageAddress})@${slot} <- ${value}`);
141
+ this.log.debug(`Storage write (address=${storageAddress}, slot=${slot}): value=${value}`);
145
142
  // Cache storage writes for later reference/reads
146
143
  this.publicStorage.write(storageAddress, slot, value);
147
144
 
@@ -172,7 +169,9 @@ export class AvmPersistableStateManager {
172
169
  */
173
170
  public async readStorage(storageAddress: Fr, slot: Fr): Promise<Fr> {
174
171
  const { value, exists, cached } = await this.publicStorage.read(storageAddress, slot);
175
- this.log.debug(`storage(${storageAddress})@${slot} ?? value: ${value}, exists: ${exists}, cached: ${cached}.`);
172
+ this.log.debug(
173
+ `Storage read (address=${storageAddress}, slot=${slot}): value=${value}, exists=${exists}, cached=${cached}`,
174
+ );
176
175
 
177
176
  // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
178
177
  // The current info to the kernel kernel does not consider cached reads.
@@ -253,7 +252,9 @@ export class AvmPersistableStateManager {
253
252
  */
254
253
  public async writeNullifier(storageAddress: Fr, nullifier: Fr) {
255
254
  // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
256
- this.transitionalExecutionResult.newNullifiers.push(new Nullifier(nullifier, this.trace.accessCounter, Fr.ZERO));
255
+ this.transitionalExecutionResult.newNullifiers.push(
256
+ new Nullifier(nullifier, this.trace.accessCounter, /*noteHash=*/ Fr.ZERO),
257
+ );
257
258
 
258
259
  this.log.debug(`nullifiers(${storageAddress}) += ${nullifier}.`);
259
260
  // Cache pending nullifiers for later access
@@ -307,12 +308,7 @@ export class AvmPersistableStateManager {
307
308
  this.transitionalExecutionResult.allUnencryptedLogs.push(ulog);
308
309
  // this duplicates exactly what happens in the trace just for the purpose of transitional integration with the kernel
309
310
  this.transitionalExecutionResult.unencryptedLogsHashes.push(
310
- new SideEffect(logHash, new Fr(this.trace.accessCounter)),
311
- );
312
- // Duplicates computation performed in public_context.nr::emit_unencrypted_log
313
- // 44 = addr (32) + selector (4) + raw log len (4) + processed log len (4).
314
- this.transitionalExecutionResult.unencryptedLogPreimagesLength = new Fr(
315
- this.transitionalExecutionResult.unencryptedLogPreimagesLength.toNumber() + 44 + log.length * Fr.SIZE_IN_BYTES,
311
+ new LogHash(logHash, this.trace.accessCounter, new Fr(ulog.length)),
316
312
  );
317
313
  // TODO(6206): likely need to track this here and not just in the transitional logic.
318
314
 
@@ -12,21 +12,38 @@ import type { CommitmentsDB } from '../../index.js';
12
12
  export class Nullifiers {
13
13
  /** Cached nullifiers. */
14
14
  public cache: NullifierCache;
15
- /** Parent's nullifier cache. Checked on cache-miss. */
16
- private readonly parentCache: NullifierCache | undefined;
17
- /** Reference to node storage. Checked on parent cache-miss. */
18
- private readonly hostNullifiers: CommitmentsDB;
19
15
 
20
- constructor(hostNullifiers: CommitmentsDB, parent?: Nullifiers) {
21
- this.hostNullifiers = hostNullifiers;
22
- this.parentCache = parent?.cache;
16
+ constructor(
17
+ /** Reference to node storage. Checked on parent cache-miss. */
18
+ private readonly hostNullifiers: CommitmentsDB,
19
+ /** Parent's nullifiers. Checked on this' cache-miss. */
20
+ private readonly parent?: Nullifiers | undefined,
21
+ ) {
23
22
  this.cache = new NullifierCache();
24
23
  }
25
24
 
25
+ /**
26
+ * Get a nullifier's existence in this' cache or parent's (recursively).
27
+ * DOES NOT CHECK HOST STORAGE!
28
+ * @param storageAddress - the address of the contract whose storage is being read from
29
+ * @param nullifier - the nullifier to check for
30
+ * @returns exists: whether the nullifier exists in cache here or in parent's
31
+ */
32
+ private checkExistsHereOrParent(storageAddress: Fr, nullifier: Fr): boolean {
33
+ // First check this cache
34
+ let existsAsPending = this.cache.exists(storageAddress, nullifier);
35
+ // Then try parent's nullifier cache
36
+ if (!existsAsPending && this.parent) {
37
+ // Note: this will recurse to grandparent/etc until a cache-hit is encountered.
38
+ existsAsPending = this.parent.checkExistsHereOrParent(storageAddress, nullifier);
39
+ }
40
+ return existsAsPending;
41
+ }
42
+
26
43
  /**
27
44
  * Get a nullifier's existence status.
28
45
  * 1. Check cache.
29
- * 2. Check parent's cache.
46
+ * 2. Check parent cache.
30
47
  * 3. Fall back to the host state.
31
48
  * 4. Not found! Nullifier does not exist.
32
49
  *
@@ -40,12 +57,8 @@ export class Nullifiers {
40
57
  storageAddress: Fr,
41
58
  nullifier: Fr,
42
59
  ): Promise<[/*exists=*/ boolean, /*isPending=*/ boolean, /*leafIndex=*/ Fr]> {
43
- // First check this cache
44
- let existsAsPending = this.cache.exists(storageAddress, nullifier);
45
- // Then check parent's cache
46
- if (!existsAsPending && this.parentCache) {
47
- existsAsPending = this.parentCache?.exists(storageAddress, nullifier);
48
- }
60
+ // Check this cache and parent's (recursively)
61
+ const existsAsPending = this.checkExistsHereOrParent(storageAddress, nullifier);
49
62
  // Finally try the host's Aztec state (a trip to the database)
50
63
  // If the value is found in the database, it will be associated with a leaf index!
51
64
  let leafIndex: bigint | undefined = undefined;
@@ -17,14 +17,13 @@ type PublicStorageReadResult = {
17
17
  export class PublicStorage {
18
18
  /** Cached storage writes. */
19
19
  private cache: PublicStorageCache;
20
- /** Parent's storage cache. Checked on cache-miss. */
21
- private readonly parentCache: PublicStorageCache | undefined;
22
- /** Reference to node storage. Checked on parent cache-miss. */
23
- private readonly hostPublicStorage: PublicStateDB;
24
20
 
25
- constructor(hostPublicStorage: PublicStateDB, parent?: PublicStorage) {
26
- this.hostPublicStorage = hostPublicStorage;
27
- this.parentCache = parent?.cache;
21
+ constructor(
22
+ /** Reference to node storage. Checked on parent cache-miss. */
23
+ private readonly hostPublicStorage: PublicStateDB,
24
+ /** Parent's storage. Checked on this' cache-miss. */
25
+ private readonly parent?: PublicStorage,
26
+ ) {
28
27
  this.cache = new PublicStorageCache();
29
28
  }
30
29
 
@@ -35,10 +34,29 @@ export class PublicStorage {
35
34
  return this.cache;
36
35
  }
37
36
 
37
+ /**
38
+ * Read a storage value from this' cache or parent's (recursively).
39
+ * DOES NOT CHECK HOST STORAGE!
40
+ *
41
+ * @param storageAddress - the address of the contract whose storage is being read from
42
+ * @param slot - the slot in the contract's storage being read from
43
+ * @returns value: the latest value written according to this cache or the parent's. undefined on cache miss.
44
+ */
45
+ public readHereOrParent(storageAddress: Fr, slot: Fr): Fr | undefined {
46
+ // First try check this storage cache
47
+ let value = this.cache.read(storageAddress, slot);
48
+ // Then try parent's storage cache
49
+ if (!value && this.parent) {
50
+ // Note: this will recurse to grandparent/etc until a cache-hit is encountered.
51
+ value = this.parent.readHereOrParent(storageAddress, slot);
52
+ }
53
+ return value;
54
+ }
55
+
38
56
  /**
39
57
  * Read a value from storage.
40
58
  * 1. Check cache.
41
- * 2. Check parent's cache.
59
+ * 2. Check parent cache.
42
60
  * 3. Fall back to the host state.
43
61
  * 4. Not found! Value has never been written to before. Flag it as non-existent and return value zero.
44
62
  *
@@ -48,12 +66,8 @@ export class PublicStorage {
48
66
  */
49
67
  public async read(storageAddress: Fr, slot: Fr): Promise<PublicStorageReadResult> {
50
68
  let cached = false;
51
- // First try check this storage cache
52
- let value = this.cache.read(storageAddress, slot);
53
- // Then try parent's storage cache (if it exists / written to earlier in this TX)
54
- if (!value && this.parentCache) {
55
- value = this.parentCache?.read(storageAddress, slot);
56
- }
69
+ // Check this cache and parent's (recursively)
70
+ let value = this.readHereOrParent(storageAddress, slot);
57
71
  // Finally try the host's Aztec state (a trip to the database)
58
72
  if (!value) {
59
73
  value = await this.hostPublicStorage.storageRead(storageAddress, slot);
@@ -73,8 +87,8 @@ export class PublicStorage {
73
87
  * @param slot - the slot in the contract's storage being written to
74
88
  * @param value - the value being written to the slot
75
89
  */
76
- public write(storageAddress: Fr, key: Fr, value: Fr) {
77
- this.cache.write(storageAddress, key, value);
90
+ public write(storageAddress: Fr, slot: Fr, value: Fr) {
91
+ this.cache.write(storageAddress, slot, value);
78
92
  }
79
93
 
80
94
  /**
@@ -1,11 +1,10 @@
1
1
  import type { AvmContext } from '../avm_context.js';
2
2
  import { Uint8 } from '../avm_memory_types.js';
3
- import { InstructionExecutionError } from '../errors.js';
3
+ import { InstructionExecutionError, StaticCallAlterationError } from '../errors.js';
4
4
  import { NullifierCollisionError } from '../journal/nullifiers.js';
5
5
  import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
6
6
  import { Addressing } from './addressing_mode.js';
7
7
  import { Instruction } from './instruction.js';
8
- import { StaticCallStorageAlterError } from './storage.js';
9
8
 
10
9
  export class NoteHashExists extends Instruction {
11
10
  static type: string = 'NOTEHASHEXISTS';
@@ -65,7 +64,7 @@ export class EmitNoteHash extends Instruction {
65
64
  context.machineState.consumeGas(this.gasCost(memoryOperations));
66
65
 
67
66
  if (context.environment.isStaticCall) {
68
- throw new StaticCallStorageAlterError();
67
+ throw new StaticCallAlterationError();
69
68
  }
70
69
 
71
70
  const noteHash = memory.get(this.noteHashOffset).toFr();
@@ -125,7 +124,7 @@ export class EmitNullifier extends Instruction {
125
124
 
126
125
  public async execute(context: AvmContext): Promise<void> {
127
126
  if (context.environment.isStaticCall) {
128
- throw new StaticCallStorageAlterError();
127
+ throw new StaticCallAlterationError();
129
128
  }
130
129
 
131
130
  const memoryOperations = { reads: 1, indirect: this.indirect };
@@ -210,7 +209,7 @@ export class EmitUnencryptedLog extends Instruction {
210
209
 
211
210
  public async execute(context: AvmContext): Promise<void> {
212
211
  if (context.environment.isStaticCall) {
213
- throw new StaticCallStorageAlterError();
212
+ throw new StaticCallAlterationError();
214
213
  }
215
214
 
216
215
  const memoryOperations = { reads: 1 + this.logSize, indirect: this.indirect };
@@ -244,7 +243,7 @@ export class SendL2ToL1Message extends Instruction {
244
243
 
245
244
  public async execute(context: AvmContext): Promise<void> {
246
245
  if (context.environment.isStaticCall) {
247
- throw new StaticCallStorageAlterError();
246
+ throw new StaticCallAlterationError();
248
247
  }
249
248
 
250
249
  const memoryOperations = { reads: 2, indirect: this.indirect };
@@ -3,7 +3,7 @@ import { padArrayEnd } from '@aztec/foundation/collection';
3
3
 
4
4
  import { convertAvmResultsToPxResult, createPublicExecution } from '../../public/transitional_adaptors.js';
5
5
  import type { AvmContext } from '../avm_context.js';
6
- import { gasLeftToGas, sumGas } from '../avm_gas.js';
6
+ import { gasLeftToGas } from '../avm_gas.js';
7
7
  import { Field, Uint8 } from '../avm_memory_types.js';
8
8
  import { type AvmContractCallResults } from '../avm_message_call_result.js';
9
9
  import { AvmSimulator } from '../avm_simulator.js';
@@ -40,7 +40,7 @@ abstract class ExternalCall extends Instruction {
40
40
  // Function selector is temporary since eventually public contract bytecode will be one blob
41
41
  // containing all functions, and function selector will become an application-level mechanism
42
42
  // (e.g. first few bytes of calldata + compiler-generated jump table)
43
- private temporaryFunctionSelectorOffset: number,
43
+ private functionSelectorOffset: number,
44
44
  ) {
45
45
  super();
46
46
  }
@@ -57,21 +57,30 @@ abstract class ExternalCall extends Instruction {
57
57
  const callAddress = memory.getAs<Field>(addrOffset);
58
58
  const calldataSize = memory.get(argsSizeOffset).toNumber();
59
59
  const calldata = memory.getSlice(argsOffset, calldataSize).map(f => f.toFr());
60
- const l2Gas = memory.get(gasOffset).toNumber();
61
- const daGas = memory.getAs<Field>(gasOffset + 1).toNumber();
62
- const functionSelector = memory.getAs<Field>(this.temporaryFunctionSelectorOffset).toFr();
60
+ const functionSelector = memory.getAs<Field>(this.functionSelectorOffset).toFr();
61
+ // If we are already in a static call, we propagate the environment.
62
+ const callType = context.environment.isStaticCall ? 'STATICCALL' : this.type;
63
63
 
64
- const allocatedGas = { l2Gas, daGas };
64
+ // First we consume the gas for this operation.
65
65
  const memoryOperations = { reads: calldataSize + 5, writes: 1 + this.retSize, indirect: this.indirect };
66
- const totalGas = sumGas(this.gasCost(memoryOperations), allocatedGas);
67
- context.machineState.consumeGas(totalGas);
66
+ context.machineState.consumeGas(this.gasCost(memoryOperations));
67
+ // Then we consume the gas allocated for the nested call. The excess will be refunded later.
68
+ // Gas allocation is capped by the amount of gas left in the current context.
69
+ // We have to do some dancing here because the gas allocation is a field,
70
+ // but in the machine state we track gas as a number.
71
+ const allocatedL2Gas = Number(BigIntMin(memory.get(gasOffset).toBigInt(), BigInt(context.machineState.l2GasLeft)));
72
+ const allocatedDaGas = Number(
73
+ BigIntMin(memory.get(gasOffset + 1).toBigInt(), BigInt(context.machineState.daGasLeft)),
74
+ );
75
+ const allocatedGas = { l2Gas: allocatedL2Gas, daGas: allocatedDaGas };
76
+ context.machineState.consumeGas(allocatedGas);
68
77
 
69
78
  // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
70
79
  const nestedContext = context.createNestedContractCallContext(
71
80
  callAddress.toFr(),
72
81
  calldata,
73
82
  allocatedGas,
74
- this.type,
83
+ callType,
75
84
  FunctionSelector.fromField(functionSelector),
76
85
  );
77
86
  const startSideEffectCounter = nestedContext.persistableState.trace.accessCounter;
@@ -215,3 +224,8 @@ export class Revert extends Instruction {
215
224
  memory.assert(memoryOperations);
216
225
  }
217
226
  }
227
+
228
+ /** Returns the smaller of two bigints. */
229
+ function BigIntMin(a: bigint, b: bigint): bigint {
230
+ return a < b ? a : b;
231
+ }
@@ -3,7 +3,7 @@ import { Fr } from '@aztec/foundation/fields';
3
3
  import type { AvmContext } from '../avm_context.js';
4
4
  import { type Gas, getBaseGasCost, getMemoryGasCost, mulGas, sumGas } from '../avm_gas.js';
5
5
  import { Field, type MemoryOperations } from '../avm_memory_types.js';
6
- import { InstructionExecutionError } from '../errors.js';
6
+ import { StaticCallAlterationError } from '../errors.js';
7
7
  import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
8
8
  import { Addressing } from './addressing_mode.js';
9
9
  import { Instruction } from './instruction.js';
@@ -44,7 +44,7 @@ export class SStore extends BaseStorageInstruction {
44
44
 
45
45
  public async execute(context: AvmContext): Promise<void> {
46
46
  if (context.environment.isStaticCall) {
47
- throw new StaticCallStorageAlterError();
47
+ throw new StaticCallAlterationError();
48
48
  }
49
49
 
50
50
  const memoryOperations = { reads: this.size + 1, indirect: this.indirect };
@@ -100,13 +100,3 @@ export class SLoad extends BaseStorageInstruction {
100
100
  memory.assert(memoryOperations);
101
101
  }
102
102
  }
103
-
104
- /**
105
- * Error is thrown when a static call attempts to alter storage
106
- */
107
- export class StaticCallStorageAlterError extends InstructionExecutionError {
108
- constructor() {
109
- super('Static calls cannot alter storage');
110
- this.name = 'StaticCallStorageAlterError';
111
- }
112
- }
@@ -1,13 +1,11 @@
1
1
  import {
2
2
  type AuthWitness,
3
3
  type AztecNode,
4
- EncryptedFunctionL2Logs,
5
4
  EncryptedL2Log,
6
5
  L1NotePayload,
7
6
  Note,
8
7
  type NoteStatus,
9
8
  TaggedNote,
10
- UnencryptedFunctionL2Logs,
11
9
  type UnencryptedL2Log,
12
10
  } from '@aztec/circuit-types';
13
11
  import {
@@ -22,8 +20,8 @@ import {
22
20
  import { Aes128 } from '@aztec/circuits.js/barretenberg';
23
21
  import { computePublicDataTreeLeafSlot, computeUniqueNoteHash, siloNoteHash } from '@aztec/circuits.js/hash';
24
22
  import { type FunctionAbi, type FunctionArtifact, countArgumentsSize } from '@aztec/foundation/abi';
25
- import { type AztecAddress } from '@aztec/foundation/aztec-address';
26
- import { Fr, type Point } from '@aztec/foundation/fields';
23
+ import { AztecAddress } from '@aztec/foundation/aztec-address';
24
+ import { Fr, GrumpkinScalar, type Point } from '@aztec/foundation/fields';
27
25
  import { applyStringFormatting, createDebugLogger } from '@aztec/foundation/log';
28
26
 
29
27
  import { type NoteData, toACVMWitness } from '../acvm/index.js';
@@ -31,7 +29,6 @@ import { type PackedValuesCache } from '../common/packed_values_cache.js';
31
29
  import { type DBOracle } from './db_oracle.js';
32
30
  import { type ExecutionNoteCache } from './execution_note_cache.js';
33
31
  import { CountedLog, type ExecutionResult, type NoteAndSlot } from './execution_result.js';
34
- import { type LogsCache } from './logs_cache.js';
35
32
  import { pickNotes } from './pick_notes.js';
36
33
  import { executePrivateFunction } from './private_execution.js';
37
34
  import { ViewDataOracle } from './view_data_oracle.js';
@@ -59,6 +56,7 @@ export class ClientExecutionContext extends ViewDataOracle {
59
56
  */
60
57
  private noteHashLeafIndexMap: Map<bigint, bigint> = new Map();
61
58
  private nullifiedNoteHashCounters: Map<number, number> = new Map();
59
+ private noteEncryptedLogs: CountedLog<EncryptedL2Log>[] = [];
62
60
  private encryptedLogs: CountedLog<EncryptedL2Log>[] = [];
63
61
  private unencryptedLogs: CountedLog<UnencryptedL2Log>[] = [];
64
62
  private nestedExecutions: ExecutionResult[] = [];
@@ -76,7 +74,6 @@ export class ClientExecutionContext extends ViewDataOracle {
76
74
  authWitnesses: AuthWitness[],
77
75
  private readonly packedValuesCache: PackedValuesCache,
78
76
  private readonly noteCache: ExecutionNoteCache,
79
- private readonly logsCache: LogsCache,
80
77
  db: DBOracle,
81
78
  private node: AztecNode,
82
79
  protected sideEffectCounter: number = 0,
@@ -133,31 +130,51 @@ export class ClientExecutionContext extends ViewDataOracle {
133
130
  }
134
131
 
135
132
  /**
136
- * Return the encrypted logs emitted during this execution.
133
+ * Return the note encrypted logs emitted during this execution.
137
134
  */
138
- public getEncryptedLogs() {
139
- return this.encryptedLogs;
135
+ public getNoteEncryptedLogs() {
136
+ return this.noteEncryptedLogs;
137
+ }
138
+
139
+ /**
140
+ * Sometimes notes can be chopped after a nested execution is complete.
141
+ * This means finished nested executions still hold transient logs. This method removes them.
142
+ * TODO(Miranda): is there a cleaner solution?
143
+ */
144
+ public chopNoteEncryptedLogs() {
145
+ // Do not return logs that have been chopped in the cache
146
+ const allNoteLogs = this.noteCache.getLogs();
147
+ this.noteEncryptedLogs = this.noteEncryptedLogs.filter(l => allNoteLogs.includes(l));
148
+ const chop = (thing: any) =>
149
+ thing.nestedExecutions.forEach((result: ExecutionResult) => {
150
+ if (!result.noteEncryptedLogs[0]?.isEmpty()) {
151
+ // The execution has note logs
152
+ result.noteEncryptedLogs = result.noteEncryptedLogs.filter(l => allNoteLogs.includes(l));
153
+ }
154
+ chop(result);
155
+ });
156
+ chop(this);
140
157
  }
141
158
 
142
159
  /**
143
- * Return the encrypted logs emitted during this execution and nested executions.
160
+ * Return the note encrypted logs emitted during this execution and nested executions.
144
161
  */
145
- public getAllEncryptedLogs() {
146
- return new EncryptedFunctionL2Logs(this.logsCache.getEncryptedLogs());
162
+ public getAllNoteEncryptedLogs() {
163
+ return this.noteCache.getLogs();
147
164
  }
148
165
 
149
166
  /**
150
167
  * Return the encrypted logs emitted during this execution.
151
168
  */
152
- public getUnencryptedLogs() {
153
- return this.unencryptedLogs;
169
+ public getEncryptedLogs() {
170
+ return this.encryptedLogs;
154
171
  }
155
172
 
156
173
  /**
157
- * Return the unencrypted logs emitted during this execution and nested executions.
174
+ * Return the encrypted logs emitted during this execution.
158
175
  */
159
- public getAllUnencryptedLogs() {
160
- return new UnencryptedFunctionL2Logs(this.logsCache.getUnencryptedLogs());
176
+ public getUnencryptedLogs() {
177
+ return this.unencryptedLogs;
161
178
  }
162
179
 
163
180
  /**
@@ -337,29 +354,53 @@ export class ClientExecutionContext extends ViewDataOracle {
337
354
  }
338
355
 
339
356
  /**
340
- * Encrypt a note and emit it as a log.
357
+ * Emit encrypted data
358
+ * @param encryptedNote - The encrypted data.
359
+ * @param counter - The effects counter.
360
+ */
361
+ public override emitEncryptedLog(encryptedData: Buffer, counter: number) {
362
+ const encryptedLog = new CountedLog(new EncryptedL2Log(encryptedData), counter);
363
+ this.encryptedLogs.push(encryptedLog);
364
+ }
365
+
366
+ /**
367
+ * Emit encrypted note data
368
+ * @param noteHash - The note hash.
369
+ * @param encryptedNote - The encrypted note data.
370
+ * @param counter - The effects counter.
371
+ */
372
+ public override emitEncryptedNoteLog(noteHash: Fr, encryptedNote: Buffer, counter: number) {
373
+ const encryptedLog = new CountedLog(new EncryptedL2Log(encryptedNote), counter);
374
+ this.noteEncryptedLogs.push(encryptedLog);
375
+ this.noteCache.addNewLog(encryptedLog, noteHash);
376
+ }
377
+
378
+ /**
379
+ * Encrypt a note
341
380
  * @param contractAddress - The contract address of the note.
342
381
  * @param storageSlot - The storage slot the note is at.
343
382
  * @param noteTypeId - The type ID of the note.
344
- * @param publicKey - The public key of the account that can decrypt the log.
345
- * @param log - The log contents.
383
+ * @param ivpk - The master incoming viewing public key.
384
+ * @param preimage - The note preimage.
346
385
  */
347
- public override emitEncryptedLog(
386
+ public override computeEncryptedLog(
348
387
  contractAddress: AztecAddress,
349
388
  storageSlot: Fr,
350
389
  noteTypeId: Fr,
351
- publicKey: Point,
352
- log: Fr[],
353
- counter: number,
390
+ ivpk: Point,
391
+ preimage: Fr[],
354
392
  ) {
355
- const note = new Note(log);
393
+ const note = new Note(preimage);
356
394
  const l1NotePayload = new L1NotePayload(note, contractAddress, storageSlot, noteTypeId);
357
395
  const taggedNote = new TaggedNote(l1NotePayload);
358
- const encryptedNote = taggedNote.toEncryptedBuffer(publicKey);
359
- const encryptedLog = new EncryptedL2Log(encryptedNote);
360
- this.encryptedLogs.push(new CountedLog(encryptedLog, counter));
361
- this.logsCache.addEncryptedLog(encryptedLog);
362
- return encryptedNote;
396
+
397
+ const ephSk = GrumpkinScalar.random();
398
+
399
+ // @todo Issue(#6410) Right now we are completely ignoring the outgoing log. Just drawing random data.
400
+ const ovsk = GrumpkinScalar.random();
401
+ const recipient = AztecAddress.random();
402
+
403
+ return taggedNote.encrypt(ephSk, recipient, ivpk, ovsk);
363
404
  }
364
405
 
365
406
  /**
@@ -368,7 +409,6 @@ export class ClientExecutionContext extends ViewDataOracle {
368
409
  */
369
410
  public override emitUnencryptedLog(log: UnencryptedL2Log, counter: number) {
370
411
  this.unencryptedLogs.push(new CountedLog(log, counter));
371
- this.logsCache.addUnencryptedLog(log);
372
412
  const text = log.toHumanReadable();
373
413
  this.log.verbose(`Emitted unencrypted log: "${text.length > 100 ? text.slice(0, 100) + '...' : text}"`);
374
414
  }
@@ -382,7 +422,6 @@ export class ClientExecutionContext extends ViewDataOracle {
382
422
  */
383
423
  public override emitContractClassUnencryptedLog(log: UnencryptedL2Log, counter: number) {
384
424
  this.unencryptedLogs.push(new CountedLog(log, counter));
385
- this.logsCache.addUnencryptedLog(log);
386
425
  const text = log.toHumanReadable();
387
426
  this.log.verbose(
388
427
  `Emitted unencrypted log from ContractClassRegisterer: "${
@@ -397,10 +436,10 @@ export class ClientExecutionContext extends ViewDataOracle {
397
436
  childExecutionResult.callStackItem.publicInputs.newNoteHashes.some(item => !item.isEmpty()) ||
398
437
  childExecutionResult.callStackItem.publicInputs.newNullifiers.some(item => !item.isEmpty()) ||
399
438
  childExecutionResult.callStackItem.publicInputs.newL2ToL1Msgs.some(item => !item.isEmpty()) ||
400
- !childExecutionResult.callStackItem.publicInputs.encryptedLogPreimagesLength.equals(new Fr(4)) ||
401
- !childExecutionResult.callStackItem.publicInputs.unencryptedLogPreimagesLength.equals(new Fr(4))
439
+ childExecutionResult.callStackItem.publicInputs.encryptedLogsHashes.some(item => !item.isEmpty()) ||
440
+ childExecutionResult.callStackItem.publicInputs.unencryptedLogsHashes.some(item => !item.isEmpty())
402
441
  ) {
403
- throw new Error(`Static call cannot create new notes, emit L2->L1 messages or generate logs`);
442
+ throw new Error(`Static call cannot update the state, emit L2->L1 messages or generate logs`);
404
443
  }
405
444
  }
406
445
 
@@ -411,7 +450,7 @@ export class ClientExecutionContext extends ViewDataOracle {
411
450
  * @param argsHash - The packed arguments to pass to the function.
412
451
  * @param sideEffectCounter - The side effect counter at the start of the call.
413
452
  * @param isStaticCall - Whether the call is a static call.
414
- * @param isStaticCall - Whether the call is a delegate call.
453
+ * @param isDelegateCall - Whether the call is a delegate call.
415
454
  * @returns The execution result.
416
455
  */
417
456
  override async callPrivateFunction(
@@ -450,7 +489,6 @@ export class ClientExecutionContext extends ViewDataOracle {
450
489
  this.authWitnesses,
451
490
  this.packedValuesCache,
452
491
  this.noteCache,
453
- this.logsCache,
454
492
  this.db,
455
493
  this.node,
456
494
  sideEffectCounter,
@@ -5,13 +5,13 @@ import {
5
5
  type NullifierMembershipWitness,
6
6
  type PublicDataWitness,
7
7
  } from '@aztec/circuit-types';
8
- import { type CompleteAddress, type Header } from '@aztec/circuits.js';
8
+ import { type CompleteAddress, type Header, type KeyValidationRequest } from '@aztec/circuits.js';
9
9
  import { type FunctionArtifact, type FunctionSelector } from '@aztec/foundation/abi';
10
10
  import { type AztecAddress } from '@aztec/foundation/aztec-address';
11
11
  import { type Fr } from '@aztec/foundation/fields';
12
12
  import { type ContractInstance } from '@aztec/types/contracts';
13
13
 
14
- import { type NoteData, type NullifierKeys } from '../acvm/index.js';
14
+ import { type NoteData } from '../acvm/index.js';
15
15
  import { type CommitmentsDB } from '../public/db.js';
16
16
 
17
17
  /**
@@ -45,10 +45,11 @@ export interface DBOracle extends CommitmentsDB {
45
45
 
46
46
  /**
47
47
  * Retrieve the complete address associated to a given address.
48
- * @param address - Address to fetch the pubkey for.
48
+ * @param account - The account address.
49
49
  * @returns A complete address associated with the input address.
50
+ * @throws An error if the account is not registered in the database.
50
51
  */
51
- getCompleteAddress(address: AztecAddress): Promise<CompleteAddress>;
52
+ getCompleteAddress(account: AztecAddress): Promise<CompleteAddress>;
52
53
 
53
54
  /**
54
55
  * Retrieve the auth witness for a given message hash.
@@ -65,14 +66,12 @@ export interface DBOracle extends CommitmentsDB {
65
66
  popCapsule(): Promise<Fr[]>;
66
67
 
67
68
  /**
68
- * Retrieve nullifier keys associated with a specific account and app/contract address.
69
- *
70
- * @param accountAddress - The account address.
71
- * @param contractAddress - The contract address.
72
- * @returns A Promise that resolves to nullifier keys of a requested account and contract.
73
- * @throws An error if the account is not registered in the database.
69
+ * Retrieve keys associated with a specific master public key and app address.
70
+ * @param pkMHash - The master public key hash.
71
+ * @returns A Promise that resolves to nullifier keys.
72
+ * @throws If the keys are not registered in the key store.
74
73
  */
75
- getNullifierKeys(accountAddress: AztecAddress, contractAddress: AztecAddress): Promise<NullifierKeys>;
74
+ getKeyValidationRequest(pkMHash: Fr, contractAddress: AztecAddress): Promise<KeyValidationRequest>;
76
75
 
77
76
  /**
78
77
  * Retrieves a set of notes stored in the database for a given contract address and storage slot.