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 known_bytecode: Some((bytecode_hash, bytecode)),
148 value: CallValue::Transfer(value),
149 scheme: CallScheme::Call,
150 is_static: context.interpreter.runtime_flag.is_static(),
151 return_memory_offset,
152 },
153 ))));
154}
155
156pub fn call_code<WIRE: InterpreterTypes, H: Host + ?Sized>(
160 mut context: InstructionContext<'_, H, WIRE>,
161) {
162 popn!([local_gas_limit, to, value], context.interpreter);
163 let to = Address::from_word(B256::from(to));
164 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
166 let has_transfer = !value.is_zero();
167
168 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter)
169 else {
170 return;
171 };
172
173 let Some((gas_limit, bytecode, bytecode_hash)) =
174 load_acc_and_calc_gas(&mut context, to, has_transfer, false, local_gas_limit)
175 else {
176 return;
177 };
178
179 context
181 .interpreter
182 .bytecode
183 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
184 CallInputs {
185 input: CallInput::SharedBuffer(input),
186 gas_limit,
187 target_address: context.interpreter.input.target_address(),
188 caller: context.interpreter.input.target_address(),
189 bytecode_address: to,
190 known_bytecode: Some((bytecode_hash, bytecode)),
191 value: CallValue::Transfer(value),
192 scheme: CallScheme::CallCode,
193 is_static: context.interpreter.runtime_flag.is_static(),
194 return_memory_offset,
195 },
196 ))));
197}
198
199pub fn delegate_call<WIRE: InterpreterTypes, H: Host + ?Sized>(
203 mut context: InstructionContext<'_, H, WIRE>,
204) {
205 check!(context.interpreter, HOMESTEAD);
206 popn!([local_gas_limit, to], context.interpreter);
207 let to = Address::from_word(B256::from(to));
208 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
210
211 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter)
212 else {
213 return;
214 };
215
216 let Some((gas_limit, bytecode, bytecode_hash)) =
217 load_acc_and_calc_gas(&mut context, to, false, false, local_gas_limit)
218 else {
219 return;
220 };
221
222 context
224 .interpreter
225 .bytecode
226 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
227 CallInputs {
228 input: CallInput::SharedBuffer(input),
229 gas_limit,
230 target_address: context.interpreter.input.target_address(),
231 caller: context.interpreter.input.caller_address(),
232 bytecode_address: to,
233 known_bytecode: Some((bytecode_hash, bytecode)),
234 value: CallValue::Apparent(context.interpreter.input.call_value()),
235 scheme: CallScheme::DelegateCall,
236 is_static: context.interpreter.runtime_flag.is_static(),
237 return_memory_offset,
238 },
239 ))));
240}
241
242pub fn static_call<WIRE: InterpreterTypes, H: Host + ?Sized>(
246 mut context: InstructionContext<'_, H, WIRE>,
247) {
248 check!(context.interpreter, BYZANTIUM);
249 popn!([local_gas_limit, to], context.interpreter);
250 let to = Address::from_word(B256::from(to));
251 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
253
254 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter)
255 else {
256 return;
257 };
258
259 let Some((gas_limit, bytecode, bytecode_hash)) =
260 load_acc_and_calc_gas(&mut context, to, false, false, local_gas_limit)
261 else {
262 return;
263 };
264
265 context
267 .interpreter
268 .bytecode
269 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
270 CallInputs {
271 input: CallInput::SharedBuffer(input),
272 gas_limit,
273 target_address: to,
274 caller: context.interpreter.input.target_address(),
275 bytecode_address: to,
276 known_bytecode: Some((bytecode_hash, bytecode)),
277 value: CallValue::Transfer(U256::ZERO),
278 scheme: CallScheme::StaticCall,
279 is_static: true,
280 return_memory_offset,
281 },
282 ))));
283}