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

Validates a child `EEVM.Block.Header` against its parent.

Covers the consensus rules that don't require running the EVM:

  * `parent_hash` matches the parent header's `hash`.
  * `number` is one greater than the parent's number.
  * `timestamp` is strictly greater than the parent's timestamp.
  * `extra_data` is at most 32 bytes.
  * `gas_limit` is at least 5,000, fits in a signed 64-bit integer, and
    differs from the parent's gas limit by less than `parent_gas_limit / 1024`.
  * Each fork-dependent field is present exactly when its fork is active:
    `base_fee_per_gas` (London), `withdrawals_root` (Shanghai),
    `blob_gas_used`, `excess_blob_gas`, and `parent_beacon_block_root`
    (Cancun), `requests_hash` (Prague).
  * From London, `base_fee_per_gas` equals the value derived from the
    parent's base fee, gas used, and gas target (EIP-1559).
  * From Paris, `difficulty` is 0, `nonce` is eight zero bytes, and
    `ommers_hash` is `EEVM.Block.Header.empty_ommers_hash/0` (EIP-3675).
  * From Cancun, `blob_gas_used` is a multiple of the per-blob gas
    and at most `EEVM.Gas.Blob.max_blob_gas_per_block/1`. `excess_blob_gas`
    equals `EEVM.Gas.Blob.calc_excess_blob_gas/2` of the parent (EIP-4844,
    EIP-7691 from Prague, EIP-7918 from Osaka).

Checks run in that order and the first failure wins. The parent is judged
under the same fork as the child, so a fork's first block (such as London's,
whose expected base fee is the initial 1 gwei) isn't modelled.

Checks against the block body and the execution result (`transactions_root`,
`withdrawals_root`, `gas_used`, `receipts_root`, `state_root`, ...) live in
`EEVM.Block.validate/3` and `EEVM.Block.execute/4`.

# `error`

```elixir
@type error() :: EEVM.Error.header_validation_error()
```

Reason returned when a header fails validation; see `EEVM.Error`.

# `validate`

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

Returns `:ok` when `child` is a valid successor of `parent`, otherwise
`{:error, reason}` for the first rule it breaks. `hardfork` selects the
fork-dependent rules and defaults to `EEVM.HardforkConfig.default/0`.

## Example

    iex> alias EEVM.Block.{Header, HeaderValidator}
    iex> shanghai = EEVM.HardforkConfig.new(:shanghai)
    iex> parent = Header.new(number: 1, timestamp: 10, gas_limit: 30_000_000, hash: <<1::256>>)
    iex> fields = [base_fee_per_gas: 0, withdrawals_root: <<0::256>>]
    iex> parent = struct!(parent, fields)
    iex> child = Header.new([number: 2, timestamp: 22, gas_limit: 30_000_000, parent_hash: <<1::256>>] ++ fields)
    iex> HeaderValidator.validate(child, parent, shanghai)
    :ok
    iex> HeaderValidator.validate(%{child | timestamp: 10}, parent, shanghai)
    {:error, :invalid_timestamp}

---

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