EEVM.Block.Processor (eevm v0.1.0)

Copy Markdown View Source

Lower-level block engine with an injectable transaction executor: system calls, then transactions in order, then beacon-chain withdrawals, then EIP-7685 requests, then the commitments a consensus-level verifier will check.

Most callers want EEVM.Block.execute/4, which validates the block, runs each transaction through EEVM.Handler, and checks the commitments against the header. Use this module directly to plug in a custom executor.

If any transaction fails (the injected executor returns an {:error, _}) the processor halts and reports the failing index. The post-state database is left at whatever the last successful transaction produced — this processor does not attempt optimistic rollback.

Options

Callers inject the executor and any per-block hooks:

  • :tx_executor — (tx, %EEVM.BlockEnv{}, %Database{}) -> {:ok, tx_result} | {:error, reason}. Each call receives the current database after all prior transactions and system calls have been applied. The returned tx_result is a map with keys :status, :gas_used, :logs, and :db, plus an optional :tx_type (default :legacy) that selects the EIP-2718 receipt encoding, an optional :state_root that the receipt carries in place of its status (before Byzantium, EIP-658), an optional :contract_address that the receipt carries for a contract creation, and an optional :trace (an EEVM.Tracer); when any transaction returns one, result.trace lists them in order.
  • :system_calls — list of hooks, each (%Database{}, %EEVM.BlockEnv{}) -> %Database{}. Executed in order, strictly before any transaction. The default is [].
  • :tx_encoder — (tx) -> binary used to compute the transactions_root. Defaults to EEVM.Transaction.Envelope.encode/1, which handles every typed envelope this codebase knows about. Tests using plain maps supply their own.
  • :rewards — list of {address, wei} balance credits for the block's proof-of-work miner and ommer rewards, applied after the transactions. Defaults to [].
  • :withdrawals — list of EEVM.Block.Withdrawal structs (EIP-4895). Applied as flat balance credits after the transaction fold and before the state root is computed, so the returned state_root already reflects them. Defaults to [].
  • :block_context — the EEVM.BlockEnv handed to system calls and the executor. Defaults to one derived from the header's fields.
  • :requests — (%Database{}, %EEVM.BlockEnv{}, [%Receipt{}]) -> {:ok, requests, %Database{}} | {:error, reason}, run after the withdrawals to collect the block's EIP-7685 requests (see EEVM.Block.Requests.collect/5). Its database is the one the state_root is computed from. Without it, result.requests is nil.

Summary

Functions

Execute every phase of the block and produce a %EEVM.Block.Result{}.

Types

process_error()

@type process_error() :: {:tx_failed, non_neg_integer(), term()} | atom()

process_opts()

@type process_opts() :: [
  tx_executor: tx_executor(),
  system_calls: [system_call()],
  tx_encoder: tx_encoder(),
  rewards: [{non_neg_integer(), non_neg_integer()}],
  withdrawals: [EEVM.Block.Withdrawal.t()],
  block_context: EEVM.BlockEnv.t(),
  requests: requests_hook()
]

requests_hook()

@type requests_hook() :: (EEVM.Database.t(),
                    EEVM.BlockEnv.t(),
                    [EEVM.Block.Receipt.t()] ->
                      {:ok, [binary()], EEVM.Database.t()} | {:error, atom()})

system_call()

@type system_call() :: (EEVM.Database.t(), EEVM.BlockEnv.t() -> EEVM.Database.t())

tx_encoder()

@type tx_encoder() :: (term() -> binary())

tx_executor()

@type tx_executor() :: (term(), EEVM.BlockEnv.t(), EEVM.Database.t() ->
                    {:ok, tx_result()} | {:error, term()})

tx_result()

@type tx_result() :: %{
  :status => 0 | 1,
  :gas_used => non_neg_integer(),
  :logs => [EEVM.Block.Bloom.log_entry()],
  :db => EEVM.Database.t(),
  optional(:tx_type) => EEVM.Block.Receipt.tx_type(),
  optional(:state_root) => binary(),
  optional(:contract_address) => non_neg_integer() | nil,
  optional(:trace) => EEVM.Tracer.t() | nil
}

Functions

process_block(header, transactions, pre_state_db, opts)

@spec process_block(
  EEVM.Block.Header.t(),
  [term()],
  EEVM.Database.t(),
  process_opts()
) ::
  {:ok, EEVM.Block.Result.t()} | {:error, process_error()}

Execute every phase of the block and produce a %EEVM.Block.Result{}.

The caller owns pre_state_db and must pass an injected :tx_executor. See the module doc for the full option list.

Returns:

  • {:ok, %Result{}} on success.
  • {:error, {:tx_failed, index, :gas_allowance_exceeded}} when a transaction's gas_limit exceeds the gas left in the block (header.gas_limit minus the gas used so far).
  • {:error, {:tx_failed, index, reason}} when the injected executor rejects a transaction. index is 0-based in transactions order.
  • {:error, reason} when the :requests hook fails.