@aztec/simulator 0.32.1 → 0.33.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.
- package/README.md +5 -3
- package/dest/acvm/oracle/index.d.ts +0 -1
- package/dest/acvm/oracle/index.d.ts.map +1 -1
- package/dest/acvm/oracle/index.js +1 -2
- package/dest/acvm/oracle/oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/oracle.js +2 -3
- package/dest/avm/avm_context.d.ts +4 -14
- package/dest/avm/avm_context.d.ts.map +1 -1
- package/dest/avm/avm_context.js +10 -22
- package/dest/avm/avm_gas.d.ts +71 -0
- package/dest/avm/avm_gas.d.ts.map +1 -0
- package/dest/avm/avm_gas.js +161 -0
- package/dest/avm/avm_machine_state.d.ts +4 -2
- package/dest/avm/avm_machine_state.d.ts.map +1 -1
- package/dest/avm/avm_machine_state.js +8 -2
- package/dest/avm/avm_memory_types.d.ts +53 -1
- package/dest/avm/avm_memory_types.d.ts.map +1 -1
- package/dest/avm/avm_memory_types.js +95 -2
- package/dest/avm/avm_simulator.d.ts.map +1 -1
- package/dest/avm/avm_simulator.js +10 -8
- package/dest/avm/opcodes/accrued_substate.d.ts.map +1 -1
- package/dest/avm/opcodes/accrued_substate.js +44 -16
- package/dest/avm/opcodes/addressing_mode.d.ts +5 -3
- package/dest/avm/opcodes/addressing_mode.d.ts.map +1 -1
- package/dest/avm/opcodes/addressing_mode.js +5 -1
- package/dest/avm/opcodes/arithmetic.d.ts +7 -3
- package/dest/avm/opcodes/arithmetic.d.ts.map +1 -1
- package/dest/avm/opcodes/arithmetic.js +27 -16
- package/dest/avm/opcodes/bitwise.d.ts +21 -20
- package/dest/avm/opcodes/bitwise.d.ts.map +1 -1
- package/dest/avm/opcodes/bitwise.js +43 -65
- package/dest/avm/opcodes/comparators.d.ts +12 -9
- package/dest/avm/opcodes/comparators.d.ts.map +1 -1
- package/dest/avm/opcodes/comparators.js +22 -32
- package/dest/avm/opcodes/context_getters.d.ts +20 -0
- package/dest/avm/opcodes/context_getters.d.ts.map +1 -0
- package/dest/avm/opcodes/context_getters.js +26 -0
- package/dest/avm/opcodes/contract.d.ts +14 -0
- package/dest/avm/opcodes/contract.d.ts.map +1 -0
- package/dest/avm/opcodes/contract.js +49 -0
- package/dest/avm/opcodes/control_flow.d.ts.map +1 -1
- package/dest/avm/opcodes/control_flow.js +12 -2
- package/dest/avm/opcodes/environment_getters.d.ts +30 -33
- package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
- package/dest/avm/opcodes/environment_getters.js +34 -43
- package/dest/avm/opcodes/external_calls.d.ts +13 -19
- package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
- package/dest/avm/opcodes/external_calls.js +50 -68
- package/dest/avm/opcodes/hashing.d.ts +2 -1
- package/dest/avm/opcodes/hashing.d.ts.map +1 -1
- package/dest/avm/opcodes/hashing.js +37 -18
- package/dest/avm/opcodes/index.d.ts +1 -0
- package/dest/avm/opcodes/index.d.ts.map +1 -1
- package/dest/avm/opcodes/index.js +2 -1
- package/dest/avm/opcodes/instruction.d.ts +10 -15
- package/dest/avm/opcodes/instruction.d.ts.map +1 -1
- package/dest/avm/opcodes/instruction.js +12 -22
- package/dest/avm/opcodes/instruction_impl.d.ts +14 -0
- package/dest/avm/opcodes/instruction_impl.d.ts.map +1 -1
- package/dest/avm/opcodes/instruction_impl.js +37 -16
- package/dest/avm/opcodes/memory.d.ts +4 -3
- package/dest/avm/opcodes/memory.d.ts.map +1 -1
- package/dest/avm/opcodes/memory.js +38 -19
- package/dest/avm/opcodes/storage.d.ts +5 -0
- package/dest/avm/opcodes/storage.d.ts.map +1 -1
- package/dest/avm/opcodes/storage.js +21 -7
- package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
- package/dest/avm/serialization/bytecode_serialization.js +7 -5
- package/dest/avm/serialization/instruction_serialization.d.ts +12 -11
- package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
- package/dest/avm/serialization/instruction_serialization.js +13 -12
- package/dest/avm/temporary_executor_migration.d.ts +2 -0
- package/dest/avm/temporary_executor_migration.d.ts.map +1 -1
- package/dest/avm/temporary_executor_migration.js +14 -3
- package/dest/client/private_execution.d.ts.map +1 -1
- package/dest/client/private_execution.js +6 -2
- package/dest/public/executor.d.ts +10 -2
- package/dest/public/executor.d.ts.map +1 -1
- package/dest/public/executor.js +59 -20
- package/dest/public/index.d.ts +1 -1
- package/dest/public/index.d.ts.map +1 -1
- package/package.json +15 -9
- package/src/acvm/oracle/index.ts +0 -1
- package/src/acvm/oracle/oracle.ts +1 -2
- package/src/avm/avm_context.ts +11 -33
- package/src/avm/{avm_gas_cost.ts → avm_gas.ts} +75 -21
- package/src/avm/avm_machine_state.ts +9 -2
- package/src/avm/avm_memory_types.ts +130 -2
- package/src/avm/avm_simulator.ts +9 -7
- package/src/avm/opcodes/accrued_substate.ts +57 -22
- package/src/avm/opcodes/addressing_mode.ts +8 -3
- package/src/avm/opcodes/arithmetic.ts +32 -22
- package/src/avm/opcodes/bitwise.ts +49 -83
- package/src/avm/opcodes/comparators.ts +28 -43
- package/src/avm/opcodes/context_getters.ts +32 -0
- package/src/avm/opcodes/contract.ts +58 -0
- package/src/avm/opcodes/control_flow.ts +23 -5
- package/src/avm/opcodes/environment_getters.ts +35 -44
- package/src/avm/opcodes/external_calls.ts +65 -84
- package/src/avm/opcodes/hashing.ts +45 -22
- package/src/avm/opcodes/index.ts +1 -0
- package/src/avm/opcodes/instruction.ts +14 -26
- package/src/avm/opcodes/instruction_impl.ts +45 -15
- package/src/avm/opcodes/memory.ts +48 -28
- package/src/avm/opcodes/storage.ts +26 -12
- package/src/avm/serialization/bytecode_serialization.ts +6 -3
- package/src/avm/serialization/instruction_serialization.ts +1 -0
- package/src/avm/temporary_executor_migration.ts +16 -2
- package/src/client/private_execution.ts +8 -2
- package/src/public/executor.ts +75 -22
- package/src/public/index.ts +2 -2
- package/dest/acvm/oracle/debug.d.ts +0 -19
- package/dest/acvm/oracle/debug.d.ts.map +0 -1
- package/dest/acvm/oracle/debug.js +0 -95
- package/dest/avm/avm_gas_cost.d.ts +0 -322
- package/dest/avm/avm_gas_cost.d.ts.map +0 -1
- package/dest/avm/avm_gas_cost.js +0 -118
- package/src/acvm/oracle/debug.ts +0 -109
|
@@ -2,136 +2,127 @@ import { type Fr } from '@aztec/circuits.js';
|
|
|
2
2
|
|
|
3
3
|
import type { AvmContext } from '../avm_context.js';
|
|
4
4
|
import type { AvmExecutionEnvironment } from '../avm_execution_environment.js';
|
|
5
|
-
import { Field } from '../avm_memory_types.js';
|
|
6
|
-
import { Opcode
|
|
7
|
-
import {
|
|
5
|
+
import { Field, type MemoryValue } from '../avm_memory_types.js';
|
|
6
|
+
import { Opcode } from '../serialization/instruction_serialization.js';
|
|
7
|
+
import { GetterInstruction } from './instruction_impl.js';
|
|
8
8
|
|
|
9
|
-
abstract class
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
constructor(protected indirect: number, protected dstOffset: number) {
|
|
14
|
-
super();
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
async execute(context: AvmContext): Promise<void> {
|
|
18
|
-
const res = new Field(this.getIt(context.environment));
|
|
19
|
-
context.machineState.memory.set(this.dstOffset, res);
|
|
20
|
-
context.machineState.incrementPc();
|
|
9
|
+
abstract class EnvironmentGetterInstruction extends GetterInstruction {
|
|
10
|
+
protected getValue(context: AvmContext): MemoryValue {
|
|
11
|
+
return new Field(this.getEnvironmentValue(context.environment));
|
|
21
12
|
}
|
|
22
13
|
|
|
23
|
-
protected abstract
|
|
14
|
+
protected abstract getEnvironmentValue(env: AvmExecutionEnvironment): Fr | number | bigint;
|
|
24
15
|
}
|
|
25
16
|
|
|
26
|
-
export class Address extends
|
|
17
|
+
export class Address extends EnvironmentGetterInstruction {
|
|
27
18
|
static type: string = 'ADDRESS';
|
|
28
19
|
static readonly opcode: Opcode = Opcode.ADDRESS;
|
|
29
20
|
|
|
30
|
-
protected
|
|
21
|
+
protected getEnvironmentValue(env: AvmExecutionEnvironment) {
|
|
31
22
|
return env.address;
|
|
32
23
|
}
|
|
33
24
|
}
|
|
34
25
|
|
|
35
|
-
export class StorageAddress extends
|
|
26
|
+
export class StorageAddress extends EnvironmentGetterInstruction {
|
|
36
27
|
static type: string = 'STORAGEADDRESS';
|
|
37
28
|
static readonly opcode: Opcode = Opcode.STORAGEADDRESS;
|
|
38
29
|
|
|
39
|
-
protected
|
|
30
|
+
protected getEnvironmentValue(env: AvmExecutionEnvironment) {
|
|
40
31
|
return env.storageAddress;
|
|
41
32
|
}
|
|
42
33
|
}
|
|
43
34
|
|
|
44
|
-
export class Sender extends
|
|
35
|
+
export class Sender extends EnvironmentGetterInstruction {
|
|
45
36
|
static type: string = 'SENDER';
|
|
46
37
|
static readonly opcode: Opcode = Opcode.SENDER;
|
|
47
38
|
|
|
48
|
-
protected
|
|
39
|
+
protected getEnvironmentValue(env: AvmExecutionEnvironment) {
|
|
49
40
|
return env.sender;
|
|
50
41
|
}
|
|
51
42
|
}
|
|
52
43
|
|
|
53
|
-
export class Origin extends
|
|
44
|
+
export class Origin extends EnvironmentGetterInstruction {
|
|
54
45
|
static type: string = 'ORIGIN';
|
|
55
46
|
static readonly opcode: Opcode = Opcode.ORIGIN;
|
|
56
47
|
|
|
57
|
-
protected
|
|
48
|
+
protected getEnvironmentValue(env: AvmExecutionEnvironment) {
|
|
58
49
|
return env.origin;
|
|
59
50
|
}
|
|
60
51
|
}
|
|
61
52
|
|
|
62
|
-
export class FeePerL1Gas extends
|
|
53
|
+
export class FeePerL1Gas extends EnvironmentGetterInstruction {
|
|
63
54
|
static type: string = 'FEEPERL1GAS';
|
|
64
55
|
static readonly opcode: Opcode = Opcode.FEEPERL1GAS;
|
|
65
56
|
|
|
66
|
-
protected
|
|
57
|
+
protected getEnvironmentValue(env: AvmExecutionEnvironment) {
|
|
67
58
|
return env.feePerL1Gas;
|
|
68
59
|
}
|
|
69
60
|
}
|
|
70
61
|
|
|
71
|
-
export class FeePerL2Gas extends
|
|
62
|
+
export class FeePerL2Gas extends EnvironmentGetterInstruction {
|
|
72
63
|
static type: string = 'FEEPERL2GAS';
|
|
73
64
|
static readonly opcode: Opcode = Opcode.FEEPERL2GAS;
|
|
74
65
|
|
|
75
|
-
protected
|
|
66
|
+
protected getEnvironmentValue(env: AvmExecutionEnvironment) {
|
|
76
67
|
return env.feePerL2Gas;
|
|
77
68
|
}
|
|
78
69
|
}
|
|
79
70
|
|
|
80
|
-
export class FeePerDAGas extends
|
|
71
|
+
export class FeePerDAGas extends EnvironmentGetterInstruction {
|
|
81
72
|
static type: string = 'FEEPERDAGAS';
|
|
82
73
|
static readonly opcode: Opcode = Opcode.FEEPERDAGAS;
|
|
83
74
|
|
|
84
|
-
protected
|
|
75
|
+
protected getEnvironmentValue(env: AvmExecutionEnvironment) {
|
|
85
76
|
return env.feePerDaGas;
|
|
86
77
|
}
|
|
87
78
|
}
|
|
88
79
|
|
|
89
|
-
export class Portal extends
|
|
80
|
+
export class Portal extends EnvironmentGetterInstruction {
|
|
90
81
|
static type: string = 'PORTAL';
|
|
91
82
|
static readonly opcode: Opcode = Opcode.PORTAL;
|
|
92
83
|
|
|
93
|
-
protected
|
|
84
|
+
protected getEnvironmentValue(env: AvmExecutionEnvironment) {
|
|
94
85
|
return env.portal.toField();
|
|
95
86
|
}
|
|
96
87
|
}
|
|
97
88
|
|
|
98
|
-
export class ChainId extends
|
|
89
|
+
export class ChainId extends EnvironmentGetterInstruction {
|
|
99
90
|
static type: string = 'CHAINID';
|
|
100
91
|
static readonly opcode: Opcode = Opcode.CHAINID;
|
|
101
92
|
|
|
102
|
-
protected
|
|
93
|
+
protected getEnvironmentValue(env: AvmExecutionEnvironment) {
|
|
103
94
|
return env.globals.chainId;
|
|
104
95
|
}
|
|
105
96
|
}
|
|
106
97
|
|
|
107
|
-
export class Version extends
|
|
98
|
+
export class Version extends EnvironmentGetterInstruction {
|
|
108
99
|
static type: string = 'VERSION';
|
|
109
100
|
static readonly opcode: Opcode = Opcode.VERSION;
|
|
110
101
|
|
|
111
|
-
protected
|
|
102
|
+
protected getEnvironmentValue(env: AvmExecutionEnvironment) {
|
|
112
103
|
return env.globals.version;
|
|
113
104
|
}
|
|
114
105
|
}
|
|
115
106
|
|
|
116
|
-
export class BlockNumber extends
|
|
107
|
+
export class BlockNumber extends EnvironmentGetterInstruction {
|
|
117
108
|
static type: string = 'BLOCKNUMBER';
|
|
118
109
|
static readonly opcode: Opcode = Opcode.BLOCKNUMBER;
|
|
119
110
|
|
|
120
|
-
protected
|
|
111
|
+
protected getEnvironmentValue(env: AvmExecutionEnvironment) {
|
|
121
112
|
return env.globals.blockNumber;
|
|
122
113
|
}
|
|
123
114
|
}
|
|
124
115
|
|
|
125
|
-
export class Timestamp extends
|
|
116
|
+
export class Timestamp extends EnvironmentGetterInstruction {
|
|
126
117
|
static type: string = 'TIMESTAMP';
|
|
127
118
|
static readonly opcode: Opcode = Opcode.TIMESTAMP;
|
|
128
119
|
|
|
129
|
-
protected
|
|
120
|
+
protected getEnvironmentValue(env: AvmExecutionEnvironment) {
|
|
130
121
|
return env.globals.timestamp;
|
|
131
122
|
}
|
|
132
123
|
}
|
|
133
124
|
|
|
134
|
-
// export class Coinbase extends
|
|
125
|
+
// export class Coinbase extends EnvironmentGetterInstruction {
|
|
135
126
|
// static type: string = 'COINBASE';
|
|
136
127
|
// static numberOfOperands = 1;
|
|
137
128
|
|
|
@@ -149,7 +140,7 @@ export class Timestamp extends GetterInstruction {
|
|
|
149
140
|
// }
|
|
150
141
|
|
|
151
142
|
// // TODO: are these even needed within the block? (both block gas limit variables - why does the execution env care?)
|
|
152
|
-
// export class BlockL1GasLimit extends
|
|
143
|
+
// export class BlockL1GasLimit extends EnvironmentGetterInstruction {
|
|
153
144
|
// static type: string = 'BLOCKL1GASLIMIT';
|
|
154
145
|
// static numberOfOperands = 1;
|
|
155
146
|
|
|
@@ -166,7 +157,7 @@ export class Timestamp extends GetterInstruction {
|
|
|
166
157
|
// }
|
|
167
158
|
// }
|
|
168
159
|
|
|
169
|
-
// export class BlockL2GasLimit extends
|
|
160
|
+
// export class BlockL2GasLimit extends EnvironmentGetterInstruction {
|
|
170
161
|
// static type: string = 'BLOCKL2GASLIMIT';
|
|
171
162
|
// static numberOfOperands = 1;
|
|
172
163
|
|
|
@@ -183,7 +174,7 @@ export class Timestamp extends GetterInstruction {
|
|
|
183
174
|
// }
|
|
184
175
|
// }
|
|
185
176
|
|
|
186
|
-
// export class BlockDAGasLimit extends
|
|
177
|
+
// export class BlockDAGasLimit extends EnvironmentGetterInstruction {
|
|
187
178
|
// static type: string = 'BLOCKDAGASLIMIT';
|
|
188
179
|
// static numberOfOperands = 1;
|
|
189
180
|
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { FunctionSelector } from '@aztec/circuits.js';
|
|
2
|
+
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
2
3
|
|
|
3
4
|
import type { AvmContext } from '../avm_context.js';
|
|
5
|
+
import { gasLeftToGas, sumGas } from '../avm_gas.js';
|
|
4
6
|
import { Field, Uint8 } from '../avm_memory_types.js';
|
|
5
7
|
import { AvmSimulator } from '../avm_simulator.js';
|
|
6
8
|
import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
|
|
7
9
|
import { Addressing } from './addressing_mode.js';
|
|
8
10
|
import { Instruction } from './instruction.js';
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
static type: string = 'CALL';
|
|
12
|
-
static readonly opcode: Opcode = Opcode.CALL;
|
|
12
|
+
abstract class ExternalCall extends Instruction {
|
|
13
13
|
// Informs (de)serialization. See Instruction.deserialize.
|
|
14
14
|
static readonly wireFormat: OperandType[] = [
|
|
15
15
|
OperandType.UINT8,
|
|
@@ -27,7 +27,7 @@ export class Call extends Instruction {
|
|
|
27
27
|
|
|
28
28
|
constructor(
|
|
29
29
|
private indirect: number,
|
|
30
|
-
private
|
|
30
|
+
private gasOffset: number /* Unused due to no formal gas implementation at this moment */,
|
|
31
31
|
private addrOffset: number,
|
|
32
32
|
private argsOffset: number,
|
|
33
33
|
private argsSize: number,
|
|
@@ -42,110 +42,81 @@ export class Call extends Instruction {
|
|
|
42
42
|
super();
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const [
|
|
48
|
-
[this.
|
|
49
|
-
|
|
45
|
+
public async execute(context: AvmContext) {
|
|
46
|
+
const memory = context.machineState.memory.track(this.type);
|
|
47
|
+
const [gasOffset, addrOffset, argsOffset, retOffset, successOffset] = Addressing.fromWire(this.indirect).resolve(
|
|
48
|
+
[this.gasOffset, this.addrOffset, this.argsOffset, this.retOffset, this.successOffset],
|
|
49
|
+
memory,
|
|
50
50
|
);
|
|
51
51
|
|
|
52
|
-
const callAddress =
|
|
53
|
-
const calldata =
|
|
54
|
-
const
|
|
52
|
+
const callAddress = memory.getAs<Field>(addrOffset);
|
|
53
|
+
const calldata = memory.getSlice(argsOffset, this.argsSize).map(f => f.toFr());
|
|
54
|
+
const l1Gas = memory.get(gasOffset).toNumber();
|
|
55
|
+
const l2Gas = memory.getAs<Field>(gasOffset + 1).toNumber();
|
|
56
|
+
const daGas = memory.getAs<Field>(gasOffset + 2).toNumber();
|
|
57
|
+
const functionSelector = memory.getAs<Field>(this.temporaryFunctionSelectorOffset).toFr();
|
|
58
|
+
|
|
59
|
+
const allocatedGas = { l1Gas, l2Gas, daGas };
|
|
60
|
+
const memoryOperations = { reads: this.argsSize + 5, writes: 1 + this.retSize, indirect: this.indirect };
|
|
61
|
+
const totalGas = sumGas(this.gasCost(memoryOperations), allocatedGas);
|
|
62
|
+
context.machineState.consumeGas(totalGas);
|
|
55
63
|
|
|
56
64
|
const nestedContext = context.createNestedContractCallContext(
|
|
57
65
|
callAddress.toFr(),
|
|
58
66
|
calldata,
|
|
67
|
+
allocatedGas,
|
|
68
|
+
this.type,
|
|
59
69
|
FunctionSelector.fromField(functionSelector),
|
|
60
70
|
);
|
|
61
71
|
|
|
62
72
|
const nestedCallResults = await new AvmSimulator(nestedContext).execute();
|
|
63
73
|
const success = !nestedCallResults.reverted;
|
|
64
74
|
|
|
65
|
-
// We only take as much data as was specified in the return size
|
|
75
|
+
// We only take as much data as was specified in the return size and pad with zeroes if the return data is smaller
|
|
76
|
+
// than the specified size in order to prevent that memory to be left with garbage
|
|
66
77
|
const returnData = nestedCallResults.output.slice(0, this.retSize);
|
|
67
|
-
const convertedReturnData =
|
|
78
|
+
const convertedReturnData = padArrayEnd(
|
|
79
|
+
returnData.map(f => new Field(f)),
|
|
80
|
+
new Field(0),
|
|
81
|
+
this.retSize,
|
|
82
|
+
);
|
|
68
83
|
|
|
69
84
|
// Write our return data into memory
|
|
70
|
-
|
|
71
|
-
|
|
85
|
+
memory.set(successOffset, new Uint8(success ? 1 : 0));
|
|
86
|
+
memory.setSlice(retOffset, convertedReturnData);
|
|
87
|
+
|
|
88
|
+
// Refund unused gas
|
|
89
|
+
context.machineState.refundGas(gasLeftToGas(nestedContext.machineState));
|
|
72
90
|
|
|
91
|
+
// TODO: Should we merge the changes from a nested call in the case of a STATIC call?
|
|
73
92
|
if (success) {
|
|
74
93
|
context.persistableState.acceptNestedCallState(nestedContext.persistableState);
|
|
75
94
|
} else {
|
|
76
95
|
context.persistableState.rejectNestedCallState(nestedContext.persistableState);
|
|
77
96
|
}
|
|
78
97
|
|
|
98
|
+
memory.assert(memoryOperations);
|
|
79
99
|
context.machineState.incrementPc();
|
|
80
100
|
}
|
|
101
|
+
|
|
102
|
+
public abstract get type(): 'CALL' | 'STATICCALL';
|
|
81
103
|
}
|
|
82
104
|
|
|
83
|
-
export class
|
|
84
|
-
static type
|
|
85
|
-
static readonly opcode: Opcode = Opcode.
|
|
86
|
-
// Informs (de)serialization. See Instruction.deserialize.
|
|
87
|
-
static readonly wireFormat: OperandType[] = [
|
|
88
|
-
OperandType.UINT8,
|
|
89
|
-
OperandType.UINT8,
|
|
90
|
-
OperandType.UINT32,
|
|
91
|
-
OperandType.UINT32,
|
|
92
|
-
OperandType.UINT32,
|
|
93
|
-
OperandType.UINT32,
|
|
94
|
-
OperandType.UINT32,
|
|
95
|
-
OperandType.UINT32,
|
|
96
|
-
OperandType.UINT32,
|
|
97
|
-
/* temporary function selector */
|
|
98
|
-
OperandType.UINT32,
|
|
99
|
-
];
|
|
105
|
+
export class Call extends ExternalCall {
|
|
106
|
+
static type = 'CALL' as const;
|
|
107
|
+
static readonly opcode: Opcode = Opcode.CALL;
|
|
100
108
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
private _gasOffset: number /* Unused due to no formal gas implementation at this moment */,
|
|
104
|
-
private addrOffset: number,
|
|
105
|
-
private argsOffset: number,
|
|
106
|
-
private argsSize: number,
|
|
107
|
-
private retOffset: number,
|
|
108
|
-
private retSize: number,
|
|
109
|
-
private successOffset: number,
|
|
110
|
-
private temporaryFunctionSelectorOffset: number,
|
|
111
|
-
) {
|
|
112
|
-
super();
|
|
109
|
+
public get type() {
|
|
110
|
+
return Call.type;
|
|
113
111
|
}
|
|
112
|
+
}
|
|
114
113
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
context.machineState.memory,
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
const callAddress = context.machineState.memory.get(addrOffset);
|
|
122
|
-
const calldata = context.machineState.memory.getSlice(argsOffset, this.argsSize).map(f => f.toFr());
|
|
123
|
-
const functionSelector = context.machineState.memory.getAs<Field>(this.temporaryFunctionSelectorOffset).toFr();
|
|
124
|
-
|
|
125
|
-
const nestedContext = context.createNestedContractStaticCallContext(
|
|
126
|
-
callAddress.toFr(),
|
|
127
|
-
calldata,
|
|
128
|
-
FunctionSelector.fromField(functionSelector),
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
const nestedCallResults = await new AvmSimulator(nestedContext).execute();
|
|
132
|
-
const success = !nestedCallResults.reverted;
|
|
133
|
-
|
|
134
|
-
// We only take as much data as was specified in the return size -> TODO: should we be reverting here
|
|
135
|
-
const returnData = nestedCallResults.output.slice(0, this.retSize);
|
|
136
|
-
const convertedReturnData = returnData.map(f => new Field(f));
|
|
137
|
-
|
|
138
|
-
// Write our return data into memory
|
|
139
|
-
context.machineState.memory.set(successOffset, new Uint8(success ? 1 : 0));
|
|
140
|
-
context.machineState.memory.setSlice(retOffset, convertedReturnData);
|
|
141
|
-
|
|
142
|
-
if (success) {
|
|
143
|
-
context.persistableState.acceptNestedCallState(nestedContext.persistableState);
|
|
144
|
-
} else {
|
|
145
|
-
context.persistableState.rejectNestedCallState(nestedContext.persistableState);
|
|
146
|
-
}
|
|
114
|
+
export class StaticCall extends ExternalCall {
|
|
115
|
+
static type = 'STATICCALL' as const;
|
|
116
|
+
static readonly opcode: Opcode = Opcode.STATICCALL;
|
|
147
117
|
|
|
148
|
-
|
|
118
|
+
public get type() {
|
|
119
|
+
return StaticCall.type;
|
|
149
120
|
}
|
|
150
121
|
}
|
|
151
122
|
|
|
@@ -164,12 +135,17 @@ export class Return extends Instruction {
|
|
|
164
135
|
super();
|
|
165
136
|
}
|
|
166
137
|
|
|
167
|
-
async execute(context: AvmContext): Promise<void> {
|
|
168
|
-
const
|
|
138
|
+
public async execute(context: AvmContext): Promise<void> {
|
|
139
|
+
const memoryOperations = { reads: this.copySize, indirect: this.indirect };
|
|
140
|
+
const memory = context.machineState.memory.track(this.type);
|
|
141
|
+
context.machineState.consumeGas(this.gasCost(memoryOperations));
|
|
142
|
+
|
|
143
|
+
const [returnOffset] = Addressing.fromWire(this.indirect).resolve([this.returnOffset], memory);
|
|
169
144
|
|
|
170
|
-
const output =
|
|
145
|
+
const output = memory.getSlice(returnOffset, this.copySize).map(word => word.toFr());
|
|
171
146
|
|
|
172
147
|
context.machineState.return(output);
|
|
148
|
+
memory.assert(memoryOperations);
|
|
173
149
|
}
|
|
174
150
|
}
|
|
175
151
|
|
|
@@ -188,11 +164,16 @@ export class Revert extends Instruction {
|
|
|
188
164
|
super();
|
|
189
165
|
}
|
|
190
166
|
|
|
191
|
-
async execute(context: AvmContext): Promise<void> {
|
|
192
|
-
const
|
|
167
|
+
public async execute(context: AvmContext): Promise<void> {
|
|
168
|
+
const memoryOperations = { reads: this.retSize, indirect: this.indirect };
|
|
169
|
+
const memory = context.machineState.memory.track(this.type);
|
|
170
|
+
context.machineState.consumeGas(this.gasCost(memoryOperations));
|
|
171
|
+
|
|
172
|
+
const [returnOffset] = Addressing.fromWire(this.indirect).resolve([this.returnOffset], memory);
|
|
193
173
|
|
|
194
|
-
const output =
|
|
174
|
+
const output = memory.getSlice(returnOffset, this.retSize).map(word => word.toFr());
|
|
195
175
|
|
|
196
176
|
context.machineState.revert(output);
|
|
177
|
+
memory.assert(memoryOperations);
|
|
197
178
|
}
|
|
198
179
|
}
|
|
@@ -29,19 +29,24 @@ export class Poseidon2 extends Instruction {
|
|
|
29
29
|
super();
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
async execute(context: AvmContext): Promise<void> {
|
|
32
|
+
public async execute(context: AvmContext): Promise<void> {
|
|
33
|
+
const memoryOperations = { reads: this.messageSize, writes: 1, indirect: this.indirect };
|
|
34
|
+
const memory = context.machineState.memory.track(this.type);
|
|
35
|
+
context.machineState.consumeGas(this.gasCost(memoryOperations));
|
|
36
|
+
|
|
33
37
|
// We hash a set of field elements
|
|
34
38
|
const [dstOffset, messageOffset] = Addressing.fromWire(this.indirect).resolve(
|
|
35
39
|
[this.dstOffset, this.messageOffset],
|
|
36
|
-
|
|
40
|
+
memory,
|
|
37
41
|
);
|
|
38
42
|
|
|
39
43
|
// Memory pointer will be indirect
|
|
40
|
-
const hashData =
|
|
44
|
+
const hashData = memory.getSlice(messageOffset, this.messageSize).map(word => word.toBuffer());
|
|
41
45
|
|
|
42
46
|
const hash = poseidonHash(hashData);
|
|
43
|
-
|
|
47
|
+
memory.set(dstOffset, new Field(hash));
|
|
44
48
|
|
|
49
|
+
memory.assert(memoryOperations);
|
|
45
50
|
context.machineState.incrementPc();
|
|
46
51
|
}
|
|
47
52
|
}
|
|
@@ -69,14 +74,18 @@ export class Keccak extends Instruction {
|
|
|
69
74
|
}
|
|
70
75
|
|
|
71
76
|
// Note hash output is 32 bytes, so takes up two fields
|
|
72
|
-
async execute(context: AvmContext): Promise<void> {
|
|
77
|
+
public async execute(context: AvmContext): Promise<void> {
|
|
78
|
+
const memoryOperations = { reads: this.messageSize, writes: 2, indirect: this.indirect };
|
|
79
|
+
const memory = context.machineState.memory.track(this.type);
|
|
80
|
+
context.machineState.consumeGas(this.gasCost(memoryOperations));
|
|
81
|
+
|
|
73
82
|
// We hash a set of field elements
|
|
74
83
|
const [dstOffset, messageOffset] = Addressing.fromWire(this.indirect).resolve(
|
|
75
84
|
[this.dstOffset, this.messageOffset],
|
|
76
|
-
|
|
85
|
+
memory,
|
|
77
86
|
);
|
|
78
87
|
|
|
79
|
-
const hashData =
|
|
88
|
+
const hashData = memory.getSlice(messageOffset, this.messageSize).map(word => word.toBuffer());
|
|
80
89
|
|
|
81
90
|
const hash = keccak(Buffer.concat(hashData));
|
|
82
91
|
|
|
@@ -84,9 +93,10 @@ export class Keccak extends Instruction {
|
|
|
84
93
|
const high = new Field(toBigIntBE(hash.subarray(0, 16)));
|
|
85
94
|
const low = new Field(toBigIntBE(hash.subarray(16, 32)));
|
|
86
95
|
|
|
87
|
-
|
|
88
|
-
|
|
96
|
+
memory.set(dstOffset, high);
|
|
97
|
+
memory.set(dstOffset + 1, low);
|
|
89
98
|
|
|
99
|
+
memory.assert(memoryOperations);
|
|
90
100
|
context.machineState.incrementPc();
|
|
91
101
|
}
|
|
92
102
|
}
|
|
@@ -114,14 +124,18 @@ export class Sha256 extends Instruction {
|
|
|
114
124
|
}
|
|
115
125
|
|
|
116
126
|
// Note hash output is 32 bytes, so takes up two fields
|
|
117
|
-
async execute(context: AvmContext): Promise<void> {
|
|
127
|
+
public async execute(context: AvmContext): Promise<void> {
|
|
128
|
+
const memoryOperations = { reads: this.messageSize, writes: 2, indirect: this.indirect };
|
|
129
|
+
const memory = context.machineState.memory.track(this.type);
|
|
130
|
+
context.machineState.consumeGas(this.gasCost(memoryOperations));
|
|
131
|
+
|
|
118
132
|
const [dstOffset, messageOffset] = Addressing.fromWire(this.indirect).resolve(
|
|
119
133
|
[this.dstOffset, this.messageOffset],
|
|
120
|
-
|
|
134
|
+
memory,
|
|
121
135
|
);
|
|
122
136
|
|
|
123
137
|
// We hash a set of field elements
|
|
124
|
-
const hashData =
|
|
138
|
+
const hashData = memory.getSlice(messageOffset, this.messageSize).map(word => word.toBuffer());
|
|
125
139
|
|
|
126
140
|
const hash = sha256(Buffer.concat(hashData));
|
|
127
141
|
|
|
@@ -129,9 +143,10 @@ export class Sha256 extends Instruction {
|
|
|
129
143
|
const high = new Field(toBigIntBE(hash.subarray(0, 16)));
|
|
130
144
|
const low = new Field(toBigIntBE(hash.subarray(16, 32)));
|
|
131
145
|
|
|
132
|
-
|
|
133
|
-
|
|
146
|
+
memory.set(dstOffset, high);
|
|
147
|
+
memory.set(dstOffset + 1, low);
|
|
134
148
|
|
|
149
|
+
memory.assert(memoryOperations);
|
|
135
150
|
context.machineState.incrementPc();
|
|
136
151
|
}
|
|
137
152
|
}
|
|
@@ -147,10 +162,12 @@ export class Pedersen extends Instruction {
|
|
|
147
162
|
OperandType.UINT32,
|
|
148
163
|
OperandType.UINT32,
|
|
149
164
|
OperandType.UINT32,
|
|
165
|
+
OperandType.UINT32,
|
|
150
166
|
];
|
|
151
167
|
|
|
152
168
|
constructor(
|
|
153
169
|
private indirect: number,
|
|
170
|
+
private genIndexOffset: number,
|
|
154
171
|
private dstOffset: number,
|
|
155
172
|
private messageOffset: number,
|
|
156
173
|
private messageSizeOffset: number,
|
|
@@ -158,20 +175,26 @@ export class Pedersen extends Instruction {
|
|
|
158
175
|
super();
|
|
159
176
|
}
|
|
160
177
|
|
|
161
|
-
async execute(context: AvmContext): Promise<void> {
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
178
|
+
public async execute(context: AvmContext): Promise<void> {
|
|
179
|
+
const memory = context.machineState.memory.track(this.type);
|
|
180
|
+
const [genIndexOffset, dstOffset, messageOffset, messageSizeOffset] = Addressing.fromWire(this.indirect).resolve(
|
|
181
|
+
[this.genIndexOffset, this.dstOffset, this.messageOffset, this.messageSizeOffset],
|
|
182
|
+
memory,
|
|
165
183
|
);
|
|
166
184
|
|
|
167
185
|
// We hash a set of field elements
|
|
168
|
-
const
|
|
169
|
-
const
|
|
186
|
+
const genIndex = Number(memory.get(genIndexOffset).toBigInt());
|
|
187
|
+
const messageSize = Number(memory.get(messageSizeOffset).toBigInt());
|
|
188
|
+
const hashData = memory.getSlice(messageOffset, messageSize);
|
|
189
|
+
|
|
190
|
+
const memoryOperations = { reads: messageSize + 2, writes: 1, indirect: this.indirect };
|
|
191
|
+
context.machineState.consumeGas(this.gasCost(memoryOperations));
|
|
170
192
|
|
|
171
193
|
// No domain sep for now
|
|
172
|
-
const hash = pedersenHash(hashData);
|
|
173
|
-
|
|
194
|
+
const hash = pedersenHash(hashData, genIndex);
|
|
195
|
+
memory.set(dstOffset, new Field(hash));
|
|
174
196
|
|
|
197
|
+
memory.assert(memoryOperations);
|
|
175
198
|
context.machineState.incrementPc();
|
|
176
199
|
}
|
|
177
200
|
}
|
package/src/avm/opcodes/index.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { strict as assert } from 'assert';
|
|
2
2
|
|
|
3
3
|
import type { AvmContext } from '../avm_context.js';
|
|
4
|
-
import {
|
|
4
|
+
import { getBaseGasCost, getMemoryGasCost, sumGas } from '../avm_gas.js';
|
|
5
|
+
import { type MemoryOperations } from '../avm_memory_types.js';
|
|
5
6
|
import { type BufferCursor } from '../serialization/buffer_cursor.js';
|
|
6
7
|
import { Opcode, type OperandType, deserialize, serialize } from '../serialization/instruction_serialization.js';
|
|
7
8
|
|
|
@@ -20,31 +21,7 @@ export abstract class Instruction {
|
|
|
20
21
|
* This is the main entry point for the instruction.
|
|
21
22
|
* @param context - The AvmContext in which the instruction executes.
|
|
22
23
|
*/
|
|
23
|
-
public
|
|
24
|
-
context.machineState.consumeGas(this.gasCost());
|
|
25
|
-
return this.execute(context);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Loads default gas cost for the instruction from the GasCosts table.
|
|
30
|
-
* Instruction sub-classes can override this if their gas cost is not fixed.
|
|
31
|
-
*/
|
|
32
|
-
protected gasCost(): GasCost {
|
|
33
|
-
const gasCost = GasCosts[this.opcode];
|
|
34
|
-
if (gasCost === DynamicGasCost) {
|
|
35
|
-
throw new Error(`Instruction ${this.type} must define its own gas cost`);
|
|
36
|
-
}
|
|
37
|
-
return gasCost;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Execute the instruction.
|
|
42
|
-
* Instruction sub-classes must implement this.
|
|
43
|
-
* As an AvmContext executes its contract code, it calls this function for
|
|
44
|
-
* each instruction until the machine state signals "halted".
|
|
45
|
-
* @param context - The AvmContext in which the instruction executes.
|
|
46
|
-
*/
|
|
47
|
-
protected abstract execute(context: AvmContext): Promise<void>;
|
|
24
|
+
public abstract execute(context: AvmContext): Promise<void>;
|
|
48
25
|
|
|
49
26
|
/**
|
|
50
27
|
* Generate a string representation of the instruction including
|
|
@@ -85,6 +62,17 @@ export abstract class Instruction {
|
|
|
85
62
|
return new this(...args);
|
|
86
63
|
}
|
|
87
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Computes gas cost for the instruction based on its base cost and memory operations.
|
|
67
|
+
* @param memoryOps Memory operations performed by the instruction.
|
|
68
|
+
* @returns Gas cost.
|
|
69
|
+
*/
|
|
70
|
+
protected gasCost(memoryOps: Partial<MemoryOperations & { indirect: number }> = {}) {
|
|
71
|
+
const baseGasCost = getBaseGasCost(this.opcode);
|
|
72
|
+
const memoryGasCost = getMemoryGasCost(memoryOps);
|
|
73
|
+
return sumGas(baseGasCost, memoryGasCost);
|
|
74
|
+
}
|
|
75
|
+
|
|
88
76
|
/**
|
|
89
77
|
* Returns the stringified type of the instruction.
|
|
90
78
|
* Instruction sub-classes should have a static `type` property.
|