> ## Documentation Index
> Fetch the complete documentation index at: https://docs.optimism.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Running op-reth with Historical Proofs

> Configure op-reth's proofs-history (v2) store to serve efficient historical eth_getProof responses for permissionless withdrawal proving.

This tutorial layers the **proofs-history** historical proof store (storage format **v2**) on top of a working op-reth node. Follow [Building and running an OP Stack node from source](/node-operators/tutorials/run-node-from-source) first to build op-reth and op-node, then return here to enable proofs-history.

<Info>
  **Do you need this tutorial?** Withdrawal proving on op-reth uses `eth_getProof` against historical L2 state, so both permissioned and permissionless chains need historical state exposed — but the required lookback differs sharply:

  * **Permissioned chains** only need a few hours of lookback (covering your dispute-game publishing cadence with margin). The lighter `--rpc.eth-proof-window <num_blocks>` flag is sufficient on its own — no separate proofs database is needed, and **this tutorial does not apply**. See the [op-reth configuration reference](/node-operators/reference/op-reth-config#rpc-eth-proof-window) for that flag.
  * **Permissionless chains** need \~28 days of lookback. `--rpc.eth-proof-window` becomes too slow and memory-hungry at that range, so follow this tutorial to set up `--proofs-history` (v2).
</Info>

<Info>
  Use historical proofs storage format v2 by setting `--proofs-history.storage-version=v2` when running `op-reth node`.
</Info>

## How it works

reth's default `eth_getProof` reverts in-memory state diffs backward from the tip, which becomes prohibitive at multi-day lookbacks. The **proofs-history** subsystem maintains a separate MDBX database that tracks intermediate Merkle Patricia Trie nodes versioned by block, enabling O(1) lookups of proofs at any block within a configurable retention window. A background pruner removes data outside the window.

The subsystem processes blocks asynchronously via reth's ExEx (Execution Extension) hook, so it adds zero overhead to sync speed and negligible tip latency. See the [historical proof configuration reference](/node-operators/reference/op-reth-historical-proof-config) for storage tables, RPC overrides, and tunable parameters.

## Prerequisites

* A built `op-reth` binary at v2.2.3 or later (required for `--proofs-history.storage-version=v2`). See [Build op-node and the execution client](/node-operators/tutorials/run-node-from-source#build-op-node-and-the-execution-client).
* An op-reth datadir, either initialized from genesis or restored from a [snapshot](https://datadirs.optimism.io/) (covered below).
* Sufficient disk: estimate `chain_size + 20% buffer` for the proofs database (e.g., \~1 TB for 4 weeks on Base at 2s block time).
* NVMe SSD recommended.

## Initialization

Running `op-reth` with historical proofs requires a two-step initialization:

### 1. Initialize op-reth

Initialize the core database with the genesis file for your chain (e.g., `optimism`).

```bash theme={null}
./target/release/op-reth init \
  --datadir="/path/to/datadir" \
  --chain="optimism"
```

#### Option: Start from a Snapshot

If you prefer to start from a pre-synchronized database snapshot instead of syncing from genesis:

1. Download and extract an `op-reth` snapshot from [datadirs.optimism.io](https://datadirs.optimism.io/) into your `datadir`.
2. Skip the `op-reth init` command above.
3. Proceed to **Initialize Proofs Storage** below. The `proofs init` command initializes the proofs database at the snapshot's chain tip — it does not retroactively populate proofs for blocks already in the snapshot.

### 2. Initialize Proofs Storage

Initialize the separate storage used by the historical proof store. This is **required** before starting the node with `--proofs-history`, even when reusing an existing op-reth datadir or restoring from a snapshot.

```bash theme={null}
./target/release/op-reth proofs init \
  --datadir="/path/to/datadir" \
  --chain="optimism" \
  --proofs-history.storage-path="/path/to/proofs-db" \
  --proofs-history.storage-version=v2
```

<Info>
  The first time `proofs init` runs, it takes minutes to hours. Subsequent invocations should only take seconds. It does **not** backfill historical proofs — it marks the current chain tip as the starting point of the proofs database. Once the node is running with `--proofs-history`, the proofs database fills forward as new blocks are committed. To serve proofs across the full retention window (e.g., 30 days for permissionless fault proofs at default settings), the node must run continuously for at least that long after initialization. For that reason it is recommended to start from a snapshot whose tip is old enough to cover the required time window.
</Info>

## Running op-reth with proofs-history

Add the `--proofs-history.*` flags below to your standard op-reth start command from [Start the execution client](/node-operators/tutorials/run-node-from-source#start-the-execution-client). The proofs-history additions are:

```bash theme={null}
./target/release/op-reth node \
  # ... your standard flags from Tutorial A ...
  --proofs-history \
  --proofs-history.storage-path="/path/to/proofs-db" \
  --proofs-history.storage-version=v2
```

<Info>
  The default `--proofs-history.window` is **1,296,000 blocks**, corresponding to \~30 days at 2s block times. For chains with a different block time, set `--proofs-history.window=<num_blocks>` explicitly using `target_retention_seconds / block_time_seconds`.
</Info>

For the full set of `--proofs-history.*` flags (window, prune-interval, metrics, etc.), see the [historical proof configuration reference](/node-operators/reference/op-reth-historical-proof-config).

## Running op-node

Start `op-node` as documented in [Start op-node](/node-operators/tutorials/run-node-from-source#start-op-node). No proofs-history-specific changes are needed on the consensus client.

## Verification

After starting both clients, query the sync status of the proofs store via the `debug_proofsSyncStatus` RPC method:

```bash theme={null}
curl -s -X POST -H "Content-Type: application/json" \
  --data '{"jsonrpc":"2.0","method":"debug_proofsSyncStatus","params":[],"id":1}' \
  http://localhost:8545
```

The response has the shape:

```json theme={null}
{"jsonrpc":"2.0","id":1,"result":{"earliest":<block>,"latest":<block>}}
```

Immediately after `proofs init`, both `earliest` and `latest` sit at the chain tip; the window then fills forward as new blocks are committed. `eth_getProof` calls for every block within `[earliest, latest]` will be served from the versioned store. Requests for blocks older than `earliest` will fail or fall back to the default reth implementation.

You can also check the op-reth startup logs for messages confirming the proofs-history ExEx is wired up:

```text theme={null}
INFO reth::cli: Using on-disk storage for proofs history
INFO reth::cli: Installing proofs-history RPC overrides (eth_getProof, debug_executePayload)
INFO reth::cli eth_replaced=true debug_replaced=true: Proofs-history RPC overrides installed
```

## Monitoring

When op-reth is run with the `--metrics=<addr>:<port>` flag, the proofs-history ExEx exposes Prometheus metrics covering proofs-DB sync state (`optimism_trie_block_*`), the background pruner (`optimism_trie_pruner_*`), and `eth_getProof` RPC traffic (`optimism_rpc_eth_api_ext_*`). See the [historical proof configuration reference](/node-operators/reference/op-reth-historical-proof-config#metrics) for the full list.

## Operational Commands

### Manual prune

Pruning runs automatically in the background, driven by the engine task as new blocks are committed, and removes data outside the retention window. You should not need to invoke `op-reth proofs prune` under normal operation.

A manual prune is only required in one situation: at startup, if the proofs database contains more than **1000 blocks** of history beyond the configured `--proofs-history.window`, the node refuses to start rather than stalling on a large prune operation. This typically happens after the node has been offline long enough that the configured window has shifted significantly, or after reducing `--proofs-history.window` to a smaller value than was previously in use.

When this happens, op-reth exits with an error indicating the number of blocks to prune. Run the prune command once to bring the database back within the safety threshold, then restart the node:

```bash theme={null}
op-reth proofs prune \
  --datadir /path/to/reth-datadir \
  --proofs-history.storage-path /path/to/proofs-db \
  --proofs-history.storage-version v2 \
  --proofs-history.window 1296000
```

### Unwind

Recover from corruption by reverting the proofs database to a specific block:

```bash theme={null}
op-reth proofs unwind \
  --datadir /path/to/reth-datadir \
  --proofs-history.storage-path /path/to/proofs-db \
  --proofs-history.storage-version v2 \
  --target <BLOCK_NUMBER>
```

<Note>
  You can only unwind to a block after the earliest block number in the database. Unwinding to a block before the earliest will fail.
</Note>

## Performance

Benchmarked on Base Sepolia (\~700k block window, WETH contract):

| Metric        | Value                                 |
| ------------- | ------------------------------------- |
| Avg latency   | \~15 ms per `eth_getProof`            |
| Throughput    | \~5,000 req/s (10 concurrent workers) |
| Sync overhead | Zero (ExEx processes asynchronously)  |
| Memory        | Bounded by window size — no OOM risk  |

## Next steps

* [op-reth v2.2.3 release notes](https://github.com/ethereum-optimism/optimism/releases/tag/op-reth%2Fv2.2.3) — the release that introduced the historical proof store v2.
* [op-reth historical proof configuration reference](/node-operators/reference/op-reth-historical-proof-config) — full `--proofs-history.*` flag set, RPC endpoints, and Prometheus metrics.
* [op-reth configuration reference](/node-operators/reference/op-reth-config) — all standard op-reth flags.
