@aztec/simulator 0.75.0 → 0.76.1
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.
- package/dest/avm/avm_machine_state.d.ts.map +1 -1
- package/dest/avm/avm_machine_state.js +18 -13
- package/dest/avm/avm_memory_types.d.ts +1 -47
- package/dest/avm/avm_memory_types.d.ts.map +1 -1
- package/dest/avm/avm_memory_types.js +42 -144
- package/dest/avm/avm_simulator.d.ts +2 -1
- package/dest/avm/avm_simulator.d.ts.map +1 -1
- package/dest/avm/avm_simulator.js +23 -7
- package/dest/avm/opcodes/accrued_substate.d.ts.map +1 -1
- package/dest/avm/opcodes/accrued_substate.js +8 -15
- package/dest/avm/opcodes/addressing_mode.d.ts.map +1 -1
- package/dest/avm/opcodes/addressing_mode.js +8 -3
- package/dest/avm/opcodes/arithmetic.d.ts.map +1 -1
- package/dest/avm/opcodes/arithmetic.js +2 -3
- package/dest/avm/opcodes/bitwise.d.ts.map +1 -1
- package/dest/avm/opcodes/bitwise.js +3 -5
- package/dest/avm/opcodes/comparators.d.ts.map +1 -1
- package/dest/avm/opcodes/comparators.js +2 -3
- package/dest/avm/opcodes/contract.d.ts.map +1 -1
- package/dest/avm/opcodes/contract.js +2 -3
- package/dest/avm/opcodes/control_flow.d.ts.map +1 -1
- package/dest/avm/opcodes/control_flow.js +2 -6
- package/dest/avm/opcodes/conversion.d.ts.map +1 -1
- package/dest/avm/opcodes/conversion.js +2 -3
- package/dest/avm/opcodes/ec_add.d.ts.map +1 -1
- package/dest/avm/opcodes/ec_add.js +2 -3
- package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
- package/dest/avm/opcodes/environment_getters.js +2 -3
- package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
- package/dest/avm/opcodes/external_calls.js +4 -7
- package/dest/avm/opcodes/hashing.d.ts.map +1 -1
- package/dest/avm/opcodes/hashing.js +4 -7
- package/dest/avm/opcodes/memory.d.ts.map +1 -1
- package/dest/avm/opcodes/memory.js +7 -13
- package/dest/avm/opcodes/misc.d.ts.map +1 -1
- package/dest/avm/opcodes/misc.js +2 -3
- package/dest/avm/opcodes/multi_scalar_mul.d.ts.map +1 -1
- package/dest/avm/opcodes/multi_scalar_mul.js +2 -7
- package/dest/avm/opcodes/storage.d.ts.map +1 -1
- package/dest/avm/opcodes/storage.js +3 -5
- package/dest/public/fixtures/public_tx_simulation_tester.d.ts +5 -0
- package/dest/public/fixtures/public_tx_simulation_tester.d.ts.map +1 -1
- package/dest/public/fixtures/public_tx_simulation_tester.js +10 -6
- package/package.json +9 -9
- package/src/avm/avm_machine_state.ts +18 -14
- package/src/avm/avm_memory_types.ts +43 -183
- package/src/avm/avm_simulator.ts +37 -11
- package/src/avm/opcodes/accrued_substate.ts +7 -21
- package/src/avm/opcodes/addressing_mode.ts +9 -2
- package/src/avm/opcodes/arithmetic.ts +1 -3
- package/src/avm/opcodes/bitwise.ts +2 -6
- package/src/avm/opcodes/comparators.ts +1 -3
- package/src/avm/opcodes/contract.ts +1 -3
- package/src/avm/opcodes/control_flow.ts +1 -9
- package/src/avm/opcodes/conversion.ts +1 -3
- package/src/avm/opcodes/ec_add.ts +1 -3
- package/src/avm/opcodes/environment_getters.ts +1 -3
- package/src/avm/opcodes/external_calls.ts +3 -6
- package/src/avm/opcodes/hashing.ts +3 -9
- package/src/avm/opcodes/memory.ts +6 -20
- package/src/avm/opcodes/misc.ts +1 -3
- package/src/avm/opcodes/multi_scalar_mul.ts +1 -7
- package/src/avm/opcodes/storage.ts +2 -6
- package/src/public/fixtures/public_tx_simulation_tester.ts +16 -4
package/src/avm/avm_simulator.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
revertReasonFromExplicitRevert,
|
|
19
19
|
} from './errors.js';
|
|
20
20
|
import { type AvmPersistableStateManager } from './journal/journal.js';
|
|
21
|
+
import { type Instruction } from './opcodes/instruction.js';
|
|
21
22
|
import {
|
|
22
23
|
INSTRUCTION_SET,
|
|
23
24
|
type InstructionSet,
|
|
@@ -33,20 +34,26 @@ export class AvmSimulator {
|
|
|
33
34
|
private log: Logger;
|
|
34
35
|
private bytecode: Buffer | undefined;
|
|
35
36
|
private opcodeTallies: Map<string, OpcodeTally> = new Map();
|
|
37
|
+
// maps pc to [instr, bytesRead]
|
|
38
|
+
private deserializedInstructionsCache: Map<number, [Instruction, number]> = new Map();
|
|
36
39
|
|
|
37
40
|
private tallyPrintFunction = () => {};
|
|
38
41
|
private tallyInstructionFunction = (_b: string, _c: Gas) => {};
|
|
39
42
|
|
|
40
43
|
// Test Purposes only: Logger will not have the proper function name. Use this constructor for testing purposes
|
|
41
44
|
// only. Otherwise, use build() below.
|
|
42
|
-
constructor(
|
|
45
|
+
constructor(
|
|
46
|
+
private context: AvmContext,
|
|
47
|
+
private instructionSet: InstructionSet = INSTRUCTION_SET(),
|
|
48
|
+
enableTallying = false,
|
|
49
|
+
) {
|
|
43
50
|
assert(
|
|
44
51
|
context.machineState.gasLeft.l2Gas <= MAX_L2_GAS_PER_TX_PUBLIC_PORTION,
|
|
45
52
|
`Cannot allocate more than ${MAX_L2_GAS_PER_TX_PUBLIC_PORTION} to the AVM for execution.`,
|
|
46
53
|
);
|
|
47
54
|
this.log = createLogger(`simulator:avm(calldata[0]: ${context.environment.calldata[0]})`);
|
|
48
|
-
//
|
|
49
|
-
if (this.log.isLevelEnabled('
|
|
55
|
+
// Turn on tallying if explicitly enabled or if trace logging
|
|
56
|
+
if (enableTallying || this.log.isLevelEnabled('trace')) {
|
|
50
57
|
this.tallyPrintFunction = this.printOpcodeTallies;
|
|
51
58
|
this.tallyInstructionFunction = this.tallyInstruction;
|
|
52
59
|
}
|
|
@@ -125,6 +132,7 @@ export class AvmSimulator {
|
|
|
125
132
|
* This method is useful for testing and debugging.
|
|
126
133
|
*/
|
|
127
134
|
public async executeBytecode(bytecode: Buffer): Promise<AvmContractCallResult> {
|
|
135
|
+
const startTotalTime = performance.now();
|
|
128
136
|
assert(isAvmBytecode(bytecode), "AVM simulator can't execute non-AVM bytecode");
|
|
129
137
|
assert(bytecode.length > 0, "AVM simulator can't execute empty bytecode");
|
|
130
138
|
|
|
@@ -137,19 +145,32 @@ export class AvmSimulator {
|
|
|
137
145
|
// continuing until the machine state signifies a halt
|
|
138
146
|
let instrCounter = 0;
|
|
139
147
|
while (!machineState.getHalted()) {
|
|
140
|
-
|
|
148
|
+
// Get the instruction from cache, or deserialize for the first time
|
|
149
|
+
let cachedInstruction = this.deserializedInstructionsCache.get(machineState.pc);
|
|
150
|
+
|
|
151
|
+
if (cachedInstruction === undefined) {
|
|
152
|
+
cachedInstruction = decodeInstructionFromBytecode(bytecode, machineState.pc, this.instructionSet);
|
|
153
|
+
this.deserializedInstructionsCache.set(machineState.pc, cachedInstruction);
|
|
154
|
+
}
|
|
155
|
+
const [instruction, bytesRead] = cachedInstruction;
|
|
156
|
+
|
|
141
157
|
const instrStartGas = machineState.gasLeft; // Save gas before executing instruction (for profiling)
|
|
142
158
|
|
|
143
|
-
this.log.trace
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
159
|
+
if (this.log.isLevelEnabled('trace')) {
|
|
160
|
+
// Skip this entirely to avoid toStringing etc if trace is not enabled
|
|
161
|
+
this.log.trace(
|
|
162
|
+
`[PC:${machineState.pc}] [IC:${instrCounter}] ${instruction.toString()} (gasLeft l2=${
|
|
163
|
+
machineState.l2GasLeft
|
|
164
|
+
} da=${machineState.daGasLeft})`,
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
instrCounter++;
|
|
168
|
+
|
|
169
|
+
machineState.nextPc = machineState.pc + bytesRead;
|
|
170
|
+
|
|
148
171
|
// Execute the instruction.
|
|
149
172
|
// Normal returns and reverts will return normally here.
|
|
150
173
|
// "Exceptional halts" will throw.
|
|
151
|
-
machineState.nextPc = machineState.pc + bytesRead;
|
|
152
|
-
|
|
153
174
|
await instruction.execute(this.context);
|
|
154
175
|
if (!instruction.handlesPC()) {
|
|
155
176
|
// Increment PC if the instruction doesn't handle it itself
|
|
@@ -181,6 +202,11 @@ export class AvmSimulator {
|
|
|
181
202
|
this.log.debug(`Executed ${instrCounter} instructions and consumed ${totalGasUsed.l2Gas} L2 Gas`);
|
|
182
203
|
|
|
183
204
|
this.tallyPrintFunction();
|
|
205
|
+
|
|
206
|
+
const endTotalTime = performance.now();
|
|
207
|
+
const totalTime = endTotalTime - startTotalTime;
|
|
208
|
+
this.log.debug(`Total execution time: ${totalTime}ms`);
|
|
209
|
+
|
|
184
210
|
// Return results for processing by calling context
|
|
185
211
|
return results;
|
|
186
212
|
} catch (err: any) {
|
|
@@ -28,7 +28,7 @@ export class NoteHashExists extends Instruction {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
public async execute(context: AvmContext): Promise<void> {
|
|
31
|
-
const memory = context.machineState.memory
|
|
31
|
+
const memory = context.machineState.memory;
|
|
32
32
|
context.machineState.consumeGas(this.gasCost());
|
|
33
33
|
const operands = [this.noteHashOffset, this.leafIndexOffset, this.existsOffset];
|
|
34
34
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
@@ -41,8 +41,6 @@ export class NoteHashExists extends Instruction {
|
|
|
41
41
|
|
|
42
42
|
const exists = await context.persistableState.checkNoteHashExists(context.environment.address, noteHash, leafIndex);
|
|
43
43
|
memory.set(existsOffset, exists ? new Uint1(1) : new Uint1(0));
|
|
44
|
-
|
|
45
|
-
memory.assert({ reads: 2, writes: 1, addressing });
|
|
46
44
|
}
|
|
47
45
|
}
|
|
48
46
|
|
|
@@ -57,7 +55,7 @@ export class EmitNoteHash extends Instruction {
|
|
|
57
55
|
}
|
|
58
56
|
|
|
59
57
|
public async execute(context: AvmContext): Promise<void> {
|
|
60
|
-
const memory = context.machineState.memory
|
|
58
|
+
const memory = context.machineState.memory;
|
|
61
59
|
context.machineState.consumeGas(this.gasCost());
|
|
62
60
|
|
|
63
61
|
const operands = [this.noteHashOffset];
|
|
@@ -71,8 +69,6 @@ export class EmitNoteHash extends Instruction {
|
|
|
71
69
|
|
|
72
70
|
const noteHash = memory.get(noteHashOffset).toFr();
|
|
73
71
|
await context.persistableState.writeNoteHash(context.environment.address, noteHash);
|
|
74
|
-
|
|
75
|
-
memory.assert({ reads: 1, addressing });
|
|
76
72
|
}
|
|
77
73
|
}
|
|
78
74
|
|
|
@@ -98,7 +94,7 @@ export class NullifierExists extends Instruction {
|
|
|
98
94
|
}
|
|
99
95
|
|
|
100
96
|
public async execute(context: AvmContext): Promise<void> {
|
|
101
|
-
const memory = context.machineState.memory
|
|
97
|
+
const memory = context.machineState.memory;
|
|
102
98
|
context.machineState.consumeGas(this.gasCost());
|
|
103
99
|
|
|
104
100
|
const operands = [this.nullifierOffset, this.addressOffset, this.existsOffset];
|
|
@@ -111,8 +107,6 @@ export class NullifierExists extends Instruction {
|
|
|
111
107
|
const exists = await context.persistableState.checkNullifierExists(address, nullifier);
|
|
112
108
|
|
|
113
109
|
memory.set(existsOffset, exists ? new Uint1(1) : new Uint1(0));
|
|
114
|
-
|
|
115
|
-
memory.assert({ reads: 2, writes: 1, addressing });
|
|
116
110
|
}
|
|
117
111
|
}
|
|
118
112
|
|
|
@@ -131,7 +125,7 @@ export class EmitNullifier extends Instruction {
|
|
|
131
125
|
throw new StaticCallAlterationError();
|
|
132
126
|
}
|
|
133
127
|
|
|
134
|
-
const memory = context.machineState.memory
|
|
128
|
+
const memory = context.machineState.memory;
|
|
135
129
|
context.machineState.consumeGas(this.gasCost());
|
|
136
130
|
|
|
137
131
|
const operands = [this.nullifierOffset];
|
|
@@ -152,8 +146,6 @@ export class EmitNullifier extends Instruction {
|
|
|
152
146
|
throw e;
|
|
153
147
|
}
|
|
154
148
|
}
|
|
155
|
-
|
|
156
|
-
memory.assert({ reads: 1, addressing });
|
|
157
149
|
}
|
|
158
150
|
}
|
|
159
151
|
|
|
@@ -179,7 +171,7 @@ export class L1ToL2MessageExists extends Instruction {
|
|
|
179
171
|
}
|
|
180
172
|
|
|
181
173
|
public async execute(context: AvmContext): Promise<void> {
|
|
182
|
-
const memory = context.machineState.memory
|
|
174
|
+
const memory = context.machineState.memory;
|
|
183
175
|
context.machineState.consumeGas(this.gasCost());
|
|
184
176
|
|
|
185
177
|
const operands = [this.msgHashOffset, this.msgLeafIndexOffset, this.existsOffset];
|
|
@@ -195,8 +187,6 @@ export class L1ToL2MessageExists extends Instruction {
|
|
|
195
187
|
msgLeafIndex,
|
|
196
188
|
);
|
|
197
189
|
memory.set(existsOffset, exists ? new Uint1(1) : new Uint1(0));
|
|
198
|
-
|
|
199
|
-
memory.assert({ reads: 2, writes: 1, addressing });
|
|
200
190
|
}
|
|
201
191
|
}
|
|
202
192
|
|
|
@@ -216,7 +206,7 @@ export class EmitUnencryptedLog extends Instruction {
|
|
|
216
206
|
throw new StaticCallAlterationError();
|
|
217
207
|
}
|
|
218
208
|
|
|
219
|
-
const memory = context.machineState.memory
|
|
209
|
+
const memory = context.machineState.memory;
|
|
220
210
|
|
|
221
211
|
const operands = [this.logOffset, this.logSizeOffset];
|
|
222
212
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
@@ -230,8 +220,6 @@ export class EmitUnencryptedLog extends Instruction {
|
|
|
230
220
|
context.machineState.consumeGas(this.gasCost(logSize));
|
|
231
221
|
const log = memory.getSlice(logOffset, logSize).map(f => f.toFr());
|
|
232
222
|
context.persistableState.writePublicLog(contractAddress, log);
|
|
233
|
-
|
|
234
|
-
memory.assert({ reads: 1 + logSize, addressing });
|
|
235
223
|
}
|
|
236
224
|
}
|
|
237
225
|
|
|
@@ -250,7 +238,7 @@ export class SendL2ToL1Message extends Instruction {
|
|
|
250
238
|
throw new StaticCallAlterationError();
|
|
251
239
|
}
|
|
252
240
|
|
|
253
|
-
const memory = context.machineState.memory
|
|
241
|
+
const memory = context.machineState.memory;
|
|
254
242
|
context.machineState.consumeGas(this.gasCost());
|
|
255
243
|
|
|
256
244
|
const operands = [this.recipientOffset, this.contentOffset];
|
|
@@ -261,7 +249,5 @@ export class SendL2ToL1Message extends Instruction {
|
|
|
261
249
|
const recipient = memory.get(recipientOffset).toFr();
|
|
262
250
|
const content = memory.get(contentOffset).toFr();
|
|
263
251
|
context.persistableState.writeL2ToL1Message(context.environment.address, recipient, content);
|
|
264
|
-
|
|
265
|
-
memory.assert({ reads: 2, addressing });
|
|
266
252
|
}
|
|
267
253
|
}
|
|
@@ -59,12 +59,19 @@ export class Addressing {
|
|
|
59
59
|
public resolve(offsets: number[], mem: TaggedMemoryInterface): number[] {
|
|
60
60
|
assert(offsets.length <= this.modePerOperand.length);
|
|
61
61
|
const resolved = new Array(offsets.length);
|
|
62
|
+
|
|
63
|
+
let didRelativeOnce = false;
|
|
64
|
+
let baseAddr = 0;
|
|
65
|
+
|
|
62
66
|
for (const [i, offset] of offsets.entries()) {
|
|
63
67
|
const mode = this.modePerOperand[i];
|
|
64
68
|
resolved[i] = offset;
|
|
65
69
|
if (mode & AddressingMode.RELATIVE) {
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
if (!didRelativeOnce) {
|
|
71
|
+
mem.checkIsValidMemoryOffsetTag(0);
|
|
72
|
+
baseAddr = Number(mem.get(0).toBigInt());
|
|
73
|
+
didRelativeOnce = true;
|
|
74
|
+
}
|
|
68
75
|
resolved[i] += baseAddr;
|
|
69
76
|
if (resolved[i] >= TaggedMemory.MAX_MEMORY_SIZE) {
|
|
70
77
|
throw new RelativeAddressOutOfRangeError(baseAddr, offset);
|
|
@@ -13,7 +13,7 @@ import { ThreeOperandInstruction } from './instruction_impl.js';
|
|
|
13
13
|
|
|
14
14
|
export abstract class ThreeOperandArithmeticInstruction extends ThreeOperandInstruction {
|
|
15
15
|
public async execute(context: AvmContext): Promise<void> {
|
|
16
|
-
const memory = context.machineState.memory
|
|
16
|
+
const memory = context.machineState.memory;
|
|
17
17
|
context.machineState.consumeGas(this.gasCost());
|
|
18
18
|
|
|
19
19
|
const operands = [this.aOffset, this.bOffset, this.dstOffset];
|
|
@@ -26,8 +26,6 @@ export abstract class ThreeOperandArithmeticInstruction extends ThreeOperandInst
|
|
|
26
26
|
|
|
27
27
|
const dest = this.compute(a, b);
|
|
28
28
|
memory.set(dstOffset, dest);
|
|
29
|
-
|
|
30
|
-
memory.assert({ reads: 2, writes: 1, addressing });
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
protected abstract compute(a: MemoryValue, b: MemoryValue): MemoryValue;
|
|
@@ -7,7 +7,7 @@ import { ThreeOperandInstruction } from './instruction_impl.js';
|
|
|
7
7
|
|
|
8
8
|
abstract class ThreeOperandBitwiseInstruction extends ThreeOperandInstruction {
|
|
9
9
|
public async execute(context: AvmContext): Promise<void> {
|
|
10
|
-
const memory = context.machineState.memory
|
|
10
|
+
const memory = context.machineState.memory;
|
|
11
11
|
context.machineState.consumeGas(this.gasCost());
|
|
12
12
|
|
|
13
13
|
const operands = [this.aOffset, this.bOffset, this.dstOffset];
|
|
@@ -20,8 +20,6 @@ abstract class ThreeOperandBitwiseInstruction extends ThreeOperandInstruction {
|
|
|
20
20
|
|
|
21
21
|
const res = this.compute(a, b);
|
|
22
22
|
memory.set(dstOffset, res);
|
|
23
|
-
|
|
24
|
-
memory.assert({ reads: 2, writes: 1, addressing });
|
|
25
23
|
}
|
|
26
24
|
|
|
27
25
|
protected abstract compute(a: IntegralValue, b: IntegralValue): IntegralValue;
|
|
@@ -96,7 +94,7 @@ export class Not extends Instruction {
|
|
|
96
94
|
}
|
|
97
95
|
|
|
98
96
|
public async execute(context: AvmContext): Promise<void> {
|
|
99
|
-
const memory = context.machineState.memory
|
|
97
|
+
const memory = context.machineState.memory;
|
|
100
98
|
context.machineState.consumeGas(this.gasCost());
|
|
101
99
|
|
|
102
100
|
const operands = [this.srcOffset, this.dstOffset];
|
|
@@ -107,7 +105,5 @@ export class Not extends Instruction {
|
|
|
107
105
|
|
|
108
106
|
const res = value.not();
|
|
109
107
|
memory.set(dstOffset, res);
|
|
110
|
-
|
|
111
|
-
memory.assert({ reads: 1, writes: 1, addressing });
|
|
112
108
|
}
|
|
113
109
|
}
|
|
@@ -6,7 +6,7 @@ import { ThreeOperandInstruction } from './instruction_impl.js';
|
|
|
6
6
|
|
|
7
7
|
abstract class ComparatorInstruction extends ThreeOperandInstruction {
|
|
8
8
|
public async execute(context: AvmContext): Promise<void> {
|
|
9
|
-
const memory = context.machineState.memory
|
|
9
|
+
const memory = context.machineState.memory;
|
|
10
10
|
context.machineState.consumeGas(this.gasCost());
|
|
11
11
|
|
|
12
12
|
const operands = [this.aOffset, this.bOffset, this.dstOffset];
|
|
@@ -19,8 +19,6 @@ abstract class ComparatorInstruction extends ThreeOperandInstruction {
|
|
|
19
19
|
|
|
20
20
|
const dest = new Uint1(this.compare(a, b) ? 1 : 0);
|
|
21
21
|
memory.set(dstOffset, dest);
|
|
22
|
-
|
|
23
|
-
memory.assert({ reads: 2, writes: 1, addressing });
|
|
24
22
|
}
|
|
25
23
|
|
|
26
24
|
protected abstract compare(a: MemoryValue, b: MemoryValue): boolean;
|
|
@@ -35,7 +35,7 @@ export class GetContractInstance extends Instruction {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
async execute(context: AvmContext): Promise<void> {
|
|
38
|
-
const memory = context.machineState.memory
|
|
38
|
+
const memory = context.machineState.memory;
|
|
39
39
|
context.machineState.consumeGas(this.gasCost());
|
|
40
40
|
|
|
41
41
|
if (!(this.memberEnum in ContractInstanceMember)) {
|
|
@@ -68,7 +68,5 @@ export class GetContractInstance extends Instruction {
|
|
|
68
68
|
|
|
69
69
|
memory.set(existsOffset, new Uint1(exists ? 1 : 0));
|
|
70
70
|
memory.set(dstOffset, memberValue);
|
|
71
|
-
|
|
72
|
-
memory.assert({ reads: 1, writes: 2, addressing });
|
|
73
71
|
}
|
|
74
72
|
}
|
|
@@ -19,8 +19,6 @@ export class Jump extends Instruction {
|
|
|
19
19
|
context.machineState.consumeGas(this.gasCost());
|
|
20
20
|
|
|
21
21
|
context.machineState.pc = this.jumpOffset;
|
|
22
|
-
|
|
23
|
-
context.machineState.memory.assert({});
|
|
24
22
|
}
|
|
25
23
|
|
|
26
24
|
public override handlesPC(): boolean {
|
|
@@ -45,7 +43,7 @@ export class JumpI extends Instruction {
|
|
|
45
43
|
}
|
|
46
44
|
|
|
47
45
|
public async execute(context: AvmContext): Promise<void> {
|
|
48
|
-
const memory = context.machineState.memory
|
|
46
|
+
const memory = context.machineState.memory;
|
|
49
47
|
context.machineState.consumeGas(this.gasCost());
|
|
50
48
|
|
|
51
49
|
const operands = [this.condOffset];
|
|
@@ -58,8 +56,6 @@ export class JumpI extends Instruction {
|
|
|
58
56
|
} else {
|
|
59
57
|
context.machineState.pc = this.loc;
|
|
60
58
|
}
|
|
61
|
-
|
|
62
|
-
memory.assert({ reads: 1, addressing });
|
|
63
59
|
}
|
|
64
60
|
|
|
65
61
|
public override handlesPC(): boolean {
|
|
@@ -85,8 +81,6 @@ export class InternalCall extends Instruction {
|
|
|
85
81
|
returnPc: context.machineState.nextPc,
|
|
86
82
|
});
|
|
87
83
|
context.machineState.pc = this.loc;
|
|
88
|
-
|
|
89
|
-
context.machineState.memory.assert({});
|
|
90
84
|
}
|
|
91
85
|
|
|
92
86
|
public override handlesPC(): boolean {
|
|
@@ -112,8 +106,6 @@ export class InternalReturn extends Instruction {
|
|
|
112
106
|
throw new InstructionExecutionError('Internal call stack empty!');
|
|
113
107
|
}
|
|
114
108
|
context.machineState.pc = stackEntry.returnPc;
|
|
115
|
-
|
|
116
|
-
context.machineState.memory.assert({});
|
|
117
109
|
}
|
|
118
110
|
|
|
119
111
|
public override handlesPC(): boolean {
|
|
@@ -32,7 +32,7 @@ export class ToRadixBE extends Instruction {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
public async execute(context: AvmContext): Promise<void> {
|
|
35
|
-
const memory = context.machineState.memory
|
|
35
|
+
const memory = context.machineState.memory;
|
|
36
36
|
const operands = [this.srcOffset, this.radixOffset, this.numLimbsOffset, this.outputBitsOffset, this.dstOffset];
|
|
37
37
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
38
38
|
const [srcOffset, radixOffset, numLimbsOffset, outputBitsOffset, dstOffset] = addressing.resolve(operands, memory);
|
|
@@ -76,7 +76,5 @@ export class ToRadixBE extends Instruction {
|
|
|
76
76
|
const outputType = outputBits != 0 ? Uint1 : Uint8;
|
|
77
77
|
const res = limbArray.map(byte => new outputType(byte));
|
|
78
78
|
memory.setSlice(dstOffset, res);
|
|
79
|
-
|
|
80
|
-
memory.assert({ reads: 4, writes: numLimbs, addressing });
|
|
81
79
|
}
|
|
82
80
|
}
|
|
@@ -38,7 +38,7 @@ export class EcAdd extends Instruction {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
public async execute(context: AvmContext): Promise<void> {
|
|
41
|
-
const memory = context.machineState.memory
|
|
41
|
+
const memory = context.machineState.memory;
|
|
42
42
|
context.machineState.consumeGas(this.gasCost());
|
|
43
43
|
|
|
44
44
|
const operands = [
|
|
@@ -89,7 +89,5 @@ export class EcAdd extends Instruction {
|
|
|
89
89
|
memory.setSlice(dstOffset, [new Field(dest.x), new Field(dest.y)]);
|
|
90
90
|
// Check representation of infinity for grumpkin
|
|
91
91
|
memory.setSlice(dstOffset + 2, [new Uint1(dest.equals(Point.ZERO) ? 1 : 0)]);
|
|
92
|
-
|
|
93
|
-
memory.assert({ reads: 6, writes: 3, addressing });
|
|
94
92
|
}
|
|
95
93
|
}
|
|
@@ -66,7 +66,7 @@ export class GetEnvVar extends Instruction {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
public async execute(context: AvmContext): Promise<void> {
|
|
69
|
-
const memory = context.machineState.memory
|
|
69
|
+
const memory = context.machineState.memory;
|
|
70
70
|
context.machineState.consumeGas(this.gasCost());
|
|
71
71
|
|
|
72
72
|
if (!(this.varEnum in EnvironmentVariable)) {
|
|
@@ -78,7 +78,5 @@ export class GetEnvVar extends Instruction {
|
|
|
78
78
|
const [dstOffset] = addressing.resolve(operands, memory);
|
|
79
79
|
|
|
80
80
|
memory.set(dstOffset, getValue(this.varEnum as EnvironmentVariable, context));
|
|
81
|
-
|
|
82
|
-
memory.assert({ writes: 1, addressing });
|
|
83
81
|
}
|
|
84
82
|
}
|
|
@@ -30,7 +30,7 @@ abstract class ExternalCall extends Instruction {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
public async execute(context: AvmContext) {
|
|
33
|
-
const memory = context.machineState.memory
|
|
33
|
+
const memory = context.machineState.memory;
|
|
34
34
|
const operands = [this.gasOffset, this.addrOffset, this.argsOffset, this.argsSizeOffset, this.successOffset];
|
|
35
35
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
36
36
|
const [gasOffset, addrOffset, argsOffset, argsSizeOffset, successOffset] = addressing.resolve(operands, memory);
|
|
@@ -94,7 +94,6 @@ abstract class ExternalCall extends Instruction {
|
|
|
94
94
|
} else {
|
|
95
95
|
context.persistableState.reject(nestedContext.persistableState);
|
|
96
96
|
}
|
|
97
|
-
memory.assert({ reads: calldataSize + 4, writes: 1, addressing });
|
|
98
97
|
}
|
|
99
98
|
|
|
100
99
|
public abstract override get type(): 'CALL' | 'STATICCALL';
|
|
@@ -134,7 +133,7 @@ export class Return extends Instruction {
|
|
|
134
133
|
}
|
|
135
134
|
|
|
136
135
|
public async execute(context: AvmContext): Promise<void> {
|
|
137
|
-
const memory = context.machineState.memory
|
|
136
|
+
const memory = context.machineState.memory;
|
|
138
137
|
|
|
139
138
|
const operands = [this.returnOffset, this.returnSizeOffset];
|
|
140
139
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
@@ -147,7 +146,6 @@ export class Return extends Instruction {
|
|
|
147
146
|
const output = memory.getSlice(returnOffset, returnSize).map(word => word.toFr());
|
|
148
147
|
|
|
149
148
|
context.machineState.return(output);
|
|
150
|
-
memory.assert({ reads: returnSize + 1, addressing });
|
|
151
149
|
}
|
|
152
150
|
|
|
153
151
|
public override handlesPC(): boolean {
|
|
@@ -177,7 +175,7 @@ export class Revert extends Instruction {
|
|
|
177
175
|
}
|
|
178
176
|
|
|
179
177
|
public async execute(context: AvmContext): Promise<void> {
|
|
180
|
-
const memory = context.machineState.memory
|
|
178
|
+
const memory = context.machineState.memory;
|
|
181
179
|
|
|
182
180
|
const operands = [this.returnOffset, this.retSizeOffset];
|
|
183
181
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
@@ -189,7 +187,6 @@ export class Revert extends Instruction {
|
|
|
189
187
|
const output = memory.getSlice(returnOffset, retSize).map(word => word.toFr());
|
|
190
188
|
|
|
191
189
|
context.machineState.revert(output);
|
|
192
|
-
memory.assert({ reads: retSize + 1, addressing });
|
|
193
190
|
}
|
|
194
191
|
|
|
195
192
|
// We don't want to increase the PC after reverting because it breaks messages.
|
|
@@ -24,7 +24,7 @@ export class Poseidon2 extends Instruction {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
public async execute(context: AvmContext): Promise<void> {
|
|
27
|
-
const memory = context.machineState.memory
|
|
27
|
+
const memory = context.machineState.memory;
|
|
28
28
|
context.machineState.consumeGas(this.gasCost());
|
|
29
29
|
|
|
30
30
|
const operands = [this.inputStateOffset, this.outputStateOffset];
|
|
@@ -39,8 +39,6 @@ export class Poseidon2 extends Instruction {
|
|
|
39
39
|
outputOffset,
|
|
40
40
|
outputState.map(word => new Field(word)),
|
|
41
41
|
);
|
|
42
|
-
|
|
43
|
-
memory.assert({ reads: Poseidon2.stateSize, writes: Poseidon2.stateSize, addressing });
|
|
44
42
|
}
|
|
45
43
|
}
|
|
46
44
|
|
|
@@ -63,7 +61,7 @@ export class KeccakF1600 extends Instruction {
|
|
|
63
61
|
// pub fn keccakf1600(input: [u64; 25]) -> [u64; 25]
|
|
64
62
|
public async execute(context: AvmContext): Promise<void> {
|
|
65
63
|
const inputSize = 25;
|
|
66
|
-
const memory = context.machineState.memory
|
|
64
|
+
const memory = context.machineState.memory;
|
|
67
65
|
const operands = [this.dstOffset, this.inputOffset];
|
|
68
66
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
69
67
|
const [dstOffset, inputOffset] = addressing.resolve(operands, memory);
|
|
@@ -76,8 +74,6 @@ export class KeccakF1600 extends Instruction {
|
|
|
76
74
|
|
|
77
75
|
const res = updatedState.map(word => new Uint64(word));
|
|
78
76
|
memory.setSlice(dstOffset, res);
|
|
79
|
-
|
|
80
|
-
memory.assert({ reads: inputSize, writes: inputSize, addressing });
|
|
81
77
|
}
|
|
82
78
|
}
|
|
83
79
|
|
|
@@ -107,7 +103,7 @@ export class Sha256Compression extends Instruction {
|
|
|
107
103
|
const STATE_SIZE = 8;
|
|
108
104
|
const INPUTS_SIZE = 16;
|
|
109
105
|
|
|
110
|
-
const memory = context.machineState.memory
|
|
106
|
+
const memory = context.machineState.memory;
|
|
111
107
|
const operands = [this.outputOffset, this.stateOffset, this.inputsOffset];
|
|
112
108
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
113
109
|
const [outputOffset, stateOffset, inputsOffset] = addressing.resolve(operands, memory);
|
|
@@ -125,7 +121,5 @@ export class Sha256Compression extends Instruction {
|
|
|
125
121
|
// Conversion required from Uint32Array to Uint32[] (can't map directly, need `...`)
|
|
126
122
|
const res = [...output].map(word => new Uint32(word));
|
|
127
123
|
memory.setSlice(outputOffset, res);
|
|
128
|
-
|
|
129
|
-
memory.assert({ reads: STATE_SIZE + INPUTS_SIZE, writes: STATE_SIZE, addressing });
|
|
130
124
|
}
|
|
131
125
|
}
|
|
@@ -66,15 +66,13 @@ export class Set extends Instruction {
|
|
|
66
66
|
// Constructor ensured that this.inTag is a valid tag
|
|
67
67
|
const res = TaggedMemory.buildFromTagTruncating(this.value, this.inTag);
|
|
68
68
|
|
|
69
|
-
const memory = context.machineState.memory
|
|
69
|
+
const memory = context.machineState.memory;
|
|
70
70
|
context.machineState.consumeGas(this.gasCost());
|
|
71
71
|
|
|
72
72
|
const operands = [this.dstOffset];
|
|
73
73
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
74
74
|
const [dstOffset] = addressing.resolve(operands, memory);
|
|
75
75
|
memory.set(dstOffset, res);
|
|
76
|
-
|
|
77
|
-
memory.assert({ writes: 1, addressing });
|
|
78
76
|
}
|
|
79
77
|
}
|
|
80
78
|
|
|
@@ -103,7 +101,7 @@ export class Cast extends Instruction {
|
|
|
103
101
|
}
|
|
104
102
|
|
|
105
103
|
public async execute(context: AvmContext): Promise<void> {
|
|
106
|
-
const memory = context.machineState.memory
|
|
104
|
+
const memory = context.machineState.memory;
|
|
107
105
|
context.machineState.consumeGas(this.gasCost());
|
|
108
106
|
|
|
109
107
|
const operands = [this.srcOffset, this.dstOffset];
|
|
@@ -115,8 +113,6 @@ export class Cast extends Instruction {
|
|
|
115
113
|
const casted = TaggedMemory.buildFromTagTruncating(a.toBigInt(), this.dstTag);
|
|
116
114
|
|
|
117
115
|
memory.set(dstOffset, casted);
|
|
118
|
-
|
|
119
|
-
memory.assert({ reads: 1, writes: 1, addressing });
|
|
120
116
|
}
|
|
121
117
|
}
|
|
122
118
|
|
|
@@ -143,18 +139,14 @@ export class Mov extends Instruction {
|
|
|
143
139
|
}
|
|
144
140
|
|
|
145
141
|
public async execute(context: AvmContext): Promise<void> {
|
|
146
|
-
const memory = context.machineState.memory
|
|
142
|
+
const memory = context.machineState.memory;
|
|
147
143
|
context.machineState.consumeGas(this.gasCost());
|
|
148
144
|
|
|
149
145
|
const operands = [this.srcOffset, this.dstOffset];
|
|
150
146
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
151
147
|
const [srcOffset, dstOffset] = addressing.resolve(operands, memory);
|
|
152
|
-
|
|
153
148
|
const a = memory.get(srcOffset);
|
|
154
|
-
|
|
155
149
|
memory.set(dstOffset, a);
|
|
156
|
-
|
|
157
|
-
memory.assert({ reads: 1, writes: 1, addressing });
|
|
158
150
|
}
|
|
159
151
|
}
|
|
160
152
|
|
|
@@ -180,7 +172,7 @@ export class CalldataCopy extends Instruction {
|
|
|
180
172
|
}
|
|
181
173
|
|
|
182
174
|
public async execute(context: AvmContext): Promise<void> {
|
|
183
|
-
const memory = context.machineState.memory
|
|
175
|
+
const memory = context.machineState.memory;
|
|
184
176
|
const operands = [this.cdStartOffset, this.copySizeOffset, this.dstOffset];
|
|
185
177
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
186
178
|
const [cdStartOffset, copySizeOffset, dstOffset] = addressing.resolve(operands, memory);
|
|
@@ -196,8 +188,6 @@ export class CalldataCopy extends Instruction {
|
|
|
196
188
|
const transformedData = [...slice, ...Array(copySize - slice.length).fill(new Field(0))];
|
|
197
189
|
|
|
198
190
|
memory.setSlice(dstOffset, transformedData);
|
|
199
|
-
|
|
200
|
-
memory.assert({ reads: 2, writes: copySize, addressing });
|
|
201
191
|
}
|
|
202
192
|
}
|
|
203
193
|
|
|
@@ -212,15 +202,13 @@ export class ReturndataSize extends Instruction {
|
|
|
212
202
|
}
|
|
213
203
|
|
|
214
204
|
public async execute(context: AvmContext): Promise<void> {
|
|
215
|
-
const memory = context.machineState.memory
|
|
205
|
+
const memory = context.machineState.memory;
|
|
216
206
|
const operands = [this.dstOffset];
|
|
217
207
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
218
208
|
const [dstOffset] = addressing.resolve(operands, memory);
|
|
219
209
|
context.machineState.consumeGas(this.gasCost());
|
|
220
210
|
|
|
221
211
|
memory.set(dstOffset, new Uint32(context.machineState.nestedReturndata.length));
|
|
222
|
-
|
|
223
|
-
memory.assert({ writes: 1, addressing });
|
|
224
212
|
}
|
|
225
213
|
}
|
|
226
214
|
|
|
@@ -246,7 +234,7 @@ export class ReturndataCopy extends Instruction {
|
|
|
246
234
|
}
|
|
247
235
|
|
|
248
236
|
public async execute(context: AvmContext): Promise<void> {
|
|
249
|
-
const memory = context.machineState.memory
|
|
237
|
+
const memory = context.machineState.memory;
|
|
250
238
|
const operands = [this.rdStartOffset, this.copySizeOffset, this.dstOffset];
|
|
251
239
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
252
240
|
const [rdStartOffset, copySizeOffset, dstOffset] = addressing.resolve(operands, memory);
|
|
@@ -262,7 +250,5 @@ export class ReturndataCopy extends Instruction {
|
|
|
262
250
|
const transformedData = [...slice, ...Array(copySize - slice.length).fill(new Field(0))];
|
|
263
251
|
|
|
264
252
|
memory.setSlice(dstOffset, transformedData);
|
|
265
|
-
|
|
266
|
-
memory.assert({ reads: 2, writes: copySize, addressing });
|
|
267
253
|
}
|
|
268
254
|
}
|
package/src/avm/opcodes/misc.ts
CHANGED
|
@@ -32,7 +32,7 @@ export class DebugLog extends Instruction {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
public async execute(context: AvmContext): Promise<void> {
|
|
35
|
-
const memory = context.machineState.memory
|
|
35
|
+
const memory = context.machineState.memory;
|
|
36
36
|
const operands = [this.messageOffset, this.fieldsOffset, this.fieldsSizeOffset];
|
|
37
37
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
38
38
|
const [messageOffset, fieldsOffset, fieldsSizeOffset] = addressing.resolve(operands, memory);
|
|
@@ -56,7 +56,5 @@ export class DebugLog extends Instruction {
|
|
|
56
56
|
);
|
|
57
57
|
|
|
58
58
|
DebugLog.logger.verbose(formattedStr);
|
|
59
|
-
|
|
60
|
-
memory.assert({ reads: 1 + fieldsSize + this.messageSize, addressing });
|
|
61
59
|
}
|
|
62
60
|
}
|
|
@@ -33,7 +33,7 @@ export class MultiScalarMul extends Instruction {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
public async execute(context: AvmContext): Promise<void> {
|
|
36
|
-
const memory = context.machineState.memory
|
|
36
|
+
const memory = context.machineState.memory;
|
|
37
37
|
// Resolve indirects
|
|
38
38
|
const operands = [this.pointsOffset, this.scalarsOffset, this.outputOffset, this.pointsLengthOffset];
|
|
39
39
|
const addressing = Addressing.fromWire(this.indirect, operands.length);
|
|
@@ -117,11 +117,5 @@ export class MultiScalarMul extends Instruction {
|
|
|
117
117
|
memory.setSlice(outputOffset, [new Field(outputPoint.x), new Field(outputPoint.y)]);
|
|
118
118
|
// Check representation of infinity for grumpkin
|
|
119
119
|
memory.setSlice(outputOffset + 2, [new Uint1(outputPoint.equals(Point.ZERO) ? 1 : 0)]);
|
|
120
|
-
|
|
121
|
-
memory.assert({
|
|
122
|
-
reads: 1 + pointsReadLength + scalarReadLength /* points and scalars */,
|
|
123
|
-
writes: 3 /* output triplet */,
|
|
124
|
-
addressing,
|
|
125
|
-
});
|
|
126
120
|
}
|
|
127
121
|
}
|