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, new_account_cost, 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!(context.interpreter, gas::initcode_cost(len));
55 }
56
57 let code_offset = as_usize_or_fail!(context.interpreter, code_offset);
58 resize_memory!(context.interpreter, code_offset, len);
59 code = Bytes::copy_from_slice(
60 context
61 .interpreter
62 .memory
63 .slice_len(code_offset, len)
64 .as_ref(),
65 );
66 }
67
68 let scheme = if IS_CREATE2 {
70 popn!([salt], context.interpreter);
71 gas_or_fail!(context.interpreter, gas::create2_cost(len));
73 CreateScheme::Create2 { salt }
74 } else {
75 gas!(context.interpreter, gas::CREATE);
76 CreateScheme::Create
77 };
78
79 let mut gas_limit = context.interpreter.gas.remaining();
80
81 if context
83 .interpreter
84 .runtime_flag
85 .spec_id()
86 .is_enabled_in(SpecId::TANGERINE)
87 {
88 gas_limit -= gas_limit / 64
90 }
91 gas!(context.interpreter, gas_limit);
92
93 context
95 .interpreter
96 .bytecode
97 .set_action(InterpreterAction::NewFrame(FrameInput::Create(Box::new(
98 CreateInputs {
99 caller: context.interpreter.input.target_address(),
100 scheme,
101 value,
102 init_code: code,
103 gas_limit,
104 },
105 ))));
106}
107
108pub fn call<WIRE: InterpreterTypes, H: Host + ?Sized>(
112 mut context: InstructionContext<'_, H, WIRE>,
113) {
114 popn!([local_gas_limit, to, value], context.interpreter);
115 let to = to.into_address();
116 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
118 let has_transfer = !value.is_zero();
119
120 if context.interpreter.runtime_flag.is_static() && has_transfer {
121 context
122 .interpreter
123 .halt(InstructionResult::CallNotAllowedInsideStatic);
124 return;
125 }
126 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter)
127 else {
128 return;
129 };
130 let Some((gas_limit, bytecode, bytecode_hash)) =
131 load_acc_and_calc_gas(&mut context, to, has_transfer, true, local_gas_limit)
132 else {
133 return;
134 };
135
136 context
138 .interpreter
139 .bytecode
140 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
141 CallInputs {
142 input: CallInput::SharedBuffer(input),
143 gas_limit,
144 target_address: to,
145 caller: context.interpreter.input.target_address(),
146 bytecode_address: to,
147 bytecode,
148 bytecode_hash,
149 value: CallValue::Transfer(value),
150 scheme: CallScheme::Call,
151 is_static: context.interpreter.runtime_flag.is_static(),
152 return_memory_offset,
153 },
154 ))));
155}
156
157pub fn call_code<WIRE: InterpreterTypes, H: Host + ?Sized>(
161 mut context: InstructionContext<'_, H, WIRE>,
162) {
163 popn!([local_gas_limit, to, value], context.interpreter);
164 let to = Address::from_word(B256::from(to));
165 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
167 let has_transfer = !value.is_zero();
168
169 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter)
170 else {
171 return;
172 };
173
174 let Some((gas_limit, bytecode, bytecode_hash)) =
175 load_acc_and_calc_gas(&mut context, to, has_transfer, false, local_gas_limit)
176 else {
177 return;
178 };
179
180 context
182 .interpreter
183 .bytecode
184 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
185 CallInputs {
186 input: CallInput::SharedBuffer(input),
187 gas_limit,
188 target_address: context.interpreter.input.target_address(),
189 caller: context.interpreter.input.target_address(),
190 bytecode_address: to,
191 bytecode,
192 bytecode_hash,
193 value: CallValue::Transfer(value),
194 scheme: CallScheme::CallCode,
195 is_static: context.interpreter.runtime_flag.is_static(),
196 return_memory_offset,
197 },
198 ))));
199}
200
201pub fn delegate_call<WIRE: InterpreterTypes, H: Host + ?Sized>(
205 mut context: InstructionContext<'_, H, WIRE>,
206) {
207 check!(context.interpreter, HOMESTEAD);
208 popn!([local_gas_limit, to], context.interpreter);
209 let to = Address::from_word(B256::from(to));
210 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
212
213 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter)
214 else {
215 return;
216 };
217
218 let Some((gas_limit, bytecode, bytecode_hash)) =
219 load_acc_and_calc_gas(&mut context, to, false, false, local_gas_limit)
220 else {
221 return;
222 };
223
224 context
226 .interpreter
227 .bytecode
228 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
229 CallInputs {
230 input: CallInput::SharedBuffer(input),
231 gas_limit,
232 target_address: context.interpreter.input.target_address(),
233 caller: context.interpreter.input.caller_address(),
234 bytecode_address: to,
235 bytecode,
236 bytecode_hash,
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 },
242 ))));
243}
244
245pub fn static_call<WIRE: InterpreterTypes, H: Host + ?Sized>(
249 mut context: InstructionContext<'_, H, WIRE>,
250) {
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 Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter)
258 else {
259 return;
260 };
261
262 let Some((gas_limit, bytecode, bytecode_hash)) =
263 load_acc_and_calc_gas(&mut context, to, false, false, local_gas_limit)
264 else {
265 return;
266 };
267
268 context
270 .interpreter
271 .bytecode
272 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
273 CallInputs {
274 input: CallInput::SharedBuffer(input),
275 gas_limit,
276 target_address: to,
277 caller: context.interpreter.input.target_address(),
278 bytecode_address: to,
279 bytecode,
280 bytecode_hash,
281 value: CallValue::Transfer(U256::ZERO),
282 scheme: CallScheme::StaticCall,
283 is_static: true,
284 return_memory_offset,
285 },
286 ))));
287}