evm_runtime/eval/
system.rs

1use super::Control;
2use crate::{
3	CallScheme, Capture, Context, CreateScheme, ExitError, ExitFatal, ExitSucceed, Handler,
4	Runtime, Transfer,
5};
6use alloc::vec::Vec;
7use primitive_types::{H256, U256};
8use sha3::{Digest, Keccak256};
9
10pub fn sha3<H: Handler>(runtime: &mut Runtime) -> Control<H> {
11	pop_u256!(runtime, from, len);
12
13	try_or_fail!(runtime.machine.memory_mut().resize_offset(from, len));
14	let data = if len == U256::zero() {
15		Vec::new()
16	} else {
17		let from = as_usize_or_fail!(from);
18		let len = as_usize_or_fail!(len);
19
20		runtime.machine.memory_mut().get(from, len)
21	};
22
23	let ret = Keccak256::digest(data.as_slice());
24	push!(runtime, H256::from_slice(ret.as_slice()));
25
26	Control::Continue
27}
28
29pub fn chainid<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
30	push_u256!(runtime, handler.chain_id());
31
32	Control::Continue
33}
34
35pub fn address<H: Handler>(runtime: &mut Runtime) -> Control<H> {
36	let ret = H256::from(runtime.context.address);
37	push!(runtime, ret);
38
39	Control::Continue
40}
41
42pub fn balance<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
43	pop!(runtime, address);
44	push_u256!(runtime, handler.balance(address.into()));
45
46	Control::Continue
47}
48
49pub fn selfbalance<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
50	push_u256!(runtime, handler.balance(runtime.context.address));
51
52	Control::Continue
53}
54
55pub fn origin<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
56	let ret = H256::from(handler.origin());
57	push!(runtime, ret);
58
59	Control::Continue
60}
61
62pub fn caller<H: Handler>(runtime: &mut Runtime) -> Control<H> {
63	let ret = H256::from(runtime.context.caller);
64	push!(runtime, ret);
65
66	Control::Continue
67}
68
69pub fn callvalue<H: Handler>(runtime: &mut Runtime) -> Control<H> {
70	let ret = runtime.context.apparent_value.to_big_endian();
71	push!(runtime, H256::from(ret));
72
73	Control::Continue
74}
75
76pub fn gasprice<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
77	let ret = handler.gas_price().to_big_endian();
78	push!(runtime, H256::from(ret));
79
80	Control::Continue
81}
82
83pub fn base_fee<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
84	let ret = handler.block_base_fee_per_gas().to_big_endian();
85	push!(runtime, H256::from(ret));
86
87	Control::Continue
88}
89
90pub fn extcodesize<H: Handler>(runtime: &mut Runtime, handler: &mut H) -> Control<H> {
91	pop!(runtime, address);
92	if let Err(e) =
93		handler.record_external_operation(crate::ExternalOperation::AddressCodeRead(address.into()))
94	{
95		return Control::Exit(e.into());
96	}
97	// EIP-7702: EXTCODESIZE does NOT follow delegations
98	let code_size = handler.code_size(address.into());
99	push_u256!(runtime, code_size);
100
101	Control::Continue
102}
103
104pub fn extcodehash<H: Handler>(runtime: &mut Runtime, handler: &mut H) -> Control<H> {
105	pop!(runtime, address);
106	if let Err(e) =
107		handler.record_external_operation(crate::ExternalOperation::AddressCodeRead(address.into()))
108	{
109		return Control::Exit(e.into());
110	}
111	// EIP-7702: EXTCODEHASH does NOT follow delegations
112	let code_hash = handler.code_hash(address.into());
113	push!(runtime, code_hash);
114
115	Control::Continue
116}
117
118pub fn extcodecopy<H: Handler>(runtime: &mut Runtime, handler: &mut H) -> Control<H> {
119	pop!(runtime, address);
120	pop_u256!(runtime, memory_offset, code_offset, len);
121
122	try_or_fail!(runtime
123		.machine
124		.memory_mut()
125		.resize_offset(memory_offset, len));
126
127	if let Err(e) =
128		handler.record_external_operation(crate::ExternalOperation::AddressCodeRead(address.into()))
129	{
130		return Control::Exit(e.into());
131	}
132	// EIP-7702: EXTCODECOPY does NOT follow delegations
133	let code = handler.code(address.into());
134	match runtime
135		.machine
136		.memory_mut()
137		.copy_large(memory_offset, code_offset, len, &code)
138	{
139		Ok(()) => (),
140		Err(e) => return Control::Exit(e.into()),
141	};
142
143	Control::Continue
144}
145
146pub fn returndatasize<H: Handler>(runtime: &mut Runtime) -> Control<H> {
147	let size = U256::from(runtime.return_data_buffer.len());
148	push_u256!(runtime, size);
149
150	Control::Continue
151}
152
153pub fn returndatacopy<H: Handler>(runtime: &mut Runtime) -> Control<H> {
154	pop_u256!(runtime, memory_offset, data_offset, len);
155
156	try_or_fail!(runtime
157		.machine
158		.memory_mut()
159		.resize_offset(memory_offset, len));
160	if data_offset
161		.checked_add(len)
162		.map(|l| l > U256::from(runtime.return_data_buffer.len()))
163		.unwrap_or(true)
164	{
165		return Control::Exit(ExitError::OutOfOffset.into());
166	}
167
168	match runtime.machine.memory_mut().copy_large(
169		memory_offset,
170		data_offset,
171		len,
172		&runtime.return_data_buffer,
173	) {
174		Ok(()) => Control::Continue,
175		Err(e) => Control::Exit(e.into()),
176	}
177}
178
179pub fn blockhash<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
180	pop_u256!(runtime, number);
181	push!(runtime, handler.block_hash(number));
182
183	Control::Continue
184}
185
186pub fn coinbase<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
187	push!(runtime, handler.block_coinbase().into());
188	Control::Continue
189}
190
191pub fn timestamp<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
192	push_u256!(runtime, handler.block_timestamp());
193	Control::Continue
194}
195
196pub fn number<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
197	push_u256!(runtime, handler.block_number());
198	Control::Continue
199}
200
201pub fn difficulty<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
202	push_u256!(runtime, handler.block_difficulty());
203	Control::Continue
204}
205
206pub fn prevrandao<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
207	if let Some(rand) = handler.block_randomness() {
208		push!(runtime, rand);
209		Control::Continue
210	} else {
211		difficulty(runtime, handler)
212	}
213}
214
215pub fn gaslimit<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
216	push_u256!(runtime, handler.block_gas_limit());
217	Control::Continue
218}
219
220pub fn sload<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
221	pop!(runtime, index);
222	let value = handler.storage(runtime.context.address, index);
223	push!(runtime, value);
224
225	event!(SLoad {
226		address: runtime.context.address,
227		index,
228		value
229	});
230
231	Control::Continue
232}
233
234pub fn sstore<H: Handler>(runtime: &mut Runtime, handler: &mut H) -> Control<H> {
235	pop!(runtime, index, value);
236
237	event!(SStore {
238		address: runtime.context.address,
239		index,
240		value
241	});
242
243	match handler.set_storage(runtime.context.address, index, value) {
244		Ok(()) => Control::Continue,
245		Err(e) => Control::Exit(e.into()),
246	}
247}
248
249pub fn gas<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
250	push_u256!(runtime, handler.gas_left());
251
252	Control::Continue
253}
254
255pub fn tload<H: Handler>(runtime: &mut Runtime, handler: &mut H) -> Control<H> {
256	pop!(runtime, index);
257	let value = handler.transient_storage(runtime.context.address, index);
258	push!(runtime, value);
259
260	Control::Continue
261}
262
263pub fn tstore<H: Handler>(runtime: &mut Runtime, handler: &mut H) -> Control<H> {
264	pop!(runtime, index, value);
265	handler.set_transient_storage(runtime.context.address, index, value);
266
267	Control::Continue
268}
269
270pub fn log<H: Handler>(runtime: &mut Runtime, n: u8, handler: &mut H) -> Control<H> {
271	pop_u256!(runtime, offset, len);
272
273	try_or_fail!(runtime.machine.memory_mut().resize_offset(offset, len));
274	let data = if len == U256::zero() {
275		Vec::new()
276	} else {
277		let offset = as_usize_or_fail!(offset);
278		let len = as_usize_or_fail!(len);
279
280		runtime.machine.memory().get(offset, len)
281	};
282
283	let mut topics = Vec::new();
284	for _ in 0..(n as usize) {
285		match runtime.machine.stack_mut().pop() {
286			Ok(value) => {
287				topics.push(value);
288			}
289			Err(e) => return Control::Exit(e.into()),
290		}
291	}
292
293	match handler.log(runtime.context.address, topics, data) {
294		Ok(()) => Control::Continue,
295		Err(e) => Control::Exit(e.into()),
296	}
297}
298
299pub fn suicide<H: Handler>(runtime: &mut Runtime, handler: &mut H) -> Control<H> {
300	pop!(runtime, target);
301
302	match handler.mark_delete(runtime.context.address, target.into()) {
303		Ok(()) => (),
304		Err(e) => return Control::Exit(e.into()),
305	}
306
307	Control::Exit(ExitSucceed::Suicided.into())
308}
309
310pub fn create<H: Handler>(runtime: &mut Runtime, is_create2: bool, handler: &mut H) -> Control<H> {
311	runtime.return_data_buffer = Vec::new();
312
313	pop_u256!(runtime, value, code_offset, len);
314
315	try_or_fail!(runtime.machine.memory_mut().resize_offset(code_offset, len));
316	let code = if len == U256::zero() {
317		Vec::new()
318	} else {
319		let code_offset = as_usize_or_fail!(code_offset);
320		let len = as_usize_or_fail!(len);
321
322		runtime.machine.memory().get(code_offset, len)
323	};
324
325	let scheme = if is_create2 {
326		pop!(runtime, salt);
327		let code_hash = H256::from_slice(Keccak256::digest(&code).as_slice());
328		CreateScheme::Create2 {
329			caller: runtime.context.address,
330			salt,
331			code_hash,
332		}
333	} else {
334		CreateScheme::Legacy {
335			caller: runtime.context.address,
336		}
337	};
338
339	match handler.create(runtime.context.address, scheme, value, code, None) {
340		Capture::Exit((reason, address, return_data)) => {
341			match super::finish_create(runtime, reason, address, return_data) {
342				Ok(()) => Control::Continue,
343				Err(e) => Control::Exit(e),
344			}
345		}
346		Capture::Trap(interrupt) => Control::CreateInterrupt(interrupt),
347	}
348}
349
350pub fn call<H: Handler>(runtime: &mut Runtime, scheme: CallScheme, handler: &mut H) -> Control<H> {
351	runtime.return_data_buffer = Vec::new();
352
353	pop_u256!(runtime, gas);
354	pop!(runtime, to);
355	let gas = if gas > U256::from(u64::MAX) {
356		None
357	} else {
358		Some(gas.as_u64())
359	};
360
361	let value = match scheme {
362		CallScheme::Call | CallScheme::CallCode => {
363			pop_u256!(runtime, value);
364			value
365		}
366		CallScheme::DelegateCall | CallScheme::StaticCall => U256::zero(),
367	};
368
369	pop_u256!(runtime, in_offset, in_len, out_offset, out_len);
370
371	try_or_fail!(runtime
372		.machine
373		.memory_mut()
374		.resize_offset(in_offset, in_len));
375	try_or_fail!(runtime
376		.machine
377		.memory_mut()
378		.resize_offset(out_offset, out_len));
379
380	let input = if in_len == U256::zero() {
381		Vec::new()
382	} else {
383		let in_offset = as_usize_or_fail!(in_offset);
384		let in_len = as_usize_or_fail!(in_len);
385
386		runtime.machine.memory().get(in_offset, in_len)
387	};
388
389	let context = match scheme {
390		CallScheme::Call | CallScheme::StaticCall => Context {
391			address: to.into(),
392			caller: runtime.context.address,
393			apparent_value: value,
394		},
395		CallScheme::CallCode => Context {
396			address: runtime.context.address,
397			caller: runtime.context.address,
398			apparent_value: value,
399		},
400		CallScheme::DelegateCall => Context {
401			address: runtime.context.address,
402			caller: runtime.context.caller,
403			apparent_value: runtime.context.apparent_value,
404		},
405	};
406
407	let transfer = if scheme == CallScheme::Call {
408		Some(Transfer {
409			source: runtime.context.address,
410			target: to.into(),
411			value,
412		})
413	} else if scheme == CallScheme::CallCode {
414		Some(Transfer {
415			source: runtime.context.address,
416			target: runtime.context.address,
417			value,
418		})
419	} else {
420		None
421	};
422
423	match handler.call(
424		to.into(),
425		transfer,
426		input,
427		gas,
428		scheme == CallScheme::StaticCall,
429		context,
430	) {
431		Capture::Exit((reason, return_data)) => {
432			match super::finish_call(runtime, out_len, out_offset, reason, return_data) {
433				Ok(()) => Control::Continue,
434				Err(e) => Control::Exit(e),
435			}
436		}
437		Capture::Trap(interrupt) => {
438			runtime.return_data_len = out_len;
439			runtime.return_data_offset = out_offset;
440			Control::CallInterrupt(interrupt)
441		}
442	}
443}