Skip to content

Conviction v2 — locked-alpha governance, perpetual locks, exponential decay

Based on Subtensor PR #2658.

Conviction is Bittensor’s governance mechanism that ties voting power to long-term commitment. When you lock alpha tokens to a subnet, you earn conviction — a measure of your stake’s weight in governance decisions and subnet ownership.

Conviction exists to:

  • Reward long-term alignment over short-term speculation
  • Provide subnet governance stability
  • Enable subnet ownership transitions through the subnet king mechanism
  • Create skin-in-the-game for validators and subnet owners

Version 2 fundamentally redesigned the system: locks are now perpetual by default, subnet owners receive instant conviction, and the unlock queue was eliminated in favor of exponential decay.

To earn conviction, you lock alpha tokens using the lock_stake extrinsic:

  • One lock per coldkey per subnet — You can only have a single active lock targeting one hotkey on each subnet.
  • Lock to a hotkey — Your locked alpha is associated with a specific hotkey on that subnet. This is typically the subnet owner’s hotkey, or the hotkey of someone building conviction to challenge for subnet ownership.
  • Top-ups must match — Additional locks to the same subnet must target the same hotkey; you can’t split locks across multiple hotkeys.
  • Perpetual by default — Locked mass stays constant indefinitely, allowing conviction to grow toward 100%.
  • Optional decay — Call set_perpetual_lock(false) to enable exponential decay if you want to eventually unstake.

When you lock alpha without toggling decay, your lock is perpetual:

  • locked_mass remains constant forever
  • conviction grows exponentially from 0 toward locked_mass
  • Conviction asymptotically approaches 99% after 1 year, 99.9%+ after 2 years
  • Cannot unstake — perpetual locks stay locked unless you toggle to decaying mode

After calling set_perpetual_lock(false), your lock begins exponential decay:

  • locked_mass decays with UnlockRate (158.6 day time constant)
  • conviction follows a coupled decay/growth formula driven by MaturityRate (79.3 day time constant)
  • After 365 days, 90% of locked mass has decayed (by design)
  • You can unstake the difference between your original lock and current locked_mass

Subnet owners receive special treatment:

  • Instant conviction — conviction equals locked_mass immediately (no growth period)
  • Auto-locked owner cut — The owner’s share of emissions is automatically locked each block, building conviction continuously
  • Owner locks are perpetual by default but can opt into decay
ParameterValue (blocks)Value (days)Meaning
UnlockRate1,142,108158.6 (τ)Time constant for locked mass decay. 90% decays in 365 days.
MaturityRate571,05479.3 (τ)Time constant for conviction growth. 2× faster than unlock rate. Half-life: 55 days.
Half-life (decay)~792,000110Time for locked mass to decay to 50% (decaying locks only). MaturityRate half-life is 55 days.

Conviction growth timeline (perpetual lock)

Section titled “Conviction growth timeline (perpetual lock)”

How conviction grows over time when locked_mass stays constant:

Days elapsedConviction (% of locked_mass)
00.0%
3031.5%
6053.1%
9067.8%
12078.0%
159 (τ)86.5%
18089.7%
24095.1%
36599.0%

Locked-mass decay timeline (decaying lock)

Section titled “Locked-mass decay timeline (decaying lock)”

How locked_mass decays after toggling set_perpetual_lock(false):

Days elapsedLocked mass remaining
0100.0%
3082.8%
6068.5%
9056.7%
110 (half-life)50.0%
12046.9%
159 (τ)36.8%
36510.0%

Scenario: a validator locks 10,000 alpha on subnet 64 to their hotkey.

locked_mass = 10,000 alpha (constant)

TimeConvictionCan unstake
Day 00 alpha0 alpha
Day 303,150 alpha0 alpha
Day 605,310 alpha0 alpha
Day 906,780 alpha0 alpha
Day 1207,800 alpha0 alpha
Day 1808,970 alpha0 alpha
Day 3659,900 alpha0 alpha

At day 365, the validator calls set_perpetual_lock(false). Now both locked_mass and conviction evolve:

Days since toggleLocked massConvictionCan unstake
010,0009,9000
308,2808,5301,720
606,8507,2803,150
905,6706,1604,330
1204,6905,1805,310
159 (τ)3,6804,0906,320
3651,0001,0909,000

Unstakeable amount = original lock (10,000) − current locked_mass.

After 1 year of decay, the validator can unstake 9,000 alpha, leaving 1,000 still locked.

