Skip to content

Features and Functionality Validator Health Tracking

dev-mondoshawan edited this page Apr 16, 2026 · 2 revisions

Validator Health Tracking

**Referenced Files in This Document** - [ValidatorTable.jsx](file://frontend/src/components/validators/ValidatorTable.jsx) - [ValidatorDetailPanel.jsx](file://frontend/src/components/validators/ValidatorDetailPanel.jsx) - [ValidatorScoreBadge.jsx](file://frontend/src/components/validators/ValidatorScoreBadge.jsx) - [Validators.jsx](file://frontend/src/pages/Validators.jsx) - [validatorStore.js](file://frontend/src/stores/validatorStore.js) - [validatorApi.js](file://frontend/src/services/validatorApi.js) - [validators.js](file://backend/src/routes/validators.js) - [validatorsApp.js](file://backend/src/services/validatorsApp.js) - [queries.js](file://backend/src/models/queries.js) - [db.js](file://backend/src/models/db.js) - [migrate.js](file://backend/src/models/migrate.js) - [routinePoller.js](file://backend/src/jobs/routinePoller.js) - [criticalPoller.js](file://backend/src/jobs/criticalPoller.js) - [redis.js](file://backend/src/models/redis.js) - [cacheKeys.js](file://backend/src/models/cacheKeys.js) - [index.js](file://backend/src/config/index.js)

Table of Contents

  1. Introduction
  2. Project Structure
  3. Core Components
  4. Architecture Overview
  5. Detailed Component Analysis
  6. Dependency Analysis
  7. Performance Considerations
  8. Troubleshooting Guide
  9. Conclusion

Introduction

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.

Validators Page Screenshot

Validators Page

The Validators Page showing the validator table with scores, stake, commission, skip rate, and delinquency status.

Project Structure

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
Loading

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

Core Components

  • 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

Architecture Overview

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
Loading

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

Detailed Component Analysis

Validator Table Implementation

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
Loading

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

Validator Detail Panel

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"])
Loading

Diagram sources

  • ValidatorDetailPanel.jsx:16-62
  • ValidatorDetailPanel.jsx:66-190
  • ValidatorDetailPanel.jsx:192-213

Section sources

  • ValidatorDetailPanel.jsx:1-218

Validator Score Badge System

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"])
Loading

Diagram sources

  • ValidatorScoreBadge.jsx:32-48

Section sources

  • ValidatorScoreBadge.jsx:1-49

Delinquency Monitoring

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
Loading

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

Commission Change Tracking

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
Loading

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

Validator Ranking and Filtering

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
Loading

Diagram sources

  • validatorStore.js:3-25
  • Validators.jsx:41-88
  • Validators.jsx:35-39

Section sources

  • validatorStore.js:1-28
  • Validators.jsx:41-88

Integration with External Validator Data Sources

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"]
Loading

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 Performance Updates

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
Loading

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

Dependency Analysis

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
Loading

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

Performance Considerations

  • 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]

Troubleshooting Guide

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

Conclusion

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]

Clone this wiki locally