ethrex-vm 30.0.0

EVM execution backend and database abstraction for the ethrex Ethereum execution client
Documentation
use crate::backends::levm::LEVM;
use ethrex_common::H256;
use ethrex_common::tracing::{CallTrace, OpcodeTraceResult, PrestateResult};
use ethrex_common::types::{Block, BlockHeader, GenericTransaction};
pub use ethrex_levm::tracing::OpcodeTracerConfig;

use crate::{Evm, EvmError};

impl Evm {
    /// Runs a single tx with the call tracer and outputs its trace.
    /// Assumes that the received state already contains changes from previous blocks and other
    /// transactions within its block.
    /// Wraps LEVM::trace_tx_calls depending on the feature.
    pub fn trace_tx_calls(
        &mut self,
        block: &Block,
        tx_index: usize,
        only_top_call: bool,
        with_log: bool,
        log_index_base: u64,
    ) -> Result<CallTrace, EvmError> {
        let tx = block
            .body
            .transactions
            .get(tx_index)
            .ok_or(EvmError::Custom(
                "Missing Transaction for Trace".to_string(),
            ))?;

        LEVM::trace_tx_calls(
            &mut self.db,
            &block.header,
            tx,
            only_top_call,
            with_log,
            log_index_base,
            self.vm_type,
            self.crypto.as_ref(),
            self.stateless_validator.as_deref(),
        )
    }

    /// Executes a single tx and captures the pre/post account state (prestateTracer).
    /// Assumes that the received state already contains changes from previous transactions.
    pub fn trace_tx_prestate(
        &mut self,
        block: &Block,
        tx_index: usize,
        diff_mode: bool,
        include_empty: bool,
    ) -> Result<PrestateResult, EvmError> {
        let tx = block
            .body
            .transactions
            .get(tx_index)
            .ok_or(EvmError::Custom(
                "Missing Transaction for Trace".to_string(),
            ))?;

        LEVM::trace_tx_prestate(
            &mut self.db,
            &block.header,
            tx,
            diff_mode,
            include_empty,
            self.vm_type,
            self.crypto.as_ref(),
        )
    }

    /// Executes a single tx and captures the per-opcode (EIP-3155) trace.
    /// Assumes that the received state already contains changes from previous transactions.
    pub fn trace_tx_opcodes(
        &mut self,
        block: &Block,
        tx_index: usize,
        cfg: OpcodeTracerConfig,
    ) -> Result<OpcodeTraceResult, EvmError> {
        let tx = block
            .body
            .transactions
            .get(tx_index)
            .ok_or(EvmError::Custom(
                "Missing Transaction for Trace".to_string(),
            ))?;

        LEVM::trace_tx_opcodes(
            &mut self.db,
            &block.header,
            tx,
            cfg,
            self.vm_type,
            self.crypto.as_ref(),
        )
    }

    /// Traces a synthetic `eth_call`-shaped request with the callTracer (`debug_traceCall`).
    /// Assumes `db` already reflects the target block/tx state to call against.
    pub fn trace_call_calls(
        &mut self,
        block_header: &BlockHeader,
        tx: &GenericTransaction,
        only_top_call: bool,
        with_log: bool,
        log_index_base: u64,
    ) -> Result<CallTrace, EvmError> {
        LEVM::trace_call_calls(
            &mut self.db,
            block_header,
            tx,
            only_top_call,
            with_log,
            log_index_base,
            self.vm_type,
            self.crypto.as_ref(),
        )
    }

    /// Traces a synthetic `eth_call`-shaped request with the prestateTracer (`debug_traceCall`).
    pub fn trace_call_prestate(
        &mut self,
        block_header: &BlockHeader,
        tx: &GenericTransaction,
        diff_mode: bool,
        include_empty: bool,
    ) -> Result<PrestateResult, EvmError> {
        LEVM::trace_call_prestate(
            &mut self.db,
            block_header,
            tx,
            diff_mode,
            include_empty,
            self.vm_type,
            self.crypto.as_ref(),
        )
    }

    /// Traces a synthetic `eth_call`-shaped request with the opcode (EIP-3155) tracer
    /// (`debug_traceCall`).
    pub fn trace_call_opcodes(
        &mut self,
        block_header: &BlockHeader,
        tx: &GenericTransaction,
        cfg: OpcodeTracerConfig,
    ) -> Result<OpcodeTraceResult, EvmError> {
        LEVM::trace_call_opcodes(
            &mut self.db,
            block_header,
            tx,
            cfg,
            self.vm_type,
            self.crypto.as_ref(),
        )
    }

    /// Traces every transaction in `block` with the callTracer. Assumes `self`'s state is
    /// the block's parent state. Runs the whole block in a single pass, reusing the
    /// block-invariant EVM config across transactions.
    pub fn trace_block_calls(
        &mut self,
        block: &Block,
        only_top_call: bool,
        with_log: bool,
    ) -> Result<Vec<(H256, CallTrace)>, EvmError> {
        LEVM::trace_block_calls(
            &mut self.db,
            block,
            only_top_call,
            with_log,
            self.vm_type,
            self.crypto.as_ref(),
        )
    }

    /// Traces every transaction in `block` with the prestateTracer. See
    /// [`Self::trace_block_calls`].
    pub fn trace_block_prestate(
        &mut self,
        block: &Block,
        diff_mode: bool,
        include_empty: bool,
    ) -> Result<Vec<(H256, PrestateResult)>, EvmError> {
        LEVM::trace_block_prestate(
            &mut self.db,
            block,
            diff_mode,
            include_empty,
            self.vm_type,
            self.crypto.as_ref(),
        )
    }

    /// Traces every transaction in `block` with the opcode (EIP-3155) tracer. See
    /// [`Self::trace_block_calls`].
    pub fn trace_block_opcodes(
        &mut self,
        block: &Block,
        cfg: OpcodeTracerConfig,
    ) -> Result<Vec<(H256, OpcodeTraceResult)>, EvmError> {
        LEVM::trace_block_opcodes(&mut self.db, block, cfg, self.vm_type, self.crypto.as_ref())
    }

    /// Reruns the given block, saving the changes on the state, doesn't output any results or receipts.
    /// If the optional argument `stop_index` is set, the run will stop just before executing the transaction at that index
    /// and won't process the withdrawals afterwards.
    /// WrapsLEVM::rerun_block depending on the feature.
    pub fn rerun_block(
        &mut self,
        block: &Block,
        stop_index: Option<usize>,
    ) -> Result<(), EvmError> {
        LEVM::rerun_block(
            &mut self.db,
            block,
            stop_index,
            self.vm_type,
            self.crypto.as_ref(),
            self.stateless_validator.as_deref(),
        )
    }
}