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, 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 if context.host.is_amsterdam_eip8037_enabled() {
93 state_gas!(
94 context.interpreter,
95 context.host.gas_params().create_state_gas()
96 );
97 }
98
99 let mut gas_limit = context.interpreter.gas.remaining();
100
101 if context
103 .interpreter
104 .runtime_flag
105 .spec_id()
106 .is_enabled_in(SpecId::TANGERINE)
107 {
108 gas_limit = context.host.gas_params().call_stipend_reduction(gas_limit);
110 }
111 gas!(context.interpreter, gas_limit);
112
113 let create_inputs = CreateInputs::new(
115 context.interpreter.input.target_address(),
116 scheme,
117 value,
118 code,
119 gas_limit,
120 context.interpreter.gas.reservoir(),
121 );
122 context
123 .interpreter
124 .bytecode
125 .set_action(InterpreterAction::NewFrame(FrameInput::Create(Box::new(
126 create_inputs,
127 ))));
128 Err(InstructionResult::Suspend)
129}
130
131pub fn call<const KIND: u8, IT: ITy, H: Host + ?Sized>(mut context: Ictx<'_, H, IT>) -> Result {
133 use bytecode::opcode::{CALL, CALLCODE, DELEGATECALL, STATICCALL};
134
135 if !matches!(KIND, CALL | CALLCODE | DELEGATECALL | STATICCALL) {
136 unreachable!("invalid call kind")
137 }
138
139 if KIND == DELEGATECALL {
140 check!(context.interpreter, HOMESTEAD);
141 } else if KIND == STATICCALL {
142 check!(context.interpreter, BYZANTIUM);
143 }
144
145 let (local_gas_limit, to, value) = if matches!(KIND, CALL | CALLCODE) {
146 popn!([local_gas_limit, to, value], context.interpreter);
147 (local_gas_limit, to, value)
148 } else {
149 popn!([local_gas_limit, to], context.interpreter);
150 (local_gas_limit, to, U256::ZERO)
151 };
152 let to = to.into_address();
153 let local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
155 let has_transfer = !value.is_zero();
156
157 if KIND == CALL && context.interpreter.runtime_flag.is_static() && has_transfer {
158 return Err(InstructionResult::CallNotAllowedInsideStatic);
159 }
160
161 let (input, return_memory_offset) =
162 get_memory_input_and_out_ranges(context.interpreter, context.host.gas_params())?;
163
164 let is_call = KIND == CALL;
165 let (gas_limit, bytecode, bytecode_hash, charged_new_account_state_gas) =
166 load_acc_and_calc_gas(&mut context, to, has_transfer, is_call, local_gas_limit)?;
167
168 let target_address = if matches!(KIND, CALLCODE | DELEGATECALL) {
169 context.interpreter.input.target_address()
170 } else {
171 to
172 };
173 let caller = if KIND == DELEGATECALL {
174 context.interpreter.input.caller_address()
175 } else {
176 context.interpreter.input.target_address()
177 };
178 let value = if KIND == DELEGATECALL {
179 CallValue::Apparent(context.interpreter.input.call_value())
180 } else {
181 CallValue::Transfer(value)
182 };
183 let scheme = match KIND {
184 CALL => CallScheme::Call,
185 CALLCODE => CallScheme::CallCode,
186 DELEGATECALL => CallScheme::DelegateCall,
187 STATICCALL => CallScheme::StaticCall,
188 _ => unreachable!(),
189 };
190 let is_static = context.interpreter.runtime_flag.is_static() || KIND == STATICCALL;
191
192 context
194 .interpreter
195 .bytecode
196 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(
197 CallInputs {
198 input: CallInput::SharedBuffer(input),
199 gas_limit,
200 target_address,
201 caller,
202 bytecode_address: to,
203 known_bytecode: (bytecode_hash, bytecode),
204 value,
205 scheme,
206 is_static,
207 return_memory_offset,
208 reservoir: context.interpreter.gas.reservoir(),
209 charged_new_account_state_gas,
210 },
211 ))));
212 Err(InstructionResult::Suspend)
213}