Evolve uses a modular architecture where each component has a well-defined interface and can be swapped independently. This document provides an overview of how the pieces fit together.
┌─────────────────────────────────────────────────────────────────┐
│ Client Apps │
│ (wallets, dapps, indexers) │
└─────────────────────────────┬───────────────────────────────────┘
│ JSON-RPC / gRPC
┌─────────────────────────────▼───────────────────────────────────┐
│ ev-node │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌──────────────┐ │
│ │ Block │ │ Sequencer │ │ P2P │ │ Sync │ │
│ │ Components│ │ │ │ Network │ │ Services │ │
│ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ └───────┬──────┘ │
└────────┼──────────────┼──────────────┼────────────────┼─────────┘
│ │ │ │
│ Executor │ Sequencer │ libp2p │ DA Client
▼ ▼ ▼ ▼
┌────────────────┐ ┌──────────┐ ┌─────────────────────────────────┐
│ Executor │ │Sequencer │ │ DA Layer │
│ (ev-reth or │ │(single, │ │ (Celestia) │
│ ev-abci) │ │ based) │ │ │
└────────────────┘ └──────────┘ └─────────────────────────────────┘
-
Zero-dependency core — The
core/package contains only interfaces with no external dependencies. This keeps the API stable and allows any implementation. -
Modular components — Executor, Sequencer, and DA layer are all pluggable. Swap them without changing ev-node.
-
Separation of concerns — Block production, syncing, and DA submission run as independent components that communicate through well-defined channels.
-
Two operating modes — Nodes run as either an Aggregator (produces blocks) or Sync-only (follows chain).
The block package is the heart of ev-node. It's organized into specialized components:
| Component | Responsibility | Runs On |
|---|---|---|
| Executor | Produces blocks by getting batches from sequencer and executing via execution layer | Aggregator only |
| Reaper | Scrapes transactions from execution layer mempool and submits to sequencer | Aggregator only |
| Syncer | Coordinates block sync from DA layer and P2P network | All nodes |
| Submitter | Submits blocks to DA layer and tracks inclusion | Aggregator only |
| Cache | Manages in-memory state for headers, data, and pending submissions | All nodes |
┌─────────────┐
│ Reaper │
│ (tx scrape)│
└──────┬──────┘
│ Submit batch
▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Sequencer │◄───│ Executor │───►│ Broadcaster │
│ │ │(block prod) │ │ (P2P) │
└─────────────┘ └──────┬──────┘ └─────────────┘
│
│ Queue for submission
▼
┌─────────────┐
│ Submitter │───► DA Layer
│ │
└──────┬──────┘
│
│ Track inclusion
▼
┌─────────────┐
│ Cache │
└─────────────┘
Evolve supports several node configurations:
| Type | Block Production | Full Validation | DA Submission | Use Case |
|---|---|---|---|---|
| Aggregator | Yes | Yes | Yes | Block producer (sequencer) |
| Full Node | No | Yes | No | RPC provider, validator |
| Light Node | No | Headers only | No | Mobile, embedded clients |
| Attester | No | Yes | No | Soft consensus participant |
The aggregator (also called sequencer node) produces blocks:
- Reaper collects transactions from execution layer
- Executor gets ordered batch from sequencer
- Executor calls execution layer to process transactions
- Executor creates and signs block (header + data)
- Broadcaster gossips block to P2P network
- Submitter queues block for DA submission
Full nodes sync and validate without producing blocks:
- Syncer receives blocks from DA layer and/or P2P
- Validates header signatures and data hashes
- Executes transactions via execution layer
- Verifies resulting state root matches header
- Persists validated blocks to local store
User Tx → Execution Layer Mempool
│
▼
Reaper scrapes txs
│
▼
Sequencer orders batch
│
▼
Executor.ExecuteTxs()
│
├──► SignedHeader + Data
│
├──► P2P Broadcast (soft confirmation)
│
└──► Submitter Queue
│
▼
DA Layer (hard confirmation)
┌────────────────────────────────────────┐
│ Syncer │
├────────────┬────────────┬──────────────┤
│ DA Worker │ P2P Worker │Forced Incl. │
│ │ │ Worker │
└─────┬──────┴─────┬──────┴───────┬──────┘
│ │ │
└────────────┴──────────────┘
│
▼
processHeightEvent()
│
▼
Validate → Execute → Persist
Built on libp2p with:
- GossipSub for transaction and block propagation
- Kademlia DHT for peer discovery
- Topics:
{chainID}-tx,{chainID}-header,{chainID}-data
Nodes discover peers through:
- Bootstrap/seed nodes
- DHT peer exchange
- PEX (peer exchange protocol)
ev-node uses a key-value store (badger) for:
- Headers — Indexed by height and hash
- Data — Transaction lists indexed by height
- State — Last committed height, app hash, DA height
- Pending — Blocks awaiting DA inclusion
- Block Lifecycle — Detailed block processing flow
- Sequencing — How transaction ordering works
- Data Availability — DA layer integration
- Executor Interface — Full interface reference