1use super::Control;
2use crate::{ExitError, ExitFatal, ExitRevert, ExitSucceed, Machine};
3use core::cmp::{max, min};
4use primitive_types::{H256, U256};
5
6#[inline]
7pub fn codesize(state: &mut Machine) -> Control {
8 let size = U256::from(state.code.len());
9 trace_op!("CodeSize: {}", size);
10 push_u256!(state, size);
11 Control::Continue(1)
12}
13
14#[inline]
15pub fn codecopy(state: &mut Machine) -> Control {
16 pop_u256!(state, memory_offset, code_offset, len);
17 trace_op!("CodeCopy: {}", len);
18
19 try_or_fail!(state.memory.resize_offset(memory_offset, len));
20 match state
21 .memory
22 .copy_large(memory_offset, code_offset, len, &state.code)
23 {
24 Ok(()) => Control::Continue(1),
25 Err(e) => Control::Exit(e.into()),
26 }
27}
28
29#[inline]
30pub fn calldataload(state: &mut Machine) -> Control {
31 pop_u256!(state, index);
32
33 let mut load = [0u8; 32];
34 #[allow(clippy::needless_range_loop)]
35 for i in 0..32 {
36 if let Some(p) = index.checked_add(U256::from(i)) {
37 if p <= U256::from(usize::MAX) {
38 let p = p.as_usize();
39 if p < state.data.len() {
40 load[i] = state.data[p];
41 }
42 }
43 }
44 }
45
46 push!(state, H256::from(load));
47 Control::Continue(1)
48}
49
50#[inline]
51pub fn calldatasize(state: &mut Machine) -> Control {
52 let len = U256::from(state.data.len());
53 trace_op!("CallDataSize: {}", len);
54 push_u256!(state, len);
55 Control::Continue(1)
56}
57
58#[inline]
59pub fn calldatacopy(state: &mut Machine) -> Control {
60 pop_u256!(state, memory_offset, data_offset, len);
61 trace_op!("CallDataCopy: {}", len);
62
63 try_or_fail!(state.memory.resize_offset(memory_offset, len));
64 if len == U256::zero() {
65 return Control::Continue(1);
66 }
67
68 match state
69 .memory
70 .copy_large(memory_offset, data_offset, len, &state.data)
71 {
72 Ok(()) => Control::Continue(1),
73 Err(e) => Control::Exit(e.into()),
74 }
75}
76
77#[inline]
78pub fn pop(state: &mut Machine) -> Control {
79 pop!(state, _val);
80 trace_op!("Pop [@{}]: {}", state.stack.len(), _val);
81 Control::Continue(1)
82}
83
84#[inline]
85pub fn mload(state: &mut Machine) -> Control {
86 pop_u256!(state, index);
87 trace_op!("MLoad: {}", index);
88 try_or_fail!(state.memory.resize_offset(index, U256::from(32)));
89 let index = as_usize_or_fail!(index);
90 let value = H256::from_slice(&state.memory.get(index, 32)[..]);
91 push!(state, value);
92 Control::Continue(1)
93}
94
95#[inline]
97pub fn mcopy(state: &mut Machine) -> Control {
98 pop_u256!(state, dst, src, len);
99 try_or_fail!(state.memory.resize_offset(max(dst, src), len));
100
101 if len.is_zero() {
102 return Control::Continue(1);
103 }
104
105 let dst = as_usize_or_fail!(dst);
106 let src = as_usize_or_fail!(src);
107 let len = as_usize_or_fail!(len);
108 state.memory.copy(dst, src, len);
109 Control::Continue(1)
110}
111
112#[inline]
113pub fn mstore(state: &mut Machine) -> Control {
114 pop_u256!(state, index);
115 pop!(state, value);
116 trace_op!("MStore: {}, {}", index, value);
117 try_or_fail!(state.memory.resize_offset(index, U256::from(32)));
118 let index = as_usize_or_fail!(index);
119 match state.memory.set(index, &value[..], Some(32)) {
120 Ok(()) => Control::Continue(1),
121 Err(e) => Control::Exit(e.into()),
122 }
123}
124
125#[inline]
126pub fn mstore8(state: &mut Machine) -> Control {
127 pop_u256!(state, index, value);
128 try_or_fail!(state.memory.resize_offset(index, U256::one()));
129 let index = as_usize_or_fail!(index);
130 let value = (value.low_u32() & 0xff) as u8;
131 match state.memory.set(index, &[value], Some(1)) {
132 Ok(()) => Control::Continue(1),
133 Err(e) => Control::Exit(e.into()),
134 }
135}
136
137#[inline]
138pub fn jump(state: &mut Machine) -> Control {
139 pop_u256!(state, dest);
140 let dest = as_usize_or_fail!(dest, ExitError::InvalidJump);
141 trace_op!("Jump: {}", dest);
142
143 if state.valids.is_valid(dest) {
144 Control::Jump(dest)
145 } else {
146 Control::Exit(ExitError::InvalidJump.into())
147 }
148}
149
150#[inline]
151pub fn jumpi(state: &mut Machine) -> Control {
152 pop_u256!(state, dest);
153 pop!(state, value);
154
155 if value != H256::zero() {
156 trace_op!("JumpI: {}", dest);
157 let dest = as_usize_or_fail!(dest, ExitError::InvalidJump);
158 if state.valids.is_valid(dest) {
159 Control::Jump(dest)
160 } else {
161 Control::Exit(ExitError::InvalidJump.into())
162 }
163 } else {
164 trace_op!("JumpI: skipped");
165 Control::Continue(1)
166 }
167}
168
169#[inline]
170pub fn pc(state: &mut Machine, position: usize) -> Control {
171 trace_op!("PC");
172 push_u256!(state, U256::from(position));
173 Control::Continue(1)
174}
175
176#[inline]
177pub fn msize(state: &mut Machine) -> Control {
178 push_u256!(state, state.memory.effective_len());
179 Control::Continue(1)
180}
181
182#[inline]
183pub fn push(state: &mut Machine, n: usize, position: usize) -> Control {
184 let end = min(position + 1 + n, state.code.len());
185 let slice = &state.code[(position + 1)..end];
186 let mut val = [0u8; 32];
187 val[(32 - n)..(32 - n + slice.len())].copy_from_slice(slice);
188
189 let result = H256(val);
190 push!(state, result);
191 trace_op!("Push [@{}]: {}", state.stack.len() - 1, result);
192 Control::Continue(1 + n)
193}
194
195#[inline]
196pub fn dup(state: &mut Machine, n: usize) -> Control {
197 let value = match state.stack.peek(n - 1) {
198 Ok(value) => value,
199 Err(e) => return Control::Exit(e.into()),
200 };
201 trace_op!("Dup{} [@{}]: {}", n, state.stack.len(), value);
202 push!(state, value);
203 Control::Continue(1)
204}
205
206#[inline]
207pub fn swap(state: &mut Machine, n: usize) -> Control {
208 let val1 = match state.stack.peek(0) {
209 Ok(value) => value,
210 Err(e) => return Control::Exit(e.into()),
211 };
212 let val2 = match state.stack.peek(n) {
213 Ok(value) => value,
214 Err(e) => return Control::Exit(e.into()),
215 };
216 match state.stack.set(0, val2) {
217 Ok(()) => (),
218 Err(e) => return Control::Exit(e.into()),
219 }
220 match state.stack.set(n, val1) {
221 Ok(()) => (),
222 Err(e) => return Control::Exit(e.into()),
223 }
224 trace_op!("Swap [@0:@{}]: {}, {}", n, val1, val2);
225 Control::Continue(1)
226}
227
228#[inline]
229pub fn ret(state: &mut Machine) -> Control {
230 trace_op!("Return");
231 pop_u256!(state, start, len);
232 try_or_fail!(state.memory.resize_offset(start, len));
233 state.return_range = start..(start + len);
234 Control::Exit(ExitSucceed::Returned.into())
235}
236
237#[inline]
238pub fn revert(state: &mut Machine) -> Control {
239 trace_op!("Revert");
240 pop_u256!(state, start, len);
241 try_or_fail!(state.memory.resize_offset(start, len));
242 state.return_range = start..(start + len);
243 Control::Exit(ExitRevert::Reverted.into())
244}