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::{
12 InputsTr, InterpreterTypes as ITy, LoopControl, MemoryTr, ReturnData, RuntimeFlag, StackTr,
13 },
14 CallInput, CallInputs, CallScheme, CallValue, CreateInputs, Host,
15 InstructionExecResult as Result, InstructionResult, InterpreterAction,
16};
17use context_interface::CreateScheme;
18use primitives::{hardfork::SpecId, Bytes, U256};
19use std::boxed::Box;
20
21use crate::InstructionContext as Ictx;
22
23pub fn create<const IS_CREATE2: bool, IT: ITy, H: Host + ?Sized>(
27 context: Ictx<'_, H, IT>,
28) -> Result {
29 require_non_staticcall!(context.interpreter);
33
34 if IS_CREATE2 {
36 check!(context.interpreter, PETERSBURG);
37 }
38
39 popn!([value, code_offset, len], context.interpreter);
40 let len = as_usize_or_fail!(context.interpreter, len);
41
42 let mut code = Bytes::new();
43 if len != 0 {
44 if context
46 .interpreter
47 .runtime_flag
48 .spec_id()
49 .is_enabled_in(SpecId::SHANGHAI)
50 {
51 if len > context.host.max_initcode_size() {
53 return Err(InstructionResult::CreateInitCodeSizeLimit);
54 }
55 gas!(
56 context.interpreter,
57 context.host.gas_params().initcode_cost(len)
58 );
59 }
60
61 let code_offset = as_usize_or_fail!(context.interpreter, code_offset);
62 context
63 .interpreter
64 .resize_memory(context.host.gas_params(), code_offset, len)?;
65
66 code = Bytes::copy_from_slice(
67 context
68 .interpreter
69 .memory
70 .slice_len(code_offset, len)
71 .as_ref(),
72 );
73 }
74
75 let scheme = if IS_CREATE2 {
77 popn!([salt], context.interpreter);
78 gas!(
80 context.interpreter,
81 context.host.gas_params().create2_cost(len)
82 );
83 CreateScheme::Create2 { salt }
84 } else {
85 gas!(context.interpreter, context.host.gas_params().create_cost());
86 CreateScheme::Create
87 };
88
89 let mut create_inputs = CreateInputs::new(
92 context.interpreter.input.target_address(),
93 scheme,
94 value,
95 code,
96 0,
97 0,
98 );
99
100 if context.host.is_amsterdam_eip8037_enabled() {
102 let caller = create_inputs.caller();
109 let caller_info = context
110 .host
111 .load_account_info_skip_cold_load(caller, false, false)?;
112 let caller_balance = caller_info.account.balance;
113 let caller_nonce = caller_info.account.nonce;
114 if caller_balance < value || caller_nonce == u64::MAX {
115 context.interpreter.return_data.clear();
116 push!(context.interpreter, U256::ZERO);
117 return Ok(());
118 }
119
120 let created_address = create_inputs.created_address(caller_nonce);
124 let destination_alive = !context
125 .host
126 .load_account_info_skip_cold_load(created_address, false, false)?
127 .is_empty;
128 if !destination_alive {
129 state_gas!(
130 context.interpreter,
131 context.host.gas_params().create_state_gas()
132 );
133 create_inputs.set_charged_create_state_gas(true);
134 }
135 }
136
137 let mut gas_limit = context.interpreter.gas.remaining();
138
139 if context
141 .interpreter
142 .runtime_flag
143 .spec_id()
144 .is_enabled_in(SpecId::TANGERINE)
145 {
146 gas_limit = context.host.gas_params().call_stipend_reduction(gas_limit);
148 }
149 gas!(context.interpreter, gas_limit);
150
151 create_inputs.set_gas_limit(gas_limit);
152 create_inputs.set_reservoir(context.interpreter.gas.reservoir());
153 context
154 .interpreter
155 .bytecode
156 .set_action(InterpreterAction::NewFrame(FrameInput::Create(Box::new(
157 create_inputs,
158 ))));
159 Err(InstructionResult::Suspend)
160}
161
162pub fn call<const KIND: u8, IT: ITy, H: Host + ?Sized>(mut context: Ictx<'_, H, IT>) -> Result {
164 use bytecode::opcode::{CALL, CALLCODE, DELEGATECALL, STATICCALL};
165
166 if !matches!(KIND, CALL | CALLCODE | DELEGATECALL | STATICCALL) {
167 unreachable!("invalid call kind")
168 }
169
170 if KIND == DELEGATECALL {
171 check!(context.interpreter, HOMESTEAD);
172 } else if KIND == STATICCALL {
173 check!(context.interpreter, BYZANTIUM);
174 }
175
176 let (local_gas_limit, to, value) = if matches!(KIND, CALL | CALLCODE) {
177 popn!([local_gas_limit, to, value], context.interpreter);
178 (local_gas_limit, to, value)
179 } else {
180 popn!([local_gas_limit, to], context.interpreter);
181 (local_gas_limit, to, U256::ZERO)
182 };
183 let to = to.into_address();
184 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
186 let has_transfer = !value.is_zero();
187
188 if KIND == CALL && context.interpreter.runtime_flag.is_static() && has_transfer {
189 return Err(InstructionResult::CallNotAllowedInsideStatic);
190 }
191
192 let (input, return_memory_offset) =
193 get_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())?;
194
195 let is_call = KIND == CALL;
196 let (gas_limit, bytecode, bytecode_hash, charged_new_account_state_gas) =
197 load_acc_and_calc_gas(&mut context, to, has_transfer, is_call, local_gas_limit)?;
198
199 let target_address = if matches!(KIND, CALLCODE | DELEGATECALL) {
200 context.interpreter.input.target_address()
201 } else {
202 to
203 };
204 let caller = if KIND == DELEGATECALL {
205 context.interpreter.input.caller_address()
206 } else {
207 context.interpreter.input.target_address()
208 };
209 let value = if KIND == DELEGATECALL {
210 CallValue::Apparent(context.interpreter.input.call_value())
211 } else {
212 CallValue::Transfer(value)
213 };
214 let scheme = match KIND {
215 CALL => CallScheme::Call,
216 CALLCODE => CallScheme::CallCode,
217 DELEGATECALL => CallScheme::DelegateCall,
218 STATICCALL => CallScheme::StaticCall,
219 _ => unreachable!(),
220 };
221 let is_static = context.interpreter.runtime_flag.is_static() || KIND == STATICCALL;
222
223 context
225 .interpreter
226 .bytecode
227 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
228 CallInputs {
229 input: CallInput::SharedBuffer(input),
230 gas_limit,
231 target_address,
232 caller,
233 bytecode_address: to,
234 known_bytecode: (bytecode_hash, bytecode),
235 value,
236 scheme,
237 is_static,
238 return_memory_offset,
239 reservoir: context.interpreter.gas.reservoir(),
240 charged_new_account_state_gas,
241 },
242 ))));
243 Err(InstructionResult::Suspend)
244}