Skip to content

added governance-configurable validator voting power cap - #147

Open
alagiz wants to merge 1 commit into
tokenize-x:masterfrom
alagiz:voting-power-cap
Open

alagiz wants to merge 1 commit into
tokenize-x:masterfrom
alagiz:voting-power-cap

Conversation

@alagiz

@alagiz alagiz commented Oct 7, 2026 •

Copy link
Copy Markdown

Summary

Implements mainnet governance proposal 45, which passed on 2026-08-22: a governance-configurable validator voting power cap. Supersedes #108.

  • New param max_voting_power in x/customparams StakingParams. Range 0.01 to 1. Default 1, which disables the cap.
  • Store migration 2 to 3 sets it to 1, so the upgrade changes no behaviour. Governance enables it later with MsgUpdateStakingParams.
  • x/wstaking enforces it on MsgDelegate, MsgBeginRedelegate (destination), MsgCancelUnbondingDelegation and MsgCreateValidator.

How it works

The wrapped handler runs the original staking handler first, then reads the target validator's actual post-state voting power. If it exceeds the cap, the handler returns an error and the message is reverted.

  • Bonded validator: tokens / total bonded
  • Not bonded validator: tokens / (total bonded + tokens), its share if it joins the bonded set
  • Nothing bonded yet (gentxs at genesis): no check

Checking post-state means staking validates the message first and the check uses exact token amounts, including redelegations between bonded and non-bonded validators.

Because enforcement is in the message server, it covers every path that routes through MsgServiceRouter: normal txs, authz, gov, ICA and CosmWasm.

The cap is preventative only. It never trims existing stake and never restricts undelegations. A validator above the cap keeps its stake, it just cannot receive more.

Upgrade

The migration is registered on the module, so it runs in any upgrade handler that calls RunMigrations, whatever the upgrade name. A network that has already executed the v8 upgrade (testnet) needs a new upgrade for the migration to run. Until it runs, staking messages on that network fail.

MsgUpdateStakingParams is now also validated at execution time, so a params proposal submitted before the upgrade (without max_voting_power) fails instead of storing an invalid value.

Known limits

  • PSE distribution delegates through the keeper (x/pse/keeper/distribute.go), not the message server, so it is not capped. It restakes rewards into the delegations delegators already chose.
  • When a not-bonded validator enters a full active set, the evicted validator's stake leaves the bonded total, so the estimate can be off by at most that stake.
  • Like any percentage cap, a validator's share also grows when others undelegate. That is expected and not blocked.
  • Deterministic gas constants are unchanged. The check adds about 1k gas while the cap is disabled and about 6k when enabled.

Tests

  • Unit tests:
    • Each wrapped message at and just over the cap.
    • A validator already over the cap, a jailed validator, nothing bonded.
    • Revert of a rejected tx.
    • Param validation.
    • The migration on the pre-upgrade store encoding.
    • Execution-time validation of params updates.
  • Integration test: a gov proposal sets the cap, then a delegation below it passes and one over it is rejected.
  • Upgrade test: before the upgrade the field is absent, after it equals 1 and min_self_delegation is unchanged.

This change is Reviewable

@alagiz
alagiz requested a review from a team as a code owner October 7, 2026 16:09
@alagiz
alagiz requested review from bashash, metalarm10, okhlopiachyi, yivo and ysv and removed request for a team October 7, 2026 16:09
@metalarm10

Copy link
Copy Markdown
Contributor

Hi @alagiz, thanks for coming back with this and for linking it to proposal 45. We've seen that the proposal passed, and we appreciate the effort you put into the reworked implementation and the tests.

The PR is now under review on our side. We've approved the CI run and will share our feedback once the review is complete.

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.

2 participants