Erigon uses a temporal database architecture separating hot (mutable) from cold (immutable) data.
datadir/
├── chaindata/ # Hot state (MDBX) - recent blocks and state
└── snapshots/
├── domain/ # Latest state values
├── history/ # Historical value changes
├── idx/ # Inverted indices for search
└── accessor/ # Additional lookup indices
- Fork of LMDB optimized for Erigon's access patterns
- Hot database for recent, mutable state
- Tables defined in
kv/tables.go
kv_temporal.go-TemporalDBwraps MDBX + Aggregator- Enables time-travel queries via
GetAsOf(txNum) - Methods:
GetLatest(),HistorySeek(),RangeAsOf(),IndexRange()
aggregator.go- Central hub managing domains and indicesdomain.go- State domain with embedded historyhistory.go- Historical value trackinginverted_index.go- Time-travel indices (key → [txNums])
| Domain | Purpose | Content |
|---|---|---|
| AccountsDomain | Account state | nonce, balance, code hash |
| StorageDomain | Contract storage | key-value slots |
| CodeDomain | Contract bytecode | deployed code |
| CommitmentDomain | Merkle proofs | state root commitments |
Each domain manages:
- Current values (hot, in MDBX)
- Historical snapshots (.seg files)
- Indices for lookups
Sorts data before database insertion to reduce write amplification:
- Collect changes in memory/temp files
- Sort by key
- Batch insert in order
.segfiles store immutable historical data- Downloaded via BitTorrent with WebSeed fallback
- Piece size: 2MB default
- Verification on download
- New state changes → hot MDBX tables
- ETL sorts before insertion
- Periodic snapshots freeze old data
- Cold data compressed for long-term storage