use crate::{ evm::{ api::{HlEvmInner, ctx::HlContext}, spec::HlSpecId, transaction::HlTxEnv, }, node::HlNode, }; use alloy_primitives::{Address, Bytes}; use config::HlEvmConfig; use reth::{ api::FullNodeTypes, builder::{BuilderContext, components::ExecutorBuilder}, }; use reth_evm::{Database, Evm, EvmEnv}; use revm::{ Context, ExecuteEvm, InspectEvm, Inspector, context::{ BlockEnv, TxEnv, result::{EVMError, ExecutionResult, HaltReason, Output, ResultAndState, SuccessReason}, }, handler::{EthPrecompiles, PrecompileProvider, instructions::EthInstructions}, interpreter::{InterpreterResult, interpreter::EthInterpreter}, state::EvmState, }; use std::ops::{Deref, DerefMut}; mod assembler; pub mod config; mod executor; mod factory; mod patch; pub mod receipt_builder; pub use executor::apply_precompiles; /// HL EVM implementation. /// /// This is a wrapper type around the `revm` evm with optional [`Inspector`] (tracing) /// support. [`Inspector`] support is configurable at runtime because it's part of the underlying #[allow(missing_debug_implementations)] pub struct HlEvm { pub inner: HlEvmInner, I, EthInstructions>, P>, pub inspect: bool, } impl HlEvm { /// Provides a reference to the EVM context. pub const fn ctx(&self) -> &HlContext { &self.inner.0.ctx } /// Provides a mutable reference to the EVM context. pub fn ctx_mut(&mut self) -> &mut HlContext { &mut self.inner.0.ctx } } impl Deref for HlEvm { type Target = HlContext; #[inline] fn deref(&self) -> &Self::Target { self.ctx() } } impl DerefMut for HlEvm { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.ctx_mut() } } impl Evm for HlEvm where DB: Database, I: Inspector>, P: PrecompileProvider, Output = InterpreterResult>, { type DB = DB; type Tx = HlTxEnv; type Error = EVMError; type HaltReason = HaltReason; type Spec = HlSpecId; type Precompiles = P; type Inspector = I; fn chain_id(&self) -> u64 { self.cfg.chain_id } fn block(&self) -> &BlockEnv { &self.block } fn transact_raw( &mut self, tx: Self::Tx, ) -> Result, Self::Error> { if self.inspect { self.inner.inspect_tx(tx) } else { self.inner.transact(tx) } } fn transact_system_call( &mut self, _caller: Address, _contract: Address, _data: Bytes, ) -> Result, Self::Error> { // NOTE: This is used for block traces. // Per hyper-evm-sync, HyperEVM doesn't seem to call this method, so // - we just return a success result with no changes, which gives the same semantics as // HyperEVM. // - In a long term (ideally), consider implementing SystemCaller. Ok(ResultAndState::new( ExecutionResult::Success { reason: SuccessReason::Stop, gas_used: 0, gas_refunded: 0, logs: vec![], output: Output::Call(Bytes::new()), }, EvmState::default(), )) } fn finish(self) -> (Self::DB, EvmEnv) { let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.0.ctx; (journaled_state.database, EvmEnv { block_env, cfg_env }) } fn set_inspector_enabled(&mut self, enabled: bool) { self.inspect = enabled; } fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) { ( &self.inner.0.ctx.journaled_state.database, &self.inner.0.inspector, &self.inner.0.precompiles, ) } fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) { ( &mut self.inner.0.ctx.journaled_state.database, &mut self.inner.0.inspector, &mut self.inner.0.precompiles, ) } } /// A regular hl evm and executor builder. #[derive(Debug, Default, Clone, Copy)] #[non_exhaustive] pub struct HlExecutorBuilder; impl ExecutorBuilder for HlExecutorBuilder where Node: FullNodeTypes, { type EVM = HlEvmConfig; async fn build_evm(self, ctx: &BuilderContext) -> eyre::Result { Ok(HlEvmConfig::hl(ctx.chain_spec())) } }