A comprehensive tool for monitoring and visualizing client diversity in the SSV (Secret Shared Validators) network. This project helps ensure network health by tracking the distribution of different SSV client implementations.
This project consists of two main components:
- SSV Identifier (Rust): Network crawler that discovers SSV peers, identifies client types (Anchor, GoSSV, Unknown), and stores data in SQLite
- Dashboard (Node.js): Web-based visualization dashboard for real-time client diversity metrics
┌─────────────────────────────────────────────────────────────────┐
│ SSV Network │
│ (Distributed validators using libp2p) │
└────────────────────────┬────────────────────────────────────────┘
│ discovers & handshakes
▼
┌─────────────────────────────────────────────────────────────────┐
│ SSV Identifier (Rust Crawler) │
│ • Discovers peers via discv5 │
│ • Performs libp2p handshakes │
│ • Identifies client types & versions │
│ • Tracks subnet membership │
│ • Records network snapshots │
└────────────────────────┬────────────────────────────────────────┘
│ writes to
▼
┌─────────────────────────────────────────────────────────────────┐
│ SQLite Database (clients.db) │
│ • peers table │
│ • subnet_membership table │
│ • network_snapshots table │
└────────────────────────┬────────────────────────────────────────┘
│ reads from (read-only)
▼
┌─────────────────────────────────────────────────────────────────┐
│ Dashboard (Node.js + Nginx) │
│ • REST API for metrics │
│ • Real-time visualizations │
│ • Auto-refresh every 30s │
│ • Supermajority warnings │
└────────────────────────┬────────────────────────────────────────┘
│ displays to
▼
┌─────────────────────────────────────────────────────────────────┐
│ Browser (Users) │
│ http://localhost (or your domain) │
└─────────────────────────────────────────────────────────────────┘
- Peer Discovery: Uses discv5 to discover SSV network peers
- Client Identification: Detects Anchor and GoSSV clients via handshake analysis
- Version Tracking: Extracts semantic versions from client strings
- Subnet Monitoring: Tracks which subnets each peer participates in
- Historical Snapshots: Periodic network composition snapshots
- Persistent Storage: SQLite database for efficient querying
- Client Distribution: Horizontal bar chart showing Anchor vs GoSSV vs Unknown
- Version Analytics: Top 10 versions for each client type
- Historical Trends: 24-hour time-series of client diversity
- Network Statistics: Total peers, active subnets, identification rates
- Subnet Participation: Peer distribution across top 20 subnets
- Supermajority Alerts: Warning when single client exceeds 66%
- Auto-Refresh: Updates every 30 seconds
- Responsive Design: Works on desktop, tablet, and mobile
- Rust: >= 1.75.0
- Cargo: Latest version
- System: Linux, macOS, or Windows
- Network: Access to SSV network
- Node.js: >= 18.0.0
- npm: Latest version
- Docker (optional): For containerized deployment
- Docker Compose (optional): For orchestration
git clone <repository-url>
cd ssv-client-diversity
The identifier discovers peers and populates the database.
# Navigate to identifier directory
cd ssv-identifier
# Build the project
cargo build --release
# Run the identifier
cargo run --release
The identifier will:
- Start discovering SSV network peers
- Perform handshakes to identify client types
- Store data in
~/.ssv-identifier/clients.db - Take periodic network snapshots
- Log activity to console and files
Let it run for at least 10-15 minutes to collect initial data before starting the dashboard.
# Open a new terminal
cd dashboard/app
# Install dependencies
npm install
# Start the development server
npm run dev
# Dashboard available at http://localhost:3000
# Navigate to dashboard directory
cd dashboard
# Build and start containers
docker-compose up -d
# Dashboard available at http://localhost
View logs:
docker-compose logs -f
Stop containers:
docker-compose down
Open your browser and navigate to:
- Development: http://localhost:3000
- Docker: http://localhost
You should see real-time metrics and visualizations of the SSV network client diversity!
The identifier can be configured via command-line arguments or environment variables.
# View all available options
cargo run --release -- --help
# Run with custom database path
cargo run --release -- --db-path /custom/path/ssv-peers.db
# Run with verbose logging
RUST_LOG=debug cargo run --release
# Run with custom snapshot interval
cargo run --release -- --snapshot-interval 600 # 10 minutes
Create a .env file in ssv-identifier/:
RUST_LOG=info
DATABASE_PATH=./data/ssv-peers.db
SNAPSHOT_INTERVAL=300
The identifier connects to the SSV mainnet by default. Network parameters are defined in ssv-identifier/src/config.rs.
Create a .env file in dashboard/app/:
NODE_ENV=production
PORT=3000
SSV_DB_PATH=~/.ssv-identifier/clients.db
CACHE_REFRESH_INTERVAL=60000
Edit dashboard/docker-compose.yml to customize:
dashboard:
environment:
- PORT=3000
- SSV_DB_PATH=/app/data/clients.db
- CACHE_REFRESH_INTERVAL=60000 # 60 seconds
volumes:
# Mount custom data directory if identifier uses --data-dir
- /custom/path:/app/data:ro
ports:
- "8080:3000" # Change external port if needed
Edit dashboard/nginx/nginx.conf to adjust:
- Rate limiting
- Port mappings
- SSL/TLS settings
- Caching policies
- Run identifier as a system service:
# Create systemd service file
sudo nano /etc/systemd/system/ssv-identifier.service
[Unit]
Description=SSV Client Diversity Identifier
After=network.target
[Service]
Type=simple
User=ssv
WorkingDirectory=/opt/ssv-client-diversity/ssv-identifier
ExecStart=/opt/ssv-client-diversity/ssv-identifier/target/release/ssv-identifier
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
# Enable and start service
sudo systemctl enable ssv-identifier
sudo systemctl start ssv-identifier
sudo systemctl status ssv-identifier
- Run dashboard with Docker:
cd dashboard
docker-compose up -d
- Set up reverse proxy with SSL (optional but recommended):
# Install nginx
sudo apt install nginx certbot python3-certbot-nginx
# Configure nginx
sudo nano /etc/nginx/sites-available/ssv-dashboard
# Add SSL certificate
sudo certbot --nginx -d your-domain.com
# View logs
tail -f ssv-identifier/logs/ssv-identifier.log
# Check database
sqlite3 ssv-identifier/data/ssv-peers.db "SELECT COUNT(*) FROM peers;"
# View recent snapshots
sqlite3 ssv-identifier/data/ssv-peers.db "SELECT * FROM network_snapshots ORDER BY timestamp DESC LIMIT 10;"
# Docker logs
docker-compose logs -f dashboard
# Health check
curl http://localhost/health
# API test
curl http://localhost/api/stats
# Open SQLite console (default location)
sqlite3 ~/.ssv-identifier/clients.db
# Useful queries
SELECT COUNT(*) FROM peers;
SELECT client_type, COUNT(*) FROM peers GROUP BY client_type;
SELECT * FROM peers ORDER BY last_seen DESC LIMIT 10;
SELECT * FROM network_snapshots ORDER BY timestamp DESC LIMIT 5;
# Create backup
sqlite3 ~/.ssv-identifier/clients.db ".backup 'backup.db'"
# Or use cp (stop identifier first)
cp ~/.ssv-identifier/clients.db ~/.ssv-identifier/clients.db.backup
# Stop identifier
# Delete database file
rm ~/.ssv-identifier/clients.db
# Restart identifier (will create new database)
cd ssv-identifier
cargo run --release
cd ssv-identifier
# Debug build
cargo build
# Release build (optimized)
cargo build --release
# Run tests
cargo test
# Check code
cargo check
# Format code
cargo fmt
# Lint code
cargo clippy
cd dashboard/app
# Install dependencies
npm install
# Development mode (auto-reload)
npm run dev
# Production mode
npm start
# Build Docker image
cd ..
docker build -t ssv-dashboard .
ssv-client-diversity/
├── ssv-identifier/ # Rust network crawler
│ ├── src/
│ │ ├── main.rs # Entry point
│ │ ├── network.rs # Network discovery
│ │ ├── database.rs # SQLite operations
│ │ ├── handshake.rs # Client identification
│ │ ├── metrics.rs # Network metrics
│ │ └── ...
│ ├── Cargo.toml # Rust dependencies
│ └── data/ # Optional custom data directory
│ └── clients.db # SQLite database (default: ~/.ssv-identifier/clients.db)
├── dashboard/ # Node.js dashboard
│ ├── app/
│ │ ├── server.js # Express API
│ │ ├── package.json # Node dependencies
│ │ ├── public/ # Static assets
│ │ │ ├── css/style.css
│ │ │ └── js/dashboard.js
│ │ └── views/
│ │ └── index.html # Main page
│ ├── nginx/
│ │ └── nginx.conf # Reverse proxy
│ ├── Dockerfile # Container image
│ ├── docker-compose.yml # Orchestration
│ └── README.md # Dashboard docs
└── README.md # This file
- Check internet connectivity
- Verify firewall allows UDP traffic
- Ensure ports are not blocked
- Stop any other processes accessing the database
- Ensure only one identifier instance is running
- Check file permissions
- Wait longer (discovery can take 5-10 minutes)
- Check network configuration
- Verify you're connected to the correct network
- Ensure identifier is running and has created database
- Check database path in environment variables
- Verify file permissions (database must be readable)
- Check dashboard logs for errors
- Run identifier first to create database at
~/.ssv-identifier/clients.db - Verify path:
ls -la ~/.ssv-identifier/clients.db - For Docker: ensure
$HOMEenvironment variable is set correctly - Check Docker volume mounts:
docker-compose configto see resolved paths
- Check browser console for JavaScript errors
- Verify Chart.js CDN is accessible
- Clear browser cache
- Ensure database has data
# Check logs
docker-compose logs dashboard
# Rebuild containers
docker-compose down
docker-compose build --no-cache
docker-compose up -d
# Check permissions
ls -la ../ssv-identifier/data/ssv-peers.db
- Adjust discovery parameters
- Reduce snapshot frequency
- Consider rate limiting
- Increase cache interval
- Reduce historical data range
- Limit concurrent requests
- Check database query performance
- Verify caching is working
- Consider adding more database indexes
See dashboard/README.md for complete API documentation.
Quick reference:
GET /api/stats- Current network statisticsGET /api/client-versions- Version distributionsGET /api/historical-trends?hours=24- Time-series dataGET /api/subnet-stats- Subnet participationGET /health- Health check
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Rust: Follow Rust style guidelines, run
cargo fmtandcargo clippy - JavaScript: Use consistent formatting, add comments for complex logic
- Testing: Add tests for new features
- Documentation: Update README for significant changes
MIT License - see LICENSE file for details.
- SSV Network team for the protocol
- Ethereum client diversity initiatives for inspiration
- libp2p and discv5 communities
- Chart.js for visualizations
- SSV Identifier: ssv-identifier/
- Dashboard: dashboard/README.md
- Design Document: DESIGN.md
- SSV Network: https://ssv.network
- GitHub Issues: Report issues here
- Discord: Join SSV Discord
Future enhancements:
- Real-time WebSocket updates for dashboard
- Prometheus metrics export
- Alerting system (email/Slack)
- Geographic distribution tracking
- Historical data export (CSV/JSON)
- Mobile app
- Multi-network support
- Advanced filtering and search
The identifier typically discovers 50-100 peers within 10-15 minutes. For comprehensive data, let it run for 1-2 hours.
Yes, but they should use different database files or run on different machines to avoid conflicts.
No, the dashboard is public by design for transparency. Add authentication via reverse proxy if needed.
The database typically grows to 50-100MB after several days. Plan for 500MB-1GB for long-term operation.
Yes! The Docker setup works with AWS, GCP, Azure, DigitalOcean, and other cloud providers.
git pull origin main
cd ssv-identifier && cargo build --release
cd ../dashboard && docker-compose down && docker-compose up -d --build
Built with ❤️ for the SSV Network community