Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions pallets/subtensor/src/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1788,4 +1788,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::<T>::init_new_network(netuid, tempo);
SubtokenEnabled::<T>::insert(netuid, true);
Subtensor::<T>::set_max_allowed_uids(netuid, 256);
Subtensor::<T>::set_network_registration_allowed(netuid, true);
Subtensor::<T>::set_burn(netuid, 1.into());

// Set network owner
SubnetOwner::<T>::insert(netuid, coldkey.clone());

Subtensor::<T>::set_max_registrations_per_block(netuid, 64);

Subtensor::<T>::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::<T>::add_balance_to_coldkey_account(&coldkey, amount_to_be_staked);

assert_ok!(Subtensor::<T>::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::<T>::insert(netuid, tao_reserve);
SubnetAlphaIn::<T>::insert(netuid, alpha_in);

#[extrinsic_call]
_(RawOrigin::Root, coldkey.clone(), netuid);
}
}
14 changes: 10 additions & 4 deletions pallets/subtensor/src/coinbase/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
// 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};
Expand Down Expand Up @@ -210,15 +209,22 @@ impl<T: Config> Pallet<T> {
Error::<T>::SubnetNotExists
);

Self::finalize_all_subnet_root_dividends(netuid);
// Just remove the network from the added networks.
NetworksAdded::<T>::remove(netuid);

let mut dissolved_networks = DissolvedNetworks::<T>::get();
ensure!(
!dissolved_networks.contains(&netuid),
Error::<T>::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);

// --- Remove the network
Self::remove_network(netuid);
dissolved_networks.push(netuid);
DissolvedNetworks::<T>::set(dissolved_networks);

// --- Emit the NetworkRemoved event
log::info!("NetworkRemoved( netuid:{netuid:?} )");
Expand Down
5 changes: 5 additions & 0 deletions pallets/subtensor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ pub mod pallet {
traits::{
OriginTrait, QueryPreimage, StorePreimage, UnfilteredDispatchable, tokens::fungible,
},
weights::{Weight, WeightMeter},
};
use frame_system::pallet_prelude::*;
use pallet_drand::types::RoundNumber;
Expand Down Expand Up @@ -1879,6 +1880,10 @@ pub mod pallet {
pub type SubtokenEnabled<T> =
StorageMap<_, Identity, NetUid, bool, ValueQuery, DefaultFalse<T>>;

/// --- ITEM ( dissolved_networks ) Networks dissolved but some storage not removed yet
#[pallet::storage]
pub type DissolvedNetworks<T> = StorageValue<_, Vec<NetUid>, ValueQuery>;

// =======================================
// ==== VotingPower Storage ====
// =======================================
Expand Down
4 changes: 4 additions & 0 deletions pallets/subtensor/src/macros/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down
5 changes: 5 additions & 0 deletions pallets/subtensor/src/macros/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
}
}
63 changes: 62 additions & 1 deletion pallets/subtensor/src/macros/hooks.rs
Original file line number Diff line number Diff line change
@@ -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]
Expand Down Expand Up @@ -177,6 +178,20 @@ mod hooks {
// Self::check_total_stake()?;
Ok(())
}

fn on_idle(_block: BlockNumberFor<T>, 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()
}
}

impl<T: Config> Pallet<T> {
Expand Down Expand Up @@ -216,5 +231,51 @@ 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::<T>::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);

DissolvedNetworks::<T>::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);
}
}
}
31 changes: 22 additions & 9 deletions pallets/subtensor/src/staking/claim_root.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -389,15 +390,27 @@ impl<T: Config> Pallet<T> {
}

/// Claim all root dividends for subnet and remove all associated data.
pub fn finalize_all_subnet_root_dividends(netuid: NetUid) {
let hotkeys = RootClaimable::<T>::iter_keys().collect::<Vec<_>>();

for hotkey in hotkeys.iter() {
RootClaimable::<T>::mutate(hotkey, |claimable| {
claimable.remove(&netuid);
});
pub fn finalize_all_subnet_root_dividends(netuid: NetUid, remaining_weight: Weight) -> Weight {
let mut weight_meter = WeightMeter::with_limit(remaining_weight);

// Iterate directly without collecting to avoid unnecessary allocation
for hotkey in RootClaimable::<T>::iter_keys() {
WeightMeterWrapper!(weight_meter, T::DbWeight::get().reads(1), {});

WeightMeterWrapper!(
weight_meter,
T::DbWeight::get().writes(1),
RootClaimable::<T>::mutate(&hotkey, |claimable| {
claimable.remove(&netuid);
})
);
}

let _ = RootClaimed::<T>::clear_prefix((netuid,), u32::MAX, None);
WeightMeterWrapper!(
weight_meter,
T::DbWeight::get().writes(1),
RootClaimed::<T>::clear_prefix((netuid,), u32::MAX, None)
);
weight_meter.consumed()
}
}
101 changes: 101 additions & 0 deletions pallets/subtensor/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
let _ = $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<bool>, 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);
}
}
1 change: 1 addition & 0 deletions pallets/swap-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub trait SwapHandler {
tao_delta: TaoCurrency,
alpha_delta: AlphaCurrency,
) -> (TaoCurrency, AlphaCurrency);

fn clear_protocol_liquidity(netuid: NetUid) -> DispatchResult;
fn init_swap(netuid: NetUid, maybe_price: Option<U64F64>);
}
Expand Down
14 changes: 14 additions & 0 deletions pallets/swap/src/pallet/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,20 @@ impl<T: Config> SwapHandler for Pallet<T> {
Self::adjust_protocol_liquidity(netuid, tao_delta, alpha_delta)
}

// fn is_user_liquidity_enabled(netuid: NetUid) -> bool {
// EnabledUserLiquidity::<T>::get(netuid)
// }

// fn dissolve_all_liquidity_providers(
// netuid: NetUid,
// remaining_weight: Option<Weight>,
// ) -> Weight {
// Self::do_dissolve_all_liquidity_providers(netuid, remaining_weight)
// }

// fn toggle_user_liquidity(netuid: NetUid, enabled: bool) {
// EnabledUserLiquidity::<T>::insert(netuid, enabled)
// }
fn clear_protocol_liquidity(netuid: NetUid) -> DispatchResult {
Self::do_clear_protocol_liquidity(netuid)
}
Expand Down
Loading