Validator Engine
The Validator Engine is the core orchestration component of the SN106 Bittensor subnet validator system. It implements a scheduled execution cycle that collects multi-chain NFT position data, calculates emission weights based on concentrated liquidity positions, and submits normalized weights to the Subtensor chain every 20 minutes.
This document covers the main validator orchestration logic, EMA weight smoothing, and distribution policy enforcement. For details about the actual weight submission mechanism, see Weight Submission System. For multi-chain data collection specifics, see Multi-Chain Integration.
Core Execution Cycle
Section titled “Core Execution Cycle”The validator engine operates on a scheduled interval defined by VALIDATOR_INTERVAL_MINUTES and follows a structured pipeline from data collection through weight submission.
Main Orchestration Flow
Section titled “Main Orchestration Flow”graph TD
START["runValidator()"] --> INIT["subtensorClient.initialize()"]
INIT --> CHAINS["CONFIG.getEnabledChains()"]
CHAINS --> HOTKEYS["getHotkeyToUidMap()"]
HOTKEYS --> POSITIONS["getAllNFTPositions()"]
POSITIONS --> TICKS["getCurrentTickPerPool()"]
TICKS --> ALPHAS["getSubnetAlphaPrices()"]
ALPHAS --> POOLW["calculatePoolWeightsWithReservedPools()"]
POOLW --> EMISSIONS["calculatePoolwiseNFTEmissions()"]
EMISSIONS --> AGGREGATE["Aggregate per-miner emissions"]
AGGREGATE --> POLICY["Distribution policy check"]
POLICY --> EMA["EMA weight smoothing"]
EMA --> SUBMIT["setWeightsOnSubtensor()"]
SUBMIT --> END["Complete run"]
POLICY --> |"hasPositiveEmission"| INRANGE["In-range miners policy"]
POLICY --> |"All zero emissions"| OUTRANGE["Out-of-range uniform policy"]
INRANGE --> EMA
OUTRANGE --> SUBMIT
Sources: validator/index.ts:17-163
Scheduler Implementation
Section titled “Scheduler Implementation”The validator engine runs continuously using setInterval with configurable timing:
| Component | Implementation | Configuration |
|---|---|---|
| Main Loop | setInterval(runValidator, ...) | VALIDATOR_INTERVAL_MINUTES |
| Initial Run | runValidator() immediate call | Runs once on startup |
| Graceful Shutdown | SIGINT/SIGTERM handlers | Calls subtensorClient.shutdown() |
Sources: validator/index.ts:179-181 , validator/index.ts:166-176
Data Collection Phase
Section titled “Data Collection Phase”The validator engine coordinates data collection across multiple blockchain networks and Bittensor chain state.
Multi-Chain Data Gathering
Section titled “Multi-Chain Data Gathering”graph LR
HOTKEYS["getHotkeyToUidMap()"] --> FILTER["Filter enabled chains"]
FILTER --> SOL["getAllNFTPositions()"]
SOL --> TICKS["getCurrentTickPerPool()"]
TICKS --> ALPHAS["getSubnetAlphaPrices()"]
SOL --> SOLPOS["Solana NFT positions"]
SOL --> ETHPOS["Ethereum NFT positions"]
SOL --> BASEPOS["Base NFT positions"]
TICKS --> SOLTICK["Solana tick data"]
TICKS --> ETHTICK["Ethereum tick data"]
TICKS --> BASETICK["Base tick data"]
ALPHAS --> SUBNET_ALPHAS["Subnet alpha prices map"]
Sources: validator/index.ts:62-86 , validator/chains/index.ts
Data Pipeline Sequence
Section titled “Data Pipeline Sequence”- Hotkey Mapping:
getHotkeyToUidMap(wsUrl, netuid)retrieves the mapping between miner hotkeys and their UID positions in the subnet - Position Collection:
getAllNFTPositions(hotkeys)aggregates NFT positions across all enabled chains - Tick Data:
getCurrentTickPerPool()fetches current market tick data for all pools - Alpha Prices:
getSubnetAlphaPrices(wsUrl, filteredSubnetIds)retrieves subnet performance metrics from Subtensor
Sources: validator/index.ts:62-86
EMA Weight Management
Section titled “EMA Weight Management”The validator engine implements Exponential Moving Average (EMA) smoothing to prevent sudden weight fluctuations and provide stability in reward distribution.
EMA State Persistence
Section titled “EMA State Persistence”graph TD
GLOBAL["global.__sn106EmaWeights"] --> CHECK{"EMA enabled?"}
CHECK --> |"CONFIG.VALIDATOR.USE_EMA"| CALCULATE["updateEma()"]
CHECK --> |"Disabled"| DIRECT["Direct weight assignment"]
CALCULATE --> ALPHA["EMA_ALPHA * current"]
CALCULATE --> PREV["(1 - EMA_ALPHA) * previous"]
ALPHA --> COMBINE["Combined EMA value"]
PREV --> COMBINE
COMBINE --> EPSILON["Apply EMA_EPSILON threshold"]
EPSILON --> PERSIST["global.__sn106EmaWeights = nextEma"]
PERSIST --> ASSIGN["Assign eligible weights"]
DIRECT --> ASSIGN
Sources: validator/index.ts:32-59 , validator/index.ts:124-146
EMA Algorithm Implementation
Section titled “EMA Algorithm Implementation”The EMA calculation uses a configurable alpha parameter and epsilon threshold:
| Parameter | Default | Purpose |
|---|---|---|
EMA_ALPHA | 0.3 | Controls smoothing rate (higher = more responsive) |
EMA_EPSILON | 0.001 | Minimum threshold for non-zero weights |
The updateEma function implements the formula: next[k] = EMA_ALPHA * current + (1 - EMA_ALPHA) * previous
Sources: validator/index.ts:47-59
Distribution Policy Enforcement
Section titled “Distribution Policy Enforcement”The validator engine enforces a two-tier distribution policy based on whether miners have in-range or out-of-range liquidity positions.
Policy Decision Logic
Section titled “Policy Decision Logic”graph TD
EMISSIONS["minerWeightsRaw"] --> CHECK{"hasPositiveEmission?"}
CHECK --> |"true"| INRANGE["In-range miners policy"]
CHECK --> |"false"| OUTRANGE["Out-of-range miners policy"]
INRANGE --> ZERO["Set all UIDs to 0"]
ZERO --> POSITIVE["Assign weights to positive emissions only"]
POSITIVE --> EMA_CHECK{"EMA enabled?"}
EMA_CHECK --> |"true"| EMA_APPLY["Apply EMA to eligible miners"]
EMA_CHECK --> |"false"| DIRECT_ASSIGN["Direct assignment"]
OUTRANGE --> UNIFORM["Fallback to uniform distribution"]
UNIFORM --> SETWEIGHTS["setWeightsOnSubtensor()"]
EMA_APPLY --> SETWEIGHTS
DIRECT_ASSIGN --> SETWEIGHTS
Sources: validator/index.ts:113-157
Policy Rules Implementation
Section titled “Policy Rules Implementation”- Positive Emission Check:
Object.values(minerWeightsRaw).some(v => isFinite(v) && v > 0) - UID Initialization: All known UIDs from
hotkeyToUidare set to 0 - Selective Assignment: Only miners with
isFinite(w) && w > 0receive weights - Uniform Fallback: When no positive emissions exist,
setWeightsOnSubtensorhandles uniform distribution
Sources: validator/index.ts:113-151
Integration Architecture
Section titled “Integration Architecture”The validator engine integrates with multiple system components through well-defined interfaces.
Component Dependencies
Section titled “Component Dependencies”graph TD
VALIDATOR["validator/index.ts"] --> API["validator/api.ts"]
VALIDATOR --> CHAINS["validator/chains/index.ts"]
VALIDATOR --> EMISSIONS["validator/calculations/emissions.ts"]
VALIDATOR --> UTILS_BT["utils/bittensor.ts"]
VALIDATOR --> UTILS_POOL["utils/poolWeights.ts"]
VALIDATOR --> UTILS_WEIGHTS["utils/setWeights.ts"]
VALIDATOR --> CONFIG["config/environment.ts"]
VALIDATOR --> LOGGER["utils/logger.ts"]
API --> SUBTENSOR["subtensorClient singleton"]
CHAINS --> SOL_CHAIN["chains/solana.ts"]
CHAINS --> ETH_CHAIN["chains/ethereum.ts"]
CHAINS --> BASE_CHAIN["chains/base.ts"]
EMISSIONS --> POOL_CALC["Pool-wise emission calculation"]
UTILS_BT --> HOTKEY_MAP["Hotkey-to-UID mapping"]
UTILS_POOL --> RESERVED_SHARE["Reserved share logic"]
UTILS_WEIGHTS --> WEIGHT_SUBMISSION["Subtensor weight submission"]
Sources: validator/index.ts:8-15 , docs/ARCHITECTURE.md:25-47
Configuration Integration
Section titled “Configuration Integration”The validator engine depends on typed configuration from the environment system:
| Configuration Section | Usage | Source |
|---|---|---|
CONFIG.SUBTENSOR | WebSocket URL, hotkey URI, netuid | validator/index.ts:25-27 |
CONFIG.VALIDATOR | EMA settings, interval timing | validator/index.ts:34-35 |
CONFIG.getEnabledChains() | Multi-chain filtering | validator/index.ts:21-22 |
Sources: validator/index.ts:21-35 , config/environment.ts
Error Handling and Resilience
Section titled “Error Handling and Resilience”The validator engine implements comprehensive error handling to ensure continuous operation despite individual component failures.
Graceful Degradation Strategy
Section titled “Graceful Degradation Strategy”- Chain Failures: Individual chain failures don’t stop the entire validation cycle
- Data Validation: All numeric values are checked with
isFinite()before use - Fallback Policies: Out-of-range scenarios trigger uniform weight distribution
- Singleton Management:
subtensorClientprovides managed WebSocket connections with proper shutdown
Sources: validator/index.ts:64-66 , validator/index.ts:83-85 , validator/index.ts:166-176