@aztec/simulator 0.32.1 → 0.34.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 (160) hide show
  1. package/README.md +5 -3
  2. package/dest/acvm/acvm.js +2 -2
  3. package/dest/acvm/oracle/index.d.ts +0 -1
  4. package/dest/acvm/oracle/index.d.ts.map +1 -1
  5. package/dest/acvm/oracle/index.js +1 -2
  6. package/dest/acvm/oracle/oracle.d.ts +1 -1
  7. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  8. package/dest/acvm/oracle/oracle.js +4 -5
  9. package/dest/avm/avm_context.d.ts +4 -14
  10. package/dest/avm/avm_context.d.ts.map +1 -1
  11. package/dest/avm/avm_context.js +10 -22
  12. package/dest/avm/avm_execution_environment.d.ts +4 -3
  13. package/dest/avm/avm_execution_environment.d.ts.map +1 -1
  14. package/dest/avm/avm_execution_environment.js +8 -7
  15. package/dest/avm/avm_gas.d.ts +71 -0
  16. package/dest/avm/avm_gas.d.ts.map +1 -0
  17. package/dest/avm/avm_gas.js +161 -0
  18. package/dest/avm/avm_machine_state.d.ts +4 -2
  19. package/dest/avm/avm_machine_state.d.ts.map +1 -1
  20. package/dest/avm/avm_machine_state.js +8 -2
  21. package/dest/avm/avm_memory_types.d.ts +53 -1
  22. package/dest/avm/avm_memory_types.d.ts.map +1 -1
  23. package/dest/avm/avm_memory_types.js +99 -6
  24. package/dest/avm/avm_simulator.d.ts.map +1 -1
  25. package/dest/avm/avm_simulator.js +15 -13
  26. package/dest/avm/fixtures/index.d.ts.map +1 -1
  27. package/dest/avm/fixtures/index.js +3 -3
  28. package/dest/avm/journal/journal.d.ts +14 -13
  29. package/dest/avm/journal/journal.d.ts.map +1 -1
  30. package/dest/avm/journal/journal.js +5 -5
  31. package/dest/avm/journal/trace.d.ts +8 -19
  32. package/dest/avm/journal/trace.d.ts.map +1 -1
  33. package/dest/avm/journal/trace.js +48 -116
  34. package/dest/avm/journal/trace_types.d.ts +23 -4
  35. package/dest/avm/journal/trace_types.d.ts.map +1 -1
  36. package/dest/avm/opcodes/accrued_substate.d.ts.map +1 -1
  37. package/dest/avm/opcodes/accrued_substate.js +45 -17
  38. package/dest/avm/opcodes/addressing_mode.d.ts +5 -3
  39. package/dest/avm/opcodes/addressing_mode.d.ts.map +1 -1
  40. package/dest/avm/opcodes/addressing_mode.js +5 -1
  41. package/dest/avm/opcodes/arithmetic.d.ts +7 -3
  42. package/dest/avm/opcodes/arithmetic.d.ts.map +1 -1
  43. package/dest/avm/opcodes/arithmetic.js +27 -16
  44. package/dest/avm/opcodes/bitwise.d.ts +21 -20
  45. package/dest/avm/opcodes/bitwise.d.ts.map +1 -1
  46. package/dest/avm/opcodes/bitwise.js +43 -65
  47. package/dest/avm/opcodes/comparators.d.ts +12 -9
  48. package/dest/avm/opcodes/comparators.d.ts.map +1 -1
  49. package/dest/avm/opcodes/comparators.js +22 -32
  50. package/dest/avm/opcodes/context_getters.d.ts +20 -0
  51. package/dest/avm/opcodes/context_getters.d.ts.map +1 -0
  52. package/dest/avm/opcodes/context_getters.js +26 -0
  53. package/dest/avm/opcodes/contract.d.ts +14 -0
  54. package/dest/avm/opcodes/contract.d.ts.map +1 -0
  55. package/dest/avm/opcodes/contract.js +49 -0
  56. package/dest/avm/opcodes/control_flow.d.ts.map +1 -1
  57. package/dest/avm/opcodes/control_flow.js +12 -2
  58. package/dest/avm/opcodes/environment_getters.d.ts +30 -33
  59. package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
  60. package/dest/avm/opcodes/environment_getters.js +34 -43
  61. package/dest/avm/opcodes/external_calls.d.ts +13 -19
  62. package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
  63. package/dest/avm/opcodes/external_calls.js +69 -72
  64. package/dest/avm/opcodes/hashing.d.ts +2 -1
  65. package/dest/avm/opcodes/hashing.d.ts.map +1 -1
  66. package/dest/avm/opcodes/hashing.js +37 -18
  67. package/dest/avm/opcodes/index.d.ts +1 -0
  68. package/dest/avm/opcodes/index.d.ts.map +1 -1
  69. package/dest/avm/opcodes/index.js +2 -1
  70. package/dest/avm/opcodes/instruction.d.ts +10 -15
  71. package/dest/avm/opcodes/instruction.d.ts.map +1 -1
  72. package/dest/avm/opcodes/instruction.js +12 -22
  73. package/dest/avm/opcodes/instruction_impl.d.ts +14 -0
  74. package/dest/avm/opcodes/instruction_impl.d.ts.map +1 -1
  75. package/dest/avm/opcodes/instruction_impl.js +37 -16
  76. package/dest/avm/opcodes/memory.d.ts +4 -3
  77. package/dest/avm/opcodes/memory.d.ts.map +1 -1
  78. package/dest/avm/opcodes/memory.js +38 -19
  79. package/dest/avm/opcodes/storage.d.ts +5 -0
  80. package/dest/avm/opcodes/storage.d.ts.map +1 -1
  81. package/dest/avm/opcodes/storage.js +21 -7
  82. package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
  83. package/dest/avm/serialization/bytecode_serialization.js +7 -5
  84. package/dest/avm/serialization/instruction_serialization.d.ts +12 -11
  85. package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
  86. package/dest/avm/serialization/instruction_serialization.js +13 -12
  87. package/dest/client/client_execution_context.d.ts +2 -2
  88. package/dest/client/client_execution_context.d.ts.map +1 -1
  89. package/dest/client/client_execution_context.js +6 -6
  90. package/dest/client/private_execution.d.ts +1 -1
  91. package/dest/client/private_execution.d.ts.map +1 -1
  92. package/dest/client/private_execution.js +8 -4
  93. package/dest/client/unconstrained_execution.d.ts +1 -1
  94. package/dest/client/unconstrained_execution.d.ts.map +1 -1
  95. package/dest/client/unconstrained_execution.js +2 -2
  96. package/dest/client/view_data_oracle.d.ts +2 -2
  97. package/dest/client/view_data_oracle.d.ts.map +1 -1
  98. package/dest/client/view_data_oracle.js +2 -2
  99. package/dest/public/executor.d.ts +2 -8
  100. package/dest/public/executor.d.ts.map +1 -1
  101. package/dest/public/executor.js +101 -69
  102. package/dest/public/index.d.ts +1 -1
  103. package/dest/public/index.d.ts.map +1 -1
  104. package/dest/public/public_execution_context.d.ts +6 -6
  105. package/dest/public/public_execution_context.d.ts.map +1 -1
  106. package/dest/public/public_execution_context.js +8 -12
  107. package/dest/public/transitional_adaptors.d.ts +32 -0
  108. package/dest/public/transitional_adaptors.d.ts.map +1 -0
  109. package/dest/public/transitional_adaptors.js +161 -0
  110. package/package.json +15 -9
  111. package/src/acvm/acvm.ts +1 -1
  112. package/src/acvm/oracle/index.ts +0 -1
  113. package/src/acvm/oracle/oracle.ts +3 -4
  114. package/src/avm/avm_context.ts +11 -33
  115. package/src/avm/avm_execution_environment.ts +9 -17
  116. package/src/avm/{avm_gas_cost.ts → avm_gas.ts} +75 -21
  117. package/src/avm/avm_machine_state.ts +9 -2
  118. package/src/avm/avm_memory_types.ts +134 -6
  119. package/src/avm/avm_simulator.ts +14 -12
  120. package/src/avm/fixtures/index.ts +2 -1
  121. package/src/avm/journal/journal.ts +24 -17
  122. package/src/avm/journal/trace.ts +59 -121
  123. package/src/avm/journal/trace_types.ts +39 -39
  124. package/src/avm/opcodes/accrued_substate.ts +58 -23
  125. package/src/avm/opcodes/addressing_mode.ts +8 -3
  126. package/src/avm/opcodes/arithmetic.ts +32 -22
  127. package/src/avm/opcodes/bitwise.ts +49 -83
  128. package/src/avm/opcodes/comparators.ts +28 -43
  129. package/src/avm/opcodes/context_getters.ts +32 -0
  130. package/src/avm/opcodes/contract.ts +58 -0
  131. package/src/avm/opcodes/control_flow.ts +23 -5
  132. package/src/avm/opcodes/environment_getters.ts +35 -44
  133. package/src/avm/opcodes/external_calls.ts +90 -89
  134. package/src/avm/opcodes/hashing.ts +45 -22
  135. package/src/avm/opcodes/index.ts +1 -0
  136. package/src/avm/opcodes/instruction.ts +14 -26
  137. package/src/avm/opcodes/instruction_impl.ts +45 -15
  138. package/src/avm/opcodes/memory.ts +48 -28
  139. package/src/avm/opcodes/storage.ts +26 -12
  140. package/src/avm/serialization/bytecode_serialization.ts +6 -3
  141. package/src/avm/serialization/instruction_serialization.ts +1 -0
  142. package/src/client/client_execution_context.ts +5 -5
  143. package/src/client/private_execution.ts +10 -4
  144. package/src/client/unconstrained_execution.ts +1 -1
  145. package/src/client/view_data_oracle.ts +1 -1
  146. package/src/public/executor.ts +123 -75
  147. package/src/public/index.ts +2 -2
  148. package/src/public/public_execution_context.ts +14 -19
  149. package/src/public/transitional_adaptors.ts +240 -0
  150. package/dest/acvm/oracle/debug.d.ts +0 -19
  151. package/dest/acvm/oracle/debug.d.ts.map +0 -1
  152. package/dest/acvm/oracle/debug.js +0 -95
  153. package/dest/avm/avm_gas_cost.d.ts +0 -322
  154. package/dest/avm/avm_gas_cost.d.ts.map +0 -1
  155. package/dest/avm/avm_gas_cost.js +0 -118
  156. package/dest/avm/temporary_executor_migration.d.ts +0 -25
  157. package/dest/avm/temporary_executor_migration.d.ts.map +0 -1
  158. package/dest/avm/temporary_executor_migration.js +0 -83
  159. package/src/acvm/oracle/debug.ts +0 -109
  160. package/src/avm/temporary_executor_migration.ts +0 -122
