1mod call_helpers;
2
3pub use call_helpers::{
4 get_memory_input_and_out_ranges, load_acc_and_calc_gas, load_account_delegated,
5 load_account_delegated_handle_error, resize_memory,
6};
7
8use crate::{
9 instructions::utility::IntoAddress,
10 interpreter_action::FrameInput,
11 interpreter_types::{InputsTr, InterpreterTypes, LoopControl, MemoryTr, RuntimeFlag, StackTr},
12 CallInput, CallInputs, CallScheme, CallValue, CreateInputs, Host, InstructionResult,
13 InterpreterAction,
14};
15use context_interface::CreateScheme;
16use primitives::{hardfork::SpecId, Address, Bytes, B256, U256};
17use std::boxed::Box;
18
19use crate::InstructionContext;
20
21pub fn create<WIRE: InterpreterTypes, const IS_CREATE2: bool, H: Host + ?Sized>(
25 context: InstructionContext<'_, H, WIRE>,
26) {
27 require_non_staticcall!(context.interpreter);
31
32 if IS_CREATE2 {
34 check!(context.interpreter, PETERSBURG);
35 }
36
37 popn!([value, code_offset, len], context.interpreter);
38 let len = as_usize_or_fail!(context.interpreter, len);
39
40 let mut code = Bytes::new();
41 if len != 0 {
42 if context
44 .interpreter
45 .runtime_flag
46 .spec_id()
47 .is_enabled_in(SpecId::SHANGHAI)
48 {
49 if len > context.host.max_initcode_size() {
51 context
52 .interpreter
53 .halt(InstructionResult::CreateInitCodeSizeLimit);
54 return;
55 }
56 gas!(
57 context.interpreter,
58 context.host.gas_params().initcode_cost(len)
59 );
60 }
61
62 let code_offset = as_usize_or_fail!(context.interpreter, code_offset);
63 resize_memory!(
64 context.interpreter,
65 context.host.gas_params(),
66 code_offset,
67 len
68 );
69
70 code = Bytes::copy_from_slice(
71 context
72 .interpreter
73 .memory
74 .slice_len(code_offset, len)
75 .as_ref(),
76 );
77 }
78
79 let scheme = if IS_CREATE2 {
81 popn!([salt], context.interpreter);
82 gas!(
84 context.interpreter,
85 context.host.gas_params().create2_cost(len)
86 );
87 CreateScheme::Create2 { salt }
88 } else {
89 gas!(context.interpreter, context.host.gas_params().create_cost());
90 CreateScheme::Create
91 };
92
93 if context.host.is_amsterdam_eip8037_enabled() {
95 state_gas!(
96 context.interpreter,
97 context.host.gas_params().create_state_gas()
98 );
99 }
100
101 let mut gas_limit = context.interpreter.gas.remaining();
102
103 if context
105 .interpreter
106 .runtime_flag
107 .spec_id()
108 .is_enabled_in(SpecId::TANGERINE)
109 {
110 gas_limit = context.host.gas_params().call_stipend_reduction(gas_limit);
112 }
113 gas!(context.interpreter, gas_limit);
114
115 let create_inputs = CreateInputs::new(
117 context.interpreter.input.target_address(),
118 scheme,
119 value,
120 code,
121 gas_limit,
122 context.interpreter.gas.reservoir(),
123 );
124 context
125 .interpreter
126 .bytecode
127 .set_action(InterpreterAction::NewFrame(FrameInput::Create(Box::new(
128 create_inputs,
129 ))));
130}
131
132pub fn call<WIRE: InterpreterTypes, H: Host + ?Sized>(
136 mut context: InstructionContext<'_, H, WIRE>,
137) {
138 popn!([local_gas_limit, to, value], context.interpreter);
139 let to = to.into_address();
140 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
142 let has_transfer = !value.is_zero();
143
144 if context.interpreter.runtime_flag.is_static() && has_transfer {
145 context
146 .interpreter
147 .halt(InstructionResult::CallNotAllowedInsideStatic);
148 return;
149 }
150
151 let Some((input, return_memory_offset)) =
152 get_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())
153 else {
154 return;
155 };
156
157 let Some((gas_limit, bytecode, bytecode_hash)) =
158 load_acc_and_calc_gas(&mut context, to, has_transfer, true, local_gas_limit)
159 else {
160 return;
161 };
162
163 context
165 .interpreter
166 .bytecode
167 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
168 CallInputs {
169 input: CallInput::SharedBuffer(input),
170 gas_limit,
171 target_address: to,
172 caller: context.interpreter.input.target_address(),
173 bytecode_address: to,
174 known_bytecode: (bytecode_hash, bytecode),
175 value: CallValue::Transfer(value),
176 scheme: CallScheme::Call,
177 is_static: context.interpreter.runtime_flag.is_static(),
178 return_memory_offset,
179 reservoir: context.interpreter.gas.reservoir(),
180 },
181 ))));
182}
183
184pub fn call_code<WIRE: InterpreterTypes, H: Host + ?Sized>(
188 mut context: InstructionContext<'_, H, WIRE>,
189) {
190 popn!([local_gas_limit, to, value], context.interpreter);
191 let to = Address::from_word(B256::from(to));
192 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
194 let has_transfer = !value.is_zero();
195
196 let Some((input, return_memory_offset)) =
197 get_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())
198 else {
199 return;
200 };
201
202 let Some((gas_limit, bytecode, bytecode_hash)) =
203 load_acc_and_calc_gas(&mut context, to, has_transfer, false, local_gas_limit)
204 else {
205 return;
206 };
207
208 context
210 .interpreter
211 .bytecode
212 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
213 CallInputs {
214 input: CallInput::SharedBuffer(input),
215 gas_limit,
216 target_address: context.interpreter.input.target_address(),
217 caller: context.interpreter.input.target_address(),
218 bytecode_address: to,
219 known_bytecode: (bytecode_hash, bytecode),
220 value: CallValue::Transfer(value),
221 scheme: CallScheme::CallCode,
222 is_static: context.interpreter.runtime_flag.is_static(),
223 return_memory_offset,
224 reservoir: context.interpreter.gas.reservoir(),
225 },
226 ))));
227}
228
229pub fn delegate_call<WIRE: InterpreterTypes, H: Host + ?Sized>(
233 mut context: InstructionContext<'_, H, WIRE>,
234) {
235 check!(context.interpreter, HOMESTEAD);
236 popn!([local_gas_limit, to], context.interpreter);
237 let to = Address::from_word(B256::from(to));
238 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
240
241 let Some((input, return_memory_offset)) =
242 get_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())
243 else {
244 return;
245 };
246
247 let Some((gas_limit, bytecode, bytecode_hash)) =
248 load_acc_and_calc_gas(&mut context, to, false, false, local_gas_limit)
249 else {
250 return;
251 };
252
253 context
255 .interpreter
256 .bytecode
257 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
258 CallInputs {
259 input: CallInput::SharedBuffer(input),
260 gas_limit,
261 target_address: context.interpreter.input.target_address(),
262 caller: context.interpreter.input.caller_address(),
263 bytecode_address: to,
264 known_bytecode: (bytecode_hash, bytecode),
265 value: CallValue::Apparent(context.interpreter.input.call_value()),
266 scheme: CallScheme::DelegateCall,
267 is_static: context.interpreter.runtime_flag.is_static(),
268 return_memory_offset,
269 reservoir: context.interpreter.gas.reservoir(),
270 },
271 ))));
272}
273
274pub fn static_call<WIRE: InterpreterTypes, H: Host + ?Sized>(
278 mut context: InstructionContext<'_, H, WIRE>,
279) {
280 check!(context.interpreter, BYZANTIUM);
281 popn!([local_gas_limit, to], context.interpreter);
282 let to = Address::from_word(B256::from(to));
283 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
285
286 let Some((input, return_memory_offset)) =
287 get_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())
288 else {
289 return;
290 };
291
292 let Some((gas_limit, bytecode, bytecode_hash)) =
293 load_acc_and_calc_gas(&mut context, to, false, false, local_gas_limit)
294 else {
295 return;
296 };
297
298 context
300 .interpreter
301 .bytecode
302 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
303 CallInputs {
304 input: CallInput::SharedBuffer(input),
305 gas_limit,
306 target_address: to,
307 caller: context.interpreter.input.target_address(),
308 bytecode_address: to,
309 known_bytecode: (bytecode_hash, bytecode),
310 value: CallValue::Transfer(U256::ZERO),
311 scheme: CallScheme::StaticCall,
312 is_static: true,
313 return_memory_offset,
314 reservoir: context.interpreter.gas.reservoir(),
315 },
316 ))));
317}