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::U256;
30
31pub struct Machine {
33 data: Rc<Vec<u8>>,
35 code: Rc<Vec<u8>>,
37 position: Result<usize, ExitReason>,
39 return_range: Range<U256>,
41 valids: Valids,
43 memory: Memory,
45 stack: Stack,
47}
48
49impl Machine {
50 pub fn stack(&self) -> &Stack {
52 &self.stack
53 }
54 pub fn stack_mut(&mut self) -> &mut Stack {
56 &mut self.stack
57 }
58 pub fn memory(&self) -> &Memory {
60 &self.memory
61 }
62 pub fn memory_mut(&mut self) -> &mut Memory {
64 &mut self.memory
65 }
66 pub fn position(&self) -> &Result<usize, ExitReason> {
68 &self.position
69 }
70
71 pub fn new(
73 code: Rc<Vec<u8>>,
74 data: Rc<Vec<u8>>,
75 stack_limit: usize,
76 memory_limit: usize,
77 ) -> Self {
78 let valids = Valids::new(&code[..]);
79
80 Self {
81 data,
82 code,
83 position: Ok(0),
84 return_range: U256::zero()..U256::zero(),
85 valids,
86 memory: Memory::new(memory_limit),
87 stack: Stack::new(stack_limit),
88 }
89 }
90
91 pub fn exit(&mut self, reason: ExitReason) {
93 self.position = Err(reason);
94 }
95
96 pub fn inspect(&self) -> Option<(Opcode, &Stack)> {
98 let position = match self.position {
99 Ok(position) => position,
100 Err(_) => return None,
101 };
102 self.code.get(position).map(|v| (Opcode(*v), &self.stack))
103 }
104
105 #[allow(clippy::slow_vector_initialization)]
107 pub fn return_value(&self) -> Vec<u8> {
110 if self.return_range.start > U256::from(usize::MAX) {
111 let mut ret = Vec::new();
112 ret.resize(
113 (self.return_range.end - self.return_range.start).as_usize(),
114 0,
115 );
116 ret
117 } else if self.return_range.end > U256::from(usize::MAX) {
118 let mut ret = self.memory.get(
119 self.return_range.start.as_usize(),
120 usize::MAX - self.return_range.start.as_usize(),
121 );
122 while ret.len() < (self.return_range.end - self.return_range.start).as_usize() {
123 ret.push(0);
124 }
125 ret
126 } else {
127 self.memory.get(
128 self.return_range.start.as_usize(),
129 (self.return_range.end - self.return_range.start).as_usize(),
130 )
131 }
132 }
133
134 pub fn run(&mut self) -> Capture<ExitReason, Trap> {
136 loop {
137 match self.step() {
138 Ok(()) => (),
139 Err(res) => return res,
140 }
141 }
142 }
143
144 #[inline]
145 pub fn step(&mut self) -> Result<(), Capture<ExitReason, Trap>> {
147 let position = *self
148 .position
149 .as_ref()
150 .map_err(|reason| Capture::Exit(reason.clone()))?;
151
152 match self.code.get(position).map(|v| Opcode(*v)) {
153 Some(opcode) => match eval(self, opcode, position) {
154 Control::Continue(p) => {
155 self.position = Ok(position + p);
156 Ok(())
157 }
158 Control::Exit(e) => {
159 self.position = Err(e.clone());
160 Err(Capture::Exit(e))
161 }
162 Control::Jump(p) => {
163 self.position = Ok(p);
164 Ok(())
165 }
166 Control::Trap(opcode) => {
167 #[cfg(feature = "force-debug")]
168 log::trace!(target: "evm", "OpCode Trap: {:?}", opcode);
169
170 self.position = Ok(position + 1);
171 Err(Capture::Trap(opcode))
172 }
173 },
174 None => {
175 self.position = Err(ExitSucceed::Stopped.into());
176 Err(Capture::Exit(ExitSucceed::Stopped.into()))
177 }
178 }
179 }
180}