1#![deny(warnings)]
4#![forbid(unsafe_code, unused_variables, unused_imports)]
5#![cfg_attr(not(feature = "std"), no_std)]
6
7extern crate alloc;
8
9mod error;
10mod eval;
11mod external;
12mod memory;
13mod opcode;
14mod stack;
15mod utils;
16mod valids;
17
18pub use crate::error::{Capture, ExitError, ExitFatal, ExitReason, ExitRevert, ExitSucceed, Trap};
19pub use crate::external::ExternalOperation;
20pub use crate::memory::Memory;
21pub use crate::opcode::Opcode;
22pub use crate::stack::Stack;
23pub use crate::valids::Valids;
24
25use crate::eval::{eval, Control};
26use alloc::rc::Rc;
27use alloc::vec::Vec;
28use core::ops::Range;
29use primitive_types::{H160, U256};
30
31pub const EIP_7702_DELEGATION_PREFIX: &[u8] = &[0xef, 0x01, 0x00];
33
34pub const EIP_7702_DELEGATION_SIZE: usize = 23; pub struct Machine {
39 data: Rc<Vec<u8>>,
41 code: Rc<Vec<u8>>,
43 position: Result<usize, ExitReason>,
45 return_range: Range<U256>,
47 valids: Valids,
49 memory: Memory,
51 stack: Stack,
53}
54
55impl Machine {
56 pub fn stack(&self) -> &Stack {
58 &self.stack
59 }
60 pub fn stack_mut(&mut self) -> &mut Stack {
62 &mut self.stack
63 }
64 pub fn memory(&self) -> &Memory {
66 &self.memory
67 }
68 pub fn memory_mut(&mut self) -> &mut Memory {
70 &mut self.memory
71 }
72 pub fn position(&self) -> &Result<usize, ExitReason> {
74 &self.position
75 }
76
77 pub fn new(
79 code: Rc<Vec<u8>>,
80 data: Rc<Vec<u8>>,
81 stack_limit: usize,
82 memory_limit: usize,
83 ) -> Self {
84 let valids = Valids::new(&code[..]);
85
86 Self {
87 data,
88 code,
89 position: Ok(0),
90 return_range: U256::zero()..U256::zero(),
91 valids,
92 memory: Memory::new(memory_limit),
93 stack: Stack::new(stack_limit),
94 }
95 }
96
97 pub fn exit(&mut self, reason: ExitReason) {
99 self.position = Err(reason);
100 }
101
102 pub fn inspect(&self) -> Option<(Opcode, &Stack)> {
104 let position = match self.position {
105 Ok(position) => position,
106 Err(_) => return None,
107 };
108 self.code.get(position).map(|v| (Opcode(*v), &self.stack))
109 }
110
111 #[allow(clippy::slow_vector_initialization)]
113 pub fn return_value(&self) -> Vec<u8> {
116 if self.return_range.start > U256::from(usize::MAX) {
117 let mut ret = Vec::new();
118 ret.resize(
119 (self.return_range.end - self.return_range.start).as_usize(),
120 0,
121 );
122 ret
123 } else if self.return_range.end > U256::from(usize::MAX) {
124 let mut ret = self.memory.get(
125 self.return_range.start.as_usize(),
126 usize::MAX - self.return_range.start.as_usize(),
127 );
128 while ret.len() < (self.return_range.end - self.return_range.start).as_usize() {
129 ret.push(0);
130 }
131 ret
132 } else {
133 self.memory.get(
134 self.return_range.start.as_usize(),
135 (self.return_range.end - self.return_range.start).as_usize(),
136 )
137 }
138 }
139
140 pub fn run(&mut self) -> Capture<ExitReason, Trap> {
142 loop {
143 match self.step() {
144 Ok(()) => (),
145 Err(res) => return res,
146 }
147 }
148 }
149
150 #[inline]
151 pub fn step(&mut self) -> Result<(), Capture<ExitReason, Trap>> {
153 let position = *self
154 .position
155 .as_ref()
156 .map_err(|reason| Capture::Exit(reason.clone()))?;
157
158 match self.code.get(position).map(|v| Opcode(*v)) {
159 Some(opcode) => match eval(self, opcode, position) {
160 Control::Continue(p) => {
161 self.position = Ok(position + p);
162 Ok(())
163 }
164 Control::Exit(e) => {
165 self.position = Err(e.clone());
166 Err(Capture::Exit(e))
167 }
168 Control::Jump(p) => {
169 self.position = Ok(p);
170 Ok(())
171 }
172 Control::Trap(opcode) => {
173 #[cfg(feature = "force-debug")]
174 log::trace!(target: "evm", "OpCode Trap: {:?}", opcode);
175
176 self.position = Ok(position + 1);
177 Err(Capture::Trap(opcode))
178 }
179 },
180 None => {
181 self.position = Err(ExitSucceed::Stopped.into());
182 Err(Capture::Exit(ExitSucceed::Stopped.into()))
183 }
184 }
185 }
186}
187
188pub fn is_delegation_designator(code: &[u8]) -> bool {
190 code.len() == EIP_7702_DELEGATION_SIZE && code.starts_with(EIP_7702_DELEGATION_PREFIX)
191}
192
193pub fn extract_delegation_address(code: &[u8]) -> Option<H160> {
195 if is_delegation_designator(code) {
196 let mut address_bytes = [0u8; 20];
197 address_bytes.copy_from_slice(&code[3..23]);
198 Some(H160::from(address_bytes))
199 } else {
200 None
201 }
202}
203
204pub fn create_delegation_designator(address: H160) -> Vec<u8> {
206 let mut designator = Vec::with_capacity(EIP_7702_DELEGATION_SIZE);
207 designator.extend_from_slice(EIP_7702_DELEGATION_PREFIX);
208 designator.extend_from_slice(address.as_bytes());
209 designator
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215
216 #[test]
217 fn test_delegation_designator_creation() {
218 let address = H160::from_slice(&[1u8; 20]);
219 let designator = create_delegation_designator(address);
220
221 assert_eq!(designator.len(), EIP_7702_DELEGATION_SIZE);
222 assert_eq!(&designator[0..3], EIP_7702_DELEGATION_PREFIX);
223 assert_eq!(&designator[3..23], address.as_bytes());
224 }
225
226 #[test]
227 fn test_delegation_designator_detection() {
228 let address = H160::from_slice(&[1u8; 20]);
229 let designator = create_delegation_designator(address);
230
231 assert!(is_delegation_designator(&designator));
232 assert_eq!(extract_delegation_address(&designator), Some(address));
233 }
234
235 #[test]
236 fn test_non_delegation_code() {
237 let regular_code = vec![0x60, 0x00]; assert!(!is_delegation_designator(®ular_code));
239 assert_eq!(extract_delegation_address(®ular_code), None);
240 }
241}