@aztec/simulator 0.23.0 → 0.24.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 (123) hide show
  1. package/dest/acvm/oracle/oracle.d.ts +2 -2
  2. package/dest/acvm/oracle/oracle.d.ts.map +1 -1
  3. package/dest/acvm/oracle/oracle.js +5 -5
  4. package/dest/acvm/oracle/typed_oracle.d.ts +2 -2
  5. package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
  6. package/dest/acvm/oracle/typed_oracle.js +3 -3
  7. package/dest/avm/avm_execution_environment.d.ts +3 -2
  8. package/dest/avm/avm_execution_environment.d.ts.map +1 -1
  9. package/dest/avm/avm_execution_environment.js +6 -5
  10. package/dest/avm/avm_memory_types.d.ts +119 -38
  11. package/dest/avm/avm_memory_types.d.ts.map +1 -1
  12. package/dest/avm/avm_memory_types.js +91 -109
  13. package/dest/avm/avm_simulator.d.ts.map +1 -1
  14. package/dest/avm/avm_simulator.js +2 -3
  15. package/dest/avm/errors.d.ts +3 -1
  16. package/dest/avm/errors.d.ts.map +1 -1
  17. package/dest/avm/errors.js +9 -3
  18. package/dest/avm/fixtures/index.d.ts +4 -0
  19. package/dest/avm/fixtures/index.d.ts.map +1 -1
  20. package/dest/avm/fixtures/index.js +10 -2
  21. package/dest/avm/journal/host_storage.d.ts +1 -1
  22. package/dest/avm/journal/host_storage.d.ts.map +1 -1
  23. package/dest/avm/opcodes/addressing_mode.d.ts +24 -0
  24. package/dest/avm/opcodes/addressing_mode.d.ts.map +1 -0
  25. package/dest/avm/opcodes/addressing_mode.js +62 -0
  26. package/dest/avm/opcodes/comparators.d.ts.map +1 -1
  27. package/dest/avm/opcodes/comparators.js +8 -5
  28. package/dest/avm/opcodes/instruction.d.ts +4 -4
  29. package/dest/avm/opcodes/instruction.d.ts.map +1 -1
  30. package/dest/avm/opcodes/instruction.js +1 -1
  31. package/dest/avm/opcodes/memory.d.ts.map +1 -1
  32. package/dest/avm/opcodes/memory.js +5 -3
  33. package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
  34. package/dest/avm/serialization/bytecode_serialization.js +24 -22
  35. package/dest/avm/serialization/instruction_serialization.d.ts +17 -15
  36. package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
  37. package/dest/avm/serialization/instruction_serialization.js +18 -16
  38. package/dest/avm/temporary_executor_migration.d.ts +25 -0
  39. package/dest/avm/temporary_executor_migration.d.ts.map +1 -0
  40. package/dest/avm/temporary_executor_migration.js +71 -0
  41. package/dest/client/client_execution_context.d.ts +4 -2
  42. package/dest/client/client_execution_context.d.ts.map +1 -1
  43. package/dest/client/client_execution_context.js +7 -4
  44. package/dest/client/execution_result.d.ts +2 -0
  45. package/dest/client/execution_result.d.ts.map +1 -1
  46. package/dest/client/execution_result.js +1 -1
  47. package/dest/client/simulator.d.ts +10 -5
  48. package/dest/client/simulator.d.ts.map +1 -1
  49. package/dest/client/simulator.js +19 -11
  50. package/dest/client/unconstrained_execution.js +2 -2
  51. package/dest/public/execution.js +2 -2
  52. package/dest/public/executor.d.ts +7 -0
  53. package/dest/public/executor.d.ts.map +1 -1
  54. package/dest/public/executor.js +26 -1
  55. package/dest/public/public_execution_context.js +2 -2
  56. package/dest/public/state_actions.d.ts +1 -1
  57. package/dest/public/state_actions.d.ts.map +1 -1
  58. package/dest/public/state_actions.js +5 -6
  59. package/dest/utils.d.ts +5 -20
  60. package/dest/utils.d.ts.map +1 -1
  61. package/dest/utils.js +4 -20
  62. package/package.json +7 -5
  63. package/src/acvm/acvm.ts +156 -0
  64. package/src/acvm/acvm_types.ts +11 -0
  65. package/src/acvm/deserialize.ts +36 -0
  66. package/src/acvm/index.ts +5 -0
  67. package/src/acvm/oracle/debug.ts +109 -0
  68. package/src/acvm/oracle/index.ts +17 -0
  69. package/src/acvm/oracle/oracle.ts +332 -0
  70. package/src/acvm/oracle/typed_oracle.ts +217 -0
  71. package/src/acvm/serialize.ts +75 -0
  72. package/src/avm/avm_context.ts +63 -0
  73. package/src/avm/avm_execution_environment.ts +98 -0
  74. package/src/avm/avm_machine_state.ts +93 -0
  75. package/src/avm/avm_memory_types.ts +309 -0
  76. package/src/avm/avm_message_call_result.ts +29 -0
  77. package/src/avm/avm_simulator.ts +89 -0
  78. package/src/avm/errors.ts +57 -0
  79. package/src/avm/fixtures/index.ts +90 -0
  80. package/src/avm/journal/host_storage.ts +20 -0
  81. package/src/avm/journal/index.ts +2 -0
  82. package/src/avm/journal/journal.ts +266 -0
  83. package/src/avm/opcodes/.eslintrc.cjs +8 -0
  84. package/src/avm/opcodes/accrued_substate.ts +92 -0
  85. package/src/avm/opcodes/addressing_mode.ts +66 -0
  86. package/src/avm/opcodes/arithmetic.ts +79 -0
  87. package/src/avm/opcodes/bitwise.ts +129 -0
  88. package/src/avm/opcodes/comparators.ts +72 -0
  89. package/src/avm/opcodes/control_flow.ts +129 -0
  90. package/src/avm/opcodes/environment_getters.ts +199 -0
  91. package/src/avm/opcodes/external_calls.ts +122 -0
  92. package/src/avm/opcodes/index.ts +10 -0
  93. package/src/avm/opcodes/instruction.ts +64 -0
  94. package/src/avm/opcodes/instruction_impl.ts +52 -0
  95. package/src/avm/opcodes/memory.ts +193 -0
  96. package/src/avm/opcodes/storage.ts +76 -0
  97. package/src/avm/serialization/buffer_cursor.ts +109 -0
  98. package/src/avm/serialization/bytecode_serialization.ts +172 -0
  99. package/src/avm/serialization/instruction_serialization.ts +167 -0
  100. package/src/avm/temporary_executor_migration.ts +108 -0
  101. package/src/client/client_execution_context.ts +472 -0
  102. package/src/client/db_oracle.ts +184 -0
  103. package/src/client/execution_note_cache.ts +90 -0
  104. package/src/client/execution_result.ts +89 -0
  105. package/src/client/index.ts +3 -0
  106. package/src/client/pick_notes.ts +125 -0
  107. package/src/client/private_execution.ts +78 -0
  108. package/src/client/simulator.ts +316 -0
  109. package/src/client/unconstrained_execution.ts +49 -0
  110. package/src/client/view_data_oracle.ts +243 -0
  111. package/src/common/errors.ts +61 -0
  112. package/src/common/index.ts +3 -0
  113. package/src/common/packed_args_cache.ts +55 -0
  114. package/src/common/side_effect_counter.ts +12 -0
  115. package/src/index.ts +3 -0
  116. package/src/public/db.ts +85 -0
  117. package/src/public/execution.ts +137 -0
  118. package/src/public/executor.ts +158 -0
  119. package/src/public/index.ts +9 -0
  120. package/src/public/public_execution_context.ts +217 -0
  121. package/src/public/state_actions.ts +100 -0
  122. package/src/test/utils.ts +38 -0
  123. package/src/utils.ts +18 -0
