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::{constants::CALL_STACK_LIMIT, 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
115 || caller_nonce == u64::MAX
116 || context.interpreter.input.depth() + 1 > CALL_STACK_LIMIT as usize
117 {
118 context.interpreter.return_data.clear();
119 push!(context.interpreter, U256::ZERO);
120 return Ok(());
121 }
122
123 let created_address = create_inputs.created_address(caller_nonce);
127 let destination_alive = !context
128 .host
129 .load_account_info_skip_cold_load(created_address, false, false)?
130 .is_empty;
131 if !destination_alive {
132 state_gas!(
133 context.interpreter,
134 context.host.gas_params().create_state_gas()
135 );
136 create_inputs.set_charged_create_state_gas(true);
137 }
138 }
139
140 let mut gas_limit = context.interpreter.gas.remaining();
141
142 if context
144 .interpreter
145 .runtime_flag
146 .spec_id()
147 .is_enabled_in(SpecId::TANGERINE)
148 {
149 gas_limit = context.host.gas_params().call_stipend_reduction(gas_limit);
151 }
152 gas!(context.interpreter, gas_limit);
153
154 create_inputs.set_gas_limit(gas_limit);
155 create_inputs.set_reservoir(context.interpreter.gas.reservoir());
156 context
157 .interpreter
158 .bytecode
159 .set_action(InterpreterAction::NewFrame(FrameInput::Create(Box::new(
160 create_inputs,
161 ))));
162 Err(InstructionResult::Suspend)
163}
164
165pub fn call<const KIND: u8, IT: ITy, H: Host + ?Sized>(mut context: Ictx<'_, H, IT>) -> Result {
167 use bytecode::opcode::{CALL, CALLCODE, DELEGATECALL, STATICCALL};
168
169 if !matches!(KIND, CALL | CALLCODE | DELEGATECALL | STATICCALL) {
170 unreachable!("invalid call kind")
171 }
172
173 if KIND == DELEGATECALL {
174 check!(context.interpreter, HOMESTEAD);
175 } else if KIND == STATICCALL {
176 check!(context.interpreter, BYZANTIUM);
177 }
178
179 let (local_gas_limit, to, value) = if matches!(KIND, CALL | CALLCODE) {
180 popn!([local_gas_limit, to, value], context.interpreter);
181 (local_gas_limit, to, value)
182 } else {
183 popn!([local_gas_limit, to], context.interpreter);
184 (local_gas_limit, to, U256::ZERO)
185 };
186 let to = to.into_address();
187 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
189 let has_transfer = !value.is_zero();
190
191 if KIND == CALL && context.interpreter.runtime_flag.is_static() && has_transfer {
192 return Err(InstructionResult::CallNotAllowedInsideStatic);
193 }
194
195 let (input, return_memory_offset) =
196 get_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())?;
197
198 let is_call = KIND == CALL;
199 let (gas_limit, bytecode, bytecode_hash, charged_new_account_state_gas) =
200 load_acc_and_calc_gas(&mut context, to, has_transfer, is_call, local_gas_limit)?;
201
202 let target_address = if matches!(KIND, CALLCODE | DELEGATECALL) {
203 context.interpreter.input.target_address()
204 } else {
205 to
206 };
207 let caller = if KIND == DELEGATECALL {
208 context.interpreter.input.caller_address()
209 } else {
210 context.interpreter.input.target_address()
211 };
212 let value = if KIND == DELEGATECALL {
213 CallValue::Apparent(context.interpreter.input.call_value())
214 } else {
215 CallValue::Transfer(value)
216 };
217 let scheme = match KIND {
218 CALL => CallScheme::Call,
219 CALLCODE => CallScheme::CallCode,
220 DELEGATECALL => CallScheme::DelegateCall,
221 STATICCALL => CallScheme::StaticCall,
222 _ => unreachable!(),
223 };
224 let is_static = context.interpreter.runtime_flag.is_static() || KIND == STATICCALL;
225
226 context
228 .interpreter
229 .bytecode
230 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
231 CallInputs {
232 input: CallInput::SharedBuffer(input),
233 gas_limit,
234 target_address,
235 caller,
236 bytecode_address: to,
237 known_bytecode: (bytecode_hash, bytecode),
238 value,
239 scheme,
240 is_static,
241 return_memory_offset,
242 reservoir: context.interpreter.gas.reservoir(),
243 charged_new_account_state_gas,
244 },
245 ))));
246 Err(InstructionResult::Suspend)
247}
248
249#[cfg(test)]
250mod tests {
251 use crate::{
252 host::DummyHost,
253 instructions::{gas_table, instruction_table},
254 interpreter::{EthInterpreter, ExtBytecode, InputsImpl, SharedMemory},
255 Interpreter, InterpreterAction,
256 };
257 use bytecode::opcode::*;
258 use bytecode::Bytecode;
259 use primitives::{constants::CALL_STACK_LIMIT, hardfork::SpecId, Bytes, U256};
260
261 #[test]
262 fn create_too_deep_pushes_zero_without_destination_access_eip8037() {
263 let bytecode =
267 Bytecode::new_raw(Bytes::copy_from_slice(&[PUSH0, PUSH0, PUSH0, CREATE, STOP]));
268 let mut interpreter = Interpreter::<EthInterpreter>::new(
269 SharedMemory::new(),
270 ExtBytecode::new(bytecode),
271 InputsImpl {
272 depth: CALL_STACK_LIMIT as usize,
273 ..Default::default()
274 },
275 false,
276 SpecId::AMSTERDAM,
277 1_000_000,
278 );
279 let table = instruction_table::<EthInterpreter, DummyHost>();
280 let gas = gas_table();
281 let mut host = DummyHost::new(SpecId::AMSTERDAM);
282 let action = interpreter.run_plain(&table, &gas, &mut host);
283 assert!(!matches!(action, InterpreterAction::NewFrame(_)));
284 assert_eq!(interpreter.stack.len(), 1);
285 assert_eq!(interpreter.stack.data()[0], U256::ZERO);
286 }
287}