1mod call_helpers;
2
3pub use call_helpers::{calc_call_gas, get_memory_input_and_out_ranges, resize_memory};
4
5use crate::{
6 gas::{self, cost_per_word, EOF_CREATE_GAS, KECCAK256WORD, MIN_CALLEE_GAS},
7 instructions::utility::IntoAddress,
8 interpreter::Interpreter,
9 interpreter_action::FrameInput,
10 interpreter_types::{
11 EofContainer, Immediates, InputsTr, InterpreterTypes, Jumps, LoopControl, MemoryTr,
12 ReturnData, RuntimeFlag, StackTr,
13 },
14 CallInputs, CallScheme, CallValue, CreateInputs, EOFCreateInputs, Host, InstructionResult,
15 InterpreterAction, InterpreterResult,
16};
17use bytecode::eof::{Eof, EofHeader};
18use context_interface::CreateScheme;
19use core::cmp::max;
20use primitives::{hardfork::SpecId, keccak256, Address, Bytes, B256, U256};
21use std::boxed::Box;
22
23pub fn eofcreate<WIRE: InterpreterTypes, H: Host + ?Sized>(
25 interpreter: &mut Interpreter<WIRE>,
26 _host: &mut H,
27) {
28 require_eof!(interpreter);
29 require_non_staticcall!(interpreter);
30 gas!(interpreter, EOF_CREATE_GAS);
31 let initcontainer_index = interpreter.bytecode.read_u8();
32
33 popn!([value, salt, data_offset, data_size], interpreter);
34
35 let container = interpreter
36 .bytecode
37 .eof_container(initcontainer_index as usize)
38 .expect("valid container")
39 .clone();
40
41 let Some(input_range) = resize_memory(interpreter, data_offset, data_size) else {
43 return;
44 };
45
46 let input = if !input_range.is_empty() {
47 interpreter.memory.slice(input_range).to_vec().into()
48 } else {
49 Bytes::new()
50 };
51
52 let eof = Eof::decode(container.clone()).expect("Subcontainer is verified");
53
54 if !eof.body.is_data_filled {
55 panic!("Panic if data section is not full");
57 }
58
59 gas_or_fail!(interpreter, cost_per_word(container.len(), KECCAK256WORD));
61
62 let created_address = interpreter
63 .input
64 .target_address()
65 .create2(salt.to_be_bytes(), keccak256(container));
66
67 let gas_limit = interpreter.control.gas().remaining_63_of_64_parts();
68 gas!(interpreter, gas_limit);
69 interpreter.control.set_next_action(
71 InterpreterAction::NewFrame(FrameInput::EOFCreate(Box::new(
72 EOFCreateInputs::new_opcode(
73 interpreter.input.target_address(),
74 created_address,
75 value,
76 eof,
77 gas_limit,
78 input,
79 ),
80 ))),
81 InstructionResult::CallOrCreate,
82 );
83
84 interpreter.bytecode.relative_jump(1);
85}
86
87pub fn return_contract<H: Host + ?Sized>(
88 interpreter: &mut Interpreter<impl InterpreterTypes>,
89 _host: &mut H,
90) {
91 if !interpreter.runtime_flag.is_eof_init() {
92 interpreter
93 .control
94 .set_instruction_result(InstructionResult::ReturnContractInNotInitEOF);
95 return;
96 }
97 let deploy_container_index = interpreter.bytecode.read_u8();
98 popn!([aux_data_offset, aux_data_size], interpreter);
99 let aux_data_size = as_usize_or_fail!(interpreter, aux_data_size);
100 let container = interpreter
101 .bytecode
102 .eof_container(deploy_container_index as usize)
103 .expect("valid container")
104 .clone();
105
106 let (eof_header, _) = EofHeader::decode(&container).expect("valid EOF header");
108
109 let static_aux_size = eof_header.eof_size() - container.len();
110
111 let mut output = if aux_data_size != 0 {
113 let aux_data_offset = as_usize_or_fail!(interpreter, aux_data_offset);
114 resize_memory!(interpreter, aux_data_offset, aux_data_size);
115
116 let aux_slice = interpreter.memory.slice_len(aux_data_offset, aux_data_size);
117
118 [&container, aux_slice.as_ref()].concat()
119 } else {
120 container.to_vec()
121 };
122
123 let new_data_size = eof_header.data_size as usize - static_aux_size + aux_data_size;
126 if new_data_size > 0xFFFF {
127 interpreter
129 .control
130 .set_instruction_result(InstructionResult::EofAuxDataOverflow);
131 return;
132 }
133 if new_data_size < eof_header.data_size as usize {
134 interpreter
136 .control
137 .set_instruction_result(InstructionResult::EofAuxDataTooSmall);
138 return;
139 }
140 let new_data_size = (new_data_size as u16).to_be_bytes();
141
142 output[eof_header.data_size_raw_i()..][..2].clone_from_slice(&new_data_size);
144 let output: Bytes = output.into();
145
146 let result = InstructionResult::ReturnContract;
147 let gas = *interpreter.control.gas();
148 interpreter.control.set_next_action(
149 crate::InterpreterAction::Return {
150 result: InterpreterResult {
151 output,
152 gas,
153 result,
154 },
155 },
156 result,
157 );
158}
159
160pub fn extcall_input(interpreter: &mut Interpreter<impl InterpreterTypes>) -> Option<Bytes> {
161 popn!([input_offset, input_size], interpreter, None);
162 let return_memory_offset = resize_memory(interpreter, input_offset, input_size)?;
163
164 if return_memory_offset.is_empty() {
165 return Some(Bytes::new());
166 }
167
168 Some(Bytes::copy_from_slice(
169 interpreter.memory.slice(return_memory_offset).as_ref(),
170 ))
171}
172
173pub fn extcall_gas_calc<WIRE: InterpreterTypes, H: Host + ?Sized>(
174 interpreter: &mut Interpreter<WIRE>,
175 host: &mut H,
176 target: Address,
177 transfers_value: bool,
178) -> Option<u64> {
179 let Some(account_load) = host.load_account_delegated(target) else {
180 interpreter
181 .control
182 .set_instruction_result(InstructionResult::FatalExternalError);
183 return None;
184 };
185
186 let call_cost = gas::call_cost(
189 interpreter.runtime_flag.spec_id(),
190 transfers_value,
191 account_load,
192 );
193 gas!(interpreter, call_cost, None);
194
195 let gas_reduce = max(interpreter.control.gas().remaining() / 64, 5000);
198 let gas_limit = interpreter
199 .control
200 .gas()
201 .remaining()
202 .saturating_sub(gas_reduce);
203
204 if gas_limit < MIN_CALLEE_GAS {
210 let _ = interpreter.stack.push(U256::from(1));
213 interpreter.return_data.clear();
214 return None;
216 }
217
218 gas!(interpreter, gas_limit, None);
219 Some(gas_limit)
220}
221
222#[inline]
226pub fn pop_extcall_target_address(
227 interpreter: &mut Interpreter<impl InterpreterTypes>,
228) -> Option<Address> {
229 popn!([target_address], interpreter, None);
230 let target_address = B256::from(target_address);
231 if target_address[..12].iter().any(|i| *i != 0) {
233 interpreter
234 .control
235 .set_instruction_result(InstructionResult::InvalidEXTCALLTarget);
236 return None;
237 }
238 Some(Address::from_word(target_address))
240}
241
242pub fn extcall<WIRE: InterpreterTypes, H: Host + ?Sized>(
243 interpreter: &mut Interpreter<WIRE>,
244 host: &mut H,
245) {
246 require_eof!(interpreter);
247
248 let Some(target_address) = pop_extcall_target_address(interpreter) else {
250 return;
251 };
252
253 let Some(input) = extcall_input(interpreter) else {
255 return;
256 };
257
258 popn!([value], interpreter);
259 let has_transfer = !value.is_zero();
260 if interpreter.runtime_flag.is_static() && has_transfer {
261 interpreter
262 .control
263 .set_instruction_result(InstructionResult::CallNotAllowedInsideStatic);
264 return;
265 }
266
267 let Some(gas_limit) = extcall_gas_calc(interpreter, host, target_address, has_transfer) else {
268 return;
269 };
270
271 interpreter.control.set_next_action(
273 InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs {
274 input,
275 gas_limit,
276 target_address,
277 caller: interpreter.input.target_address(),
278 bytecode_address: target_address,
279 value: CallValue::Transfer(value),
280 scheme: CallScheme::ExtCall,
281 is_static: interpreter.runtime_flag.is_static(),
282 is_eof: true,
283 return_memory_offset: 0..0,
284 }))),
285 InstructionResult::CallOrCreate,
286 );
287}
288
289pub fn extdelegatecall<WIRE: InterpreterTypes, H: Host + ?Sized>(
290 interpreter: &mut Interpreter<WIRE>,
291 host: &mut H,
292) {
293 require_eof!(interpreter);
294
295 let Some(target_address) = pop_extcall_target_address(interpreter) else {
297 return;
298 };
299
300 let Some(input) = extcall_input(interpreter) else {
302 return;
303 };
304
305 let Some(gas_limit) = extcall_gas_calc(interpreter, host, target_address, false) else {
306 return;
307 };
308
309 interpreter.control.set_next_action(
311 InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs {
312 input,
313 gas_limit,
314 target_address: interpreter.input.target_address(),
315 caller: interpreter.input.caller_address(),
316 bytecode_address: target_address,
317 value: CallValue::Apparent(interpreter.input.call_value()),
318 scheme: CallScheme::ExtDelegateCall,
319 is_static: interpreter.runtime_flag.is_static(),
320 is_eof: true,
321 return_memory_offset: 0..0,
322 }))),
323 InstructionResult::CallOrCreate,
324 );
325}
326
327pub fn extstaticcall<WIRE: InterpreterTypes, H: Host + ?Sized>(
328 interpreter: &mut Interpreter<WIRE>,
329 host: &mut H,
330) {
331 require_eof!(interpreter);
332
333 let Some(target_address) = pop_extcall_target_address(interpreter) else {
335 return;
336 };
337
338 let Some(input) = extcall_input(interpreter) else {
340 return;
341 };
342
343 let Some(gas_limit) = extcall_gas_calc(interpreter, host, target_address, false) else {
344 return;
345 };
346
347 interpreter.control.set_next_action(
349 InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs {
350 input,
351 gas_limit,
352 target_address,
353 caller: interpreter.input.target_address(),
354 bytecode_address: target_address,
355 value: CallValue::Transfer(U256::ZERO),
356 scheme: CallScheme::ExtStaticCall,
357 is_static: true,
358 is_eof: true,
359 return_memory_offset: 0..0,
360 }))),
361 InstructionResult::CallOrCreate,
362 );
363}
364
365pub fn create<WIRE: InterpreterTypes, const IS_CREATE2: bool, H: Host + ?Sized>(
366 interpreter: &mut Interpreter<WIRE>,
367 host: &mut H,
368) {
369 require_non_staticcall!(interpreter);
370
371 if IS_CREATE2 {
373 check!(interpreter, PETERSBURG);
374 }
375
376 popn!([value, code_offset, len], interpreter);
377 let len = as_usize_or_fail!(interpreter, len);
378
379 let mut code = Bytes::new();
380 if len != 0 {
381 if interpreter
383 .runtime_flag
384 .spec_id()
385 .is_enabled_in(SpecId::SHANGHAI)
386 {
387 if len > host.max_initcode_size() {
389 interpreter
390 .control
391 .set_instruction_result(InstructionResult::CreateInitCodeSizeLimit);
392 return;
393 }
394 gas!(interpreter, gas::initcode_cost(len));
395 }
396
397 let code_offset = as_usize_or_fail!(interpreter, code_offset);
398 resize_memory!(interpreter, code_offset, len);
399 code = Bytes::copy_from_slice(interpreter.memory.slice_len(code_offset, len).as_ref());
400 }
401
402 let scheme = if IS_CREATE2 {
404 popn!([salt], interpreter);
405 gas_or_fail!(interpreter, gas::create2_cost(len));
407 CreateScheme::Create2 { salt }
408 } else {
409 gas!(interpreter, gas::CREATE);
410 CreateScheme::Create
411 };
412
413 let mut gas_limit = interpreter.control.gas().remaining();
414
415 if interpreter
417 .runtime_flag
418 .spec_id()
419 .is_enabled_in(SpecId::TANGERINE)
420 {
421 gas_limit -= gas_limit / 64
423 }
424 gas!(interpreter, gas_limit);
425
426 interpreter.control.set_next_action(
428 InterpreterAction::NewFrame(FrameInput::Create(Box::new(CreateInputs {
429 caller: interpreter.input.target_address(),
430 scheme,
431 value,
432 init_code: code,
433 gas_limit,
434 }))),
435 InstructionResult::CallOrCreate,
436 );
437}
438
439pub fn call<WIRE: InterpreterTypes, H: Host + ?Sized>(
440 interpreter: &mut Interpreter<WIRE>,
441 host: &mut H,
442) {
443 popn!([local_gas_limit, to, value], interpreter);
444 let to = to.into_address();
445 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
447
448 let has_transfer = !value.is_zero();
449 if interpreter.runtime_flag.is_static() && has_transfer {
450 interpreter
451 .control
452 .set_instruction_result(InstructionResult::CallNotAllowedInsideStatic);
453 return;
454 }
455
456 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(interpreter) else {
457 return;
458 };
459
460 let Some(account_load) = host.load_account_delegated(to) else {
461 interpreter
462 .control
463 .set_instruction_result(InstructionResult::FatalExternalError);
464 return;
465 };
466
467 let Some(mut gas_limit) =
468 calc_call_gas(interpreter, account_load, has_transfer, local_gas_limit)
469 else {
470 return;
471 };
472
473 gas!(interpreter, gas_limit);
474
475 if has_transfer {
477 gas_limit = gas_limit.saturating_add(gas::CALL_STIPEND);
478 }
479
480 interpreter.control.set_next_action(
482 InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs {
483 input,
484 gas_limit,
485 target_address: to,
486 caller: interpreter.input.target_address(),
487 bytecode_address: to,
488 value: CallValue::Transfer(value),
489 scheme: CallScheme::Call,
490 is_static: interpreter.runtime_flag.is_static(),
491 is_eof: false,
492 return_memory_offset,
493 }))),
494 InstructionResult::CallOrCreate,
495 );
496}
497
498pub fn call_code<WIRE: InterpreterTypes, H: Host + ?Sized>(
499 interpreter: &mut Interpreter<WIRE>,
500 host: &mut H,
501) {
502 popn!([local_gas_limit, to, value], interpreter);
503 let to = Address::from_word(B256::from(to));
504 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
506
507 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(interpreter) else {
509 return;
510 };
511
512 let Some(mut load) = host.load_account_delegated(to) else {
513 interpreter
514 .control
515 .set_instruction_result(InstructionResult::FatalExternalError);
516 return;
517 };
518
519 load.is_empty = false;
521 let Some(mut gas_limit) = calc_call_gas(interpreter, load, !value.is_zero(), local_gas_limit)
522 else {
523 return;
524 };
525
526 gas!(interpreter, gas_limit);
527
528 if !value.is_zero() {
530 gas_limit = gas_limit.saturating_add(gas::CALL_STIPEND);
531 }
532
533 interpreter.control.set_next_action(
535 InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs {
536 input,
537 gas_limit,
538 target_address: interpreter.input.target_address(),
539 caller: interpreter.input.target_address(),
540 bytecode_address: to,
541 value: CallValue::Transfer(value),
542 scheme: CallScheme::CallCode,
543 is_static: interpreter.runtime_flag.is_static(),
544 is_eof: false,
545 return_memory_offset,
546 }))),
547 InstructionResult::CallOrCreate,
548 );
549}
550
551pub fn delegate_call<WIRE: InterpreterTypes, H: Host + ?Sized>(
552 interpreter: &mut Interpreter<WIRE>,
553 host: &mut H,
554) {
555 check!(interpreter, HOMESTEAD);
556 popn!([local_gas_limit, to], interpreter);
557 let to = Address::from_word(B256::from(to));
558 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
560
561 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(interpreter) else {
562 return;
563 };
564
565 let Some(mut load) = host.load_account_delegated(to) else {
566 interpreter
567 .control
568 .set_instruction_result(InstructionResult::FatalExternalError);
569 return;
570 };
571
572 load.is_empty = false;
574 let Some(gas_limit) = calc_call_gas(interpreter, load, false, local_gas_limit) else {
575 return;
576 };
577
578 gas!(interpreter, gas_limit);
579
580 interpreter.control.set_next_action(
582 InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs {
583 input,
584 gas_limit,
585 target_address: interpreter.input.target_address(),
586 caller: interpreter.input.caller_address(),
587 bytecode_address: to,
588 value: CallValue::Apparent(interpreter.input.call_value()),
589 scheme: CallScheme::DelegateCall,
590 is_static: interpreter.runtime_flag.is_static(),
591 is_eof: false,
592 return_memory_offset,
593 }))),
594 InstructionResult::CallOrCreate,
595 );
596}
597
598pub fn static_call<WIRE: InterpreterTypes, H: Host + ?Sized>(
599 interpreter: &mut Interpreter<WIRE>,
600 host: &mut H,
601) {
602 check!(interpreter, BYZANTIUM);
603 popn!([local_gas_limit, to], interpreter);
604 let to = Address::from_word(B256::from(to));
605 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
607
608 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(interpreter) else {
609 return;
610 };
611
612 let Some(mut load) = host.load_account_delegated(to) else {
613 interpreter
614 .control
615 .set_instruction_result(InstructionResult::FatalExternalError);
616 return;
617 };
618 load.is_empty = false;
620 let Some(gas_limit) = calc_call_gas(interpreter, load, false, local_gas_limit) else {
621 return;
622 };
623 gas!(interpreter, gas_limit);
624
625 interpreter.control.set_next_action(
627 InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs {
628 input,
629 gas_limit,
630 target_address: to,
631 caller: interpreter.input.target_address(),
632 bytecode_address: to,
633 value: CallValue::Transfer(U256::ZERO),
634 scheme: CallScheme::StaticCall,
635 is_static: true,
636 is_eof: false,
637 return_memory_offset,
638 }))),
639 InstructionResult::CallOrCreate,
640 );
641}