Skip to content

Epic: v440 emission pipeline — publish where each subnet's TAO share is decided and where the TAO actually goes #8739

Description

@JSONbored

Revised 2026-07-30 after reading the v440 source (#8740). The premise this epic was
originally filed on — that the emission gate throttles TAO injection — is wrong. The gate
redistributes; it does not withhold. 100.00% of block emission reaches subnets. The
corrected mechanism, and the surface that is actually worth building, are below. #8740 carries
the full derivation.

What v440 actually does

Runtime spec 440 (live on finney since 2026-07-27) added a Hill emission gate to the subnet
emission pipeline. The full pipeline, read from
pallets/subtensor/src/coinbase/{subnet_emissions,run_coinbase,block_emission}.rs at tag v440
and reproduced against live chain state to a mean share error of 4.3e-8:

# stage source
0 eligibility: non-root ∧ FirstEmissionBlockNumber.is_some()SubtokenEnabledNetworkRegistrationAllowed get_subnets_to_emit_to
1 s_i = SubnetMovingPrice_i / Σ SubnetMovingPrice — price EMA share get_shares_price_ema
2 w_i = s_i · (1 − MinerBurned_i), renormalized get_shares
3 θ = q-mass bar over w, recomputed when block % 360 == 0 maybe_update_emission_gate_bar
4 g_i = w_i · 1/(1+(θ/w_i)^h), renormalized to sum 1 apply_emission_gate
5 SubnetEmissionEnabled == false → zeroed, share redistributed get_subnet_block_emissions
6 tao_emission_i = block_emission · g_i get_subnet_block_emissions
7 alpha_in_i = tao_emission_i / price_i, capped at root_proportion_i · alpha_emission_i; the remainder becomes excess_taochain buys get_subnet_terms
8 balancer splits materialized TAO into price-active vs reservoir; only the price-active part is written to SubnetTaoInEmission inject_and_maybe_swap

Live parameters: θ = 0.008989, q = 0.75 (raised from the 0.61 default post-deploy),
EmissionGateExponent storage unset → runtime default h = 3.

The four things that make this worth building

1. The gate is redistributive, not extractive. Step 4 renormalizes gated shares to sum to 1
— the source says so directly: e_i = gate(s_i) * s_i / sum(gate(s_j) * s_j). Aggregate TAO is
untouched; what changes is which subnets get it. Who gained and who lost share at the gate is a
real, publishable, currently-invisible number.

2. TAO arrives through two channels, and only one is visible anywhere. Measured at block
8,736,990:

Σ SubnetTaoInEmission (pool liquidity injection) = 0.166547 TAO/block   33.3%
Σ SubnetExcessTao     (chain buys)               = 0.333453 TAO/block   66.7%
Σ combined                                       = 0.500000 TAO/block  100.00%
real block emission                              = 0.500000 TAO/block

The 67% arriving as chain buys is the alpha injection cap at step 7 — as a subnet's alpha
issuance grows, root_proportion shrinks, the cap falls, and TAO that can no longer be paired
as liquidity is spent buying alpha on the subnet's own pool instead. Age-driven, not
gate-driven. Both channels are TAO arriving, with different price effects. The split, per
subnet, is the single most useful thing on this surface and nobody publishes it.

3. MinerBurned silently reweights every subnet's share. 68 of 128 subnets have a non-zero
value, and it multiplies straight into their TAO share at step 2. Unpublished anywhere.
(U96F32 — divide by 2^32. Scaling this as rao was the largest error in the first
reconstruction.)

4. The network is past its first halving, and the obvious storage item is stale.
TotalIssuance = 11,180,113 TAO → log2(1/(1−issuance/2.1e16)) = 1.0966 → floor 1 → block
emission = 0.5 TAO/block. The BlockEmission storage item reads 1.0 TAO and is not the
live figure; the live value is recomputed from issuance every block. Anyone deriving emission
percentages from that storage item is off by 2×.

What we already publish that is now misleading

emission_share = alpha_price / Σ alpha_price (scripts/lib/economics-artifacts.ts:186) is
stage 1 of the pipeline above — the gate's raw input, before miner-burn weighting, before
the gate, before the enabled filter. It is the default sort on /api/v1/economics, summed into
total_emission_share (src/domain-summary.ts:116), exported as mean_emission_share on
/economics/trends, and rendered in three UI surfaces. Every one of them reads as "share of TAO
emission" and is now five stages upstream of it. That is #8746.

Sub-issues

# Sub-issue Size Depends on
#8740 Pin the gate's actual inputdone, findings on the issue S
#8741 ADR: what we publish, what emission_share means, the reconstruction rule S
#8742 Gate parameters on /api/v1/network/parameters (pure storage read) S
#8747 Issuance-derived block emission — the BlockEmission item is stale S
#8743 Per-subnet pipeline input capture M #8747
#8748 Gate-parameter + SubnetEmissionEnabled change history S
#8749 Reconstruction harness + live drift monitor M #8743
#8744 Emission-pipeline API surface M #8741, #8743, #8747, #8749
#8745 /chain/emissions UI + per-subnet panel M #8744
#8746 Disambiguate emission_share as stage-1 input S #8741
#8750 Monitor: dormant TAO-flow emission path activation S

Unblocked now: #8741, #8742, #8747, #8748, #8750. #8743 needs only #8747.

Why the split. #8743 was carrying four separable deliverables (per-subnet capture, a
network-level change log, the block-emission derivation, and the verification harness). They
have different storage shapes, different write patterns, and different review surfaces, so they
are four PRs, not one. #8749 exists because everything #8744 publishes is a reconstruction
without a harness holding it against live chain state, the surface is a claim rather than a
verified one. #8750 exists because a single dormant switch would invalidate the entire
decomposition at once.

