From 0178b88495a7a595e4790be2c2a38e95367829a1 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 26 May 2025 11:52:00 -0700 Subject: [PATCH 1/7] impl get_network_to_prune --- pallets/subtensor/src/subnets/subnet.rs | 36 +++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index b122bfa049..bf7ada34d8 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -440,4 +440,40 @@ impl Pallet { pub fn is_valid_subnet_for_emission(netuid: u16) -> bool { FirstEmissionBlockNumber::::get(netuid).is_some() } + + pub fn get_network_to_prune() -> Option { + let current_block: u64 = Self::get_current_block_as_u64(); + let total_networks: u16 = TotalNetworks::::get(); + + let mut candidate_netuid: Option = None; + let mut candidate_emission = u64::MAX; + let mut candidate_timestamp = u64::MAX; + + for netuid in 1..=total_networks { + if FirstEmissionBlockNumber::::get(netuid).is_none() { + continue; + } + + let registered_at = NetworkRegisteredAt::::get(netuid); + let immunity_period = ImmunityPeriod::::get(netuid); + if current_block < registered_at.saturating_add(immunity_period as u64) { + continue; + } + + // We want total emission across all UIDs in this subnet: + let emission_vec = Emission::::get(netuid); + let total_emission = emission_vec.iter().sum::(); + + // If tie on total_emission, earliest registration wins + if total_emission < candidate_emission + || (total_emission == candidate_emission && registered_at < candidate_timestamp) + { + candidate_netuid = Some(netuid); + candidate_emission = total_emission; + candidate_timestamp = registered_at; + } + } + + candidate_netuid + } } From 562823c73e7403196a3a799a045cb97fbf91c005 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Tue, 27 May 2025 11:54:17 -0700 Subject: [PATCH 2/7] use NetworkImmunityPeriod --- pallets/subtensor/src/subnets/subnet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index bf7ada34d8..1f6524e2b2 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -455,7 +455,7 @@ impl Pallet { } let registered_at = NetworkRegisteredAt::::get(netuid); - let immunity_period = ImmunityPeriod::::get(netuid); + let immunity_period = Self::get_network_immunity_period(); if current_block < registered_at.saturating_add(immunity_period as u64) { continue; } From b2ef90e55e8290e13a8ba6ac2462a96bf0326910 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Tue, 27 May 2025 13:45:56 -0700 Subject: [PATCH 3/7] update get_network_to_prune. --- pallets/subtensor/src/subnets/subnet.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index 1f6524e2b2..a04ae1df07 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -441,6 +441,11 @@ impl Pallet { FirstEmissionBlockNumber::::get(netuid).is_some() } + /// Select a subnet to prune: + /// - Only consider subnets that are Enabled. + /// - Exclude subnets still within `ImmunityPeriod`. + /// - Pick the one with the lowest total emission + /// - In the case of a tie, pick the earliest registered. pub fn get_network_to_prune() -> Option { let current_block: u64 = Self::get_current_block_as_u64(); let total_networks: u16 = TotalNetworks::::get(); @@ -450,19 +455,22 @@ impl Pallet { let mut candidate_timestamp = u64::MAX; for netuid in 1..=total_networks { - if FirstEmissionBlockNumber::::get(netuid).is_none() { - continue; - } + // Exclude disabled subnets + let first_emission_block = match FirstEmissionBlockNumber::::get(netuid) { + Some(block) => block, + None => continue, + }; - let registered_at = NetworkRegisteredAt::::get(netuid); + // Check if the subnet's immunity period is expired. let immunity_period = Self::get_network_immunity_period(); - if current_block < registered_at.saturating_add(immunity_period as u64) { + if current_block < first_emission_block.saturating_add(immunity_period as u64) { continue; } // We want total emission across all UIDs in this subnet: let emission_vec = Emission::::get(netuid); let total_emission = emission_vec.iter().sum::(); + let registered_at = NetworkRegisteredAt::::get(netuid); // If tie on total_emission, earliest registration wins if total_emission < candidate_emission From d569309fdd0a65d1dfafc0d3fbaa88bac370fca5 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Tue, 27 May 2025 14:39:41 -0700 Subject: [PATCH 4/7] add `NetworkActivationDeadline ` --- pallets/subtensor/src/coinbase/root.rs | 3 +++ pallets/subtensor/src/lib.rs | 9 +++++++++ pallets/subtensor/src/subnets/subnet.rs | 19 ++++++++++++++----- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index 1f3a91b339..e8d529309d 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -627,6 +627,9 @@ impl Pallet { pub fn get_network_immunity_period() -> u64 { NetworkImmunityPeriod::::get() } + pub fn get_network_activation_deadline() -> u64 { + NetworkActivationDeadline::::get() + } pub fn set_network_immunity_period(net_immunity_period: u64) { NetworkImmunityPeriod::::set(net_immunity_period); Self::deposit_event(Event::NetworkImmunityPeriodSet(net_immunity_period)); diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 197cd5f8f7..8e148bee69 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -556,6 +556,11 @@ pub mod pallet { T::InitialNetworkImmunityPeriod::get() } #[pallet::type_value] + /// Default value for network activation deadline. + pub fn DefaultNetworkActivationDeadline() -> u64 { + 1_296_000 + } + #[pallet::type_value] /// Default value for network last registered. pub fn DefaultNetworkLastRegistered() -> u64 { 0 @@ -1194,6 +1199,10 @@ pub mod pallet { pub type NetworkImmunityPeriod = StorageValue<_, u64, ValueQuery, DefaultNetworkImmunityPeriod>; #[pallet::storage] + /// ITEM( network_activation_deadline ) + pub type NetworkActivationDeadline = + StorageValue<_, u64, ValueQuery, DefaultNetworkActivationDeadline>; + #[pallet::storage] /// ITEM( network_last_registered_block ) pub type NetworkLastRegistered = StorageValue<_, u64, ValueQuery, DefaultNetworkLastRegistered>; diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index a04ae1df07..c60689d23d 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -455,22 +455,31 @@ impl Pallet { let mut candidate_timestamp = u64::MAX; for netuid in 1..=total_networks { - // Exclude disabled subnets - let first_emission_block = match FirstEmissionBlockNumber::::get(netuid) { + let registered_at = NetworkRegisteredAt::::get(netuid); + + let start_block = match FirstEmissionBlockNumber::::get(netuid) { Some(block) => block, - None => continue, + None => { + // Not enabled yet. If still within ActivationDeadline, skip pruning this subnet. + if current_block + < registered_at.saturating_add(Self::get_network_activation_deadline()) + { + continue; + } + // Otherwise, we treat it as if it started at its registered time + registered_at + } }; // Check if the subnet's immunity period is expired. let immunity_period = Self::get_network_immunity_period(); - if current_block < first_emission_block.saturating_add(immunity_period as u64) { + if current_block < start_block.saturating_add(immunity_period as u64) { continue; } // We want total emission across all UIDs in this subnet: let emission_vec = Emission::::get(netuid); let total_emission = emission_vec.iter().sum::(); - let registered_at = NetworkRegisteredAt::::get(netuid); // If tie on total_emission, earliest registration wins if total_emission < candidate_emission From 8016183fbdbafb44bcbb31f5416e372e2a191ed2 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 2 Jun 2025 08:35:21 -0700 Subject: [PATCH 5/7] WIP --- pallets/subtensor/src/coinbase/root.rs | 219 +++++++++++++++------ pallets/subtensor/src/macros/dispatches.rs | 2 +- pallets/subtensor/src/subnets/subnet.rs | 53 ----- pallets/subtensor/src/tests/networks.rs | 3 +- 4 files changed, 162 insertions(+), 115 deletions(-) diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index e8d529309d..218137b8eb 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -22,7 +22,9 @@ use frame_support::weights::Weight; use safe_math::*; use sp_core::Get; use sp_std::vec; -use substrate_fixed::types::I64F64; +use sp_runtime::Perbill; +use substrate_fixed::types::{I64F64, U96F32}; +use sp_runtime::PerThing; impl Pallet { /// Fetches the total count of root network validators @@ -427,64 +429,25 @@ impl Pallet { .into()) } - /// Facilitates the removal of a user's subnetwork. - /// - /// # Args: - /// * 'origin': ('T::RuntimeOrigin'): The calling origin. Must be signed. - /// * 'netuid': ('u16'): The unique identifier of the network to be removed. - /// - /// # Event: - /// * 'NetworkRemoved': Emitted when a network is successfully removed. - /// - /// # Raises: - /// * 'SubNetworkDoesNotExist': If the specified network does not exist. - /// * 'NotSubnetOwner': If the caller does not own the specified subnet. - /// - pub fn user_remove_network(coldkey: T::AccountId, netuid: u16) -> dispatch::DispatchResult { - // --- 1. Ensure this subnet exists. - ensure!( - Self::if_subnet_exist(netuid), - Error::::SubNetworkDoesNotExist - ); - - // --- 2. Ensure the caller owns this subnet. - ensure!( - SubnetOwner::::get(netuid) == coldkey, - Error::::NotSubnetOwner - ); - - // --- 4. Remove the subnet identity if it exists. - if SubnetIdentitiesV2::::take(netuid).is_some() { - Self::deposit_event(Event::SubnetIdentityRemoved(netuid)); - } + pub fn do_dissolve_network(netuid: u16) -> dispatch::DispatchResult { + // --- Perform the dtTao-compatible cleanup before removing the network. + Self::destroy_alpha_in_out_stakes(netuid)?; - // --- 5. Explicitly erase the network and all its parameters. + // --- Finally, remove the network entirely. + ensure!(Self::if_subnet_exist(netuid), Error::::SubNetworkDoesNotExist); Self::remove_network(netuid); - // --- 6. Emit the NetworkRemoved event. + // --- Emit event. log::debug!("NetworkRemoved( netuid:{:?} )", netuid); Self::deposit_event(Event::NetworkRemoved(netuid)); - // --- 7. Return success. Ok(()) } - /// Removes a network (identified by netuid) and all associated parameters. - /// - /// This function is responsible for cleaning up all the data associated with a network. - /// It ensures that all the storage values related to the network are removed, any - /// reserved balance is returned to the network owner, and the subnet identity is removed if it exists. - /// - /// # Args: - /// * 'netuid': ('u16'): The unique identifier of the network to be removed. - /// - /// # Note: - /// This function does not emit any events, nor does it raise any errors. It silently - /// returns if any internal checks fail. pub fn remove_network(netuid: u16) { - // --- 1. Return balance to subnet owner. + // --- 1. Get the owner and remove from SubnetOwner. let owner_coldkey: T::AccountId = SubnetOwner::::get(netuid); - let reserved_amount: u64 = Self::get_subnet_locked_balance(netuid); + SubnetOwner::::remove(netuid); // --- 2. Remove network count. SubnetworkN::::remove(netuid); @@ -507,28 +470,26 @@ impl Pallet { let _ = Keys::::clear_prefix(netuid, u32::MAX, None); let _ = Bonds::::clear_prefix(netuid, u32::MAX, None); - // --- 8. Removes the weights for this subnet (do not remove). + // --- 8. Remove the weights for this subnet itself. let _ = Weights::::clear_prefix(netuid, u32::MAX, None); - // --- 9. Iterate over stored weights and fill the matrix. + // --- 9. Also zero out any weights *in the root network* that point to this netuid. for (uid_i, weights_i) in as IterableStorageDoubleMap>>::iter_prefix( Self::get_root_netuid(), ) { - // Create a new vector to hold modified weights. let mut modified_weights: Vec<(u16, u16)> = weights_i.clone(); - // Iterate over each weight entry to potentially update it. for (subnet_id, weight) in modified_weights.iter_mut() { + // If the root network had a weight pointing to this netuid, set it to 0 if subnet_id == &netuid { - // If the condition matches, modify the weight - *weight = 0; // Set weight to 0 for the matching subnet_id. + *weight = 0; } } Weights::::insert(Self::get_root_netuid(), uid_i, modified_weights); } - // --- 10. Remove various network-related parameters. + // --- 10. Remove various network-related parameters and data. Rank::::remove(netuid); Trust::::remove(netuid); Active::::remove(netuid); @@ -558,16 +519,26 @@ impl Pallet { POWRegistrationsThisInterval::::remove(netuid); BurnRegistrationsThisInterval::::remove(netuid); - // --- 12. Add the balance back to the owner. - Self::add_balance_to_coldkey_account(&owner_coldkey, reserved_amount); - Self::set_subnet_locked_balance(netuid, 0); - SubnetOwner::::remove(netuid); + // --- 12. Remove additional dTao-related storages if applicable. + SubnetTAO::::remove(netuid); + SubnetAlphaInEmission::::remove(netuid); + SubnetAlphaOutEmission::::remove(netuid); + SubnetTaoInEmission::::remove(netuid); + SubnetVolume::::remove(netuid); + SubnetMovingPrice::::remove(netuid); // --- 13. Remove subnet identity if it exists. if SubnetIdentitiesV2::::contains_key(netuid) { SubnetIdentitiesV2::::remove(netuid); Self::deposit_event(Event::SubnetIdentityRemoved(netuid)); } + + // --- Log final removal. + log::debug!( + "remove_network: netuid={}, owner={:?} removed successfully", + netuid, + owner_coldkey + ); } #[allow(clippy::arithmetic_side_effects)] @@ -674,4 +645,134 @@ impl Pallet { pub fn set_rate_limited_last_block(rate_limit_key: &RateLimitKey, block: u64) { LastRateLimitedBlock::::set(rate_limit_key, block); } + + fn destroy_alpha_in_out_stakes(netuid: u16) -> DispatchResult { + // 1. Ensure the subnet exists. + ensure!(Self::if_subnet_exist(netuid), Error::::SubNetworkDoesNotExist); + + // 2. Gather relevant info. + let owner_coldkey: T::AccountId = SubnetOwner::::get(netuid); + let lock_cost: u64 = Self::get_subnet_locked_balance(netuid); + + // (Optional) Grab total emission in Tao. + let emission_vec = Emission::::get(netuid); + let total_emission: u64 = emission_vec.iter().sum(); + + // The portion the owner received is total_emission * owner_cut (stored as fraction in U96F32). + let owner_fraction = Self::get_float_subnet_owner_cut(); + let owner_received_emission = (U96F32::from_num(total_emission) * owner_fraction) + .floor() + .saturating_to_num::(); + + // 3. Destroy α stakes and distribute remaining subnet Tao to α-out stakers (pro rata). + let mut total_alpha_out: u128 = 0; + let mut stakers_data = Vec::new(); + + // (A) First pass: sum total alpha-out for this netuid. + for ((hotkey, coldkey, this_netuid), alpha_shares) in Alpha::::iter() { + if this_netuid == netuid { + // alpha_shares is U64F64; convert to u128 for ratio math + let alpha_as_u128 = alpha_shares.saturating_to_num::(); + total_alpha_out = total_alpha_out.saturating_add(alpha_as_u128); + stakers_data.push((hotkey, coldkey, alpha_as_u128)); + } + } + + // (B) Second pass: distribute the subnet’s Tao among those stakers. + let subnet_tao = SubnetTAO::::get(netuid); + + if total_alpha_out > 0 { + let accuracy_as_u128 = u128::from(Perbill::ACCURACY); + + for (hotkey, coldkey, alpha_amount) in stakers_data { + let scaled = alpha_amount + .saturating_mul(accuracy_as_u128) + .checked_div(total_alpha_out) + .unwrap_or(0); + + // Clamp to avoid overflow beyond the Perbill limit (which is a 1.0 fraction). + let clamped = if scaled > accuracy_as_u128 { + Perbill::ACCURACY + } else { + scaled as u32 + }; + + // Construct a Perbill from these parts + let fraction = Perbill::from_parts(clamped); + + // Multiply fraction by subnet_tao to get the staker’s share (u64). + let tao_share = fraction * subnet_tao; + + // Credit the coldkey (or hotkey, depending on your design). + Self::add_balance_to_coldkey_account(&coldkey, tao_share); + + // Remove these alpha shares. + Alpha::::remove((hotkey.clone(), coldkey.clone(), netuid)); + } + } + + // Clear any leftover alpha in/out accumulations. + SubnetAlphaIn::::insert(netuid, 0); + SubnetAlphaOut::::insert(netuid, 0); + + // 4. Calculate partial refund = max(0, lock_cost - owner_received_emission). + let final_refund = lock_cost.saturating_sub(owner_received_emission).max(0); + + // 5. Set the locked balance on this subnet to 0, then credit the final_refund. + Self::set_subnet_locked_balance(netuid, 0); + + if final_refund > 0 { + Self::add_balance_to_coldkey_account(&owner_coldkey, final_refund); + } + + Ok(()) + } + + pub fn get_network_to_prune() -> Option { + let current_block: u64 = Self::get_current_block_as_u64(); + let total_networks: u16 = TotalNetworks::::get(); + + let mut candidate_netuid: Option = None; + let mut candidate_emission = u64::MAX; + let mut candidate_timestamp = u64::MAX; + + for netuid in 1..=total_networks { + let registered_at = NetworkRegisteredAt::::get(netuid); + + let start_block = match FirstEmissionBlockNumber::::get(netuid) { + Some(block) => block, + None => { + // Not enabled yet. If still within ActivationDeadline, skip pruning this subnet. + if current_block + < registered_at.saturating_add(Self::get_network_activation_deadline()) + { + continue; + } + // Otherwise, we treat it as if it started at its registered time + registered_at + } + }; + + // Check if the subnet's immunity period is expired. + let immunity_period = Self::get_network_immunity_period(); + if current_block < start_block.saturating_add(immunity_period as u64) { + continue; + } + + // We want total emission across all UIDs in this subnet: + let emission_vec = Emission::::get(netuid); + let total_emission = emission_vec.iter().sum::(); + + // If tie on total_emission, earliest registration wins + if total_emission < candidate_emission + || (total_emission == candidate_emission && registered_at < candidate_timestamp) + { + candidate_netuid = Some(netuid); + candidate_emission = total_emission; + candidate_timestamp = registered_at; + } + } + + candidate_netuid + } } diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 650fb50451..0a0d9083f5 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1231,7 +1231,7 @@ mod dispatches { netuid: u16, ) -> DispatchResult { ensure_root(origin)?; - Self::user_remove_network(coldkey, netuid) + Self::do_dissolve_network(netuid) } /// Set a single child for a given hotkey on a specified network. diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index c60689d23d..b122bfa049 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -440,57 +440,4 @@ impl Pallet { pub fn is_valid_subnet_for_emission(netuid: u16) -> bool { FirstEmissionBlockNumber::::get(netuid).is_some() } - - /// Select a subnet to prune: - /// - Only consider subnets that are Enabled. - /// - Exclude subnets still within `ImmunityPeriod`. - /// - Pick the one with the lowest total emission - /// - In the case of a tie, pick the earliest registered. - pub fn get_network_to_prune() -> Option { - let current_block: u64 = Self::get_current_block_as_u64(); - let total_networks: u16 = TotalNetworks::::get(); - - let mut candidate_netuid: Option = None; - let mut candidate_emission = u64::MAX; - let mut candidate_timestamp = u64::MAX; - - for netuid in 1..=total_networks { - let registered_at = NetworkRegisteredAt::::get(netuid); - - let start_block = match FirstEmissionBlockNumber::::get(netuid) { - Some(block) => block, - None => { - // Not enabled yet. If still within ActivationDeadline, skip pruning this subnet. - if current_block - < registered_at.saturating_add(Self::get_network_activation_deadline()) - { - continue; - } - // Otherwise, we treat it as if it started at its registered time - registered_at - } - }; - - // Check if the subnet's immunity period is expired. - let immunity_period = Self::get_network_immunity_period(); - if current_block < start_block.saturating_add(immunity_period as u64) { - continue; - } - - // We want total emission across all UIDs in this subnet: - let emission_vec = Emission::::get(netuid); - let total_emission = emission_vec.iter().sum::(); - - // If tie on total_emission, earliest registration wins - if total_emission < candidate_emission - || (total_emission == candidate_emission && registered_at < candidate_timestamp) - { - candidate_netuid = Some(netuid); - candidate_emission = total_emission; - candidate_timestamp = registered_at; - } - } - - candidate_netuid - } } diff --git a/pallets/subtensor/src/tests/networks.rs b/pallets/subtensor/src/tests/networks.rs index 7dda0502c1..0a157c3a5c 100644 --- a/pallets/subtensor/src/tests/networks.rs +++ b/pallets/subtensor/src/tests/networks.rs @@ -32,8 +32,7 @@ fn test_registration_ok() { coldkey_account_id )); - assert_ok!(SubtensorModule::user_remove_network( - coldkey_account_id, + assert_ok!(SubtensorModule::do_dissolve_network( netuid )); From 000c3d0a1b420a52ac1af555d76d203ad83a4933 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 2 Jun 2025 11:08:03 -0700 Subject: [PATCH 6/7] remove NetworkActivationDeadline --- pallets/subtensor/src/coinbase/root.rs | 81 ++++++++++--------------- pallets/subtensor/src/lib.rs | 9 --- pallets/subtensor/src/tests/networks.rs | 4 +- 3 files changed, 33 insertions(+), 61 deletions(-) diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index 218137b8eb..dd8206e281 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -21,10 +21,10 @@ use frame_support::storage::IterableStorageDoubleMap; use frame_support::weights::Weight; use safe_math::*; use sp_core::Get; -use sp_std::vec; +use sp_runtime::PerThing; use sp_runtime::Perbill; +use sp_std::vec; use substrate_fixed::types::{I64F64, U96F32}; -use sp_runtime::PerThing; impl Pallet { /// Fetches the total count of root network validators @@ -434,7 +434,10 @@ impl Pallet { Self::destroy_alpha_in_out_stakes(netuid)?; // --- Finally, remove the network entirely. - ensure!(Self::if_subnet_exist(netuid), Error::::SubNetworkDoesNotExist); + ensure!( + Self::if_subnet_exist(netuid), + Error::::SubNetworkDoesNotExist + ); Self::remove_network(netuid); // --- Emit event. @@ -489,7 +492,7 @@ impl Pallet { Weights::::insert(Self::get_root_netuid(), uid_i, modified_weights); } - // --- 10. Remove various network-related parameters and data. + // --- 10. Remove network-related parameters and data. Rank::::remove(netuid); Trust::::remove(netuid); Active::::remove(netuid); @@ -505,8 +508,6 @@ impl Pallet { for (_uid, key) in keys { IsNetworkMember::::remove(key, netuid); } - - // --- 11. Erase network parameters. Tempo::::remove(netuid); Kappa::::remove(netuid); Difficulty::::remove(netuid); @@ -518,8 +519,6 @@ impl Pallet { RegistrationsThisInterval::::remove(netuid); POWRegistrationsThisInterval::::remove(netuid); BurnRegistrationsThisInterval::::remove(netuid); - - // --- 12. Remove additional dTao-related storages if applicable. SubnetTAO::::remove(netuid); SubnetAlphaInEmission::::remove(netuid); SubnetAlphaOutEmission::::remove(netuid); @@ -527,7 +526,6 @@ impl Pallet { SubnetVolume::::remove(netuid); SubnetMovingPrice::::remove(netuid); - // --- 13. Remove subnet identity if it exists. if SubnetIdentitiesV2::::contains_key(netuid) { SubnetIdentitiesV2::::remove(netuid); Self::deposit_event(Event::SubnetIdentityRemoved(netuid)); @@ -598,9 +596,6 @@ impl Pallet { pub fn get_network_immunity_period() -> u64 { NetworkImmunityPeriod::::get() } - pub fn get_network_activation_deadline() -> u64 { - NetworkActivationDeadline::::get() - } pub fn set_network_immunity_period(net_immunity_period: u64) { NetworkImmunityPeriod::::set(net_immunity_period); Self::deposit_event(Event::NetworkImmunityPeriodSet(net_immunity_period)); @@ -648,26 +643,29 @@ impl Pallet { fn destroy_alpha_in_out_stakes(netuid: u16) -> DispatchResult { // 1. Ensure the subnet exists. - ensure!(Self::if_subnet_exist(netuid), Error::::SubNetworkDoesNotExist); - + ensure!( + Self::if_subnet_exist(netuid), + Error::::SubNetworkDoesNotExist + ); + // 2. Gather relevant info. let owner_coldkey: T::AccountId = SubnetOwner::::get(netuid); let lock_cost: u64 = Self::get_subnet_locked_balance(netuid); - + // (Optional) Grab total emission in Tao. let emission_vec = Emission::::get(netuid); let total_emission: u64 = emission_vec.iter().sum(); - + // The portion the owner received is total_emission * owner_cut (stored as fraction in U96F32). let owner_fraction = Self::get_float_subnet_owner_cut(); let owner_received_emission = (U96F32::from_num(total_emission) * owner_fraction) .floor() .saturating_to_num::(); - + // 3. Destroy α stakes and distribute remaining subnet Tao to α-out stakers (pro rata). let mut total_alpha_out: u128 = 0; let mut stakers_data = Vec::new(); - + // (A) First pass: sum total alpha-out for this netuid. for ((hotkey, coldkey, this_netuid), alpha_shares) in Alpha::::iter() { if this_netuid == netuid { @@ -677,54 +675,54 @@ impl Pallet { stakers_data.push((hotkey, coldkey, alpha_as_u128)); } } - + // (B) Second pass: distribute the subnet’s Tao among those stakers. let subnet_tao = SubnetTAO::::get(netuid); - + if total_alpha_out > 0 { let accuracy_as_u128 = u128::from(Perbill::ACCURACY); - + for (hotkey, coldkey, alpha_amount) in stakers_data { let scaled = alpha_amount .saturating_mul(accuracy_as_u128) .checked_div(total_alpha_out) .unwrap_or(0); - + // Clamp to avoid overflow beyond the Perbill limit (which is a 1.0 fraction). let clamped = if scaled > accuracy_as_u128 { Perbill::ACCURACY } else { scaled as u32 }; - + // Construct a Perbill from these parts let fraction = Perbill::from_parts(clamped); - + // Multiply fraction by subnet_tao to get the staker’s share (u64). let tao_share = fraction * subnet_tao; - + // Credit the coldkey (or hotkey, depending on your design). Self::add_balance_to_coldkey_account(&coldkey, tao_share); - + // Remove these alpha shares. Alpha::::remove((hotkey.clone(), coldkey.clone(), netuid)); } } - + // Clear any leftover alpha in/out accumulations. SubnetAlphaIn::::insert(netuid, 0); SubnetAlphaOut::::insert(netuid, 0); - + // 4. Calculate partial refund = max(0, lock_cost - owner_received_emission). let final_refund = lock_cost.saturating_sub(owner_received_emission).max(0); - + // 5. Set the locked balance on this subnet to 0, then credit the final_refund. Self::set_subnet_locked_balance(netuid, 0); - + if final_refund > 0 { Self::add_balance_to_coldkey_account(&owner_coldkey, final_refund); } - + Ok(()) } @@ -739,23 +737,8 @@ impl Pallet { for netuid in 1..=total_networks { let registered_at = NetworkRegisteredAt::::get(netuid); - let start_block = match FirstEmissionBlockNumber::::get(netuid) { - Some(block) => block, - None => { - // Not enabled yet. If still within ActivationDeadline, skip pruning this subnet. - if current_block - < registered_at.saturating_add(Self::get_network_activation_deadline()) - { - continue; - } - // Otherwise, we treat it as if it started at its registered time - registered_at - } - }; - - // Check if the subnet's immunity period is expired. - let immunity_period = Self::get_network_immunity_period(); - if current_block < start_block.saturating_add(immunity_period as u64) { + // Skip immune networks + if current_block < registered_at.saturating_add(Self::get_network_immunity_period()) { continue; } @@ -774,5 +757,5 @@ impl Pallet { } candidate_netuid - } + } } diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 8e148bee69..197cd5f8f7 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -556,11 +556,6 @@ pub mod pallet { T::InitialNetworkImmunityPeriod::get() } #[pallet::type_value] - /// Default value for network activation deadline. - pub fn DefaultNetworkActivationDeadline() -> u64 { - 1_296_000 - } - #[pallet::type_value] /// Default value for network last registered. pub fn DefaultNetworkLastRegistered() -> u64 { 0 @@ -1199,10 +1194,6 @@ pub mod pallet { pub type NetworkImmunityPeriod = StorageValue<_, u64, ValueQuery, DefaultNetworkImmunityPeriod>; #[pallet::storage] - /// ITEM( network_activation_deadline ) - pub type NetworkActivationDeadline = - StorageValue<_, u64, ValueQuery, DefaultNetworkActivationDeadline>; - #[pallet::storage] /// ITEM( network_last_registered_block ) pub type NetworkLastRegistered = StorageValue<_, u64, ValueQuery, DefaultNetworkLastRegistered>; diff --git a/pallets/subtensor/src/tests/networks.rs b/pallets/subtensor/src/tests/networks.rs index 0a157c3a5c..c9bb787437 100644 --- a/pallets/subtensor/src/tests/networks.rs +++ b/pallets/subtensor/src/tests/networks.rs @@ -32,9 +32,7 @@ fn test_registration_ok() { coldkey_account_id )); - assert_ok!(SubtensorModule::do_dissolve_network( - netuid - )); + assert_ok!(SubtensorModule::do_dissolve_network(netuid)); assert!(!SubtensorModule::if_subnet_exist(netuid)) }) From dfe72d5cbfaee7d6684197865434c45f5503b527 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 2 Jun 2025 11:18:37 -0700 Subject: [PATCH 7/7] update InitialNetworkImmunityPeriod --- pallets/admin-utils/src/tests/mock.rs | 2 +- pallets/subtensor/src/tests/mock.rs | 2 +- runtime/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pallets/admin-utils/src/tests/mock.rs b/pallets/admin-utils/src/tests/mock.rs index f8b3e6a9b6..b625145410 100644 --- a/pallets/admin-utils/src/tests/mock.rs +++ b/pallets/admin-utils/src/tests/mock.rs @@ -120,7 +120,7 @@ parameter_types! { pub const InitialMaxDifficulty: u64 = u64::MAX; pub const InitialRAORecycledForRegistration: u64 = 0; pub const InitialSenateRequiredStakePercentage: u64 = 2; // 2 percent of total stake - pub const InitialNetworkImmunityPeriod: u64 = 7200 * 7; + pub const InitialNetworkImmunityPeriod: u64 = 1_296_000; pub const InitialNetworkMinAllowedUids: u16 = 128; pub const InitialNetworkMinLockCost: u64 = 100_000_000_000; pub const InitialSubnetOwnerCut: u16 = 0; // 0%. 100% of rewards go to validators + miners. diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 221d802ccd..dbabfb926f 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -172,7 +172,7 @@ parameter_types! { pub const InitialMaxDifficulty: u64 = u64::MAX; pub const InitialRAORecycledForRegistration: u64 = 0; pub const InitialSenateRequiredStakePercentage: u64 = 2; // 2 percent of total stake - pub const InitialNetworkImmunityPeriod: u64 = 7200 * 7; + pub const InitialNetworkImmunityPeriod: u64 = 1_296_000; pub const InitialNetworkMinAllowedUids: u16 = 128; pub const InitialNetworkMinLockCost: u64 = 100_000_000_000; pub const InitialSubnetOwnerCut: u16 = 0; // 0%. 100% of rewards go to validators + miners. diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 95b032f9e6..f4af9956be 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1073,7 +1073,7 @@ parameter_types! { pub const SubtensorInitialTxChildKeyTakeRateLimit: u64 = INITIAL_CHILDKEY_TAKE_RATELIMIT; pub const SubtensorInitialRAORecycledForRegistration: u64 = 0; // 0 rao pub const SubtensorInitialSenateRequiredStakePercentage: u64 = 1; // 1 percent of total stake - pub const SubtensorInitialNetworkImmunity: u64 = 7 * 7200; + pub const SubtensorInitialNetworkImmunity: u64 = 1_296_000; pub const SubtensorInitialMinAllowedUids: u16 = 128; pub const SubtensorInitialMinLockCost: u64 = 1_000_000_000_000; // 1000 TAO pub const SubtensorInitialSubnetOwnerCut: u16 = 11_796; // 18 percent