revm_interpreter/instructions/
contract.rs1mod call_helpers;
2
3pub use call_helpers::{calc_call_gas, get_memory_input_and_out_ranges, resize_memory};
4
5use crate::{
6 gas,
7 instructions::utility::IntoAddress,
8 interpreter_action::FrameInput,
9 interpreter_types::{InputsTr, InterpreterTypes, LoopControl, MemoryTr, RuntimeFlag, StackTr},
10 CallInput, CallInputs, CallScheme, CallValue, CreateInputs, Host, InstructionResult,
11 InterpreterAction,
12};
13use context_interface::CreateScheme;
14use primitives::{hardfork::SpecId, Address, Bytes, B256, U256};
15use std::boxed::Box;
16
17use crate::InstructionContext;
18
19pub fn create<WIRE: InterpreterTypes, const IS_CREATE2: bool, H: Host + ?Sized>(
23 context: InstructionContext<'_, H, WIRE>,
24) {
25 require_non_staticcall!(context.interpreter);
26
27 if IS_CREATE2 {
29 check!(context.interpreter, PETERSBURG);
30 }
31
32 popn!([value, code_offset, len], context.interpreter);
33 let len = as_usize_or_fail!(context.interpreter, len);
34
35 let mut code = Bytes::new();
36 if len != 0 {
37 if context
39 .interpreter
40 .runtime_flag
41 .spec_id()
42 .is_enabled_in(SpecId::SHANGHAI)
43 {
44 if len > context.host.max_initcode_size() {
46 context
47 .interpreter
48 .halt(InstructionResult::CreateInitCodeSizeLimit);
49 return;
50 }
51 gas!(context.interpreter, gas::initcode_cost(len));
52 }
53
54 let code_offset = as_usize_or_fail!(context.interpreter, code_offset);
55 resize_memory!(context.interpreter, code_offset, len);
56 code = Bytes::copy_from_slice(
57 context
58 .interpreter
59 .memory
60 .slice_len(code_offset, len)
61 .as_ref(),
62 );
63 }
64
65 let scheme = if IS_CREATE2 {
67 popn!([salt], context.interpreter);
68 gas_or_fail!(context.interpreter, gas::create2_cost(len));
70 CreateScheme::Create2 { salt }
71 } else {
72 gas!(context.interpreter, gas::CREATE);
73 CreateScheme::Create
74 };
75
76 let mut gas_limit = context.interpreter.gas.remaining();
77
78 if context
80 .interpreter
81 .runtime_flag
82 .spec_id()
83 .is_enabled_in(SpecId::TANGERINE)
84 {
85 gas_limit -= gas_limit / 64
87 }
88 gas!(context.interpreter, gas_limit);
89
90 context
92 .interpreter
93 .bytecode
94 .set_action(InterpreterAction::NewFrame(FrameInput::Create(Box::new(
95 CreateInputs {
96 caller: context.interpreter.input.target_address(),
97 scheme,
98 value,
99 init_code: code,
100 gas_limit,
101 },
102 ))));
103}
104
105pub fn call<WIRE: InterpreterTypes, H: Host + ?Sized>(context: InstructionContext<'_, H, WIRE>) {
109 popn!([local_gas_limit, to, value], context.interpreter);
110 let to = to.into_address();
111 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
113
114 let has_transfer = !value.is_zero();
115 if context.interpreter.runtime_flag.is_static() && has_transfer {
116 context
117 .interpreter
118 .halt(InstructionResult::CallNotAllowedInsideStatic);
119 return;
120 }
121
122 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter)
123 else {
124 return;
125 };
126
127 let Some(account_load) = context.host.load_account_delegated(to) else {
128 context
129 .interpreter
130 .halt(InstructionResult::FatalExternalError);
131 return;
132 };
133
134 let Some(mut gas_limit) = calc_call_gas(
135 context.interpreter,
136 account_load,
137 has_transfer,
138 local_gas_limit,
139 ) else {
140 return;
141 };
142
143 gas!(context.interpreter, gas_limit);
144
145 if has_transfer {
147 gas_limit = gas_limit.saturating_add(gas::CALL_STIPEND);
148 }
149
150 context
152 .interpreter
153 .bytecode
154 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
155 CallInputs {
156 input: CallInput::SharedBuffer(input),
157 gas_limit,
158 target_address: to,
159 caller: context.interpreter.input.target_address(),
160 bytecode_address: to,
161 value: CallValue::Transfer(value),
162 scheme: CallScheme::Call,
163 is_static: context.interpreter.runtime_flag.is_static(),
164 return_memory_offset,
165 },
166 ))));
167}
168
169pub fn call_code<WIRE: InterpreterTypes, H: Host + ?Sized>(
173 context: InstructionContext<'_, H, WIRE>,
174) {
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
180 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter)
182 else {
183 return;
184 };
185
186 let Some(mut load) = context.host.load_account_delegated(to) else {
187 context
188 .interpreter
189 .halt(InstructionResult::FatalExternalError);
190 return;
191 };
192
193 load.is_empty = false;
195 let Some(mut gas_limit) =
196 calc_call_gas(context.interpreter, load, !value.is_zero(), local_gas_limit)
197 else {
198 return;
199 };
200
201 gas!(context.interpreter, gas_limit);
202
203 if !value.is_zero() {
205 gas_limit = gas_limit.saturating_add(gas::CALL_STIPEND);
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 value: CallValue::Transfer(value),
220 scheme: CallScheme::CallCode,
221 is_static: context.interpreter.runtime_flag.is_static(),
222 return_memory_offset,
223 },
224 ))));
225}
226
227pub fn delegate_call<WIRE: InterpreterTypes, H: Host + ?Sized>(
231 context: InstructionContext<'_, H, WIRE>,
232) {
233 check!(context.interpreter, HOMESTEAD);
234 popn!([local_gas_limit, to], context.interpreter);
235 let to = Address::from_word(B256::from(to));
236 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
238
239 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter)
240 else {
241 return;
242 };
243
244 let Some(mut load) = context.host.load_account_delegated(to) else {
245 context
246 .interpreter
247 .halt(InstructionResult::FatalExternalError);
248 return;
249 };
250
251 load.is_empty = false;
253 let Some(gas_limit) = calc_call_gas(context.interpreter, load, false, local_gas_limit) else {
254 return;
255 };
256
257 gas!(context.interpreter, gas_limit);
258
259 context
261 .interpreter
262 .bytecode
263 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
264 CallInputs {
265 input: CallInput::SharedBuffer(input),
266 gas_limit,
267 target_address: context.interpreter.input.target_address(),
268 caller: context.interpreter.input.caller_address(),
269 bytecode_address: to,
270 value: CallValue::Apparent(context.interpreter.input.call_value()),
271 scheme: CallScheme::DelegateCall,
272 is_static: context.interpreter.runtime_flag.is_static(),
273 return_memory_offset,
274 },
275 ))));
276}
277
278pub fn static_call<WIRE: InterpreterTypes, H: Host + ?Sized>(
282 context: InstructionContext<'_, H, WIRE>,
283) {
284 check!(context.interpreter, BYZANTIUM);
285 popn!([local_gas_limit, to], context.interpreter);
286 let to = Address::from_word(B256::from(to));
287 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
289
290 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter)
291 else {
292 return;
293 };
294
295 let Some(mut load) = context.host.load_account_delegated(to) else {
296 context
297 .interpreter
298 .halt(InstructionResult::FatalExternalError);
299 return;
300 };
301 load.is_empty = false;
303 let Some(gas_limit) = calc_call_gas(context.interpreter, load, false, local_gas_limit) else {
304 return;
305 };
306 gas!(context.interpreter, gas_limit);
307
308 context
310 .interpreter
311 .bytecode
312 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
313 CallInputs {
314 input: CallInput::SharedBuffer(input),
315 gas_limit,
316 target_address: to,
317 caller: context.interpreter.input.target_address(),
318 bytecode_address: to,
319 value: CallValue::Transfer(U256::ZERO),
320 scheme: CallScheme::StaticCall,
321 is_static: true,
322 return_memory_offset,
323 },
324 ))));
325}