# `EEVM.Block.Processor`
[🔗](https://github.com/mw2000/eevm/blob/main/lib/eevm/block/processor.ex#L1)

Execute a block end-to-end: system calls, then transactions in order, then
beacon-chain withdrawals, then the commitments a consensus-level verifier
will check.

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, %Context.Block{}, %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`.
- `:system_calls` — list of hooks, each `(%Database{}, %Context.Block{})
  -> %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.
- `: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 `[]`.
- `:hardfork` — optional atom, purely informational today; the real
  executor will consume it once wired in.

# `process_error`

```elixir
@type process_error() ::
  :block_gas_limit_exceeded | {:tx_failed, non_neg_integer(), term()}
```

# `process_opts`

```elixir
@type process_opts() :: [
  tx_executor: tx_executor(),
  system_calls: [system_call()],
  tx_encoder: tx_encoder(),
  withdrawals: [EEVM.Block.Withdrawal.t()],
  hardfork: atom() | nil
]
```

# `system_call`

```elixir
@type system_call() :: (EEVM.Database.t(), EEVM.Context.Block.t() -&gt;
                    EEVM.Database.t())
```

# `tx_encoder`

```elixir
@type tx_encoder() :: (term() -&gt; binary())
```

# `tx_executor`

```elixir
@type tx_executor() :: (term(), EEVM.Context.Block.t(), EEVM.Database.t() -&gt;
                    {:ok, tx_result()} | {:error, term()})
```

# `tx_result`

```elixir
@type tx_result() :: %{
  status: 0 | 1,
  gas_used: non_neg_integer(),
  logs: [EEVM.Block.Bloom.log_entry()],
  db: EEVM.Database.t()
}
```

# `process_block`

```elixir
@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, :block_gas_limit_exceeded}` when `sum(tx.gas_limit)` exceeds
  `header.gas_limit`.
- `{:error, {:tx_failed, index, reason}}` when the injected executor
  rejects a transaction. `index` is 0-based in `transactions` order.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
