pallet_revive/vm/evm/instructions/
contract.rs1mod call_helpers;
19
20use super::{utility::IntoAddress, Context};
21use crate::{
22 vm::{evm::U256Converter, Ext, RuntimeCosts},
23 Pallet,
24};
25use alloc::boxed::Box;
26pub use call_helpers::{calc_call_gas, get_memory_input_and_out_ranges};
27use revm::{
28 context_interface::CreateScheme,
29 interpreter::{
30 gas as revm_gas,
31 interpreter_action::{
32 CallInputs, CallScheme, CallValue, CreateInputs, FrameInput, InterpreterAction,
33 },
34 interpreter_types::{LoopControl, RuntimeFlag, StackTr},
35 CallInput, InstructionResult,
36 },
37 primitives::{Address, Bytes, B256, U256},
38};
39
40pub fn create<'ext, const IS_CREATE2: bool, E: Ext>(context: Context<'_, 'ext, E>) {
44 require_non_staticcall!(context.interpreter);
45
46 popn!([value, code_offset, len], context.interpreter);
47 let len = as_usize_or_fail!(context.interpreter, len);
48
49 let val = crate::U256::from_revm_u256(&value);
53 gas!(
54 context.interpreter,
55 RuntimeCosts::Instantiate {
56 input_data_len: len as u32, balance_transfer: Pallet::<E::T>::has_balance(val),
58 dust_transfer: Pallet::<E::T>::has_dust(val),
59 }
60 );
61
62 let mut code = Bytes::new();
63 if len != 0 {
64 if len > revm::primitives::eip3860::MAX_INITCODE_SIZE {
66 context.interpreter.halt(InstructionResult::CreateInitCodeSizeLimit);
67 return;
68 }
69
70 let code_offset = as_usize_or_fail!(context.interpreter, code_offset);
71 resize_memory!(context.interpreter, code_offset, len);
72 code =
73 Bytes::copy_from_slice(context.interpreter.memory.slice_len(code_offset, len).as_ref());
74 }
75
76 let scheme = if IS_CREATE2 {
78 popn!([salt], context.interpreter);
79 CreateScheme::Create2 { salt }
80 } else {
81 gas_legacy!(context.interpreter, revm_gas::CREATE);
82 CreateScheme::Create
83 };
84
85 context
87 .interpreter
88 .bytecode
89 .set_action(InterpreterAction::NewFrame(FrameInput::Create(Box::new(CreateInputs {
90 caller: context.interpreter.extend.address().0.into(),
91 scheme,
92 value,
93 init_code: code,
94 gas_limit: u64::MAX, }))));
96}
97
98pub fn call<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
102 popn!([local_gas_limit, to, value], context.interpreter);
103 let to = to.into_address();
104 let _local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
107
108 let has_transfer = !value.is_zero();
109 if context.interpreter.runtime_flag.is_static() && has_transfer {
110 context.interpreter.halt(InstructionResult::CallNotAllowedInsideStatic);
111 return;
112 }
113
114 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter)
115 else {
116 return;
117 };
118
119 let scheme = CallScheme::Call;
120 let input = CallInput::SharedBuffer(input);
121
122 let Some(gas_limit) = calc_call_gas(context.interpreter, to, scheme, input.len(), value) else {
123 return;
124 };
125
126 context
128 .interpreter
129 .bytecode
130 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs {
131 input,
132 gas_limit,
133 target_address: to,
134 caller: Address::default(),
135 bytecode_address: to,
136 value: CallValue::Transfer(value),
137 scheme,
138 is_static: context.interpreter.runtime_flag.is_static(),
139 return_memory_offset,
140 }))));
141}
142
143pub fn call_code<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
150 context.interpreter.halt(revm::interpreter::InstructionResult::NotActivated);
151}
152
153pub fn delegate_call<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
157 popn!([local_gas_limit, to], context.interpreter);
158 let to = Address::from_word(B256::from(to));
159 let _local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
162
163 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter)
164 else {
165 return;
166 };
167
168 let scheme = CallScheme::DelegateCall;
169 let input = CallInput::SharedBuffer(input);
170
171 let Some(gas_limit) = calc_call_gas(context.interpreter, to, scheme, input.len(), U256::ZERO)
172 else {
173 return;
174 };
175
176 context
178 .interpreter
179 .bytecode
180 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs {
181 input,
182 gas_limit,
183 target_address: Default::default(),
184 caller: Default::default(),
185 bytecode_address: to,
186 value: CallValue::Apparent(Default::default()),
187 scheme,
188 is_static: context.interpreter.runtime_flag.is_static(),
189 return_memory_offset,
190 }))));
191}
192
193pub fn static_call<'ext, E: Ext>(context: Context<'_, 'ext, E>) {
197 popn!([local_gas_limit, to], context.interpreter);
198 let to = Address::from_word(B256::from(to));
199 let _local_gas_limit = u64::try_from(local_gas_limit).unwrap_or(u64::MAX);
202
203 let Some((input, return_memory_offset)) = get_memory_input_and_out_ranges(context.interpreter)
204 else {
205 return;
206 };
207
208 let scheme = CallScheme::StaticCall;
209 let input = CallInput::SharedBuffer(input);
210
211 let Some(gas_limit) = calc_call_gas(context.interpreter, to, scheme, input.len(), U256::ZERO)
212 else {
213 return;
214 };
215
216 context
218 .interpreter
219 .bytecode
220 .set_action(InterpreterAction::NewFrame(FrameInput::Call(Box::new(CallInputs {
221 input,
222 gas_limit,
223 target_address: to,
224 caller: Default::default(),
225 bytecode_address: to,
226 value: CallValue::Transfer(U256::ZERO),
227 scheme,
228 is_static: true,
229 return_memory_offset,
230 }))));
231}