Traps, all of which cost real debugging time

  • MinerBurned is U96F32 (÷2^32), not rao.
  • The three gate parameters are 128-bit U64F64 (16 bytes), not 64-bit.
  • EmissionGateExponent unset means h = 3, not 0. h = 0 yields gate = 0.5 for everything.
  • SubnetEmissionEnabled defaults to true — absent ≠ disabled.
  • BlockEmission storage is stale; derive from TotalIssuance.
  • SubnetAlphaOutEmission is alpha to participants; SubnetAlphaInEmission is alpha to the
    pool. Σ 127.0 vs Σ 9.42 per block. Pool-ratio math needs alpha_in.
  • SubnetAlphaOutEmission is not a constant 1.0 — it is a per-subnet halving curve
    (get_block_emission_for_issuance(alpha_issuance_i)). It reads 1.0 today only because no
    subnet has crossed its first threshold.
  • SubnetTaoInEmission is per-block, reservoir-smoothed and cap-limited. A single sample is
    not a stable measure; 47 of the 54 subnets reading zero are SubnetEmissionEnabled = false,
    not gate casualties.
  • get_shares_flow (TAO-flow EMA) exists in v440 but is #[allow(dead_code)] and not wired
    in
    . The machinery is provisioned and partially warm: SubnetTaoFlow is written on all 128
    subnets by live stake/swap code, while SubnetEmaTaoFlow is set on 124 and frozen at
    exactly block 8,466,530
    (~37.6 days behind tip) — the signature of a path that ran and was
    switched off. If it is switched back on, the gate's input changes from price to demand flow
    and every figure here moves at once. Monitored by monitor(chain): alert if the dormant TAO-flow emission path is activated #8750.

Placement

/chain/emissions, a peer of /chain/governance and /chain/runtime, plus a panel on
/subnets/{netuid}. Network-wide mechanism, not a tab under one subnet.

Explicitly out of scope

  • Any claim that emission is being throttled or withheld. It is not. 100.00% of block
    emission reaches subnets.
  • Reimplementing the pipeline as a forecast. We publish the decomposition of what happened, not
    a simulation of what will.
  • Forecasting parameter changes.
  • Advice on what to do about any of it.

Definition of done

  1. For any subnet: its price share, its miner-burn weight, its post-gate share, whether it is
    emission-enabled, and its TAO split between pool injection and chain buys — each with the
    block height and storage key that produced it.
  2. The decomposition reproduces the chain to fixed-point tolerance, and a regression test holds
    it there.
  3. θ, q, h served with change history.
  4. emission_share is unambiguous everywhere it appears.
  5. Every published value is reproducible by an outside reader against a public RPC endpoint.

Reproducing

RPC=https://entrypoint-finney.opentensor.ai; P=658faa385070e074c85bf6b568cf0555
q(){ curl -s -X POST $RPC -H 'content-type: application/json' \
 -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"state_getStorage\",\"params\":[\"0x$1\"]}"; }
q "${P}57c875e4cff74148e4628f264b974c80"       # TotalIssuance -> 0.5 TAO/block
q "${P}7c9b0d2964cc73e7519676c3cc4d5df9"       # EmissionGateBar (U64F64, 16 bytes)
q "${P}a772007dde2ed63e0f21b5f9d7f16650"       # EmissionBarQuantile -> exactly 0.75
q "${P}dd62ae7237581e8f6a684f1ecae062154000"   # SubnetTaoInEmission netuid 64
q "${P}857b0a5b920bc5e41cb0695a4b7d38e74000"   # SubnetExcessTao    netuid 64
q "${P}1eac6222ebba7feba4ca36a94736815e4000"   # MinerBurned        netuid 64 (U96F32)

Map hasher is Identity — key suffix is the netuid as u16 little-endian (74 → 4a00). All 128
per item in one state_queryStorageAt. Item hashes are twox128(<name>), derivable with the
repo's own src/twox-storage-key.ts.

Related: #8702 (upgrade radar) would have flagged v440 while it was still on testnet.

Metadata

Metadata

Assignees

Labels

backendmaintainer-onlyOwner-only work — yields no Gittensor points.roadmapRoadmap epic / tracking

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions