From 8c3ec679d4d26bc3cd80d141aa3a7433ebd9b636 Mon Sep 17 00:00:00 2001 From: open-junius Date: Tue, 10 Feb 2026 13:57:51 +0800 Subject: [PATCH 01/40] try dissolve_network benchmark --- pallets/subtensor/src/benchmarks.rs | 47 +++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 8a6f8d757d..d1dc40dc72 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -1764,4 +1764,51 @@ mod pallet_benchmarks { Some(limit), ); } + + #[benchmark] + fn dissolve_network() { + let netuid = NetUid::from(1); + let tempo: u16 = 1; + let coldkey: T::AccountId = account("Owner", 0, 1); + + // Initialize network + Subtensor::::init_new_network(netuid, tempo); + SubtokenEnabled::::insert(netuid, true); + Subtensor::::set_max_allowed_uids(netuid, 256); + Subtensor::::set_network_registration_allowed(netuid, true); + Subtensor::::set_burn(netuid, 1.into()); + + // Set network owner + SubnetOwner::::insert(netuid, coldkey.clone()); + + Subtensor::::set_max_registrations_per_block(netuid, 64); + + Subtensor::::set_target_registrations_per_interval(netuid, 64); + + // Add some registrations to make the benchmark realistic + let mut seed: u32 = 2; + for _ in 0..64 { + let hotkey: T::AccountId = account("Hotkey", 0, seed); + let coldkey: T::AccountId = account("Coldkey", 0, seed); + seed += 1; + + let amount_to_be_staked: u64 = 1_000_000; + Subtensor::::add_balance_to_coldkey_account(&coldkey, amount_to_be_staked); + + assert_ok!(Subtensor::::do_burned_registration( + RawOrigin::Signed(coldkey.clone()).into(), + netuid, + hotkey.clone() + )); + } + + // Add some network reserves to make it more realistic + let tao_reserve = TaoCurrency::from(10_000_000_000); + let alpha_in = AlphaCurrency::from(5_000_000_000); + SubnetTAO::::insert(netuid, tao_reserve); + SubnetAlphaIn::::insert(netuid, alpha_in); + + #[extrinsic_call] + _(RawOrigin::Root, coldkey.clone(), netuid); + } } From 9030e64d4701c32b8d678f2bd15906535c2e26ba Mon Sep 17 00:00:00 2001 From: open-junius Date: Tue, 10 Feb 2026 13:58:39 +0800 Subject: [PATCH 02/40] remove collect --- pallets/subtensor/src/staking/claim_root.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pallets/subtensor/src/staking/claim_root.rs b/pallets/subtensor/src/staking/claim_root.rs index 24a26d154c..b9fcc43332 100644 --- a/pallets/subtensor/src/staking/claim_root.rs +++ b/pallets/subtensor/src/staking/claim_root.rs @@ -390,10 +390,9 @@ impl Pallet { /// Claim all root dividends for subnet and remove all associated data. pub fn finalize_all_subnet_root_dividends(netuid: NetUid) { - let hotkeys = RootClaimable::::iter_keys().collect::>(); - - for hotkey in hotkeys.iter() { - RootClaimable::::mutate(hotkey, |claimable| { + // Iterate directly without collecting to avoid unnecessary allocation + for hotkey in RootClaimable::::iter_keys() { + RootClaimable::::mutate(&hotkey, |claimable| { claimable.remove(&netuid); }); } From f6293d7cc1b448774c6a3d9ec5dfadd8e4d3cea5 Mon Sep 17 00:00:00 2001 From: open-junius Date: Wed, 11 Feb 2026 09:20:57 +0800 Subject: [PATCH 03/40] add on idle --- pallets/subtensor/src/lib.rs | 1 + pallets/subtensor/src/macros/hooks.rs | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index ba7e3dcbf6..029be02c33 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -87,6 +87,7 @@ pub mod pallet { traits::{ OriginTrait, QueryPreimage, StorePreimage, UnfilteredDispatchable, tokens::fungible, }, + weights::WeightMeter, }; use frame_system::pallet_prelude::*; use pallet_drand::types::RoundNumber; diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index 899e8d32f2..facd351cc9 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -177,6 +177,17 @@ mod hooks { // Self::check_total_stake()?; Ok(()) } + + fn on_idle(_block: BlockNumberFor, limit: Weight) -> Weight { + let mut weight_meter = WeightMeter::with_limit(limit.saturating_div(2)); + let on_idle_weight = T::DbWeight::get().reads(1); + // let on_idle_weight = T::WeightInfo::on_idle_base(); + if !weight_meter.can_consume(on_idle_weight) { + return weight_meter.consumed(); + } + weight_meter.consume(on_idle_weight); + weight_meter.consumed() + } } impl Pallet { From fb3dc040a980adaf5eb21f4ef2608ba8c8792e0f Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 12 Feb 2026 22:43:23 +0800 Subject: [PATCH 04/40] add weight meter --- pallets/subtensor/src/coinbase/root.rs | 19 ++++++------ pallets/subtensor/src/lib.rs | 4 +++ pallets/subtensor/src/macros/errors.rs | 2 ++ pallets/subtensor/src/macros/events.rs | 5 +++ pallets/subtensor/src/macros/hooks.rs | 42 +++++++++++++++++++++++++- 5 files changed, 61 insertions(+), 11 deletions(-) diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index 83567b6f57..ab09c99192 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -16,11 +16,9 @@ // DEALINGS IN THE SOFTWARE. use super::*; -use crate::CommitmentsInterface; use safe_math::*; use substrate_fixed::types::{I64F64, U96F32}; use subtensor_runtime_common::{AlphaCurrency, Currency, NetUid, NetUidStorageIndex, TaoCurrency}; -use subtensor_swap_interface::SwapHandler; impl Pallet { /// Fetches the total count of root network validators @@ -210,16 +208,17 @@ impl Pallet { Error::::SubnetNotExists ); - Self::finalize_all_subnet_root_dividends(netuid); + // Just remove the network from the added networks. + NetworksAdded::::remove(netuid); - // --- Perform the cleanup before removing the network. - T::SwapInterface::dissolve_all_liquidity_providers(netuid)?; - Self::destroy_alpha_in_out_stakes(netuid)?; - T::SwapInterface::clear_protocol_liquidity(netuid)?; - T::CommitmentsInterface::purge_netuid(netuid); + let mut dissolved_networks = DissolvedNetworks::::get(); + ensure!( + !dissolved_networks.contains(&netuid), + Error::::NetworkAlreadyDissolved + ); - // --- Remove the network - Self::remove_network(netuid); + dissolved_networks.push(netuid); + DissolvedNetworks::::set(dissolved_networks); // --- Emit the NetworkRemoved event log::info!("NetworkRemoved( netuid:{netuid:?} )"); diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 029be02c33..e186fa161d 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1890,6 +1890,10 @@ pub mod pallet { pub type SubtokenEnabled = StorageMap<_, Identity, NetUid, bool, ValueQuery, DefaultFalse>; + /// --- ITEM ( dissolved_networks ) Networks dissolved but some storage not removed yet + #[pallet::storage] + pub type DissolvedNetworks = StorageValue<_, Vec, ValueQuery>; + // ======================================= // ==== VotingPower Storage ==== // ======================================= diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index f74a7657d8..8dad82d55a 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -282,5 +282,7 @@ mod errors { Deprecated, /// Subnet buyback exceeded the operation rate limit SubnetBuybackRateLimitExceeded, + /// Network already dissolved + NetworkAlreadyDissolved, } } diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index 9f0c2bdfd5..f934f40923 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -528,5 +528,10 @@ mod events { /// Alpha burned alpha: AlphaCurrency, }, + /// data for a dissolved network has been cleaned up. + DissolvedNetworkDataCleaned { + /// The subnet ID + netuid: NetUid, + }, } } diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index facd351cc9..2435b802fa 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -1,5 +1,6 @@ use frame_support::pallet_macros::pallet_section; - +// use subtensor_commitments_interface::CommitmentsHandler; +// use subtensor_swap_interface::SwapHandler; /// A [`pallet_section`] that defines the events for a pallet. /// This can later be imported into the pallet using [`import_section`]. #[pallet_section] @@ -186,6 +187,9 @@ mod hooks { return weight_meter.consumed(); } weight_meter.consume(on_idle_weight); + weight_meter.consumed(); + + let _ = Self::remove_data_for_dissolved_networks(weight_meter.remaining()); weight_meter.consumed() } } @@ -227,5 +231,41 @@ mod hooks { } weight } + + // Clean the data for dissolved networks + // + // # Args: + // * 'remaining_weight': (Weight): + // - The remaining weight for the function. + // + // # Returns: + // * 'Weight': The weight consumed by the function. + // + fn remove_data_for_dissolved_networks(remaining_weight: Weight) -> Weight { + let dissolved_networks = DissolvedNetworks::::get(); + + for netuid in dissolved_networks.iter() { + Self::finalize_all_subnet_root_dividends(*netuid); + let _ = T::SwapInterface::dissolve_all_liquidity_providers(*netuid); + let _ = Self::destroy_alpha_in_out_stakes(*netuid); + let _ = T::SwapInterface::clear_protocol_liquidity(*netuid); + let _ = T::CommitmentsInterface::purge_netuid(*netuid); + let _ = Self::remove_network(*netuid); + + Self::deposit_event(Event::DissolvedNetworkDataCleaned { netuid: *netuid }); + } + let mut _weight_meter = WeightMeter::with_limit(remaining_weight); + Weight::from_parts(0, 0) + // Self::finalize_all_subnet_root_dividends(netuid); + + // --- Perform the cleanup before removing the network. + // T::SwapInterface::dissolve_all_liquidity_providers(netuid)?; + // Self::destroy_alpha_in_out_stakes(netuid)?; + // T::SwapInterface::clear_protocol_liquidity(netuid)?; + // T::CommitmentsInterface::purge_netuid(netuid); + + // --- Remove the network + // Self::remove_network(netuid); + } } } From e7d60f112a2b9d898541bf35957d4b201a4417bc Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 13 Feb 2026 09:26:03 +0800 Subject: [PATCH 05/40] on_idle hook --- pallets/subtensor/src/lib.rs | 2 +- pallets/subtensor/src/macros/hooks.rs | 2 +- pallets/subtensor/src/staking/claim_root.rs | 17 +++++++++++++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index e186fa161d..cf03ff0f98 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -87,7 +87,7 @@ pub mod pallet { traits::{ OriginTrait, QueryPreimage, StorePreimage, UnfilteredDispatchable, tokens::fungible, }, - weights::WeightMeter, + weights::{Weight, WeightMeter}, }; use frame_system::pallet_prelude::*; use pallet_drand::types::RoundNumber; diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index 2435b802fa..9b198ad478 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -243,6 +243,7 @@ mod hooks { // fn remove_data_for_dissolved_networks(remaining_weight: Weight) -> Weight { let dissolved_networks = DissolvedNetworks::::get(); + let mut _weight_meter = WeightMeter::with_limit(remaining_weight); for netuid in dissolved_networks.iter() { Self::finalize_all_subnet_root_dividends(*netuid); @@ -254,7 +255,6 @@ mod hooks { Self::deposit_event(Event::DissolvedNetworkDataCleaned { netuid: *netuid }); } - let mut _weight_meter = WeightMeter::with_limit(remaining_weight); Weight::from_parts(0, 0) // Self::finalize_all_subnet_root_dividends(netuid); diff --git a/pallets/subtensor/src/staking/claim_root.rs b/pallets/subtensor/src/staking/claim_root.rs index b9fcc43332..9df60610f7 100644 --- a/pallets/subtensor/src/staking/claim_root.rs +++ b/pallets/subtensor/src/staking/claim_root.rs @@ -1,5 +1,5 @@ use super::*; -use frame_support::weights::Weight; +use frame_support::weights::{Weight, WeightMeter}; use sp_core::Get; use sp_std::collections::btree_set::BTreeSet; use substrate_fixed::types::I96F32; @@ -389,14 +389,27 @@ impl Pallet { } /// Claim all root dividends for subnet and remove all associated data. - pub fn finalize_all_subnet_root_dividends(netuid: NetUid) { + pub fn finalize_all_subnet_root_dividends(netuid: NetUid, remaining_weight: Weight) -> Weight { + let mut weight_meter = WeightMeter::with_limit(remaining_weight); + + if !weight_meter.can_consume(T::DbWeight::get().reads(1)) { + return weight_meter.consumed(); + } // Iterate directly without collecting to avoid unnecessary allocation for hotkey in RootClaimable::::iter_keys() { + weight_meter.consume(T::DbWeight::get().reads(1)); + + if !weight_meter.can_consume(T::DbWeight::get().writes(1)) { + return weight_meter.consumed(); + } + RootClaimable::::mutate(&hotkey, |claimable| { claimable.remove(&netuid); }); + weight_meter.consume(T::DbWeight::get().writes(1)); } let _ = RootClaimed::::clear_prefix((netuid,), u32::MAX, None); + Weight::from_parts(0, 0) } } From 860d84d39dd8be442a63fac0a94ac36cbb2922c1 Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 13 Feb 2026 11:34:41 +0800 Subject: [PATCH 06/40] add macro --- pallets/subtensor/src/macros/hooks.rs | 2 +- pallets/subtensor/src/staking/claim_root.rs | 13 ++- pallets/subtensor/src/utils/mod.rs | 101 ++++++++++++++++++++ 3 files changed, 112 insertions(+), 4 deletions(-) diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index 9b198ad478..75f7a28043 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -246,7 +246,7 @@ mod hooks { let mut _weight_meter = WeightMeter::with_limit(remaining_weight); for netuid in dissolved_networks.iter() { - Self::finalize_all_subnet_root_dividends(*netuid); + Self::finalize_all_subnet_root_dividends(*netuid, remaining_weight); let _ = T::SwapInterface::dissolve_all_liquidity_providers(*netuid); let _ = Self::destroy_alpha_in_out_stakes(*netuid); let _ = T::SwapInterface::clear_protocol_liquidity(*netuid); diff --git a/pallets/subtensor/src/staking/claim_root.rs b/pallets/subtensor/src/staking/claim_root.rs index 9df60610f7..f5f7804810 100644 --- a/pallets/subtensor/src/staking/claim_root.rs +++ b/pallets/subtensor/src/staking/claim_root.rs @@ -1,4 +1,5 @@ use super::*; +use crate::WeightMeterWrapper; use frame_support::weights::{Weight, WeightMeter}; use sp_core::Get; use sp_std::collections::btree_set::BTreeSet; @@ -395,6 +396,8 @@ impl Pallet { if !weight_meter.can_consume(T::DbWeight::get().reads(1)) { return weight_meter.consumed(); } + // MeterX!(weight_meter, T::DbWeight::get().reads(1)); + // Iterate directly without collecting to avoid unnecessary allocation for hotkey in RootClaimable::::iter_keys() { weight_meter.consume(T::DbWeight::get().reads(1)); @@ -403,9 +406,13 @@ impl Pallet { return weight_meter.consumed(); } - RootClaimable::::mutate(&hotkey, |claimable| { - claimable.remove(&netuid); - }); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().reads(1), + RootClaimable::::mutate(&hotkey, |claimable| { + claimable.remove(&netuid); + }) + ); weight_meter.consume(T::DbWeight::get().writes(1)); } diff --git a/pallets/subtensor/src/utils/mod.rs b/pallets/subtensor/src/utils/mod.rs index a91875da59..e3949c0821 100644 --- a/pallets/subtensor/src/utils/mod.rs +++ b/pallets/subtensor/src/utils/mod.rs @@ -6,3 +6,104 @@ pub mod rate_limiting; #[cfg(feature = "try-runtime")] pub mod try_state; pub mod voting_power; + +#[macro_export] +macro_rules! WeightMeterWrapper { + ( $meter:expr, $weight:expr, $body:expr ) => {{ + if !$meter.can_consume($weight) { + return $meter.consumed(); + } + $body; + $meter.consume($weight); + }}; +} + +#[cfg(test)] +mod tests { + use core::cell::Cell; + + /// Mock weight meter for testing the macro. + struct MockWeightMeter { + limit: u64, + used: u64, + } + + impl MockWeightMeter { + fn with_limit(limit: u64) -> Self { + Self { limit, used: 0 } + } + fn can_consume(&self, weight: u64) -> bool { + self.used.saturating_add(weight) <= self.limit + } + fn consume(&mut self, weight: u64) { + self.used = self.used.saturating_add(weight); + } + fn consumed(&self) -> u64 { + self.used + } + } + + /// Helper: the macro's early return yields u64, so it must be in a fn returning u64. + fn run_with_meter(mut meter: MockWeightMeter) -> u64 { + WeightMeterWrapper!(meter, 10u64, { + // body executes when we can consume + }); + WeightMeterWrapper!(meter, 20u64, { + // body executes + }); + meter.consumed() + } + + #[test] + fn test_weight_meter_wrapper_consumes_weight() { + let meter = MockWeightMeter::with_limit(100); + let consumed = run_with_meter(meter); + assert_eq!(consumed, 30, "should consume 10 + 20 = 30"); + } + + #[test] + fn test_weight_meter_wrapper_returns_early_when_over_limit() { + let meter = MockWeightMeter::with_limit(15); + let consumed = run_with_meter(meter); + // First block consumes 10, second would need 20 but only 5 remain -> early return + assert_eq!( + consumed, 10, + "should return after first consume when second would exceed limit" + ); + } + + #[test] + fn test_weight_meter_wrapper_body_executes() { + fn helper() -> u64 { + let executed = Cell::new(false); + let mut meter = MockWeightMeter::with_limit(100); + WeightMeterWrapper!(meter, 10u64, { + executed.set(true); + }); + assert!( + executed.get(), + "body should execute when weight is available" + ); + meter.consumed() + } + assert_eq!(helper(), 10); + } + + #[test] + fn test_weight_meter_wrapper_body_does_not_execute_when_over_limit() { + let executed = Cell::new(false); + let mut meter = MockWeightMeter::with_limit(5); + fn run(executed: &Cell, meter: &mut MockWeightMeter) -> u64 { + WeightMeterWrapper!(meter, 10u64, { + executed.set(true); + }); + meter.consumed() + } + let consumed = run(&executed, &mut meter); + assert!( + !executed.get(), + "body should not execute when weight exceeds limit" + ); + assert_eq!(consumed, 0); + } +} From 5161299bd9bed8785341c038f593f0d545a180ee Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 13 Feb 2026 16:25:13 +0800 Subject: [PATCH 07/40] need handle remove all lp --- pallets/subtensor/src/macros/hooks.rs | 22 +++++++++++++++------ pallets/subtensor/src/staking/claim_root.rs | 22 ++++++++------------- pallets/subtensor/src/utils/mod.rs | 2 +- pallets/swap/src/pallet/impls.rs | 2 +- 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index 75f7a28043..d0321744ea 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -242,16 +242,26 @@ mod hooks { // * 'Weight': The weight consumed by the function. // fn remove_data_for_dissolved_networks(remaining_weight: Weight) -> Weight { + let mut remaining_weight = remaining_weight; let dissolved_networks = DissolvedNetworks::::get(); let mut _weight_meter = WeightMeter::with_limit(remaining_weight); for netuid in dissolved_networks.iter() { - Self::finalize_all_subnet_root_dividends(*netuid, remaining_weight); - let _ = T::SwapInterface::dissolve_all_liquidity_providers(*netuid); - let _ = Self::destroy_alpha_in_out_stakes(*netuid); - let _ = T::SwapInterface::clear_protocol_liquidity(*netuid); - let _ = T::CommitmentsInterface::purge_netuid(*netuid); - let _ = Self::remove_network(*netuid); + let weight_used = + Self::finalize_all_subnet_root_dividends(*netuid, remaining_weight); + remaining_weight = remaining_weight.saturating_sub(weight_used); + // let weight_used = T::SwapInterface::dissolve_all_liquidity_providers(*netuid); + // remaining_weight = remaining_weight.saturating_sub(weight_used); + // let weight_used = Self::destroy_alpha_in_out_stakes(*netuid); + // remaining_weight = remaining_weight.saturating_sub(weight_used); + // let weight_used = T::SwapInterface::clear_protocol_liquidity(*netuid); + // remaining_weight = remaining_weight.saturating_sub(weight_used); + // let weight_used_ = T::CommitmentsInterface::purge_netuid(*netuid); + // remaining_weight = remaining_weight.saturating_sub(weight_used); + // let weight_used = Self::remove_network(*netuid); + // remaining_weight = remaining_weight.saturating_sub(weight_used); + + DissolvedNetworks::::mutate(|networks| networks.retain(|n| *n != *netuid)); Self::deposit_event(Event::DissolvedNetworkDataCleaned { netuid: *netuid }); } diff --git a/pallets/subtensor/src/staking/claim_root.rs b/pallets/subtensor/src/staking/claim_root.rs index f5f7804810..0619a38c04 100644 --- a/pallets/subtensor/src/staking/claim_root.rs +++ b/pallets/subtensor/src/staking/claim_root.rs @@ -393,30 +393,24 @@ impl Pallet { pub fn finalize_all_subnet_root_dividends(netuid: NetUid, remaining_weight: Weight) -> Weight { let mut weight_meter = WeightMeter::with_limit(remaining_weight); - if !weight_meter.can_consume(T::DbWeight::get().reads(1)) { - return weight_meter.consumed(); - } - // MeterX!(weight_meter, T::DbWeight::get().reads(1)); - // Iterate directly without collecting to avoid unnecessary allocation for hotkey in RootClaimable::::iter_keys() { - weight_meter.consume(T::DbWeight::get().reads(1)); - - if !weight_meter.can_consume(T::DbWeight::get().writes(1)) { - return weight_meter.consumed(); - } + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1), {}); WeightMeterWrapper!( weight_meter, - T::DbWeight::get().reads(1), + T::DbWeight::get().writes(1), RootClaimable::::mutate(&hotkey, |claimable| { claimable.remove(&netuid); }) ); - weight_meter.consume(T::DbWeight::get().writes(1)); } - let _ = RootClaimed::::clear_prefix((netuid,), u32::MAX, None); - Weight::from_parts(0, 0) + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().writes(1), + RootClaimed::::clear_prefix((netuid,), u32::MAX, None) + ); + weight_meter.consumed() } } diff --git a/pallets/subtensor/src/utils/mod.rs b/pallets/subtensor/src/utils/mod.rs index e3949c0821..072a29c453 100644 --- a/pallets/subtensor/src/utils/mod.rs +++ b/pallets/subtensor/src/utils/mod.rs @@ -13,7 +13,7 @@ macro_rules! WeightMeterWrapper { if !$meter.can_consume($weight) { return $meter.consumed(); } - $body; + let _ = $body; $meter.consume($weight); }}; } diff --git a/pallets/swap/src/pallet/impls.rs b/pallets/swap/src/pallet/impls.rs index 6ec02879bf..f99f3330b9 100644 --- a/pallets/swap/src/pallet/impls.rs +++ b/pallets/swap/src/pallet/impls.rs @@ -871,7 +871,7 @@ impl Pallet { }; for CloseItem { owner, pos_id } in to_close.into_iter() { - match Self::do_remove_liquidity(netuid, &owner, pos_id) { + match Self::do_remove_liquixdity(netuid, &owner, pos_id) { Ok(rm) => { // α withdrawn from the pool = principal + accrued fees let alpha_total_from_pool: AlphaCurrency = From 890f68531f557fe49477bf89793bd2f179052eea Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 13 Feb 2026 16:28:16 +0800 Subject: [PATCH 08/40] fix typo --- pallets/swap/src/pallet/impls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/swap/src/pallet/impls.rs b/pallets/swap/src/pallet/impls.rs index f99f3330b9..6ec02879bf 100644 --- a/pallets/swap/src/pallet/impls.rs +++ b/pallets/swap/src/pallet/impls.rs @@ -871,7 +871,7 @@ impl Pallet { }; for CloseItem { owner, pos_id } in to_close.into_iter() { - match Self::do_remove_liquixdity(netuid, &owner, pos_id) { + match Self::do_remove_liquidity(netuid, &owner, pos_id) { Ok(rm) => { // α withdrawn from the pool = principal + accrued fees let alpha_total_from_pool: AlphaCurrency = From 07da3b5273c73804ce6dad093bacfac52f283db7 Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 13 Feb 2026 17:06:00 +0800 Subject: [PATCH 09/40] update interface --- pallets/swap-interface/src/lib.rs | 3 +- pallets/swap/src/pallet/impls.rs | 74 ++++++++++++++++++++++++------- pallets/swap/src/pallet/mod.rs | 2 +- 3 files changed, 60 insertions(+), 19 deletions(-) diff --git a/pallets/swap-interface/src/lib.rs b/pallets/swap-interface/src/lib.rs index 19af1303c1..3e00dd15bb 100644 --- a/pallets/swap-interface/src/lib.rs +++ b/pallets/swap-interface/src/lib.rs @@ -48,7 +48,8 @@ pub trait SwapHandler { alpha_delta: AlphaCurrency, ); fn is_user_liquidity_enabled(netuid: NetUid) -> bool; - fn dissolve_all_liquidity_providers(netuid: NetUid) -> DispatchResult; + fn dissolve_all_liquidity_providers(netuid: NetUid, remaining_weight: Option) + -> Weight; fn toggle_user_liquidity(netuid: NetUid, enabled: bool); fn clear_protocol_liquidity(netuid: NetUid) -> DispatchResult; } diff --git a/pallets/swap/src/pallet/impls.rs b/pallets/swap/src/pallet/impls.rs index 6ec02879bf..fd2181566a 100644 --- a/pallets/swap/src/pallet/impls.rs +++ b/pallets/swap/src/pallet/impls.rs @@ -1,6 +1,6 @@ use core::ops::Neg; - use frame_support::storage::{TransactionOutcome, transactional}; +use frame_support::weights::{Weight, WeightMeter}; use frame_support::{ensure, pallet_prelude::DispatchError, traits::Get}; use safe_math::*; use sp_arithmetic::helpers_128bit; @@ -828,7 +828,18 @@ impl Pallet { } /// Dissolve all LPs and clean state. - pub fn do_dissolve_all_liquidity_providers(netuid: NetUid) -> DispatchResult { + pub fn do_dissolve_all_liquidity_providers( + netuid: NetUid, + remaining_weight: Option, + ) -> Weight { + let mut meter_weight = remaining_weight.map(|value| WeightMeter::with_limit(value)); + if let Some(meter_weight) = &mut meter_weight { + if meter_weight.can_consume(T::DbWeight::get().reads(1)) { + return meter_weight.consumed(); + } else { + meter_weight.consume(T::DbWeight::get().reads(1)); + } + } if SwapV3Initialized::::get(netuid) { // 1) Snapshot only *non‑protocol* positions: (owner, position_id). struct CloseItem { @@ -848,7 +859,11 @@ impl Pallet { log::debug!( "dissolve_all_lp: no user positions; netuid={netuid:?}, protocol liquidity untouched" ); - return Ok(()); + if let Some(meter_weight) = meter_weight { + return meter_weight.consumed(); + } else { + return Weight::from_parts(0, 0); + } } let mut user_refunded_tao = TaoCurrency::ZERO; @@ -891,20 +906,34 @@ impl Pallet { // 2) Stake ALL withdrawn α (principal + fees) to the best permitted validator. if alpha_total_from_pool > AlphaCurrency::ZERO { if let Some(target_uid) = pick_target_uid(&trust, &permit) { - let validator_hotkey: T::AccountId = + let validator_hotkey: Result = T::SubnetInfo::hotkey_of_uid(netuid.into(), target_uid).ok_or( sp_runtime::DispatchError::Other( "validator_hotkey_missing", ), - )?; - - // Stake α from LP owner (coldkey) to chosen validator (hotkey). - T::BalanceOps::increase_stake( - &owner, - &validator_hotkey, - netuid, - alpha_total_from_pool, - )?; + ); + + if let Ok(validator_hotkey) = validator_hotkey { + // Stake α from LP owner (coldkey) to chosen validator (hotkey). + if let Err(_e) = T::BalanceOps::increase_stake( + &owner, + &validator_hotkey, + netuid, + alpha_total_from_pool, + ) { + if let Some(meter_weight) = meter_weight { + return meter_weight.consumed(); + } else { + return Weight::from_parts(0, 0); + } + } + } else { + if let Some(meter_weight) = meter_weight { + return meter_weight.consumed(); + } else { + return Weight::from_parts(0, 0); + } + } user_staked_alpha = user_staked_alpha.saturating_add(alpha_total_from_pool); @@ -935,14 +964,22 @@ impl Pallet { "dissolve_all_liquidity_providers (users-only): netuid={netuid:?}, users_refunded_total_τ={user_refunded_tao:?}, users_staked_total_α={user_staked_alpha:?}; protocol liquidity untouched" ); - return Ok(()); + if let Some(meter_weight) = meter_weight { + return meter_weight.consumed(); + } else { + return Weight::from_parts(0, 0); + } } log::debug!( "dissolve_all_liquidity_providers: netuid={netuid:?}, mode=V2-or-nonV3, leaving all liquidity/state intact" ); - Ok(()) + if let Some(meter_weight) = meter_weight { + return meter_weight.consumed(); + } else { + return Weight::from_parts(0, 0); + } } /// Clear **protocol-owned** liquidity and wipe all swap state for `netuid`. @@ -1151,8 +1188,11 @@ impl SwapHandler for Pallet { fn is_user_liquidity_enabled(netuid: NetUid) -> bool { EnabledUserLiquidity::::get(netuid) } - fn dissolve_all_liquidity_providers(netuid: NetUid) -> DispatchResult { - Self::do_dissolve_all_liquidity_providers(netuid) + fn dissolve_all_liquidity_providers( + netuid: NetUid, + remaining_weight: Option, + ) -> Weight { + Self::do_dissolve_all_liquidity_providers(netuid, remaining_weight) } fn toggle_user_liquidity(netuid: NetUid, enabled: bool) { EnabledUserLiquidity::::insert(netuid, enabled) diff --git a/pallets/swap/src/pallet/mod.rs b/pallets/swap/src/pallet/mod.rs index b55df77fee..dc40512bd4 100644 --- a/pallets/swap/src/pallet/mod.rs +++ b/pallets/swap/src/pallet/mod.rs @@ -621,7 +621,7 @@ mod pallet { // Remove provided liquidity unconditionally because the network may have // user liquidity previously disabled // Ignore result to avoid early stopping - let _ = Self::do_dissolve_all_liquidity_providers(netuid); + let _ = Self::do_dissolve_all_liquidity_providers(netuid, None); } Ok(()) From 4b9a6a04af39e0a6b03a72dc1d60b09f34540fdd Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 13 Feb 2026 20:17:45 +0800 Subject: [PATCH 10/40] cargo clippy --- pallets/swap/src/pallet/impls.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/pallets/swap/src/pallet/impls.rs b/pallets/swap/src/pallet/impls.rs index 48dd887e12..9656a81f50 100644 --- a/pallets/swap/src/pallet/impls.rs +++ b/pallets/swap/src/pallet/impls.rs @@ -1,6 +1,4 @@ -use core::ops::Neg; use frame_support::storage::{TransactionOutcome, transactional}; -use frame_support::weights::{Weight, WeightMeter}; use frame_support::{ensure, pallet_prelude::DispatchError, traits::Get}; use safe_math::*; use sp_arithmetic::{ From e9a67b8ab414aca634a458fe1c134703d8f6a1fe Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 16 Feb 2026 15:45:21 +0800 Subject: [PATCH 11/40] add weigth for all db ops --- common/src/lib.rs | 26 ++ pallets/commitments/src/lib.rs | 29 +- pallets/commitments/src/tests.rs | 2 +- pallets/subtensor/src/coinbase/root.rs | 277 +++++++++++++++--- pallets/subtensor/src/lib.rs | 3 +- pallets/subtensor/src/macros/hooks.rs | 50 ++-- pallets/subtensor/src/staking/claim_root.rs | 27 +- pallets/subtensor/src/staking/remove_stake.rs | 39 ++- pallets/subtensor/src/tests/networks.rs | 1 + pallets/subtensor/src/utils/mod.rs | 42 +-- pallets/swap-interface/src/lib.rs | 2 +- pallets/swap/src/pallet/impls.rs | 40 ++- runtime/src/lib.rs | 4 +- 13 files changed, 401 insertions(+), 141 deletions(-) diff --git a/common/src/lib.rs b/common/src/lib.rs index 658f8b2e01..ec81a874ca 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -437,6 +437,32 @@ impl TypeInfo for NetUidStorageIndex { } } +#[macro_export] +macro_rules! WeightMeterWrapper { + ( $meter:expr, $weight:expr ) => {{ + if !$meter.can_consume($weight) { + return $meter.consumed(); + } + $meter.consume($weight); + }}; +} + +#[macro_export] +macro_rules! LoopRemovePrefixWithWeightMeter { + ( $meter:expr, $weight:expr, $body:expr ) => {{ + loop { + if !$meter.can_consume($weight * 1024) { + return $meter.consumed(); + } + let result = $body; + $meter.consume($weight * result.backend as u64); + if result.maybe_cursor.is_none() { + break; + } + } + }}; +} + #[cfg(test)] mod tests { use super::*; diff --git a/pallets/commitments/src/lib.rs b/pallets/commitments/src/lib.rs index a627220f76..73cdd846ca 100644 --- a/pallets/commitments/src/lib.rs +++ b/pallets/commitments/src/lib.rs @@ -13,6 +13,7 @@ pub mod weights; use ark_serialize::CanonicalDeserialize; use codec::Encode; use frame_support::IterableStorageDoubleMap; +use frame_support::weights::WeightMeter; use frame_support::{ BoundedVec, traits::{Currency, Get}, @@ -23,7 +24,7 @@ use scale_info::prelude::collections::BTreeSet; use sp_runtime::SaturatedConversion; use sp_runtime::{Saturating, Weight, traits::Zero}; use sp_std::{boxed::Box, vec::Vec}; -use subtensor_runtime_common::NetUid; +use subtensor_runtime_common::{NetUid, WeightMeterWrapper}; use tle::{ curves::drand::TinyBLS381, stream_ciphers::AESGCMStreamCipherProvider, @@ -567,16 +568,40 @@ impl Pallet { commitments } - pub fn purge_netuid(netuid: NetUid) { + pub fn purge_netuid(netuid: NetUid, remaining_weight: Weight) -> Weight { + let mut weight_meter = WeightMeter::with_limit(remaining_weight); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().writes(CommitmentOf::::iter_prefix(netuid).count() as u64) + ); let _ = CommitmentOf::::clear_prefix(netuid, u32::MAX, None); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().writes(LastCommitment::::iter_prefix(netuid).count() as u64) + ); let _ = LastCommitment::::clear_prefix(netuid, u32::MAX, None); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().writes(LastBondsReset::::iter_prefix(netuid).count() as u64) + ); let _ = LastBondsReset::::clear_prefix(netuid, u32::MAX, None); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().writes(RevealedCommitments::::iter_prefix(netuid).count() as u64) + ); let _ = RevealedCommitments::::clear_prefix(netuid, u32::MAX, None); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().writes(UsedSpaceOf::::iter_prefix(netuid).count() as u64) + ); let _ = UsedSpaceOf::::clear_prefix(netuid, u32::MAX, None); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); + TimelockedIndex::::mutate(|index| { index.retain(|(n, _)| *n != netuid); }); + weight_meter.consumed() } } diff --git a/pallets/commitments/src/tests.rs b/pallets/commitments/src/tests.rs index 9270a84bb7..742d28eea1 100644 --- a/pallets/commitments/src/tests.rs +++ b/pallets/commitments/src/tests.rs @@ -2265,7 +2265,7 @@ fn purge_netuid_clears_only_that_netuid() { assert!(TimelockedIndex::::get().contains(&(net_a, who_a1))); // Act - Pallet::::purge_netuid(net_a); + Pallet::::purge_netuid(net_a, Weight::from_parts(u64::MAX, u64::MAX)); // NET A: everything cleared assert_eq!(CommitmentOf::::iter_prefix(net_a).count(), 0); diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index a55766387e..a0d3cb87d2 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -16,6 +16,7 @@ // DEALINGS IN THE SOFTWARE. use super::*; +use frame_support::weights::{Weight, WeightMeter}; use safe_math::*; use substrate_fixed::types::{I64F64, U96F32}; use subtensor_runtime_common::{AlphaCurrency, Currency, NetUid, NetUidStorageIndex, TaoCurrency}; @@ -209,50 +210,71 @@ impl Pallet { Error::::SubnetNotExists ); - // Just remove the network from the added networks. - NetworksAdded::::remove(netuid); - let mut dissolved_networks = DissolvedNetworks::::get(); ensure!( !dissolved_networks.contains(&netuid), Error::::NetworkAlreadyDissolved ); - // --- Perform the cleanup before removing the network. - Self::destroy_alpha_in_out_stakes(netuid)?; - T::SwapInterface::clear_protocol_liquidity(netuid)?; - T::CommitmentsInterface::purge_netuid(netuid); + // Just remove the network from the added networks. + NetworksAdded::::remove(netuid); + TotalNetworks::::mutate(|n: &mut u16| *n = n.saturating_sub(1)); dissolved_networks.push(netuid); DissolvedNetworks::::set(dissolved_networks); - // --- Emit the NetworkRemoved event + // --- Perform the cleanup before removing the network. + // Self::destroy_alpha_in_out_stakes(netuid)?; + // T::SwapInterface::clear_protocol_liquidity(netuid)?; + // T::CommitmentsInterface::purge_netuid(netuid); + + // finalize_all_subnet_root_dividends() + // remove_network() + log::info!("NetworkRemoved( netuid:{netuid:?} )"); + + // --- Emit the NetworkRemoved event Self::deposit_event(Event::NetworkRemoved(netuid)); Ok(()) } - pub fn remove_network(netuid: NetUid) { + pub fn remove_network(netuid: NetUid, remaining_weight: Weight) -> Weight { + let mut weight_meter = WeightMeter::with_limit(remaining_weight); + // --- 1. Get the owner and remove from SubnetOwner. + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1)); let owner_coldkey: T::AccountId = SubnetOwner::::get(netuid); + + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SubnetOwner::::remove(netuid); // --- 2. Remove network count. + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(3)); SubnetworkN::::remove(netuid); - // --- 3. Remove netuid from added networks. - NetworksAdded::::remove(netuid); - - // --- 4. Decrement the network counter. - TotalNetworks::::mutate(|n: &mut u16| *n = n.saturating_sub(1)); - // --- 5. Remove various network-related storages. + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); NetworkRegisteredAt::::remove(netuid); // --- 6. Remove incentive mechanism memory. + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().writes(Uids::::iter_prefix(netuid).count() as u64) + ); + let _ = Uids::::clear_prefix(netuid, u32::MAX, None); + let keys = Keys::::iter_prefix(netuid).collect::>(); + let keys_len = keys.len() as u64; + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(keys_len)); + for (_uid, key) in keys { + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); + IsNetworkMember::::remove(key, netuid); + } + + let count = Keys::::iter_prefix(netuid).count() as u64; + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(count)); let _ = Keys::::clear_prefix(netuid, u32::MAX, None); // --- 8. Iterate over stored weights and fill the matrix. @@ -262,142 +284,273 @@ impl Pallet { 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 == &u16::from(netuid) { + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); *weight = 0; } } + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); Weights::::insert(NetUidStorageIndex::ROOT, uid_i, modified_weights); } // --- 9. Remove various network-related parameters. + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); Rank::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); Trust::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); Active::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); Emission::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); Consensus::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); Dividends::::remove(netuid); PruningScores::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); ValidatorPermit::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); ValidatorTrust::::remove(netuid); - for (_uid, key) in keys { - IsNetworkMember::::remove(key, netuid); - } - // --- 10. Erase network parameters. + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); Tempo::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); Kappa::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); Difficulty::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); MaxAllowedUids::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); ImmunityPeriod::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); ActivityCutoff::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); MinAllowedWeights::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); RegistrationsThisInterval::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); POWRegistrationsThisInterval::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); BurnRegistrationsThisInterval::::remove(netuid); // --- 11. AMM / price / accounting. // SubnetTAO, SubnetAlpha{In,InProvided,Out} are already cleared during dissolve/destroy. + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SubnetAlphaInEmission::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SubnetAlphaOutEmission::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SubnetTaoInEmission::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SubnetVolume::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SubnetMovingPrice::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SubnetTaoFlow::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SubnetEmaTaoFlow::::remove(netuid); // --- 13. Token / mechanism / registration toggles. + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); TokenSymbol::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SubnetMechanism::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SubnetOwnerHotkey::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); NetworkRegistrationAllowed::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); NetworkPowRegistrationAllowed::::remove(netuid); // --- 14. Locks & toggles. + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); TransferToggle::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SubnetLocked::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); LargestLocked::::remove(netuid); // --- 15. Mechanism step / emissions bookkeeping. + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); FirstEmissionBlockNumber::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); PendingValidatorEmission::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); PendingServerEmission::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); PendingRootAlphaDivs::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); PendingOwnerCut::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); BlocksSinceLastStep::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); LastMechansimStepBlock::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); LastAdjustmentBlock::::remove(netuid); // --- 16. Serving / rho / curves, and other per-net controls. + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); ServingRateLimit::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); Rho::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); AlphaSigmoidSteepness::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); MaxAllowedValidators::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); AdjustmentInterval::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); BondsMovingAverage::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); BondsPenalty::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); BondsResetOn::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); WeightsSetRateLimit::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); ValidatorPruneLen::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); ScalingLawPower::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); TargetRegistrationsPerInterval::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); AdjustmentAlpha::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); CommitRevealWeightsEnabled::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); Burn::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); MinBurn::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); MaxBurn::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); MinDifficulty::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); MaxDifficulty::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); RegistrationsThisBlock::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); EMAPriceHalvingBlocks::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); RAORecycledForRegistration::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); MaxRegistrationsPerBlock::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); WeightsVersionKey::::remove(netuid); // --- 17. Subtoken / feature flags. + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); LiquidAlphaOn::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); Yuma3On::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); AlphaValues::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SubtokenEnabled::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); ImmuneOwnerUidsLimit::::remove(netuid); // --- 18. Consensus aux vectors. + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); StakeWeight::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); LoadedEmission::::remove(netuid); // --- 19. DMAPs where netuid is the FIRST key: clear by prefix. + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().writes(BlockAtRegistration::::iter_prefix(netuid).count() as u64) + ); let _ = BlockAtRegistration::::clear_prefix(netuid, u32::MAX, None); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().writes(Axons::::iter_prefix(netuid).count() as u64) + ); let _ = Axons::::clear_prefix(netuid, u32::MAX, None); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().writes(NeuronCertificates::::iter_prefix(netuid).count() as u64) + ); let _ = NeuronCertificates::::clear_prefix(netuid, u32::MAX, None); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().writes(Prometheus::::iter_prefix(netuid).count() as u64) + ); let _ = Prometheus::::clear_prefix(netuid, u32::MAX, None); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get() + .writes(AlphaDividendsPerSubnet::::iter_prefix(netuid).count() as u64) + ); let _ = AlphaDividendsPerSubnet::::clear_prefix(netuid, u32::MAX, None); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().writes(PendingChildKeys::::iter_prefix(netuid).count() as u64) + ); let _ = PendingChildKeys::::clear_prefix(netuid, u32::MAX, None); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get() + .writes(AssociatedEvmAddress::::iter_prefix(netuid).count() as u64) + ); let _ = AssociatedEvmAddress::::clear_prefix(netuid, u32::MAX, None); // Commit-reveal / weights commits (all per-net prefixes): let mechanisms: u8 = MechanismCountCurrent::::get(netuid).into(); for subid in 0..mechanisms { let netuid_index = Self::get_mechanism_storage_index(netuid, subid.into()); + LastUpdate::::remove(netuid_index); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); Incentive::::remove(netuid_index); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get() + .writes(WeightCommits::::iter_prefix(netuid_index).count() as u64) + ); let _ = WeightCommits::::clear_prefix(netuid_index, u32::MAX, None); let _ = TimelockedWeightCommits::::clear_prefix(netuid_index, u32::MAX, None); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get() + .writes(CRV3WeightCommits::::iter_prefix(netuid_index).count() as u64) + ); let _ = CRV3WeightCommits::::clear_prefix(netuid_index, u32::MAX, None); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get() + .writes(CRV3WeightCommitsV2::::iter_prefix(netuid_index).count() as u64) + ); let _ = CRV3WeightCommitsV2::::clear_prefix(netuid_index, u32::MAX, None); - let _ = Bonds::::clear_prefix(netuid_index, u32::MAX, None); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().writes(Weights::::iter_prefix(netuid_index).count() as u64) + ); let _ = Weights::::clear_prefix(netuid_index, u32::MAX, None); } + + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); RevealPeriodEpochs::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); MechanismCountCurrent::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); MechanismEmissionSplit::::remove(netuid); // Last hotkey swap (DMAP where netuid is FIRST key → easy) + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get() + .writes(LastHotkeySwapOnNetuid::::iter_prefix(netuid).count() as u64) + ); let _ = LastHotkeySwapOnNetuid::::clear_prefix(netuid, u32::MAX, None); // --- 20. Identity maps across versions (netuid-scoped). if SubnetIdentitiesV3::::contains_key(netuid) { + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SubnetIdentitiesV3::::remove(netuid); Self::deposit_event(Event::SubnetIdentityRemoved(netuid)); } @@ -406,88 +559,142 @@ impl Pallet { // ChildkeyTake: (hot, netuid) → u16 { + let mut read_count = 0_u64; let to_rm: sp_std::vec::Vec = ChildkeyTake::::iter() - .filter_map(|(hot, n, _)| if n == netuid { Some(hot) } else { None }) + .filter(|(_, n, _)| { + read_count = read_count.saturating_add(1); + *n == netuid + }) + .map(|(hot, _, _)| hot) .collect(); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(read_count)); for hot in to_rm { + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); ChildkeyTake::::remove(&hot, netuid); } } // ChildKeys: (parent, netuid) → Vec<...> { + let mut read_count = 0_u64; let to_rm: sp_std::vec::Vec = ChildKeys::::iter() - .filter_map(|(parent, n, _)| if n == netuid { Some(parent) } else { None }) + .filter(|(_, n, _)| { + read_count = read_count.saturating_add(1); + *n == netuid + }) + .map(|(parent, _, _)| parent) .collect(); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(read_count)); for parent in to_rm { + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); ChildKeys::::remove(&parent, netuid); } } // ParentKeys: (child, netuid) → Vec<...> { + let mut read_count = 0_u64; let to_rm: sp_std::vec::Vec = ParentKeys::::iter() - .filter_map(|(child, n, _)| if n == netuid { Some(child) } else { None }) + .filter(|(_, n, _)| { + read_count = read_count.saturating_add(1); + *n == netuid + }) + .map(|(child, _, _)| child) .collect(); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(read_count)); for child in to_rm { + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); ParentKeys::::remove(&child, netuid); } } // LastHotkeyEmissionOnNetuid: (hot, netuid) → α { + let mut read_count = 0_u64; let to_rm: sp_std::vec::Vec = LastHotkeyEmissionOnNetuid::::iter() - .filter_map(|(hot, n, _)| if n == netuid { Some(hot) } else { None }) + .filter(|(_, n, _)| { + read_count = read_count.saturating_add(1); + *n == netuid + }) + .map(|(hot, _, _)| hot) .collect(); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(read_count)); for hot in to_rm { + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); LastHotkeyEmissionOnNetuid::::remove(&hot, netuid); } } // TotalHotkeyAlphaLastEpoch: (hot, netuid) → ... // (TotalHotkeyAlpha and TotalHotkeyShares were already removed during dissolve.) { + let mut read_count = 0_u64; let to_rm_alpha_last: sp_std::vec::Vec = TotalHotkeyAlphaLastEpoch::::iter() - .filter_map(|(hot, n, _)| if n == netuid { Some(hot) } else { None }) + .filter(|(_, n, _)| { + read_count = read_count.saturating_add(1); + *n == netuid + }) + .map(|(hot, _, _)| hot) .collect(); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(read_count)); for hot in to_rm_alpha_last { + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); TotalHotkeyAlphaLastEpoch::::remove(&hot, netuid); } } // TransactionKeyLastBlock NMAP: (hot, netuid, name) → u64 { + let mut read_count = 0_u64; let to_rm: sp_std::vec::Vec<(T::AccountId, u16)> = TransactionKeyLastBlock::::iter() - .filter_map( - |((hot, n, name), _)| if n == netuid { Some((hot, name)) } else { None }, - ) + .filter(|((_, n, _), _)| { + read_count = read_count.saturating_add(1); + *n == netuid + }) + .map(|((hot, _, name), _)| (hot, name)) .collect(); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(read_count)); for (hot, name) in to_rm { + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); TransactionKeyLastBlock::::remove((hot, netuid, name)); } } // StakingOperationRateLimiter NMAP: (hot, cold, netuid) → bool { + let mut read_count = 0_u64; let to_rm: sp_std::vec::Vec<(T::AccountId, T::AccountId)> = StakingOperationRateLimiter::::iter() - .filter_map( - |((hot, cold, n), _)| { - if n == netuid { Some((hot, cold)) } else { None } - }, - ) + .filter(|((_, _, n), _)| { + read_count = read_count.saturating_add(1); + *n == netuid + }) + .map(|((hot, cold, _), _)| (hot, cold)) .collect(); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(read_count)); + for (hot, cold) in to_rm { + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); StakingOperationRateLimiter::::remove((hot, cold, netuid)); } } // --- 22. Subnet leasing: remove mapping and any lease-scoped state linked to this netuid. - if let Some(lease_id) = SubnetUidToLeaseId::::take(netuid) { + if let Some(lease_id) = SubnetUidToLeaseId::::get(netuid) { + // Fixed: Import the macro type to resolve the error + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + SubnetLeaseShares::::clear_prefix(lease_id, 1024, None) + ); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SubnetLeases::::remove(lease_id); - let _ = SubnetLeaseShares::::clear_prefix(lease_id, u32::MAX, None); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); AccumulatedLeaseDividends::::remove(lease_id); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); + SubnetUidToLeaseId::::remove(netuid); } // --- Final removal logging. log::debug!( "remove_network: netuid={netuid}, owner={owner_coldkey:?} removed successfully" ); + weight_meter.consumed() } #[allow(clippy::arithmetic_side_effects)] diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 64b2c3684b..7e46f1e2a6 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -25,6 +25,7 @@ use sp_core::Get; use sp_runtime::{DispatchError, transaction_validity::TransactionValidityError}; use sp_std::marker::PhantomData; use subtensor_runtime_common::{AlphaCurrency, Currency, CurrencyReserve, NetUid, TaoCurrency}; +pub use subtensor_runtime_common::{LoopRemovePrefixWithWeightMeter, WeightMeterWrapper}; // ============================ // ==== Benchmark Imports ===== @@ -2740,5 +2741,5 @@ impl ProxyInterface for () { /// Pallets that hold per-subnet commitments implement this to purge all state for `netuid`. pub trait CommitmentsInterface { - fn purge_netuid(netuid: NetUid); + fn purge_netuid(netuid: NetUid, remaining_weight: Weight) -> Weight; } diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index d0321744ea..97e4a107d0 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -180,17 +180,9 @@ mod hooks { } fn on_idle(_block: BlockNumberFor, limit: Weight) -> Weight { - let mut weight_meter = WeightMeter::with_limit(limit.saturating_div(2)); - let on_idle_weight = T::DbWeight::get().reads(1); - // let on_idle_weight = T::WeightInfo::on_idle_base(); - if !weight_meter.can_consume(on_idle_weight) { - return weight_meter.consumed(); - } - weight_meter.consume(on_idle_weight); - weight_meter.consumed(); - - let _ = Self::remove_data_for_dissolved_networks(weight_meter.remaining()); - weight_meter.consumed() + limit.saturating_sub(Self::remove_data_for_dissolved_networks( + limit.saturating_div(2), + )) } } @@ -244,38 +236,30 @@ mod hooks { fn remove_data_for_dissolved_networks(remaining_weight: Weight) -> Weight { let mut remaining_weight = remaining_weight; let dissolved_networks = DissolvedNetworks::::get(); - let mut _weight_meter = WeightMeter::with_limit(remaining_weight); for netuid in dissolved_networks.iter() { let weight_used = Self::finalize_all_subnet_root_dividends(*netuid, remaining_weight); remaining_weight = remaining_weight.saturating_sub(weight_used); - // let weight_used = T::SwapInterface::dissolve_all_liquidity_providers(*netuid); - // remaining_weight = remaining_weight.saturating_sub(weight_used); - // let weight_used = Self::destroy_alpha_in_out_stakes(*netuid); - // remaining_weight = remaining_weight.saturating_sub(weight_used); - // let weight_used = T::SwapInterface::clear_protocol_liquidity(*netuid); - // remaining_weight = remaining_weight.saturating_sub(weight_used); - // let weight_used_ = T::CommitmentsInterface::purge_netuid(*netuid); - // remaining_weight = remaining_weight.saturating_sub(weight_used); - // let weight_used = Self::remove_network(*netuid); - // remaining_weight = remaining_weight.saturating_sub(weight_used); + + let weight_used = Self::destroy_alpha_in_out_stakes(*netuid, remaining_weight); + remaining_weight = remaining_weight.saturating_sub(weight_used); + + let weight_used = + T::SwapInterface::clear_protocol_liquidity(*netuid, remaining_weight); + remaining_weight = remaining_weight.saturating_sub(weight_used); + + let weight_used = T::CommitmentsInterface::purge_netuid(*netuid, remaining_weight); + remaining_weight = remaining_weight.saturating_sub(weight_used); + + let weight_used = Self::remove_network(*netuid, remaining_weight); + remaining_weight = remaining_weight.saturating_sub(weight_used); DissolvedNetworks::::mutate(|networks| networks.retain(|n| *n != *netuid)); Self::deposit_event(Event::DissolvedNetworkDataCleaned { netuid: *netuid }); } - Weight::from_parts(0, 0) - // Self::finalize_all_subnet_root_dividends(netuid); - - // --- Perform the cleanup before removing the network. - // T::SwapInterface::dissolve_all_liquidity_providers(netuid)?; - // Self::destroy_alpha_in_out_stakes(netuid)?; - // T::SwapInterface::clear_protocol_liquidity(netuid)?; - // T::CommitmentsInterface::purge_netuid(netuid); - - // --- Remove the network - // Self::remove_network(netuid); + remaining_weight } } } diff --git a/pallets/subtensor/src/staking/claim_root.rs b/pallets/subtensor/src/staking/claim_root.rs index 0619a38c04..24a55163f8 100644 --- a/pallets/subtensor/src/staking/claim_root.rs +++ b/pallets/subtensor/src/staking/claim_root.rs @@ -392,25 +392,22 @@ impl Pallet { /// Claim all root dividends for subnet and remove all associated data. pub fn finalize_all_subnet_root_dividends(netuid: NetUid, remaining_weight: Weight) -> Weight { let mut weight_meter = WeightMeter::with_limit(remaining_weight); - + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1)); // Iterate directly without collecting to avoid unnecessary allocation for hotkey in RootClaimable::::iter_keys() { - WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1), {}); - - WeightMeterWrapper!( - weight_meter, - T::DbWeight::get().writes(1), - RootClaimable::::mutate(&hotkey, |claimable| { - claimable.remove(&netuid); - }) - ); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1)); + let mut claimable = RootClaimable::::get(&hotkey); + if claimable.contains_key(&netuid) { + claimable.remove(&netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); + RootClaimable::::insert(&hotkey, claimable); + } + + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1)); } - WeightMeterWrapper!( - weight_meter, - T::DbWeight::get().writes(1), - RootClaimed::::clear_prefix((netuid,), u32::MAX, None) - ); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); + let _ = RootClaimed::::clear_prefix((netuid,), u32::MAX, None); weight_meter.consumed() } } diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs index 735ec804df..dd855d51f0 100644 --- a/pallets/subtensor/src/staking/remove_stake.rs +++ b/pallets/subtensor/src/staking/remove_stake.rs @@ -1,4 +1,5 @@ use super::*; +use frame_support::weights::WeightMeter; use substrate_fixed::types::U96F32; use subtensor_runtime_common::{AlphaCurrency, Currency, NetUid, TaoCurrency}; use subtensor_swap_interface::{Order, SwapHandler}; @@ -433,16 +434,24 @@ impl Pallet { } } - pub fn destroy_alpha_in_out_stakes(netuid: NetUid) -> DispatchResult { + pub fn destroy_alpha_in_out_stakes(netuid: NetUid, remaining_weight: Weight) -> Weight { // 1) Ensure the subnet exists. - ensure!(Self::if_subnet_exist(netuid), Error::::SubnetNotExists); + if !Self::if_subnet_exist(netuid) { + return Weight::from_parts(0, 0); + } + + let mut meter_weight = WeightMeter::with_limit(remaining_weight); // 2) Owner / lock cost. + WeightMeterWrapper!(meter_weight, T::DbWeight::get().reads(1)); let owner_coldkey: T::AccountId = SubnetOwner::::get(netuid); + WeightMeterWrapper!(meter_weight, T::DbWeight::get().reads(1)); let lock_cost: TaoCurrency = Self::get_subnet_locked_balance(netuid); // Determine if this subnet is eligible for a lock refund (legacy). + WeightMeterWrapper!(meter_weight, T::DbWeight::get().reads(1)); let reg_at: u64 = NetworkRegisteredAt::::get(netuid); + WeightMeterWrapper!(meter_weight, T::DbWeight::get().reads(1)); let start_block: u64 = NetworkRegistrationStartBlock::::get(); let should_refund_owner: bool = reg_at < start_block; @@ -453,9 +462,11 @@ impl Pallet { // - price that α using a *simulated* AMM swap. let mut owner_emission_tao = TaoCurrency::ZERO; if should_refund_owner && !lock_cost.is_zero() { + WeightMeterWrapper!(meter_weight, T::DbWeight::get().reads(1)); let total_emitted_alpha_u128: u128 = Self::get_alpha_issuance(netuid).to_u64() as u128; if total_emitted_alpha_u128 > 0 { + WeightMeterWrapper!(meter_weight, T::DbWeight::get().reads(1)); let owner_fraction: U96F32 = Self::get_float_subnet_owner_cut(); let owner_alpha_u64 = U96F32::from_num(total_emitted_alpha_u128) .saturating_mul(owner_fraction) @@ -463,6 +474,8 @@ impl Pallet { .saturating_to_num::(); owner_emission_tao = if owner_alpha_u64 > 0 { + // Need max 3 reads for current_alpha_price + WeightMeterWrapper!(meter_weight, T::DbWeight::get().reads(3)); let cur_price: U96F32 = U96F32::saturating_from_num( T::SwapInterface::current_alpha_price(netuid.into()), ); @@ -490,8 +503,15 @@ impl Pallet { .map(|(hot, _, _)| hot.clone()) .collect::>(); + WeightMeterWrapper!( + meter_weight, + T::DbWeight::get().reads(hotkeys_in_subnet.len() as u64) + ); + for hot in hotkeys_in_subnet.iter() { - for ((cold, this_netuid), share_u64f64) in Alpha::::iter_prefix((hot,)) { + WeightMeterWrapper!(meter_weight, T::DbWeight::get().reads(1)); + for ((cold, this_netuid), share_u64f64) in Alpha::::iter_prefix((hot.clone(),)) { + WeightMeterWrapper!(meter_weight, T::DbWeight::get().reads(1)); if this_netuid != netuid { continue; } @@ -517,11 +537,14 @@ impl Pallet { } // 5) Determine the TAO pot and pre-adjust accounting to avoid double counting. + WeightMeterWrapper!(meter_weight, T::DbWeight::get().reads(1)); let pot_tao: TaoCurrency = SubnetTAO::::get(netuid); let pot_u64: u64 = pot_tao.into(); if pot_u64 > 0 { + WeightMeterWrapper!(meter_weight, T::DbWeight::get().reads(1)); SubnetTAO::::remove(netuid); + WeightMeterWrapper!(meter_weight, T::DbWeight::get().writes(1)); TotalStake::::mutate(|total| *total = total.saturating_sub(pot_tao)); } @@ -577,15 +600,20 @@ impl Pallet { Alpha::::remove((hot, cold, netuid)); } // 7.b) Clear share‑pool totals for each hotkey on this subnet. - for hot in hotkeys_in_subnet { + for hot in hotkeys_in_subnet.iter() { + WeightMeterWrapper!(meter_weight, T::DbWeight::get().writes(1)); TotalHotkeyAlpha::::remove(&hot, netuid); + WeightMeterWrapper!(meter_weight, T::DbWeight::get().writes(1)); TotalHotkeyShares::::remove(&hot, netuid); } // 7.c) Remove α‑in/α‑out counters (fully destroyed). + WeightMeterWrapper!(meter_weight, T::DbWeight::get().writes(1)); SubnetAlphaIn::::remove(netuid); + WeightMeterWrapper!(meter_weight, T::DbWeight::get().writes(1)); SubnetAlphaOut::::remove(netuid); // Clear the locked balance on the subnet. + WeightMeterWrapper!(meter_weight, T::DbWeight::get().writes(1)); Self::set_subnet_locked_balance(netuid, TaoCurrency::ZERO); // 8) Finalize lock handling: @@ -599,9 +627,10 @@ impl Pallet { }; if !refund.is_zero() { + WeightMeterWrapper!(meter_weight, T::DbWeight::get().writes(1)); Self::add_balance_to_coldkey_account(&owner_coldkey, refund.to_u64()); } - Ok(()) + meter_weight.consumed() } } diff --git a/pallets/subtensor/src/tests/networks.rs b/pallets/subtensor/src/tests/networks.rs index 5176ae05dc..148ec429b7 100644 --- a/pallets/subtensor/src/tests/networks.rs +++ b/pallets/subtensor/src/tests/networks.rs @@ -642,6 +642,7 @@ fn dissolve_alpha_out_but_zero_tao_no_rewards() { SubnetTAO::::insert(net, TaoCurrency::from(0)); // zero TAO SubtensorModule::set_subnet_locked_balance(net, TaoCurrency::from(0)); Emission::::insert(net, Vec::::new()); + TotalHotkeyAlpha::::insert(sh, net, AlphaCurrency::from(1_000u64)); let before = SubtensorModule::get_coldkey_balance(&sc); diff --git a/pallets/subtensor/src/utils/mod.rs b/pallets/subtensor/src/utils/mod.rs index 072a29c453..b997605779 100644 --- a/pallets/subtensor/src/utils/mod.rs +++ b/pallets/subtensor/src/utils/mod.rs @@ -7,20 +7,8 @@ pub mod rate_limiting; pub mod try_state; pub mod voting_power; -#[macro_export] -macro_rules! WeightMeterWrapper { - ( $meter:expr, $weight:expr, $body:expr ) => {{ - if !$meter.can_consume($weight) { - return $meter.consumed(); - } - let _ = $body; - $meter.consume($weight); - }}; -} - #[cfg(test)] mod tests { - use core::cell::Cell; /// Mock weight meter for testing the macro. struct MockWeightMeter { @@ -45,12 +33,8 @@ mod tests { /// Helper: the macro's early return yields u64, so it must be in a fn returning u64. fn run_with_meter(mut meter: MockWeightMeter) -> u64 { - WeightMeterWrapper!(meter, 10u64, { - // body executes when we can consume - }); - WeightMeterWrapper!(meter, 20u64, { - // body executes - }); + WeightMeterWrapper!(meter, 10u64); + WeightMeterWrapper!(meter, 20u64); meter.consumed() } @@ -75,15 +59,8 @@ mod tests { #[test] fn test_weight_meter_wrapper_body_executes() { fn helper() -> u64 { - let executed = Cell::new(false); let mut meter = MockWeightMeter::with_limit(100); - WeightMeterWrapper!(meter, 10u64, { - executed.set(true); - }); - assert!( - executed.get(), - "body should execute when weight is available" - ); + WeightMeterWrapper!(meter, 10u64); meter.consumed() } assert_eq!(helper(), 10); @@ -91,19 +68,12 @@ mod tests { #[test] fn test_weight_meter_wrapper_body_does_not_execute_when_over_limit() { - let executed = Cell::new(false); let mut meter = MockWeightMeter::with_limit(5); - fn run(executed: &Cell, meter: &mut MockWeightMeter) -> u64 { - WeightMeterWrapper!(meter, 10u64, { - executed.set(true); - }); + fn run(meter: &mut MockWeightMeter) -> u64 { + WeightMeterWrapper!(meter, 10u64); meter.consumed() } - let consumed = run(&executed, &mut meter); - assert!( - !executed.get(), - "body should not execute when weight exceeds limit" - ); + let consumed = run(&mut meter); assert_eq!(consumed, 0); } } diff --git a/pallets/swap-interface/src/lib.rs b/pallets/swap-interface/src/lib.rs index 9c22ca95e8..300a12be0f 100644 --- a/pallets/swap-interface/src/lib.rs +++ b/pallets/swap-interface/src/lib.rs @@ -47,7 +47,7 @@ pub trait SwapHandler { alpha_delta: AlphaCurrency, ) -> (TaoCurrency, AlphaCurrency); - fn clear_protocol_liquidity(netuid: NetUid) -> DispatchResult; + fn clear_protocol_liquidity(netuid: NetUid, remaining_weight: Weight) -> Weight; fn init_swap(netuid: NetUid, maybe_price: Option); } diff --git a/pallets/swap/src/pallet/impls.rs b/pallets/swap/src/pallet/impls.rs index 9656a81f50..19fe48a18c 100644 --- a/pallets/swap/src/pallet/impls.rs +++ b/pallets/swap/src/pallet/impls.rs @@ -1,5 +1,13 @@ +use super::pallet::*; +use super::swap_step::{BasicSwapStep, SwapStep}; +use crate::{pallet::Balancer, pallet::balancer::BalancerError}; use frame_support::storage::{TransactionOutcome, transactional}; -use frame_support::{ensure, pallet_prelude::DispatchError, traits::Get}; +use frame_support::{ + ensure, + pallet_prelude::DispatchError, + traits::Get, + weights::{Weight, WeightMeter}, +}; use safe_math::*; use sp_arithmetic::{ //helpers_128bit, @@ -7,6 +15,7 @@ use sp_arithmetic::{ }; use sp_runtime::{DispatchResult, traits::AccountIdConversion}; use substrate_fixed::types::U64F64; +use subtensor_runtime_common::WeightMeterWrapper; use subtensor_runtime_common::{ AlphaCurrency, // BalanceOps, @@ -20,10 +29,6 @@ use subtensor_swap_interface::{ DefaultPriceLimit, Order as OrderT, SwapEngine, SwapHandler, SwapResult, }; -use super::pallet::*; -use super::swap_step::{BasicSwapStep, SwapStep}; -use crate::{pallet::Balancer, pallet::balancer::BalancerError}; - impl Pallet { pub fn current_price(netuid: NetUid) -> U64F64 { match T::SubnetInfo::mechanism(netuid.into()) { @@ -285,27 +290,42 @@ impl Pallet { } /// Clear **protocol-owned** liquidity and wipe all swap state for `netuid`. - pub fn do_clear_protocol_liquidity(netuid: NetUid) -> DispatchResult { + pub fn do_clear_protocol_liquidity(netuid: NetUid, remaining_weight: Weight) -> Weight { + let mut weight_meter = WeightMeter::with_limit(remaining_weight); + // let protocol_account = Self::protocol_account_id(); // 1) Force-close protocol liquidity, burning proceeds. + + // Record a database read (for reserve state). + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1)); + + // Burn all protocol reserves for τ and α. let burned_tao = T::TaoReserve::reserve(netuid.into()); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1)); let burned_alpha = T::AlphaReserve::reserve(netuid.into()); - + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); T::TaoReserve::decrease_provided(netuid.into(), burned_tao); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); T::AlphaReserve::decrease_provided(netuid.into(), burned_alpha); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); FeesTao::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); FeesAlpha::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); PalSwapInitialized::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); FeeRate::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SwapBalancer::::remove(netuid); log::debug!( "clear_protocol_liquidity: netuid={netuid:?}, protocol_burned: τ={burned_tao:?}, α={burned_alpha:?}; state cleared" ); - Ok(()) + weight_meter.consumed() } } @@ -431,8 +451,8 @@ impl SwapHandler for Pallet { // fn toggle_user_liquidity(netuid: NetUid, enabled: bool) { // EnabledUserLiquidity::::insert(netuid, enabled) // } - fn clear_protocol_liquidity(netuid: NetUid) -> DispatchResult { - Self::do_clear_protocol_liquidity(netuid) + fn clear_protocol_liquidity(netuid: NetUid, remaining_weight: Weight) -> Weight { + Self::do_clear_protocol_liquidity(netuid, remaining_weight) } fn init_swap(netuid: NetUid, maybe_price: Option) { Self::maybe_initialize_palswap(netuid, maybe_price).unwrap_or_default(); diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 89735b1011..2c38ad14ce 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -770,8 +770,8 @@ impl ProxyInterface for Proxier { pub struct CommitmentsI; impl CommitmentsInterface for CommitmentsI { - fn purge_netuid(netuid: NetUid) { - pallet_commitments::Pallet::::purge_netuid(netuid); + fn purge_netuid(netuid: NetUid, remaining_weight: Weight) -> Weight { + pallet_commitments::Pallet::::purge_netuid(netuid, remaining_weight) } } From 8f17e842279da2e9c551d52294883a64b01ecb75 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 16 Feb 2026 15:48:20 +0800 Subject: [PATCH 12/40] commit Cargo.lock --- pallets/commitments/src/tests.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pallets/commitments/src/tests.rs b/pallets/commitments/src/tests.rs index 742d28eea1..57d0b329d7 100644 --- a/pallets/commitments/src/tests.rs +++ b/pallets/commitments/src/tests.rs @@ -18,6 +18,7 @@ use frame_support::pallet_prelude::Hooks; use frame_support::{ BoundedVec, assert_noop, assert_ok, traits::{Currency, Get, ReservableCurrency}, + weights::Weight, }; use frame_system::{Pallet as System, RawOrigin}; @@ -2298,7 +2299,7 @@ fn purge_netuid_clears_only_that_netuid() { assert!(idx_after.contains(&(net_b, who_b))); // Idempotency - Pallet::::purge_netuid(net_a); + Pallet::::purge_netuid(net_a, Weight::from_parts(u64::MAX, u64::MAX)); assert_eq!(CommitmentOf::::iter_prefix(net_a).count(), 0); assert!(!TimelockedIndex::::get().contains(&(net_a, who_a1))); }); From f932ae6777a6ce4eb9017ec19392ae9441a3ce7e Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 16 Feb 2026 15:49:57 +0800 Subject: [PATCH 13/40] commit Cargo.lock --- pallets/subtensor/src/coinbase/root.rs | 1 - pallets/subtensor/src/lib.rs | 2 +- pallets/swap/src/pallet/impls.rs | 2 +- pallets/swap/src/pallet/tests.rs | 6 +++--- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index a0d3cb87d2..3b1970c26d 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -20,7 +20,6 @@ use frame_support::weights::{Weight, WeightMeter}; use safe_math::*; use substrate_fixed::types::{I64F64, U96F32}; use subtensor_runtime_common::{AlphaCurrency, Currency, NetUid, NetUidStorageIndex, TaoCurrency}; -use subtensor_swap_interface::SwapHandler; impl Pallet { /// Fetches the total count of root network validators diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 7e46f1e2a6..9e9304aa63 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -88,7 +88,7 @@ pub mod pallet { traits::{ OriginTrait, QueryPreimage, StorePreimage, UnfilteredDispatchable, tokens::fungible, }, - weights::{Weight, WeightMeter}, + weights::Weight, }; use frame_system::pallet_prelude::*; use pallet_drand::types::RoundNumber; diff --git a/pallets/swap/src/pallet/impls.rs b/pallets/swap/src/pallet/impls.rs index 19fe48a18c..9e6640303a 100644 --- a/pallets/swap/src/pallet/impls.rs +++ b/pallets/swap/src/pallet/impls.rs @@ -13,7 +13,7 @@ use sp_arithmetic::{ //helpers_128bit, Perquintill, }; -use sp_runtime::{DispatchResult, traits::AccountIdConversion}; +use sp_runtime::traits::AccountIdConversion; use substrate_fixed::types::U64F64; use subtensor_runtime_common::WeightMeterWrapper; use subtensor_runtime_common::{ diff --git a/pallets/swap/src/pallet/tests.rs b/pallets/swap/src/pallet/tests.rs index 912c89bbe8..a954b3f57a 100644 --- a/pallets/swap/src/pallet/tests.rs +++ b/pallets/swap/src/pallet/tests.rs @@ -801,7 +801,7 @@ fn test_liquidate_pal_simple_ok_and_clears() { assert!(PalSwapInitialized::::get(netuid)); // ACT - assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::MAX, u64::MAX)); // All single-key maps should not have the key after liquidation assert!(!FeeRate::::contains_key(netuid)); @@ -827,7 +827,7 @@ fn test_clear_protocol_liquidity_green_path() { // --- Act --- // Green path: just clear protocol liquidity and wipe all V3 state. - assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::MAX, u64::MAX)); // Fee globals assert!(!FeesTao::::contains_key(netuid)); @@ -840,7 +840,7 @@ fn test_clear_protocol_liquidity_green_path() { assert!(!FeeRate::::contains_key(netuid)); // --- And it's idempotent --- - assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::MAX, u64::MAX)); assert!(!PalSwapInitialized::::contains_key(netuid)); }); } From 71668dea08ba2b89c1d4ca9c9b45939ee1bed693 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 16 Feb 2026 15:52:17 +0800 Subject: [PATCH 14/40] commit Cargo.lock --- chain-extensions/src/mock.rs | 4 +++- pallets/admin-utils/src/tests/mock.rs | 4 +++- pallets/subtensor/src/tests/mock.rs | 4 +++- pallets/transaction-fee/src/tests/mock.rs | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/chain-extensions/src/mock.rs b/chain-extensions/src/mock.rs index 69fb9de089..4ad9fbea0a 100644 --- a/chain-extensions/src/mock.rs +++ b/chain-extensions/src/mock.rs @@ -443,7 +443,9 @@ impl PrivilegeCmp for OriginPrivilegeCmp { pub struct CommitmentsI; impl CommitmentsInterface for CommitmentsI { - fn purge_netuid(_netuid: NetUid) {} + fn purge_netuid(_netuid: NetUid, remaining_weight: Weight) -> Weight { + remaining_weight + } } parameter_types! { diff --git a/pallets/admin-utils/src/tests/mock.rs b/pallets/admin-utils/src/tests/mock.rs index c28755802f..9bb8cb757e 100644 --- a/pallets/admin-utils/src/tests/mock.rs +++ b/pallets/admin-utils/src/tests/mock.rs @@ -348,7 +348,9 @@ impl PrivilegeCmp for OriginPrivilegeCmp { pub struct CommitmentsI; impl pallet_subtensor::CommitmentsInterface for CommitmentsI { - fn purge_netuid(_netuid: NetUid) {} + fn purge_netuid(_netuid: NetUid, remaining_weight: Weight) -> Weight { + remaining_weight + } } pub struct GrandpaInterfaceImpl; diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 62f11ad4d0..36f6d9766b 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -334,7 +334,9 @@ impl PrivilegeCmp for OriginPrivilegeCmp { pub struct CommitmentsI; impl CommitmentsInterface for CommitmentsI { - fn purge_netuid(_netuid: NetUid) {} + fn purge_netuid(_netuid: NetUid, remaining_weight: Weight) -> Weight { + remaining_weight + } } parameter_types! { diff --git a/pallets/transaction-fee/src/tests/mock.rs b/pallets/transaction-fee/src/tests/mock.rs index 56b7b77308..c8d80117b2 100644 --- a/pallets/transaction-fee/src/tests/mock.rs +++ b/pallets/transaction-fee/src/tests/mock.rs @@ -413,7 +413,9 @@ impl PrivilegeCmp for OriginPrivilegeCmp { pub struct CommitmentsI; impl pallet_subtensor::CommitmentsInterface for CommitmentsI { - fn purge_netuid(_netuid: NetUid) {} + fn purge_netuid(_netuid: NetUid, remaining_weight: Weight) -> Weight { + remaining_weight + } } parameter_types! { From 85d33d6e703f0db854cc83716147714fadca0ade Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 16 Feb 2026 15:53:39 +0800 Subject: [PATCH 15/40] commit Cargo.lock --- pallets/subtensor/src/tests/networks.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/tests/networks.rs b/pallets/subtensor/src/tests/networks.rs index 148ec429b7..7e98ccab57 100644 --- a/pallets/subtensor/src/tests/networks.rs +++ b/pallets/subtensor/src/tests/networks.rs @@ -1052,7 +1052,10 @@ fn destroy_alpha_out_refund_gating_by_registration_block() { let owner_before = SubtensorModule::get_coldkey_balance(&owner_cold); // Run the path under test - assert_ok!(SubtensorModule::destroy_alpha_in_out_stakes(netuid)); + SubtensorModule::destroy_alpha_in_out_stakes( + netuid, + Weight::from_parts(u64::MAX, u64::MAX), + ); // No refund for non‑legacy let owner_after = SubtensorModule::get_coldkey_balance(&owner_cold); @@ -1086,7 +1089,10 @@ fn destroy_alpha_out_refund_gating_by_registration_block() { SubnetOwnerCut::::put(32_768u16); // ~50% let owner_before = SubtensorModule::get_coldkey_balance(&owner_cold); - assert_ok!(SubtensorModule::destroy_alpha_in_out_stakes(netuid)); + SubtensorModule::destroy_alpha_in_out_stakes( + netuid, + Weight::from_parts(u64::MAX, u64::MAX), + ); let owner_after = SubtensorModule::get_coldkey_balance(&owner_cold); // No refund possible when lock = 0 From dc8b74456c7c3de0d4f7f0bbb71d71c46050b8db Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 16 Feb 2026 15:56:37 +0800 Subject: [PATCH 16/40] commit Cargo.lock --- pallets/subtensor/src/tests/networks.rs | 15 ++++-- pallets/subtensor/src/utils/mod.rs | 71 ------------------------- 2 files changed, 12 insertions(+), 74 deletions(-) diff --git a/pallets/subtensor/src/tests/networks.rs b/pallets/subtensor/src/tests/networks.rs index 7e98ccab57..c90e46baa5 100644 --- a/pallets/subtensor/src/tests/networks.rs +++ b/pallets/subtensor/src/tests/networks.rs @@ -767,7 +767,10 @@ fn destroy_alpha_out_multiple_stakers_pro_rata() { let owner_before = SubtensorModule::get_coldkey_balance(&owner_cold); // 7. Run the (now credit-to-coldkey) logic - assert_ok!(SubtensorModule::destroy_alpha_in_out_stakes(netuid)); + SubtensorModule::destroy_alpha_in_out_stakes( + netuid, + Weight::from_parts(u64::MAX, u64::MAX), + ); // 8. Expected τ shares via largest remainder let prod1 = (tao_pot as u128) * a1; @@ -922,7 +925,10 @@ fn destroy_alpha_out_many_stakers_complex_distribution() { let expected_refund = lock.saturating_sub(owner_emission_tao); // ── 6) run distribution (credits τ to coldkeys, wipes α state) ───── - assert_ok!(SubtensorModule::destroy_alpha_in_out_stakes(netuid)); + SubtensorModule::destroy_alpha_in_out_stakes( + netuid, + Weight::from_parts(u64::MAX, u64::MAX), + ); // ── 7) post checks ────────────────────────────────────────────────── for i in 0..N { @@ -1006,7 +1012,10 @@ fn destroy_alpha_out_refund_gating_by_registration_block() { let owner_before = SubtensorModule::get_coldkey_balance(&owner_cold); // Run the path under test - assert_ok!(SubtensorModule::destroy_alpha_in_out_stakes(netuid)); + SubtensorModule::destroy_alpha_in_out_stakes( + netuid, + Weight::from_parts(u64::MAX, u64::MAX), + ); // Owner received their refund… let owner_after = SubtensorModule::get_coldkey_balance(&owner_cold); diff --git a/pallets/subtensor/src/utils/mod.rs b/pallets/subtensor/src/utils/mod.rs index b997605779..a91875da59 100644 --- a/pallets/subtensor/src/utils/mod.rs +++ b/pallets/subtensor/src/utils/mod.rs @@ -6,74 +6,3 @@ pub mod rate_limiting; #[cfg(feature = "try-runtime")] pub mod try_state; pub mod voting_power; - -#[cfg(test)] -mod tests { - - /// Mock weight meter for testing the macro. - struct MockWeightMeter { - limit: u64, - used: u64, - } - - impl MockWeightMeter { - fn with_limit(limit: u64) -> Self { - Self { limit, used: 0 } - } - fn can_consume(&self, weight: u64) -> bool { - self.used.saturating_add(weight) <= self.limit - } - fn consume(&mut self, weight: u64) { - self.used = self.used.saturating_add(weight); - } - fn consumed(&self) -> u64 { - self.used - } - } - - /// Helper: the macro's early return yields u64, so it must be in a fn returning u64. - fn run_with_meter(mut meter: MockWeightMeter) -> u64 { - WeightMeterWrapper!(meter, 10u64); - WeightMeterWrapper!(meter, 20u64); - meter.consumed() - } - - #[test] - fn test_weight_meter_wrapper_consumes_weight() { - let meter = MockWeightMeter::with_limit(100); - let consumed = run_with_meter(meter); - assert_eq!(consumed, 30, "should consume 10 + 20 = 30"); - } - - #[test] - fn test_weight_meter_wrapper_returns_early_when_over_limit() { - let meter = MockWeightMeter::with_limit(15); - let consumed = run_with_meter(meter); - // First block consumes 10, second would need 20 but only 5 remain -> early return - assert_eq!( - consumed, 10, - "should return after first consume when second would exceed limit" - ); - } - - #[test] - fn test_weight_meter_wrapper_body_executes() { - fn helper() -> u64 { - let mut meter = MockWeightMeter::with_limit(100); - WeightMeterWrapper!(meter, 10u64); - meter.consumed() - } - assert_eq!(helper(), 10); - } - - #[test] - fn test_weight_meter_wrapper_body_does_not_execute_when_over_limit() { - let mut meter = MockWeightMeter::with_limit(5); - fn run(meter: &mut MockWeightMeter) -> u64 { - WeightMeterWrapper!(meter, 10u64); - meter.consumed() - } - let consumed = run(&mut meter); - assert_eq!(consumed, 0); - } -} From 08d2d34a4bc26cdcbf79a3d74645fb0b1245af95 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 16 Feb 2026 17:15:25 +0800 Subject: [PATCH 17/40] optimize some db ops --- pallets/commitments/src/lib.rs | 36 ++++--- pallets/subtensor/src/coinbase/root.rs | 133 +++++++++++++------------ pallets/swap/src/pallet/impls.rs | 15 +-- 3 files changed, 89 insertions(+), 95 deletions(-) diff --git a/pallets/commitments/src/lib.rs b/pallets/commitments/src/lib.rs index 73cdd846ca..5284c3eb68 100644 --- a/pallets/commitments/src/lib.rs +++ b/pallets/commitments/src/lib.rs @@ -24,7 +24,7 @@ use scale_info::prelude::collections::BTreeSet; use sp_runtime::SaturatedConversion; use sp_runtime::{Saturating, Weight, traits::Zero}; use sp_std::{boxed::Box, vec::Vec}; -use subtensor_runtime_common::{NetUid, WeightMeterWrapper}; +use subtensor_runtime_common::{LoopRemovePrefixWithWeightMeter, NetUid, WeightMeterWrapper}; use tle::{ curves::drand::TinyBLS381, stream_ciphers::AESGCMStreamCipherProvider, @@ -570,31 +570,35 @@ impl Pallet { pub fn purge_netuid(netuid: NetUid, remaining_weight: Weight) -> Weight { let mut weight_meter = WeightMeter::with_limit(remaining_weight); - WeightMeterWrapper!( + LoopRemovePrefixWithWeightMeter!( weight_meter, - T::DbWeight::get().writes(CommitmentOf::::iter_prefix(netuid).count() as u64) + T::DbWeight::get().writes(1), + CommitmentOf::::clear_prefix(netuid, 1024, None) ); - let _ = CommitmentOf::::clear_prefix(netuid, u32::MAX, None); - WeightMeterWrapper!( + + LoopRemovePrefixWithWeightMeter!( weight_meter, - T::DbWeight::get().writes(LastCommitment::::iter_prefix(netuid).count() as u64) + T::DbWeight::get().writes(1), + LastCommitment::::clear_prefix(netuid, 1024, None) ); - let _ = LastCommitment::::clear_prefix(netuid, u32::MAX, None); - WeightMeterWrapper!( + + LoopRemovePrefixWithWeightMeter!( weight_meter, - T::DbWeight::get().writes(LastBondsReset::::iter_prefix(netuid).count() as u64) + T::DbWeight::get().writes(1), + LastBondsReset::::clear_prefix(netuid, 1024, None) ); - let _ = LastBondsReset::::clear_prefix(netuid, u32::MAX, None); - WeightMeterWrapper!( + + LoopRemovePrefixWithWeightMeter!( weight_meter, - T::DbWeight::get().writes(RevealedCommitments::::iter_prefix(netuid).count() as u64) + T::DbWeight::get().writes(1), + RevealedCommitments::::clear_prefix(netuid, 1024, None) ); - let _ = RevealedCommitments::::clear_prefix(netuid, u32::MAX, None); - WeightMeterWrapper!( + + LoopRemovePrefixWithWeightMeter!( weight_meter, - T::DbWeight::get().writes(UsedSpaceOf::::iter_prefix(netuid).count() as u64) + T::DbWeight::get().writes(1), + UsedSpaceOf::::clear_prefix(netuid, 1024, None) ); - let _ = UsedSpaceOf::::clear_prefix(netuid, u32::MAX, None); WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index 3b1970c26d..a0d7fa55f7 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -222,14 +222,6 @@ impl Pallet { dissolved_networks.push(netuid); DissolvedNetworks::::set(dissolved_networks); - // --- Perform the cleanup before removing the network. - // Self::destroy_alpha_in_out_stakes(netuid)?; - // T::SwapInterface::clear_protocol_liquidity(netuid)?; - // T::CommitmentsInterface::purge_netuid(netuid); - - // finalize_all_subnet_root_dividends() - // remove_network() - log::info!("NetworkRemoved( netuid:{netuid:?} )"); // --- Emit the NetworkRemoved event @@ -249,7 +241,7 @@ impl Pallet { SubnetOwner::::remove(netuid); // --- 2. Remove network count. - WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(3)); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SubnetworkN::::remove(netuid); // --- 5. Remove various network-related storages. @@ -257,30 +249,36 @@ impl Pallet { NetworkRegisteredAt::::remove(netuid); // --- 6. Remove incentive mechanism memory. - WeightMeterWrapper!( + LoopRemovePrefixWithWeightMeter!( weight_meter, - T::DbWeight::get().writes(Uids::::iter_prefix(netuid).count() as u64) + T::DbWeight::get().writes(1), + Uids::::clear_prefix(netuid, 1024, None) ); - let _ = Uids::::clear_prefix(netuid, u32::MAX, None); - let keys = Keys::::iter_prefix(netuid).collect::>(); let keys_len = keys.len() as u64; - WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(keys_len)); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().reads_writes(keys_len, keys_len) + ); + for (_uid, key) in keys { - WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); IsNetworkMember::::remove(key, netuid); } - let count = Keys::::iter_prefix(netuid).count() as u64; - WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(count)); - let _ = Keys::::clear_prefix(netuid, u32::MAX, None); + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + Keys::::clear_prefix(netuid, 1024, None) + ); // --- 8. Iterate over stored weights and fill the matrix. for (uid_i, weights_i) in Weights::::iter_prefix(NetUidStorageIndex::ROOT) { + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1)); // Create a new vector to hold modified weights. let mut modified_weights = weights_i.clone(); for (subnet_id, weight) in modified_weights.iter_mut() { + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1)); // If the root network had a weight pointing to this netuid, set it to 0 if subnet_id == &u16::from(netuid) { WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); @@ -459,77 +457,80 @@ impl Pallet { LoadedEmission::::remove(netuid); // --- 19. DMAPs where netuid is the FIRST key: clear by prefix. - WeightMeterWrapper!( + LoopRemovePrefixWithWeightMeter!( weight_meter, - T::DbWeight::get().writes(BlockAtRegistration::::iter_prefix(netuid).count() as u64) + T::DbWeight::get().writes(1), + BlockAtRegistration::::clear_prefix(netuid, 1024, None) ); - let _ = BlockAtRegistration::::clear_prefix(netuid, u32::MAX, None); - WeightMeterWrapper!( + LoopRemovePrefixWithWeightMeter!( weight_meter, - T::DbWeight::get().writes(Axons::::iter_prefix(netuid).count() as u64) + T::DbWeight::get().writes(1), + Axons::::clear_prefix(netuid, 1024, None) ); - let _ = Axons::::clear_prefix(netuid, u32::MAX, None); - WeightMeterWrapper!( + LoopRemovePrefixWithWeightMeter!( weight_meter, - T::DbWeight::get().writes(NeuronCertificates::::iter_prefix(netuid).count() as u64) + T::DbWeight::get().writes(1), + Prometheus::::clear_prefix(netuid, 1024, None) ); - let _ = NeuronCertificates::::clear_prefix(netuid, u32::MAX, None); - WeightMeterWrapper!( + LoopRemovePrefixWithWeightMeter!( weight_meter, - T::DbWeight::get().writes(Prometheus::::iter_prefix(netuid).count() as u64) + T::DbWeight::get().writes(1), + AlphaDividendsPerSubnet::::clear_prefix(netuid, 1024, None) ); - let _ = Prometheus::::clear_prefix(netuid, u32::MAX, None); - WeightMeterWrapper!( + LoopRemovePrefixWithWeightMeter!( weight_meter, - T::DbWeight::get() - .writes(AlphaDividendsPerSubnet::::iter_prefix(netuid).count() as u64) + T::DbWeight::get().writes(1), + PendingChildKeys::::clear_prefix(netuid, 1024, None) ); - let _ = AlphaDividendsPerSubnet::::clear_prefix(netuid, u32::MAX, None); - WeightMeterWrapper!( + LoopRemovePrefixWithWeightMeter!( weight_meter, - T::DbWeight::get().writes(PendingChildKeys::::iter_prefix(netuid).count() as u64) + T::DbWeight::get().writes(1), + AssociatedEvmAddress::::clear_prefix(netuid, 1024, None) ); - let _ = PendingChildKeys::::clear_prefix(netuid, u32::MAX, None); - WeightMeterWrapper!( - weight_meter, - T::DbWeight::get() - .writes(AssociatedEvmAddress::::iter_prefix(netuid).count() as u64) - ); - let _ = AssociatedEvmAddress::::clear_prefix(netuid, u32::MAX, None); // Commit-reveal / weights commits (all per-net prefixes): + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1)); let mechanisms: u8 = MechanismCountCurrent::::get(netuid).into(); + + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(mechanisms as u64)); for subid in 0..mechanisms { + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1)); let netuid_index = Self::get_mechanism_storage_index(netuid, subid.into()); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); LastUpdate::::remove(netuid_index); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); Incentive::::remove(netuid_index); - WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); - WeightMeterWrapper!( + + LoopRemovePrefixWithWeightMeter!( weight_meter, - T::DbWeight::get() - .writes(WeightCommits::::iter_prefix(netuid_index).count() as u64) + T::DbWeight::get().writes(1), + WeightCommits::::clear_prefix(netuid_index, 1024, None) ); - let _ = WeightCommits::::clear_prefix(netuid_index, u32::MAX, None); - let _ = TimelockedWeightCommits::::clear_prefix(netuid_index, u32::MAX, None); - WeightMeterWrapper!( + LoopRemovePrefixWithWeightMeter!( weight_meter, - T::DbWeight::get() - .writes(CRV3WeightCommits::::iter_prefix(netuid_index).count() as u64) + T::DbWeight::get().writes(1), + TimelockedWeightCommits::::clear_prefix(netuid_index, 1024, None) ); - let _ = CRV3WeightCommits::::clear_prefix(netuid_index, u32::MAX, None); - WeightMeterWrapper!( + + LoopRemovePrefixWithWeightMeter!( weight_meter, - T::DbWeight::get() - .writes(CRV3WeightCommitsV2::::iter_prefix(netuid_index).count() as u64) + T::DbWeight::get().writes(1), + CRV3WeightCommits::::clear_prefix(netuid_index, 1024, None) ); - let _ = CRV3WeightCommitsV2::::clear_prefix(netuid_index, u32::MAX, None); - WeightMeterWrapper!( + + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + CRV3WeightCommitsV2::::clear_prefix(netuid_index, 1024, None) + ); + + LoopRemovePrefixWithWeightMeter!( weight_meter, - T::DbWeight::get().writes(Weights::::iter_prefix(netuid_index).count() as u64) + T::DbWeight::get().writes(1), + Weights::::clear_prefix(netuid_index, 1024, None) ); - let _ = Weights::::clear_prefix(netuid_index, u32::MAX, None); } WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); @@ -540,12 +541,11 @@ impl Pallet { MechanismEmissionSplit::::remove(netuid); // Last hotkey swap (DMAP where netuid is FIRST key → easy) - WeightMeterWrapper!( + LoopRemovePrefixWithWeightMeter!( weight_meter, - T::DbWeight::get() - .writes(LastHotkeySwapOnNetuid::::iter_prefix(netuid).count() as u64) + T::DbWeight::get().writes(1), + LastHotkeySwapOnNetuid::::clear_prefix(netuid, 1024, None) ); - let _ = LastHotkeySwapOnNetuid::::clear_prefix(netuid, u32::MAX, None); // --- 20. Identity maps across versions (netuid-scoped). if SubnetIdentitiesV3::::contains_key(netuid) { @@ -566,7 +566,10 @@ impl Pallet { }) .map(|(hot, _, _)| hot) .collect(); - WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(read_count)); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().reads_writes(read_count, read_count) + ); for hot in to_rm { WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); ChildkeyTake::::remove(&hot, netuid); diff --git a/pallets/swap/src/pallet/impls.rs b/pallets/swap/src/pallet/impls.rs index 9e6640303a..d9db04d650 100644 --- a/pallets/swap/src/pallet/impls.rs +++ b/pallets/swap/src/pallet/impls.rs @@ -437,23 +437,10 @@ impl SwapHandler for Pallet { Self::adjust_protocol_liquidity(netuid, tao_delta, alpha_delta) } - // fn is_user_liquidity_enabled(netuid: NetUid) -> bool { - // EnabledUserLiquidity::::get(netuid) - // } - - // fn dissolve_all_liquidity_providers( - // netuid: NetUid, - // remaining_weight: Option, - // ) -> Weight { - // Self::do_dissolve_all_liquidity_providers(netuid, remaining_weight) - // } - - // fn toggle_user_liquidity(netuid: NetUid, enabled: bool) { - // EnabledUserLiquidity::::insert(netuid, enabled) - // } fn clear_protocol_liquidity(netuid: NetUid, remaining_weight: Weight) -> Weight { Self::do_clear_protocol_liquidity(netuid, remaining_weight) } + fn init_swap(netuid: NetUid, maybe_price: Option) { Self::maybe_initialize_palswap(netuid, maybe_price).unwrap_or_default(); } From 50cd88ca7f6a275c47ef273741167b3ce6a50094 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 16 Feb 2026 18:21:44 +0800 Subject: [PATCH 18/40] add unit test for macro --- common/src/lib.rs | 83 +++++++++++++++++++++ pallets/subtensor/src/staking/claim_root.rs | 7 +- 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/common/src/lib.rs b/common/src/lib.rs index ec81a874ca..1a94118a5c 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -455,20 +455,103 @@ macro_rules! LoopRemovePrefixWithWeightMeter { return $meter.consumed(); } let result = $body; + $meter.consume($weight * result.backend as u64); if result.maybe_cursor.is_none() { break; } } + $meter.consumed() }}; } #[cfg(test)] mod tests { use super::*; + use frame_support::weights::WeightMeter; + + struct TestBody { + count: u64, + } + + struct TestResult { + backend: u64, + maybe_cursor: Option<()>, + } + + impl TestBody { + fn new(count: u64) -> Self { + Self { count: count } + } + + fn execute(&mut self, number: u64) -> TestResult { + if self.count >= number { + self.count -= number; + TestResult { + backend: number, + maybe_cursor: Some(()), + } + } else { + let tmp = self.count; + self.count = 0; + TestResult { + backend: tmp, + maybe_cursor: None, + } + } + } + } #[test] fn netuid_has_u16_bin_repr() { assert_eq!(NetUid(5).encode(), 5u16.encode()); } + + fn test_weight(remaining_weight: Weight, weight: Weight) -> Weight { + let mut weight_meter = WeightMeter::with_limit(remaining_weight); + WeightMeterWrapper!(weight_meter, weight); + weight_meter.consumed() + } + + fn test_loop( + remaining_weight: Weight, + weight: Weight, + mut body: TestBody, + number: u64, + ) -> Weight { + let mut weight_meter = WeightMeter::with_limit(remaining_weight); + LoopRemovePrefixWithWeightMeter!(weight_meter, weight, body.execute(number)); + weight_meter.consumed() + } + + #[test] + fn test_weight_meter_wrapper() { + let remaining_weight = Weight::from_parts(200, 200); + let used_weight = test_weight(remaining_weight, Weight::from_parts(100, 100)); + assert_eq!(used_weight, Weight::from_parts(100, 100)); + + let used_weight = test_weight(remaining_weight, Weight::from_parts(300, 300)); + assert_eq!(used_weight, Weight::from_parts(0, 0)); + } + + #[test] + fn test_loop_remove_prefix_with_weight_meter() { + // remaining weight matches the body count + let body = TestBody::new(1024); + let remaining_weight = Weight::from_parts(100 * 1024, 100 * 1024); + let used_weight = test_loop(remaining_weight, Weight::from_parts(100, 100), body, 1024); + assert_eq!(used_weight, Weight::from_parts(100, 100) * 1024); + + // remaining weight is less than the body count + let body = TestBody::new(1025); + let remaining_weight = Weight::from_parts(100 * 1024, 100 * 1024); + let used_weight = test_loop(remaining_weight, Weight::from_parts(100, 100), body, 1024); + assert_eq!(used_weight, Weight::from_parts(100, 100) * 1024); + + // remaining weight is more than the body count + let body = TestBody::new(1025); + let remaining_weight = Weight::from_parts(100 * 1024 * 2, 100 * 1024 * 2); + let used_weight = test_loop(remaining_weight, Weight::from_parts(100, 100), body, 1024); + assert_eq!(used_weight, Weight::from_parts(100, 100) * 1025); + } } diff --git a/pallets/subtensor/src/staking/claim_root.rs b/pallets/subtensor/src/staking/claim_root.rs index 24a55163f8..4e84a58626 100644 --- a/pallets/subtensor/src/staking/claim_root.rs +++ b/pallets/subtensor/src/staking/claim_root.rs @@ -406,8 +406,11 @@ impl Pallet { WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1)); } - WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); - let _ = RootClaimed::::clear_prefix((netuid,), u32::MAX, None); + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + RootClaimed::::clear_prefix((netuid,), u32::MAX, None) + ); weight_meter.consumed() } } From 2dc8630c189c5715ca6709d5d5b28c17b5cca71a Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 16 Feb 2026 18:41:49 +0800 Subject: [PATCH 19/40] cargo clippy --- common/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/lib.rs b/common/src/lib.rs index 1a94118a5c..3e8e56550a 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -481,12 +481,12 @@ mod tests { impl TestBody { fn new(count: u64) -> Self { - Self { count: count } + Self { count } } fn execute(&mut self, number: u64) -> TestResult { if self.count >= number { - self.count -= number; + self.count = self.count.saturating_sub(number); TestResult { backend: number, maybe_cursor: Some(()), From f3eb5bdf4d3c81e8336374c527170313b9099226 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 16 Feb 2026 18:42:57 +0800 Subject: [PATCH 20/40] commit Cargo.lock --- common/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/lib.rs b/common/src/lib.rs index 3e8e56550a..2d991fffdf 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -451,12 +451,12 @@ macro_rules! WeightMeterWrapper { macro_rules! LoopRemovePrefixWithWeightMeter { ( $meter:expr, $weight:expr, $body:expr ) => {{ loop { - if !$meter.can_consume($weight * 1024) { + if !$meter.can_consume($weight.saturating_mul(1024)) { return $meter.consumed(); } let result = $body; - $meter.consume($weight * result.backend as u64); + $meter.consume($weight.saturating_mul(result.backend as u64)); if result.maybe_cursor.is_none() { break; } From cc033e6f1fa81eb1f5b43e94c94c6486ba81dd7c Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 16 Feb 2026 19:49:55 +0800 Subject: [PATCH 21/40] exclude the dissolved network id when registration --- pallets/subtensor/src/subnets/subnet.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index 86462dd06d..4500bea3a9 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -53,6 +53,10 @@ impl Pallet { let mut next_netuid = NetUid::from(1); // do not allow creation of root let netuids = Self::get_all_subnet_netuids(); loop { + if DissolvedNetworks::::get().contains(&next_netuid) { + next_netuid = next_netuid.next(); + continue; + } if !netuids.contains(&next_netuid) { break next_netuid; } From 8f2add81cf43c008bceff00f86aef196be352079 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 16 Feb 2026 22:07:21 +0800 Subject: [PATCH 22/40] fix unit test --- pallets/subtensor/src/coinbase/root.rs | 13 +++++-------- pallets/subtensor/src/staking/claim_root.rs | 7 ++++++- pallets/subtensor/src/tests/claim_root.rs | 14 ++++++++++---- pallets/subtensor/src/tests/mock.rs | 9 +++++++++ 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index a0d7fa55f7..4d3afb21c9 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -215,9 +215,12 @@ impl Pallet { Error::::NetworkAlreadyDissolved ); - // Just remove the network from the added networks. + // Just remove the network from the added networks, it is used to check if the network is existed. NetworksAdded::::remove(netuid); + // Reduce the total networks count. TotalNetworks::::mutate(|n: &mut u16| *n = n.saturating_sub(1)); + // Remove the network owner, to avoid a lots of owner only extrinsics. + SubnetOwner::::remove(netuid); dissolved_networks.push(netuid); DissolvedNetworks::::set(dissolved_networks); @@ -233,10 +236,6 @@ impl Pallet { pub fn remove_network(netuid: NetUid, remaining_weight: Weight) -> Weight { let mut weight_meter = WeightMeter::with_limit(remaining_weight); - // --- 1. Get the owner and remove from SubnetOwner. - WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1)); - let owner_coldkey: T::AccountId = SubnetOwner::::get(netuid); - WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SubnetOwner::::remove(netuid); @@ -693,9 +692,7 @@ impl Pallet { } // --- Final removal logging. - log::debug!( - "remove_network: netuid={netuid}, owner={owner_coldkey:?} removed successfully" - ); + log::debug!("remove_network: netuid={netuid} removed successfully"); weight_meter.consumed() } diff --git a/pallets/subtensor/src/staking/claim_root.rs b/pallets/subtensor/src/staking/claim_root.rs index 4e84a58626..06962657ac 100644 --- a/pallets/subtensor/src/staking/claim_root.rs +++ b/pallets/subtensor/src/staking/claim_root.rs @@ -132,6 +132,10 @@ impl Pallet { root_claim_type: RootClaimTypeEnum, ignore_minimum_condition: bool, ) { + if DissolvedNetworks::::get().contains(&netuid) { + log::debug!("root claim on subnet {netuid} is skipped, network is dissolved"); + return; // no-op + } // Subtract the root claimed. let owed: I96F32 = Self::get_root_owed_for_hotkey_coldkey_float(hotkey, coldkey, netuid); @@ -393,6 +397,7 @@ impl Pallet { pub fn finalize_all_subnet_root_dividends(netuid: NetUid, remaining_weight: Weight) -> Weight { let mut weight_meter = WeightMeter::with_limit(remaining_weight); WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1)); + // Iterate directly without collecting to avoid unnecessary allocation for hotkey in RootClaimable::::iter_keys() { WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1)); @@ -409,7 +414,7 @@ impl Pallet { LoopRemovePrefixWithWeightMeter!( weight_meter, T::DbWeight::get().writes(1), - RootClaimed::::clear_prefix((netuid,), u32::MAX, None) + RootClaimed::::clear_prefix((netuid,), 1024, None) ); weight_meter.consumed() } diff --git a/pallets/subtensor/src/tests/claim_root.rs b/pallets/subtensor/src/tests/claim_root.rs index 9d08c65e3c..6157e36e98 100644 --- a/pallets/subtensor/src/tests/claim_root.rs +++ b/pallets/subtensor/src/tests/claim_root.rs @@ -1,14 +1,16 @@ #![allow(clippy::expect_used)] +use super::mock::run_block_idle; use crate::RootAlphaDividendsPerSubnet; use crate::tests::mock::{ RuntimeOrigin, SubtensorModule, Test, add_dynamic_network, new_test_ext, run_to_block, }; use crate::{ - DefaultMinRootClaimAmount, Error, MAX_NUM_ROOT_CLAIMS, MAX_ROOT_CLAIM_THRESHOLD, NetworksAdded, - NumRootClaim, NumStakingColdkeys, PendingRootAlphaDivs, RootClaimable, RootClaimableThreshold, - StakingColdkeys, StakingColdkeysByIndex, SubnetAlphaIn, SubnetMechanism, SubnetMovingPrice, - SubnetTAO, SubnetTaoFlow, SubtokenEnabled, Tempo, pallet, + DefaultMinRootClaimAmount, DissolvedNetworks, Error, MAX_NUM_ROOT_CLAIMS, + MAX_ROOT_CLAIM_THRESHOLD, NetworksAdded, NumRootClaim, NumStakingColdkeys, + PendingRootAlphaDivs, RootClaimable, RootClaimableThreshold, StakingColdkeys, + StakingColdkeysByIndex, SubnetAlphaIn, SubnetMechanism, SubnetMovingPrice, SubnetTAO, + SubnetTaoFlow, SubtokenEnabled, Tempo, pallet, }; use crate::{RootClaimType, RootClaimTypeEnum, RootClaimed}; use approx::assert_abs_diff_eq; @@ -1387,6 +1389,10 @@ fn test_claim_root_on_network_deregistration() { assert_ok!(SubtensorModule::do_dissolve_network(netuid)); + DissolvedNetworks::::set(vec![netuid]); + + run_block_idle(); + assert!(!RootClaimed::::contains_key(( netuid, &hotkey, &coldkey, ))); diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 36f6d9766b..97fd0de9b8 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -5,6 +5,7 @@ )] use core::num::NonZeroU64; +use std::u64; use crate::utils::rate_limiting::TransactionType; use crate::*; @@ -688,6 +689,14 @@ pub(crate) fn run_to_block_ext(n: u64, enable_events: bool) { } } +#[allow(dead_code)] +pub(crate) fn run_block_idle() { + SubtensorModule::on_idle( + System::block_number(), + Weight::from_parts(u64::MAX, u64::MAX), + ); +} + #[allow(dead_code)] pub(crate) fn next_block_no_epoch(netuid: NetUid) -> u64 { // high tempo to skip automatic epochs in on_initialize From cbc441b8ce69d5a9ac721013790b1eaed45b018f Mon Sep 17 00:00:00 2001 From: open-junius Date: Wed, 25 Feb 2026 17:53:15 +0800 Subject: [PATCH 23/40] fix unit test --- pallets/subtensor/src/coinbase/root.rs | 2 -- pallets/subtensor/src/tests/networks.rs | 8 ++++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index 4d3afb21c9..a803f4e9a7 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -219,8 +219,6 @@ impl Pallet { NetworksAdded::::remove(netuid); // Reduce the total networks count. TotalNetworks::::mutate(|n: &mut u16| *n = n.saturating_sub(1)); - // Remove the network owner, to avoid a lots of owner only extrinsics. - SubnetOwner::::remove(netuid); dissolved_networks.push(netuid); DissolvedNetworks::::set(dissolved_networks); diff --git a/pallets/subtensor/src/tests/networks.rs b/pallets/subtensor/src/tests/networks.rs index 02c7aef628..9eee3dee84 100644 --- a/pallets/subtensor/src/tests/networks.rs +++ b/pallets/subtensor/src/tests/networks.rs @@ -90,6 +90,7 @@ fn dissolve_refunds_full_lock_cost_when_no_emission() { let before = SubtensorModule::get_coldkey_balance(&cold); assert_ok!(SubtensorModule::do_dissolve_network(net)); + run_block_idle(); let after = SubtensorModule::get_coldkey_balance(&cold); assert_eq!(TaoCurrency::from(after), TaoCurrency::from(before) + lock); @@ -119,6 +120,7 @@ fn dissolve_single_alpha_out_staker_gets_all_tao() { // Dissolve assert_ok!(SubtensorModule::do_dissolve_network(net)); + run_block_idle(); // Cold-key received full pot let after = SubtensorModule::get_coldkey_balance(&s_cold); @@ -190,6 +192,7 @@ fn dissolve_two_stakers_pro_rata_distribution() { // Dissolve assert_ok!(SubtensorModule::do_dissolve_network(net)); + run_block_idle(); // Cold-keys received their τ shares assert_eq!( @@ -267,6 +270,7 @@ fn dissolve_owner_cut_refund_logic() { let before = SubtensorModule::get_coldkey_balance(&oc); assert_ok!(SubtensorModule::do_dissolve_network(net)); + run_block_idle(); let after = SubtensorModule::get_coldkey_balance(&oc); assert!(after > before); // some refund is expected @@ -460,6 +464,7 @@ fn dissolve_clears_all_per_subnet_storages() { // Dissolve // ------------------------------------------------------------------ assert_ok!(SubtensorModule::do_dissolve_network(net)); + run_block_idle(); // ------------------------------------------------------------------ // Items that must be COMPLETELY REMOVED @@ -647,6 +652,7 @@ fn dissolve_alpha_out_but_zero_tao_no_rewards() { let before = SubtensorModule::get_coldkey_balance(&sc); assert_ok!(SubtensorModule::do_dissolve_network(net)); + run_block_idle(); let after = SubtensorModule::get_coldkey_balance(&sc); // No reward distributed, α-out cleared. @@ -698,6 +704,7 @@ fn dissolve_rounding_remainder_distribution() { // 3. Run full dissolve flow assert_ok!(SubtensorModule::do_dissolve_network(net)); + run_block_idle(); // 4. s1 (larger remainder) should get +1 τ on cold-key let c1_after = SubtensorModule::get_coldkey_balance(&s1c); @@ -1858,6 +1865,7 @@ fn dissolve_clears_all_mechanism_scoped_maps_for_all_mechanisms() { // --- Dissolve the subnet --- assert_ok!(SubtensorModule::do_dissolve_network(net)); + run_block_idle(); // After dissolve, ALL mechanism-scoped items must be cleared for ALL mechanisms. From 21d8e4f48ae998c901e1983d7f6da25d2a2adfe8 Mon Sep 17 00:00:00 2001 From: open-junius Date: Wed, 25 Feb 2026 17:54:14 +0800 Subject: [PATCH 24/40] fix clippy --- pallets/subtensor/src/tests/mock.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 3b4e09c021..79376c8ca7 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -5,7 +5,6 @@ )] use core::num::NonZeroU64; -use std::u64; use crate::utils::rate_limiting::TransactionType; use crate::*; From f2ed907608f4e3152a1b15925498a9a19a72baf9 Mon Sep 17 00:00:00 2001 From: open-junius Date: Wed, 25 Feb 2026 18:09:44 +0800 Subject: [PATCH 25/40] reduce benchmark for dissolve_network --- pallets/subtensor/src/benchmarks.rs | 31 ----------------------------- 1 file changed, 31 deletions(-) diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index e11159fc88..3febd7d2ce 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -1797,41 +1797,10 @@ mod pallet_benchmarks { // Initialize network Subtensor::::init_new_network(netuid, tempo); - SubtokenEnabled::::insert(netuid, true); - Subtensor::::set_max_allowed_uids(netuid, 256); - Subtensor::::set_network_registration_allowed(netuid, true); - Subtensor::::set_burn(netuid, 1.into()); // Set network owner SubnetOwner::::insert(netuid, coldkey.clone()); - Subtensor::::set_max_registrations_per_block(netuid, 64); - - Subtensor::::set_target_registrations_per_interval(netuid, 64); - - // Add some registrations to make the benchmark realistic - let mut seed: u32 = 2; - for _ in 0..64 { - let hotkey: T::AccountId = account("Hotkey", 0, seed); - let coldkey: T::AccountId = account("Coldkey", 0, seed); - seed += 1; - - let amount_to_be_staked: u64 = 1_000_000; - Subtensor::::add_balance_to_coldkey_account(&coldkey, amount_to_be_staked); - - assert_ok!(Subtensor::::do_burned_registration( - RawOrigin::Signed(coldkey.clone()).into(), - netuid, - hotkey.clone() - )); - } - - // Add some network reserves to make it more realistic - let tao_reserve = TaoCurrency::from(10_000_000_000); - let alpha_in = AlphaCurrency::from(5_000_000_000); - SubnetTAO::::insert(netuid, tao_reserve); - SubnetAlphaIn::::insert(netuid, alpha_in); - #[extrinsic_call] _(RawOrigin::Root, coldkey.clone(), netuid); } From d489382fe456854f38fc88fc401f6e58e5ad7c99 Mon Sep 17 00:00:00 2001 From: open-junius Date: Wed, 25 Feb 2026 18:27:07 +0800 Subject: [PATCH 26/40] fix unit test --- pallets/subtensor/src/coinbase/root.rs | 2 ++ pallets/subtensor/src/staking/remove_stake.rs | 6 +----- scripts/benchmark.sh | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index a803f4e9a7..e238ab8faa 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -215,6 +215,8 @@ impl Pallet { Error::::NetworkAlreadyDissolved ); + // TODO Most of data cleanup is done in the block hook, should we charge the user for this? + // Just remove the network from the added networks, it is used to check if the network is existed. NetworksAdded::::remove(netuid); // Reduce the total networks count. diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs index dd855d51f0..3e902a1d17 100644 --- a/pallets/subtensor/src/staking/remove_stake.rs +++ b/pallets/subtensor/src/staking/remove_stake.rs @@ -435,11 +435,7 @@ impl Pallet { } pub fn destroy_alpha_in_out_stakes(netuid: NetUid, remaining_weight: Weight) -> Weight { - // 1) Ensure the subnet exists. - if !Self::if_subnet_exist(netuid) { - return Weight::from_parts(0, 0); - } - + // 1) Initialize the weight meter from the remaining weight. let mut meter_weight = WeightMeter::with_limit(remaining_weight); // 2) Owner / lock cost. diff --git a/scripts/benchmark.sh b/scripts/benchmark.sh index 4a1c99a62c..d82a9a5a1f 100755 --- a/scripts/benchmark.sh +++ b/scripts/benchmark.sh @@ -16,6 +16,6 @@ RUNTIME_WASM=./target/production/wbuild/node-subtensor-runtime/node_subtensor_ru --genesis-builder-preset=benchmark \ --wasm-execution=compiled \ --pallet=pallet_subtensor \ - --extrinsic="$EXTRINSIC" \ + --extrinsic="$dissolve_network" \ --steps 50 \ --repeat 5 \ From aabec8c6e8d8de4a046ca0843020953451c8fb26 Mon Sep 17 00:00:00 2001 From: open-junius Date: Wed, 25 Feb 2026 19:24:13 +0800 Subject: [PATCH 27/40] update purge netuid in mock --- pallets/subtensor/src/tests/mock.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 79376c8ca7..5e14aec0dd 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -343,8 +343,8 @@ impl PrivilegeCmp for OriginPrivilegeCmp { pub struct CommitmentsI; impl CommitmentsInterface for CommitmentsI { - fn purge_netuid(_netuid: NetUid, remaining_weight: Weight) -> Weight { - remaining_weight + fn purge_netuid(_netuid: NetUid, _remaining_weight: Weight) -> Weight { + Weight::from(0) } } From 06f5cdc76de98f949e37c01ddb314263857d0936 Mon Sep 17 00:00:00 2001 From: open-junius Date: Wed, 25 Feb 2026 19:31:02 +0800 Subject: [PATCH 28/40] fix bug, missed bonds removal --- pallets/subtensor/src/coinbase/root.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index e238ab8faa..9253157bd4 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -525,6 +525,12 @@ impl Pallet { CRV3WeightCommitsV2::::clear_prefix(netuid_index, 1024, None) ); + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + Bonds::::clear_prefix(netuid_index, 1024, None) + ); + LoopRemovePrefixWithWeightMeter!( weight_meter, T::DbWeight::get().writes(1), From 203628c3d00ec5d846902e56ead386454fd026e0 Mon Sep 17 00:00:00 2001 From: open-junius Date: Wed, 25 Feb 2026 21:56:31 +0800 Subject: [PATCH 29/40] correct weights for dissolve network --- pallets/subtensor/src/macros/dispatches.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 6330e07d1c..14b7828ac1 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1243,8 +1243,8 @@ mod dispatches { /// The caller must be the owner of the network #[pallet::call_index(61)] #[pallet::weight(Weight::from_parts(119_000_000, 0) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(31)))] + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)))] pub fn dissolve_network( origin: OriginFor, _coldkey: T::AccountId, From 984f14cdfb2133203c8263dbd8c0f43ba84d82a9 Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 26 Feb 2026 22:13:02 +0800 Subject: [PATCH 30/40] fix benchmark --- pallets/subtensor/src/macros/dispatches.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 14b7828ac1..48cad8b2a7 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1242,7 +1242,7 @@ mod dispatches { /// Remove a user's subnetwork /// The caller must be the owner of the network #[pallet::call_index(61)] - #[pallet::weight(Weight::from_parts(119_000_000, 0) + #[pallet::weight(Weight::from_parts(28_560_000, 0) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)))] pub fn dissolve_network( From 936181397eb345a3af35c7608777db0716cd7fe6 Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 26 Feb 2026 22:41:33 +0800 Subject: [PATCH 31/40] commit Cargo.lock --- pallets/swap/src/pallet/tests.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/pallets/swap/src/pallet/tests.rs b/pallets/swap/src/pallet/tests.rs index 36f537a5b3..6e931b95bf 100644 --- a/pallets/swap/src/pallet/tests.rs +++ b/pallets/swap/src/pallet/tests.rs @@ -2001,7 +2001,10 @@ fn test_liquidate_v3_removes_positions_ticks_and_state() { // ACT: users-only liquidation then protocol clear assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); - assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + Pallet::::do_clear_protocol_liquidity( + netuid, + Weight::from_parts(u64::Max, U64F64::MAX) + ); // ASSERT: positions cleared (both user and protocol) assert_eq!( @@ -2086,7 +2089,7 @@ fn test_liquidate_v3_removes_positions_ticks_and_state() { // // Users-only dissolve, then clear protocol liquidity/state. // assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); -// assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); +// Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::Max, U64F64::MAX))); // // ASSERT: positions & ticks gone, state reset // assert_eq!( @@ -2188,8 +2191,8 @@ fn test_liquidate_idempotent() { assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); // Now clear protocol liquidity/state—also idempotent. - assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); - assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::Max, U64F64::MAX))); + Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::Max, U64F64::MAX))); // State remains empty assert!( @@ -2297,7 +2300,7 @@ fn liquidate_v3_refunds_user_funds_and_clears_state() { ); // Clear protocol liquidity and V3 state now. - assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::Max, U64F64::MAX))); // User position(s) are gone and all V3 state cleared. assert_eq!(Pallet::::count_positions(netuid, &cold), 0); @@ -2359,7 +2362,7 @@ fn refund_alpha_single_provider_exact() { ); // Clear protocol liquidity and V3 state now. - assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::Max, U64F64::MAX))); // --- State is cleared. assert!(Ticks::::iter_prefix(netuid).next().is_none()); @@ -2629,7 +2632,7 @@ fn test_dissolve_v3_green_path_refund_tao_stake_alpha_and_clear_state() { } // Now clear protocol liquidity & state and assert full reset. - assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::Max, U64F64::MAX))); let protocol_id = Pallet::::protocol_account_id(); assert_eq!(Pallet::::count_positions(netuid, &cold), 0); From 694b833a8f3ceea87766872086a81bbf27f55a5a Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 26 Feb 2026 22:42:46 +0800 Subject: [PATCH 32/40] commit Cargo.lock --- pallets/swap/src/pallet/tests.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pallets/swap/src/pallet/tests.rs b/pallets/swap/src/pallet/tests.rs index 6e931b95bf..84108ced02 100644 --- a/pallets/swap/src/pallet/tests.rs +++ b/pallets/swap/src/pallet/tests.rs @@ -2191,8 +2191,7 @@ fn test_liquidate_idempotent() { assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); // Now clear protocol liquidity/state—also idempotent. - Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::Max, U64F64::MAX))); - Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::Max, U64F64::MAX))); + Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::Max, U64F64::MAX)); // State remains empty assert!( @@ -2300,7 +2299,7 @@ fn liquidate_v3_refunds_user_funds_and_clears_state() { ); // Clear protocol liquidity and V3 state now. - Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::Max, U64F64::MAX))); + Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::Max, U64F64::MAX)); // User position(s) are gone and all V3 state cleared. assert_eq!(Pallet::::count_positions(netuid, &cold), 0); From ed7b2e335bca997f64a51e01df29ba1e34a5798e Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 26 Feb 2026 22:45:23 +0800 Subject: [PATCH 33/40] commit Cargo.lock --- pallets/swap/src/pallet/tests.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pallets/swap/src/pallet/tests.rs b/pallets/swap/src/pallet/tests.rs index 84108ced02..9de8aa87c4 100644 --- a/pallets/swap/src/pallet/tests.rs +++ b/pallets/swap/src/pallet/tests.rs @@ -2001,10 +2001,7 @@ fn test_liquidate_v3_removes_positions_ticks_and_state() { // ACT: users-only liquidation then protocol clear assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); - Pallet::::do_clear_protocol_liquidity( - netuid, - Weight::from_parts(u64::Max, U64F64::MAX) - ); + Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::MAX, u64::MAX)); // ASSERT: positions cleared (both user and protocol) assert_eq!( @@ -2089,7 +2086,7 @@ fn test_liquidate_v3_removes_positions_ticks_and_state() { // // Users-only dissolve, then clear protocol liquidity/state. // assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); -// Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::Max, U64F64::MAX))); +// Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::MAX, u64::MAX))); // // ASSERT: positions & ticks gone, state reset // assert_eq!( @@ -2191,7 +2188,7 @@ fn test_liquidate_idempotent() { assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); // Now clear protocol liquidity/state—also idempotent. - Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::Max, U64F64::MAX)); + Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::MAX, u64::MAX)); // State remains empty assert!( @@ -2299,7 +2296,7 @@ fn liquidate_v3_refunds_user_funds_and_clears_state() { ); // Clear protocol liquidity and V3 state now. - Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::Max, U64F64::MAX)); + Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::MAX, u64::MAX)); // User position(s) are gone and all V3 state cleared. assert_eq!(Pallet::::count_positions(netuid, &cold), 0); @@ -2361,7 +2358,10 @@ fn refund_alpha_single_provider_exact() { ); // Clear protocol liquidity and V3 state now. - Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::Max, U64F64::MAX))); + Pallet::::do_clear_protocol_liquidity( + netuid, + Weight::from_parts(u64::MAX, U64F64::MAX), + ); // --- State is cleared. assert!(Ticks::::iter_prefix(netuid).next().is_none()); @@ -2631,7 +2631,7 @@ fn test_dissolve_v3_green_path_refund_tao_stake_alpha_and_clear_state() { } // Now clear protocol liquidity & state and assert full reset. - Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::Max, U64F64::MAX))); + Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::MAX, u64::MAX)); let protocol_id = Pallet::::protocol_account_id(); assert_eq!(Pallet::::count_positions(netuid, &cold), 0); From 951d04ab54008d7196b9d2c3881d886eb9c6c8af Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 26 Feb 2026 22:50:37 +0800 Subject: [PATCH 34/40] commit Cargo.lock --- pallets/swap/src/pallet/tests.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pallets/swap/src/pallet/tests.rs b/pallets/swap/src/pallet/tests.rs index 9de8aa87c4..1ca5881726 100644 --- a/pallets/swap/src/pallet/tests.rs +++ b/pallets/swap/src/pallet/tests.rs @@ -2358,10 +2358,7 @@ fn refund_alpha_single_provider_exact() { ); // Clear protocol liquidity and V3 state now. - Pallet::::do_clear_protocol_liquidity( - netuid, - Weight::from_parts(u64::MAX, U64F64::MAX), - ); + Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::MAX, u64::MAX)); // --- State is cleared. assert!(Ticks::::iter_prefix(netuid).next().is_none()); @@ -2731,7 +2728,6 @@ fn test_clear_protocol_liquidity_green_path() { assert!(!EnabledUserLiquidity::::contains_key(netuid)); // --- And it's idempotent --- - assert!(!PalSwapInitialized::::contains_key(netuid)); Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::MAX, u64::MAX)); assert!( From 453db3fb42ec1911f50a3c9c97a797ad1601795a Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 27 Feb 2026 00:31:14 +0800 Subject: [PATCH 35/40] fix unit test --- pallets/subtensor/src/tests/networks.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/pallets/subtensor/src/tests/networks.rs b/pallets/subtensor/src/tests/networks.rs index b13ed9e6d3..4923d83682 100644 --- a/pallets/subtensor/src/tests/networks.rs +++ b/pallets/subtensor/src/tests/networks.rs @@ -2045,6 +2045,7 @@ fn massive_dissolve_refund_and_reregistration_flow_is_lossless_and_cleans_state( for &net in nets.iter() { assert_ok!(SubtensorModule::do_dissolve_network(net)); } + run_block_idle(); // ──────────────────────────────────────────────────────────────────── // 7) Assertions: τ balances, α gone, nets removed, swap state clean From a8616726a0d12ad3da71d67b5fcd8f41dc33109c Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 27 Feb 2026 17:17:03 +0800 Subject: [PATCH 36/40] add subnet exist check in admin util --- pallets/admin-utils/src/lib.rs | 53 +++++++++++++++++++++++++ pallets/subtensor/src/tests/networks.rs | 53 +++++++++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 654f7207b8..86f5fbd166 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -655,6 +655,11 @@ pub mod pallet { registration_allowed: bool, ) -> DispatchResult { ensure_root(origin)?; + + ensure!( + pallet_subtensor::Pallet::::if_subnet_exist(netuid), + Error::::SubnetDoesNotExist + ); pallet_subtensor::Pallet::::set_network_registration_allowed( netuid, registration_allowed, @@ -1258,6 +1263,10 @@ pub mod pallet { netuid, &[Hyperparameter::LiquidAlphaEnabled.into()], )?; + ensure!( + pallet_subtensor::Pallet::::if_subnet_exist(netuid), + Error::::SubnetDoesNotExist + ); pallet_subtensor::Pallet::::ensure_admin_window_open(netuid)?; pallet_subtensor::Pallet::::set_liquid_alpha_enabled(netuid, enabled); log::debug!("LiquidAlphaEnableToggled( netuid: {netuid:?}, Enabled: {enabled:?} ) "); @@ -1285,6 +1294,10 @@ pub mod pallet { netuid, &[Hyperparameter::AlphaValues.into()], )?; + ensure!( + pallet_subtensor::Pallet::::if_subnet_exist(netuid), + Error::::SubnetDoesNotExist + ); pallet_subtensor::Pallet::::ensure_admin_window_open(netuid)?; let res = pallet_subtensor::Pallet::::do_set_alpha_values( origin, netuid, alpha_low, alpha_high, @@ -1458,6 +1471,10 @@ pub mod pallet { netuid, &[Hyperparameter::TransferEnabled.into()], )?; + ensure!( + pallet_subtensor::Pallet::::if_subnet_exist(netuid), + Error::::SubnetDoesNotExist + ); pallet_subtensor::Pallet::::ensure_admin_window_open(netuid)?; let res = pallet_subtensor::Pallet::::toggle_transfer(netuid, toggle); if res.is_ok() { @@ -1493,6 +1510,10 @@ pub mod pallet { netuid, &[Hyperparameter::RecycleOrBurn.into()], )?; + ensure!( + pallet_subtensor::Pallet::::if_subnet_exist(netuid), + Error::::SubnetDoesNotExist + ); pallet_subtensor::Pallet::::ensure_admin_window_open(netuid)?; pallet_subtensor::Pallet::::set_recycle_or_burn(netuid, recycle_or_burn); @@ -1604,6 +1625,10 @@ pub mod pallet { ema_halving: u64, ) -> DispatchResult { ensure_root(origin)?; + ensure!( + pallet_subtensor::Pallet::::if_subnet_exist(netuid), + Error::::SubnetDoesNotExist + ); pallet_subtensor::EMAPriceHalvingBlocks::::set(netuid, ema_halving); log::debug!( @@ -1688,6 +1713,10 @@ pub mod pallet { netuid, &[Hyperparameter::Yuma3Enabled.into()], )?; + ensure!( + pallet_subtensor::Pallet::::if_subnet_exist(netuid), + Error::::SubnetDoesNotExist + ); pallet_subtensor::Pallet::::ensure_admin_window_open(netuid)?; pallet_subtensor::Pallet::::set_yuma3_enabled(netuid, enabled); @@ -1724,6 +1753,10 @@ pub mod pallet { netuid, &[Hyperparameter::BondsResetEnabled.into()], )?; + ensure!( + pallet_subtensor::Pallet::::if_subnet_exist(netuid), + Error::::SubnetDoesNotExist + ); pallet_subtensor::Pallet::::ensure_admin_window_open(netuid)?; pallet_subtensor::Pallet::::set_bonds_reset(netuid, enabled); @@ -1839,6 +1872,10 @@ pub mod pallet { netuid, &[Hyperparameter::ImmuneNeuronLimit.into()], )?; + ensure!( + pallet_subtensor::Pallet::::if_subnet_exist(netuid), + Error::::SubnetDoesNotExist + ); pallet_subtensor::Pallet::::ensure_admin_window_open(netuid)?; pallet_subtensor::Pallet::::set_owner_immune_neuron_limit(netuid, immune_neurons)?; pallet_subtensor::Pallet::::record_owner_rl( @@ -1907,6 +1944,10 @@ pub mod pallet { netuid, &[TransactionType::MechanismCountUpdate], )?; + ensure!( + pallet_subtensor::Pallet::::if_subnet_exist(netuid), + Error::::SubnetDoesNotExist + ); pallet_subtensor::Pallet::::ensure_admin_window_open(netuid)?; pallet_subtensor::Pallet::::do_set_mechanism_count(netuid, mechanism_count)?; @@ -1934,6 +1975,10 @@ pub mod pallet { netuid, &[TransactionType::MechanismEmission], )?; + ensure!( + pallet_subtensor::Pallet::::if_subnet_exist(netuid), + Error::::SubnetDoesNotExist + ); pallet_subtensor::Pallet::::ensure_admin_window_open(netuid)?; pallet_subtensor::Pallet::::do_set_emission_split(netuid, maybe_split)?; @@ -1965,6 +2010,10 @@ pub mod pallet { netuid, &[TransactionType::MaxUidsTrimming], )?; + ensure!( + pallet_subtensor::Pallet::::if_subnet_exist(netuid), + Error::::SubnetDoesNotExist + ); pallet_subtensor::Pallet::::ensure_admin_window_open(netuid)?; pallet_subtensor::Pallet::::trim_to_max_allowed_uids(netuid, max_n)?; @@ -2090,6 +2139,10 @@ pub mod pallet { min: u16, ) -> DispatchResult { ensure_root(origin)?; + ensure!( + pallet_subtensor::Pallet::::if_subnet_exist(netuid), + Error::::SubnetDoesNotExist + ); pallet_subtensor::Pallet::::set_min_non_immune_uids(netuid, min); Ok(()) } diff --git a/pallets/subtensor/src/tests/networks.rs b/pallets/subtensor/src/tests/networks.rs index 4923d83682..0fe0df0331 100644 --- a/pallets/subtensor/src/tests/networks.rs +++ b/pallets/subtensor/src/tests/networks.rs @@ -66,6 +66,34 @@ fn dissolve_no_stakers_no_alpha_no_emission() { }); } +#[test] +fn dissolve_defers_cleanup_until_on_idle() { + new_test_ext(0).execute_with(|| { + let owner_cold = U256::from(11); + let owner_hot = U256::from(12); + let net = add_dynamic_network(&owner_hot, &owner_cold); + + assert!(SubnetOwner::::contains_key(net)); + assert!(NetworkRegisteredAt::::contains_key(net)); + assert!(!DissolvedNetworks::::get().contains(&net)); + + assert_ok!(SubtensorModule::do_dissolve_network(net)); + + // Network is no longer considered "existing" but data is not cleaned yet. + assert!(!SubtensorModule::if_subnet_exist(net)); + assert!(DissolvedNetworks::::get().contains(&net)); + assert!(SubnetOwner::::contains_key(net)); + assert!(NetworkRegisteredAt::::contains_key(net)); + + // Cleanup happens in on_idle. + run_block_idle(); + + assert!(!SubnetOwner::::contains_key(net)); + assert!(!NetworkRegisteredAt::::contains_key(net)); + assert!(!DissolvedNetworks::::get().contains(&net)); + }); +} + #[test] fn dissolve_refunds_full_lock_cost_when_no_emission() { new_test_ext(0).execute_with(|| { @@ -1424,6 +1452,31 @@ fn register_network_prunes_and_recycles_netuid() { }); } +#[test] +fn register_network_skips_dissolved_netuid() { + new_test_ext(0).execute_with(|| { + let dissolved = NetUid::from(1); + DissolvedNetworks::::put(vec![dissolved]); + + let cold = U256::from(60); + let hot = U256::from(61); + let needed: u64 = SubtensorModule::get_network_lock_cost().into(); + SubtensorModule::add_balance_to_coldkey_account(&cold, needed.saturating_mul(10)); + + assert_ok!(SubtensorModule::do_register_network( + RuntimeOrigin::signed(cold), + &hot, + 1, + None, + )); + + assert!(!NetworksAdded::::get(dissolved)); + let expected = NetUid::from(2); + assert!(NetworksAdded::::get(expected)); + assert_eq!(SubnetOwner::::get(expected), cold); + }); +} + #[test] fn register_network_fails_before_prune_keeps_existing() { new_test_ext(0).execute_with(|| { From b8eac0cc56bf17ac50aa7fc0cc30c32eab9ea146 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 2 Mar 2026 13:50:47 +0800 Subject: [PATCH 37/40] add netuid exist check --- runtime/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index c2aa1190d3..104415335c 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -959,7 +959,8 @@ pub struct AllowCommitments; impl CanCommit for AllowCommitments { #[cfg(not(feature = "runtime-benchmarks"))] fn can_commit(netuid: NetUid, address: &AccountId) -> bool { - SubtensorModule::is_hotkey_registered_on_network(netuid, address) + SubtensorModule::if_subnet_exist(netuid) + && SubtensorModule::is_hotkey_registered_on_network(netuid, address) } #[cfg(feature = "runtime-benchmarks")] From f40789660193c1de58f8497f9c54c8f817800a63 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 2 Mar 2026 15:17:21 +0800 Subject: [PATCH 38/40] check all clean up function --- pallets/subtensor/src/staking/claim_root.rs | 1 - pallets/subtensor/src/staking/remove_stake.rs | 8 +++- pallets/swap/src/pallet/impls.rs | 44 ++++++++++++++++--- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/pallets/subtensor/src/staking/claim_root.rs b/pallets/subtensor/src/staking/claim_root.rs index 06962657ac..a1a28f0242 100644 --- a/pallets/subtensor/src/staking/claim_root.rs +++ b/pallets/subtensor/src/staking/claim_root.rs @@ -396,7 +396,6 @@ impl Pallet { /// Claim all root dividends for subnet and remove all associated data. pub fn finalize_all_subnet_root_dividends(netuid: NetUid, remaining_weight: Weight) -> Weight { let mut weight_meter = WeightMeter::with_limit(remaining_weight); - WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1)); // Iterate directly without collecting to avoid unnecessary allocation for hotkey in RootClaimable::::iter_keys() { diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs index 95bc5420c2..1cac603a80 100644 --- a/pallets/subtensor/src/staking/remove_stake.rs +++ b/pallets/subtensor/src/staking/remove_stake.rs @@ -448,6 +448,7 @@ impl Pallet { WeightMeterWrapper!(meter_weight, T::DbWeight::get().reads(1)); let reg_at: u64 = NetworkRegisteredAt::::get(netuid); WeightMeterWrapper!(meter_weight, T::DbWeight::get().reads(1)); + let start_block: u64 = NetworkRegistrationStartBlock::::get(); let should_refund_owner: bool = reg_at < start_block; @@ -583,6 +584,7 @@ impl Pallet { // Credit each share directly to coldkey free balance. for p in portions { if p.share > 0 { + WeightMeterWrapper!(meter_weight, T::DbWeight::get().reads_writes(1, 1)); Self::add_balance_to_coldkey_account(&p.cold, p.share); } } @@ -591,6 +593,7 @@ impl Pallet { // 7) Destroy all α-in/α-out state for this subnet. // 7.a) Remove every (hot, cold, netuid) α entry. for (hot, cold) in keys_to_remove { + WeightMeterWrapper!(meter_weight, T::DbWeight::get().writes(1)); Alpha::::remove((hot, cold, netuid)); } // 7.b) Clear share‑pool totals for each hotkey on this subnet. @@ -623,7 +626,10 @@ impl Pallet { }; if !refund.is_zero() { - WeightMeterWrapper!(meter_weight, T::DbWeight::get().writes(1)); + WeightMeterWrapper!( + meter_weight, + T::DbWeight::get().reads(1) + T::DbWeight::get().writes(1) + ); Self::add_balance_to_coldkey_account(&owner_coldkey, refund.to_u64()); } diff --git a/pallets/swap/src/pallet/impls.rs b/pallets/swap/src/pallet/impls.rs index 4c0d3ed25d..e40578fcfb 100644 --- a/pallets/swap/src/pallet/impls.rs +++ b/pallets/swap/src/pallet/impls.rs @@ -20,7 +20,8 @@ use sp_arithmetic::helpers_128bit; use sp_runtime::{DispatchResult, Vec, traits::AccountIdConversion}; use substrate_fixed::types::{I64F64, U64F64, U96F32}; use subtensor_runtime_common::{ - AlphaCurrency, BalanceOps, Currency, CurrencyReserve, NetUid, SubnetInfo, TaoCurrency, + AlphaCurrency, BalanceOps, Currency, CurrencyReserve, LoopRemovePrefixWithWeightMeter, NetUid, + SubnetInfo, TaoCurrency, WeightMeterWrapper, }; use subtensor_swap_interface::{ DefaultPriceLimit, Order as OrderT, SwapEngine, SwapHandler, SwapResult, @@ -957,8 +958,9 @@ impl Pallet { /// Clear **protocol-owned** liquidity and wipe all swap state for `netuid`. pub fn do_clear_protocol_liquidity(netuid: NetUid, remaining_weight: Weight) -> Weight { - let weight_meter = WeightMeter::with_limit(remaining_weight); + let mut weight_meter = WeightMeter::with_limit(remaining_weight); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1)); let protocol_account = Self::protocol_account_id(); // 1) Force-close only protocol positions, burning proceeds. @@ -976,9 +978,16 @@ impl Pallet { }) .collect(); + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().reads(protocol_pos_ids.len() as u64) + ); + for pos_id in protocol_pos_ids { + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads_writes(2, 2)); match Self::do_remove_liquidity(netuid, &protocol_account, pos_id) { Ok(rm) => { + WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1)); let alpha_total_from_pool: AlphaCurrency = rm.alpha.saturating_add(rm.fee_alpha); let tao_total_from_pool: TaoCurrency = rm.tao.saturating_add(rm.fee_tao); @@ -1006,22 +1015,47 @@ impl Pallet { // 2) Clear active tick index entries, then all swap state (idempotent even if empty/non‑V3). let active_ticks: sp_std::vec::Vec = Ticks::::iter_prefix(netuid).map(|(ti, _)| ti).collect(); + + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().reads_writes(active_ticks.len() as u64, active_ticks.len() as u64) + ); for ti in active_ticks { ActiveTickIndexManager::::remove(netuid, ti); } - let _ = Positions::::clear_prefix((netuid,), u32::MAX, None); - let _ = Ticks::::clear_prefix(netuid, u32::MAX, None); + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + Positions::::clear_prefix((netuid,), 1024, None) + ); + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + Ticks::::clear_prefix(netuid, 1024, None) + ); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); FeeGlobalTao::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); FeeGlobalAlpha::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); CurrentLiquidity::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); CurrentTick::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); AlphaSqrtPrice::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SwapV3Initialized::::remove(netuid); - let _ = TickIndexBitmapWords::::clear_prefix((netuid,), u32::MAX, None); + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + TickIndexBitmapWords::::clear_prefix((netuid,), 1024, None) + ); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); FeeRate::::remove(netuid); + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); EnabledUserLiquidity::::remove(netuid); log::debug!( From 0ec605feac1cb15eb663a2d456671867d138aae8 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 2 Mar 2026 15:46:12 +0800 Subject: [PATCH 39/40] cargo clippy --- pallets/admin-utils/src/tests/mod.rs | 1 + pallets/subtensor/src/staking/remove_stake.rs | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pallets/admin-utils/src/tests/mod.rs b/pallets/admin-utils/src/tests/mod.rs index f87ba31bba..219c1dfdd8 100644 --- a/pallets/admin-utils/src/tests/mod.rs +++ b/pallets/admin-utils/src/tests/mod.rs @@ -1168,6 +1168,7 @@ fn test_sudo_set_liquid_alpha_enabled() { new_test_ext().execute_with(|| { let netuid = NetUid::from(1); let enabled: bool = true; + NetworksAdded::::insert(netuid, true); assert_eq!(!enabled, SubtensorModule::get_liquid_alpha_enabled(netuid)); assert_ok!(AdminUtils::sudo_set_liquid_alpha_enabled( diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs index 1cac603a80..9418187871 100644 --- a/pallets/subtensor/src/staking/remove_stake.rs +++ b/pallets/subtensor/src/staking/remove_stake.rs @@ -626,10 +626,7 @@ impl Pallet { }; if !refund.is_zero() { - WeightMeterWrapper!( - meter_weight, - T::DbWeight::get().reads(1) + T::DbWeight::get().writes(1) - ); + WeightMeterWrapper!(meter_weight, T::DbWeight::get().reads_writes(1, 1)); Self::add_balance_to_coldkey_account(&owner_coldkey, refund.to_u64()); } From f30093ea733b010b7bf8919869a1cab457c422b6 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 2 Mar 2026 15:52:54 +0800 Subject: [PATCH 40/40] fix unit test --- pallets/admin-utils/src/lib.rs | 2 ++ pallets/admin-utils/src/tests/mod.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 86f5fbd166..0b63bf8500 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -2010,10 +2010,12 @@ pub mod pallet { netuid, &[TransactionType::MaxUidsTrimming], )?; + ensure!( pallet_subtensor::Pallet::::if_subnet_exist(netuid), Error::::SubnetDoesNotExist ); + pallet_subtensor::Pallet::::ensure_admin_window_open(netuid)?; pallet_subtensor::Pallet::::trim_to_max_allowed_uids(netuid, max_n)?; diff --git a/pallets/admin-utils/src/tests/mod.rs b/pallets/admin-utils/src/tests/mod.rs index 219c1dfdd8..c3e5ac717f 100644 --- a/pallets/admin-utils/src/tests/mod.rs +++ b/pallets/admin-utils/src/tests/mod.rs @@ -2750,7 +2750,7 @@ fn test_trim_to_max_allowed_uids() { NetUid::from(42), new_max_n ), - pallet_subtensor::Error::::SubnetNotExists + Error::::SubnetDoesNotExist ); // New max n less than lower bound