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