@aztec/simulator 0.37.0 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/dest/acvm/acvm.d.ts +1 -1
  2. package/dest/acvm/acvm.d.ts.map +1 -1
  3. package/dest/acvm/acvm.js +2 -2
  4. package/dest/acvm/oracle/oracle.d.ts +5 -4
  5. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  6. package/dest/acvm/oracle/oracle.js +19 -8
  7. package/dest/acvm/oracle/typed_oracle.d.ts +3 -2
  8. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  9. package/dest/acvm/oracle/typed_oracle.js +6 -3
  10. package/dest/avm/avm_gas.d.ts.map +1 -1
  11. package/dest/avm/avm_gas.js +2 -1
  12. package/dest/avm/avm_memory_types.d.ts +1 -1
  13. package/dest/avm/avm_memory_types.d.ts.map +1 -1
  14. package/dest/avm/avm_simulator.d.ts.map +1 -1
  15. package/dest/avm/avm_simulator.js +3 -1
  16. package/dest/avm/journal/journal.d.ts +20 -1
  17. package/dest/avm/journal/journal.d.ts.map +1 -1
  18. package/dest/avm/journal/journal.js +69 -9
  19. package/dest/avm/journal/nullifiers.d.ts +3 -1
  20. package/dest/avm/journal/nullifiers.d.ts.map +1 -1
  21. package/dest/avm/journal/nullifiers.js +14 -6
  22. package/dest/avm/journal/public_storage.d.ts +10 -1
  23. package/dest/avm/journal/public_storage.d.ts.map +1 -1
  24. package/dest/avm/journal/public_storage.js +17 -2
  25. package/dest/avm/journal/trace.d.ts +1 -4
  26. package/dest/avm/journal/trace.d.ts.map +1 -1
  27. package/dest/avm/journal/trace.js +4 -5
  28. package/dest/avm/journal/trace_types.d.ts +1 -0
  29. package/dest/avm/journal/trace_types.d.ts.map +1 -1
  30. package/dest/avm/journal/trace_types.js +1 -1
  31. package/dest/avm/opcodes/bitwise.d.ts +4 -1
  32. package/dest/avm/opcodes/bitwise.d.ts.map +1 -1
  33. package/dest/avm/opcodes/bitwise.js +14 -2
  34. package/dest/avm/opcodes/environment_getters.d.ts +5 -0
  35. package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
  36. package/dest/avm/opcodes/environment_getters.js +8 -1
  37. package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
  38. package/dest/avm/opcodes/external_calls.js +14 -13
  39. package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
  40. package/dest/avm/serialization/bytecode_serialization.js +3 -2
  41. package/dest/avm/serialization/instruction_serialization.d.ts +39 -38
  42. package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
  43. package/dest/avm/serialization/instruction_serialization.js +40 -39
  44. package/dest/client/client_execution_context.d.ts +31 -18
  45. package/dest/client/client_execution_context.d.ts.map +1 -1
  46. package/dest/client/client_execution_context.js +48 -31
  47. package/dest/client/db_oracle.d.ts +3 -3
  48. package/dest/client/db_oracle.d.ts.map +1 -1
  49. package/dest/client/execution_result.d.ts +19 -15
  50. package/dest/client/execution_result.d.ts.map +1 -1
  51. package/dest/client/execution_result.js +45 -12
  52. package/dest/client/logs_cache.d.ts +33 -0
  53. package/dest/client/logs_cache.d.ts.map +1 -0
  54. package/dest/client/logs_cache.js +59 -0
  55. package/dest/client/private_execution.d.ts +2 -2
  56. package/dest/client/private_execution.d.ts.map +1 -1
  57. package/dest/client/private_execution.js +3 -7
  58. package/dest/client/simulator.d.ts +3 -3
  59. package/dest/client/simulator.d.ts.map +1 -1
  60. package/dest/client/simulator.js +3 -2
  61. package/dest/client/unconstrained_execution.d.ts +2 -2
  62. package/dest/client/unconstrained_execution.d.ts.map +1 -1
  63. package/dest/client/unconstrained_execution.js +1 -1
  64. package/dest/mocks/fixtures.d.ts.map +1 -1
  65. package/dest/mocks/fixtures.js +3 -1
  66. package/dest/public/abstract_phase_manager.d.ts +2 -0
  67. package/dest/public/abstract_phase_manager.d.ts.map +1 -1
  68. package/dest/public/abstract_phase_manager.js +13 -6
  69. package/dest/public/execution.d.ts +9 -0
  70. package/dest/public/execution.d.ts.map +1 -1
  71. package/dest/public/execution.js +1 -1
  72. package/dest/public/executor.d.ts +2 -2
  73. package/dest/public/executor.d.ts.map +1 -1
  74. package/dest/public/executor.js +34 -14
  75. package/dest/public/public_execution_context.d.ts +10 -4
  76. package/dest/public/public_execution_context.d.ts.map +1 -1
  77. package/dest/public/public_execution_context.js +19 -6
  78. package/dest/public/tail_phase_manager.d.ts +0 -1
  79. package/dest/public/tail_phase_manager.d.ts.map +1 -1
  80. package/dest/public/tail_phase_manager.js +3 -26
  81. package/dest/public/transitional_adaptors.d.ts +4 -17
  82. package/dest/public/transitional_adaptors.d.ts.map +1 -1
  83. package/dest/public/transitional_adaptors.js +27 -119
  84. package/package.json +8 -8
  85. package/src/acvm/acvm.ts +2 -2
  86. package/src/acvm/oracle/oracle.ts +39 -9
  87. package/src/acvm/oracle/typed_oracle.ts +7 -2
  88. package/src/avm/avm_gas.ts +1 -0
  89. package/src/avm/avm_memory_types.ts +1 -1
  90. package/src/avm/avm_simulator.ts +2 -0
  91. package/src/avm/journal/journal.ts +133 -9
  92. package/src/avm/journal/nullifiers.ts +19 -8
  93. package/src/avm/journal/public_storage.ts +23 -2
  94. package/src/avm/journal/trace.ts +3 -4
  95. package/src/avm/journal/trace_types.ts +1 -0
  96. package/src/avm/opcodes/bitwise.ts +18 -7
  97. package/src/avm/opcodes/environment_getters.ts +9 -0
  98. package/src/avm/opcodes/external_calls.ts +21 -16
  99. package/src/avm/serialization/bytecode_serialization.ts +2 -0
  100. package/src/avm/serialization/instruction_serialization.ts +1 -0
  101. package/src/client/client_execution_context.ts +55 -31
  102. package/src/client/db_oracle.ts +3 -9
  103. package/src/client/execution_result.ts +55 -24
  104. package/src/client/logs_cache.ts +65 -0
  105. package/src/client/private_execution.ts +4 -10
  106. package/src/client/simulator.ts +6 -4
  107. package/src/client/unconstrained_execution.ts +2 -2
  108. package/src/mocks/fixtures.ts +2 -0
  109. package/src/public/abstract_phase_manager.ts +13 -5
  110. package/src/public/execution.ts +9 -0
  111. package/src/public/executor.ts +47 -10
  112. package/src/public/public_execution_context.ts +18 -4
  113. package/src/public/tail_phase_manager.ts +2 -34
  114. package/src/public/transitional_adaptors.ts +39 -178
