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, EOF_CREATE_GAS, 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 CallInput, CallInputs, CallScheme, CallValue, CreateInputs, EOFCreateInputs, Host,
15 InstructionResult, InterpreterAction, InterpreterResult,
16};
17use bytecode::eof::{Eof, EofHeader};
18use context_interface::CreateScheme;
19use core::cmp::max;
20use primitives::{eof::new_eof_address, hardfork::SpecId, 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!([salt, input_offset, input_size, value], 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, input_offset, input_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 let created_address = new_eof_address(
61 interpreter.input.target_address(),
62 salt.to_be_bytes().into(),
63 );
64
65 let gas_limit = interpreter.control.gas().remaining_63_of_64_parts();
66 gas!(interpreter, gas_limit);
67
68 interpreter.control.set_next_action(
70 InterpreterAction::NewFrame(FrameInput::EOFCreate(Box::new(
71 EOFCreateInputs::new_opcode(
72 interpreter.input.target_address(),
73 created_address,
74 value,
75 eof,
76 gas_limit,
77 CallInput::Bytes(input),
78 ),
79 ))),
80 InstructionResult::CallOrCreate,
81 );
82
83 interpreter.bytecode.relative_jump(1);
85}
86
87pub fn txcreate<WIRE: InterpreterTypes, H: Host + ?Sized>(
89 interpreter: &mut Interpreter<WIRE>,
90 host: &mut H,
91) {
92 require_eof!(interpreter);
94 require_non_staticcall!(interpreter);
95 gas!(interpreter, EOF_CREATE_GAS);
96
97 popn!(
99 [tx_initcode_hash, salt, input_offset, input_size, value],
100 interpreter
101 );
102 let tx_initcode_hash = B256::from(tx_initcode_hash);
103
104 let Some(input_range) = resize_memory(interpreter, input_offset, input_size) else {
106 return;
107 };
108
109 let Some(initcode) = host.initcode_by_hash(tx_initcode_hash) else {
111 push!(interpreter, U256::ZERO);
113 return;
114 };
115
116 let input = if !input_range.is_empty() {
118 interpreter.memory.slice(input_range).to_vec().into()
119 } else {
120 Bytes::new()
121 };
122
123 let eof = Eof::decode(initcode).expect("Subcontainer is verified");
125
126 let created_address = new_eof_address(
128 interpreter.input.target_address(),
129 salt.to_be_bytes().into(),
130 );
131
132 let gas_limit = interpreter.control.gas().remaining_63_of_64_parts();
133 gas!(interpreter, gas_limit);
134
135 interpreter.control.set_next_action(
137 InterpreterAction::NewFrame(FrameInput::EOFCreate(Box::new(
138 EOFCreateInputs::new_opcode(
139 interpreter.input.target_address(),
140 created_address,
141 value,
142 eof,
143 gas_limit,
144 CallInput::Bytes(input),
145 ),
146 ))),
147 InstructionResult::CallOrCreate,
148 );
149}
150
151pub fn return_contract<H: Host + ?Sized>(
152 interpreter: &mut Interpreter<impl InterpreterTypes>,
153 _host: &mut H,
154) {
155 if !interpreter.runtime_flag.is_eof_init() {
156 interpreter
157 .control
158 .set_instruction_result(InstructionResult::ReturnContractInNotInitEOF);
159 return;
160 }
161 let deploy_container_index = interpreter.bytecode.read_u8();
162 popn!([aux_data_offset, aux_data_size], interpreter);
163 let aux_data_size = as_usize_or_fail!(interpreter, aux_data_size);
164 let container = interpreter
165 .bytecode
166 .eof_container(deploy_container_index as usize)
167 .expect("valid container")
168 .clone();
169
170 let (eof_header, _) = EofHeader::decode(&container).expect("valid EOF header");
172
173 let static_aux_size = eof_header.eof_size() - container.len();
174
175 let mut output = if aux_data_size != 0 {
177 let aux_data_offset = as_usize_or_fail!(interpreter, aux_data_offset);
178 resize_memory!(interpreter, aux_data_offset, aux_data_size);
179
180 let aux_slice = interpreter.memory.slice_len(aux_data_offset, aux_data_size);
181
182 [&container, aux_slice.as_ref()].concat()
183 } else {
184 container.to_vec()
185 };
186
187 let new_data_size = eof_header.data_size as usize - static_aux_size + aux_data_size;
190 if new_data_size > 0xFFFF {
191 interpreter
193 .control
194 .set_instruction_result(InstructionResult::EofAuxDataOverflow);
195 return;
196 }
197 if new_data_size < eof_header.data_size as usize {
198 interpreter
200 .control
201 .set_instruction_result(InstructionResult::EofAuxDataTooSmall);
202 return;
203 }
204 let new_data_size = (new_data_size as u16).to_be_bytes();
205
206 output[eof_header.data_size_raw_i()..][..2].clone_from_slice(&new_data_size);
208 let output: Bytes = output.into();
209
210 let result = InstructionResult::ReturnContract;
211 let gas = *interpreter.control.gas();
212 interpreter.control.set_next_action(
213 crate::InterpreterAction::Return {
214 result: InterpreterResult {
215 output,
216 gas,
217 result,
218 },
219 },
220 result,
221 );
222}
223
224pub fn extcall_input(interpreter: &mut Interpreter<impl InterpreterTypes>) -> Option<Bytes> {
225 popn!([input_offset, input_size], interpreter, None);
226 let return_memory_offset = resize_memory(interpreter, input_offset, input_size)?;
227
228 if return_memory_offset.is_empty() {
229 return Some(Bytes::new());
230 }
231
232 Some(Bytes::copy_from_slice(
233 interpreter.memory.slice(return_memory_offset).as_ref(),
234 ))
235}
236
237pub fn extcall_gas_calc<WIRE: InterpreterTypes, H: Host + ?Sized>(
238 interpreter: &mut Interpreter<WIRE>,
239 host: &mut H,
240 target: Address,
241 transfers_value: bool,
242) -> Option<u64> {
243 let Some(account_load) = host.load_account_delegated(target) else {
244 interpreter
245 .control
246 .set_instruction_result(InstructionResult::FatalExternalError);
247 return None;
248 };
249
250 let call_cost = gas::call_cost(
253 interpreter.runtime_flag.spec_id(),
254 transfers_value,
255 account_load,
256 );
257 gas!(interpreter, call_cost, None);
258
259 let gas_reduce = max(interpreter.control.gas().remaining() / 64, 5000);
262 let gas_limit = interpreter
263 .control
264 .gas()
265 .remaining()
266 .saturating_sub(gas_reduce);
267
268 if gas_limit < MIN_CALLEE_GAS {
274 let _ = interpreter.stack.push(U256::from(1));
277 interpreter.return_data.clear();
278 return None;
280 }
281
282 gas!(interpreter, gas_limit, None);
283 Some(gas_limit)
284}
285
286#[inline]
290pub fn pop_extcall_target_address(
291 interpreter: &mut Interpreter<impl InterpreterTypes>,
292) -> Option<Address> {
293 popn!([target_address], interpreter, None);
294 let target_address = B256::from(target_address);
295 if target_address[..12].iter().any(|i| *i != 0) {
297 interpreter
298 .control
299 .set_instruction_result(InstructionResult::InvalidEXTCALLTarget);
300 return None;
301 }
302 Some(Address::from_word(target_address))
304}
305
306pub fn extcall<WIRE: InterpreterTypes, H: Host + ?Sized>(
307 interpreter: &mut Interpreter<WIRE>,
308 host: &mut H,
309) {
310 require_eof!(interpreter);
311
312 let Some(target_address) = pop_extcall_target_address(interpreter) else {
314 return;
315 };
316
317 let Some(input) = extcall_input(interpreter) else {
319 return;
320 };
321
322 popn!([value], interpreter);
323 let has_transfer = !value.is_zero();
324 if interpreter.runtime_flag.is_static() && has_transfer {
325 interpreter
326 .control
327 .set_instruction_result(InstructionResult::CallNotAllowedInsideStatic);
328 return;
329 }
330
331 let Some(gas_limit) = extcall_gas_calc(interpreter, host, target_address, has_transfer) else {
332 return;
333 };
334
335 interpreter.control.set_next_action(
337 InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs {
338 input: CallInput::Bytes(input),
339 gas_limit,
340 target_address,
341 caller: interpreter.input.target_address(),
342 bytecode_address: target_address,
343 value: CallValue::Transfer(value),
344 scheme: CallScheme::ExtCall,
345 is_static: interpreter.runtime_flag.is_static(),
346 is_eof: true,
347 return_memory_offset: 0..0,
348 }))),
349 InstructionResult::CallOrCreate,
350 );
351}
352
353pub fn extdelegatecall<WIRE: InterpreterTypes, H: Host + ?Sized>(
354 interpreter: &mut Interpreter<WIRE>,
355 host: &mut H,
356) {
357 require_eof!(interpreter);
358
359 let Some(target_address) = pop_extcall_target_address(interpreter) else {
361 return;
362 };
363
364 let Some(input) = extcall_input(interpreter) else {
366 return;
367 };
368
369 let Some(gas_limit) = extcall_gas_calc(interpreter, host, target_address, false) else {
370 return;
371 };
372
373 interpreter.control.set_next_action(
375 InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs {
376 input: CallInput::Bytes(input),
377 gas_limit,
378 target_address: interpreter.input.target_address(),
379 caller: interpreter.input.caller_address(),
380 bytecode_address: target_address,
381 value: CallValue::Apparent(interpreter.input.call_value()),
382 scheme: CallScheme::ExtDelegateCall,
383 is_static: interpreter.runtime_flag.is_static(),
384 is_eof: true,
385 return_memory_offset: 0..0,
386 }))),
387 InstructionResult::CallOrCreate,
388 );
389}
390
391pub fn extstaticcall<WIRE: InterpreterTypes, H: Host + ?Sized>(
392 interpreter: &mut Interpreter<WIRE>,
393 host: &mut H,
394) {
395 require_eof!(interpreter);
396
397 let Some(target_address) = pop_extcall_target_address(interpreter) else {
399 return;
400 };
401
402 let Some(input) = extcall_input(interpreter) else {
404 return;
405 };
406
407 let Some(gas_limit) = extcall_gas_calc(interpreter, host, target_address, false) else {
408 return;
409 };
410
411 interpreter.control.set_next_action(
413 InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs {
414 input: CallInput::Bytes(input),
415 gas_limit,
416 target_address,
417 caller: interpreter.input.target_address(),
418 bytecode_address: target_address,
419 value: CallValue::Transfer(U256::ZERO),
420 scheme: CallScheme::ExtStaticCall,
421 is_static: true,
422 is_eof: true,
423 return_memory_offset: 0..0,
424 }))),
425 InstructionResult::CallOrCreate,
426 );
427}
428
429pub fn create<WIRE: InterpreterTypes, const IS_CREATE2: bool, H: Host + ?Sized>(
430 interpreter: &mut Interpreter<WIRE>,
431 host: &mut H,
432) {
433 require_non_staticcall!(interpreter);
434
435 if IS_CREATE2 {
437 check!(interpreter, PETERSBURG);
438 }
439
440 popn!([value, code_offset, len], interpreter);
441 let len = as_usize_or_fail!(interpreter, len);
442
443 let mut code = Bytes::new();
444 if len != 0 {
445 if interpreter
447 .runtime_flag
448 .spec_id()
449 .is_enabled_in(SpecId::SHANGHAI)
450 {
451 if len > host.max_initcode_size() {
453 interpreter
454 .control
455 .set_instruction_result(InstructionResult::CreateInitCodeSizeLimit);
456 return;
457 }
458 gas!(interpreter, gas::initcode_cost(len));
459 }
460
461 let code_offset = as_usize_or_fail!(interpreter, code_offset);
462 resize_memory!(interpreter, code_offset, len);
463 code = Bytes::copy_from_slice(interpreter.memory.slice_len(code_offset, len).as_ref());
464 }
465
466 let scheme = if IS_CREATE2 {
468 popn!([salt], interpreter);
469 gas_or_fail!(interpreter, gas::create2_cost(len));
471 CreateScheme::Create2 { salt }
472 } else {
473 gas!(interpreter, gas::CREATE);
474 CreateScheme::Create
475 };
476
477 let mut gas_limit = interpreter.control.gas().remaining();
478
479 if interpreter
481 .runtime_flag
482 .spec_id()
483 .is_enabled_in(SpecId::TANGERINE)
484 {
485 gas_limit -= gas_limit / 64
487 }
488 gas!(interpreter, gas_limit);
489
490 interpreter.control.set_next_action(
492 InterpreterAction::NewFrame(FrameInput::Create(Box::new(CreateInputs {
493 caller: interpreter.input.target_address(),
494 scheme,
495 value,
496 init_code: code,
497 gas_limit,
498 }))),
499 InstructionResult::CallOrCreate,
500 );
501}
502
503pub fn call<WIRE: InterpreterTypes, H: Host + ?Sized>(
504 interpreter: &mut Interpreter<WIRE>,
505 host: &mut H,
506) {
507 popn!([local_gas_limit, to, value], interpreter);
508 let to = to.into_address();
509 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
511
512 let has_transfer = !value.is_zero();
513 if interpreter.runtime_flag.is_static() && has_transfer {
514 interpreter
515 .control
516 .set_instruction_result(InstructionResult::CallNotAllowedInsideStatic);
517 return;
518 }
519
520 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(interpreter) else {
521 return;
522 };
523
524 let Some(account_load) = host.load_account_delegated(to) else {
525 interpreter
526 .control
527 .set_instruction_result(InstructionResult::FatalExternalError);
528 return;
529 };
530
531 let Some(mut gas_limit) =
532 calc_call_gas(interpreter, account_load, has_transfer, local_gas_limit)
533 else {
534 return;
535 };
536
537 gas!(interpreter, gas_limit);
538
539 if has_transfer {
541 gas_limit = gas_limit.saturating_add(gas::CALL_STIPEND);
542 }
543
544 interpreter.control.set_next_action(
546 InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs {
547 input: CallInput::SharedBuffer(input),
548 gas_limit,
549 target_address: to,
550 caller: interpreter.input.target_address(),
551 bytecode_address: to,
552 value: CallValue::Transfer(value),
553 scheme: CallScheme::Call,
554 is_static: interpreter.runtime_flag.is_static(),
555 is_eof: false,
556 return_memory_offset,
557 }))),
558 InstructionResult::CallOrCreate,
559 );
560}
561
562pub fn call_code<WIRE: InterpreterTypes, H: Host + ?Sized>(
563 interpreter: &mut Interpreter<WIRE>,
564 host: &mut H,
565) {
566 popn!([local_gas_limit, to, value], interpreter);
567 let to = Address::from_word(B256::from(to));
568 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
570
571 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(interpreter) else {
573 return;
574 };
575
576 let Some(mut load) = host.load_account_delegated(to) else {
577 interpreter
578 .control
579 .set_instruction_result(InstructionResult::FatalExternalError);
580 return;
581 };
582
583 load.is_empty = false;
585 let Some(mut gas_limit) = calc_call_gas(interpreter, load, !value.is_zero(), local_gas_limit)
586 else {
587 return;
588 };
589
590 gas!(interpreter, gas_limit);
591
592 if !value.is_zero() {
594 gas_limit = gas_limit.saturating_add(gas::CALL_STIPEND);
595 }
596
597 interpreter.control.set_next_action(
599 InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs {
600 input: CallInput::SharedBuffer(input),
601 gas_limit,
602 target_address: interpreter.input.target_address(),
603 caller: interpreter.input.target_address(),
604 bytecode_address: to,
605 value: CallValue::Transfer(value),
606 scheme: CallScheme::CallCode,
607 is_static: interpreter.runtime_flag.is_static(),
608 is_eof: false,
609 return_memory_offset,
610 }))),
611 InstructionResult::CallOrCreate,
612 );
613}
614
615pub fn delegate_call<WIRE: InterpreterTypes, H: Host + ?Sized>(
616 interpreter: &mut Interpreter<WIRE>,
617 host: &mut H,
618) {
619 check!(interpreter, HOMESTEAD);
620 popn!([local_gas_limit, to], interpreter);
621 let to = Address::from_word(B256::from(to));
622 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
624
625 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(interpreter) else {
626 return;
627 };
628
629 let Some(mut load) = host.load_account_delegated(to) else {
630 interpreter
631 .control
632 .set_instruction_result(InstructionResult::FatalExternalError);
633 return;
634 };
635
636 load.is_empty = false;
638 let Some(gas_limit) = calc_call_gas(interpreter, load, false, local_gas_limit) else {
639 return;
640 };
641
642 gas!(interpreter, gas_limit);
643
644 interpreter.control.set_next_action(
646 InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs {
647 input: CallInput::SharedBuffer(input),
648 gas_limit,
649 target_address: interpreter.input.target_address(),
650 caller: interpreter.input.caller_address(),
651 bytecode_address: to,
652 value: CallValue::Apparent(interpreter.input.call_value()),
653 scheme: CallScheme::DelegateCall,
654 is_static: interpreter.runtime_flag.is_static(),
655 is_eof: false,
656 return_memory_offset,
657 }))),
658 InstructionResult::CallOrCreate,
659 );
660}
661
662pub fn static_call<WIRE: InterpreterTypes, H: Host + ?Sized>(
663 interpreter: &mut Interpreter<WIRE>,
664 host: &mut H,
665) {
666 check!(interpreter, BYZANTIUM);
667 popn!([local_gas_limit, to], interpreter);
668 let to = Address::from_word(B256::from(to));
669 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
671
672 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(interpreter) else {
673 return;
674 };
675
676 let Some(mut load) = host.load_account_delegated(to) else {
677 interpreter
678 .control
679 .set_instruction_result(InstructionResult::FatalExternalError);
680 return;
681 };
682 load.is_empty = false;
684 let Some(gas_limit) = calc_call_gas(interpreter, load, false, local_gas_limit) else {
685 return;
686 };
687 gas!(interpreter, gas_limit);
688
689 interpreter.control.set_next_action(
691 InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs {
692 input: CallInput::SharedBuffer(input),
693 gas_limit,
694 target_address: to,
695 caller: interpreter.input.target_address(),
696 bytecode_address: to,
697 value: CallValue::Transfer(U256::ZERO),
698 scheme: CallScheme::StaticCall,
699 is_static: true,
700 is_eof: false,
701 return_memory_offset,
702 }))),
703 InstructionResult::CallOrCreate,
704 );
705}