Explains ev-node architecture, components, and internal workings. Use when the user asks how ev-node works, wants to understand the block package, DA layer, sequencing, namespaces, or needs architecture explanations. Covers block production, syncing, DA submission, forced inclusion, single vs based sequencer, and censorship resistance.
93
Does it follow best practices?
Validation for skill structure
ev-node is a sovereign rollup framework that allows building rollups on any Data Availability (DA) layer. It follows a modular architecture where components can be swapped.
Reference files:
core/ contains only interfaces, no external deps| Package | Responsibility |
|---|---|
core/ | Interfaces only (Executor, Sequencer) |
types/ | Data structures (Header, Data, State, SignedHeader) |
block/ | Block lifecycle management |
execution/ | Execution layer implementations (EVM, ABCI) |
node/ | Node initialization and orchestration |
pkg/p2p/ | libp2p-based networking |
pkg/store/ | Persistent storage |
pkg/da/ | DA layer abstraction |
The block package is the most complex part of ev-node. See block-architecture.md for the complete breakdown.
Components struct:
├── Executor - Block production (Aggregator only)
├── Reaper - Transaction scraping (Aggregator only)
├── Syncer - Block synchronization
├── Submitter - DA submission and inclusion
└── Cache - Unified state cachingNewAggregatorComponents() - Full node that produces and syncs blocksNewSyncComponents() - Non-aggregator that only syncsHeader - Block metadata (height, time, hashes, proposer) Data - Transaction list with metadata SignedHeader - Header with proposer signature State - Chain state (last block, app hash, DA height)
Sequencer.GetNextBatch()
│
▼
Executor.ExecuteTxs()
│
├──► SignedHeader + Data
│
├──► P2P Broadcast
│
└──► Submitter Queue
│
▼
DA Layer┌─────────────────────────────────────┐
│ Syncer │
├─────────────┬─────────────┬─────────┤
│ DA Worker │ P2P Worker │ Forced │
│ │ │ Incl. │
└──────┬──────┴──────┬──────┴────┬────┘
│ │ │
└─────────────┴───────────┘
│
▼
processHeightEvent()
│
▼
ExecuteTxs → Update StateThe DA layer abstracts blob storage. ev-node uses Celestia but the interface is pluggable. See da-sequencing.md for full details.
DA uses 29-byte namespaces (1 byte version + 28 byte ID). Three namespaces are used:
| Namespace | Purpose |
|---|---|
| Header | Block headers |
| Data | Transaction data (optional, can share with header) |
| Forced Inclusion | User-submitted txs for censorship resistance |
type Client interface {
Submit(ctx, data [][]byte, gasPrice, namespace, options) ResultSubmit
Retrieve(ctx, height uint64, namespace) ResultRetrieve
Get(ctx, ids []ID, namespace) ([]Blob, error)
}| File | Purpose |
|---|---|
pkg/da/types/types.go | Core types (Blob, ID, Commitment) |
pkg/da/types/namespace.go | Namespace handling |
block/internal/da/client.go | DA client wrapper |
block/internal/da/forced_inclusion_retriever.go | Forced tx retrieval |
Sequencers order transactions for block production. See da-sequencing.md for full details.
| Mode | Mempool | Forced Inclusion | Use Case |
|---|---|---|---|
| Single | Yes | Yes | Traditional rollup |
| Based | No | Only source | High liveness guarantee |
type Sequencer interface {
SubmitBatchTxs(ctx, req) (*SubmitBatchTxsResponse, error)
GetNextBatch(ctx, req) (*GetNextBatchResponse, error)
VerifyBatch(ctx, req) (*VerifyBatchResponse, error)
SetDAHeight(height uint64)
GetDAHeight() uint64
}Batches include a mask distinguishing tx sources:
type Batch struct {
Transactions [][]byte
ForceIncludedMask []bool // true = from DA (must validate)
}This allows the execution layer to skip validation for already-validated mempool txs.
| File | Purpose |
|---|---|
core/sequencer/sequencing.go | Core interface |
pkg/sequencers/single/sequencer.go | Hybrid sequencer |
pkg/sequencers/based/sequencer.go | Pure DA sequencer |
pkg/sequencers/common/checkpoint.go | Shared checkpoint logic |
Forced inclusion prevents sequencer censorship:
| File | Purpose |
|---|---|
block/public.go | Exported types and factories |
block/components.go | Component creation |
block/internal/executing/executor.go | Block production |
block/internal/syncing/syncer.go | Sync orchestration |
block/internal/submitting/submitter.go | DA submission |
block/internal/cache/manager.go | Unified cache |
The Executor runs executionLoop():
The Syncer coordinates three workers:
All feed into processHeightEvent() which validates and executes.
Submitter has retry logic with exponential backoff. Status codes:
TooBig - Splits blob into chunksAlreadyInMempool - Skips (duplicate)NotIncludedInBlock - Retries with backoffContextCanceled - Request canceledThe Replayer syncs execution layer from disk:
For detailed component diagrams and state machines, see block-architecture.md.
c449847
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.