# ECP-0104: `ecp-forge` dual Ethereum full nodes on dedicated NVMe ZFS

## Why

`every.channel` now has OP Stack and Ethereum contract rails on `ecp-forge`, but it still depends on
public L1 RPC and beacon providers for Ethereum itself.

The forge host has enough raw capacity in `tank`, but `tank` is a large HDD `raidz3` pool that is
well suited for archive bytes, not for the random-read/write pattern of concurrent Ethereum
execution and consensus sync. The same host also has a free 7 TB NVMe device, which is the right
media class for a self-hosted node.

## Decision

1. Create a dedicated single-device ZFS pool for Ethereum on the free NVMe in `ecp-forge`.
2. Run two full-sync Ethereum node pairs on that pool:
   - Ethereum mainnet
   - Ethereum Sepolia
3. Use Reth for execution and Lighthouse for consensus.
4. Keep raw execution and beacon RPC local-only on `ecp-forge` for the first tranche.
5. Publish sync and finality status on `https://eth.every.channel`.
6. Because this tranche is explicitly full-sync from genesis, run Lighthouse with
   `--allow-insecure-genesis-sync` instead of checkpoint bootstrap.

## Consequences

- `every.channel` gets repo-owned L1 execution and consensus rails for both mainnet and Sepolia.
- Ethereum state no longer competes with `tank` archive I/O.
- The first public surface is intentionally conservative: health and sync visibility, not
  unauthenticated public JSON-RPC.
- The dedicated Ethereum pool is single-device NVMe, so it optimizes for node performance rather
  than storage redundancy.
- Consensus sync starts from genesis without checkpoint assistance, which is slower but matches the
  requested full-sync posture.

## Rejected Alternatives

- Put Ethereum state on `tank`: rejected because the HDD `raidz3` pool is the wrong latency profile
  for concurrent execution and consensus sync.
- Keep using only public upstream Ethereum providers: rejected because the OP Stack and settlement
  rails should not depend on third-party RPC availability.
- Expose raw JSON-RPC on `eth.every.channel` immediately: rejected for the first tranche because it
  creates an unauthenticated public abuse surface before auth and rate policy exists.
- Use checkpoint sync for Lighthouse: rejected for this tranche because the requested posture is
  full sync from genesis on both networks.
