A brutalist Ethereum block explorer built on Rust and Reth.
┌─────────────────────────────────────────────────────────────────┐
│ FRONTEND │
│ Next.js + Tailwind (Brutalist B&W, JetBrains Mono) │
└──────────────────────┬──────────────────────────────────────────┘
│ HTTP/WebSocket
┌──────────────────────▼──────────────────────────────────────────┐
│ RUST API SERVER (Axum) │
│ REST API │ WebSocket │ Price Service │
└──────────────────────┬──────────────────────────────────────────┘
│
┌──────────────────────▼──────────────────────────────────────────┐
│ RUST INDEXER │
│ Block Sync │ Token Parser │ Trace Parser │
└───────┬─────────────────────────────────────────┬───────────────┘
│ Direct MDBX read │ Write
┌───────▼───────┐ ┌───────▼───────┐
│ Reth Node │ │ ClickHouse │
│ (MDBX DB) │ │ (Analytics) │
└───────────────┘ └───────────────┘
| Layer | Technology |
|---|---|
| Frontend | Next.js 14, Tailwind, wagmi |
| API | Axum (Rust) |
| Indexer | Rust + reth-db crate |
| Database | ClickHouse |
| Cache | Redis |
| Node | Reth |
| Deploy | Kubernetes |
etherescan/
├── crates/
│ ├── etherescan-common/ # Shared types, config, db
│ ├── etherescan-api/ # Axum REST API + WebSocket
│ ├── etherescan-indexer/ # Blockchain indexer
│ └── etherescan-prices/ # CoinGecko price service
├── apps/web/ # Next.js frontend
├── deploy/
│ ├── k8s/ # Kubernetes manifests
│ ├── docker/ # Dockerfiles
│ └── clickhouse/ # ClickHouse migrations
├── Cargo.toml # Rust workspace
└── config.toml # Configuration
- Rust 1.82+
- Node.js 20+
- Reth node with synced data
- ClickHouse
- Redis
Copy and edit the configuration:
cp config.toml config.local.tomlEdit config.local.toml with your settings:
- Reth database paths
- ClickHouse connection
- Redis connection
- Start ClickHouse and Redis:
docker compose up -d clickhouse redis- Run the Indexer:
cargo run --release -p etherescan-indexer- Run the API Server:
cargo run --release -p etherescan-api- Run the Frontend:
cd apps/web
npm install
npm run dev# Build Rust binaries
cargo build --release
# Build Docker images
docker build -f deploy/docker/Dockerfile.api -t etherescan/api .
docker build -f deploy/docker/Dockerfile.indexer -t etherescan/indexer .
docker build -f deploy/docker/Dockerfile.web -t etherescan/web apps/web# Create namespace and resources
kubectl apply -f deploy/k8s/namespace.yaml
kubectl apply -f deploy/k8s/configmap.yaml
kubectl apply -f deploy/k8s/clickhouse.yaml
kubectl apply -f deploy/k8s/redis.yaml
kubectl apply -f deploy/k8s/api.yaml
kubectl apply -f deploy/k8s/indexer.yaml
kubectl apply -f deploy/k8s/web.yamlGET /api/v1/blocks- List blocksGET /api/v1/block/:number- Block by numberGET /api/v1/block/hash/:hash- Block by hashGET /api/v1/block/:number/txs- Block transactions
GET /api/v1/txs- List transactionsGET /api/v1/tx/:hash- Transaction by hashGET /api/v1/address/:addr/txs- Address transactions
GET /api/v1/address/:addr- Address infoGET /api/v1/address/:addr/tokens- Token transfers
GET /api/v1/tokens- List tokensGET /api/v1/token/:addr- Token infoGET /api/v1/token/:addr/transfers- Token transfers
GET /api/v1/gas- Current gas pricesGET /api/v1/gas/history- Historical gas data
GET /api/v1/search?q=- Universal search
GET /api/v1/stats- Network statistics
Connect to /ws and subscribe to events:
{ "action": "subscribe", "channels": ["blocks", "transactions"] }Event types:
block- New blocktx- New transactionaddress_activity- Activity on watched address
The frontend uses a brutalist design:
- Black and white colors only
- JetBrains Mono font
- 1px borders, no shadows, no rounded corners
- Hover states: inverted colors
MIT