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 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 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 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}