@@ -1,3 +1,4 @@
1
+ import { AztecAddress } from '@aztec/circuits.js';
1
2
  import { siloNullifier } from '@aztec/circuits.js/hash';
2
3
  import { Fr } from '@aztec/foundation/fields';
3
4
 
@@ -10,7 +11,7 @@ import type { CommitmentsDB } from '../../index.js';
10
11
  */
11
12
  export class Nullifiers {
12
13
  /** Cached nullifiers. */
13
- private cache: NullifierCache;
14
+ public cache: NullifierCache;
14
15
  /** Parent's nullifier cache. Checked on cache-miss. */
15
16
  private readonly parentCache: NullifierCache | undefined;
16
17
  /** Reference to node storage. Checked on parent cache-miss. */
@@ -95,6 +96,7 @@ export class NullifierCache {
95
96
  * each entry being a nullifier.
96
97
  */
97
98
  private cachePerContract: Map<bigint, Set<bigint>> = new Map();
99
+ private siloedNullifiers: Set<bigint> = new Set();
98
100
 
99
101
  /**
100
102
  * Check whether a nullifier exists in the cache.
@@ -104,8 +106,10 @@ export class NullifierCache {
104
106
  * @returns whether the nullifier is found in the cache
105
107
  */
106
108
  public exists(storageAddress: Fr, nullifier: Fr): boolean {
107
- const exists = this.cachePerContract.get(storageAddress.toBigInt())?.has(nullifier.toBigInt());
108
- return exists ? true : false;
109
+ const exists =
110
+ this.cachePerContract.get(storageAddress.toBigInt())?.has(nullifier.toBigInt()) ||
111
+ this.siloedNullifiers.has(siloNullifier(AztecAddress.fromField(storageAddress), nullifier).toBigInt());
112
+ return !!exists;
109
113
  }
110
114
 
111
115
  /**
@@ -115,20 +119,25 @@ export class NullifierCache {
115
119
  * @param nullifier - the nullifier to stage
116
120
  */
117
121
  public append(storageAddress: Fr, nullifier: Fr) {
122
+ if (this.exists(storageAddress, nullifier)) {
123
+ throw new NullifierCollisionError(
124
+ `Nullifier ${nullifier} at contract ${storageAddress} already exists in cache.`,
125
+ );
126
+ }
127
+
118
128
  let nullifiersForContract = this.cachePerContract.get(storageAddress.toBigInt());
119
129
  // If this contract's nullifier set has no cached nullifiers, create a new Set to store them
120
130
  if (!nullifiersForContract) {
121
131
  nullifiersForContract = new Set();
122
132
  this.cachePerContract.set(storageAddress.toBigInt(), nullifiersForContract);
123
133
  }
124
- if (nullifiersForContract.has(nullifier.toBigInt())) {
125
- throw new NullifierCollisionError(
126
- `Nullifier ${nullifier} at contract ${storageAddress} already exists in cache.`,
127
- );
128
- }
129
134
  nullifiersForContract.add(nullifier.toBigInt());
130
135
  }
131
136
 
137
+ public appendSiloed(siloedNullifier: Fr) {
138
+ this.siloedNullifiers.add(siloedNullifier.toBigInt());
139
+ }
140
+
132
141
  /**
133
142
  * Merge another cache's nullifiers into this instance's.
134
143
  *
@@ -139,6 +148,8 @@ export class NullifierCache {
139
148
  * @param incomingNullifiers - the incoming cached nullifiers to merge into this instance's
140
149
  */
141
150
  public acceptAndMerge(incomingNullifiers: NullifierCache) {
151
+ // Merge siloed nullifiers.
152
+ this.siloedNullifiers = new Set([...this.siloedNullifiers, ...incomingNullifiers.siloedNullifiers]);
142
153
  // Iterate over all contracts with staged writes in the child.
143
154
  for (const [incomingAddress, incomingCacheAtContract] of incomingNullifiers.cachePerContract) {
144
155
  const thisCacheAtContract = this.cachePerContract.get(incomingAddress);
@@ -1,7 +1,14 @@
1
+ import { AztecAddress } from '@aztec/circuits.js';
1
2
  import { Fr } from '@aztec/foundation/fields';
2
3
 
3
4
  import type { PublicStateDB } from '../../index.js';
4
5
 
6
+ type PublicStorageReadResult = {
7
+ value: Fr;
8
+ exists: boolean;
9
+ cached: boolean;
10
+ };
11
+
5
12
  /**
6
13
  * A class to manage public storage reads and writes during a contract call's AVM simulation.
7
14
  * Maintains a storage write cache, and ensures that reads fall back to the correct source.
@@ -39,7 +46,8 @@ export class PublicStorage {
39
46
  * @param slot - the slot in the contract's storage being read from
40
47
  * @returns exists: whether the slot has EVER been written to before, value: the latest value written to slot, or 0 if never written to before
41
48
  */
42
- public async read(storageAddress: Fr, slot: Fr): Promise<[/*exists=*/ boolean, /*value=*/ Fr]> {
49
+ public async read(storageAddress: Fr, slot: Fr): Promise<PublicStorageReadResult> {
50
+ let cached = false;
43
51
  // First try check this storage cache
44
52
  let value = this.cache.read(storageAddress, slot);
45
53
  // Then try parent's storage cache (if it exists / written to earlier in this TX)
@@ -49,11 +57,13 @@ export class PublicStorage {
49
57
  // Finally try the host's Aztec state (a trip to the database)
50
58
  if (!value) {
51
59
  value = await this.hostPublicStorage.storageRead(storageAddress, slot);
60
+ } else {
61
+ cached = true;
52
62
  }
53
63
  // if value is undefined, that means this slot has never been written to!
54
64
  const exists = value !== undefined;
55
65
  const valueOrZero = exists ? value : Fr.ZERO;
56
- return Promise.resolve([exists, valueOrZero]);
66
+ return Promise.resolve({ value: valueOrZero, exists, cached });
57
67
  }
58
68
 
59
69
  /**
@@ -75,6 +85,17 @@ export class PublicStorage {
75
85
  public acceptAndMerge(incomingPublicStorage: PublicStorage) {
76
86
  this.cache.acceptAndMerge(incomingPublicStorage.cache);
77
87
  }
88
+
89
+ /**
90
+ * Commits ALL staged writes to the host's state.
91
+ */
92
+ public async commitToDB() {
93
+ for (const [storageAddress, cacheAtContract] of this.cache.cachePerContract) {
94
+ for (const [slot, value] of cacheAtContract) {
95
+ await this.hostPublicStorage.storageWrite(AztecAddress.fromBigInt(storageAddress), new Fr(slot), value);
96
+ }
97
+ }
98
+ }
78
99
  }
79
100
 
80
101
  /**
@@ -29,13 +29,14 @@ export class WorldStateAccessTrace {
29
29
 
30
30
  constructor(parentTrace?: WorldStateAccessTrace) {
31
31
  this.accessCounter = parentTrace ? parentTrace.accessCounter : 0;
32
+ // TODO(4805): consider tracking the parent's trace vector lengths so we can enforce limits
32
33
  }
33
34
 
34
35
  public getAccessCounter() {
35
36
  return this.accessCounter;
36
37
  }
37
38
 
38
- public tracePublicStorageRead(storageAddress: Fr, slot: Fr, value: Fr, exists: boolean) {
39
+ public tracePublicStorageRead(storageAddress: Fr, slot: Fr, value: Fr, exists: boolean, cached: boolean) {
39
40
  // TODO(4805): check if some threshold is reached for max storage reads
40
41
  // (need access to parent length, or trace needs to be initialized with parent's contents)
41
42
  const traced: TracedPublicStorageRead = {
@@ -44,6 +45,7 @@ export class WorldStateAccessTrace {
44
45
  slot,
45
46
  value,
46
47
  exists,
48
+ cached,
47
49
  counter: new Fr(this.accessCounter),
48
50
  // endLifetime: Fr.ZERO,
49
51
  };
@@ -151,9 +153,6 @@ export class WorldStateAccessTrace {
151
153
  /**
152
154
  * Merges another trace into this one
153
155
  *
154
- * - Public state journals (r/w logs), with the accessing being appended in chronological order
155
- * - Utxo objects are concatenated
156
- *
157
156
  * @param incomingTrace - the incoming trace to merge into this instance
158
157
  */
159
158
  public acceptAndMerge(incomingTrace: WorldStateAccessTrace) {
@@ -11,6 +11,7 @@ export type TracedPublicStorageRead = {
11
11
  // callPointer: Fr;
12
12
  storageAddress: Fr;
13
13
  exists: boolean;
14
+ cached: boolean;
14
15
  slot: Fr;
15
16
  value: Fr;
16
17
  counter: Fr;
@@ -1,5 +1,5 @@
1
1
  import type { AvmContext } from '../avm_context.js';
2
- import { type IntegralValue } from '../avm_memory_types.js';
2
+ import { type IntegralValue, type TaggedMemoryInterface, TypeTag } from '../avm_memory_types.js';
3
3
  import { Opcode } from '../serialization/instruction_serialization.js';
4
4
  import { ThreeOperandInstruction, TwoOperandInstruction } from './instruction_impl.js';
5
5
 
@@ -9,7 +9,7 @@ abstract class ThreeOperandBitwiseInstruction extends ThreeOperandInstruction {
9
9
  const memory = context.machineState.memory.track(this.type);
10
10
  context.machineState.consumeGas(this.gasCost(memoryOperations));
11
11
 
12
- memory.checkTags(this.inTag, this.aOffset, this.bOffset);
12
+ this.checkTags(memory, this.inTag, this.aOffset, this.bOffset);
13
13
 
14
14
  const a = memory.getAs<IntegralValue>(this.aOffset);
15
15
  const b = memory.getAs<IntegralValue>(this.bOffset);
@@ -22,13 +22,16 @@ abstract class ThreeOperandBitwiseInstruction extends ThreeOperandInstruction {
22
22
  }
23
23
 
24
24
  protected abstract compute(a: IntegralValue, b: IntegralValue): IntegralValue;
25
+ protected checkTags(memory: TaggedMemoryInterface, inTag: number, aOffset: number, bOffset: number) {
26
+ memory.checkTags(inTag, aOffset, bOffset);
27
+ }
25
28
  }
26
29
 
27
30
  export class And extends ThreeOperandBitwiseInstruction {
28
31
  static readonly type: string = 'AND';
29
32
  static readonly opcode = Opcode.AND;
30
33
 
31
- protected compute(a: IntegralValue, b: IntegralValue): IntegralValue {
34
+ protected override compute(a: IntegralValue, b: IntegralValue): IntegralValue {
32
35
  return a.and(b);
33
36
  }
34
37
  }
@@ -37,7 +40,7 @@ export class Or extends ThreeOperandBitwiseInstruction {
37
40
  static readonly type: string = 'OR';
38
41
  static readonly opcode = Opcode.OR;
39
42
 
40
- protected compute(a: IntegralValue, b: IntegralValue): IntegralValue {
43
+ protected override compute(a: IntegralValue, b: IntegralValue): IntegralValue {
41
44
  return a.or(b);
42
45
  }
43
46
  }
@@ -46,7 +49,7 @@ export class Xor extends ThreeOperandBitwiseInstruction {
46
49
  static readonly type: string = 'XOR';
47
50
  static readonly opcode = Opcode.XOR;
48
51
 
49
- protected compute(a: IntegralValue, b: IntegralValue): IntegralValue {
52
+ protected override compute(a: IntegralValue, b: IntegralValue): IntegralValue {
50
53
  return a.xor(b);
51
54
  }
52
55
  }
@@ -55,18 +58,26 @@ export class Shl extends ThreeOperandBitwiseInstruction {
55
58
  static readonly type: string = 'SHL';
56
59
  static readonly opcode = Opcode.SHL;
57
60
 
58
- protected compute(a: IntegralValue, b: IntegralValue): IntegralValue {
61
+ protected override compute(a: IntegralValue, b: IntegralValue): IntegralValue {
59
62
  return a.shl(b);
60
63
  }
64
+ protected override checkTags(memory: TaggedMemoryInterface, inTag: number, aOffset: number, bOffset: number) {
65
+ memory.checkTag(inTag, aOffset);
66
+ memory.checkTag(TypeTag.UINT8, bOffset);
67
+ }
61
68
  }
62
69
 
63
70
  export class Shr extends ThreeOperandBitwiseInstruction {
64
71
  static readonly type: string = 'SHR';
65
72
  static readonly opcode = Opcode.SHR;
66
73
 
67
- protected compute(a: IntegralValue, b: IntegralValue): IntegralValue {
74
+ protected override compute(a: IntegralValue, b: IntegralValue): IntegralValue {
68
75
  return a.shr(b);
69
76
  }
77
+ protected override checkTags(memory: TaggedMemoryInterface, inTag: number, aOffset: number, bOffset: number) {
78
+ memory.checkTag(inTag, aOffset);
79
+ memory.checkTag(TypeTag.UINT8, bOffset);
80
+ }
70
81
  }
71
82
 
72
83
  export class Not extends TwoOperandInstruction {
@@ -59,6 +59,15 @@ export class FeePerDAGas extends EnvironmentGetterInstruction {
59
59
  }
60
60
  }
61
61
 
62
+ export class TransactionFee extends EnvironmentGetterInstruction {
63
+ static type: string = 'TRANSACTIONFEE';
64
+ static readonly opcode: Opcode = Opcode.TRANSACTIONFEE;
65
+
66
+ protected getEnvironmentValue(env: AvmExecutionEnvironment) {
67
+ return env.transactionFee;
68
+ }
69
+ }
70
+
62
71
  export class ChainId extends EnvironmentGetterInstruction {
63
72
  static type: string = 'CHAINID';
64
73
  static readonly opcode: Opcode = Opcode.CHAINID;
@@ -1,16 +1,12 @@
1
- import { FunctionSelector } from '@aztec/circuits.js';
1
+ import { FunctionSelector, Gas } from '@aztec/circuits.js';
2
2
  import { padArrayEnd } from '@aztec/foundation/collection';
3
3
 
4
- import { executePublicFunction } from '../../public/executor.js';
5
- import {
6
- convertPublicExecutionResult,
7
- createPublicExecutionContext,
8
- updateAvmContextFromPublicExecutionResult,
9
- } from '../../public/transitional_adaptors.js';
4
+ import { convertAvmResultsToPxResult, createPublicExecution } from '../../public/transitional_adaptors.js';
10
5
  import type { AvmContext } from '../avm_context.js';
11
6
  import { gasLeftToGas, sumGas } from '../avm_gas.js';
12
7
  import { Field, Uint8 } from '../avm_memory_types.js';
13
8
  import { type AvmContractCallResults } from '../avm_message_call_result.js';
9
+ import { AvmSimulator } from '../avm_simulator.js';
14
10
  import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
15
11
  import { Addressing } from './addressing_mode.js';
16
12
  import { Instruction } from './instruction.js';
@@ -69,7 +65,7 @@ abstract class ExternalCall extends Instruction {
69
65
  const totalGas = sumGas(this.gasCost(memoryOperations), allocatedGas);
70
66
  context.machineState.consumeGas(totalGas);
71
67
 
72
- // TRANSITIONAL: This should be removed once the AVM is fully operational and the public executor is gone.
68
+ // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit
73
69
  const nestedContext = context.createNestedContractCallContext(
74
70
  callAddress.toFr(),
75
71
  calldata,
@@ -77,11 +73,21 @@ abstract class ExternalCall extends Instruction {
77
73
  this.type,
78
74
  FunctionSelector.fromField(functionSelector),
79
75
  );
80
- const pxContext = createPublicExecutionContext(nestedContext, calldata);
81
- const pxResults = await executePublicFunction(pxContext, /*nested=*/ true);
82
- const nestedCallResults: AvmContractCallResults = convertPublicExecutionResult(pxResults);
83
- updateAvmContextFromPublicExecutionResult(nestedContext, pxResults);
84
- const nestedPersistableState = nestedContext.persistableState;
76
+ const startSideEffectCounter = nestedContext.persistableState.trace.accessCounter;
77
+
78
+ const oldStyleExecution = createPublicExecution(startSideEffectCounter, nestedContext.environment, calldata);
79
+ const nestedCallResults: AvmContractCallResults = await new AvmSimulator(nestedContext).execute();
80
+ const pxResults = convertAvmResultsToPxResult(
81
+ nestedCallResults,
82
+ startSideEffectCounter,
83
+ oldStyleExecution,
84
+ Gas.from(allocatedGas),
85
+ nestedContext,
86
+ );
87
+ // store the old PublicExecutionResult object to maintain a recursive data structure for the old kernel
88
+ context.persistableState.transitionalExecutionResult.nestedExecutions.push(pxResults);
89
+ // END TRANSITIONAL
90
+
85
91
  // const nestedContext = context.createNestedContractCallContext(
86
92
  // callAddress.toFr(),
87
93
  // calldata,
@@ -90,7 +96,6 @@ abstract class ExternalCall extends Instruction {
90
96
  // FunctionSelector.fromField(functionSelector),
91
97
  // );
92
98
  // const nestedCallResults: AvmContractCallResults = await new AvmSimulator(nestedContext).execute();
93
- // const nestedPersistableState = nestedContext.persistableState;
94
99
 
95
100
  const success = !nestedCallResults.reverted;
96
101
 
@@ -112,9 +117,9 @@ abstract class ExternalCall extends Instruction {
112
117
 
113
118
  // TODO: Should we merge the changes from a nested call in the case of a STATIC call?
114
119
  if (success) {
115
- context.persistableState.acceptNestedCallState(nestedPersistableState);
120
+ context.persistableState.acceptNestedCallState(nestedContext.persistableState);
116
121
  } else {
117
- context.persistableState.rejectNestedCallState(nestedPersistableState);
122
+ context.persistableState.rejectNestedCallState(nestedContext.persistableState);
118
123
  }
119
124
 
120
125
  memory.assert(memoryOperations);
@@ -46,6 +46,7 @@ import {
46
46
  StorageAddress,
47
47
  Sub,
48
48
  Timestamp,
49
+ TransactionFee,
49
50
  Version,
50
51
  Xor,
51
52
  } from '../opcodes/index.js';
@@ -82,6 +83,7 @@ const INSTRUCTION_SET = () =>
82
83
  [Sender.opcode, Sender],
83
84
  [FeePerL2Gas.opcode, FeePerL2Gas],
84
85
  [FeePerDAGas.opcode, FeePerDAGas],
86
+ [TransactionFee.opcode, TransactionFee],
85
87
  //[Contractcalldepth.opcode, Contractcalldepth],
86
88
  // Execution Environment - Globals
87
89
  [ChainId.opcode, ChainId],
@@ -29,6 +29,7 @@ export enum Opcode {
29
29
  SENDER,
30
30
  FEEPERL2GAS,
31
31
  FEEPERDAGAS,
32
+ TRANSACTIONFEE,
32
33
  CONTRACTCALLDEPTH,
33
34
  CHAINID,
34
35
  VERSION,
@@ -15,10 +15,8 @@ import {
15
15
  FunctionData,
16
16
  FunctionSelector,
17
17
  type Header,
18
- NoteHashReadRequestMembershipWitness,
19
18
  PrivateContextInputs,
20
19
  PublicCallRequest,
21
- type SideEffect,
22
20
  type TxContext,
23
21
  } from '@aztec/circuits.js';
24
22
  import { Aes128 } from '@aztec/circuits.js/barretenberg';
@@ -32,7 +30,8 @@ import { type NoteData, toACVMWitness } from '../acvm/index.js';
32
30
  import { type PackedValuesCache } from '../common/packed_values_cache.js';
33
31
  import { type DBOracle } from './db_oracle.js';
34
32
  import { type ExecutionNoteCache } from './execution_note_cache.js';
35
- import { type ExecutionResult, type NoteAndSlot, type NullifiedNoteHashCounter } from './execution_result.js';
33
+ import { CountedLog, type ExecutionResult, type NoteAndSlot } from './execution_result.js';
34
+ import { type LogsCache } from './logs_cache.js';
36
35
  import { pickNotes } from './pick_notes.js';
37
36
  import { executePrivateFunction } from './private_execution.js';
38
37
  import { ViewDataOracle } from './view_data_oracle.js';
@@ -58,10 +57,10 @@ export class ClientExecutionContext extends ViewDataOracle {
58
57
  * because these notes are meant to be maintained on a per-call basis
59
58
  * They should act as references for the read requests output by an app circuit via public inputs.
60
59
  */
61
- private gotNotes: Map<bigint, bigint> = new Map();
62
- private nullifiedNoteHashCounters: NullifiedNoteHashCounter[] = [];
63
- private encryptedLogs: EncryptedL2Log[] = [];
64
- private unencryptedLogs: UnencryptedL2Log[] = [];
60
+ private noteHashLeafIndexMap: Map<bigint, bigint> = new Map();
61
+ private nullifiedNoteHashCounters: Map<number, number> = new Map();
62
+ private encryptedLogs: CountedLog<EncryptedL2Log>[] = [];
63
+ private unencryptedLogs: CountedLog<UnencryptedL2Log>[] = [];
65
64
  private nestedExecutions: ExecutionResult[] = [];
66
65
  private enqueuedPublicFunctionCalls: PublicCallRequest[] = [];
67
66
 
@@ -76,6 +75,7 @@ export class ClientExecutionContext extends ViewDataOracle {
76
75
  authWitnesses: AuthWitness[],
77
76
  private readonly packedValuesCache: PackedValuesCache,
78
77
  private readonly noteCache: ExecutionNoteCache,
78
+ private readonly logsCache: LogsCache,
79
79
  db: DBOracle,
80
80
  private node: AztecNode,
81
81
  protected sideEffectCounter: number = 0,
@@ -112,23 +112,11 @@ export class ClientExecutionContext extends ViewDataOracle {
112
112
  }
113
113
 
114
114
  /**
115
- * This function will populate readRequestPartialWitnesses which
116
- * here is just used to flag reads as "transient" for new notes created during this execution
117
- * or to flag non-transient reads with their leafIndex.
118
- * The KernelProver will use this to fully populate witnesses and provide hints to
119
- * the kernel regarding which commitments each transient read request corresponds to.
120
- * @param noteHashReadRequests - SideEffect containing Note hashed of the notes being read and counter.
121
- * @returns An array of partially filled in read request membership witnesses.
115
+ * The KernelProver will use this to fully populate witnesses and provide hints to the kernel circuit
116
+ * regarding which note hash each settled read request corresponds to.
122
117
  */
123
- public getNoteHashReadRequestPartialWitnesses(noteHashReadRequests: SideEffect[]) {
124
- return noteHashReadRequests
125
- .filter(r => !r.isEmpty())
126
- .map(r => {
127
- const index = this.gotNotes.get(r.value.toBigInt());
128
- return index !== undefined
129
- ? NoteHashReadRequestMembershipWitness.empty(index)
130
- : NoteHashReadRequestMembershipWitness.emptyTransient();
131
- });
118
+ public getNoteHashLeafIndexMap() {
119
+ return this.noteHashLeafIndexMap;
132
120
  }
133
121
 
134
122
  /**
@@ -147,14 +135,28 @@ export class ClientExecutionContext extends ViewDataOracle {
147
135
  * Return the encrypted logs emitted during this execution.
148
136
  */
149
137
  public getEncryptedLogs() {
150
- return new EncryptedFunctionL2Logs(this.encryptedLogs);
138
+ return this.encryptedLogs;
139
+ }
140
+
141
+ /**
142
+ * Return the encrypted logs emitted during this execution and nested executions.
143
+ */
144
+ public getAllEncryptedLogs() {
145
+ return new EncryptedFunctionL2Logs(this.logsCache.getEncryptedLogs());
151
146
  }
152
147
 
153
148
  /**
154
149
  * Return the encrypted logs emitted during this execution.
155
150
  */
156
151
  public getUnencryptedLogs() {
157
- return new UnencryptedFunctionL2Logs(this.unencryptedLogs);
152
+ return this.unencryptedLogs;
153
+ }
154
+
155
+ /**
156
+ * Return the unencrypted logs emitted during this execution and nested executions.
157
+ */
158
+ public getAllUnencryptedLogs() {
159
+ return new UnencryptedFunctionL2Logs(this.logsCache.getUnencryptedLogs());
158
160
  }
159
161
 
160
162
  /**
@@ -265,7 +267,7 @@ export class ClientExecutionContext extends ViewDataOracle {
265
267
  // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1386)
266
268
  // Should always be uniqueSiloedNoteHash when publicly created notes include nonces.
267
269
  const noteHashForReadRequest = n.nonce.isZero() ? siloedNoteHash : uniqueSiloedNoteHash;
268
- this.gotNotes.set(noteHashForReadRequest.value, n.index);
270
+ this.noteHashLeafIndexMap.set(noteHashForReadRequest.toBigInt(), n.index);
269
271
  }
270
272
  });
271
273
 
@@ -321,7 +323,7 @@ export class ClientExecutionContext extends ViewDataOracle {
321
323
  innerNoteHash,
322
324
  );
323
325
  if (nullifiedNoteHashCounter !== undefined) {
324
- this.nullifiedNoteHashCounters.push({ noteHashCounter: nullifiedNoteHashCounter, nullifierCounter: counter });
326
+ this.nullifiedNoteHashCounters.set(nullifiedNoteHashCounter, counter);
325
327
  }
326
328
  return Promise.resolve();
327
329
  }
@@ -340,24 +342,45 @@ export class ClientExecutionContext extends ViewDataOracle {
340
342
  noteTypeId: Fr,
341
343
  publicKey: Point,
342
344
  log: Fr[],
345
+ counter: number,
343
346
  ) {
344
347
  const note = new Note(log);
345
348
  const l1NotePayload = new L1NotePayload(note, contractAddress, storageSlot, noteTypeId);
346
349
  const taggedNote = new TaggedNote(l1NotePayload);
347
350
  const encryptedNote = taggedNote.toEncryptedBuffer(publicKey);
348
351
  const encryptedLog = new EncryptedL2Log(encryptedNote);
349
- this.encryptedLogs.push(encryptedLog);
350
- return Fr.fromBuffer(encryptedLog.hash());
352
+ this.encryptedLogs.push(new CountedLog(encryptedLog, counter));
353
+ this.logsCache.addEncryptedLog(encryptedLog);
354
+ return encryptedNote;
351
355
  }
352
356
 
353
357
  /**
354
358
  * Emit an unencrypted log.
355
359
  * @param log - The unencrypted log to be emitted.
356
360
  */
357
- public override emitUnencryptedLog(log: UnencryptedL2Log) {
358
- this.unencryptedLogs.push(log);
361
+ public override emitUnencryptedLog(log: UnencryptedL2Log, counter: number) {
362
+ this.unencryptedLogs.push(new CountedLog(log, counter));
363
+ this.logsCache.addUnencryptedLog(log);
359
364
  const text = log.toHumanReadable();
360
365
  this.log.verbose(`Emitted unencrypted log: "${text.length > 100 ? text.slice(0, 100) + '...' : text}"`);
366
+ }
367
+
368
+ /**
369
+ * Emit a contract class unencrypted log.
370
+ * This fn exists separately from emitUnencryptedLog because sha hashing the preimage
371
+ * is too large to compile (16,200 fields, 518,400 bytes) => the oracle hashes it.
372
+ * See private_context.nr
373
+ * @param log - The unencrypted log to be emitted.
374
+ */
375
+ public override emitContractClassUnencryptedLog(log: UnencryptedL2Log, counter: number) {
376
+ this.unencryptedLogs.push(new CountedLog(log, counter));
377
+ this.logsCache.addUnencryptedLog(log);
378
+ const text = log.toHumanReadable();
379
+ this.log.verbose(
380
+ `Emitted unencrypted log from ContractClassRegisterer: "${
381
+ text.length > 100 ? text.slice(0, 100) + '...' : text
382
+ }"`,
383
+ );
361
384
  return Fr.fromBuffer(log.hash());
362
385
  }
363
386
 
@@ -419,6 +442,7 @@ export class ClientExecutionContext extends ViewDataOracle {
419
442
  this.authWitnesses,
420
443
  this.packedValuesCache,
421
444
  this.noteCache,
445
+ this.logsCache,
422
446
  this.db,
423
447
  this.node,
424
448
  sideEffectCounter,
@@ -6,7 +6,7 @@ import {
6
6
  type PublicDataWitness,
7
7
  } from '@aztec/circuit-types';
8
8
  import { type CompleteAddress, type Header } from '@aztec/circuits.js';
9
- import { type FunctionArtifactWithDebugMetadata, type FunctionSelector } from '@aztec/foundation/abi';
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, type Point } from '@aztec/foundation/fields';
12
12
  import { type ContractInstance } from '@aztec/types/contracts';
@@ -102,10 +102,7 @@ export interface DBOracle extends CommitmentsDB {
102
102
  * @param selector - The corresponding function selector.
103
103
  * @returns A Promise that resolves to a FunctionArtifact object.
104
104
  */
105
- getFunctionArtifact(
106
- contractAddress: AztecAddress,
107
- selector: FunctionSelector,
108
- ): Promise<FunctionArtifactWithDebugMetadata>;
105
+ getFunctionArtifact(contractAddress: AztecAddress, selector: FunctionSelector): Promise<FunctionArtifact>;
109
106
 
110
107
  /**
111
108
  * Retrieves the artifact of a specified function within a given contract.
@@ -115,10 +112,7 @@ export interface DBOracle extends CommitmentsDB {
115
112
  * @param functionName - The name of the function.
116
113
  * @returns The corresponding function's artifact as an object.
117
114
  */
118
- getFunctionArtifactByName(
119
- contractAddress: AztecAddress,
120
- functionName: string,
121
- ): Promise<FunctionArtifactWithDebugMetadata | undefined>;
115
+ getFunctionArtifactByName(contractAddress: AztecAddress, functionName: string): Promise<FunctionArtifact | undefined>;
122
116
 
123
117
  /**
124
118
  * Gets the index of a nullifier in the nullifier tree.