1use crate::{
18 debug::DebugSettings,
19 precompiles::Token,
20 vm::{evm::instructions::exec_instruction, BytecodeType, ExecResult, Ext},
21 weights::WeightInfo,
22 AccountIdOf, CodeInfo, Config, ContractBlob, DispatchError, Error, Weight, H256, LOG_TARGET,
23};
24use alloc::vec::Vec;
25use core::{convert::Infallible, ops::ControlFlow};
26use revm::{bytecode::Bytecode, primitives::Bytes};
27
28#[cfg(feature = "runtime-benchmarks")]
29pub mod instructions;
30#[cfg(not(feature = "runtime-benchmarks"))]
31mod instructions;
32
33mod interpreter;
34pub use interpreter::{Halt, Interpreter};
35
36mod ext_bytecode;
37use ext_bytecode::ExtBytecode;
38
39mod memory;
40mod stack;
41mod util;
42
43pub(crate) const DIFFICULTY: u64 = 2500000000000000_u64;
50
51#[derive(Eq, PartialEq, Debug, Clone, Copy)]
53pub struct EVMGas(pub u64);
54
55impl<T: Config> Token<T> for EVMGas {
56 fn weight(&self) -> Weight {
57 let base_cost = T::WeightInfo::evm_opcode(1).saturating_sub(T::WeightInfo::evm_opcode(0));
58 base_cost.saturating_mul(self.0)
59 }
60}
61
62impl<T: Config> ContractBlob<T> {
63 pub fn from_evm_init_code(code: Vec<u8>, owner: AccountIdOf<T>) -> Result<Self, DispatchError> {
65 if code.len() > revm::primitives::eip3860::MAX_INITCODE_SIZE &&
66 !DebugSettings::is_unlimited_contract_size_allowed::<T>()
67 {
68 return Err(<Error<T>>::BlobTooLarge.into());
69 }
70
71 if code.first() == Some(&0xEF) {
73 return Err(<Error<T>>::CodeRejected.into());
74 }
75
76 let code_len = code.len() as u32;
77 let code_info = CodeInfo {
78 owner,
79 deposit: Default::default(),
80 refcount: 0,
81 code_len,
82 code_type: BytecodeType::Evm,
83 behaviour_version: Default::default(),
84 };
85
86 Bytecode::new_raw_checked(Bytes::from(code.to_vec())).map_err(|err| {
87 log::debug!(target: LOG_TARGET, "failed to create evm bytecode from init code: {err:?}" );
88 <Error<T>>::CodeRejected
89 })?;
90
91 let code_hash = H256::default();
93 Ok(ContractBlob { code, code_info, code_hash })
94 }
95
96 pub fn from_evm_runtime_code(
98 code: Vec<u8>,
99 owner: AccountIdOf<T>,
100 ) -> Result<Self, DispatchError> {
101 if code.len() > revm::primitives::eip170::MAX_CODE_SIZE &&
102 !DebugSettings::is_unlimited_contract_size_allowed::<T>()
103 {
104 return Err(<Error<T>>::BlobTooLarge.into());
105 }
106
107 let code_len = code.len() as u32;
108 let deposit = super::calculate_code_deposit::<T>(code_len);
109
110 let code_info = CodeInfo {
111 owner,
112 deposit,
113 refcount: 0,
114 code_len,
115 code_type: BytecodeType::Evm,
116 behaviour_version: Default::default(),
117 };
118
119 Bytecode::new_raw_checked(Bytes::from(code.to_vec())).map_err(|err| {
120 log::debug!(target: LOG_TARGET, "failed to create evm bytecode from code: {err:?}" );
121 <Error<T>>::CodeRejected
122 })?;
123
124 let code_hash = H256(sp_io::hashing::keccak_256(&code));
125 Ok(ContractBlob { code, code_info, code_hash })
126 }
127}
128
129pub fn call<E: Ext>(bytecode: Bytecode, ext: &mut E, input: Vec<u8>) -> ExecResult {
131 let mut interpreter = Interpreter::new(ExtBytecode::new(bytecode), input, ext);
132 let ControlFlow::Break(halt) = run_plain(&mut interpreter);
133 halt.into()
134}
135
136fn run_plain<E: Ext>(interpreter: &mut Interpreter<E>) -> ControlFlow<Halt, Infallible> {
137 loop {
138 let opcode = interpreter.bytecode.opcode();
139 interpreter.bytecode.relative_jump(1);
140 exec_instruction(interpreter, opcode)?;
141 }
142}