Skip to content

Release v444: remove miner-burn scaling from subnet emission shares - #3058

Open
unarbos wants to merge 33 commits into
mainfrom
release-444
Open

Release v444: remove miner-burn scaling from subnet emission shares#3058
unarbos wants to merge 33 commits into
mainfrom
release-444

Conversation

@unarbos

@unarbos unarbos commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Release v444. Two changes ride this train:

Remove miner-burn scaling from subnet emission shares

  • Removes the (1 - MinerBurned) weighting from get_shares in pallets/subtensor/src/coinbase/subnet_emissions.rs, introduced in Price-based emissions with miner-burn scaling (+ locked transfer flags) #2781. Subnet emission shares are now pure price-EMA passed through the emission gate, so teams can route miner incentive to the burn key again without it reducing their subnet's emission.
  • Keeps the incentive recycle/burn path and the MinerBurned bookkeeping unchanged — the proportion is informational only (still consumed by the website emission snapshot) and is still cleared on dissolve.

Recycle transaction fees instead of rewarding block authors (#3053)

  • Merged revert-block-author-transaction-fees (2 approvals) into this branch: native TAO fees/tips are recycled by reducing issuance instead of crediting the block author; alpha-paid fees swap to TAO and recycle atomically; EVM base and priority fees use the same handler.

btcli root output fix (#3037)

  • Cherry-picked fix(cli): align root output shapes: btcli root list --coldkey <ss58> no longer crashes with IndexError (row/column mismatch), and --json root show --hotkey emits one JSON document. SDK/CLI-only.

Complete implementation of precompiles (#3018)

  • Merged feat/full-precompiles: five new precompiles (Scheduler 0x80f, Drand 0x810, Timestamp 0x811, RuntimeConfiguration 0x812, PrecompileRegistry 0x813) plus 69 functions appended to existing precompiles, all dispatching as the mapped EVM signer so pallet authorization and rate limits are preserved. Includes the migrate_total_voting_power migration (idempotent, HasMigrationRun-guarded, weight-accounted) and the root claim extrinsics/getters.
  • Reviewed pre-merge by two audit agents: origin safety (no Root/None origins manufactured), input bounds enforced before decode, append-only ABIs, view-only new precompiles, and migration safety all verified. Minor notes: rao-unit doc comments missing on transferKeepAlive/burnBalance amounts; getTotalVotingPower now reads the migrated aggregate; dissolution doesn't clear voting-power keys (pre-existing, self-healing).

btcli v11 UX, wallet compat, and alpha-fee runtime fixes (#3052)

EVM precompile maintenance skill (#2998)

  • Merged feat/add-evm-maintainer-skill: public docs for the EVM precompile surface (per-precompile pages, extrinsic coverage matrix, design/lifecycle guide) plus the evm-maintainer agent skill covering ABI versioning, backwards compatibility, coverage, and regression testing — requiring soft deprecation and a completed migration window before any mainnet compatibility break. Docs/skill/website-only; no runtime or node code.
  • 21 add/add doc conflicts with Complete implementation of precompiles #3018 resolved in favor of the release branch's newer "Deployed" pages (incoming copies were the pre-implementation "Proposed" drafts); dropped a stale ---Proposed--- separator in precompiles/meta.json.

GRANDPA finality fixes + SDK pin (#3055)

  • Pins all workspace polkadot-sdk dependencies (220 manifest entries + Cargo.lock, single unique git source) to fork rev cacb4310, the merge of fix(grandpa): clean up concluded round state polkadot-sdk#31 whose history also contains fixed failing unit tests and debugged burn registration. #33: GRANDPA warp-finality fix (preserve warp-verified authority set, scoped checkpoint authority handoff) plus concluded-round state-leak cleanup.
  • Testnet warp checkpoint fix in node/src/service/grandpa_warp_sync.rs: authority list corrected to the five live authorities (stale sixth removed) and second checkpoint set ID 3 → 2. Client-side only and gated on the testnet genesis hash — mainnet path and runtime/wasm unchanged.

Release plumbing

  • spec_version 443 → 444, SDK 11.1.0.dev0, bittensor-core 0.1.3 (current bases already exist on PyPI, which the release train rejects).

Supersedes #3057 (branch renamed to release-444). #3052 has landed in this branch; both sides set spec 444 so no rebump was needed (neither had shipped).

Test plan

  • cargo test -p pallet-subtensor --features pow-faucet — 1396 passed, 0 failed (pre-merge); emission tests re-run post-merge, 17 passed
  • cargo test -p subtensor-transaction-fee --lib — 28 passed
  • SKIP_WASM_BUILD=1 cargo test -p node-subtensor-runtime --test evm_transaction_fee — 1 passed
  • SKIP_WASM_BUILD=1 cargo check -p node-subtensor-runtime — clean
  • pytest sdk/python/tests/unit/test_cli.py — 37 passed
  • cargo test -p subtensor-precompiles — 125 passed; cargo test -p pallet-admin-utils — 77 passed; pytest tests/unit/test_evm.py — 34 passed (post-merge)
  • cargo test -p bittensor-core --lib — 64 passed (post-btcli v11 UX, wallet compat, and alpha-fee runtime fixes (combines #3046–#3051) #3052 merge)
  • SKIP_WASM_BUILD=1 cargo test -p node-subtensor-runtime --test alpha_only_coldkey_fees — 2 passed; --lib check_nonce — 1 passed
  • pytest sdk/python/tests/unit — 1087 passed, 1 skipped (post-btcli v11 UX, wallet compat, and alpha-fee runtime fixes (combines #3046–#3051) #3052 merge, includes EVM precompile tests)
  • ruff check + ruff format --check on sdk/python — clean
  • SKIP_WASM_BUILD=1 cargo check -p node-subtensor-runtime — clean (post-btcli v11 UX, wallet compat, and alpha-fee runtime fixes (combines #3046–#3051) #3052 merge)
  • cargo metadata --locked --format-version 1 --no-deps — lock consistent; every polkadot-sdk source pinned at cacb4310
  • SKIP_WASM_BUILD=1 cargo test -p node-subtensor grandpa_warp_sync --locked — 4 passed (2 lib + 2 bin)
  • SKIP_WASM_BUILD=1 cargo check -p node-subtensor-runtime --locked — clean against the pinned SDK
  • Release train: devnet deploy + smoke, testnet approval + smoke, mainnet multisig ceremony

UnArbosFour and others added 24 commits July 27, 2026 18:56
Combine the btcli UX, multisig, dry-run, secret-handling, name-resolution, SDK compatibility, and alpha-fee runtime updates into a single signed change.
Subnet emission shares were weighted by (1 - MinerBurned), penalizing
subnets that route miner incentive to owner/burn hotkeys. Remove the
term so shares are pure price-EMA through the emission gate, letting
teams use the burn key again without hurting their emission.

MinerBurned bookkeeping and the incentive recycle/burn path are kept
unchanged; the proportion is now informational only (still surfaced by
the website emission snapshot).

Release v444: bump spec_version to 444, SDK to 11.0.3.dev0,
bittensor-core to 0.1.3.

Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel

vercel Bot commented Aug 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
subtensor Ready Ready Preview Aug 6, 2026 12:46pm

Request Review

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🛡️ AI Review — Skeptic (security review)

VERDICT: VULNERABLE

MEDIUM scrutiny: ~5-month-old contributor with substantial activity and repository write access; no Gittensor association found; release-444 -> main.

The AI-review trust boundary is unchanged. The prior runtime-migration concern remains present in the current head.

Findings

Sev File Finding
HIGH pallets/subtensor/src/migrations/migrate_total_voting_power.rs:20 Runtime upgrade scans the complete voting-power map inline

Prior-comment reconciliation

  • 3bc7ac09: not addressed — The current head still calls VotingPower::<T>::iter() synchronously from on_runtime_upgrade; no bound or resumable cursor was added.

Conclusion

The synchronous, unbounded voting-power migration can exhaust runtime-upgrade execution capacity as state grows. It must be made bounded and resumable before release.


📜 Previous run (superseded)
Sev File Finding Status
HIGH pallets/subtensor/src/migrations/migrate_total_voting_power.rs:20 Runtime upgrade scans the complete voting-power map ➡️ Carried forward to current findings
The current head still calls VotingPower::<T>::iter() synchronously from on_runtime_upgrade; no bound or resumable cursor was added.

🔍 AI Review — Auditor (domain review)

VERDICT: 👎

UNKNOWN gittensor association; established contributor with repository write access and substantial prior merged work.

The PR description is now substantive and accurately covers the release contents, including the GRANDPA warp-sync fix. The spec_version bump to 444 is present.

This release branch incorporates the implementations from overlapping PRs #3052, #3053, #3055, #3018, and #2998. This PR is the better candidate. Recommend closing those incorporated PRs. The other file overlaps are with distinct, unincorporated work.

Findings

Sev File Finding
HIGH pallets/subtensor/src/coinbase/subnet_emissions.rs:356 Emission-policy change lacks regression coverage inline
HIGH pallets/subtensor/src/migrations/migrate_total_voting_power.rs:20 Voting-power migration performs an unbounded upgrade-time scan inline

Prior-comment reconciliation

  • b47bee07: not addressed — No regression test sets unequal nonzero MinerBurned values and verifies that shares remain unaffected.
  • dfbcdc8b: not addressed — The migration still iterates the complete VotingPower map synchronously during runtime upgrade.

Conclusion

The release remains blocked by missing regression coverage for its headline economic-policy change and an unbounded runtime-upgrade migration. Both must be corrected before deployment.


📜 Previous run (superseded)
Sev File Finding Status
HIGH pallets/subtensor/src/coinbase/subnet_emissions.rs:355 Emission-policy change has no regression coverage ➡️ Carried forward to current findings
No regression test sets unequal nonzero MinerBurned values and verifies that shares remain unaffected.
HIGH pallets/subtensor/src/migrations/migrate_total_voting_power.rs:21 Voting-power migration performs an unbounded upgrade-time scan ➡️ Carried forward to current findings
The migration still iterates the complete VotingPower map synchronously during runtime upgrade.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

@@ -353,40 +353,7 @@ impl<T: Config> Pallet<T> {
// `get_subnet_block_emissions`, so the effective emission is
// e_i = gate(s_i) * s_i / sum(gate(s_j) * s_j) over emit-enabled subnets.
pub(crate) fn get_shares(subnets_to_emit_to: &[NetUid]) -> BTreeMap<NetUid, U64F64> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[HIGH] Emission-policy change has no regression coverage

This removes MinerBurned from an economic allocation formula, but every current get_shares test sets MinerBurned to 0.0; therefore the stated full-suite run would also pass with the removed weighting restored. Add a regression test with equal prices and unequal boundary values (0 and 1) that asserts equal final shares, plus a non-boundary case if rounding behavior matters. The test must fail under the previous implementation and pass here.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👎

Keep root position rows aligned with their human table columns in both single-wallet and all-wallet modes. Emit one consolidated JSON document for explicit validator details and cover the affected human and JSON paths.

(cherry picked from commit 3e56c87)

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

@@ -353,40 +353,7 @@ impl<T: Config> Pallet<T> {
// `get_subnet_block_emissions`, so the effective emission is
// e_i = gate(s_i) * s_i / sum(gate(s_j) * s_j) over emit-enabled subnets.
pub(crate) fn get_shares(subnets_to_emit_to: &[NetUid]) -> BTreeMap<NetUid, U64F64> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[HIGH] Emission-policy change has no regression coverage

The prior finding remains unresolved. This changes economic allocation by making MinerBurned irrelevant, but every active get_shares test still sets it to zero. Add a regression test that records baseline shares, assigns unequal values (including 0 and 1) to otherwise identical subnets, and asserts the shares remain unchanged; this prevents the removed weighting from being silently reintroduced.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👎

unarbos added 2 commits August 6, 2026 07:46
…nto release-444

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	docs/guides/evm/precompile-design.mdx
#	docs/guides/evm/precompiles/account-balance.mdx
#	docs/guides/evm/precompiles/alpha.mdx
#	docs/guides/evm/precompiles/balance-transfer.mdx
#	docs/guides/evm/precompiles/crowdloan.mdx
#	docs/guides/evm/precompiles/drand.mdx
#	docs/guides/evm/precompiles/extrinsic-coverage.mdx
#	docs/guides/evm/precompiles/index.mdx
#	docs/guides/evm/precompiles/leasing.mdx
#	docs/guides/evm/precompiles/metagraph.mdx
#	docs/guides/evm/precompiles/neuron.mdx
#	docs/guides/evm/precompiles/proxy.mdx
#	docs/guides/evm/precompiles/registry.mdx
#	docs/guides/evm/precompiles/runtime-configuration.mdx
#	docs/guides/evm/precompiles/scheduler.mdx
#	docs/guides/evm/precompiles/staking-v2.mdx
#	docs/guides/evm/precompiles/storage-query.mdx
#	docs/guides/evm/precompiles/subnet.mdx
#	docs/guides/evm/precompiles/timestamp.mdx
#	docs/guides/evm/precompiles/uid-lookup.mdx
#	docs/guides/evm/precompiles/voting-power.mdx

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

@@ -353,40 +353,7 @@ impl<T: Config> Pallet<T> {
// `get_subnet_block_emissions`, so the effective emission is
// e_i = gate(s_i) * s_i / sum(gate(s_j) * s_j) over emit-enabled subnets.
pub(crate) fn get_shares(subnets_to_emit_to: &[NetUid]) -> BTreeMap<NetUid, U64F64> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[HIGH] Emission-policy change has no regression coverage

This removes MinerBurned from an economic allocation formula, but every active get_shares test still assigns zero to MinerBurned. Add a regression test with equal prices and unequal boundary values (for example, 0 and 1) and assert equal shares. The test must fail against the prior weighted implementation and pass here.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👎

…e-444

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	sdk/python/pyproject.toml
#	sdk/python/tests/unit/test_cli.py
#	sdk/python/uv.lock
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

eco-tests changed — indexer review required

This PR modifies files under eco-tests/. and may affect downstream indexing.
cc @evgeny-s — please review manually

Changed files
  • eco-tests/Cargo.toml

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

@@ -353,40 +353,7 @@ impl<T: Config> Pallet<T> {
// `get_subnet_block_emissions`, so the effective emission is
// e_i = gate(s_i) * s_i / sum(gate(s_j) * s_j) over emit-enabled subnets.
pub(crate) fn get_shares(subnets_to_emit_to: &[NetUid]) -> BTreeMap<NetUid, U64F64> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[HIGH] Emission-policy change has no regression coverage

The headline economic change still has no test proving get_shares is independent of MinerBurned. Existing share tests only exercise zero-valued entries, so restoring the removed multiplier could pass unnoticed. Add cases with unequal values and the 0/100% boundaries, asserting identical price-derived shares.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in fb0843b: added get_shares_independent_of_miner_burned covering boundary splits (0/1, 1/0) and a non-boundary split (0.25/0.75) with equal prices, asserting equal 0.5/0.5 shares. Verified the test FAILS with the previous (1 - miner_burned) weighting restored and passes with the current implementation.


let mut totals = BTreeMap::<NetUid, u64>::new();
for (netuid, _, voting_power) in VotingPower::<T>::iter() {
reads = reads.saturating_add(1);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[HIGH] Voting-power migration performs an unbounded upgrade-time scan

VotingPower::iter() scans every entry during on_runtime_upgrade without a bound or resumable cursor. Returning the measured weight afterward does not prevent the upgrade block from exceeding its execution budget. Move this to a bounded, cursor-based multi-block migration (or establish and enforce a safe protocol-level bound). The migration also needs try-runtime pre/post validation that recomputes the expected totals and checks every stored aggregate.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Measured on Finney mainnet (state_getKeysPaged): VotingPower currently holds 12 entries total, with VotingPowerTrackingEnabled set on exactly 1 subnet. The scan this migration performs at upgrade time is 12 reads, far below any block-weight concern. The theoretical bound is subnets-with-tracking-enabled x 256 UIDs, and tracking has only just started being adopted. A cursor-based multi-block migration for a one-shot 12-entry backfill would add more risk to this release than it removes; the migration follows the same HasMigrationRun one-shot pattern as the rest of this pallet's migrations, and the try-runtime CI job will execute it against forked mainnet state once builds are green.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👎

Co-authored-by: Cursor <cursoragent@cursor.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

// unweighted price shares so the block's emission is not stranded.
price_shares
};
let mut shares = Self::get_shares_price_ema(subnets_to_emit_to);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[HIGH] Emission-policy change lacks regression coverage

The headline economic change removes MinerBurned from share calculation, but no test proves that unequal burn proportions no longer affect otherwise equal subnet shares. Existing active tests set burns to zero or equal values, so they would not detect restoration of the removed weighting. Add a regression test with equal prices and unequal nonzero MinerBurned values, asserting equal resulting shares.

}

let mut totals = BTreeMap::<NetUid, u64>::new();
for (netuid, _, voting_power) in VotingPower::<T>::iter() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[HIGH] Voting-power migration performs an unbounded upgrade-time scan

VotingPower::iter() scans every stored voting-power row synchronously in on_runtime_upgrade. Reporting the consumed database weight afterward does not constrain execution, so sufficiently large chain state can exceed the upgrade block budget. Convert this to a cursor-based, bounded multi-block migration (for example via on_idle), with completion guards and pre/post-state validation.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👎

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

}

let mut totals = BTreeMap::<NetUid, u64>::new();
for (netuid, _, voting_power) in VotingPower::<T>::iter() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[HIGH] Runtime upgrade scans the complete voting-power map

VotingPower::iter() performs an unbounded synchronous scan during on_runtime_upgrade. The map can grow across subnets and validators, while returning a calculated weight does not limit work already executed. A sufficiently large state can exceed the upgrade block's execution budget and prevent safe activation. Migrate in bounded batches with a persisted cursor (for example through on_idle), and mark completion only after the final batch.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Data and precedent on this: (1) This is a one-shot backfill gated by HasMigrationRun — it executes exactly once, at the upgrade block, so the relevant size is the map size at upgrade time, not future growth (post-upgrade writes maintain TotalVotingPower incrementally). (2) Measured on Finney via state_getKeysPaged: VotingPower holds 12 entries; VotingPowerTrackingEnabled is set on 1 subnet. (3) 25 of the existing migrations in this pallet use the same unbounded-iter one-shot pattern (e.g. migrate_total_issuance, migrate_populate_owned_hotkeys) and have shipped safely. (4) The try-runtime mainnet CI job on this PR executes this migration against forked mainnet archive state, so any weight blowout would surface there before release. Converting a 12-entry backfill to a cursor-based multi-block migration would introduce more release risk than it removes.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: VULNERABLE

…es stub

Co-authored-by: Cursor <cursoragent@cursor.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

}

let mut totals = BTreeMap::<NetUid, u64>::new();
for (netuid, _, voting_power) in VotingPower::<T>::iter() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[HIGH] Runtime upgrade scans the complete voting-power map

This loop synchronously reads every VotingPower entry during on_runtime_upgrade and also accumulates an unbounded BTreeMap. Returning the measured weight afterward does not limit execution to the upgrade's available weight, so sufficiently large state can exhaust the upgrade block and prevent the new runtime from completing. Convert this to a bounded, cursor-based multi-block migration and only set HasMigrationRun after the final batch.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: VULNERABLE

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