@@ -0,0 +1,90 @@
1
+ import { GlobalVariables } from '@aztec/circuits.js';
2
+ import { FunctionSelector } from '@aztec/foundation/abi';
3
+ import { AztecAddress } from '@aztec/foundation/aztec-address';
4
+ import { EthAddress } from '@aztec/foundation/eth-address';
5
+ import { Fr } from '@aztec/foundation/fields';
6
+
7
+ import { mock } from 'jest-mock-extended';
8
+ import merge from 'lodash.merge';
9
+
10
+ import { CommitmentsDB, PublicContractsDB, PublicStateDB } from '../../index.js';
11
+ import { AvmContext } from '../avm_context.js';
12
+ import { AvmExecutionEnvironment } from '../avm_execution_environment.js';
13
+ import { AvmMachineState } from '../avm_machine_state.js';
14
+ import { HostStorage } from '../journal/host_storage.js';
15
+ import { AvmWorldStateJournal } from '../journal/journal.js';
16
+
17
+ /**
18
+ * Create a new AVM context with default values.
19
+ */
20
+ export function initContext(overrides?: {
21
+ worldState?: AvmWorldStateJournal;
22
+ env?: AvmExecutionEnvironment;
23
+ machineState?: AvmMachineState;
24
+ }): AvmContext {
25
+ return new AvmContext(
26
+ overrides?.worldState || initMockWorldStateJournal(),
27
+ overrides?.env || initExecutionEnvironment(),
28
+ overrides?.machineState || initMachineState(),
29
+ );
30
+ }
31
+
32
+ /** Creates an empty world state with mocked storage. */
33
+ export function initMockWorldStateJournal(): AvmWorldStateJournal {
34
+ const hostStorage = new HostStorage(mock<PublicStateDB>(), mock<PublicContractsDB>(), mock<CommitmentsDB>());
35
+ return new AvmWorldStateJournal(hostStorage);
36
+ }
37
+
38
+ /**
39
+ * Create an empty instance of the Execution Environment where all values are zero, unless overridden in the overrides object
40
+ */
41
+ export function initExecutionEnvironment(overrides?: Partial<AvmExecutionEnvironment>): AvmExecutionEnvironment {
42
+ return new AvmExecutionEnvironment(
43
+ overrides?.address ?? AztecAddress.zero(),
44
+ overrides?.storageAddress ?? AztecAddress.zero(),
45
+ overrides?.origin ?? AztecAddress.zero(),
46
+ overrides?.sender ?? AztecAddress.zero(),
47
+ overrides?.portal ?? EthAddress.ZERO,
48
+ overrides?.feePerL1Gas ?? Fr.zero(),
49
+ overrides?.feePerL2Gas ?? Fr.zero(),
50
+ overrides?.feePerDaGas ?? Fr.zero(),
51
+ overrides?.contractCallDepth ?? Fr.zero(),
52
+ overrides?.globals ?? GlobalVariables.empty(),
53
+ overrides?.isStaticCall ?? false,
54
+ overrides?.isDelegateCall ?? false,
55
+ overrides?.calldata ?? [],
56
+ overrides?.temporaryFunctionSelector ?? FunctionSelector.empty(),
57
+ );
58
+ }
59
+
60
+ /**
61
+ * Create an empty instance of the Execution Environment where all values are zero, unless overridden in the overrides object
62
+ */
63
+ export function initGlobalVariables(overrides?: Partial<GlobalVariables>): GlobalVariables {
64
+ return new GlobalVariables(
65
+ overrides?.chainId ?? Fr.zero(),
66
+ overrides?.version ?? Fr.zero(),
67
+ overrides?.blockNumber ?? Fr.zero(),
68
+ overrides?.timestamp ?? Fr.zero(),
69
+ overrides?.coinbase ?? EthAddress.ZERO,
70
+ overrides?.feeRecipient ?? AztecAddress.zero(),
71
+ );
72
+ }
73
+
74
+ /**
75
+ * Create an empty instance of the Machine State where all values are zero, unless overridden in the overrides object
76
+ */
77
+ export function initMachineState(overrides?: Partial<AvmMachineState>): AvmMachineState {
78
+ return AvmMachineState.fromState({
79
+ l1GasLeft: overrides?.l1GasLeft ?? 0,
80
+ l2GasLeft: overrides?.l2GasLeft ?? 0,
81
+ daGasLeft: overrides?.daGasLeft ?? 0,
82
+ });
83
+ }
84
+
85
+ /**
86
+ * Create a new object with all the same properties as the original, except for the ones in the overrides object.
87
+ */
88
+ export function allSameExcept(original: any, overrides: any): any {
89
+ return merge({}, original, overrides);
90
+ }
@@ -0,0 +1,20 @@
1
+ import { CommitmentsDB, PublicContractsDB, PublicStateDB } from '../../public/db.js';
2
+
3
+ /**
4
+ * Host storage
5
+ *
6
+ * A wrapper around the node dbs
7
+ */
8
+ export class HostStorage {
9
+ public readonly publicStateDb: PublicStateDB;
10
+
11
+ public readonly contractsDb: PublicContractsDB;
12
+
13
+ public readonly commitmentsDb: CommitmentsDB;
14
+
15
+ constructor(publicStateDb: PublicStateDB, contractsDb: PublicContractsDB, commitmentsDb: CommitmentsDB) {
16
+ this.publicStateDb = publicStateDb;
17
+ this.contractsDb = contractsDb;
18
+ this.commitmentsDb = commitmentsDb;
19
+ }
20
+ }
@@ -0,0 +1,2 @@
1
+ export * from './host_storage.js';
2
+ export * from './journal.js';
@@ -0,0 +1,266 @@
1
+ import { Fr } from '@aztec/foundation/fields';
2
+
3
+ import { HostStorage } from './host_storage.js';
4
+
5
+ /**
6
+ * Data held within the journal
7
+ */
8
+ export type JournalData = {
9
+ newNoteHashes: Fr[];
10
+ newNullifiers: Fr[];
11
+ newL1Messages: Fr[][];
12
+ newLogs: Fr[][];
13
+
14
+ /** contract address -\> key -\> value */
15
+ currentStorageValue: Map<bigint, Map<bigint, Fr>>;
16
+
17
+ /** contract address -\> key -\> value[] (stored in order of access) */
18
+ storageWrites: Map<bigint, Map<bigint, Fr[]>>;
19
+ /** contract address -\> key -\> value[] (stored in order of access) */
20
+ storageReads: Map<bigint, Map<bigint, Fr[]>>;
21
+ };
22
+
23
+ /**
24
+ * A cache of the current state of the AVM
25
+ * The interpreter should make any state queries through this object
26
+ *
27
+ * When a nested context succeeds, it's journal is merge into the parent
28
+ * When a call fails, it's journal is discarded and the parent is used from this point forward
29
+ * When a call succeeds's we can merge a child into its parent
30
+ */
31
+ export class AvmWorldStateJournal {
32
+ /** Reference to node storage */
33
+ public readonly hostStorage: HostStorage;
34
+
35
+ // Reading state - must be tracked for vm execution
36
+ // contract address -> key -> value[] (array stored in order of reads)
37
+ private storageReads: Map<bigint, Map<bigint, Fr[]>> = new Map();
38
+ private storageWrites: Map<bigint, Map<bigint, Fr[]>> = new Map();
39
+
40
+ // New written state
41
+ private newNoteHashes: Fr[] = [];
42
+ private newNullifiers: Fr[] = [];
43
+
44
+ // New Substate
45
+ private newL1Messages: Fr[][] = [];
46
+ private newLogs: Fr[][] = [];
47
+
48
+ // contract address -> key -> value
49
+ private currentStorageValue: Map<bigint, Map<bigint, Fr>> = new Map();
50
+
51
+ private parentJournal: AvmWorldStateJournal | undefined;
52
+
53
+ constructor(hostStorage: HostStorage, parentJournal?: AvmWorldStateJournal) {
54
+ this.hostStorage = hostStorage;
55
+ this.parentJournal = parentJournal;
56
+ }
57
+
58
+ /**
59
+ * Create a new world state journal forked from this one
60
+ */
61
+ public fork() {
62
+ return new AvmWorldStateJournal(this.hostStorage, this);
63
+ }
64
+
65
+ /**
66
+ * Write storage into journal
67
+ *
68
+ * @param contractAddress -
69
+ * @param key -
70
+ * @param value -
71
+ */
72
+ public writeStorage(contractAddress: Fr, key: Fr, value: Fr) {
73
+ let contractMap = this.currentStorageValue.get(contractAddress.toBigInt());
74
+ if (!contractMap) {
75
+ contractMap = new Map();
76
+ this.currentStorageValue.set(contractAddress.toBigInt(), contractMap);
77
+ }
78
+ contractMap.set(key.toBigInt(), value);
79
+
80
+ // We want to keep track of all performed writes in the journal
81
+ this.journalWrite(contractAddress, key, value);
82
+ }
83
+
84
+ /**
85
+ * Read storage from journal
86
+ * Read from host storage on cache miss
87
+ *
88
+ * @param contractAddress -
89
+ * @param key -
90
+ * @returns current value
91
+ */
92
+ public async readStorage(contractAddress: Fr, key: Fr): Promise<Fr> {
93
+ // - We first try this journal's storage cache ( if written to before in this call frame )
94
+ // - Then we try the parent journal's storage cache ( if it exists ) ( written to earlier in this block )
95
+ // - Finally we try the host storage ( a trip to the database )
96
+
97
+ // Do not early return as we want to keep track of reads in this.storageReads
98
+ let value = this.currentStorageValue.get(contractAddress.toBigInt())?.get(key.toBigInt());
99
+ if (!value && this.parentJournal) {
100
+ value = await this.parentJournal?.readStorage(contractAddress, key);
101
+ }
102
+ if (!value) {
103
+ value = await this.hostStorage.publicStateDb.storageRead(contractAddress, key);
104
+ }
105
+
106
+ this.journalRead(contractAddress, key, value);
107
+ return Promise.resolve(value);
108
+ }
109
+
110
+ /**
111
+ * We want to keep track of all performed reads in the journal
112
+ * This information is hinted to the avm circuit
113
+
114
+ * @param contractAddress -
115
+ * @param key -
116
+ * @param value -
117
+ */
118
+ journalUpdate(map: Map<bigint, Map<bigint, Fr[]>>, contractAddress: Fr, key: Fr, value: Fr): void {
119
+ let contractMap = map.get(contractAddress.toBigInt());
120
+ if (!contractMap) {
121
+ contractMap = new Map<bigint, Array<Fr>>();
122
+ map.set(contractAddress.toBigInt(), contractMap);
123
+ }
124
+
125
+ let accessArray = contractMap.get(key.toBigInt());
126
+ if (!accessArray) {
127
+ accessArray = new Array<Fr>();
128
+ contractMap.set(key.toBigInt(), accessArray);
129
+ }
130
+ accessArray.push(value);
131
+ }
132
+
133
+ // Create an instance of journalUpdate that appends to the read array
134
+ private journalRead = this.journalUpdate.bind(this, this.storageReads);
135
+ // Create an instance of journalUpdate that appends to the writes array
136
+ private journalWrite = this.journalUpdate.bind(this, this.storageWrites);
137
+
138
+ public writeNoteHash(noteHash: Fr) {
139
+ this.newNoteHashes.push(noteHash);
140
+ }
141
+
142
+ public writeL1Message(message: Fr[]) {
143
+ this.newL1Messages.push(message);
144
+ }
145
+
146
+ public writeNullifier(nullifier: Fr) {
147
+ this.newNullifiers.push(nullifier);
148
+ }
149
+
150
+ public writeLog(log: Fr[]) {
151
+ this.newLogs.push(log);
152
+ }
153
+
154
+ /**
155
+ * Accept nested world state, merging in its journal, and accepting its state modifications
156
+ * - Utxo objects are concatenated
157
+ * - Public state changes are merged, with the value in the incoming journal taking precedent
158
+ * - Public state journals (r/w logs), with the accessing being appended in chronological order
159
+ */
160
+ public acceptNestedWorldState(nestedJournal: AvmWorldStateJournal) {
161
+ // Merge UTXOs
162
+ this.newNoteHashes = this.newNoteHashes.concat(nestedJournal.newNoteHashes);
163
+ this.newL1Messages = this.newL1Messages.concat(nestedJournal.newL1Messages);
164
+ this.newNullifiers = this.newNullifiers.concat(nestedJournal.newNullifiers);
165
+ this.newLogs = this.newLogs.concat(nestedJournal.newLogs);
166
+
167
+ // Merge Public State
168
+ mergeCurrentValueMaps(this.currentStorageValue, nestedJournal.currentStorageValue);
169
+
170
+ // Merge storage read and write journals
171
+ mergeContractJournalMaps(this.storageReads, nestedJournal.storageReads);
172
+ mergeContractJournalMaps(this.storageWrites, nestedJournal.storageWrites);
173
+ }
174
+
175
+ /**
176
+ * Reject nested world state, merging in its journal, but not accepting its state modifications
177
+ * - Utxo objects are concatenated
178
+ * - Public state changes are dropped
179
+ * - Public state journals (r/w logs) are maintained, with the accessing being appended in chronological order
180
+ */
181
+ public rejectNestedWorldState(nestedJournal: AvmWorldStateJournal) {
182
+ // Merge storage read and write journals
183
+ mergeContractJournalMaps(this.storageReads, nestedJournal.storageReads);
184
+ mergeContractJournalMaps(this.storageWrites, nestedJournal.storageWrites);
185
+ }
186
+
187
+ /**
188
+ * Access the current state of the journal
189
+ *
190
+ * @returns a JournalData object
191
+ */
192
+ public flush(): JournalData {
193
+ return {
194
+ newNoteHashes: this.newNoteHashes,
195
+ newNullifiers: this.newNullifiers,
196
+ newL1Messages: this.newL1Messages,
197
+ newLogs: this.newLogs,
198
+ currentStorageValue: this.currentStorageValue,
199
+ storageReads: this.storageReads,
200
+ storageWrites: this.storageWrites,
201
+ };
202
+ }
203
+ }
204
+
205
+ /**
206
+ * Merges two contract current value together
207
+ * Where childMap keys will take precedent over the hostMap
208
+ * The assumption being that the child map is created at a later time
209
+ * And thus contains more up to date information
210
+ *
211
+ * @param hostMap - The map to be merged into
212
+ * @param childMap - The map to be merged from
213
+ */
214
+ function mergeCurrentValueMaps(hostMap: Map<bigint, Map<bigint, Fr>>, childMap: Map<bigint, Map<bigint, Fr>>) {
215
+ for (const [key, value] of childMap) {
216
+ const map1Value = hostMap.get(key);
217
+ if (!map1Value) {
218
+ hostMap.set(key, value);
219
+ } else {
220
+ mergeStorageCurrentValueMaps(map1Value, value);
221
+ }
222
+ }
223
+ }
224
+
225
+ /**
226
+ * @param hostMap - The map to be merge into
227
+ * @param childMap - The map to be merged from
228
+ */
229
+ function mergeStorageCurrentValueMaps(hostMap: Map<bigint, Fr>, childMap: Map<bigint, Fr>) {
230
+ for (const [key, value] of childMap) {
231
+ hostMap.set(key, value);
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Merges two contract journalling maps together
237
+ * For read maps, we just append the childMap arrays into the host map arrays, as the order is important
238
+ *
239
+ * @param hostMap - The map to be merged into
240
+ * @param childMap - The map to be merged from
241
+ */
242
+ function mergeContractJournalMaps(hostMap: Map<bigint, Map<bigint, Fr[]>>, childMap: Map<bigint, Map<bigint, Fr[]>>) {
243
+ for (const [key, value] of childMap) {
244
+ const map1Value = hostMap.get(key);
245
+ if (!map1Value) {
246
+ hostMap.set(key, value);
247
+ } else {
248
+ mergeStorageJournalMaps(map1Value, value);
249
+ }
250
+ }
251
+ }
252
+
253
+ /**
254
+ * @param hostMap - The map to be merge into
255
+ * @param childMap - The map to be merged from
256
+ */
257
+ function mergeStorageJournalMaps(hostMap: Map<bigint, Fr[]>, childMap: Map<bigint, Fr[]>) {
258
+ for (const [key, value] of childMap) {
259
+ const readArr = hostMap.get(key);
260
+ if (!readArr) {
261
+ hostMap.set(key, value);
262
+ } else {
263
+ hostMap.set(key, readArr?.concat(...value));
264
+ }
265
+ }
266
+ }
@@ -0,0 +1,8 @@
1
+ const baseConfig = require('@aztec/foundation/eslint');
2
+ module.exports = {
3
+ ...baseConfig,
4
+ rules: {
5
+ ...baseConfig.rules,
6
+ 'require-await': 'off',
7
+ },
8
+ };
@@ -0,0 +1,92 @@
1
+ import type { AvmContext } from '../avm_context.js';
2
+ import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
3
+ import { Instruction } from './instruction.js';
4
+ import { StaticCallStorageAlterError } from './storage.js';
5
+
6
+ export class EmitNoteHash extends Instruction {
7
+ static type: string = 'EMITNOTEHASH';
8
+ static readonly opcode: Opcode = Opcode.EMITNOTEHASH;
9
+ // Informs (de)serialization. See Instruction.deserialize.
10
+ static readonly wireFormat = [OperandType.UINT8, OperandType.UINT8, OperandType.UINT32];
11
+
12
+ constructor(private indirect: number, private noteHashOffset: number) {
13
+ super();
14
+ }
15
+
16
+ async execute(context: AvmContext): Promise<void> {
17
+ if (context.environment.isStaticCall) {
18
+ throw new StaticCallStorageAlterError();
19
+ }
20
+
21
+ const noteHash = context.machineState.memory.get(this.noteHashOffset).toFr();
22
+ context.worldState.writeNoteHash(noteHash);
23
+
24
+ context.machineState.incrementPc();
25
+ }
26
+ }
27
+
28
+ export class EmitNullifier extends Instruction {
29
+ static type: string = 'EMITNULLIFIER';
30
+ static readonly opcode: Opcode = Opcode.EMITNULLIFIER;
31
+ // Informs (de)serialization. See Instruction.deserialize.
32
+ static readonly wireFormat = [OperandType.UINT8, OperandType.UINT8, OperandType.UINT32];
33
+
34
+ constructor(private indirect: number, private nullifierOffset: number) {
35
+ super();
36
+ }
37
+
38
+ async execute(context: AvmContext): Promise<void> {
39
+ if (context.environment.isStaticCall) {
40
+ throw new StaticCallStorageAlterError();
41
+ }
42
+
43
+ const nullifier = context.machineState.memory.get(this.nullifierOffset).toFr();
44
+ context.worldState.writeNullifier(nullifier);
45
+
46
+ context.machineState.incrementPc();
47
+ }
48
+ }
49
+
50
+ export class EmitUnencryptedLog extends Instruction {
51
+ static type: string = 'EMITUNENCRYPTEDLOG';
52
+ static readonly opcode: Opcode = Opcode.EMITUNENCRYPTEDLOG;
53
+ // Informs (de)serialization. See Instruction.deserialize.
54
+ static readonly wireFormat = [OperandType.UINT8, OperandType.UINT8, OperandType.UINT32, OperandType.UINT32];
55
+
56
+ constructor(private indirect: number, private logOffset: number, private logSize: number) {
57
+ super();
58
+ }
59
+
60
+ async execute(context: AvmContext): Promise<void> {
61
+ if (context.environment.isStaticCall) {
62
+ throw new StaticCallStorageAlterError();
63
+ }
64
+
65
+ const log = context.machineState.memory.getSlice(this.logOffset, this.logSize).map(f => f.toFr());
66
+ context.worldState.writeLog(log);
67
+
68
+ context.machineState.incrementPc();
69
+ }
70
+ }
71
+
72
+ export class SendL2ToL1Message extends Instruction {
73
+ static type: string = 'SENDL2TOL1MSG';
74
+ static readonly opcode: Opcode = Opcode.SENDL2TOL1MSG;
75
+ // Informs (de)serialization. See Instruction.deserialize.
76
+ static readonly wireFormat = [OperandType.UINT8, OperandType.UINT8, OperandType.UINT32, OperandType.UINT32];
77
+
78
+ constructor(private indirect: number, private msgOffset: number, private msgSize: number) {
79
+ super();
80
+ }
81
+
82
+ async execute(context: AvmContext): Promise<void> {
83
+ if (context.environment.isStaticCall) {
84
+ throw new StaticCallStorageAlterError();
85
+ }
86
+
87
+ const msg = context.machineState.memory.getSlice(this.msgOffset, this.msgSize).map(f => f.toFr());
88
+ context.worldState.writeL1Message(msg);
89
+
90
+ context.machineState.incrementPc();
91
+ }
92
+ }
@@ -0,0 +1,66 @@
1
+ import { strict as assert } from 'assert';
2
+
3
+ import { TaggedMemory, TypeTag } from '../avm_memory_types.js';
4
+
5
+ export enum AddressingMode {
6
+ DIRECT,
7
+ INDIRECT,
8
+ INDIRECT_PLUS_CONSTANT, // Not implemented yet.
9
+ }
10
+
11
+ /** A class to represent the addressing mode of an instruction. */
12
+ export class Addressing {
13
+ public constructor(
14
+ /** The addressing mode for each operand. The length of this array is the number of operands of the instruction. */
15
+ private readonly modePerOperand: AddressingMode[],
16
+ ) {
17
+ assert(modePerOperand.length <= 8, 'At most 8 operands are supported');
18
+ }
19
+
20
+ public static fromWire(wireModes: number): Addressing {
21
+ // The modes are stored in the wire format as a byte, with each bit representing the mode for an operand.
22
+ // The least significant bit represents the zeroth operand, and the most significant bit represents the last operand.
23
+ const modes = new Array<AddressingMode>(8);
24
+ for (let i = 0; i < 8; i++) {
25
+ modes[i] = (wireModes & (1 << i)) === 0 ? AddressingMode.DIRECT : AddressingMode.INDIRECT;
26
+ }
27
+ return new Addressing(modes);
28
+ }
29
+
30
+ public toWire(): number {
31
+ // The modes are stored in the wire format as a byte, with each bit representing the mode for an operand.
32
+ // The least significant bit represents the zeroth operand, and the least significant bit represents the last operand.
33
+ let wire: number = 0;
34
+ for (let i = 0; i < 8; i++) {
35
+ if (this.modePerOperand[i] === AddressingMode.INDIRECT) {
36
+ wire |= 1 << i;
37
+ }
38
+ }
39
+ return wire;
40
+ }
41
+
42
+ /**
43
+ * Resolves the offsets using the addressing mode.
44
+ * @param offsets The offsets to resolve.
45
+ * @param mem The memory to use for resolution.
46
+ * @returns The resolved offsets. The length of the returned array is the same as the length of the input array.
47
+ */
48
+ public resolve(offsets: number[], mem: TaggedMemory): number[] {
49
+ assert(offsets.length <= this.modePerOperand.length);
50
+ const resolved = new Array(offsets.length);
51
+ for (const [i, offset] of offsets.entries()) {
52
+ switch (this.modePerOperand[i]) {
53
+ case AddressingMode.INDIRECT:
54
+ mem.checkTag(TypeTag.UINT32, offset);
55
+ resolved[i] = Number(mem.get(offset).toBigInt());
56
+ break;
57
+ case AddressingMode.DIRECT:
58
+ resolved[i] = offset;
59
+ break;
60
+ default:
61
+ throw new Error(`Unimplemented addressing mode: ${AddressingMode[this.modePerOperand[i]]}`);
62
+ }
63
+ }
64
+ return resolved;
65
+ }
66
+ }
@@ -0,0 +1,79 @@
1
+ import type { AvmContext } from '../avm_context.js';
2
+ import { Opcode } from '../serialization/instruction_serialization.js';
3
+ import { ThreeOperandInstruction } from './instruction_impl.js';
4
+
5
+ export class Add extends ThreeOperandInstruction {
6
+ static readonly type: string = 'ADD';
7
+ static readonly opcode = Opcode.ADD;
8
+
9
+ constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) {
10
+ super(indirect, inTag, aOffset, bOffset, dstOffset);
11
+ }
12
+
13
+ async execute(context: AvmContext): Promise<void> {
14
+ const a = context.machineState.memory.get(this.aOffset);
15
+ const b = context.machineState.memory.get(this.bOffset);
16
+
17
+ const dest = a.add(b);
18
+ context.machineState.memory.set(this.dstOffset, dest);
19
+
20
+ context.machineState.incrementPc();
21
+ }
22
+ }
23
+
24
+ export class Sub extends ThreeOperandInstruction {
25
+ static readonly type: string = 'SUB';
26
+ static readonly opcode = Opcode.SUB;
27
+
28
+ constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) {
29
+ super(indirect, inTag, aOffset, bOffset, dstOffset);
30
+ }
31
+
32
+ async execute(context: AvmContext): Promise<void> {
33
+ const a = context.machineState.memory.get(this.aOffset);
34
+ const b = context.machineState.memory.get(this.bOffset);
35
+
36
+ const dest = a.sub(b);
37
+ context.machineState.memory.set(this.dstOffset, dest);
38
+
39
+ context.machineState.incrementPc();
40
+ }
41
+ }
42
+
43
+ export class Mul extends ThreeOperandInstruction {
44
+ static type: string = 'MUL';
45
+ static readonly opcode = Opcode.MUL;
46
+
47
+ constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) {
48
+ super(indirect, inTag, aOffset, bOffset, dstOffset);
49
+ }
50
+
51
+ async execute(context: AvmContext): Promise<void> {
52
+ const a = context.machineState.memory.get(this.aOffset);
53
+ const b = context.machineState.memory.get(this.bOffset);
54
+
55
+ const dest = a.mul(b);
56
+ context.machineState.memory.set(this.dstOffset, dest);
57
+
58
+ context.machineState.incrementPc();
59
+ }
60
+ }
61
+
62
+ export class Div extends ThreeOperandInstruction {
63
+ static type: string = 'DIV';
64
+ static readonly opcode = Opcode.DIV;
65
+
66
+ constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) {
67
+ super(indirect, inTag, aOffset, bOffset, dstOffset);
68
+ }
69
+
70
+ async execute(context: AvmContext): Promise<void> {
71
+ const a = context.machineState.memory.get(this.aOffset);
72
+ const b = context.machineState.memory.get(this.bOffset);
73
+
74
+ const dest = a.div(b);
75
+ context.machineState.memory.set(this.dstOffset, dest);
76
+
77
+ context.machineState.incrementPc();
78
+ }
79
+ }