evm_interpreter/
etable.rs

1use alloc::boxed::Box;
2use core::{
3	marker::PhantomData,
4	ops::{Deref, DerefMut},
5};
6
7use crate::{
8	error::{CallCreateTrap, ExitException, ExitResult},
9	eval::*,
10	machine::Machine,
11	opcode::Opcode,
12	runtime::{GasState, RuntimeBackend, RuntimeEnvironment, RuntimeState},
13};
14
15/// An etable "set" that can be evaluated. This is the generic trait to support
16/// all types of dispatching strategies (via `match` or an actual etable array).
17pub trait EtableSet {
18	type State;
19	type Handle;
20	type Trap;
21
22	/// Evaluate the etable.
23	///
24	/// ### Safety
25	///
26	/// The interpreter guarantee that the byte at `position` exists.
27	fn eval(
28		&self,
29		machine: &mut Machine<Self::State>,
30		handle: &mut Self::Handle,
31		position: usize,
32	) -> Control<Self::Trap>;
33}
34
35/// A chained Etable, stopping at the first if it does not return
36/// `Control::NoAction`.
37pub struct Chained<E1, E2>(pub E1, pub E2);
38
39impl<S, H, Tr, E1, E2> EtableSet for Chained<E1, E2>
40where
41	E1: EtableSet<State = S, Handle = H, Trap = Tr>,
42	E2: EtableSet<State = S, Handle = H, Trap = Tr>,
43{
44	type State = S;
45	type Handle = H;
46	type Trap = Tr;
47
48	fn eval(&self, machine: &mut Machine<S>, handle: &mut H, position: usize) -> Control<Tr> {
49		let ret1 = self.0.eval(machine, handle, position);
50
51		if let Control::NoAction = ret1 {
52			self.1.eval(machine, handle, position)
53		} else {
54			ret1
55		}
56	}
57}
58
59/// A tracing Etable, with pre and post actions.
60pub struct Tracing<EPre, E, EPost>(pub EPre, pub E, pub EPost);
61
62impl<S, H, Tr, EPre, E, EPost> EtableSet for Tracing<EPre, E, EPost>
63where
64	EPre: EtableSet<State = S, Handle = H, Trap = Tr>,
65	E: EtableSet<State = S, Handle = H, Trap = Tr>,
66	EPost: EtableSet<State = S, Handle = H, Trap = Tr>,
67{
68	type State = S;
69	type Handle = H;
70	type Trap = Tr;
71
72	fn eval(&self, machine: &mut Machine<S>, handle: &mut H, position: usize) -> Control<Tr> {
73		let _ = self.0.eval(machine, handle, position);
74		let ret = self.1.eval(machine, handle, position);
75		let _ = self.2.eval(machine, handle, position);
76
77		ret
78	}
79}
80
81/// Evaluation function type.
82pub type Efn<S, H, Tr> = fn(&mut Machine<S>, &mut H, usize) -> Control<Tr>;
83
84/// Etable with only one function.
85pub struct Single<S, H, Tr, F = Efn<S, H, Tr>>(F, PhantomData<(S, H, Tr)>);
86
87unsafe impl<S, H, Tr, F: Send> Send for Single<S, H, Tr, F> {}
88unsafe impl<S, H, Tr, F: Sync> Sync for Single<S, H, Tr, F> {}
89
90impl<S, H, Tr, F> Deref for Single<S, H, Tr, F> {
91	type Target = F;
92
93	fn deref(&self) -> &F {
94		&self.0
95	}
96}
97
98impl<S, H, Tr, F> DerefMut for Single<S, H, Tr, F> {
99	fn deref_mut(&mut self) -> &mut F {
100		&mut self.0
101	}
102}
103
104impl<S, H, Tr, F> Single<S, H, Tr, F> {
105	/// Create a new single Etable.
106	pub fn new(single: F) -> Self {
107		Self(single, PhantomData)
108	}
109}
110
111impl<S, H, Tr, F> EtableSet for Single<S, H, Tr, F>
112where
113	F: Fn(&mut Machine<S>, &mut H, usize) -> Control<Tr>,
114{
115	type State = S;
116	type Handle = H;
117	type Trap = Tr;
118
119	fn eval(&self, machine: &mut Machine<S>, handle: &mut H, position: usize) -> Control<Tr> {
120		self.0(machine, handle, position)
121	}
122}
123
124/// Nested evaluation function.
125pub enum MultiEfn<S, H, Tr, F = Efn<S, H, Tr>> {
126	/// Leaf function.
127	Leaf(F),
128	/// Node function.
129	Node(Box<MultiEtable<S, H, Tr, F>>),
130}
131
132unsafe impl<S, H, Tr, F: Send> Send for MultiEfn<S, H, Tr, F> {}
133unsafe impl<S, H, Tr, F: Sync> Sync for MultiEfn<S, H, Tr, F> {}
134
135/// Nested evaluation table.
136pub struct MultiEtable<S, H, Tr, F = Efn<S, H, Tr>>(
137	[MultiEfn<S, H, Tr, F>; 256],
138	PhantomData<(S, H, Tr)>,
139);
140
141unsafe impl<S, H, Tr, F: Send> Send for MultiEtable<S, H, Tr, F> {}
142unsafe impl<S, H, Tr, F: Sync> Sync for MultiEtable<S, H, Tr, F> {}
143
144impl<S, H, Tr, F> Deref for MultiEtable<S, H, Tr, F> {
145	type Target = [MultiEfn<S, H, Tr, F>; 256];
146
147	fn deref(&self) -> &[MultiEfn<S, H, Tr, F>; 256] {
148		&self.0
149	}
150}
151
152impl<S, H, Tr, F> DerefMut for MultiEtable<S, H, Tr, F> {
153	fn deref_mut(&mut self) -> &mut [MultiEfn<S, H, Tr, F>; 256] {
154		&mut self.0
155	}
156}
157
158impl<S, H, Tr, F> From<Etable<S, H, Tr, F>> for MultiEtable<S, H, Tr, F> {
159	fn from(etable: Etable<S, H, Tr, F>) -> Self {
160		Self(etable.0.map(|v| MultiEfn::Leaf(v)), PhantomData)
161	}
162}
163
164impl<S, H, Tr, F> EtableSet for MultiEtable<S, H, Tr, F>
165where
166	F: Fn(&mut Machine<S>, &mut H, usize) -> Control<Tr>,
167{
168	type State = S;
169	type Handle = H;
170	type Trap = Tr;
171
172	fn eval(&self, machine: &mut Machine<S>, handle: &mut H, position: usize) -> Control<Tr> {
173		let opcode = Opcode(machine.code()[position]);
174
175		match &self[opcode.as_usize()] {
176			MultiEfn::Leaf(f) => f(machine, handle, position),
177			MultiEfn::Node(n) => {
178				let nextpos = position + 1;
179				if nextpos >= machine.code.len() {
180					return Control::Exit(ExitException::PCUnderflow.into());
181				}
182
183				match n.eval(machine, handle, nextpos) {
184					Control::Continue(c) => Control::Continue(c + 1),
185					ctrl => ctrl,
186				}
187			}
188		}
189	}
190}
191
192/// The evaluation table for the EVM.
193pub struct Etable<S, H, Tr, F = Efn<S, H, Tr>>([F; 256], PhantomData<(S, H, Tr)>);
194
195unsafe impl<S, H, Tr, F: Send> Send for Etable<S, H, Tr, F> {}
196unsafe impl<S, H, Tr, F: Sync> Sync for Etable<S, H, Tr, F> {}
197
198impl<S, H, Tr, F> Deref for Etable<S, H, Tr, F> {
199	type Target = [F; 256];
200
201	fn deref(&self) -> &[F; 256] {
202		&self.0
203	}
204}
205
206impl<S, H, Tr, F> DerefMut for Etable<S, H, Tr, F> {
207	fn deref_mut(&mut self) -> &mut [F; 256] {
208		&mut self.0
209	}
210}
211
212impl<S, H, Tr, F> From<Single<S, H, Tr, F>> for Etable<S, H, Tr, F>
213where
214	F: Copy,
215{
216	fn from(single: Single<S, H, Tr, F>) -> Self {
217		Self([single.0; 256], PhantomData)
218	}
219}
220
221impl<S, H, Tr, F> EtableSet for Etable<S, H, Tr, F>
222where
223	F: Fn(&mut Machine<S>, &mut H, usize) -> Control<Tr>,
224{
225	type State = S;
226	type Handle = H;
227	type Trap = Tr;
228
229	fn eval(&self, machine: &mut Machine<S>, handle: &mut H, position: usize) -> Control<Tr> {
230		let opcode = Opcode(machine.code()[position]);
231
232		self[opcode.as_usize()](machine, handle, position)
233	}
234}
235
236impl<S, H, Tr, F> Etable<S, H, Tr, F>
237where
238	F: Fn(&mut Machine<S>, &mut H, usize) -> Control<Tr>,
239{
240	/// Wrap to create a new Etable.
241	pub fn wrap<FW, FR>(self, wrapper: FW) -> Etable<S, H, Tr, FR>
242	where
243		FW: Fn(F, Opcode) -> FR,
244		FR: Fn(&mut Machine<S>, &mut H, usize) -> Control<Tr>,
245	{
246		let mut current_opcode = Opcode(0);
247		Etable(
248			self.0.map(|f| {
249				let fr = wrapper(f, current_opcode);
250				if current_opcode != Opcode(255) {
251					current_opcode.0 += 1;
252				}
253				fr
254			}),
255			PhantomData,
256		)
257	}
258}
259
260impl<S, H, Tr> Etable<S, H, Tr> {
261	#[must_use]
262	pub const fn none() -> Self {
263		Self([eval_unknown as _; 256], PhantomData)
264	}
265
266	#[must_use]
267	pub const fn pass() -> Self {
268		Self([eval_pass as _; 256], PhantomData)
269	}
270
271	/// Default core value for Etable.
272	#[must_use]
273	pub const fn core() -> Self {
274		let mut table = [eval_unknown as _; 256];
275
276		table[Opcode::STOP.as_usize()] = eval_stop as _;
277		table[Opcode::ADD.as_usize()] = eval_add as _;
278		table[Opcode::MUL.as_usize()] = eval_mul as _;
279		table[Opcode::SUB.as_usize()] = eval_sub as _;
280		table[Opcode::DIV.as_usize()] = eval_div as _;
281		table[Opcode::SDIV.as_usize()] = eval_sdiv as _;
282		table[Opcode::MOD.as_usize()] = eval_mod as _;
283		table[Opcode::SMOD.as_usize()] = eval_smod as _;
284		table[Opcode::ADDMOD.as_usize()] = eval_addmod as _;
285		table[Opcode::MULMOD.as_usize()] = eval_mulmod as _;
286		table[Opcode::EXP.as_usize()] = eval_exp as _;
287		table[Opcode::SIGNEXTEND.as_usize()] = eval_signextend as _;
288
289		table[Opcode::LT.as_usize()] = eval_lt as _;
290		table[Opcode::GT.as_usize()] = eval_gt as _;
291		table[Opcode::SLT.as_usize()] = eval_slt as _;
292		table[Opcode::SGT.as_usize()] = eval_sgt as _;
293		table[Opcode::EQ.as_usize()] = eval_eq as _;
294		table[Opcode::ISZERO.as_usize()] = eval_iszero as _;
295		table[Opcode::AND.as_usize()] = eval_and as _;
296		table[Opcode::OR.as_usize()] = eval_or as _;
297		table[Opcode::XOR.as_usize()] = eval_xor as _;
298		table[Opcode::NOT.as_usize()] = eval_not as _;
299		table[Opcode::BYTE.as_usize()] = eval_byte as _;
300
301		table[Opcode::SHL.as_usize()] = eval_shl as _;
302		table[Opcode::SHR.as_usize()] = eval_shr as _;
303		table[Opcode::SAR.as_usize()] = eval_sar as _;
304
305		table[Opcode::CALLDATALOAD.as_usize()] = eval_calldataload as _;
306		table[Opcode::CALLDATASIZE.as_usize()] = eval_calldatasize as _;
307		table[Opcode::CALLDATACOPY.as_usize()] = eval_calldatacopy as _;
308		table[Opcode::CODESIZE.as_usize()] = eval_codesize as _;
309		table[Opcode::CODECOPY.as_usize()] = eval_codecopy as _;
310
311		table[Opcode::POP.as_usize()] = eval_pop as _;
312		table[Opcode::MLOAD.as_usize()] = eval_mload as _;
313		table[Opcode::MSTORE.as_usize()] = eval_mstore as _;
314		table[Opcode::MSTORE8.as_usize()] = eval_mstore8 as _;
315
316		table[Opcode::JUMP.as_usize()] = eval_jump as _;
317		table[Opcode::JUMPI.as_usize()] = eval_jumpi as _;
318		table[Opcode::PC.as_usize()] = eval_pc as _;
319		table[Opcode::MSIZE.as_usize()] = eval_msize as _;
320
321		table[Opcode::JUMPDEST.as_usize()] = eval_jumpdest as _;
322		table[Opcode::MCOPY.as_usize()] = eval_mcopy as _;
323
324		table[Opcode::PUSH0.as_usize()] = eval_push0 as _;
325		table[Opcode::PUSH1.as_usize()] = eval_push1 as _;
326		table[Opcode::PUSH2.as_usize()] = eval_push2 as _;
327		table[Opcode::PUSH3.as_usize()] = eval_push3 as _;
328		table[Opcode::PUSH4.as_usize()] = eval_push4 as _;
329		table[Opcode::PUSH5.as_usize()] = eval_push5 as _;
330		table[Opcode::PUSH6.as_usize()] = eval_push6 as _;
331		table[Opcode::PUSH7.as_usize()] = eval_push7 as _;
332		table[Opcode::PUSH8.as_usize()] = eval_push8 as _;
333		table[Opcode::PUSH9.as_usize()] = eval_push9 as _;
334		table[Opcode::PUSH10.as_usize()] = eval_push10 as _;
335		table[Opcode::PUSH11.as_usize()] = eval_push11 as _;
336		table[Opcode::PUSH12.as_usize()] = eval_push12 as _;
337		table[Opcode::PUSH13.as_usize()] = eval_push13 as _;
338		table[Opcode::PUSH14.as_usize()] = eval_push14 as _;
339		table[Opcode::PUSH15.as_usize()] = eval_push15 as _;
340		table[Opcode::PUSH16.as_usize()] = eval_push16 as _;
341		table[Opcode::PUSH17.as_usize()] = eval_push17 as _;
342		table[Opcode::PUSH18.as_usize()] = eval_push18 as _;
343		table[Opcode::PUSH19.as_usize()] = eval_push19 as _;
344		table[Opcode::PUSH20.as_usize()] = eval_push20 as _;
345		table[Opcode::PUSH21.as_usize()] = eval_push21 as _;
346		table[Opcode::PUSH22.as_usize()] = eval_push22 as _;
347		table[Opcode::PUSH23.as_usize()] = eval_push23 as _;
348		table[Opcode::PUSH24.as_usize()] = eval_push24 as _;
349		table[Opcode::PUSH25.as_usize()] = eval_push25 as _;
350		table[Opcode::PUSH26.as_usize()] = eval_push26 as _;
351		table[Opcode::PUSH27.as_usize()] = eval_push27 as _;
352		table[Opcode::PUSH28.as_usize()] = eval_push28 as _;
353		table[Opcode::PUSH29.as_usize()] = eval_push29 as _;
354		table[Opcode::PUSH30.as_usize()] = eval_push30 as _;
355		table[Opcode::PUSH31.as_usize()] = eval_push31 as _;
356		table[Opcode::PUSH32.as_usize()] = eval_push32 as _;
357
358		table[Opcode::DUP1.as_usize()] = eval_dup1 as _;
359		table[Opcode::DUP2.as_usize()] = eval_dup2 as _;
360		table[Opcode::DUP3.as_usize()] = eval_dup3 as _;
361		table[Opcode::DUP4.as_usize()] = eval_dup4 as _;
362		table[Opcode::DUP5.as_usize()] = eval_dup5 as _;
363		table[Opcode::DUP6.as_usize()] = eval_dup6 as _;
364		table[Opcode::DUP7.as_usize()] = eval_dup7 as _;
365		table[Opcode::DUP8.as_usize()] = eval_dup8 as _;
366		table[Opcode::DUP9.as_usize()] = eval_dup9 as _;
367		table[Opcode::DUP10.as_usize()] = eval_dup10 as _;
368		table[Opcode::DUP11.as_usize()] = eval_dup11 as _;
369		table[Opcode::DUP12.as_usize()] = eval_dup12 as _;
370		table[Opcode::DUP13.as_usize()] = eval_dup13 as _;
371		table[Opcode::DUP14.as_usize()] = eval_dup14 as _;
372		table[Opcode::DUP15.as_usize()] = eval_dup15 as _;
373		table[Opcode::DUP16.as_usize()] = eval_dup16 as _;
374
375		table[Opcode::SWAP1.as_usize()] = eval_swap1 as _;
376		table[Opcode::SWAP2.as_usize()] = eval_swap2 as _;
377		table[Opcode::SWAP3.as_usize()] = eval_swap3 as _;
378		table[Opcode::SWAP4.as_usize()] = eval_swap4 as _;
379		table[Opcode::SWAP5.as_usize()] = eval_swap5 as _;
380		table[Opcode::SWAP6.as_usize()] = eval_swap6 as _;
381		table[Opcode::SWAP7.as_usize()] = eval_swap7 as _;
382		table[Opcode::SWAP8.as_usize()] = eval_swap8 as _;
383		table[Opcode::SWAP9.as_usize()] = eval_swap9 as _;
384		table[Opcode::SWAP10.as_usize()] = eval_swap10 as _;
385		table[Opcode::SWAP11.as_usize()] = eval_swap11 as _;
386		table[Opcode::SWAP12.as_usize()] = eval_swap12 as _;
387		table[Opcode::SWAP13.as_usize()] = eval_swap13 as _;
388		table[Opcode::SWAP14.as_usize()] = eval_swap14 as _;
389		table[Opcode::SWAP15.as_usize()] = eval_swap15 as _;
390		table[Opcode::SWAP16.as_usize()] = eval_swap16 as _;
391
392		table[Opcode::RETURN.as_usize()] = eval_return as _;
393
394		table[Opcode::REVERT.as_usize()] = eval_revert as _;
395
396		table[Opcode::INVALID.as_usize()] = eval_invalid as _;
397
398		Self(table, PhantomData)
399	}
400}
401
402impl<S, H: RuntimeEnvironment + RuntimeBackend, Tr> Etable<S, H, Tr>
403where
404	S: AsRef<RuntimeState> + AsMut<RuntimeState> + GasState,
405	Tr: From<CallCreateTrap>,
406{
407	/// Runtime Etable.
408	#[must_use]
409	pub const fn runtime() -> Self {
410		let mut table = Self::core();
411
412		table.0[Opcode::SHA3.as_usize()] = eval_sha3 as _;
413
414		table.0[Opcode::ADDRESS.as_usize()] = eval_address as _;
415		table.0[Opcode::BALANCE.as_usize()] = eval_balance as _;
416		table.0[Opcode::ORIGIN.as_usize()] = eval_origin as _;
417		table.0[Opcode::CALLER.as_usize()] = eval_caller as _;
418		table.0[Opcode::CALLVALUE.as_usize()] = eval_callvalue as _;
419
420		table.0[Opcode::GASPRICE.as_usize()] = eval_gasprice as _;
421		table.0[Opcode::EXTCODESIZE.as_usize()] = eval_extcodesize as _;
422		table.0[Opcode::EXTCODECOPY.as_usize()] = eval_extcodecopy as _;
423		table.0[Opcode::RETURNDATASIZE.as_usize()] = eval_returndatasize as _;
424		table.0[Opcode::RETURNDATACOPY.as_usize()] = eval_returndatacopy as _;
425		table.0[Opcode::EXTCODEHASH.as_usize()] = eval_extcodehash as _;
426
427		table.0[Opcode::BLOCKHASH.as_usize()] = eval_blockhash as _;
428		table.0[Opcode::COINBASE.as_usize()] = eval_coinbase as _;
429		table.0[Opcode::TIMESTAMP.as_usize()] = eval_timestamp as _;
430		table.0[Opcode::NUMBER.as_usize()] = eval_number as _;
431		table.0[Opcode::DIFFICULTY.as_usize()] = eval_difficulty as _;
432		table.0[Opcode::GASLIMIT.as_usize()] = eval_gaslimit as _;
433		table.0[Opcode::CHAINID.as_usize()] = eval_chainid as _;
434		table.0[Opcode::SELFBALANCE.as_usize()] = eval_selfbalance as _;
435		table.0[Opcode::BASEFEE.as_usize()] = eval_basefee as _;
436
437		table.0[Opcode::SLOAD.as_usize()] = eval_sload as _;
438		table.0[Opcode::SSTORE.as_usize()] = eval_sstore as _;
439
440		table.0[Opcode::GAS.as_usize()] = eval_gas as _;
441
442		table.0[Opcode::TLOAD.as_usize()] = eval_tload as _;
443		table.0[Opcode::TSTORE.as_usize()] = eval_tstore as _;
444
445		table.0[Opcode::LOG0.as_usize()] = eval_log0 as _;
446		table.0[Opcode::LOG1.as_usize()] = eval_log1 as _;
447		table.0[Opcode::LOG2.as_usize()] = eval_log2 as _;
448		table.0[Opcode::LOG3.as_usize()] = eval_log3 as _;
449		table.0[Opcode::LOG4.as_usize()] = eval_log4 as _;
450
451		table.0[Opcode::CREATE.as_usize()] = eval_call_create_trap as _;
452		table.0[Opcode::CALL.as_usize()] = eval_call_create_trap as _;
453		table.0[Opcode::CALLCODE.as_usize()] = eval_call_create_trap as _;
454
455		table.0[Opcode::DELEGATECALL.as_usize()] = eval_call_create_trap as _;
456		table.0[Opcode::CREATE2.as_usize()] = eval_call_create_trap as _;
457
458		table.0[Opcode::STATICCALL.as_usize()] = eval_call_create_trap as _;
459
460		table.0[Opcode::SUICIDE.as_usize()] = eval_suicide as _;
461
462		table
463	}
464}
465
466/// Control state.
467#[derive(Eq, PartialEq, Debug)]
468pub enum Control<Trap> {
469	/// No action.
470	NoAction,
471	/// Continue the execution, increase the PC by N.
472	Continue(usize),
473	/// Exit the execution.
474	Exit(ExitResult),
475	/// Jump to the specified PC.
476	Jump(usize),
477	/// Trapping the execution with the possibility to resume.
478	Trap(Box<Trap>),
479}