diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 7de39aa38a..90e0c12929 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -554,7 +554,7 @@ pub mod pallet { } /// The extrinsic sets the minimum burn for a subnet. - /// It is only callable by the root account or subnet owner. + /// It is only callable by the root account. /// The extrinsic will call the Subtensor pallet to set the minimum burn. #[pallet::call_index(22)] #[pallet::weight(::WeightInfo::sudo_set_min_burn())] @@ -563,7 +563,7 @@ pub mod pallet { netuid: u16, min_burn: u64, ) -> DispatchResult { - pallet_subtensor::Pallet::::ensure_subnet_owner_or_root(origin, netuid)?; + ensure_root(origin)?; ensure!( pallet_subtensor::Pallet::::if_subnet_exist(netuid), diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 7516857b49..b57a085034 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -122,20 +122,26 @@ impl Pallet { netuid, subnet_proportion ); - // 3.7: Calculate subnet's TAO emission: E_s = P_s * E_m - let tao_in: u64 = mech_emission - .checked_mul(subnet_proportion) - .unwrap_or(I96F32::saturating_from_num(0)) - .saturating_to_num::(); - log::debug!( - "Subnet TAO emission (E_s) for netuid {:?}: {:?}", - netuid, - tao_in - ); - // 3.8: Store the subnet TAO emission. - *tao_in_map.entry(*netuid).or_insert(0) = tao_in; - // 3.9: Store the block emission for this subnet for chain storage. - EmissionValues::::insert(*netuid, tao_in); + + // Only emit TAO if the subnetwork allows registration. + if Self::get_network_registration_allowed(*netuid) + || Self::get_network_pow_registration_allowed(*netuid) + { + // 3.7: Calculate subnet's TAO emission: E_s = P_s * E_m + let tao_in: u64 = mech_emission + .checked_mul(subnet_proportion) + .unwrap_or(I96F32::saturating_from_num(0)) + .saturating_to_num::(); + log::debug!( + "Subnet TAO emission (E_s) for netuid {:?}: {:?}", + netuid, + tao_in + ); + // 3.8: Store the subnet TAO emission. + *tao_in_map.entry(*netuid).or_insert(0) = tao_in; + // 3.9: Store the block emission for this subnet for chain storage. + EmissionValues::::insert(*netuid, tao_in); + } } // == We'll save the owner cuts for each subnet. diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index ff4908172e..fb7a927be8 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -389,3 +389,189 @@ fn test_total_issuance_after_coinbase() { ); }); } + +// Verifies that the total issuance after the coinbase is not changed when registration is disabled. +// Includes TAO weight. +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_registration_disabled_total_issuance_same --exact --show-output --nocapture +#[test] +fn test_registration_disabled_total_issuance_same() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + add_network(netuid, 1, 0); + // Set TAO weight to 18% + SubtensorModule::set_tao_weight(I96F32::from_num(0.18).saturating_to_num::()); + // Set owner cut to ~11.11% + SubtensorModule::set_subnet_owner_cut(u16::MAX / 9); + let total_coinbase_emission: I96F32 = I96F32::from_num(1_123_456_789); + let epsilon: u64 = 100; + + // Define hotkeys and coldkeys + let hotkey_a: U256 = U256::from(1); + let hotkey_b: U256 = U256::from(2); + let hotkey_c: U256 = U256::from(3); + let coldkey_a: U256 = U256::from(100); + let coldkey_b: U256 = U256::from(101); + let coldkey_c: U256 = U256::from(102); + + // Register neurons with decreasing stakes + register_ok_neuron(netuid, hotkey_a, coldkey_a, 0); + register_ok_neuron(netuid, hotkey_b, coldkey_b, 0); + register_ok_neuron(netuid, hotkey_c, coldkey_c, 0); + + // Add initial stakes + SubtensorModule::add_balance_to_coldkey_account(&coldkey_a, 1_000); + SubtensorModule::add_balance_to_coldkey_account(&coldkey_b, 1_000); + SubtensorModule::add_balance_to_coldkey_account(&coldkey_c, 1_000); + + // Swap to alpha + let total_tao: I96F32 = I96F32::from_num(300_000 + 100_000 + 50_000); + let total_alpha: I96F32 = I96F32::from_num(SubtensorModule::swap_tao_for_alpha( + netuid, + total_tao.saturating_to_num::(), + )); + + // Set the stakes directly + // This avoids needing to swap tao to alpha, impacting the initial stake distribution. + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_a, + &coldkey_a, + netuid, + (total_alpha * I96F32::from_num(300_000) / total_tao).saturating_to_num::(), + ); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_b, + &coldkey_b, + netuid, + (total_alpha * I96F32::from_num(100_000) / total_tao).saturating_to_num::(), + ); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_c, + &coldkey_c, + netuid, + (total_alpha * I96F32::from_num(50_000) / total_tao).saturating_to_num::(), + ); + + // Stake some to root + let stake_to_root: u64 = 10_000_000; + SubtensorModule::add_balance_to_coldkey_account(&coldkey_a, stake_to_root); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_a, + &coldkey_a, + netuid, + stake_to_root, + ); + + let alpha_price = SubtensorModule::get_alpha_price(netuid); + log::info!("alpha_price: {:?}", alpha_price); + + // Get the total issuance + let mut total_issuance_before = TotalIssuance::::get(); + log::info!("total_issuance_before: {:?}", total_issuance_before); + + // Disable registration on the network + SubtensorModule::set_network_registration_allowed(netuid, false); + SubtensorModule::set_network_pow_registration_allowed(netuid, false); + + // Run the coinbase + SubtensorModule::run_coinbase(total_coinbase_emission); + + // Should be the same + let total_issuance_after = TotalIssuance::::get(); + assert_abs_diff_eq!( + total_issuance_after, + total_issuance_before, + epsilon = epsilon + ); + }); +} + +// Verifies that the TAO-in after the coinbase is not changed when registration is disabled. +// Includes TAO weight. +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_registration_disabled_tao_in_same --exact --show-output --nocapture +#[test] +fn test_registration_disabled_tao_in_same() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + add_network(netuid, 1, 0); + // Set TAO weight to 18% + SubtensorModule::set_tao_weight(I96F32::from_num(0.18).saturating_to_num::()); + // Set owner cut to ~11.11% + SubtensorModule::set_subnet_owner_cut(u16::MAX / 9); + let total_coinbase_emission: I96F32 = I96F32::from_num(1_123_456_789); + let epsilon: u64 = 100; + + // Define hotkeys and coldkeys + let hotkey_a: U256 = U256::from(1); + let hotkey_b: U256 = U256::from(2); + let hotkey_c: U256 = U256::from(3); + let coldkey_a: U256 = U256::from(100); + let coldkey_b: U256 = U256::from(101); + let coldkey_c: U256 = U256::from(102); + + // Register neurons with decreasing stakes + register_ok_neuron(netuid, hotkey_a, coldkey_a, 0); + register_ok_neuron(netuid, hotkey_b, coldkey_b, 0); + register_ok_neuron(netuid, hotkey_c, coldkey_c, 0); + + // Add initial stakes + SubtensorModule::add_balance_to_coldkey_account(&coldkey_a, 1_000); + SubtensorModule::add_balance_to_coldkey_account(&coldkey_b, 1_000); + SubtensorModule::add_balance_to_coldkey_account(&coldkey_c, 1_000); + + // Swap to alpha + let total_tao: I96F32 = I96F32::from_num(300_000 + 100_000 + 50_000); + let total_alpha: I96F32 = I96F32::from_num(SubtensorModule::swap_tao_for_alpha( + netuid, + total_tao.saturating_to_num::(), + )); + + // Set the stakes directly + // This avoids needing to swap tao to alpha, impacting the initial stake distribution. + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_a, + &coldkey_a, + netuid, + (total_alpha * I96F32::from_num(300_000) / total_tao).saturating_to_num::(), + ); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_b, + &coldkey_b, + netuid, + (total_alpha * I96F32::from_num(100_000) / total_tao).saturating_to_num::(), + ); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_c, + &coldkey_c, + netuid, + (total_alpha * I96F32::from_num(50_000) / total_tao).saturating_to_num::(), + ); + + // Stake some to root + let stake_to_root: u64 = 10_000_000; + SubtensorModule::add_balance_to_coldkey_account(&coldkey_a, stake_to_root); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey_a, + &coldkey_a, + netuid, + stake_to_root, + ); + + let alpha_price = SubtensorModule::get_alpha_price(netuid); + log::info!("alpha_price: {:?}", alpha_price); + + // Get the total issuance + let mut tao_in_before = SubnetTAO::::get(netuid); + log::info!("tao_in_before: {:?}", tao_in_before); + + // Disable registration on the network + SubtensorModule::set_network_registration_allowed(netuid, false); + SubtensorModule::set_network_pow_registration_allowed(netuid, false); + + // Run the coinbase + SubtensorModule::run_coinbase(total_coinbase_emission); + + // Should be the same + let tao_in_after = SubnetTAO::::get(netuid); + assert_abs_diff_eq!(tao_in_after, tao_in_before, epsilon = epsilon); + }); +}