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::{
12 InputsTr, InterpreterTypes as ITy, LoopControl, MemoryTr, RuntimeFlag, StackTr,
13 },
14 CallInput, CallInputs, CallScheme, CallValue, CreateInputs, Host,
15 InstructionExecResult as Result, InstructionResult, InterpreterAction,
16};
17use context_interface::CreateScheme;
18use primitives::{hardfork::SpecId, Address, Bytes, B256, U256};
19use std::boxed::Box;
20
21use crate::InstructionContext as Ictx;
22
23pub fn create<IT: ITy, const IS_CREATE2: bool, H: Host + ?Sized>(
27 context: Ictx<'_, H, IT>,
28) -> Result {
29 require_non_staticcall!(context.interpreter);
33
34 if IS_CREATE2 {
36 check!(context.interpreter, PETERSBURG);
37 }
38
39 popn!([value, code_offset, len], context.interpreter);
40 let len = as_usize_or_fail!(context.interpreter, len);
41
42 let mut code = Bytes::new();
43 if len != 0 {
44 if context
46 .interpreter
47 .runtime_flag
48 .spec_id()
49 .is_enabled_in(SpecId::SHANGHAI)
50 {
51 if len > context.host.max_initcode_size() {
53 return Err(InstructionResult::CreateInitCodeSizeLimit);
54 }
55 gas!(
56 context.interpreter,
57 context.host.gas_params().initcode_cost(len)
58 );
59 }
60
61 let code_offset = as_usize_or_fail!(context.interpreter, code_offset);
62 context
63 .interpreter
64 .resize_memory(context.host.gas_params(), code_offset, len)?;
65
66 code = Bytes::copy_from_slice(
67 context
68 .interpreter
69 .memory
70 .slice_len(code_offset, len)
71 .as_ref(),
72 );
73 }
74
75 let scheme = if IS_CREATE2 {
77 popn!([salt], context.interpreter);
78 gas!(
80 context.interpreter,
81 context.host.gas_params().create2_cost(len)
82 );
83 CreateScheme::Create2 { salt }
84 } else {
85 gas!(context.interpreter, context.host.gas_params().create_cost());
86 CreateScheme::Create
87 };
88
89 if context.host.is_amsterdam_eip8037_enabled() {
91 state_gas!(
92 context.interpreter,
93 context.host.gas_params().create_state_gas()
94 );
95 }
96
97 let mut gas_limit = context.interpreter.gas.remaining();
98
99 if context
101 .interpreter
102 .runtime_flag
103 .spec_id()
104 .is_enabled_in(SpecId::TANGERINE)
105 {
106 gas_limit = context.host.gas_params().call_stipend_reduction(gas_limit);
108 }
109 gas!(context.interpreter, gas_limit);
110
111 let create_inputs = CreateInputs::new(
113 context.interpreter.input.target_address(),
114 scheme,
115 value,
116 code,
117 gas_limit,
118 context.interpreter.gas.reservoir(),
119 );
120 context
121 .interpreter
122 .bytecode
123 .set_action(InterpreterAction::NewFrame(FrameInput::Create(Box::new(
124 create_inputs,
125 ))));
126 Err(InstructionResult::Suspend)
127}
128
129pub fn call<IT: ITy, H: Host + ?Sized>(mut context: Ictx<'_, H, IT>) -> Result {
133 popn!([local_gas_limit, to, value], context.interpreter);
134 let to = to.into_address();
135 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
137 let has_transfer = !value.is_zero();
138
139 if context.interpreter.runtime_flag.is_static() && has_transfer {
140 return Err(InstructionResult::CallNotAllowedInsideStatic);
141 }
142
143 let (input, return_memory_offset) =
144 get_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())?;
145
146 let (gas_limit, bytecode, bytecode_hash) =
147 load_acc_and_calc_gas(&mut context, to, has_transfer, true, local_gas_limit)?;
148
149 context
151 .interpreter
152 .bytecode
153 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
154 CallInputs {
155 input: CallInput::SharedBuffer(input),
156 gas_limit,
157 target_address: to,
158 caller: context.interpreter.input.target_address(),
159 bytecode_address: to,
160 known_bytecode: (bytecode_hash, bytecode),
161 value: CallValue::Transfer(value),
162 scheme: CallScheme::Call,
163 is_static: context.interpreter.runtime_flag.is_static(),
164 return_memory_offset,
165 reservoir: context.interpreter.gas.reservoir(),
166 },
167 ))));
168 Err(InstructionResult::Suspend)
169}
170
171pub fn call_code<IT: ITy, H: Host + ?Sized>(mut context: Ictx<'_, H, IT>) -> Result {
175 popn!([local_gas_limit, to, value], context.interpreter);
176 let to = Address::from_word(B256::from(to));
177 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
179 let has_transfer = !value.is_zero();
180
181 let (input, return_memory_offset) =
182 get_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())?;
183
184 let (gas_limit, bytecode, bytecode_hash) =
185 load_acc_and_calc_gas(&mut context, to, has_transfer, false, local_gas_limit)?;
186
187 context
189 .interpreter
190 .bytecode
191 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
192 CallInputs {
193 input: CallInput::SharedBuffer(input),
194 gas_limit,
195 target_address: context.interpreter.input.target_address(),
196 caller: context.interpreter.input.target_address(),
197 bytecode_address: to,
198 known_bytecode: (bytecode_hash, bytecode),
199 value: CallValue::Transfer(value),
200 scheme: CallScheme::CallCode,
201 is_static: context.interpreter.runtime_flag.is_static(),
202 return_memory_offset,
203 reservoir: context.interpreter.gas.reservoir(),
204 },
205 ))));
206 Err(InstructionResult::Suspend)
207}
208
209pub fn delegate_call<IT: ITy, H: Host + ?Sized>(mut context: Ictx<'_, H, IT>) -> Result {
213 check!(context.interpreter, HOMESTEAD);
214 popn!([local_gas_limit, to], context.interpreter);
215 let to = Address::from_word(B256::from(to));
216 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
218
219 let (input, return_memory_offset) =
220 get_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())?;
221
222 let (gas_limit, bytecode, bytecode_hash) =
223 load_acc_and_calc_gas(&mut context, to, false, false, local_gas_limit)?;
224
225 context
227 .interpreter
228 .bytecode
229 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
230 CallInputs {
231 input: CallInput::SharedBuffer(input),
232 gas_limit,
233 target_address: context.interpreter.input.target_address(),
234 caller: context.interpreter.input.caller_address(),
235 bytecode_address: to,
236 known_bytecode: (bytecode_hash, bytecode),
237 value: CallValue::Apparent(context.interpreter.input.call_value()),
238 scheme: CallScheme::DelegateCall,
239 is_static: context.interpreter.runtime_flag.is_static(),
240 return_memory_offset,
241 reservoir: context.interpreter.gas.reservoir(),
242 },
243 ))));
244 Err(InstructionResult::Suspend)
245}
246
247pub fn static_call<IT: ITy, H: Host + ?Sized>(mut context: Ictx<'_, H, IT>) -> Result {
251 check!(context.interpreter, BYZANTIUM);
252 popn!([local_gas_limit, to], context.interpreter);
253 let to = Address::from_word(B256::from(to));
254 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
256
257 let (input, return_memory_offset) =
258 get_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())?;
259
260 let (gas_limit, bytecode, bytecode_hash) =
261 load_acc_and_calc_gas(&mut context, to, false, false, local_gas_limit)?;
262
263 context
265 .interpreter
266 .bytecode
267 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
268 CallInputs {
269 input: CallInput::SharedBuffer(input),
270 gas_limit,
271 target_address: to,
272 caller: context.interpreter.input.target_address(),
273 bytecode_address: to,
274 known_bytecode: (bytecode_hash, bytecode),
275 value: CallValue::Transfer(U256::ZERO),
276 scheme: CallScheme::StaticCall,
277 is_static: true,
278 return_memory_offset,
279 reservoir: context.interpreter.gas.reservoir(),
280 },
281 ))));
282 Err(InstructionResult::Suspend)
283}