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