1use crate::{
19 exec::ExecError,
20 gas, vec,
21 vm::{BytecodeType, ExecResult, Ext},
22 AccountIdOf, Code, CodeInfo, Config, ContractBlob, DispatchError, Error, ExecReturnValue,
23 RuntimeCosts, H256, LOG_TARGET, U256,
24};
25use alloc::{boxed::Box, vec::Vec};
26use core::cmp::min;
27use instructions::instruction_table;
28use pallet_revive_uapi::ReturnFlags;
29use revm::{
30 bytecode::Bytecode,
31 context::CreateScheme,
32 interpreter::{
33 host::DummyHost,
34 interpreter::{ExtBytecode, ReturnDataImpl, RuntimeFlags},
35 interpreter_action::InterpreterAction,
36 interpreter_types::{InputsTr, MemoryTr, ReturnData},
37 CallInput, CallInputs, CallScheme, CreateInputs, FrameInput, Gas, InstructionResult,
38 Interpreter, InterpreterResult, InterpreterTypes, SharedMemory, Stack,
39 },
40 primitives::{self, hardfork::SpecId, Address, Bytes},
41};
42use sp_core::H160;
43use sp_runtime::Weight;
44
45#[cfg(feature = "runtime-benchmarks")]
46pub mod instructions;
47#[cfg(not(feature = "runtime-benchmarks"))]
48mod instructions;
49
50pub(crate) const DIFFICULTY: u64 = 2500000000000000_u64;
57
58pub(crate) const BASE_FEE: U256 = U256::zero();
62
63impl<T: Config> ContractBlob<T> {
64 pub fn from_evm_init_code(code: Vec<u8>, owner: AccountIdOf<T>) -> Result<Self, DispatchError> {
66 if code.len() > revm::primitives::eip3860::MAX_INITCODE_SIZE {
67 return Err(<Error<T>>::BlobTooLarge.into());
68 }
69
70 if code.first() == Some(&0xEF) {
72 return Err(<Error<T>>::CodeRejected.into());
73 }
74
75 let code_len = code.len() as u32;
76 let code_info = CodeInfo {
77 owner,
78 deposit: Default::default(),
79 refcount: 0,
80 code_len,
81 code_type: BytecodeType::Evm,
82 behaviour_version: Default::default(),
83 };
84
85 Bytecode::new_raw_checked(Bytes::from(code.to_vec())).map_err(|err| {
86 log::debug!(target: LOG_TARGET, "failed to create evm bytecode from init code: {err:?}" );
87 <Error<T>>::CodeRejected
88 })?;
89
90 let code_hash = H256::default();
92 Ok(ContractBlob { code, code_info, code_hash })
93 }
94
95 pub fn from_evm_runtime_code(
97 code: Vec<u8>,
98 owner: AccountIdOf<T>,
99 ) -> Result<Self, DispatchError> {
100 if code.len() > revm::primitives::eip170::MAX_CODE_SIZE {
101 return Err(<Error<T>>::BlobTooLarge.into());
102 }
103
104 let code_len = code.len() as u32;
105 let deposit = super::calculate_code_deposit::<T>(code_len);
106
107 let code_info = CodeInfo {
108 owner,
109 deposit,
110 refcount: 0,
111 code_len,
112 code_type: BytecodeType::Evm,
113 behaviour_version: Default::default(),
114 };
115
116 Bytecode::new_raw_checked(Bytes::from(code.to_vec())).map_err(|err| {
117 log::debug!(target: LOG_TARGET, "failed to create evm bytecode from code: {err:?}" );
118 <Error<T>>::CodeRejected
119 })?;
120
121 let code_hash = H256(sp_io::hashing::keccak_256(&code));
122 Ok(ContractBlob { code, code_info, code_hash })
123 }
124}
125
126pub fn call<'a, E: Ext>(bytecode: Bytecode, ext: &'a mut E, inputs: EVMInputs) -> ExecResult {
128 let mut interpreter: Interpreter<EVMInterpreter<'a, E>> = Interpreter {
129 gas: Gas::default(),
130 bytecode: ExtBytecode::new(bytecode),
131 stack: Stack::new(),
132 return_data: Default::default(),
133 memory: SharedMemory::new(),
134 input: inputs,
135 runtime_flag: RuntimeFlags { is_static: ext.is_read_only(), spec_id: SpecId::default() },
136 extend: ext,
137 };
138
139 let table = instruction_table::<'a, E>();
140 let result = run(&mut interpreter, &table);
141
142 instruction_result_into_exec_error::<E>(result.result)
143 .map(Err)
144 .unwrap_or_else(|| {
145 Ok(ExecReturnValue {
146 flags: if result.is_revert() { ReturnFlags::REVERT } else { ReturnFlags::empty() },
147 data: result.output.to_vec(),
148 })
149 })
150}
151
152fn run<'a, E: Ext>(
154 interpreter: &mut Interpreter<EVMInterpreter<'a, E>>,
155 table: &revm::interpreter::InstructionTable<EVMInterpreter<'a, E>, DummyHost>,
156) -> InterpreterResult {
157 let host = &mut DummyHost {};
158 loop {
159 #[cfg(not(feature = "std"))]
160 let action = interpreter.run_plain(table, host);
161 #[cfg(feature = "std")]
162 let action = run_plain(interpreter, table, host);
163 match action {
164 InterpreterAction::Return(result) => {
165 log::trace!(target: LOG_TARGET, "Evm return {:?}", result);
166 debug_assert!(
167 result.gas == Default::default(),
168 "Interpreter gas state is unused; found: {:?}",
169 result.gas,
170 );
171 return result;
172 },
173 InterpreterAction::NewFrame(frame_input) => match frame_input {
174 FrameInput::Call(call_input) => run_call(interpreter, call_input),
175 FrameInput::Create(create_input) => run_create(interpreter, create_input),
176 FrameInput::Empty => unreachable!(),
177 },
178 }
179 }
180}
181
182fn run_call<'a, E: Ext>(
183 interpreter: &mut Interpreter<EVMInterpreter<'a, E>>,
184 call_input: Box<CallInputs>,
185) {
186 let callee: H160 = if call_input.scheme.is_delegate_call() {
187 call_input.bytecode_address.0 .0.into()
188 } else {
189 call_input.target_address.0 .0.into()
190 };
191
192 let input = match &call_input.input {
193 CallInput::Bytes(bytes) => bytes.to_vec(),
194 CallInput::SharedBuffer(range) => interpreter.memory.global_slice(range.clone()).to_vec(),
195 };
196 let call_result = match call_input.scheme {
197 CallScheme::Call | CallScheme::StaticCall => interpreter.extend.call(
198 Weight::from_parts(call_input.gas_limit, u64::MAX),
199 U256::MAX,
200 &callee,
201 U256::from_revm_u256(&call_input.call_value()),
202 input,
203 true,
204 call_input.is_static,
205 ),
206 CallScheme::CallCode => {
207 unreachable!()
208 },
209 CallScheme::DelegateCall => interpreter.extend.delegate_call(
210 Weight::from_parts(call_input.gas_limit, u64::MAX),
211 U256::MAX,
212 callee,
213 input,
214 ),
215 };
216
217 let (return_data, did_revert) = {
218 let return_value = interpreter.extend.last_frame_output();
219 let return_data: Bytes = return_value.data.clone().into();
220 (return_data, return_value.did_revert())
221 };
222
223 let mem_length = call_input.return_memory_offset.len();
224 let mem_start = call_input.return_memory_offset.start;
225 let returned_len = return_data.len();
226 let target_len = min(mem_length, returned_len);
227
228 interpreter.return_data.set_buffer(return_data);
229
230 match call_result {
231 Ok(()) => {
232 gas!(interpreter, RuntimeCosts::CopyToContract(target_len as u32));
234 interpreter
235 .memory
236 .set(mem_start, &interpreter.return_data.buffer()[..target_len]);
237 let _ = interpreter.stack.push(primitives::U256::from(!did_revert as u8));
238 },
239 Err(err) => {
240 let _ = interpreter.stack.push(primitives::U256::ZERO);
241 if let Some(reason) = exec_error_into_halt_reason::<E>(err) {
242 interpreter.halt(reason);
243 }
244 },
245 }
246}
247
248#[cfg(feature = "std")]
251fn run_plain<WIRE: InterpreterTypes>(
252 interpreter: &mut Interpreter<WIRE>,
253 instruction_table: &revm::interpreter::InstructionTable<WIRE, DummyHost>,
254 host: &mut DummyHost,
255) -> InterpreterAction {
256 use crate::{alloc::string::ToString, format};
257 use revm::{
258 bytecode::OpCode,
259 interpreter::{
260 instruction_context::InstructionContext,
261 interpreter_types::{Jumps, LoopControl, MemoryTr, StackTr},
262 },
263 };
264 while interpreter.bytecode.is_not_end() {
265 log::trace!(target: LOG_TARGET,
266 "[{pc}]: {opcode}, stacktop: {stacktop}, memory size: {memsize} {memory:?}",
267 pc = interpreter.bytecode.pc(),
268 opcode = OpCode::new(interpreter.bytecode.opcode())
269 .map_or("INVALID".to_string(), |x| format!("{:?}", x.info())),
270 stacktop = interpreter.stack.top().map_or("None".to_string(), |x| format!("{:#x}", x)),
271 memsize = interpreter.memory.size(),
272 memory = interpreter
274 .memory
275 .slice_len(0, core::cmp::min(32, interpreter.memory.size()))
276 .to_vec(),
277 );
278 let opcode = interpreter.bytecode.opcode();
280
281 interpreter.bytecode.relative_jump(1);
285 let context = InstructionContext { interpreter, host };
286 instruction_table[opcode as usize](context);
288 }
289 interpreter.bytecode.revert_to_previous_pointer();
290
291 interpreter.take_next_action()
292}
293
294fn run_create<'a, E: Ext>(
295 interpreter: &mut Interpreter<EVMInterpreter<'a, E>>,
296 create_input: Box<CreateInputs>,
297) {
298 let value = U256::from_revm_u256(&create_input.value);
299
300 let salt = match create_input.scheme {
301 CreateScheme::Create => None,
302 CreateScheme::Create2 { salt } => Some(salt.to_be_bytes()),
303 CreateScheme::Custom { .. } => unreachable!("custom create schemes are not supported"),
304 };
305
306 let call_result = interpreter.extend.instantiate(
307 Weight::from_parts(create_input.gas_limit, u64::MAX),
308 U256::MAX,
309 Code::Upload(create_input.init_code.to_vec()),
310 value,
311 vec![],
312 salt.as_ref(),
313 );
314
315 let return_value = interpreter.extend.last_frame_output();
316 let return_data: Bytes = return_value.data.clone().into();
317
318 match call_result {
319 Ok(address) => {
320 if return_value.did_revert() {
321 gas!(interpreter, RuntimeCosts::CopyToContract(return_data.len() as u32));
323 interpreter.return_data.set_buffer(return_data);
324 let _ = interpreter.stack.push(primitives::U256::ZERO);
325 } else {
326 interpreter.return_data.clear();
328 let stack_item: Address = address.0.into();
329 let _ = interpreter.stack.push(stack_item.into_word().into());
330 }
331 },
332 Err(err) => {
333 let _ = interpreter.stack.push(primitives::U256::ZERO);
334 if let Some(reason) = exec_error_into_halt_reason::<E>(err) {
335 interpreter.halt(reason);
336 }
337 },
338 }
339}
340
341pub struct EVMInterpreter<'a, E: Ext> {
348 _phantom: core::marker::PhantomData<&'a E>,
349}
350
351impl<'a, E: Ext> InterpreterTypes for EVMInterpreter<'a, E> {
352 type Stack = Stack;
353 type Memory = SharedMemory;
354 type Bytecode = ExtBytecode;
355 type ReturnData = ReturnDataImpl;
356 type Input = EVMInputs;
357 type RuntimeFlag = RuntimeFlags;
358 type Extend = &'a mut E;
359 type Output = InterpreterAction;
360}
361
362#[derive(Debug, Clone, Default)]
371pub struct EVMInputs(CallInput);
372
373impl EVMInputs {
374 pub fn new(input: Vec<u8>) -> Self {
375 Self(CallInput::Bytes(input.into()))
376 }
377}
378
379impl InputsTr for EVMInputs {
380 fn target_address(&self) -> Address {
381 panic!()
382 }
383
384 fn caller_address(&self) -> Address {
385 panic!()
386 }
387
388 fn bytecode_address(&self) -> Option<&Address> {
389 panic!()
390 }
391
392 fn input(&self) -> &CallInput {
393 &self.0
394 }
395
396 fn call_value(&self) -> primitives::U256 {
397 panic!()
398 }
399}
400
401fn exec_error_into_halt_reason<E: Ext>(from: ExecError) -> Option<InstructionResult> {
415 log::trace!("call frame execution error in EVM caller: {:?}", &from);
416
417 if super::exec_error_into_return_code::<E>(from).is_ok() {
418 return None;
419 }
420
421 let static_memory_too_large = Error::<E::T>::StaticMemoryTooLarge.into();
422 let code_rejected = Error::<E::T>::CodeRejected.into();
423 let transfer_failed = Error::<E::T>::TransferFailed.into();
424 let duplicate_contract = Error::<E::T>::DuplicateContract.into();
425 let balance_conversion_failed = Error::<E::T>::BalanceConversionFailed.into();
426 let value_too_large = Error::<E::T>::ValueTooLarge.into();
427 let out_of_gas = Error::<E::T>::OutOfGas.into();
428 let out_of_deposit = Error::<E::T>::StorageDepositLimitExhausted.into();
429
430 Some(match from.error {
431 err if err == static_memory_too_large => InstructionResult::MemoryLimitOOG,
432 err if err == code_rejected => InstructionResult::OpcodeNotFound,
433 err if err == transfer_failed => InstructionResult::OutOfFunds,
434 err if err == duplicate_contract => InstructionResult::CreateCollision,
435 err if err == balance_conversion_failed => InstructionResult::OverflowPayment,
436 err if err == value_too_large => InstructionResult::OverflowPayment,
437 err if err == out_of_deposit => InstructionResult::OutOfFunds,
438 err if err == out_of_gas => InstructionResult::OutOfGas,
439 _ => InstructionResult::Revert,
440 })
441}
442
443fn instruction_result_into_exec_error<E: Ext>(from: InstructionResult) -> Option<ExecError> {
447 match from {
448 InstructionResult::OutOfGas |
449 InstructionResult::InvalidOperandOOG |
450 InstructionResult::ReentrancySentryOOG |
451 InstructionResult::PrecompileOOG |
452 InstructionResult::MemoryOOG => Some(Error::<E::T>::OutOfGas),
453 InstructionResult::MemoryLimitOOG => Some(Error::<E::T>::StaticMemoryTooLarge),
454 InstructionResult::OpcodeNotFound |
455 InstructionResult::InvalidJump |
456 InstructionResult::NotActivated |
457 InstructionResult::InvalidFEOpcode |
458 InstructionResult::CreateContractStartingWithEF => Some(Error::<E::T>::InvalidInstruction),
459 InstructionResult::CallNotAllowedInsideStatic |
460 InstructionResult::StateChangeDuringStaticCall => Some(Error::<E::T>::StateChangeDenied),
461 InstructionResult::StackUnderflow |
462 InstructionResult::StackOverflow |
463 InstructionResult::NonceOverflow |
464 InstructionResult::PrecompileError |
465 InstructionResult::FatalExternalError => Some(Error::<E::T>::ContractTrapped),
466 InstructionResult::OutOfOffset => Some(Error::<E::T>::OutOfBounds),
467 InstructionResult::CreateCollision => Some(Error::<E::T>::DuplicateContract),
468 InstructionResult::OverflowPayment => Some(Error::<E::T>::BalanceConversionFailed),
469 InstructionResult::CreateContractSizeLimit | InstructionResult::CreateInitCodeSizeLimit =>
470 Some(Error::<E::T>::StaticMemoryTooLarge),
471 InstructionResult::CallTooDeep => Some(Error::<E::T>::MaxCallDepthReached),
472 InstructionResult::OutOfFunds => Some(Error::<E::T>::TransferFailed),
473 InstructionResult::CreateInitCodeStartingEF00 |
474 InstructionResult::InvalidEOFInitCode |
475 InstructionResult::InvalidExtDelegateCallTarget => Some(Error::<E::T>::ContractTrapped),
476 InstructionResult::Stop |
477 InstructionResult::Return |
478 InstructionResult::Revert |
479 InstructionResult::SelfDestruct => None,
480 }
481 .map(Into::into)
482}
483
484pub trait U256Converter {
486 fn into_revm_u256(&self) -> revm::primitives::U256;
488
489 fn from_revm_u256(value: &revm::primitives::U256) -> Self;
491}
492
493impl U256Converter for sp_core::U256 {
494 fn into_revm_u256(&self) -> revm::primitives::U256 {
495 let bytes = self.to_big_endian();
496 revm::primitives::U256::from_be_bytes(bytes)
497 }
498
499 fn from_revm_u256(value: &revm::primitives::U256) -> Self {
500 let bytes = value.to_be_bytes::<32>();
501 sp_core::U256::from_big_endian(&bytes)
502 }
503}