Release v444: remove miner-burn scaling from subnet emission shares - #3058
Release v444: remove miner-burn scaling from subnet emission shares#3058unarbos wants to merge 33 commits into
Conversation
…lude issue 2445 notes.
…n evm maintainer skill
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>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🛡️ 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
Prior-comment reconciliation
ConclusionThe 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)
🔍 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 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
Prior-comment reconciliation
ConclusionThe 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)
|
…fees' into release-444
| @@ -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> { | |||
There was a problem hiding this comment.
[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.
|
🔄 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)
| @@ -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> { | |||
There was a problem hiding this comment.
[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.
|
🔄 AI review updated — Skeptic: SAFE Auditor: 👎 |
…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
…-pin' into release-444
| @@ -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> { | |||
There was a problem hiding this comment.
[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.
|
🔄 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
eco-tests changed — indexer review requiredThis PR modifies files under Changed files
|
| @@ -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> { | |||
There was a problem hiding this comment.
[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.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
[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.
There was a problem hiding this comment.
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.
|
🔄 AI review updated — Skeptic: SAFE Auditor: 👎 |
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
| // 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); |
There was a problem hiding this comment.
[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() { |
There was a problem hiding this comment.
[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.
|
🔄 AI review updated — Skeptic: SAFE Auditor: 👎 |
| } | ||
|
|
||
| let mut totals = BTreeMap::<NetUid, u64>::new(); | ||
| for (netuid, _, voting_power) in VotingPower::<T>::iter() { |
There was a problem hiding this comment.
[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.
There was a problem hiding this comment.
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.
|
🔄 AI review updated — Skeptic: VULNERABLE |
…es stub Co-authored-by: Cursor <cursoragent@cursor.com>
| } | ||
|
|
||
| let mut totals = BTreeMap::<NetUid, u64>::new(); | ||
| for (netuid, _, voting_power) in VotingPower::<T>::iter() { |
There was a problem hiding this comment.
[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.
|
🔄 AI review updated — Skeptic: VULNERABLE |
Summary
Release v444. Two changes ride this train:
Remove miner-burn scaling from subnet emission shares
(1 - MinerBurned)weighting fromget_sharesinpallets/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.MinerBurnedbookkeeping 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)
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)
fix(cli): align root output shapes:btcli root list --coldkey <ss58>no longer crashes withIndexError(row/column mismatch), and--json root show --hotkeyemits one JSON document. SDK/CLI-only.Complete implementation of precompiles (#3018)
feat/full-precompiles: five new precompiles (Scheduler0x80f, Drand0x810, Timestamp0x811, RuntimeConfiguration0x812, PrecompileRegistry0x813) plus 69 functions appended to existing precompiles, all dispatching as the mapped EVM signer so pallet authorization and rate limits are preserved. Includes themigrate_total_voting_powermigration (idempotent,HasMigrationRun-guarded, weight-accounted) and the root claim extrinsics/getters.transferKeepAlive/burnBalanceamounts;getTotalVotingPowernow 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)
feat/btcli-combined(2 approvals): six combined btcli PRs — multisig names as wallets (feat(cli): treat saved multisig names as -w wallets #3046), stake UX (btcli stake UX: free balance + 'all', paste any target hotkey, stake burn #3047), machine-readable--dry-run --jsonplans (feat(cli): machine-readable dry-run plans with spend, args, and replay command #3048), secret hygiene (feat(cli): keep key material out of shell history, ps output, and scrollback #3049), name resolution in--call/--argsJSON (feat(cli): resolve address-book/wallet names inside --call/--args JSON #3050), multisig funding preflight (feat(sdk): fail multisig approvals early when the signer cannot cover deposit + fee #3051).CheckNoncefix: coldkeys holding only transferred alpha (zero providers/sufficients, no free TAO) can now pay fees via the alpha fee fallback; addsruntime/tests/alpha_only_coldkey_fees.rs.Keypairretains mnemonic/seed sosecretPhrase/secretSeedare written; reader self-healscryptoType.11.1.0.dev0,uv.lockregenerated,test_cli.pytook the incoming superset (release branch already carried fix(cli): align root output shapes #3037).EVM precompile maintenance skill (#2998)
feat/add-evm-maintainer-skill: public docs for the EVM precompile surface (per-precompile pages, extrinsic coverage matrix, design/lifecycle guide) plus theevm-maintaineragent 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.---Proposed---separator inprecompiles/meta.json.GRANDPA finality fixes + SDK pin (#3055)
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.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_version443 → 444, SDK11.1.0.dev0,bittensor-core0.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 passedcargo test -p subtensor-transaction-fee --lib— 28 passedSKIP_WASM_BUILD=1 cargo test -p node-subtensor-runtime --test evm_transaction_fee— 1 passedSKIP_WASM_BUILD=1 cargo check -p node-subtensor-runtime— cleanpytest sdk/python/tests/unit/test_cli.py— 37 passedcargo 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 passedpytest 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 --checkon sdk/python — cleanSKIP_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 atcacb4310SKIP_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