Skip to content

Conversation

@konrad0960
Copy link

Description

Voting power feature
Purpose: Track validator voting power using an Exponential Moving Average (EMA) of their stake over time, preventing sudden stake changes from immediately affecting governance weight.

Key Components:

  • EMA-based voting power calculation (updated each epoch)
  • Per-subnet enable/disable with 14-day grace period
  • Configurable alpha parameter for EMA smoothness
  • Voting power transfers on hotkey swap
  • EVM precompile for smart contract access

Extrinsics: enable_voting_power_tracking, disable_voting_power_tracking, sudo_set_voting_power_ema_alpha

Storage: VotingPower, VotingPowerTrackingEnabled, VotingPowerDisableAtBlock, VotingPowerEmaAlpha

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Other (please describe):

Checklist

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have run ./scripts/fix_rust.sh to ensure my code is formatted and linted correctly
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Additional Notes

I’ve attempted to run the VotingPower precompile EVM tests locally but encountered multiple Node.js compatibility issues with the polkadot-api dependencies.
Being unable to resolve them I want to give CI a try
That being said the unit tests written cover the core logic.

@konrad0960 konrad0960 changed the title commit Cargo.lock Voting Power EMA Dec 1, 2025
@open-junius
Copy link
Contributor

Enabled the CI process, to check if EVM test is runnable for PR.

@konrad0960
Copy link
Author

Enabled the CI process, to check if EVM test is runnable for PR.

can we try again?


// Only remove if they previously had voting power ABOVE threshold and it decayed below.
// This allows new validators to build up voting power from 0 without being removed.
if new_ema < min_stake && previous_ema >= min_stake {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the new validator has just built the previous_ema above min_stake and new_ema dropped below min_stake because of noise, the ema will be reset to 0. Is that desired behavior?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn’t thought of this edge case
I guess we can then decide to reset to 0 when it gets below 90% of required threshold?

@konrad0960 konrad0960 force-pushed the voting-power-feature branch from 2a22ace to e541d53 Compare January 8, 2026 22:39
@konrad0960 konrad0960 requested a review from gztensor January 8, 2026 22:40
StakeWeight::<T>::insert(netuid, stake_weight);

// Update voting power EMA for all validators on this subnet
Self::update_voting_power_for_subnet(netuid, output);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great update! Please one little change here: Call this function before (or after) calling persist_netuid_epoch_terms in epoch_with_mechanisms to avoid confusion that persist_netuid_epoch_terms also updates voting power.

let new_ema = Self::calculate_voting_power_ema(current_stake, previous_ema, alpha);

// Use 90% of min_stake as removal threshold (hysteresis to prevent noise-triggered removal)
let removal_threshold = min_stake.saturating_mul(9) / 10;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use safe_div(10u64) or CI will fail


// Only remove if they previously had voting power ABOVE threshold and decayed significantly below.
// This allows new validators to build up voting power from 0 without being removed.
if new_ema < removal_threshold && previous_ema >= min_stake {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If alpha is slow enough, we'll probably never hit this condition.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So far the requirements didn't specify how fast removal should happen in case stake is drastically dropped.
Hard rules on having voting power removed immediately if stake drops below threshold could be easily gamed by dropping stake just near the threshold.
Probably assymetric EMA could solve this? Introducing alpha_up and alpha_down whereas alpha_down should default to faster decay in example 0.5?

// Iterate over epoch output using pre-calculated values
for (hotkey, terms) in epoch_output.iter() {
// Only validators (with vpermit) get voting power, not miners
if terms.new_validator_permit {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if a neuron gets deregistered? We don't have it in epoch terms, but we've got to garbage-collect their voting power at some point, probably not immediately.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we got clear_voting_power_for_deregistered_hotkeys() just at the end of this function

@konrad0960 konrad0960 requested a review from gztensor January 9, 2026 21:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants