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