use crate::{ evm::{ api::{ctx::HlContext, HlEvmInner}, spec::HlSpecId, transaction::HlTxEnv, }, node::HlNode, }; use alloy_primitives::{Address, Bytes}; use config::HlEvmConfig; use reth::{ api::FullNodeTypes, builder::{components::ExecutorBuilder, BuilderContext}, }; use reth_evm::{Evm, EvmEnv}; use revm::{ context::{ result::{EVMError, ExecutionResult, HaltReason, Output, ResultAndState, SuccessReason}, BlockEnv, TxEnv, }, handler::{instructions::EthInstructions, EthPrecompiles, PrecompileProvider}, interpreter::{interpreter::EthInterpreter, InterpreterResult}, state::EvmState, Context, Database, ExecuteEvm, InspectEvm, Inspector, }; use std::ops::{Deref, DerefMut}; mod assembler; pub mod config; mod executor; mod factory; mod patch; pub mod receipt_builder; /// 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>, ::Error: std::marker::Send + std::marker::Sync + 'static, { 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: (HACK) Per hyper-evm-sync, HyperEVM doesn't seem to call this method, so we just return a success result with no changes // This is used for block traces. In a long term, 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 db_mut(&mut self) -> &mut Self::DB { &mut self.journaled_state.database } 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 precompiles_mut(&mut self) -> &mut Self::Precompiles { &mut self.inner.0.precompiles } fn inspector_mut(&mut self) -> &mut Self::Inspector { &mut self.inner.0.inspector } fn precompiles(&self) -> &Self::Precompiles { &self.inner.0.precompiles } fn inspector(&self) -> &Self::Inspector { &self.inner.0.inspector } } /// 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 { let evm_config = HlEvmConfig::hl(ctx.chain_spec()); Ok(evm_config) } }