referrerpolicy=no-referrer-when-downgrade

pallet_revive/vm/
evm.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use 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
50/// Hard-coded value returned by the EVM `DIFFICULTY` opcode.
51///
52/// After Ethereum's Merge (Sept 2022), the `DIFFICULTY` opcode was redefined to return
53/// `prevrandao`, a randomness value from the beacon chain. In Substrate pallet-revive
54/// a fixed constant is returned instead for compatibility with contracts that still read this
55/// opcode. The value is aligned with the difficulty hardcoded for PVM contracts.
56pub(crate) const DIFFICULTY: u64 = 2500000000000000_u64;
57
58/// The base fee per gas used in the network as defined by EIP-1559.
59///
60/// For `pallet-revive`, this is hardcoded to 0
61pub(crate) const BASE_FEE: U256 = U256::zero();
62
63impl<T: Config> ContractBlob<T> {
64	/// Create a new contract from EVM init code.
65	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		// EIP-3541: Reject new contract code starting with the 0xEF byte
71		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		// Code hash is not relevant for init code, since it is not stored on-chain.
91		let code_hash = H256::default();
92		Ok(ContractBlob { code, code_info, code_hash })
93	}
94
95	/// Create a new contract from EVM runtime code.
96	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
126/// Calls the EVM interpreter with the provided bytecode and inputs.
127pub 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
152/// Runs the EVM interpreter
153fn 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			// success or revert
233			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/// Re-implementation of REVM run_plain function to add trace logging to our EVM interpreter loop.
249/// NB: copied directly from revm tag v82
250#[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			// printing at most the first 32 bytes of memory
273			memory = interpreter
274				.memory
275				.slice_len(0, core::cmp::min(32, interpreter.memory.size()))
276				.to_vec(),
277		);
278		// Get current opcode.
279		let opcode = interpreter.bytecode.opcode();
280
281		// SAFETY: In analysis we are doing padding of bytecode so that we are sure that last
282		// byte instruction is STOP so we are safe to just increment program_counter bcs on last
283		// instruction it will do noop and just stop execution of this contract
284		interpreter.bytecode.relative_jump(1);
285		let context = InstructionContext { interpreter, host };
286		// Execute instruction.
287		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				// Contract creation reverted — return data must be propagated
322				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				// Otherwise clear it. Note that RETURN opcode should abort.
327				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
341/// EVMInterpreter implements the `InterpreterTypes`.
342///
343/// Note:
344///
345/// Our implementation set the `InterpreterTypes::Extend` associated type, to the `Ext` trait, to
346/// reuse all the host functions that are defined by this trait
347pub 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/// EVMInputs implements the `InputsTr` trait for EVM inputs, allowing the EVM interpreter to access
363/// the call input data.
364///
365/// Note:
366///
367/// In our implementation of the instruction table, Everything except the call input data will be
368/// accessed through the `InterpreterTypes::Extend` associated type, our implementation will panic
369/// if any of those methods are called.
370#[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
401/// Conversion of a `ExecError` to `ReturnErrorCode`.
402///
403/// Used when converting the error returned from a subcall in order to map it to the
404/// equivalent EVM interpreter [InstructionResult].
405///
406/// - Returns `None` when the caller can recover the error.
407/// - Otherwise, some [InstructionResult] error code (the halt reason) is returned. Most [ExecError]
408///   variants don't map to a [InstructionResult]. The conversion is lossy and defaults to
409///   [InstructionResult::Revert] for most cases.
410///
411/// Uses the overarching [super::exec_error_into_return_code] method to determine if
412/// the error is recoverable or not. This guarantees consistent behavior accross both
413/// VM backends.
414fn 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
443/// Map [InstructionResult] into an [ExecError] for passing it up the stack.
444///
445/// Returns `None` if the instruction result is not an error case.
446fn 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
484/// Blanket conversion trait between `sp_core::U256` and `revm::primitives::U256`
485pub trait U256Converter {
486	/// Convert `self` into `revm::primitives::U256`
487	fn into_revm_u256(&self) -> revm::primitives::U256;
488
489	/// Convert from `revm::primitives::U256` into `Self`
490	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}