referrerpolicy=no-referrer-when-downgrade

pallet_revive/vm/evm/instructions/
mod.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! EVM opcode implementations.
19
20use crate::vm::{
21	evm::{DummyHost, EVMInterpreter},
22	Ext,
23};
24use revm::interpreter::{Instruction, InstructionContext};
25
26type Context<'ctx, 'ext, E> =
27	InstructionContext<'ctx, crate::vm::evm::DummyHost, crate::vm::evm::EVMInterpreter<'ext, E>>;
28
29#[macro_use]
30mod macros;
31/// Arithmetic operations (ADD, SUB, MUL, DIV, etc.).
32mod arithmetic;
33/// Bitwise operations (AND, OR, XOR, NOT, etc.).
34mod bitwise;
35/// Block information instructions (COINBASE, TIMESTAMP, etc.).
36mod block_info;
37/// Contract operations (CALL, CREATE, DELEGATECALL, etc.).
38mod contract;
39/// Control flow instructions (JUMP, JUMPI, REVERT, etc.).
40mod control;
41/// Host environment interactions (SLOAD, SSTORE, LOG, etc.).
42mod host;
43/// Signed 256-bit integer operations.
44mod i256;
45/// Memory operations (MLOAD, MSTORE, MSIZE, etc.).
46mod memory;
47/// Stack operations (PUSH, POP, DUP, SWAP, etc.).
48mod stack;
49/// System information instructions (ADDRESS, CALLER, etc.).
50mod system;
51/// Transaction information instructions (ORIGIN, GASPRICE, etc.).
52mod tx_info;
53/// Utility functions and helpers for instruction implementation.
54mod utility;
55
56/// Returns the instruction table for the given spec.
57pub const fn instruction_table<'a, E: Ext>() -> [Instruction<EVMInterpreter<'a, E>, DummyHost>; 256]
58{
59	use revm::bytecode::opcode::*;
60	let mut table = [control::unknown as Instruction<EVMInterpreter<'a, E>, DummyHost>; 256];
61
62	table[STOP as usize] = control::stop;
63	table[ADD as usize] = arithmetic::add;
64	table[MUL as usize] = arithmetic::mul;
65	table[SUB as usize] = arithmetic::sub;
66	table[DIV as usize] = arithmetic::div;
67	table[SDIV as usize] = arithmetic::sdiv;
68	table[MOD as usize] = arithmetic::rem;
69	table[SMOD as usize] = arithmetic::smod;
70	table[ADDMOD as usize] = arithmetic::addmod;
71	table[MULMOD as usize] = arithmetic::mulmod;
72	table[EXP as usize] = arithmetic::exp;
73	table[SIGNEXTEND as usize] = arithmetic::signextend;
74
75	table[LT as usize] = bitwise::lt;
76	table[GT as usize] = bitwise::gt;
77	table[SLT as usize] = bitwise::slt;
78	table[SGT as usize] = bitwise::sgt;
79	table[EQ as usize] = bitwise::eq;
80	table[ISZERO as usize] = bitwise::iszero;
81	table[AND as usize] = bitwise::bitand;
82	table[OR as usize] = bitwise::bitor;
83	table[XOR as usize] = bitwise::bitxor;
84	table[NOT as usize] = bitwise::not;
85	table[BYTE as usize] = bitwise::byte;
86	table[SHL as usize] = bitwise::shl;
87	table[SHR as usize] = bitwise::shr;
88	table[SAR as usize] = bitwise::sar;
89	table[CLZ as usize] = bitwise::clz;
90
91	table[KECCAK256 as usize] = system::keccak256;
92
93	table[ADDRESS as usize] = system::address;
94	table[BALANCE as usize] = host::balance;
95	table[ORIGIN as usize] = tx_info::origin;
96	table[CALLER as usize] = system::caller;
97	table[CALLVALUE as usize] = system::callvalue;
98	table[CALLDATALOAD as usize] = system::calldataload;
99	table[CALLDATASIZE as usize] = system::calldatasize;
100	table[CALLDATACOPY as usize] = system::calldatacopy;
101	table[CODESIZE as usize] = system::codesize;
102	table[CODECOPY as usize] = system::codecopy;
103
104	table[GASPRICE as usize] = tx_info::gasprice;
105	table[EXTCODESIZE as usize] = host::extcodesize;
106	table[EXTCODECOPY as usize] = host::extcodecopy;
107	table[RETURNDATASIZE as usize] = system::returndatasize;
108	table[RETURNDATACOPY as usize] = system::returndatacopy;
109	table[EXTCODEHASH as usize] = host::extcodehash;
110	table[BLOCKHASH as usize] = host::blockhash;
111	table[COINBASE as usize] = block_info::coinbase;
112	table[TIMESTAMP as usize] = block_info::timestamp;
113	table[NUMBER as usize] = block_info::block_number;
114	table[DIFFICULTY as usize] = block_info::difficulty;
115	table[GASLIMIT as usize] = block_info::gaslimit;
116	table[CHAINID as usize] = block_info::chainid;
117	table[SELFBALANCE as usize] = host::selfbalance;
118	table[BASEFEE as usize] = block_info::basefee;
119	table[BLOBHASH as usize] = tx_info::blob_hash;
120	table[BLOBBASEFEE as usize] = block_info::blob_basefee;
121
122	table[POP as usize] = stack::pop;
123	table[MLOAD as usize] = memory::mload;
124	table[MSTORE as usize] = memory::mstore;
125	table[MSTORE8 as usize] = memory::mstore8;
126	table[SLOAD as usize] = host::sload;
127	table[SSTORE as usize] = host::sstore;
128	table[JUMP as usize] = control::jump;
129	table[JUMPI as usize] = control::jumpi;
130	table[PC as usize] = control::pc;
131	table[MSIZE as usize] = memory::msize;
132	table[GAS as usize] = system::gas;
133	table[JUMPDEST as usize] = control::jumpdest;
134	table[TLOAD as usize] = host::tload;
135	table[TSTORE as usize] = host::tstore;
136	table[MCOPY as usize] = memory::mcopy;
137
138	table[PUSH0 as usize] = stack::push0;
139	table[PUSH1 as usize] = stack::push::<1, _>;
140	table[PUSH2 as usize] = stack::push::<2, _>;
141	table[PUSH3 as usize] = stack::push::<3, _>;
142	table[PUSH4 as usize] = stack::push::<4, _>;
143	table[PUSH5 as usize] = stack::push::<5, _>;
144	table[PUSH6 as usize] = stack::push::<6, _>;
145	table[PUSH7 as usize] = stack::push::<7, _>;
146	table[PUSH8 as usize] = stack::push::<8, _>;
147	table[PUSH9 as usize] = stack::push::<9, _>;
148	table[PUSH10 as usize] = stack::push::<10, _>;
149	table[PUSH11 as usize] = stack::push::<11, _>;
150	table[PUSH12 as usize] = stack::push::<12, _>;
151	table[PUSH13 as usize] = stack::push::<13, _>;
152	table[PUSH14 as usize] = stack::push::<14, _>;
153	table[PUSH15 as usize] = stack::push::<15, _>;
154	table[PUSH16 as usize] = stack::push::<16, _>;
155	table[PUSH17 as usize] = stack::push::<17, _>;
156	table[PUSH18 as usize] = stack::push::<18, _>;
157	table[PUSH19 as usize] = stack::push::<19, _>;
158	table[PUSH20 as usize] = stack::push::<20, _>;
159	table[PUSH21 as usize] = stack::push::<21, _>;
160	table[PUSH22 as usize] = stack::push::<22, _>;
161	table[PUSH23 as usize] = stack::push::<23, _>;
162	table[PUSH24 as usize] = stack::push::<24, _>;
163	table[PUSH25 as usize] = stack::push::<25, _>;
164	table[PUSH26 as usize] = stack::push::<26, _>;
165	table[PUSH27 as usize] = stack::push::<27, _>;
166	table[PUSH28 as usize] = stack::push::<28, _>;
167	table[PUSH29 as usize] = stack::push::<29, _>;
168	table[PUSH30 as usize] = stack::push::<30, _>;
169	table[PUSH31 as usize] = stack::push::<31, _>;
170	table[PUSH32 as usize] = stack::push::<32, _>;
171
172	table[DUP1 as usize] = stack::dup::<1, _>;
173	table[DUP2 as usize] = stack::dup::<2, _>;
174	table[DUP3 as usize] = stack::dup::<3, _>;
175	table[DUP4 as usize] = stack::dup::<4, _>;
176	table[DUP5 as usize] = stack::dup::<5, _>;
177	table[DUP6 as usize] = stack::dup::<6, _>;
178	table[DUP7 as usize] = stack::dup::<7, _>;
179	table[DUP8 as usize] = stack::dup::<8, _>;
180	table[DUP9 as usize] = stack::dup::<9, _>;
181	table[DUP10 as usize] = stack::dup::<10, _>;
182	table[DUP11 as usize] = stack::dup::<11, _>;
183	table[DUP12 as usize] = stack::dup::<12, _>;
184	table[DUP13 as usize] = stack::dup::<13, _>;
185	table[DUP14 as usize] = stack::dup::<14, _>;
186	table[DUP15 as usize] = stack::dup::<15, _>;
187	table[DUP16 as usize] = stack::dup::<16, _>;
188
189	table[SWAP1 as usize] = stack::swap::<1, _>;
190	table[SWAP2 as usize] = stack::swap::<2, _>;
191	table[SWAP3 as usize] = stack::swap::<3, _>;
192	table[SWAP4 as usize] = stack::swap::<4, _>;
193	table[SWAP5 as usize] = stack::swap::<5, _>;
194	table[SWAP6 as usize] = stack::swap::<6, _>;
195	table[SWAP7 as usize] = stack::swap::<7, _>;
196	table[SWAP8 as usize] = stack::swap::<8, _>;
197	table[SWAP9 as usize] = stack::swap::<9, _>;
198	table[SWAP10 as usize] = stack::swap::<10, _>;
199	table[SWAP11 as usize] = stack::swap::<11, _>;
200	table[SWAP12 as usize] = stack::swap::<12, _>;
201	table[SWAP13 as usize] = stack::swap::<13, _>;
202	table[SWAP14 as usize] = stack::swap::<14, _>;
203	table[SWAP15 as usize] = stack::swap::<15, _>;
204	table[SWAP16 as usize] = stack::swap::<16, _>;
205
206	table[LOG0 as usize] = host::log::<0, _>;
207	table[LOG1 as usize] = host::log::<1, _>;
208	table[LOG2 as usize] = host::log::<2, _>;
209	table[LOG3 as usize] = host::log::<3, _>;
210	table[LOG4 as usize] = host::log::<4, _>;
211
212	table[CREATE as usize] = contract::create::<false, _>;
213	table[CALL as usize] = contract::call;
214	table[CALLCODE as usize] = contract::call_code;
215	table[RETURN as usize] = control::ret;
216	table[DELEGATECALL as usize] = contract::delegate_call;
217	table[CREATE2 as usize] = contract::create::<true, _>;
218
219	table[STATICCALL as usize] = contract::static_call;
220	table[REVERT as usize] = control::revert;
221	table[INVALID as usize] = control::invalid;
222	table[SELFDESTRUCT as usize] = host::selfdestruct;
223	table
224}
225
226#[cfg(test)]
227mod tests {
228	use super::instruction_table;
229	use revm::bytecode::opcode::*;
230
231	#[test]
232	fn all_instructions_and_opcodes_used() {
233		// known unknown instruction we compare it with other instructions from table.
234		let unknown_instruction = 0x0C_usize;
235
236		use crate::{exec::Stack, tests::Test, ContractBlob};
237		let instr_table = instruction_table::<'static, Stack<'static, Test, ContractBlob<Test>>>();
238
239		let unknown_istr = instr_table[unknown_instruction];
240		for (i, instr) in instr_table.iter().enumerate() {
241			let is_opcode_unknown = OpCode::new(i as u8).is_none();
242			//
243			let is_instr_unknown = std::ptr::fn_addr_eq(*instr, unknown_istr);
244			assert_eq!(is_instr_unknown, is_opcode_unknown, "Opcode 0x{i:X?} is not handled",);
245		}
246	}
247}