Skip to content
Open
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
6 changes: 6 additions & 0 deletions chain-extensions/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ impl pallet_subtensor::Config for Test {
type GetCommitments = ();
type MaxImmuneUidsPercentage = MaxImmuneUidsPercentage;
type CommitmentsInterface = CommitmentsI;
type PrecompileCleanupInterface = PrecompileCleanupI;
type EvmKeyAssociateRateLimit = EvmKeyAssociateRateLimit;
type AuthorshipProvider = MockAuthorshipProvider;
type SubtensorPalletId = SubtensorPalletId;
Expand Down Expand Up @@ -467,6 +468,11 @@ impl CommitmentsInterface for CommitmentsI {
fn purge_netuid(_netuid: NetUid) {}
}

pub struct PrecompileCleanupI;
impl pallet_subtensor::PrecompileCleanupInterface for PrecompileCleanupI {
fn purge_netuid(_netuid: NetUid) {}
}

parameter_types! {
pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
BlockWeights::get().max_block;
Expand Down
6 changes: 6 additions & 0 deletions eco-tests/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ impl pallet_subtensor::Config for Test {
type GetCommitments = ();
type MaxImmuneUidsPercentage = MaxImmuneUidsPercentage;
type CommitmentsInterface = CommitmentsI;
type PrecompileCleanupInterface = PrecompileCleanupI;
type EvmKeyAssociateRateLimit = EvmKeyAssociateRateLimit;
type AuthorshipProvider = MockAuthorshipProvider;
type SubtensorPalletId = SubtensorPalletId;
Expand Down Expand Up @@ -350,6 +351,11 @@ impl CommitmentsInterface for CommitmentsI {
fn purge_netuid(_netuid: NetUid) {}
}

pub struct PrecompileCleanupI;
impl pallet_subtensor::PrecompileCleanupInterface for PrecompileCleanupI {
fn purge_netuid(_netuid: NetUid) {}
}

parameter_types! {
pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
BlockWeights::get().max_block;
Expand Down
6 changes: 6 additions & 0 deletions pallets/admin-utils/src/tests/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ impl pallet_subtensor::Config for Test {
type GetCommitments = ();
type MaxImmuneUidsPercentage = MaxImmuneUidsPercentage;
type CommitmentsInterface = CommitmentsI;
type PrecompileCleanupInterface = PrecompileCleanupI;
type EvmKeyAssociateRateLimit = EvmKeyAssociateRateLimit;
type AuthorshipProvider = MockAuthorshipProvider;
type SubtensorPalletId = SubtensorPalletId;
Expand Down Expand Up @@ -370,6 +371,11 @@ impl pallet_subtensor::CommitmentsInterface for CommitmentsI {
fn purge_netuid(_netuid: NetUid) {}
}

pub struct PrecompileCleanupI;
impl pallet_subtensor::PrecompileCleanupInterface for PrecompileCleanupI {
fn purge_netuid(_netuid: NetUid) {}
}

pub struct GrandpaInterfaceImpl;
impl crate::GrandpaInterface<Test> for GrandpaInterfaceImpl {
fn schedule_change(
Expand Down
78 changes: 76 additions & 2 deletions pallets/subtensor/src/coinbase/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// DEALINGS IN THE SOFTWARE.

use super::*;
use crate::CommitmentsInterface;
use crate::{CommitmentsInterface, PrecompileCleanupInterface};
use safe_math::*;
use substrate_fixed::types::{I64F64, U96F32};
use subtensor_runtime_common::{AlphaBalance, NetUid, NetUidStorageIndex, TaoBalance, Token};
Expand Down Expand Up @@ -218,6 +218,7 @@ impl<T: Config> Pallet<T> {
Self::destroy_alpha_in_out_stakes(netuid)?;
T::SwapInterface::clear_protocol_liquidity(netuid)?;
T::CommitmentsInterface::purge_netuid(netuid);
T::PrecompileCleanupInterface::purge_netuid(netuid);

// --- Remove the network
Self::remove_network(netuid);
Expand Down Expand Up @@ -273,18 +274,27 @@ impl<T: Config> Pallet<T> {
ValidatorPermit::<T>::remove(netuid);
ValidatorTrust::<T>::remove(netuid);

// Strip IsNetworkMember for every hotkey on this subnet and retain a
// snapshot for the orphan-hotkey cleanup pass further down.
let mut subnet_hotkeys: Vec<T::AccountId> = Vec::with_capacity(keys.len());
for (_uid, key) in keys {
IsNetworkMember::<T>::remove(key, netuid);
IsNetworkMember::<T>::remove(&key, netuid);
subnet_hotkeys.push(key);
}

// --- 10. Erase network parameters.
Tempo::<T>::remove(netuid);
Kappa::<T>::remove(netuid);
Difficulty::<T>::remove(netuid);
MaxAllowedUids::<T>::remove(netuid);
MinAllowedUids::<T>::remove(netuid);
ImmunityPeriod::<T>::remove(netuid);
ActivityCutoff::<T>::remove(netuid);
MinAllowedWeights::<T>::remove(netuid);
MaxWeightsLimit::<T>::remove(netuid);
AdjustmentAlpha::<T>::remove(netuid);
AdjustmentInterval::<T>::remove(netuid);
MinNonImmuneUids::<T>::remove(netuid);
RegistrationsThisInterval::<T>::remove(netuid);
POWRegistrationsThisInterval::<T>::remove(netuid);
BurnRegistrationsThisInterval::<T>::remove(netuid);
Expand All @@ -300,6 +310,11 @@ impl<T: Config> Pallet<T> {
SubnetEmaTaoFlow::<T>::remove(netuid);
SubnetTaoProvided::<T>::remove(netuid);

// --- 12. Root / emission split parameters.
RootProp::<T>::remove(netuid);
RecycleOrBurn::<T>::remove(netuid);
RootClaimableThreshold::<T>::remove(netuid);

// --- 13. Token / mechanism / registration toggles.
TokenSymbol::<T>::remove(netuid);
SubnetMechanism::<T>::remove(netuid);
Expand Down Expand Up @@ -362,12 +377,71 @@ impl<T: Config> Pallet<T> {
StakeWeight::<T>::remove(netuid);
LoadedEmission::<T>::remove(netuid);

// --- 18b. Voting power.
let _ = VotingPower::<T>::clear_prefix(netuid, u32::MAX, None);
VotingPowerTrackingEnabled::<T>::remove(netuid);
VotingPowerDisableAtBlock::<T>::remove(netuid);
VotingPowerEmaAlpha::<T>::remove(netuid);

// --- 18c. Drop RootClaimable hotkey entries whose BTreeMap is now
// empty. finalize_all_subnet_root_dividends (called above) already
// stripped this netuid from every map via mutate, leaving some maps
// empty; here we just garbage-collect those entries.
let rc_hotkeys: sp_std::vec::Vec<T::AccountId> =
RootClaimable::<T>::iter().map(|(hot, _)| hot).collect();
for hot in rc_hotkeys {
Comment thread
plind-junior marked this conversation as resolved.
if RootClaimable::<T>::get(&hot).is_empty() {
RootClaimable::<T>::remove(&hot);
}
}

// --- 18d. Hotkey orphan cleanup. Any hotkey that was registered on
// this subnet and has now lost its last IsNetworkMember entry is no
// longer reachable via any subnet, so drop its per-hotkey global
// bookkeeping (Owner, Delegates, OwnedHotkeys, StakingHotkeys,
// LastColdkeyHotkeyStakeBlock) to stop state piling up forever.
// subnet_hotkeys came from Keys::iter_prefix(netuid) where uid is the
// second key, so it cannot contain duplicates — Vec is fine.
let mut orphans: sp_std::vec::Vec<T::AccountId> = sp_std::vec::Vec::new();
for hot in &subnet_hotkeys {
if IsNetworkMember::<T>::iter_prefix(hot).next().is_none() {
orphans.push(hot.clone());
}
}
for hot in &orphans {
let cold = Owner::<T>::get(hot);
Owner::<T>::remove(hot);
Delegates::<T>::remove(hot);
OwnedHotkeys::<T>::mutate(&cold, |v| v.retain(|h| h != hot));
if OwnedHotkeys::<T>::get(&cold).is_empty() {
OwnedHotkeys::<T>::remove(&cold);
}
}
// StakingHotkeys and LastColdkeyHotkeyStakeBlock are keyed by coldkey;
// scan all coldkeys that staked anywhere and strip references to any
// orphan hotkey.
if !orphans.is_empty() {
let staking_colds: Vec<T::AccountId> =
StakingHotkeys::<T>::iter().map(|(c, _)| c).collect();
for cold in staking_colds {
StakingHotkeys::<T>::mutate(&cold, |v| v.retain(|h| !orphans.contains(h)));
if StakingHotkeys::<T>::get(&cold).is_empty() {
StakingHotkeys::<T>::remove(&cold);
}
for hot in &orphans {
LastColdkeyHotkeyStakeBlock::<T>::remove(&cold, hot);
}
}
}

// --- 19. DMAPs where netuid is the FIRST key: clear by prefix.
let _ = BlockAtRegistration::<T>::clear_prefix(netuid, u32::MAX, None);
let _ = Axons::<T>::clear_prefix(netuid, u32::MAX, None);
let _ = NeuronCertificates::<T>::clear_prefix(netuid, u32::MAX, None);
let _ = Prometheus::<T>::clear_prefix(netuid, u32::MAX, None);
let _ = AlphaDividendsPerSubnet::<T>::clear_prefix(netuid, u32::MAX, None);
let _ = RootAlphaDividendsPerSubnet::<T>::clear_prefix(netuid, u32::MAX, None);
// RootClaimed is already cleared by finalize_all_subnet_root_dividends above.
let _ = PendingChildKeys::<T>::clear_prefix(netuid, u32::MAX, None);
let _ = AssociatedEvmAddress::<T>::clear_prefix(netuid, u32::MAX, None);

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 @@ -2769,3 +2769,8 @@ impl<T> ProxyInterface<T> for () {
pub trait CommitmentsInterface {
fn purge_netuid(netuid: NetUid);
}

/// EVM precompile crates implement this to clean up storage when a subnet is removed.
pub trait PrecompileCleanupInterface {
fn purge_netuid(netuid: NetUid);
}
5 changes: 4 additions & 1 deletion pallets/subtensor/src/macros/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use frame_support::pallet_macros::pallet_section;
#[pallet_section]
mod config {

use crate::{CommitmentsInterface, GetAlphaForTao, GetTaoForAlpha};
use crate::{CommitmentsInterface, GetAlphaForTao, GetTaoForAlpha, PrecompileCleanupInterface};
use frame_support::PalletId;
use pallet_commitments::GetCommitments;
use subtensor_runtime_common::AuthorshipInfo;
Expand Down Expand Up @@ -61,6 +61,9 @@ mod config {
/// Interface to clean commitments on network dissolution.
type CommitmentsInterface: CommitmentsInterface;

/// Interface to clean EVM precompile storage on network dissolution.
type PrecompileCleanupInterface: PrecompileCleanupInterface;

/// Rate limit for associating an EVM key.
type EvmKeyAssociateRateLimit: Get<u64>;

Expand Down
6 changes: 6 additions & 0 deletions pallets/subtensor/src/tests/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ impl crate::Config for Test {
type GetCommitments = ();
type MaxImmuneUidsPercentage = MaxImmuneUidsPercentage;
type CommitmentsInterface = CommitmentsI;
type PrecompileCleanupInterface = PrecompileCleanupI;
type EvmKeyAssociateRateLimit = EvmKeyAssociateRateLimit;
type AuthorshipProvider = MockAuthorshipProvider;
type SubtensorPalletId = SubtensorPalletId;
Expand Down Expand Up @@ -366,6 +367,11 @@ impl CommitmentsInterface for CommitmentsI {
fn purge_netuid(_netuid: NetUid) {}
}

pub struct PrecompileCleanupI;
impl PrecompileCleanupInterface for PrecompileCleanupI {
fn purge_netuid(_netuid: NetUid) {}
}

parameter_types! {
pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
BlockWeights::get().max_block;
Expand Down
6 changes: 6 additions & 0 deletions pallets/subtensor/src/tests/mock_high_ed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ impl crate::Config for Test {
type GetCommitments = ();
type MaxImmuneUidsPercentage = MaxImmuneUidsPercentage;
type CommitmentsInterface = CommitmentsI;
type PrecompileCleanupInterface = PrecompileCleanupI;
type EvmKeyAssociateRateLimit = EvmKeyAssociateRateLimit;
type AuthorshipProvider = MockAuthorshipProvider;
type SubtensorPalletId = SubtensorPalletId;
Expand Down Expand Up @@ -326,6 +327,11 @@ impl CommitmentsInterface for CommitmentsI {
fn purge_netuid(_netuid: NetUid) {}
}

pub struct PrecompileCleanupI;
impl crate::PrecompileCleanupInterface for PrecompileCleanupI {
fn purge_netuid(_netuid: NetUid) {}
}

parameter_types! {
pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
BlockWeights::get().max_block;
Expand Down
Loading
Loading