From e9c94240019fd3bccb3b76dbf066b2e785b5f009 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Thu, 6 Nov 2025 22:25:13 -0500 Subject: [PATCH 01/10] add totalemission counter --- pallets/subtensor/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 5df8a9c429..c536873128 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1433,6 +1433,10 @@ pub mod pallet { /// --- MAP ( netuid ) --> pending_emission pub type PendingEmission = StorageMap<_, Identity, NetUid, AlphaCurrency, ValueQuery, DefaultPendingEmission>; + #[pallet::storage] + /// --- MAP ( netuid ) --> total_emission + pub type TotalEmission = + StorageMap<_, Identity, NetUid, AlphaCurrency, ValueQuery, DefaultZeroAlpha>; /// --- MAP ( netuid ) --> pending_root_alpha_emission #[pallet::storage] pub type PendingRootAlphaDivs = From 5cafe0a3bae5c3734dc7a293be2fc54ac071aa80 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Thu, 6 Nov 2025 22:34:26 -0500 Subject: [PATCH 02/10] burn alpha not sold by root --- pallets/subtensor/src/benchmarks.rs | 1 + .../subtensor/src/coinbase/run_coinbase.rs | 52 ++++++++++++------- pallets/subtensor/src/tests/claim_root.rs | 14 +++++ pallets/subtensor/src/tests/coinbase.rs | 29 +++++++++-- 4 files changed, 73 insertions(+), 23 deletions(-) diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 1e7d6991c1..223c086419 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -1619,6 +1619,7 @@ mod pallet_benchmarks { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), AlphaCurrency::ZERO, ); diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index d998ad1f7d..c8169c317f 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -195,29 +195,27 @@ impl Pallet { let alpha_out_i: U96F32 = *alpha_out.get(netuid_i).unwrap_or(&asfloat!(0.0)); log::debug!("alpha_out_i: {alpha_out_i:?}"); - // Get root proportion of alpha_out dividends. - let mut root_alpha: U96F32 = asfloat!(0.0); + // Get ALPHA issuance. + let alpha_issuance: U96F32 = asfloat!(Self::get_alpha_issuance(*netuid_i)); + log::debug!("alpha_issuance: {alpha_issuance:?}"); + + // Get root proportional dividends. + let root_proportion: U96F32 = tao_weight + .checked_div(tao_weight.saturating_add(alpha_issuance)) + .unwrap_or(asfloat!(0.0)); + log::debug!("root_proportion: {root_proportion:?}"); + + // Get root alpha from root prop. + let root_alpha: U96F32 = root_proportion + .saturating_mul(alpha_out_i) // Total alpha emission per block remaining. + .saturating_mul(asfloat!(0.5)); // 50% to validators. + log::debug!("root_alpha: {root_alpha:?}"); + if root_sell_flag { - // Get ALPHA issuance. - let alpha_issuance: U96F32 = asfloat!(Self::get_alpha_issuance(*netuid_i)); - log::debug!("alpha_issuance: {alpha_issuance:?}"); - - // Get root proportional dividends. - let root_proportion: U96F32 = tao_weight - .checked_div(tao_weight.saturating_add(alpha_issuance)) - .unwrap_or(asfloat!(0.0)); - log::debug!("root_proportion: {root_proportion:?}"); - - // Get root alpha from root prop. - root_alpha = root_proportion - .saturating_mul(alpha_out_i) // Total alpha emission per block remaining. - .saturating_mul(asfloat!(0.5)); // 50% to validators. PendingRootAlphaDivs::::mutate(*netuid_i, |total| { *total = total.saturating_add(tou64!(root_alpha).into()); }); } - // Remove root alpha from alpha_out. - log::debug!("root_alpha: {root_alpha:?}"); // Get pending alpha as original alpha_out - root_alpha. let pending_alpha: U96F32 = alpha_out_i.saturating_sub(root_alpha); @@ -227,6 +225,10 @@ impl Pallet { PendingEmission::::mutate(*netuid_i, |total| { *total = total.saturating_add(tou64!(pending_alpha).into()); }); + // Accumulate total alpha emission, including burned alpha from root prop. + TotalEmission::::mutate(*netuid_i, |total| { + *total = total.saturating_add(tou64!(alpha_out_i).into()); + }); } // --- 8. Update moving prices after using them in the emission calculation. @@ -263,8 +265,18 @@ impl Pallet { let owner_cut = PendingOwnerCut::::get(netuid); PendingOwnerCut::::insert(netuid, AlphaCurrency::ZERO); + // Get total emission and drain. + let total_emission = TotalEmission::::get(netuid); + TotalEmission::::insert(netuid, AlphaCurrency::ZERO); + // Distribute the emission. - Self::distribute_emission(netuid, pending_alpha, pending_root_alpha, owner_cut); + Self::distribute_emission( + netuid, + pending_alpha, + pending_root_alpha, + total_emission, + owner_cut, + ); } else { // Increment BlocksSinceLastStep::::mutate(netuid, |total| *total = total.saturating_add(1)); @@ -635,6 +647,7 @@ impl Pallet { netuid: NetUid, pending_alpha: AlphaCurrency, pending_root_alpha: AlphaCurrency, + total_alpha: AlphaCurrency, owner_cut: AlphaCurrency, ) { log::debug!( @@ -642,7 +655,6 @@ impl Pallet { ); let tao_weight = Self::get_tao_weight(); - let total_alpha = pending_alpha.saturating_add(pending_root_alpha); // Run the epoch. let hotkey_emission: Vec<(T::AccountId, AlphaCurrency, AlphaCurrency)> = diff --git a/pallets/subtensor/src/tests/claim_root.rs b/pallets/subtensor/src/tests/claim_root.rs index 951dfa0ae1..5e8f0a8907 100644 --- a/pallets/subtensor/src/tests/claim_root.rs +++ b/pallets/subtensor/src/tests/claim_root.rs @@ -76,6 +76,7 @@ fn test_claim_root_with_drain_emissions() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -144,6 +145,7 @@ fn test_claim_root_with_drain_emissions() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -245,6 +247,7 @@ fn test_claim_root_adding_stake_proportionally_for_two_stakers() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -346,6 +349,7 @@ fn test_claim_root_adding_stake_disproportionally_for_two_stakers() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -437,6 +441,7 @@ fn test_claim_root_with_changed_stake() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -489,6 +494,7 @@ fn test_claim_root_with_changed_stake() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -542,6 +548,7 @@ fn test_claim_root_with_changed_stake() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -634,6 +641,7 @@ fn test_claim_root_with_drain_emissions_and_swap_claim_type() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -678,6 +686,7 @@ fn test_claim_root_with_drain_emissions_and_swap_claim_type() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -714,6 +723,7 @@ fn test_claim_root_with_drain_emissions_and_swap_claim_type() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -1139,6 +1149,7 @@ fn test_claim_root_with_swap_coldkey() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -1229,6 +1240,7 @@ fn test_claim_root_with_swap_hotkey() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -1345,6 +1357,7 @@ fn test_claim_root_on_network_deregistration() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -1485,6 +1498,7 @@ fn test_claim_root_with_unrelated_subnets() { netuid, AlphaCurrency::ZERO, pending_root_alpha.into(), + pending_root_alpha.into(), AlphaCurrency::ZERO, ); diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 5d03afa973..d97fbfb037 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -708,6 +708,7 @@ fn test_drain_base() { AlphaCurrency::ZERO, AlphaCurrency::ZERO, AlphaCurrency::ZERO, + AlphaCurrency::ZERO, ) }); } @@ -723,6 +724,7 @@ fn test_drain_base_with_subnet() { AlphaCurrency::ZERO, AlphaCurrency::ZERO, AlphaCurrency::ZERO, + AlphaCurrency::ZERO, ) }); } @@ -747,6 +749,7 @@ fn test_drain_base_with_subnet_with_single_staker_not_registered() { netuid, pending_alpha.into(), AlphaCurrency::ZERO, + pending_alpha.into(), AlphaCurrency::ZERO, ); let stake_after = @@ -776,6 +779,7 @@ fn test_drain_base_with_subnet_with_single_staker_registered() { netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); let stake_after = @@ -820,6 +824,7 @@ fn test_drain_base_with_subnet_with_single_staker_registered_root_weight() { netuid, pending_alpha, pending_root_alpha, + pending_alpha.saturating_add(pending_root_alpha), AlphaCurrency::ZERO, ); let stake_after = @@ -867,6 +872,7 @@ fn test_drain_base_with_subnet_with_two_stakers_registered() { netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -932,6 +938,7 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root() { netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -1003,7 +1010,13 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am let pending_tao = TaoCurrency::from(1_000_000_000); let pending_alpha = AlphaCurrency::from(1_000_000_000); assert_eq!(SubnetTAO::::get(NetUid::ROOT), TaoCurrency::ZERO); - SubtensorModule::distribute_emission(netuid, pending_alpha, AlphaCurrency::ZERO, 0.into()); + SubtensorModule::distribute_emission( + netuid, + pending_alpha, + AlphaCurrency::ZERO, + pending_alpha, + 0.into(), + ); let stake_after1 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey1, &coldkey, netuid); let root_after1 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet( @@ -1082,6 +1095,7 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -1143,6 +1157,7 @@ fn test_drain_alpha_childkey_parentkey() { netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); let parent_stake_after = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); @@ -1368,6 +1383,7 @@ fn test_get_root_children_drain() { alpha, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -1390,8 +1406,8 @@ fn test_get_root_children_drain() { SubtensorModule::distribute_emission( alpha, pending_alpha, - // pending_root1, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -1415,6 +1431,7 @@ fn test_get_root_children_drain() { alpha, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -1503,6 +1520,7 @@ fn test_get_root_children_drain_half_proportion() { alpha, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -1589,6 +1607,7 @@ fn test_get_root_children_drain_with_take() { alpha, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -1676,6 +1695,7 @@ fn test_get_root_children_drain_with_half_take() { alpha, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); @@ -2391,6 +2411,7 @@ fn test_distribute_emission_no_miners_all_drained() { netuid, emission, AlphaCurrency::ZERO, + emission, AlphaCurrency::ZERO, ); @@ -2461,7 +2482,8 @@ fn test_distribute_emission_zero_emission() { // Set the emission to be ZERO. SubtensorModule::distribute_emission( netuid, - 0.into(), + AlphaCurrency::ZERO, + AlphaCurrency::ZERO, AlphaCurrency::ZERO, AlphaCurrency::ZERO, ); @@ -2756,6 +2778,7 @@ fn test_drain_alpha_childkey_parentkey_with_burn() { netuid, pending_alpha, AlphaCurrency::ZERO, + pending_alpha, AlphaCurrency::ZERO, ); let parent_stake_after = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); From cfca5d09232b2c8b632c76ce166b0cf10bf774d3 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Thu, 6 Nov 2025 22:56:06 -0500 Subject: [PATCH 03/10] chore: fmt --- pallets/subtensor/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index c536873128..3989733558 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1433,7 +1433,7 @@ pub mod pallet { /// --- MAP ( netuid ) --> pending_emission pub type PendingEmission = StorageMap<_, Identity, NetUid, AlphaCurrency, ValueQuery, DefaultPendingEmission>; - #[pallet::storage] + #[pallet::storage] /// --- MAP ( netuid ) --> total_emission pub type TotalEmission = StorageMap<_, Identity, NetUid, AlphaCurrency, ValueQuery, DefaultZeroAlpha>; From 3975359ddd0bf023a39788527fe9c3eeffea398d Mon Sep 17 00:00:00 2001 From: camfairchild Date: Thu, 6 Nov 2025 22:56:24 -0500 Subject: [PATCH 04/10] bump spec --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index fe9bda8b6c..45e470be80 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -220,7 +220,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 342, + spec_version: 343, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From abef5e0223ec9441814adbd0cc1a5e2a30761516 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Fri, 7 Nov 2025 14:01:03 -0500 Subject: [PATCH 05/10] add pending server and pending vali emissions --- .../subtensor/src/coinbase/run_coinbase.rs | 90 ++++++++++++------- pallets/subtensor/src/lib.rs | 8 +- 2 files changed, 65 insertions(+), 33 deletions(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index c8169c317f..428c23e41e 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -212,22 +212,31 @@ impl Pallet { log::debug!("root_alpha: {root_alpha:?}"); if root_sell_flag { + // Only accumulate root alpha divs if root sell is allowed. PendingRootAlphaDivs::::mutate(*netuid_i, |total| { *total = total.saturating_add(tou64!(root_alpha).into()); }); + } else { + // If we are not selling the root alpha, we should recycle it. + Self::recycle_subnet_alpha(*netuid_i, AlphaCurrency::from(tou64!(root_alpha))); } - // Get pending alpha as original alpha_out - root_alpha. - let pending_alpha: U96F32 = alpha_out_i.saturating_sub(root_alpha); - log::debug!("pending_alpha: {pending_alpha:?}"); + // Get pending server alpha, which is the miner cut of the alpha out. + // Currently miner cut is 50% of the alpha out. + let pending_server_alpha = alpha_out_i.saturating_mul(asfloat!(0.5)); + // The total validator alpha is the remaining alpha out minus the server alpha. + let total_validator_alpha = alpha_out_i.saturating_sub(pending_server_alpha); + + // The alpha validators don't get the root alpha. + let pending_validator_alpha = total_validator_alpha.saturating_sub(root_alpha); - // Accumulate alpha emission in pending. - PendingEmission::::mutate(*netuid_i, |total| { - *total = total.saturating_add(tou64!(pending_alpha).into()); + // Accumulate the server alpha emission. + PendingServerEmission::::mutate(*netuid_i, |total| { + *total = total.saturating_add(tou64!(pending_server_alpha).into()); }); - // Accumulate total alpha emission, including burned alpha from root prop. - TotalEmission::::mutate(*netuid_i, |total| { - *total = total.saturating_add(tou64!(alpha_out_i).into()); + // Accumulate the validator alpha emission. + PendingValidatorEmission::::mutate(*netuid_i, |total| { + *total = total.saturating_add(tou64!(pending_validator_alpha).into()); }); } @@ -253,9 +262,29 @@ impl Pallet { BlocksSinceLastStep::::insert(netuid, 0); LastMechansimStepBlock::::insert(netuid, current_block); - // Get and drain the subnet pending emission. - let pending_alpha = PendingEmission::::get(netuid); + // Get and drain the PendingEmission. + // deprecated + let pending_emission = PendingEmission::::get(netuid); PendingEmission::::insert(netuid, AlphaCurrency::ZERO); + // If pending_emission is not zero, we split it between the server emission and the validator emission. + if !pending_emission.is_zero() { + let server_alpha = pending_emission.saturating_div(2.into()); + let validator_alpha = pending_emission.saturating_sub(server_alpha); + + PendingServerEmission::::mutate(netuid, |total| { + *total = total.saturating_add(server_alpha) + }); + PendingValidatorEmission::::mutate(netuid, |total| { + *total = total.saturating_add(validator_alpha) + }); + } + + // Get and drain the subnet pending emission. + let pending_server_alpha = PendingServerEmission::::get(netuid); + PendingServerEmission::::insert(netuid, AlphaCurrency::ZERO); + + let pending_validator_alpha = PendingValidatorEmission::::get(netuid); + PendingValidatorEmission::::insert(netuid, AlphaCurrency::ZERO); // Get and drain the subnet pending root alpha divs. let pending_root_alpha = PendingRootAlphaDivs::::get(netuid); @@ -265,16 +294,12 @@ impl Pallet { let owner_cut = PendingOwnerCut::::get(netuid); PendingOwnerCut::::insert(netuid, AlphaCurrency::ZERO); - // Get total emission and drain. - let total_emission = TotalEmission::::get(netuid); - TotalEmission::::insert(netuid, AlphaCurrency::ZERO); - // Distribute the emission. Self::distribute_emission( netuid, - pending_alpha, + pending_server_alpha, + pending_validator_alpha, pending_root_alpha, - total_emission, owner_cut, ); } else { @@ -645,20 +670,23 @@ impl Pallet { pub fn distribute_emission( netuid: NetUid, - pending_alpha: AlphaCurrency, + pending_server_alpha: AlphaCurrency, + pending_validator_alpha: AlphaCurrency, pending_root_alpha: AlphaCurrency, - total_alpha: AlphaCurrency, - owner_cut: AlphaCurrency, + pending_owner_cut: AlphaCurrency, ) { log::debug!( - "Draining pending alpha emission for netuid {netuid:?}, pending_alpha: {pending_alpha:?}, pending_root_alpha: {pending_root_alpha:?}, owner_cut: {owner_cut:?}" + "Draining pending alpha emission for netuid {netuid:?}, pending_server_alpha: {pending_server_alpha:?}, pending_validator_alpha: {pending_validator_alpha:?}, pending_root_alpha: {pending_root_alpha:?}, pending_owner_cut: {pending_owner_cut:?}" ); let tao_weight = Self::get_tao_weight(); + let total_alpha_minus_owner_cut = pending_server_alpha + .saturating_add(pending_validator_alpha) + .saturating_add(pending_root_alpha); - // Run the epoch. + // Run the epoch, using the alpha going to both the servers and the validators. let hotkey_emission: Vec<(T::AccountId, AlphaCurrency, AlphaCurrency)> = - Self::epoch_with_mechanisms(netuid, total_alpha); + Self::epoch_with_mechanisms(netuid, total_alpha_minus_owner_cut); log::debug!("hotkey_emission: {hotkey_emission:?}"); // Compute the pending validator alpha. @@ -673,20 +701,20 @@ impl Pallet { }); log::debug!("incentive_sum: {incentive_sum:?}"); - let pending_validator_alpha = if !incentive_sum.is_zero() { - total_alpha - .saturating_div(2.into()) - .saturating_sub(pending_root_alpha) + let validator_alpha = if !incentive_sum.is_zero() { + pending_validator_alpha } else { - // If the incentive is 0, then Validators get 100% of the alpha. - pending_alpha + // If the incentive is 0, then Alpha Validators get . + pending_validator_alpha.saturating_add(pending_server_alpha) }; + let root_alpha = pending_root_alpha; + let owner_cut = pending_owner_cut; let (incentives, (alpha_dividends, root_alpha_dividends)) = Self::calculate_dividend_and_incentive_distribution( netuid, - pending_root_alpha, - pending_validator_alpha, + root_alpha, + validator_alpha, hotkey_emission, tao_weight, ); diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 3989733558..93471186e9 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1434,8 +1434,12 @@ pub mod pallet { pub type PendingEmission = StorageMap<_, Identity, NetUid, AlphaCurrency, ValueQuery, DefaultPendingEmission>; #[pallet::storage] - /// --- MAP ( netuid ) --> total_emission - pub type TotalEmission = + /// --- MAP ( netuid ) --> pending_server_emission + pub type PendingServerEmission = + StorageMap<_, Identity, NetUid, AlphaCurrency, ValueQuery, DefaultZeroAlpha>; + #[pallet::storage] + /// --- MAP ( netuid ) --> pending_validator_emission + pub type PendingValidatorEmission = StorageMap<_, Identity, NetUid, AlphaCurrency, ValueQuery, DefaultZeroAlpha>; /// --- MAP ( netuid ) --> pending_root_alpha_emission #[pallet::storage] From 6418911d66346df709f42153dfc9e18c43295696 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Fri, 7 Nov 2025 14:08:04 -0500 Subject: [PATCH 06/10] fix args for em distr in tests --- pallets/subtensor/src/tests/claim_root.rs | 28 +++++----- pallets/subtensor/src/tests/coinbase.rs | 66 +++++++++++------------ 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/pallets/subtensor/src/tests/claim_root.rs b/pallets/subtensor/src/tests/claim_root.rs index 5e8f0a8907..c11d88033f 100644 --- a/pallets/subtensor/src/tests/claim_root.rs +++ b/pallets/subtensor/src/tests/claim_root.rs @@ -75,7 +75,7 @@ fn test_claim_root_with_drain_emissions() { SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, - pending_root_alpha.into(), + AlphaCurrency::ZERO, pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -144,7 +144,7 @@ fn test_claim_root_with_drain_emissions() { SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, - pending_root_alpha.into(), + AlphaCurrency::ZERO, pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -246,7 +246,7 @@ fn test_claim_root_adding_stake_proportionally_for_two_stakers() { SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, - pending_root_alpha.into(), + AlphaCurrency::ZERO, pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -348,7 +348,7 @@ fn test_claim_root_adding_stake_disproportionally_for_two_stakers() { SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, - pending_root_alpha.into(), + AlphaCurrency::ZERO, pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -440,7 +440,7 @@ fn test_claim_root_with_changed_stake() { SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, - pending_root_alpha.into(), + AlphaCurrency::ZERO, pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -493,7 +493,7 @@ fn test_claim_root_with_changed_stake() { SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, - pending_root_alpha.into(), + AlphaCurrency::ZERO, pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -547,7 +547,7 @@ fn test_claim_root_with_changed_stake() { SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, - pending_root_alpha.into(), + AlphaCurrency::ZERO, pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -640,7 +640,7 @@ fn test_claim_root_with_drain_emissions_and_swap_claim_type() { SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, - pending_root_alpha.into(), + AlphaCurrency::ZERO, pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -685,7 +685,7 @@ fn test_claim_root_with_drain_emissions_and_swap_claim_type() { SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, - pending_root_alpha.into(), + AlphaCurrency::ZERO, pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -722,7 +722,7 @@ fn test_claim_root_with_drain_emissions_and_swap_claim_type() { SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, - pending_root_alpha.into(), + AlphaCurrency::ZERO, pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -1148,7 +1148,7 @@ fn test_claim_root_with_swap_coldkey() { SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, - pending_root_alpha.into(), + AlphaCurrency::ZERO, pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -1239,7 +1239,7 @@ fn test_claim_root_with_swap_hotkey() { SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, - pending_root_alpha.into(), + AlphaCurrency::ZERO, pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -1356,7 +1356,7 @@ fn test_claim_root_on_network_deregistration() { SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, - pending_root_alpha.into(), + AlphaCurrency::ZERO, pending_root_alpha.into(), AlphaCurrency::ZERO, ); @@ -1497,7 +1497,7 @@ fn test_claim_root_with_unrelated_subnets() { SubtensorModule::distribute_emission( netuid, AlphaCurrency::ZERO, - pending_root_alpha.into(), + AlphaCurrency::ZERO, pending_root_alpha.into(), AlphaCurrency::ZERO, ); diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index d97fbfb037..55706b47e3 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -747,9 +747,9 @@ fn test_drain_base_with_subnet_with_single_staker_not_registered() { let pending_alpha = AlphaCurrency::from(1_000_000_000); SubtensorModule::distribute_emission( netuid, - pending_alpha.into(), + pending_alpha.saturating_div(2.into()).into(), + pending_alpha.saturating_div(2.into()).into(), AlphaCurrency::ZERO, - pending_alpha.into(), AlphaCurrency::ZERO, ); let stake_after = @@ -777,9 +777,9 @@ fn test_drain_base_with_subnet_with_single_staker_registered() { let pending_alpha = AlphaCurrency::from(1_000_000_000); SubtensorModule::distribute_emission( netuid, - pending_alpha, + pending_alpha.saturating_div(2.into()).into(), + pending_alpha.saturating_div(2.into()).into(), AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); let stake_after = @@ -822,9 +822,9 @@ fn test_drain_base_with_subnet_with_single_staker_registered_root_weight() { assert_eq!(SubnetTAO::::get(NetUid::ROOT), TaoCurrency::ZERO); SubtensorModule::distribute_emission( netuid, - pending_alpha, + pending_alpha.saturating_div(2.into()).into(), + pending_alpha.saturating_div(2.into()).into(), pending_root_alpha, - pending_alpha.saturating_add(pending_root_alpha), AlphaCurrency::ZERO, ); let stake_after = @@ -870,9 +870,9 @@ fn test_drain_base_with_subnet_with_two_stakers_registered() { let pending_alpha = AlphaCurrency::from(1_000_000_000); SubtensorModule::distribute_emission( netuid, - pending_alpha, + pending_alpha.saturating_div(2.into()).into(), + pending_alpha.saturating_div(2.into()).into(), AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -936,9 +936,9 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root() { assert_eq!(SubnetTAO::::get(NetUid::ROOT), TaoCurrency::ZERO); SubtensorModule::distribute_emission( netuid, - pending_alpha, + pending_alpha.saturating_div(2.into()).into(), + pending_alpha.saturating_div(2.into()).into(), AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -1012,10 +1012,10 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am assert_eq!(SubnetTAO::::get(NetUid::ROOT), TaoCurrency::ZERO); SubtensorModule::distribute_emission( netuid, - pending_alpha, + pending_alpha.saturating_div(2.into()).into(), + pending_alpha.saturating_div(2.into()).into(), + AlphaCurrency::ZERO, AlphaCurrency::ZERO, - pending_alpha, - 0.into(), ); let stake_after1 = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey1, &coldkey, netuid); @@ -1093,9 +1093,9 @@ fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_am assert_eq!(SubnetTAO::::get(NetUid::ROOT), TaoCurrency::ZERO); SubtensorModule::distribute_emission( netuid, - pending_alpha, + pending_alpha.saturating_div(2.into()).into(), + pending_alpha.saturating_div(2.into()).into(), AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); let stake_after1 = @@ -1155,9 +1155,9 @@ fn test_drain_alpha_childkey_parentkey() { let pending_alpha = AlphaCurrency::from(1_000_000_000); SubtensorModule::distribute_emission( netuid, - pending_alpha, + pending_alpha.saturating_div(2.into()).into(), + pending_alpha.saturating_div(2.into()).into(), AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); let parent_stake_after = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); @@ -1381,9 +1381,9 @@ fn test_get_root_children_drain() { let pending_alpha = AlphaCurrency::from(1_000_000_000); SubtensorModule::distribute_emission( alpha, - pending_alpha, + pending_alpha.saturating_div(2.into()).into(), + pending_alpha.saturating_div(2.into()).into(), AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -1405,9 +1405,9 @@ fn test_get_root_children_drain() { let pending_root1 = TaoCurrency::from(1_000_000_000); SubtensorModule::distribute_emission( alpha, - pending_alpha, + pending_alpha.saturating_div(2.into()).into(), + pending_alpha.saturating_div(2.into()).into(), AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -1429,9 +1429,9 @@ fn test_get_root_children_drain() { let pending_root2 = TaoCurrency::from(1_000_000_000); SubtensorModule::distribute_emission( alpha, - pending_alpha, + pending_alpha.saturating_div(2.into()).into(), + pending_alpha.saturating_div(2.into()).into(), AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -1518,9 +1518,9 @@ fn test_get_root_children_drain_half_proportion() { let pending_alpha = AlphaCurrency::from(1_000_000_000); SubtensorModule::distribute_emission( alpha, - pending_alpha, + pending_alpha.saturating_div(2.into()).into(), + pending_alpha.saturating_div(2.into()).into(), AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -1605,9 +1605,9 @@ fn test_get_root_children_drain_with_take() { let pending_alpha = AlphaCurrency::from(1_000_000_000); SubtensorModule::distribute_emission( alpha, - pending_alpha, + pending_alpha.saturating_div(2.into()).into(), + pending_alpha.saturating_div(2.into()).into(), AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -1693,9 +1693,9 @@ fn test_get_root_children_drain_with_half_take() { let pending_alpha = AlphaCurrency::from(1_000_000_000); SubtensorModule::distribute_emission( alpha, - pending_alpha, + pending_alpha.saturating_div(2.into()).into(), + pending_alpha.saturating_div(2.into()).into(), AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); @@ -2409,9 +2409,9 @@ fn test_distribute_emission_no_miners_all_drained() { // Run drain pending without any miners. SubtensorModule::distribute_emission( netuid, - emission, + emission.saturating_div(2.into()).into(), + emission.saturating_div(2.into()).into(), AlphaCurrency::ZERO, - emission, AlphaCurrency::ZERO, ); @@ -2776,9 +2776,9 @@ fn test_drain_alpha_childkey_parentkey_with_burn() { let pending_alpha = AlphaCurrency::from(1_000_000_000); SubtensorModule::distribute_emission( netuid, - pending_alpha, + pending_alpha.saturating_div(2.into()).into(), + pending_alpha.saturating_div(2.into()).into(), AlphaCurrency::ZERO, - pending_alpha, AlphaCurrency::ZERO, ); let parent_stake_after = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); From 264d9c337427783e8efc6ac8aa40571fd53d96dc Mon Sep 17 00:00:00 2001 From: camfairchild Date: Fri, 7 Nov 2025 14:19:12 -0500 Subject: [PATCH 07/10] use new pending em storages --- pallets/subtensor/src/coinbase/root.rs | 2 ++ pallets/subtensor/src/rpc_info/dynamic_info.rs | 4 +++- pallets/subtensor/src/rpc_info/metagraph.rs | 10 ++++++++-- pallets/subtensor/src/tests/children.rs | 3 ++- pallets/subtensor/src/tests/coinbase.rs | 17 ++++++++++++----- pallets/subtensor/src/tests/networks.rs | 6 ++++-- pallets/subtensor/src/utils/misc.rs | 3 --- 7 files changed, 31 insertions(+), 14 deletions(-) diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index 80965f0bbb..42f04b5754 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -315,6 +315,8 @@ impl Pallet { // --- 15. Mechanism step / emissions bookkeeping. FirstEmissionBlockNumber::::remove(netuid); PendingEmission::::remove(netuid); + PendingValidatorEmission::::remove(netuid); + PendingServerEmission::::remove(netuid); PendingRootAlphaDivs::::remove(netuid); PendingOwnerCut::::remove(netuid); BlocksSinceLastStep::::remove(netuid); diff --git a/pallets/subtensor/src/rpc_info/dynamic_info.rs b/pallets/subtensor/src/rpc_info/dynamic_info.rs index 3bfbda8676..d4f99176ac 100644 --- a/pallets/subtensor/src/rpc_info/dynamic_info.rs +++ b/pallets/subtensor/src/rpc_info/dynamic_info.rs @@ -62,7 +62,9 @@ impl Pallet { alpha_out_emission: SubnetAlphaOutEmission::::get(netuid).into(), alpha_in_emission: SubnetAlphaInEmission::::get(netuid).into(), tao_in_emission: SubnetTaoInEmission::::get(netuid).into(), - pending_alpha_emission: PendingEmission::::get(netuid).into(), + pending_alpha_emission: PendingValidatorEmission::::get(netuid) + .saturating_add(PendingServerEmission::::get(netuid)) + .into(), pending_root_emission: TaoCurrency::from(0u64).into(), subnet_volume: SubnetVolume::::get(netuid).into(), network_registered_at: NetworkRegisteredAt::::get(netuid).into(), diff --git a/pallets/subtensor/src/rpc_info/metagraph.rs b/pallets/subtensor/src/rpc_info/metagraph.rs index df0c8023b0..ea24657aeb 100644 --- a/pallets/subtensor/src/rpc_info/metagraph.rs +++ b/pallets/subtensor/src/rpc_info/metagraph.rs @@ -694,7 +694,9 @@ impl Pallet { alpha_out_emission: SubnetAlphaOutEmission::::get(netuid).into(), // amount injected in alpha reserves per block alpha_in_emission: SubnetAlphaInEmission::::get(netuid).into(), // amount injected outstanding per block tao_in_emission: SubnetTaoInEmission::::get(netuid).into(), // amount of tao injected per block - pending_alpha_emission: PendingEmission::::get(netuid).into(), // pending alpha to be distributed + pending_alpha_emission: PendingValidatorEmission::::get(netuid) + .saturating_add(PendingServerEmission::::get(netuid)) + .into(), // pending alpha to be distributed pending_root_emission: TaoCurrency::from(0u64).into(), // panding tao for root divs to be distributed subnet_volume: subnet_volume.into(), moving_price: SubnetMovingPrice::::get(netuid), @@ -1000,7 +1002,11 @@ impl Pallet { }, Some(SelectiveMetagraphIndex::PendingAlphaEmission) => SelectiveMetagraph { netuid: netuid.into(), - pending_alpha_emission: Some(PendingEmission::::get(netuid).into()), + pending_alpha_emission: Some( + PendingValidatorEmission::::get(netuid) + .saturating_add(PendingServerEmission::::get(netuid)) + .into(), + ), ..Default::default() }, Some(SelectiveMetagraphIndex::PendingRootEmission) => SelectiveMetagraph { diff --git a/pallets/subtensor/src/tests/children.rs b/pallets/subtensor/src/tests/children.rs index 14b7a0b29d..e8be57f021 100644 --- a/pallets/subtensor/src/tests/children.rs +++ b/pallets/subtensor/src/tests/children.rs @@ -3095,7 +3095,8 @@ fn test_parent_child_chain_emission() { ); // Set pending emission to 0 - PendingEmission::::insert(netuid, AlphaCurrency::ZERO); + PendingValidatorEmission::::insert(netuid, AlphaCurrency::ZERO); + PendingServerEmission::::insert(netuid, AlphaCurrency::ZERO); // Run epoch with emission value SubtensorModule::run_coinbase(emission); diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 55706b47e3..5366b3310b 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -686,16 +686,22 @@ fn test_pending_emission() { // 1 TAO / ( 1 + 3 ) = 0.25 * 1 / 2 = 125000000 assert_abs_diff_eq!( - u64::from(PendingEmission::::get(netuid)), - 1_000_000_000 - 125000000, + u64::from(PendingServerEmission::::get(netuid)), + 500_000_000, epsilon = 1 - ); // 1 - swapped. + ); // 1 / 2. + + assert_abs_diff_eq!( + u64::from(PendingValidatorEmission::::get(netuid)), + 500_000_000 - 125000000, + epsilon = 1 + ); // 1 / 2 - swapped. assert_abs_diff_eq!( u64::from(PendingRootAlphaDivs::::get(netuid)), 125000000, epsilon = 1 - ); // 1 / 2 = 125000000 + ); // 1 / 2 * 0.25 --> (from root_prop) }); } @@ -3081,9 +3087,10 @@ fn test_mining_emission_distribution_with_no_root_sell() { // Run again but with some root stake step_block(subnet_tempo - 2); assert_abs_diff_eq!( - PendingEmission::::get(netuid).to_u64(), + PendingServerEmission::::get(netuid).to_u64(), U96F32::saturating_from_num(per_block_emission) .saturating_mul(U96F32::saturating_from_num(subnet_tempo as u64)) + .saturating_mul(U96F32::saturating_from_num(0.5)) // miner cut .saturating_mul(U96F32::saturating_from_num(0.90)) .saturating_to_num::(), epsilon = 100_000_u64.into() diff --git a/pallets/subtensor/src/tests/networks.rs b/pallets/subtensor/src/tests/networks.rs index 3706878bb6..0fa27a99d6 100644 --- a/pallets/subtensor/src/tests/networks.rs +++ b/pallets/subtensor/src/tests/networks.rs @@ -374,7 +374,8 @@ fn dissolve_clears_all_per_subnet_storages() { SubnetMechanism::::insert(net, 1u16); NetworkRegistrationAllowed::::insert(net, true); NetworkPowRegistrationAllowed::::insert(net, true); - PendingEmission::::insert(net, AlphaCurrency::from(1)); + PendingServerEmission::::insert(net, AlphaCurrency::from(1)); + PendingValidatorEmission::::insert(net, AlphaCurrency::from(1)); PendingRootAlphaDivs::::insert(net, AlphaCurrency::from(1)); PendingOwnerCut::::insert(net, AlphaCurrency::from(1)); BlocksSinceLastStep::::insert(net, 1u64); @@ -529,7 +530,8 @@ fn dissolve_clears_all_per_subnet_storages() { assert!(!SubnetMechanism::::contains_key(net)); assert!(!NetworkRegistrationAllowed::::contains_key(net)); assert!(!NetworkPowRegistrationAllowed::::contains_key(net)); - assert!(!PendingEmission::::contains_key(net)); + assert!(!PendingServerEmission::::contains_key(net)); + assert!(!PendingValidatorEmission::::contains_key(net)); assert!(!PendingRootAlphaDivs::::contains_key(net)); assert!(!PendingOwnerCut::::contains_key(net)); assert!(!BlocksSinceLastStep::::contains_key(net)); diff --git a/pallets/subtensor/src/utils/misc.rs b/pallets/subtensor/src/utils/misc.rs index 0ba3df1103..46dc8e42c2 100644 --- a/pallets/subtensor/src/utils/misc.rs +++ b/pallets/subtensor/src/utils/misc.rs @@ -334,9 +334,6 @@ impl Pallet { pub fn get_tempo(netuid: NetUid) -> u16 { Tempo::::get(netuid) } - pub fn get_pending_emission(netuid: NetUid) -> AlphaCurrency { - PendingEmission::::get(netuid) - } pub fn get_last_adjustment_block(netuid: NetUid) -> u64 { LastAdjustmentBlock::::get(netuid) } From 94d093bf61e0d8a24ff7b408dfd4f6cb2717b050 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Fri, 7 Nov 2025 14:45:34 -0500 Subject: [PATCH 08/10] use migration to clear the old pending em map --- pallets/subtensor/src/coinbase/root.rs | 1 - .../subtensor/src/coinbase/run_coinbase.rs | 17 ----- pallets/subtensor/src/lib.rs | 4 - pallets/subtensor/src/macros/hooks.rs | 4 +- .../migrations/migrate_pending_emissions.rs | 73 +++++++++++++++++++ pallets/subtensor/src/migrations/mod.rs | 1 + 6 files changed, 77 insertions(+), 23 deletions(-) create mode 100644 pallets/subtensor/src/migrations/migrate_pending_emissions.rs diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index 42f04b5754..893f855f3e 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -314,7 +314,6 @@ impl Pallet { // --- 15. Mechanism step / emissions bookkeeping. FirstEmissionBlockNumber::::remove(netuid); - PendingEmission::::remove(netuid); PendingValidatorEmission::::remove(netuid); PendingServerEmission::::remove(netuid); PendingRootAlphaDivs::::remove(netuid); diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 428c23e41e..e25ccf6e27 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -262,23 +262,6 @@ impl Pallet { BlocksSinceLastStep::::insert(netuid, 0); LastMechansimStepBlock::::insert(netuid, current_block); - // Get and drain the PendingEmission. - // deprecated - let pending_emission = PendingEmission::::get(netuid); - PendingEmission::::insert(netuid, AlphaCurrency::ZERO); - // If pending_emission is not zero, we split it between the server emission and the validator emission. - if !pending_emission.is_zero() { - let server_alpha = pending_emission.saturating_div(2.into()); - let validator_alpha = pending_emission.saturating_sub(server_alpha); - - PendingServerEmission::::mutate(netuid, |total| { - *total = total.saturating_add(server_alpha) - }); - PendingValidatorEmission::::mutate(netuid, |total| { - *total = total.saturating_add(validator_alpha) - }); - } - // Get and drain the subnet pending emission. let pending_server_alpha = PendingServerEmission::::get(netuid); PendingServerEmission::::insert(netuid, AlphaCurrency::ZERO); diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 93471186e9..8e53fb9c4e 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1430,10 +1430,6 @@ pub mod pallet { pub type NetworkRegisteredAt = StorageMap<_, Identity, NetUid, u64, ValueQuery, DefaultNetworkRegisteredAt>; #[pallet::storage] - /// --- MAP ( netuid ) --> pending_emission - pub type PendingEmission = - StorageMap<_, Identity, NetUid, AlphaCurrency, ValueQuery, DefaultPendingEmission>; - #[pallet::storage] /// --- MAP ( netuid ) --> pending_server_emission pub type PendingServerEmission = StorageMap<_, Identity, NetUid, AlphaCurrency, ValueQuery, DefaultZeroAlpha>; diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index 7095ce8ecb..692de0e3fa 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -161,7 +161,9 @@ mod hooks { // Remove obsolete map entries .saturating_add(migrations::migrate_remove_tao_dividends::migrate_remove_tao_dividends::()) // Re-init tao flows - .saturating_add(migrations::migrate_init_tao_flow::migrate_init_tao_flow::()); + .saturating_add(migrations::migrate_init_tao_flow::migrate_init_tao_flow::()) + // Migrate pending emissions + .saturating_add(migrations::migrate_pending_emissions::migrate_pending_emissions::()); weight } diff --git a/pallets/subtensor/src/migrations/migrate_pending_emissions.rs b/pallets/subtensor/src/migrations/migrate_pending_emissions.rs new file mode 100644 index 0000000000..416080f5b2 --- /dev/null +++ b/pallets/subtensor/src/migrations/migrate_pending_emissions.rs @@ -0,0 +1,73 @@ +use super::*; +use frame_support::{storage_alias, traits::Get, weights::Weight}; +use substrate_fixed::types::U96F32; + +pub mod deprecated_pending_emission_format { + use super::*; + + #[storage_alias] + pub(super) type PendingEmission = + StorageMap, Identity, NetUid, AlphaCurrency, ValueQuery>; +} + +pub fn migrate_pending_emissions() -> Weight { + let migration_name = b"migrate_pending_emissions".to_vec(); + let mut weight: Weight = T::DbWeight::get().reads(1); + + // Skip if already executed + if HasMigrationRun::::get(&migration_name) { + log::info!( + target: "runtime", + "Migration '{}' already run - skipping.", + String::from_utf8_lossy(&migration_name) + ); + return weight; + } + log::info!( + "Running migration '{}'", + String::from_utf8_lossy(&migration_name) + ); + + // Pull from PendingEmission and distribute to PendingValidatorEmission and PendingServerEmission + for (netuid, pending_emission) in + deprecated_pending_emission_format::PendingEmission::::iter() + { + // Split up the pending emission into server and validator emission + // Server emission is pending+root_alpha times the 50% miner cut. + let root_alpha: U96F32 = + U96F32::saturating_from_num(PendingRootAlphaDivs::::get(netuid).to_u64()); + let server_emission_float: U96F32 = U96F32::saturating_from_num(pending_emission.to_u64()) + .saturating_add(root_alpha) + .saturating_div(U96F32::saturating_from_num(2)); + let server_emission: AlphaCurrency = + server_emission_float.saturating_to_num::().into(); + let validator_emission = pending_emission.saturating_sub(server_emission); + + PendingValidatorEmission::::mutate(netuid, |total| { + *total = total.saturating_add(validator_emission) + }); + PendingServerEmission::::mutate(netuid, |total| { + *total = total.saturating_add(server_emission) + }); + + weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 2)); + } + + // Kill the map + let removal_result = + deprecated_pending_emission_format::PendingEmission::::clear(u32::MAX, None); + weight = weight.saturating_add( + T::DbWeight::get().reads_writes(removal_result.loops as u64, removal_result.backend as u64), + ); + + // Mark Migration as Completed + HasMigrationRun::::insert(&migration_name, true); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); + + log::info!( + "Migration '{:?}' completed successfully.", + String::from_utf8_lossy(&migration_name) + ); + + weight +} diff --git a/pallets/subtensor/src/migrations/mod.rs b/pallets/subtensor/src/migrations/mod.rs index 7fe37617fd..b6aac3d7d8 100644 --- a/pallets/subtensor/src/migrations/mod.rs +++ b/pallets/subtensor/src/migrations/mod.rs @@ -27,6 +27,7 @@ pub mod migrate_network_immunity_period; pub mod migrate_network_lock_cost_2500; pub mod migrate_network_lock_reduction_interval; pub mod migrate_orphaned_storage_items; +pub mod migrate_pending_emissions; pub mod migrate_populate_owned_hotkeys; pub mod migrate_rao; pub mod migrate_rate_limit_keys; From c2e6ab702190f1678898dca890e79e1655f93281 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Fri, 7 Nov 2025 15:39:49 -0500 Subject: [PATCH 09/10] amend comment --- pallets/subtensor/src/coinbase/run_coinbase.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index e25ccf6e27..33f05b68a4 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -687,7 +687,7 @@ impl Pallet { let validator_alpha = if !incentive_sum.is_zero() { pending_validator_alpha } else { - // If the incentive is 0, then Alpha Validators get . + // If the incentive is 0, then Alpha Validators get both the server and validator alpha. pending_validator_alpha.saturating_add(pending_server_alpha) }; let root_alpha = pending_root_alpha; From e931123e664877ffdd326eb44056c3a453717158 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Fri, 7 Nov 2025 17:58:32 -0500 Subject: [PATCH 10/10] Update pallets/subtensor/src/lib.rs Co-authored-by: Loris Moulin <45130584+l0r1s@users.noreply.github.com> --- pallets/subtensor/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 8e53fb9c4e..6c3ee1d84e 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1433,8 +1433,8 @@ pub mod pallet { /// --- MAP ( netuid ) --> pending_server_emission pub type PendingServerEmission = StorageMap<_, Identity, NetUid, AlphaCurrency, ValueQuery, DefaultZeroAlpha>; - #[pallet::storage] /// --- MAP ( netuid ) --> pending_validator_emission + #[pallet::storage] pub type PendingValidatorEmission = StorageMap<_, Identity, NetUid, AlphaCurrency, ValueQuery, DefaultZeroAlpha>; /// --- MAP ( netuid ) --> pending_root_alpha_emission