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

A full execution-layer block — header, transactions, ommers, and
withdrawals — and the public path to build, encode, validate, and execute
one.

| Field | Description |
|-------|-------------|
| `header` | The `EEVM.Block.Header` |
| `transactions` | Signed transactions (see `EEVM.Transaction`), in order |
| `ommers` | Uncle headers; always empty after the Merge |
| `withdrawals` | `EEVM.Block.Withdrawal`s from Shanghai on, `nil` before |

- `decode/1` and `encode/1` convert to and from canonical RLP.
- `validate/3` runs every check that needs no state: the EIP-7934 size
  limit, `EEVM.Block.HeaderValidator` against the parent, and the body
  against the header's commitments.
- `execute/4` validates the block, applies it to a database (system calls,
  each transaction through `EEVM.Handler`, withdrawals, EIP-7685 requests),
  and checks the header's `gas_used`, `logs_bloom`, `receipts_root`,
  `state_root`, and `requests_hash` against the result.
- `build/4` produces a child block of a parent: it derives the header,
  executes the transactions, fills in every commitment, and hashes it.

Options follow `EEVM.Handler.execute/4`: a full `:config` (hardfork, chain
id, custom precompiles) or the `:hardfork` shorthand (default `:cancun`);
`:chain_id` is deprecated in favour of the config's. `:block_hashes` maps
recent block numbers to their 32-byte hashes for BLOCKHASH. From Prague,
`:deposit_contract_address` names the chain's EIP-6110 deposit contract
(default: mainnet's, `EEVM.Block.Requests.mainnet_deposit_contract/0`).
`tracer: true` traces every transaction: `result.trace` is a list with one
`EEVM.Tracer` per transaction, in block order (like geth's
`debug_traceBlock`), so transaction boundaries stay visible.

Errors are `{:error, reason}` with the reasons catalogued in `EEVM.Error`
as `t:EEVM.Error.block_error/0`.

## Example

    iex> alias EEVM.Block
    iex> parent = EEVM.Block.Header.new(gas_limit: 30_000_000, base_fee_per_gas: 7, hash: <<1::256>>)
    iex> db = EEVM.Database.InMemory.new()
    iex> {:ok, block, _result} = Block.build(parent, [], db, hardfork: :shanghai, timestamp: 12)
    iex> {:ok, decoded} = block |> Block.encode() |> Block.decode()
    iex> decoded == block
    true
    iex> {:ok, result} = Block.execute(decoded, parent, db, hardfork: :shanghai)
    iex> result.gas_used
    0

Not covered: ommer (uncle) validation and rewards, and fork transitions
inside a chain.

# `build_opts`

```elixir
@type build_opts() :: [
  hardfork: EEVM.HardforkConfig.spec_id(),
  config: EEVM.Config.t(),
  chain_id: non_neg_integer(),
  block_hashes: %{required(non_neg_integer()) =&gt; &lt;&lt;_::256&gt;&gt;},
  deposit_contract_address: non_neg_integer(),
  tracer: boolean(),
  timestamp: non_neg_integer(),
  coinbase: non_neg_integer(),
  gas_limit: non_neg_integer(),
  prev_randao: non_neg_integer(),
  extra_data: binary(),
  parent_beacon_block_root: &lt;&lt;_::256&gt;&gt; | non_neg_integer(),
  withdrawals: [EEVM.Block.Withdrawal.t()]
]
```

# `opts`

```elixir
@type opts() :: [
  hardfork: EEVM.HardforkConfig.spec_id(),
  config: EEVM.Config.t(),
  chain_id: non_neg_integer(),
  block_hashes: %{required(non_neg_integer()) =&gt; &lt;&lt;_::256&gt;&gt;},
  deposit_contract_address: non_neg_integer(),
  tracer: boolean()
]
```

# `t`

```elixir
@type t() :: %EEVM.Block{
  header: EEVM.Block.Header.t(),
  ommers: [EEVM.Block.Header.t()],
  transactions: [transaction()],
  withdrawals: [EEVM.Block.Withdrawal.t()] | nil
}
```

# `transaction`

```elixir
@type transaction() ::
  EEVM.Transaction.Legacy.t()
  | EEVM.Transaction.AccessList.t()
  | EEVM.Transaction.FeeMarket.t()
  | EEVM.Transaction.Blob.t()
  | EEVM.Transaction.SetCode.t()
```

# `build`

```elixir
@spec build(EEVM.Block.Header.t(), [transaction()], EEVM.Database.t(), build_opts()) ::
  {:ok, t(), EEVM.Block.Result.t()} | {:error, EEVM.Error.block_error()}
```

Builds the child of `parent` holding `transactions` (signed wire
transactions, in order) and executes it on `db`.

The header takes `number`, `parent_hash`, the EIP-1559 base fee, and the
EIP-4844 excess blob gas from `parent`, and every commitment from the
execution result; `hash` is computed. Fork-dependent fields are set exactly
for the forks that define them.

Options are those of `execute/4` plus header attributes: `:timestamp`
(default: 12 seconds, one mainnet slot, after the parent's), `:coinbase`,
`:gas_limit` (default: the parent's),
`:prev_randao`, `:extra_data`, `:parent_beacon_block_root`, and
`:withdrawals` (from Shanghai).

Returns `{:ok, block, result}` or the first error `execute/4` would report,
including `{:error, :simulation_config}` for a config with a simulation
switch set.

From Prague the state must hold the EIP-7002 and EIP-7251 request contracts,
as on mainnet; give a new chain its system contracts with
`EEVM.SystemContracts.genesis_accounts/1`.

# `decode`

```elixir
@spec decode(binary()) :: {:ok, t()} | {:error, :invalid_block_encoding}
```

Decodes a canonical RLP block. The header's `hash` is set from its bytes.

Returns `{:error, :invalid_block_encoding}` when the bytes aren't a
canonical encoding of a block (malformed RLP, a wrong-sized field, a
non-canonical integer, a withdrawal field over 64 bits, or an undecodable
transaction).

# `encode`

```elixir
@spec encode(t()) :: binary()
```

Encodes `block` as canonical RLP:
`[header, transactions, ommers]`, plus `withdrawals` when it isn't `nil`.

Legacy transactions are embedded as RLP lists and typed transactions as
their EIP-2718 envelope bytes.

# `execute`

```elixir
@spec execute(t(), EEVM.Block.Header.t(), EEVM.Database.t(), opts()) ::
  {:ok, EEVM.Block.Result.t()} | {:error, EEVM.Error.block_error()}
```

Validates `block` with `validate/3`, then applies it to `db`: the EIP-4788
and EIP-2935 system calls, each transaction through `EEVM.Handler`, the
EIP-4895 withdrawals, and from Prague the EIP-7685 requests (EIP-6110
deposits, then the EIP-7002 and EIP-7251 system calls; see
`EEVM.Block.Requests`). Finally checks the header's `gas_used`,
`logs_bloom`, `receipts_root`, `state_root`, and `requests_hash` against
the result.

With `tracer: true`, each transaction is traced and `result.trace` lists
one `EEVM.Tracer` per transaction, in block order; system calls are not
traced.

Returns `{:ok, %EEVM.Block.Result{}}` whose `db` is the state after the
block and whose `requests` are the block's requests. A
transaction that `EEVM.Handler` rejects, or whose gas limit exceeds the gas
left in the block, fails the block with
`{:error, {:tx_failed, index, reason}}`; a request that can't be collected
fails it with that reason.

# `max_rlp_block_size`

```elixir
@spec max_rlp_block_size() :: pos_integer()
```

Returns `MAX_RLP_BLOCK_SIZE`, the largest encoded block valid from Osaka (EIP-7934).

# `validate`

```elixir
@spec validate(t(), EEVM.Block.Header.t(), opts()) ::
  :ok | {:error, EEVM.Error.block_error()}
```

Checks `block` against `parent` without touching state, in this order:

1. The config sets no simulation switch (`EEVM.Config.simulation?/1`),
   else `:simulation_config`: blocks never run with relaxed rules.
2. From Osaka, the encoded block is at most `max_rlp_block_size/0` bytes
   (EIP-7934), else `:rlp_block_size_exceeded`.
3. The header is a valid child of `parent` (`EEVM.Block.HeaderValidator`;
   the checks and their errors are listed in `EEVM.Error`).
4. The body matches the header: `ommers_hash`, `transactions_root`,
   `withdrawals_root` (withdrawals are present exactly from Shanghai), and
   from Cancun the total blob gas of the transactions equals
   `blob_gas_used`.

---

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