evm_interpreter/interpreter/
etable.rs

1use alloc::vec::Vec;
2use core::ops::{Deref, DerefMut};
3
4use crate::{
5	Capture, Control, ExitError, ExitException, ExitResult, ExitSucceed, FeedbackInterpreter,
6	Interpreter, Machine, Opcode, Stack, StepInterpreter, Valids,
7	etable::Etable,
8	runtime::RuntimeState,
9	trap::{CallFeedback, CreateFeedback},
10};
11
12/// Interpreter that uses [Etable].
13pub struct EtableInterpreter<'etable, S, ES> {
14	valids: Valids,
15	position: usize,
16	machine: Machine<S>,
17	etable: &'etable ES,
18}
19
20impl<'etable, S, ES> AsRef<Machine<S>> for EtableInterpreter<'etable, S, ES> {
21	fn as_ref(&self) -> &Machine<S> {
22		&self.machine
23	}
24}
25
26impl<'etable, S, ES> AsMut<Machine<S>> for EtableInterpreter<'etable, S, ES> {
27	fn as_mut(&mut self) -> &mut Machine<S> {
28		&mut self.machine
29	}
30}
31
32impl<'etable, S, ES> Deref for EtableInterpreter<'etable, S, ES> {
33	type Target = Machine<S>;
34
35	fn deref(&self) -> &Machine<S> {
36		&self.machine
37	}
38}
39
40impl<'etable, S, ES> DerefMut for EtableInterpreter<'etable, S, ES> {
41	fn deref_mut(&mut self) -> &mut Machine<S> {
42		&mut self.machine
43	}
44}
45
46impl<'etable, S, ES> EtableInterpreter<'etable, S, ES> {
47	/// Return a reference of the program counter.
48	pub const fn position(&self) -> usize {
49		self.position
50	}
51
52	/// Create a new interpreter from the machine state and etable.
53	pub fn new(machine: Machine<S>, etable: &'etable ES) -> Self {
54		let valids = Valids::new(&machine.code[..]);
55
56		Self {
57			machine,
58			valids,
59			position: 0,
60			etable,
61		}
62	}
63
64	/// Deconstruct the interpreter to get the underlying machine state.
65	pub fn deconstruct(self) -> Machine<S> {
66		self.machine
67	}
68
69	/// Explicit exit of the machine. Further step will return error.
70	pub fn exit(&mut self) {
71		self.position = self.code.len();
72	}
73
74	/// Inspect the machine's next opcode and current stack.
75	pub fn inspect(&self) -> Option<(Opcode, &Stack)> {
76		self.code
77			.get(self.position)
78			.map(|v| (Opcode(*v), &self.stack))
79	}
80
81	/// Perform any operation. If the operation fails, then set the machine
82	/// status to already exited.
83	pub fn perform<R, F: FnOnce(&mut Self) -> Result<R, ExitError>>(
84		&mut self,
85		f: F,
86	) -> Result<R, ExitError> {
87		match f(self) {
88			Ok(r) => Ok(r),
89			Err(e) => {
90				self.exit();
91				Err(e)
92			}
93		}
94	}
95
96	/// Pick the next opcode.
97	pub fn peek_opcode(&self) -> Option<Opcode> {
98		self.code.get(self.position).map(|opcode| Opcode(*opcode))
99	}
100
101	/// Advance the PC by one.
102	pub fn advance(&mut self) {
103		if self.position == self.code.len() {
104			return;
105		}
106
107		self.position += 1;
108	}
109}
110
111impl<'etable, S, H, ES: Etable<H, State = S>> Interpreter<H> for EtableInterpreter<'etable, S, ES> {
112	type State = S;
113	type Trap = ES::Trap;
114
115	fn deconstruct(self) -> (ES::State, Vec<u8>) {
116		(self.machine.state, self.machine.retval)
117	}
118
119	fn state(&self) -> &Self::State {
120		&self.machine.state
121	}
122
123	fn state_mut(&mut self) -> &mut Self::State {
124		&mut self.machine.state
125	}
126
127	fn run(&mut self, handle: &mut H) -> Capture<ExitResult, Self::Trap> {
128		loop {
129			match self.step(handle) {
130				Ok(()) => (),
131				Err(res) => return res,
132			}
133		}
134	}
135}
136
137impl<'etable, S, H, ES: Etable<H, State = S>> FeedbackInterpreter<H, CallFeedback>
138	for EtableInterpreter<'etable, S, ES>
139where
140	S: AsRef<RuntimeState> + AsMut<RuntimeState>,
141{
142	fn feedback(&mut self, feedback: CallFeedback, _handler: &mut H) -> Result<(), ExitError> {
143		match feedback.to_machine(self) {
144			Ok(()) => {
145				self.advance();
146				Ok(())
147			}
148			Err(err) => Err(err),
149		}
150	}
151}
152
153impl<'etable, S, H, ES: Etable<H, State = S>> FeedbackInterpreter<H, CreateFeedback>
154	for EtableInterpreter<'etable, S, ES>
155where
156	S: AsRef<RuntimeState> + AsMut<RuntimeState>,
157{
158	fn feedback(&mut self, feedback: CreateFeedback, _handler: &mut H) -> Result<(), ExitError> {
159		match feedback.to_machine(self) {
160			Ok(()) => {
161				self.advance();
162				Ok(())
163			}
164			Err(err) => Err(err),
165		}
166	}
167}
168
169impl<'etable, S, H, ES: Etable<H, State = S>> StepInterpreter<H>
170	for EtableInterpreter<'etable, S, ES>
171{
172	#[inline]
173	fn step(&mut self, handle: &mut H) -> Result<(), Capture<ExitResult, ES::Trap>> {
174		let position = self.position;
175		if position >= self.code.len() {
176			return Err(Capture::Exit(ExitSucceed::Stopped.into()));
177		}
178
179		let control = self.etable.eval(&mut self.machine, handle, self.position);
180
181		match control {
182			Control::NoAction => (),
183			Control::Continue(p) => {
184				self.position = position + p;
185			}
186			Control::Exit(e) => {
187				self.position = self.code.len();
188				return Err(Capture::Exit(e));
189			}
190			Control::Jump(p) => {
191				if self.valids.is_valid(p) {
192					self.position = p;
193				} else {
194					self.position = self.code.len();
195					return Err(Capture::Exit(ExitException::InvalidJump.into()));
196				}
197			}
198			Control::Trap(opcode) => return Err(Capture::Trap(opcode)),
199		};
200
201		Ok(())
202	}
203}