@@ -1,10 +1,12 @@
1
1
  import { toBufferBE } from '@aztec/foundation/bigint-buffer';
2
2
  import { Fr } from '@aztec/foundation/fields';
3
3
  import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';
4
+ import { type FunctionsOf } from '@aztec/foundation/types';
4
5
 
5
6
  import { strict as assert } from 'assert';
6
7
 
7
- import { TagCheckError } from './errors.js';
8
+ import { InstructionExecutionError, TagCheckError } from './errors.js';
9
+ import { Addressing, AddressingMode } from './opcodes/addressing_mode.js';
8
10
 
9
11
  /** MemoryValue gathers the common operations for all memory types. */
10
12
  export abstract class MemoryValue {
@@ -30,6 +32,11 @@ export abstract class MemoryValue {
30
32
  return new Fr(this.toBigInt());
31
33
  }
32
34
 
35
+ // To number. Throws if exceeds max safe int.
36
+ public toNumber(): number {
37
+ return this.toFr().toNumber();
38
+ }
39
+
33
40
  public toString(): string {
34
41
  return `${this.constructor.name}(0x${this.toBigInt().toString(16)})`;
35
42
  }
@@ -198,10 +205,16 @@ export enum TypeTag {
198
205
  INVALID,
199
206
  }
200
207
 
208
+ // Lazy interface definition for tagged memory
209
+ export type TaggedMemoryInterface = FunctionsOf<TaggedMemory>;
210
+
201
211
  // TODO: Consider automatic conversion when getting undefined values.
202
- export class TaggedMemory {
212
+ export class TaggedMemory implements TaggedMemoryInterface {
203
213
  static readonly log: DebugLogger = createDebugLogger('aztec:avm_simulator:memory');
204
214
 
215
+ // Whether to track and validate memory accesses for each instruction.
216
+ static readonly TRACK_MEMORY_ACCESSES = process.env.NODE_ENV === 'test';
217
+
205
218
  // FIXME: memory should be 2^32, but TS doesn't allow for arrays that big.
206
219
  static readonly MAX_MEMORY_SIZE = Number((1n << 32n) - 2n);
207
220
  private _mem: MemoryValue[];
@@ -211,6 +224,11 @@ export class TaggedMemory {
211
224
  this._mem = [];
212
225
  }
213
226
 
227
+ /** Returns a MeteredTaggedMemory instance to track the number of reads and writes if TRACK_MEMORY_ACCESSES is set. */
228
+ public track(type: string = 'instruction') {
229
+ return TaggedMemory.TRACK_MEMORY_ACCESSES ? new MeteredTaggedMemory(this, type) : this;
230
+ }
231
+
214
232
  public get(offset: number): MemoryValue {
215
233
  assert(offset < TaggedMemory.MAX_MEMORY_SIZE);
216
234
  const value = this.getAs<MemoryValue>(offset);
@@ -220,7 +238,10 @@ export class TaggedMemory {
220
238
  public getAs<T>(offset: number): T {
221
239
  assert(offset < TaggedMemory.MAX_MEMORY_SIZE);
222
240
  const word = this._mem[offset];
223
- TaggedMemory.log(`get(${offset}) = ${word}`);
241
+ TaggedMemory.log.debug(`get(${offset}) = ${word}`);
242
+ if (word === undefined) {
243
+ TaggedMemory.log.warn(`Memory at offset ${offset} is undefined! This might be OK if it's stack dumping.`);
244
+ }
224
245
  return word as T;
225
246
  }
226
247
 
@@ -228,7 +249,8 @@ export class TaggedMemory {
228
249
  assert(offset < TaggedMemory.MAX_MEMORY_SIZE);
229
250
  assert(offset + size < TaggedMemory.MAX_MEMORY_SIZE);
230
251
  const value = this._mem.slice(offset, offset + size);
231
- TaggedMemory.log(`getSlice(${offset}, ${size}) = ${value}`);
252
+ TaggedMemory.log.debug(`getSlice(${offset}, ${size}) = ${value}`);
253
+ assert(!value.some(e => e === undefined), 'Memory slice contains undefined values.');
232
254
  assert(value.length === size, `Expected slice of size ${size}, got ${value.length}.`);
233
255
  return value;
234
256
  }
@@ -248,7 +270,7 @@ export class TaggedMemory {
248
270
  public set(offset: number, v: MemoryValue) {
249
271
  assert(offset < TaggedMemory.MAX_MEMORY_SIZE);
250
272
  this._mem[offset] = v;
251
- TaggedMemory.log(`set(${offset}, ${v})`);
273
+ TaggedMemory.log.debug(`set(${offset}, ${v})`);
252
274
  }
253
275
 
254
276
  public setSlice(offset: number, vs: MemoryValue[]) {
@@ -259,7 +281,7 @@ export class TaggedMemory {
259
281
  this._mem.length = offset + vs.length;
260
282
  }
261
283
  this._mem.splice(offset, vs.length, ...vs);
262
- TaggedMemory.log(`setSlice(${offset}, ${vs})`);
284
+ TaggedMemory.log.debug(`setSlice(${offset}, ${vs})`);
263
285
  }
264
286
 
265
287
  public getTag(offset: number): TypeTag {
@@ -367,4 +389,110 @@ export class TaggedMemory {
367
389
  throw new Error(`${TypeTag[tag]} is not a valid integral type.`);
368
390
  }
369
391
  }
392
+
393
+ /** No-op. Implemented here for compatibility with the MeteredTaggedMemory. */
394
+ public assert(_operations: Partial<MemoryOperations & { indirect: number }>) {}
395
+ }
396
+
397
+ /** Tagged memory wrapper with metering for each memory read and write operation. */
398
+ export class MeteredTaggedMemory implements TaggedMemoryInterface {
399
+ private reads: number = 0;
400
+ private writes: number = 0;
401
+
402
+ constructor(private wrapped: TaggedMemory, private type: string = 'instruction') {}
403
+
404
+ /** Returns the number of reads and writes tracked so far and resets them to zero. */
405
+ public reset(): MemoryOperations {
406
+ const stats = { reads: this.reads, writes: this.writes };
407
+ this.reads = 0;
408
+ this.writes = 0;
409
+ return stats;
410
+ }
411
+
412
+ /**
413
+ * Asserts that the exact number of memory operations have been performed.
414
+ * Indirect represents the flags for indirect accesses: each bit set to one counts as an extra read.
415
+ */
416
+ public assert(operations: Partial<MemoryOperations & { indirect: number }>) {
417
+ const { reads: expectedReads, writes: expectedWrites, indirect } = { reads: 0, writes: 0, ...operations };
418
+
419
+ const totalExpectedReads = expectedReads + Addressing.fromWire(indirect ?? 0).count(AddressingMode.INDIRECT);
420
+ const { reads: actualReads, writes: actualWrites } = this.reset();
421
+ if (actualReads !== totalExpectedReads) {
422
+ throw new InstructionExecutionError(
423
+ `Incorrect number of memory reads for ${this.type}: expected ${totalExpectedReads} but executed ${actualReads}`,
424
+ );
425
+ }
426
+ if (actualWrites !== expectedWrites) {
427
+ throw new InstructionExecutionError(
428
+ `Incorrect number of memory writes for ${this.type}: expected ${expectedWrites} but executed ${actualWrites}`,
429
+ );
430
+ }
431
+ }
432
+
433
+ public track(type: string = 'instruction'): MeteredTaggedMemory {
434
+ return new MeteredTaggedMemory(this.wrapped, type);
435
+ }
436
+
437
+ public get(offset: number): MemoryValue {
438
+ this.reads++;
439
+ return this.wrapped.get(offset);
440
+ }
441
+
442
+ public getSliceAs<T>(offset: number, size: number): T[] {
443
+ this.reads += size;
444
+ return this.wrapped.getSliceAs<T>(offset, size);
445
+ }
446
+
447
+ public getAs<T>(offset: number): T {
448
+ this.reads++;
449
+ return this.wrapped.getAs(offset);
450
+ }
451
+
452
+ public getSlice(offset: number, size: number): MemoryValue[] {
453
+ this.reads += size;
454
+ return this.wrapped.getSlice(offset, size);
455
+ }
456
+
457
+ public set(offset: number, v: MemoryValue): void {
458
+ this.writes++;
459
+ this.wrapped.set(offset, v);
460
+ }
461
+
462
+ public setSlice(offset: number, vs: MemoryValue[]): void {
463
+ this.writes += vs.length;
464
+ this.wrapped.setSlice(offset, vs);
465
+ }
466
+
467
+ public getSliceTags(offset: number, size: number): TypeTag[] {
468
+ return this.wrapped.getSliceTags(offset, size);
469
+ }
470
+
471
+ public getTag(offset: number): TypeTag {
472
+ return this.wrapped.getTag(offset);
473
+ }
474
+
475
+ public checkTag(tag: TypeTag, offset: number): void {
476
+ this.wrapped.checkTag(tag, offset);
477
+ }
478
+
479
+ public checkIsValidMemoryOffsetTag(offset: number): void {
480
+ this.wrapped.checkIsValidMemoryOffsetTag(offset);
481
+ }
482
+
483
+ public checkTags(tag: TypeTag, ...offsets: number[]): void {
484
+ this.wrapped.checkTags(tag, ...offsets);
485
+ }
486
+
487
+ public checkTagsRange(tag: TypeTag, startOffset: number, size: number): void {
488
+ this.wrapped.checkTagsRange(tag, startOffset, size);
489
+ }
370
490
  }
491
+
492
+ /** Tracks number of memory reads and writes. */
493
+ export type MemoryOperations = {
494
+ /** How many total reads are performed. Slice reads are count as one per element. */
495
+ reads: number;
496
+ /** How many total writes are performed. Slice writes are count as one per element. */
497
+ writes: number;
498
+ };
@@ -50,43 +50,45 @@ export class AvmSimulator {
50
50
  */
51
51
  public async executeInstructions(instructions: Instruction[]): Promise<AvmContractCallResults> {
52
52
  assert(instructions.length > 0);
53
+ const { machineState } = this.context;
53
54
  try {
54
55
  // Execute instruction pointed to by the current program counter
55
56
  // continuing until the machine state signifies a halt
56
- while (!this.context.machineState.halted) {
57
- const instruction = instructions[this.context.machineState.pc];
57
+ while (!machineState.halted) {
58
+ const instruction = instructions[machineState.pc];
58
59
  assert(
59
60
  !!instruction,
60
61
  'AVM attempted to execute non-existent instruction. This should never happen (invalid bytecode or AVM simulator bug)!',
61
62
  );
62
63
 
63
- this.log.debug(`@${this.context.machineState.pc} ${instruction.toString()}`);
64
+ const gasLeft = `l1=${machineState.l1GasLeft} l2=${machineState.l2GasLeft} da=${machineState.daGasLeft}`;
65
+ this.log.debug(`@${machineState.pc} (${gasLeft}) ${instruction.toString()}`);
64
66
  // Execute the instruction.
65
67
  // Normal returns and reverts will return normally here.
66
68
  // "Exceptional halts" will throw.
67
- await instruction.run(this.context);
69
+ await instruction.execute(this.context);
68
70
 
69
- if (this.context.machineState.pc >= instructions.length) {
70
- this.log('Passed end of program!');
71
- throw new InvalidProgramCounterError(this.context.machineState.pc, /*max=*/ instructions.length);
71
+ if (machineState.pc >= instructions.length) {
72
+ this.log.warn('Passed end of program');
73
+ throw new InvalidProgramCounterError(machineState.pc, /*max=*/ instructions.length);
72
74
  }
73
75
  }
74
76
 
75
77
  // Return results for processing by calling context
76
- const results = this.context.machineState.getResults();
77
- this.log(`Context execution results: ${results.toString()}`);
78
+ const results = machineState.getResults();
79
+ this.log.debug(`Context execution results: ${results.toString()}`);
78
80
  return results;
79
81
  } catch (e) {
80
- this.log('Exceptional halt');
82
+ this.log.verbose('Exceptional halt');
81
83
  if (!(e instanceof AvmExecutionError)) {
82
- this.log(`Unknown error thrown by avm: ${e}`);
84
+ this.log.verbose(`Unknown error thrown by avm: ${e}`);
83
85
  throw e;
84
86
  }
85
87
 
86
88
  // Return results for processing by calling context
87
89
  // Note: "exceptional halts" cannot return data
88
90
  const results = new AvmContractCallResults(/*reverted=*/ true, /*output=*/ [], /*revertReason=*/ e);
89
- this.log(`Context execution results: ${results.toString()}`);
91
+ this.log.debug(`Context execution results: ${results.toString()}`);
90
92
  return results;
91
93
  }
92
94
  }
@@ -1,5 +1,5 @@
1
1
  import { SiblingPath } from '@aztec/circuit-types';
2
- import { GlobalVariables, L1_TO_L2_MSG_TREE_HEIGHT } from '@aztec/circuits.js';
2
+ import { GlobalVariables, Header, L1_TO_L2_MSG_TREE_HEIGHT } from '@aztec/circuits.js';
3
3
  import { FunctionSelector } from '@aztec/foundation/abi';
4
4
  import { AztecAddress } from '@aztec/foundation/aztec-address';
5
5
  import { EthAddress } from '@aztec/foundation/eth-address';
@@ -67,6 +67,7 @@ export function initExecutionEnvironment(overrides?: Partial<AvmExecutionEnviron
67
67
  overrides?.feePerL2Gas ?? Fr.zero(),
68
68
  overrides?.feePerDaGas ?? Fr.zero(),
69
69
  overrides?.contractCallDepth ?? Fr.zero(),
70
+ overrides?.header ?? Header.empty(),
70
71
  overrides?.globals ?? GlobalVariables.empty(),
71
72
  overrides?.isStaticCall ?? false,
72
73
  overrides?.isDelegateCall ?? false,
@@ -7,16 +7,27 @@ import { type HostStorage } from './host_storage.js';
7
7
  import { Nullifiers } from './nullifiers.js';
8
8
  import { PublicStorage } from './public_storage.js';
9
9
  import { WorldStateAccessTrace } from './trace.js';
10
- import { type TracedL1toL2MessageCheck, type TracedNoteHashCheck, type TracedNullifierCheck } from './trace_types.js';
10
+ import {
11
+ type TracedL1toL2MessageCheck,
12
+ type TracedNoteHash,
13
+ type TracedNoteHashCheck,
14
+ type TracedNullifier,
15
+ type TracedNullifierCheck,
16
+ type TracedPublicStorageRead,
17
+ type TracedPublicStorageWrite,
18
+ } from './trace_types.js';
11
19
 
12
20
  /**
13
21
  * Data held within the journal
14
22
  */
15
23
  export type JournalData = {
24
+ storageWrites: TracedPublicStorageWrite[];
25
+ storageReads: TracedPublicStorageRead[];
26
+
16
27
  noteHashChecks: TracedNoteHashCheck[];
17
- newNoteHashes: Fr[];
28
+ newNoteHashes: TracedNoteHash[];
18
29
  nullifierChecks: TracedNullifierCheck[];
19
- newNullifiers: Fr[];
30
+ newNullifiers: TracedNullifier[];
20
31
  l1ToL2MessageChecks: TracedL1toL2MessageCheck[];
21
32
 
22
33
  newL1Messages: L2ToL1Message[];
@@ -24,11 +35,6 @@ export type JournalData = {
24
35
 
25
36
  /** contract address -\> key -\> value */
26
37
  currentStorageValue: Map<bigint, Map<bigint, Fr>>;
27
-
28
- /** contract address -\> key -\> value[] (stored in order of access) */
29
- storageWrites: Map<bigint, Map<bigint, Fr[]>>;
30
- /** contract address -\> key -\> value[] (stored in order of access) */
31
- storageReads: Map<bigint, Map<bigint, Fr[]>>;
32
38
  };
33
39
 
34
40
  /**
@@ -44,18 +50,19 @@ export class AvmPersistableStateManager {
44
50
  /** Reference to node storage */
45
51
  public readonly hostStorage: HostStorage;
46
52
 
53
+ // TODO: make members private once this is not used in transitional_adaptors.ts.
47
54
  /** World State */
48
55
  /** Public storage, including cached writes */
49
- private publicStorage: PublicStorage;
56
+ public publicStorage: PublicStorage;
50
57
  /** Nullifier set, including cached/recently-emitted nullifiers */
51
- private nullifiers: Nullifiers;
58
+ public nullifiers: Nullifiers;
52
59
 
53
60
  /** World State Access Trace */
54
- private trace: WorldStateAccessTrace;
61
+ public trace: WorldStateAccessTrace;
55
62
 
56
63
  /** Accrued Substate **/
57
- private newL1Messages: L2ToL1Message[] = [];
58
- private newLogs: UnencryptedL2Log[] = [];
64
+ public newL1Messages: L2ToL1Message[] = [];
65
+ public newLogs: UnencryptedL2Log[] = [];
59
66
 
60
67
  constructor(hostStorage: HostStorage, parent?: AvmPersistableStateManager) {
61
68
  this.hostStorage = hostStorage;
@@ -93,9 +100,9 @@ export class AvmPersistableStateManager {
93
100
  * @returns the latest value written to slot, or 0 if never written to before
94
101
  */
95
102
  public async readStorage(storageAddress: Fr, slot: Fr): Promise<Fr> {
96
- const [_exists, value] = await this.publicStorage.read(storageAddress, slot);
103
+ const [exists, value] = await this.publicStorage.read(storageAddress, slot);
97
104
  // We want to keep track of all performed reads (even reverted ones)
98
- this.trace.tracePublicStorageRead(storageAddress, slot, value);
105
+ this.trace.tracePublicStorageRead(storageAddress, slot, value, exists);
99
106
  return Promise.resolve(value);
100
107
  }
101
108
 
@@ -119,8 +126,8 @@ export class AvmPersistableStateManager {
119
126
  * Write a note hash, trace the write.
120
127
  * @param noteHash - the unsiloed note hash to write
121
128
  */
122
- public writeNoteHash(noteHash: Fr) {
123
- this.trace.traceNewNoteHash(/*storageAddress*/ Fr.ZERO, noteHash);
129
+ public writeNoteHash(storageAddress: Fr, noteHash: Fr) {
130
+ this.trace.traceNewNoteHash(storageAddress, noteHash);
124
131
  }
125
132
 
126
133
  /**
@@ -1,23 +1,28 @@
1
1
  import { Fr } from '@aztec/foundation/fields';
2
2
 
3
- import { type TracedL1toL2MessageCheck, type TracedNoteHashCheck, type TracedNullifierCheck } from './trace_types.js';
3
+ import {
4
+ type TracedL1toL2MessageCheck,
5
+ type TracedNoteHash,
6
+ type TracedNoteHashCheck,
7
+ type TracedNullifier,
8
+ type TracedNullifierCheck,
9
+ type TracedPublicStorageRead,
10
+ type TracedPublicStorageWrite,
11
+ } from './trace_types.js';
4
12
 
5
13
  export class WorldStateAccessTrace {
6
14
  public accessCounter: number;
7
- //public contractCalls: Array<TracedContractCall> = [];
8
15
 
9
- //public publicStorageReads: Array<TracedPublicStorageRead> = [];
10
- public publicStorageReads: Map<bigint, Map<bigint, Fr[]>> = new Map();
11
- //public publicStorageWrites: Array<TracedPublicStorageWrite> = [];
12
- public publicStorageWrites: Map<bigint, Map<bigint, Fr[]>> = new Map();
16
+ public publicStorageReads: TracedPublicStorageRead[] = [];
17
+ public publicStorageWrites: TracedPublicStorageWrite[] = [];
13
18
 
14
19
  public noteHashChecks: TracedNoteHashCheck[] = [];
15
- //public newNoteHashes: TracedNoteHash[] = [];
16
- public newNoteHashes: Fr[] = [];
20
+ public newNoteHashes: TracedNoteHash[] = [];
17
21
  public nullifierChecks: TracedNullifierCheck[] = [];
18
- //public newNullifiers: TracedNullifier[] = [];
19
- public newNullifiers: Fr[] = [];
22
+ public newNullifiers: TracedNullifier[] = [];
20
23
  public l1ToL2MessageChecks: TracedL1toL2MessageCheck[] = [];
24
+
25
+ //public contractCalls: TracedContractCall[] = [];
21
26
  //public archiveChecks: TracedArchiveLeafCheck[] = [];
22
27
 
23
28
  constructor(parentTrace?: WorldStateAccessTrace) {
@@ -28,76 +33,73 @@ export class WorldStateAccessTrace {
28
33
  return this.accessCounter;
29
34
  }
30
35
 
31
- public tracePublicStorageRead(storageAddress: Fr, slot: Fr, value: Fr /*, _exists: boolean*/) {
36
+ public tracePublicStorageRead(storageAddress: Fr, slot: Fr, value: Fr, exists: boolean) {
32
37
  // TODO(4805): check if some threshold is reached for max storage reads
33
38
  // (need access to parent length, or trace needs to be initialized with parent's contents)
34
- //const traced: TracedPublicStorageRead = {
35
- // callPointer: Fr.ZERO,
36
- // storageAddress,
37
- // slot,
38
- // value,
39
- // exists,
40
- // counter: new Fr(this.accessCounter),
41
- // endLifetime: Fr.ZERO,
42
- //};
43
- //this.publicStorageReads.push(traced);
44
- this.journalRead(storageAddress, slot, value);
39
+ const traced: TracedPublicStorageRead = {
40
+ // callPointer: Fr.ZERO,
41
+ storageAddress,
42
+ slot,
43
+ value,
44
+ exists,
45
+ counter: new Fr(this.accessCounter),
46
+ // endLifetime: Fr.ZERO,
47
+ };
48
+ this.publicStorageReads.push(traced);
45
49
  this.incrementAccessCounter();
46
50
  }
47
51
 
48
52
  public tracePublicStorageWrite(storageAddress: Fr, slot: Fr, value: Fr) {
49
53
  // TODO(4805): check if some threshold is reached for max storage writes
50
54
  // (need access to parent length, or trace needs to be initialized with parent's contents)
51
- //const traced: TracedPublicStorageWrite = {
52
- // callPointer: Fr.ZERO,
53
- // storageAddress,
54
- // slot,
55
- // value,
56
- // counter: new Fr(this.accessCounter),
57
- // endLifetime: Fr.ZERO,
58
- //};
59
- //this.publicStorageWrites.push(traced);
60
- this.journalWrite(storageAddress, slot, value);
55
+ const traced: TracedPublicStorageWrite = {
56
+ // callPointer: Fr.ZERO,
57
+ storageAddress,
58
+ slot,
59
+ value,
60
+ counter: new Fr(this.accessCounter),
61
+ // endLifetime: Fr.ZERO,
62
+ };
63
+ this.publicStorageWrites.push(traced);
61
64
  this.incrementAccessCounter();
62
65
  }
63
66
 
64
67
  public traceNoteHashCheck(storageAddress: Fr, noteHash: Fr, exists: boolean, leafIndex: Fr) {
65
68
  const traced: TracedNoteHashCheck = {
66
- callPointer: Fr.ZERO, // FIXME
69
+ // callPointer: Fr.ZERO,
67
70
  storageAddress,
68
71
  noteHash,
69
72
  exists,
70
73
  counter: new Fr(this.accessCounter),
71
- endLifetime: Fr.ZERO,
74
+ // endLifetime: Fr.ZERO,
72
75
  leafIndex,
73
76
  };
74
77
  this.noteHashChecks.push(traced);
75
78
  this.incrementAccessCounter();
76
79
  }
77
80
 
78
- public traceNewNoteHash(_storageAddress: Fr, noteHash: Fr) {
81
+ public traceNewNoteHash(storageAddress: Fr, noteHash: Fr) {
79
82
  // TODO(4805): check if some threshold is reached for max new note hash
80
- //const traced: TracedNoteHash = {
81
- // callPointer: Fr.ZERO,
82
- // storageAddress,
83
- // noteHash,
84
- // counter: new Fr(this.accessCounter),
85
- // endLifetime: Fr.ZERO,
86
- //};
87
- //this.newNoteHashes.push(traced);
88
- this.newNoteHashes.push(noteHash);
83
+ const traced: TracedNoteHash = {
84
+ // callPointer: Fr.ZERO,
85
+ storageAddress,
86
+ noteHash,
87
+ counter: new Fr(this.accessCounter),
88
+ // endLifetime: Fr.ZERO,
89
+ };
90
+ this.newNoteHashes.push(traced);
89
91
  this.incrementAccessCounter();
90
92
  }
91
93
 
92
94
  public traceNullifierCheck(storageAddress: Fr, nullifier: Fr, exists: boolean, isPending: boolean, leafIndex: Fr) {
93
95
  // TODO(4805): check if some threshold is reached for max new nullifier
94
96
  const traced: TracedNullifierCheck = {
95
- callPointer: Fr.ZERO, // FIXME
97
+ // callPointer: Fr.ZERO,
96
98
  storageAddress,
97
99
  nullifier,
98
100
  exists,
99
101
  counter: new Fr(this.accessCounter),
100
- endLifetime: Fr.ZERO,
102
+ // endLifetime: Fr.ZERO,
101
103
  isPending,
102
104
  leafIndex,
103
105
  };
@@ -105,17 +107,16 @@ export class WorldStateAccessTrace {
105
107
  this.incrementAccessCounter();
106
108
  }
107
109
 
108
- public traceNewNullifier(_storageAddress: Fr, nullifier: Fr) {
110
+ public traceNewNullifier(storageAddress: Fr, nullifier: Fr) {
109
111
  // TODO(4805): check if some threshold is reached for max new nullifier
110
- //const traced: TracedNullifier = {
111
- // callPointer: Fr.ZERO,
112
- // storageAddress,
113
- // nullifier,
114
- // counter: new Fr(this.accessCounter),
115
- // endLifetime: Fr.ZERO,
116
- //};
117
- //this.newNullifiers.push(traced);
118
- this.newNullifiers.push(nullifier);
112
+ const tracedNullifier: TracedNullifier = {
113
+ // callPointer: Fr.ZERO,
114
+ storageAddress,
115
+ nullifier,
116
+ counter: new Fr(this.accessCounter),
117
+ // endLifetime: Fr.ZERO,
118
+ };
119
+ this.newNullifiers.push(tracedNullifier);
119
120
  this.incrementAccessCounter();
120
121
  }
121
122
 
@@ -146,8 +147,8 @@ export class WorldStateAccessTrace {
146
147
  */
147
148
  public acceptAndMerge(incomingTrace: WorldStateAccessTrace) {
148
149
  // Merge storage read and write journals
149
- mergeContractJournalMaps(this.publicStorageReads, incomingTrace.publicStorageReads);
150
- mergeContractJournalMaps(this.publicStorageWrites, incomingTrace.publicStorageWrites);
150
+ this.publicStorageReads = this.publicStorageReads.concat(incomingTrace.publicStorageReads);
151
+ this.publicStorageWrites = this.publicStorageWrites.concat(incomingTrace.publicStorageWrites);
151
152
  // Merge new note hashes and nullifiers
152
153
  this.noteHashChecks = this.noteHashChecks.concat(incomingTrace.noteHashChecks);
153
154
  this.newNoteHashes = this.newNoteHashes.concat(incomingTrace.newNoteHashes);
@@ -157,67 +158,4 @@ export class WorldStateAccessTrace {
157
158
  // it is assumed that the incoming trace was initialized with this as parent, so accept counter
158
159
  this.accessCounter = incomingTrace.accessCounter;
159
160
  }
160
-
161
- /**
162
- * We want to keep track of all performed reads in the journal
163
- * This information is hinted to the avm circuit
164
-
165
- * @param contractAddress -
166
- * @param key -
167
- * @param value -
168
- */
169
- journalUpdate(map: Map<bigint, Map<bigint, Fr[]>>, contractAddress: Fr, key: Fr, value: Fr): void {
170
- let contractMap = map.get(contractAddress.toBigInt());
171
- if (!contractMap) {
172
- contractMap = new Map<bigint, Array<Fr>>();
173
- map.set(contractAddress.toBigInt(), contractMap);
174
- }
175
-
176
- let accessArray = contractMap.get(key.toBigInt());
177
- if (!accessArray) {
178
- accessArray = new Array<Fr>();
179
- contractMap.set(key.toBigInt(), accessArray);
180
- }
181
- accessArray.push(value);
182
- }
183
-
184
- // Create an instance of journalUpdate that appends to the read array
185
- private journalRead = this.journalUpdate.bind(this, this.publicStorageReads);
186
- // Create an instance of journalUpdate that appends to the writes array
187
- private journalWrite = this.journalUpdate.bind(this, this.publicStorageWrites);
188
- }
189
-
190
- /**
191
- * Merges two contract journalling maps together
192
- * For read maps, we just append the childMap arrays into the host map arrays, as the order is important
193
- *
194
- * @param hostMap - The map to be merged into
195
- * @param childMap - The map to be merged from
196
- */
197
- function mergeContractJournalMaps(hostMap: Map<bigint, Map<bigint, Fr[]>>, childMap: Map<bigint, Map<bigint, Fr[]>>) {
198
- for (const [key, value] of childMap) {
199
- const map1Value = hostMap.get(key);
200
- if (!map1Value) {
201
- hostMap.set(key, value);
202
- } else {
203
- mergeStorageJournalMaps(map1Value, value);
204
- }
205
- }
206
- }
207
-
208
- /**
209
- * Merge two storage journalling maps together (for a particular contract).
210
- *
211
- * @param hostMap - The map to be merge into
212
- * @param childMap - The map to be merged from
213
- */
214
- function mergeStorageJournalMaps(hostMap: Map<bigint, Fr[]>, childMap: Map<bigint, Fr[]>) {
215
- for (const [key, value] of childMap) {
216
- const readArr = hostMap.get(key);
217
- if (!readArr) {
218
- hostMap.set(key, value);
219
- } else {
220
- hostMap.set(key, readArr?.concat(...value));
221
- }
222
- }
223
161
  }