evm_core/eval/
misc.rs

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/// Support for EIP-5656: MCOPY instruction.
96#[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}