-
Notifications
You must be signed in to change notification settings - Fork 0
Features and Functionality Validator Health Tracking
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
This document describes the Validator Health Tracking system that powers the validators page. It covers the validator table implementation, performance metrics, voting participation rates, commission information, and the validator detail panel. It also documents the validator score badge system, delinquency monitoring, commission change tracking, ranking and sorting, and integration with external validator data sources and real-time updates.
The Validators Page showing the validator table with scores, stake, commission, skip rate, and delinquency status.
The system spans a frontend React application and a Node.js/PostgreSQL backend with Redis caching and scheduled jobs.
graph TB
subgraph "Frontend"
FE_Validators["Validators Page<br/>frontend/src/pages/Validators.jsx"]
FE_Table["ValidatorTable<br/>frontend/src/components/validators/ValidatorTable.jsx"]
FE_Detail["ValidatorDetailPanel<br/>frontend/src/components/validators/ValidatorDetailPanel.jsx"]
FE_Badge["ValidatorScoreBadge<br/>frontend/src/components/validators/ValidatorScoreBadge.jsx"]
FE_Store["validatorStore<br/>frontend/src/stores/validatorStore.js"]
FE_Api["validatorApi<br/>frontend/src/services/validatorApi.js"]
end
subgraph "Backend"
BE_Routes["Validators Routes<br/>backend/src/routes/validators.js"]
BE_Svc["Validators.app Service<br/>backend/src/services/validatorsApp.js"]
BE_DB["Queries & DAL<br/>backend/src/models/queries.js"]
BE_DB_Init["DB Init<br/>backend/src/models/db.js"]
BE_Mig["Migrations<br/>backend/src/models/migrate.js"]
BE_Redis["Redis<br/>backend/src/models/redis.js"]
BE_Cache["Cache Keys<br/>backend/src/models/cacheKeys.js"]
BE_Config["Config<br/>backend/src/config/index.js"]
end
subgraph "Jobs"
JOB_Routine["Routine Poller<br/>backend/src/jobs/routinePoller.js"]
JOB_Critical["Critical Poller<br/>backend/src/jobs/criticalPoller.js"]
end
FE_Validators --> FE_Table
FE_Validators --> FE_Detail
FE_Validators --> FE_Badge
FE_Validators --> FE_Store
FE_Validators --> FE_Api
FE_Api --> BE_Routes
BE_Routes --> BE_Svc
BE_Routes --> BE_DB
BE_Routes --> BE_Redis
BE_Svc --> BE_Config
BE_DB --> BE_DB_Init
BE_DB_Init --> BE_Mig
BE_Routes --> BE_Cache
JOB_Routine --> BE_Svc
JOB_Routine --> BE_DB
JOB_Routine --> BE_Redis
JOB_Critical --> BE_DB
JOB_Critical --> BE_Redis
Diagram sources
- Validators.jsx:1-179
- ValidatorTable.jsx:1-202
- ValidatorDetailPanel.jsx:1-218
- ValidatorScoreBadge.jsx:1-49
- validatorStore.js:1-28
- validatorApi.js:1-8
- validators.js:1-112
- validatorsApp.js:1-388
- queries.js:1-459
- db.js:1-98
- migrate.js:1-160
- redis.js:1-161
- cacheKeys.js:1-50
- index.js:1-68
- routinePoller.js:1-116
- criticalPoller.js:1-108
Section sources
- Validators.jsx:1-179
- validatorApi.js:1-8
- validators.js:1-112
- validatorsApp.js:1-388
- queries.js:1-459
- db.js:1-98
- migrate.js:1-160
- redis.js:1-161
- cacheKeys.js:1-50
- index.js:1-68
- routinePoller.js:1-116
- criticalPoller.js:1-108
- Validator table displays top validators with rank, name, score, stake, commission, skip rate, software version, data center, and delinquency status. Sorting is supported by clicking column headers.
- Validator detail panel shows comprehensive health indicators including performance score, stake, commission, skip rate, software version, data center, Jito status, and delinquency status. It also provides identity and vote pubkeys with copy-to-clipboard support.
- Validator score badge renders a colored, bordered badge representing the validator’s score with thresholds for “Excellent”, “Good”, and “Needs Attention”.
- Frontend store manages validators list, selection, loading state, error state, and sorting preferences.
- Backend routes expose endpoints to fetch top validators and a specific validator detail, with Redis caching and fallback to database.
- Validators.app service normalizes external validator data, enforces rate limits, caches responses, detects commission changes, and exposes helper functions for delinquency and grouping.
- Database schema persists current validator state and historical snapshots, with indexes optimized for score and stake lookups.
- Jobs orchestrate periodic refresh of validator data, detection of commission changes, and alerting.
Section sources
- ValidatorTable.jsx:1-202
- ValidatorDetailPanel.jsx:1-218
- ValidatorScoreBadge.jsx:1-49
- Validators.jsx:1-179
- validatorStore.js:1-28
- validatorApi.js:1-8
- validators.js:1-112
- validatorsApp.js:1-388
- queries.js:159-264
- db.js:1-98
- migrate.js:44-78
- routinePoller.js:1-116
The system integrates external validator data from Validators.app, normalizes it, and persists it to PostgreSQL. Redis caches frequently accessed lists and details. Scheduled jobs keep data fresh and detect significant changes (e.g., commission adjustments). The frontend fetches data via API, sorts and filters locally, and renders the validator table and detail panels.
sequenceDiagram
participant Browser as "Browser"
participant FE as "Frontend Store/API"
participant BE_R as "Validators Route"
participant BE_RA as "Validators.app Service"
participant BE_DB as "PostgreSQL"
participant BE_RD as "Redis"
Browser->>FE : Load Validators page
FE->>BE_R : GET /api/validators/top?limit=50
BE_R->>BE_RD : Try cache VALIDATORS_TOP100
alt Cache hit
BE_RD-->>BE_R : Cached validators
else Cache miss
BE_R->>BE_RA : Fetch validators (rate-limited)
BE_RA-->>BE_R : Normalized validators
BE_R->>BE_DB : Upsert validators (batch)
BE_R->>BE_RD : Cache VALIDATORS_TOP100
end
BE_R-->>FE : Return validators
FE-->>Browser : Render table and detail panel
Diagram sources
- Validators.jsx:24-39
- validatorApi.js:3-7
- validators.js:17-46
- validatorsApp.js:186-209
- queries.js:180-220
- redis.js:75-112
The validator table presents:
- Rank: row index + 1
- Name: validator name or truncated identity pubkey
- Score: rendered via ValidatorScoreBadge
- Stake: compact-formatted SOL amount
- Commission: percentage with color-coded thresholds
- Skip Rate: formatted percentage with color-coded thresholds
- Software Version: version string or placeholder
- Data Center: location or placeholder
- Status: delinquency indicator using StatusIndicator
Sorting is handled by clicking column headers, toggling direction when the same field is selected again.
flowchart TD
Start(["Render ValidatorTable"]) --> Headers["Render table headers<br/>with sort icons"]
Headers --> Rows["Map validators to rows"]
Rows --> RowFields["Render fields:<br/>rank, name, score, stake,<br/>commission, skip_rate,<br/>version, data_center, status"]
RowFields --> ClickHeader{"Header clicked?"}
ClickHeader --> |Yes| HandleSort["onSort(field)"]
ClickHeader --> |No| Hover["Hover effects"]
HandleSort --> UpdateSort["Update sortField/sortDirection"]
UpdateSort --> ReRender["Re-render with sorted data"]
Hover --> End(["Done"])
ReRender --> End
Diagram sources
- ValidatorTable.jsx:35-63
- ValidatorTable.jsx:45-51
- ValidatorTable.jsx:92-196
Section sources
- ValidatorTable.jsx:1-202
- Validators.jsx:53-88
- validatorStore.js:16-23
The detail panel shows:
- Identity avatar/name and vote pubkey with copy action
- Performance Score with progress bar and threshold coloring
- Stake, Commission, Skip Rate with contextual colors
- Software Version with “Up to date” badge
- Data Center and ASN
- Jito MEV status indicator
- Delinquency status with health indicator
flowchart TD
Open(["Open Detail Panel"]) --> Load["Load validator props"]
Load --> Sections["Render metric sections:<br/>score, stake, commission,<br/>skip_rate, version, data_center,<br/>jito, status"]
Sections --> CopyPubkey["Copy pubkey actions"]
CopyPubkey --> Close["Close panel"]
Close --> End(["Done"])
Diagram sources
- ValidatorDetailPanel.jsx:16-62
- ValidatorDetailPanel.jsx:66-190
- ValidatorDetailPanel.jsx:192-213
Section sources
- ValidatorDetailPanel.jsx:1-218
The score badge renders a monospaced, bordered badge with:
- Thresholds: 90+ (green), 70–89 (amber), below 70 (red), missing (gray)
- Rounded score value or placeholder
- Dynamic background, border, and text color based on score
flowchart TD
Input["score prop"] --> CheckNull{"score is null/undefined?"}
CheckNull --> |Yes| Gray["Gray default config"]
CheckNull --> |No| Range{"score >= 90?"}
Range --> |Yes| Green["Green config"]
Range --> |No| Range2{"score >= 70?"}
Range2 --> |Yes| Amber["Amber config"]
Range2 --> |No| Red["Red config"]
Green --> Render["Render badge"]
Amber --> Render
Red --> Render
Gray --> Render
Render --> End(["Done"])
Diagram sources
- ValidatorScoreBadge.jsx:32-48
Section sources
- ValidatorScoreBadge.jsx:1-49
Delinquency status is represented by:
- Column indicator in the table (highlighted border and status icon)
- Dedicated status indicator in the detail panel
- Backend job that periodically refreshes validator lists and writes snapshots, enabling historical tracking
sequenceDiagram
participant Job as "Routine Poller"
participant VA as "Validators.app Service"
participant DB as "PostgreSQL"
participant FE as "Frontend"
Job->>VA : getValidators(100)
VA-->>Job : normalized validators
Job->>DB : upsert validators
Job->>DB : insert top-50 snapshots
FE->>DB : SELECT validators ORDER BY score
DB-->>FE : ranked validators
Diagram sources
- routinePoller.js:21-108
- validatorsApp.js:186-209
- queries.js:180-235
Section sources
- ValidatorTable.jsx:93-104
- ValidatorDetailPanel.jsx:182-188
- routinePoller.js:47-63
- queries.js:270-324
The backend detects commission changes between cached and current validator lists and emits warnings and alerts:
- Detects increases/decreases and records old/new commission
- Emits WebSocket alerts and inserts alert records
- Frontend can surface these alerts via the alerts page
flowchart TD
Fetch["Fetch current validators"] --> Cache["Compare with cached validators"]
Cache --> Changes{"Any commission changes?"}
Changes --> |Yes| Build["Build change records"]
Build --> Alert["Insert alert record"]
Alert --> WS["Emit WebSocket alert"]
Changes --> |No| Done["No action"]
WS --> Done
Diagram sources
- validatorsApp.js:268-298
- routinePoller.js:80-100
- queries.js:340-403
Section sources
- validatorsApp.js:268-298
- routinePoller.js:80-100
- queries.js:340-403
Ranking is driven by score (highest first). The frontend supports:
- Sorting by score, stake, commission, skip rate, and name
- Persistent sort state in the store
- Periodic reloads to keep data fresh
flowchart TD
Init["Initialize store"] --> Load["Fetch top validators"]
Load --> Sort["Sort by selected field/direction"]
Sort --> Render["Render table"]
Render --> UserAction{"User clicks header?"}
UserAction --> |Yes| Toggle["Toggle direction or change field"]
Toggle --> Sort
UserAction --> |No| Timer["Periodic reload"]
Timer --> Load
Diagram sources
- validatorStore.js:3-25
- Validators.jsx:41-88
- Validators.jsx:35-39
Section sources
- validatorStore.js:1-28
- Validators.jsx:41-88
The backend integrates with Validators.app:
- Normalization to internal schema (vote_pubkey, identity_pubkey, name, avatar_url, score, stake_sol, commission, is_delinquent, skip_rate, software_version, data_center, asn, jito_enabled)
- Rate limiting (40 requests per 5 minutes) with queueing
- Module-level cache with TTL
- Optional API key configuration
flowchart TD
Config["Load config"] --> RL["Initialize rate limiter"]
RL --> Request["makeRequest(endpoint, params)"]
Request --> Normalize["normalizeValidator()"]
Normalize --> Cache["Module cache update"]
Cache --> Return["Return normalized data"]
Diagram sources
- validatorsApp.js:115-149
- validatorsApp.js:156-179
- validatorsApp.js:101-109
- index.js:39-43
Section sources
- validatorsApp.js:1-388
- index.js:39-43
Real-time updates are achieved via:
- Frontend polling (every 60 seconds) for the top validators list
- WebSocket broadcasts from backend jobs for network and RPC updates
- Redis caching for fast retrieval and reduced load
sequenceDiagram
participant FE as "Frontend"
participant WS as "WebSocket Server"
participant CR as "Critical Poller"
participant RU as "Routine Poller"
loop Every 30s
CR->>WS : emit network : update
end
loop Every 5min
RU->>WS : emit alert : new (commission changes)
end
FE->>FE : Periodic fetch top validators
Diagram sources
- criticalPoller.js:88-92
- routinePoller.js:96-100
- Validators.jsx:35-39
Section sources
- Validators.jsx:24-39
- criticalPoller.js:88-92
- routinePoller.js:96-100
The system exhibits layered dependencies:
- Frontend depends on backend routes and stores for data and state
- Backend routes depend on Validators.app service, Redis, and database queries
- Jobs depend on Validators.app service and database/Redis for persistence and caching
- Database schema defines primary keys and indexes for efficient lookups
graph LR
FE["Frontend"] --> API["Routes"]
API --> SVC["Validators.app Service"]
API --> DB["PostgreSQL"]
API --> RD["Redis"]
SVC --> CFG["Config"]
DB --> MIG["Migrations"]
JOB1["Routine Poller"] --> SVC
JOB1 --> DB
JOB1 --> RD
JOB2["Critical Poller"] --> DB
JOB2 --> RD
Diagram sources
- Validators.jsx:1-179
- validatorApi.js:1-8
- validators.js:1-112
- validatorsApp.js:1-388
- queries.js:1-459
- migrate.js:1-160
- routinePoller.js:1-116
- criticalPoller.js:1-108
- redis.js:1-161
- index.js:1-68
Section sources
- validatorApi.js:1-8
- validators.js:1-112
- validatorsApp.js:1-388
- queries.js:1-459
- migrate.js:1-160
- routinePoller.js:1-116
- criticalPoller.js:1-108
- redis.js:1-161
- index.js:1-68
- Caching: Redis caches top validators and details with TTLs to reduce latency and external API load.
- Rate Limiting: Validators.app requests are throttled to avoid quota exhaustion.
- Database: Upserts and snapshots are batched; indexes on score and stake optimize ranking queries.
- Frontend: Local sorting and memoization minimize re-renders; polling intervals balance freshness and resource usage.
- Graceful Degradation: Routes fall back to database if Redis is unavailable; jobs continue even if individual steps fail.
[No sources needed since this section provides general guidance]
Common issues and remedies:
- Missing or stale validator data:
- Verify backend configuration for Validators.app API key and base URL.
- Confirm database connectivity and migrations have run.
- Check Redis availability for caching.
- Commission change alerts not appearing:
- Ensure routine poller runs and detects differences between cached and current lists.
- Confirm alert insertion succeeds and WebSocket emits events.
- Slow table rendering:
- Reduce sort field churn; leverage local sorting state.
- Increase polling interval if acceptable for your UX.
- Delinquency status discrepancies:
- Validate backend snapshot writes and frontend queries.
Section sources
- index.js:39-43
- migrate.js:100-139
- redis.js:16-68
- routinePoller.js:21-108
- queries.js:180-235
The Validator Health Tracking system combines external validator data normalization, robust caching, and scheduled ingestion to deliver a responsive, informative interface. The validator table and detail panel present key health signals, while the score badge and delinquency monitoring help users quickly assess trustworthiness. Commission change tracking and real-time updates further support informed delegation decisions.
[No sources needed since this section summarizes without analyzing specific files]