Subnet owners accumulate locked alpha automatically and receive immediate conviction:

  • Owner cut auto-locked: Each block, the owner’s emissions share is locked to their subnet ownership hotkey.
  • No initial alpha distribution: In v2, subnet registration does not distribute initial alpha to the owner. Conviction builds solely through the auto-locked owner cut from ongoing emissions.
  • Instant conviction: Unlike validators, owners don’t wait for conviction to grow — conviction = locked_mass immediately.
  • Perpetual by default: Owner locks don’t decay unless the owner explicitly calls set_perpetual_lock(false).
  • Aggregate tracking: All owner locks on a subnet are aggregated into OwnerLock storage for subnet king calculations.

This instant conviction ensures subnet owners always have governance weight proportional to their locked stake without waiting periods.

After a subnet has been active for 1 year (365.25 days), ownership can transfer via the subnet king mechanism.

  • Subnet must be at least 365.25 days old.
  • Total rolled conviction across the entire subnet (all hotkeys, all coldkeys, including owner) must be at least 10% of SubnetAlphaOut. This is a subnet-wide gate, not per-challenger.
  • The hotkey with the highest aggregate conviction wins. Conviction is aggregated per hotkey (from all coldkeys locking to that hotkey), not per coldkey.
  1. Aggregate calculation: The system sums conviction across all locks (owner + non-owner) for each coldkey.
  2. Comparison: The hotkey with the highest total conviction (summed from HotkeyLock + DecayingHotkeyLock + OwnerLock) becomes the subnet king.
  3. Transfer: Ownership transfers, and the lock aggregates swap:
    • Old owner’s OwnerLock → becomes non-owner locks
    • New owner’s non-owner locks → become OwnerLock
  4. Instant conviction retained: The new owner keeps their conviction value but now has instant-conviction status for future locks.

Design rationale: This mechanism prevents permanent ownership monopolies while requiring challengers to demonstrate long-term commitment through locked alpha and conviction growth.

  • Top up existing lock: Add more alpha to your existing lock (must target the same hotkey).
  • Move lock to a different hotkey: You can move your lock to a different hotkey on the same subnet. If the destination hotkey is owned by the same coldkey, conviction is preserved. If owned by a different coldkey, conviction resets to zero.
  • Toggle decay mode: Switch between perpetual and decaying at any time with set_perpetual_lock.
  • Partial unstaking (decaying only): Unstake the difference between original lock and current locked_mass.
  • Unstake perpetual locks: You must first toggle to decaying mode and wait for mass to decay.
  • Cross-subnet transfers: Locks are subnet-specific and cannot be moved between subnets.
  • Multi-hotkey locks: You cannot have multiple locks to different hotkeys on the same subnet from one coldkey.
  • Lock hotkey changes: If you have an active lock on a subnet, you can’t lock to a different hotkey without first removing the existing lock.
  • Coldkey swap with active locks on destination: A coldkey swap requires the destination coldkey to have no active locks. The source coldkey’s locks transfer to the destination, but only if the destination is clean.
StorageKeyValuePurpose
Lock(coldkey, netuid)LockStateLegacy/compatibility — tracks basic lock state
HotkeyLock(netuid, hotkey)(coldkey, netuid, hotkey)LockStateAggregate conviction from all perpetual (non-decaying) non-owner coldkeys locking to this hotkey on this subnet
DecayingHotkeyLock(netuid, hotkey)(coldkey, netuid, hotkey)LockStateAggregate conviction from all decaying non-owner coldkeys locking to this hotkey on this subnet
OwnerLock(netuid)(coldkey, netuid)LockStateAggregate conviction for the subnet owner coldkey’s lock on this subnet
DecayingLock(coldkey, netuid)(coldkey, netuid)LockStatePer-coldkey flag: when present, that coldkey’s lock decays. Missing = perpetual.
LockState {
locked_mass: u64, // Current locked alpha (decays if non-perpetual)
conviction: u64, // Governance weight (grows/decays based on mode)
last_update: u64 // Block number of last state update
}

When reading lock state, the system rolls forward from last_update to the current block:

// Time elapsed in blocks
dt = current_block - last_update
// Decay factors
decay_x = exp(-dt / UnlockRate) // = exp(-dt / 1,142,108)
decay_z = exp(-dt / MaturityRate) // = exp(-dt / 571,054)
// Coupling factor
gamma = UnlockRate × (decay_x - decay_z) / (UnlockRate - MaturityRate)
// State update
if perpetual:
locked_mass_new = locked_mass_old // No decay
else:
locked_mass_new = locked_mass_old × decay_x // Exponential decay
conviction_new = decay_z × conviction_old + gamma × locked_mass_old

For subnet owners with instant conviction, the formula simplifies to conviction = locked_mass (no roll-forward needed for conviction growth).

  • lock_stake(hotkey, netuid, amount) — Lock alpha to a hotkey on a subnet (perpetual by default).
  • set_perpetual_lock(netuid, perpetual: bool) — Toggle between perpetual (true) and decaying (false) mode.