Epoch Processing
An epoch is a periodic recalculation that runs Yuma Consensus and distributes rewards. Epochs are part of block execution, triggered by each subnet's tempo parameter.
Step 1: Check Tempo Trigger
Each subnet has a Tempo parameter that determines how often its epoch runs. At each block, the runtime checks whether this
subnet's epoch is due. Subnets are staggered by their network ID so they don't all run in the same
block:
The netuid offset ensures subnets with the same tempo run in different blocks,
spreading the computation load. The + 1 adjustments prevent division-by-zero edge cases.
Common tempo values:
| Tempo | Interval | Use Case |
|---|---|---|
| 10 | ~2 minutes | Fast-updating subnets |
| 100 | ~20 minutes | Standard subnets |
| 360 | ~72 minutes | Slow, stable subnets |
| 7200 | ~24 hours | Root network (SN0) |
Block time is ~12 seconds, so tempo 100 = ~20 minutes between epochs.
Step 2: Read Current State
When an epoch triggers, the runtime reads all relevant state from storage:
| Storage Item | Purpose |
|---|---|
Weights | Validator weight assignments (sparse matrix) |
Bonds | Previous epoch's bond matrix |
TotalStake | TAO staked to each hotkey |
LastUpdate | Last block each neuron set weights |
ValidatorPermit | Which neurons can validate |
BlockAtRegistration | When each neuron registered |
Step 3: Filter Active Participants
Before computing consensus, several filters are applied to determine which neurons participate:
| Filter | What It Does | Storage Reference |
|---|---|---|
| Activity Cutoff | Neurons who haven't set weights within activity_cutoff blocks are inactive | ActivityCutoff |
| Stake Threshold | Validators below minimum stake don't count | NominatorMinRequiredStake |
| Validator Permits | Only permitted validators' weights count | ValidatorPermit |
| Outdated Weights | Weights to neurons registered after weight-setting are masked | — |
| Self-Weights | Diagonal (self-voting) is always masked out | — |
// Simplified filtering logic
let active = last_update.map(|block|
current_block - block < activity_cutoff
);
let filtered_stake = stake.map(|s|
if s < min_stake { 0 } else { s }
);
// Mask non-validators and self-weights
weights = mask_rows(&validator_forbids, &weights);
weights = mask_diag(&weights);Step 4: Run Yuma Consensus
With filtered inputs, the Yuma Consensus algorithm runs:
- Compute consensus: Stake-weighted median per miner
- Clip weights: Limit all weights to consensus values
- Calculate ranks: Stake-weighted sum of clipped weights
- Normalize to incentive: Miner emission shares
- Update bonds: EMA of weight × stake products
- Calculate dividends: Validator shares from bond positions
See Yuma Consensus for the detailed algorithm.
Step 5: Compute Emission Distribution
The epoch determines how the subnet's accumulated emission is distributed:
| Recipient | Source | Pending Storage |
|---|---|---|
| Miners | Incentive[j] × alpha emission | PendingServerEmission |
| Validators | Dividends[i] × alpha emission | PendingValidatorEmission |
| Owner | Owner cut percentage | PendingOwnerCut |
| Root Divs | Root network validators | PendingRootAlphaDivs |
Emission accumulates in pending storage items and is released to wallets when the epoch completes. See Emission Mechanics for the full flow.
Step 6: Write Results to Storage
Finally, all computed values are written back to on-chain storage:
| Storage Item | Updated Value |
|---|---|
Consensus | Consensus weights per miner (u16) |
Incentive | Normalized miner incentive scores (u16) |
Dividends | Normalized validator dividend scores (u16) |
Bonds | Updated EMA bonds matrix |
ValidatorTrust | Trust scores per validator (u16) |
Emission | Combined emission per neuron |
Active | Activity status per neuron |
ValidatorPermit | Updated permits (top-k by stake) |
Yuma3 Variant
Yuma3 is an enhanced epoch algorithm enabled per-subnet via the Yuma3On flag.
Key Differences
| Feature | Standard Yuma | Yuma3 |
|---|---|---|
| EMA Alpha | Fixed per subnet | Dynamic "Liquid Alpha" per weight |
| Bond Normalization | Column normalization | Incentive-weighted normalization |
| Dividend Formula | bonds × incentive | Modified formula with stake weighting |
Liquid Alpha
In Yuma3, the EMA alpha for bond updates is dynamic. Weights closer to consensus get faster bond accumulation:
// Liquid alpha: consensus-aligned weights bond faster
fn liquid_alpha(weight, consensus, bond, alpha_low, alpha_high) {
let diff = if weight >= bond {
weight - consensus // buying position
} else {
bond - weight // selling position
};
// Sigmoid: closer to 0 diff = higher alpha
let sigmoid = 1 / (1 + exp(-steepness * (diff - 0.5)));
alpha_low + sigmoid * (alpha_high - alpha_low)
}The alpha range is configured by AlphaValues (which stores both the low and high bounds).
When to Use Yuma3
Yuma3 is designed for subnets using dTAO where the liquid alpha mechanism smooths bond changes as validators adjust weights. It rewards consensus-aligned validators with faster bond accumulation, providing more nuanced incentive alignment.
Performance Considerations
Epoch processing must complete within block time constraints (~12 seconds for all subnets combined). Optimizations include:
- Sparse matrices: Weights and bonds are stored as sparse vectors (
Vec<(uid, u16)>) to handle subnets with many neurons - Fixed-point arithmetic: All computations use
I32F32fixed-point to avoid floating-point non-determinism across nodes - Efficient median: Pivot-based search instead of full sorting for the weighted median calculation
Epoch Events
The epoch emits events that can be observed on-chain:
IncentiveAlphaEmittedToMiners: Server emission per miner
These events allow indexers and explorers to track emission distribution without parsing storage changes.
Related Pages
- Yuma Consensus: The core algorithm run during epochs
- Emission Mechanics: How emission flows to neurons
- Block Execution: Where epochs fit in the block lifecycle
- Glossary: Definitions for tempo, epoch, bonds, etc.
Source Code
Epoch processing is implemented in:
pallets/subtensor/src/epoch/run_epoch.rsepoch_mechanism()at line 559: Main epoch functionepoch_dense_mechanism()at line 146: Dense matrix variant (testing)compute_bonds()at line 1258: Bond computationcompute_ema_bonds_normal()at line 1222: Standard EMA bonds