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 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);
28
29 if IS_CREATE2 {
31 check!(context.interpreter, PETERSBURG);
32 }
33
34 popn!([value, code_offset, len], context.interpreter);
35 let len = as_usize_or_fail!(context.interpreter, len);
36
37 let mut code = Bytes::new();
38 if len != 0 {
39 if context
41 .interpreter
42 .runtime_flag
43 .spec_id()
44 .is_enabled_in(SpecId::SHANGHAI)
45 {
46 if len > context.host.max_initcode_size() {
48 context
49 .interpreter
50 .halt(InstructionResult::CreateInitCodeSizeLimit);
51 return;
52 }
53 gas!(
54 context.interpreter,
55 context.host.gas_params().initcode_cost(len)
56 );
57 }
58
59 let code_offset = as_usize_or_fail!(context.interpreter, code_offset);
60 resize_memory!(
61 context.interpreter,
62 context.host.gas_params(),
63 code_offset,
64 len
65 );
66
67 code = Bytes::copy_from_slice(
68 context
69 .interpreter
70 .memory
71 .slice_len(code_offset, len)
72 .as_ref(),
73 );
74 }
75
76 let scheme = if IS_CREATE2 {
78 popn!([salt], context.interpreter);
79 gas!(
81 context.interpreter,
82 context.host.gas_params().create2_cost(len)
83 );
84 CreateScheme::Create2 { salt }
85 } else {
86 gas!(context.interpreter, context.host.gas_params().create_cost());
87 CreateScheme::Create
88 };
89
90 let mut gas_limit = context.interpreter.gas.remaining();
91
92 if context
94 .interpreter
95 .runtime_flag
96 .spec_id()
97 .is_enabled_in(SpecId::TANGERINE)
98 {
99 gas_limit = context.host.gas_params().call_stipend_reduction(gas_limit);
101 }
102 gas!(context.interpreter, gas_limit);
103
104 context
106 .interpreter
107 .bytecode
108 .set_action(InterpreterAction::NewFrame(FrameInput::Create(Box::new(
109 CreateInputs::new(
110 context.interpreter.input.target_address(),
111 scheme,
112 value,
113 code,
114 gas_limit,
115 ),
116 ))));
117}
118
119pub fn call<WIRE: InterpreterTypes, H: Host + ?Sized>(
123 mut context: InstructionContext<'_, H, WIRE>,
124) {
125 popn!([local_gas_limit, to, value], context.interpreter);
126 let to = to.into_address();
127 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
129 let has_transfer = !value.is_zero();
130
131 if context.interpreter.runtime_flag.is_static() && has_transfer {
132 context
133 .interpreter
134 .halt(InstructionResult::CallNotAllowedInsideStatic);
135 return;
136 }
137
138 let Some((input, return_memory_offset)) =
139 get_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())
140 else {
141 return;
142 };
143
144 let Some((gas_limit, bytecode, bytecode_hash)) =
145 load_acc_and_calc_gas(&mut context, to, has_transfer, true, local_gas_limit)
146 else {
147 return;
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 known_bytecode: Some((bytecode_hash, bytecode)),
162 value: CallValue::Transfer(value),
163 scheme: CallScheme::Call,
164 is_static: context.interpreter.runtime_flag.is_static(),
165 return_memory_offset,
166 },
167 ))));
168}
169
170pub fn call_code<WIRE: InterpreterTypes, H: Host + ?Sized>(
174 mut context: InstructionContext<'_, H, WIRE>,
175) {
176 popn!([local_gas_limit, to, value], context.interpreter);
177 let to = Address::from_word(B256::from(to));
178 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
180 let has_transfer = !value.is_zero();
181
182 let Some((input, return_memory_offset)) =
183 get_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())
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)) =
227 get_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())
228 else {
229 return;
230 };
231
232 let Some((gas_limit, bytecode, bytecode_hash)) =
233 load_acc_and_calc_gas(&mut context, to, false, false, local_gas_limit)
234 else {
235 return;
236 };
237
238 context
240 .interpreter
241 .bytecode
242 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
243 CallInputs {
244 input: CallInput::SharedBuffer(input),
245 gas_limit,
246 target_address: context.interpreter.input.target_address(),
247 caller: context.interpreter.input.caller_address(),
248 bytecode_address: to,
249 known_bytecode: Some((bytecode_hash, bytecode)),
250 value: CallValue::Apparent(context.interpreter.input.call_value()),
251 scheme: CallScheme::DelegateCall,
252 is_static: context.interpreter.runtime_flag.is_static(),
253 return_memory_offset,
254 },
255 ))));
256}
257
258pub fn static_call<WIRE: InterpreterTypes, H: Host + ?Sized>(
262 mut context: InstructionContext<'_, H, WIRE>,
263) {
264 check!(context.interpreter, BYZANTIUM);
265 popn!([local_gas_limit, to], context.interpreter);
266 let to = Address::from_word(B256::from(to));
267 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
269
270 let Some((input, return_memory_offset)) =
271 get_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())
272 else {
273 return;
274 };
275
276 let Some((gas_limit, bytecode, bytecode_hash)) =
277 load_acc_and_calc_gas(&mut context, to, false, false, local_gas_limit)
278 else {
279 return;
280 };
281
282 context
284 .interpreter
285 .bytecode
286 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
287 CallInputs {
288 input: CallInput::SharedBuffer(input),
289 gas_limit,
290 target_address: to,
291 caller: context.interpreter.input.target_address(),
292 bytecode_address: to,
293 known_bytecode: Some((bytecode_hash, bytecode)),
294 value: CallValue::Transfer(U256::ZERO),
295 scheme: CallScheme::StaticCall,
296 is_static: true,
297 return_memory_offset,
298 },
299 ))));
300}