diff --git a/chain-extensions/src/mock.rs b/chain-extensions/src/mock.rs index 45c7811adb..7189be90bf 100644 --- a/chain-extensions/src/mock.rs +++ b/chain-extensions/src/mock.rs @@ -454,7 +454,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/common/src/lib.rs b/common/src/lib.rs index a63b92779a..8bdb1dfce1 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -445,12 +445,121 @@ 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.saturating_mul(1024)) { + return $meter.consumed(); + } + let result = $body; + + $meter.consume($weight.saturating_mul(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 } + } + + fn execute(&mut self, number: u64) -> TestResult { + if self.count >= number { + self.count = self.count.saturating_sub(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/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/admin-utils/src/tests/mock.rs b/pallets/admin-utils/src/tests/mock.rs index 2d51ecf105..b01bc9e859 100644 --- a/pallets/admin-utils/src/tests/mock.rs +++ b/pallets/admin-utils/src/tests/mock.rs @@ -359,7 +359,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/commitments/src/lib.rs b/pallets/commitments/src/lib.rs index 98e5961708..7c3423ccf3 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::{LoopRemovePrefixWithWeightMeter, NetUid, WeightMeterWrapper}; use tle::{ curves::drand::TinyBLS381, stream_ciphers::AESGCMStreamCipherProvider, @@ -563,16 +564,44 @@ impl Pallet { commitments } - pub fn purge_netuid(netuid: NetUid) { - let _ = CommitmentOf::::clear_prefix(netuid, u32::MAX, None); - let _ = LastCommitment::::clear_prefix(netuid, u32::MAX, None); - let _ = LastBondsReset::::clear_prefix(netuid, u32::MAX, None); - let _ = RevealedCommitments::::clear_prefix(netuid, u32::MAX, None); - let _ = UsedSpaceOf::::clear_prefix(netuid, u32::MAX, None); + pub fn purge_netuid(netuid: NetUid, remaining_weight: Weight) -> Weight { + let mut weight_meter = WeightMeter::with_limit(remaining_weight); + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + CommitmentOf::::clear_prefix(netuid, 1024, None) + ); + + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + LastCommitment::::clear_prefix(netuid, 1024, None) + ); + + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + LastBondsReset::::clear_prefix(netuid, 1024, None) + ); + + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + RevealedCommitments::::clear_prefix(netuid, 1024, None) + ); + + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + UsedSpaceOf::::clear_prefix(netuid, 1024, 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..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}; @@ -2265,7 +2266,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); @@ -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))); }); diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index b370b6dbe1..3683fcba2a 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -1764,4 +1764,20 @@ 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); + + // Set network owner + SubnetOwner::::insert(netuid, coldkey.clone()); + + #[extrinsic_call] + _(RawOrigin::Root, coldkey.clone(), netuid); + } } diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index 83567b6f57..b740d58c98 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -16,11 +16,10 @@ // DEALINGS IN THE SOFTWARE. use super::*; -use crate::CommitmentsInterface; +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 @@ -210,190 +209,353 @@ impl Pallet { Error::::SubnetNotExists ); - Self::finalize_all_subnet_root_dividends(netuid); + let mut dissolved_networks = DissolvedNetworks::::get(); + ensure!( + !dissolved_networks.contains(&netuid), + Error::::NetworkAlreadyDissolved + ); - // --- 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); + // TODO Most of data cleanup is done in the block hook, should we charge the user for this? - // --- Remove the network - Self::remove_network(netuid); + // 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)); + + dissolved_networks.push(netuid); + DissolvedNetworks::::set(dissolved_networks); - // --- Emit the NetworkRemoved event log::info!("NetworkRemoved( netuid:{netuid:?} )"); + + // --- Emit the NetworkRemoved event Self::deposit_event(Event::NetworkRemoved(netuid)); Ok(()) } - pub fn remove_network(netuid: NetUid) { - // --- 1. Get the owner and remove from SubnetOwner. - let owner_coldkey: T::AccountId = SubnetOwner::::get(netuid); + pub fn remove_network(netuid: NetUid, remaining_weight: Weight) -> Weight { + let mut weight_meter = WeightMeter::with_limit(remaining_weight); + + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); SubnetOwner::::remove(netuid); // --- 2. Remove network count. + WeightMeterWrapper!(weight_meter, T::DbWeight::get().writes(1)); 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. - let _ = Uids::::clear_prefix(netuid, u32::MAX, None); + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + Uids::::clear_prefix(netuid, 1024, None) + ); + let keys = Keys::::iter_prefix(netuid).collect::>(); - let _ = Keys::::clear_prefix(netuid, u32::MAX, None); + let keys_len = keys.len() as u64; + WeightMeterWrapper!( + weight_meter, + T::DbWeight::get().reads_writes(keys_len, keys_len) + ); + + for (_uid, key) in keys { + IsNetworkMember::::remove(key, netuid); + } + + 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)); *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); SubnetTaoProvided::::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. - let _ = BlockAtRegistration::::clear_prefix(netuid, u32::MAX, None); - let _ = Axons::::clear_prefix(netuid, u32::MAX, None); - let _ = NeuronCertificates::::clear_prefix(netuid, u32::MAX, None); - let _ = Prometheus::::clear_prefix(netuid, u32::MAX, None); - let _ = AlphaDividendsPerSubnet::::clear_prefix(netuid, u32::MAX, None); - let _ = PendingChildKeys::::clear_prefix(netuid, u32::MAX, None); - let _ = AssociatedEvmAddress::::clear_prefix(netuid, u32::MAX, None); + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + BlockAtRegistration::::clear_prefix(netuid, 1024, None) + ); + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + Axons::::clear_prefix(netuid, 1024, None) + ); + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + Prometheus::::clear_prefix(netuid, 1024, None) + ); + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + AlphaDividendsPerSubnet::::clear_prefix(netuid, 1024, None) + ); + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + PendingChildKeys::::clear_prefix(netuid, 1024, None) + ); + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + AssociatedEvmAddress::::clear_prefix(netuid, 1024, 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); - let _ = WeightCommits::::clear_prefix(netuid_index, u32::MAX, None); - let _ = TimelockedWeightCommits::::clear_prefix(netuid_index, u32::MAX, None); - let _ = CRV3WeightCommits::::clear_prefix(netuid_index, u32::MAX, None); - let _ = CRV3WeightCommitsV2::::clear_prefix(netuid_index, u32::MAX, None); - let _ = Bonds::::clear_prefix(netuid_index, u32::MAX, None); - let _ = Weights::::clear_prefix(netuid_index, u32::MAX, None); + + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + WeightCommits::::clear_prefix(netuid_index, 1024, None) + ); + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + TimelockedWeightCommits::::clear_prefix(netuid_index, 1024, None) + ); + + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + CRV3WeightCommits::::clear_prefix(netuid_index, 1024, None) + ); + + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + 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), + Weights::::clear_prefix(netuid_index, 1024, 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) - let _ = LastHotkeySwapOnNetuid::::clear_prefix(netuid, u32::MAX, None); + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + LastHotkeySwapOnNetuid::::clear_prefix(netuid, 1024, 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)); } @@ -402,88 +564,143 @@ 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_writes(read_count, 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" - ); + log::debug!("remove_network: netuid={netuid} 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 47726bd6b0..a18f9778f3 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 ===== @@ -89,6 +90,7 @@ pub mod pallet { traits::{ OriginTrait, QueryPreimage, StorePreimage, UnfilteredDispatchable, tokens::fungible, }, + weights::Weight, }; use frame_system::pallet_prelude::*; use pallet_drand::types::RoundNumber; @@ -1891,6 +1893,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 ==== // ======================================= @@ -2746,5 +2752,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/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 37e8adadf2..6758e4eba0 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1242,9 +1242,9 @@ 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) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(31)))] + #[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( origin: OriginFor, _coldkey: T::AccountId, diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index e6c3aa5e78..5a00abb98f 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -280,6 +280,10 @@ mod errors { PrecisionLoss, /// Deprecated call. Deprecated, + /// Subnet buyback exceeded the operation rate limit + SubnetBuybackRateLimitExceeded, + /// Network already dissolved + NetworkAlreadyDissolved, /// "Add stake and burn" exceeded the operation rate limit AddStakeBurnRateLimitExceeded, /// A coldkey swap has been announced for this account. diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index 65c33aee87..8e982ad31b 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 899e8d32f2..97e4a107d0 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] @@ -177,6 +178,12 @@ mod hooks { // Self::check_total_stake()?; Ok(()) } + + fn on_idle(_block: BlockNumberFor, limit: Weight) -> Weight { + limit.saturating_sub(Self::remove_data_for_dissolved_networks( + limit.saturating_div(2), + )) + } } impl Pallet { @@ -216,5 +223,43 @@ 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 mut remaining_weight = remaining_weight; + let dissolved_networks = DissolvedNetworks::::get(); + + 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 = 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 }); + } + remaining_weight + } } } diff --git a/pallets/subtensor/src/staking/claim_root.rs b/pallets/subtensor/src/staking/claim_root.rs index 24a26d154c..06962657ac 100644 --- a/pallets/subtensor/src/staking/claim_root.rs +++ b/pallets/subtensor/src/staking/claim_root.rs @@ -1,5 +1,6 @@ use super::*; -use frame_support::weights::Weight; +use crate::WeightMeterWrapper; +use frame_support::weights::{Weight, WeightMeter}; use sp_core::Get; use sp_std::collections::btree_set::BTreeSet; use substrate_fixed::types::I96F32; @@ -131,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); @@ -389,15 +394,28 @@ 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| { + 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)); + 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)); } - let _ = RootClaimed::::clear_prefix((netuid,), u32::MAX, None); + LoopRemovePrefixWithWeightMeter!( + weight_meter, + T::DbWeight::get().writes(1), + RootClaimed::::clear_prefix((netuid,), 1024, None) + ); + weight_meter.consumed() } } diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs index 74a6bf34a6..95bc5420c2 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,20 @@ impl Pallet { } } - pub fn destroy_alpha_in_out_stakes(netuid: NetUid) -> DispatchResult { - // 1) Ensure the subnet exists. - ensure!(Self::if_subnet_exist(netuid), Error::::SubnetNotExists); + pub fn destroy_alpha_in_out_stakes(netuid: NetUid, remaining_weight: Weight) -> Weight { + // 1) Initialize the weight meter from the remaining weight. + 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 +458,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 +470,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 = T::SwapInterface::current_alpha_price(netuid.into()); let val_u64 = U96F32::from_num(owner_alpha_u64) .saturating_mul(cur_price) @@ -488,8 +497,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; } @@ -515,11 +531,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)); } @@ -575,16 +594,22 @@ 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)); SubnetAlphaInProvided::::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: @@ -598,9 +623,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/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index ecb5ce0452..b89090354f 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; } diff --git a/pallets/subtensor/src/tests/claim_root.rs b/pallets/subtensor/src/tests/claim_root.rs index 6bcaee2fca..8b46947af3 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; @@ -1371,6 +1373,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 7af9420ba3..24a24282b4 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -348,7 +348,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 { + Weight::from(0) + } } parameter_types! { @@ -700,6 +702,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 diff --git a/pallets/subtensor/src/tests/networks.rs b/pallets/subtensor/src/tests/networks.rs index aa45fb441a..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(|| { @@ -84,6 +112,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); @@ -113,6 +142,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); @@ -184,6 +214,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!( @@ -260,6 +291,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 @@ -455,6 +487,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 @@ -639,10 +672,12 @@ 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); assert_ok!(SubtensorModule::do_dissolve_network(net)); + run_block_idle(); let after = SubtensorModule::get_coldkey_balance(&sc); // No reward distributed, α-out cleared. @@ -694,6 +729,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); @@ -763,7 +799,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; @@ -918,7 +957,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 { @@ -1001,7 +1043,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); @@ -1047,7 +1092,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); @@ -1081,7 +1129,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 @@ -1401,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(|| { @@ -2022,6 +2098,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 @@ -2289,6 +2366,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. diff --git a/pallets/swap-interface/src/lib.rs b/pallets/swap-interface/src/lib.rs index 76e149b4b7..6b7c27b5fb 100644 --- a/pallets/swap-interface/src/lib.rs +++ b/pallets/swap-interface/src/lib.rs @@ -46,11 +46,12 @@ pub trait SwapHandler { netuid: NetUid, tao_delta: TaoCurrency, alpha_delta: AlphaCurrency, - ); + ) -> (TaoCurrency, AlphaCurrency); + + fn clear_protocol_liquidity(netuid: NetUid, remaining_weight: Weight) -> Weight; fn is_user_liquidity_enabled(netuid: NetUid) -> bool; fn dissolve_all_liquidity_providers(netuid: NetUid) -> DispatchResult; fn toggle_user_liquidity(netuid: NetUid, enabled: bool); - fn clear_protocol_liquidity(netuid: NetUid) -> DispatchResult; } pub trait DefaultPriceLimit diff --git a/pallets/swap/src/pallet/impls.rs b/pallets/swap/src/pallet/impls.rs index 38830ec688..4c0d3ed25d 100644 --- a/pallets/swap/src/pallet/impls.rs +++ b/pallets/swap/src/pallet/impls.rs @@ -1,9 +1,22 @@ +use super::pallet::*; +use super::swap_step::{BasicSwapStep, SwapStep, SwapStepAction}; +use crate::{ + SqrtPrice, + position::{Position, PositionId}, + tick::{ActiveTickIndexManager, Tick, TickIndex}, +}; use core::ops::Neg; 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; + use sp_runtime::{DispatchResult, Vec, traits::AccountIdConversion}; use substrate_fixed::types::{I64F64, U64F64, U96F32}; use subtensor_runtime_common::{ @@ -13,14 +26,6 @@ use subtensor_swap_interface::{ DefaultPriceLimit, Order as OrderT, SwapEngine, SwapHandler, SwapResult, }; -use super::pallet::*; -use super::swap_step::{BasicSwapStep, SwapStep, SwapStepAction}; -use crate::{ - SqrtPrice, - position::{Position, PositionId}, - tick::{ActiveTickIndexManager, Tick, TickIndex}, -}; - const MAX_SWAP_ITERATIONS: u16 = 1000; #[derive(Debug, PartialEq)] @@ -153,7 +158,7 @@ impl Pallet { netuid: NetUid, tao_delta: TaoCurrency, alpha_delta: AlphaCurrency, - ) { + ) -> (TaoCurrency, AlphaCurrency) { // Update protocol position with new liquidity let protocol_account_id = Self::protocol_account_id(); let mut positions = @@ -211,6 +216,7 @@ impl Pallet { Self::add_liquidity_at_index(netuid, position.tick_high, liquidity_delta, true); } } + (tao_delta, alpha_delta) } /// Executes a token swap on the specified subnet. @@ -950,7 +956,9 @@ 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 weight_meter = WeightMeter::with_limit(remaining_weight); + let protocol_account = Self::protocol_account_id(); // 1) Force-close only protocol positions, burning proceeds. @@ -1020,7 +1028,7 @@ impl Pallet { "clear_protocol_liquidity: netuid={netuid:?}, protocol_burned: τ={burned_tao:?}, α={burned_alpha:?}; state cleared" ); - Ok(()) + weight_meter.consumed() } } @@ -1149,8 +1157,12 @@ impl SwapHandler for Pallet { netuid: NetUid, tao_delta: TaoCurrency, alpha_delta: AlphaCurrency, - ) { - Self::adjust_protocol_liquidity(netuid, tao_delta, alpha_delta); + ) -> (TaoCurrency, AlphaCurrency) { + Self::adjust_protocol_liquidity(netuid, tao_delta, alpha_delta) + } + + fn clear_protocol_liquidity(netuid: NetUid, remaining_weight: Weight) -> Weight { + Self::do_clear_protocol_liquidity(netuid, remaining_weight) } fn is_user_liquidity_enabled(netuid: NetUid) -> bool { @@ -1162,7 +1174,4 @@ 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) - } } diff --git a/pallets/swap/src/pallet/tests.rs b/pallets/swap/src/pallet/tests.rs index 727e65c95a..1ca5881726 100644 --- a/pallets/swap/src/pallet/tests.rs +++ b/pallets/swap/src/pallet/tests.rs @@ -2001,7 +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)); - assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); + Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::MAX, u64::MAX)); // ASSERT: positions cleared (both user and protocol) assert_eq!( @@ -2086,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)); -// assert_ok!(Pallet::::do_clear_protocol_liquidity(netuid)); +// Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::MAX, u64::MAX))); // // ASSERT: positions & ticks gone, state reset // assert_eq!( @@ -2131,6 +2131,7 @@ fn test_liquidate_non_v3_uninitialized_ok_and_clears() { ); // ACT + Pallet::::do_clear_protocol_liquidity(netuid, Weight::from_parts(u64::MAX, u64::MAX)); assert_ok!(Pallet::::do_dissolve_all_liquidity_providers(netuid)); // ASSERT: Defensive clears leave no residues and do not panic @@ -2187,8 +2188,7 @@ 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, u64::MAX)); // State remains empty assert!( @@ -2296,7 +2296,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, u64::MAX)); // User position(s) are gone and all V3 state cleared. assert_eq!(Pallet::::count_positions(netuid, &cold), 0); @@ -2358,7 +2358,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, u64::MAX)); // --- State is cleared. assert!(Ticks::::iter_prefix(netuid).next().is_none()); @@ -2628,7 +2628,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, u64::MAX)); let protocol_id = Pallet::::protocol_account_id(); assert_eq!(Pallet::::count_positions(netuid, &cold), 0); @@ -2693,7 +2693,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)); // --- Assert: all protocol positions removed --- let prot_positions_after = @@ -2728,7 +2728,8 @@ fn test_clear_protocol_liquidity_green_path() { assert!(!EnabledUserLiquidity::::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!( Positions::::iter_prefix_values((netuid, protocol_id)) .next() diff --git a/pallets/transaction-fee/src/tests/mock.rs b/pallets/transaction-fee/src/tests/mock.rs index e4572bbfea..169e92a7c4 100644 --- a/pallets/transaction-fee/src/tests/mock.rs +++ b/pallets/transaction-fee/src/tests/mock.rs @@ -429,7 +429,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! { diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index b324934caa..c2aa1190d3 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -837,8 +837,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) } } 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 \