use super::*; use crate::Error; use crate::system::{ensure_signed, ensure_signed_or_root, pallet_prelude::BlockNumberFor}; use safe_math::*; use sp_core::Get; use sp_core::U256; use sp_runtime::{PerU16, Saturating}; use substrate_fixed::types::{I32F32, I64F64, U64F64, U96F32}; use subtensor_runtime_common::{AlphaBalance, NetUid, NetUidStorageIndex, TaoBalance}; impl Pallet { pub fn ensure_subnet_owner_or_root( o: OriginFor, netuid: NetUid, ) -> Result, DispatchError> { let coldkey = ensure_signed_or_root(o); match coldkey { Ok(Some(who)) if SubnetOwner::::get(netuid) == who => Ok(Some(who)), Ok(Some(_)) => Err(DispatchError::BadOrigin), Ok(None) => Ok(None), Err(x) => Err(x.into()), } } pub fn ensure_subnet_owner( o: OriginFor, netuid: NetUid, ) -> Result { let coldkey = ensure_signed(o); match coldkey { Ok(who) if SubnetOwner::::get(netuid) == who => Ok(who), Ok(_) => Err(DispatchError::BadOrigin), Err(x) => Err(x.into()), } } /// Ensure owner-or-root with a set of TransactionType rate checks (owner only). pub fn ensure_sn_owner_or_root_with_limits( o: OriginFor, netuid: NetUid, limits: &[crate::utils::rate_limiting::TransactionType], ) -> Result, DispatchError> { let maybe_who = Self::ensure_subnet_owner_or_root(o, netuid)?; if let Some(who) = maybe_who.as_ref() { for tx in limits.iter() { ensure!( tx.passes_rate_limit_on_subnet::(who, netuid), Error::::TxRateLimitExceeded ); } } Ok(maybe_who) } /// Returns true if the current block is within the terminal freeze window of the tempo for the /// given subnet. During this window, admin ops are prohibited to avoid interference with /// validator weight submissions. Engages immediately on a pending manual trigger (so the trigger /// arms the freeze for the entire countdown to `PendingEpochAt`). pub fn is_in_admin_freeze_window(netuid: NetUid, current_block: u64) -> bool { let tempo = Self::get_tempo(netuid); if tempo == 0 { return false; } let pending = PendingEpochAt::::get(netuid); if pending > 0 && pending > current_block { return true; } let remaining = Self::blocks_until_next_auto_epoch(netuid, tempo, current_block); let window = AdminFreezeWindow::::get() as u64; remaining < window } /// Ensures the admin freeze window is not currently active for the given subnet. pub fn ensure_admin_window_open(netuid: NetUid) -> Result<(), DispatchError> { let now = Self::get_current_block_as_u64(); ensure!( !Self::is_in_admin_freeze_window(netuid, now), Error::::AdminActionProhibitedDuringWeightsWindow ); Ok(()) } pub fn set_admin_freeze_window(window: u16) { AdminFreezeWindow::::set(window); Self::deposit_event(Event::AdminFreezeWindowSet(window)); } pub fn set_owner_hyperparam_rate_limit(epochs: u16) { OwnerHyperparamRateLimit::::set(epochs); Self::deposit_event(Event::OwnerHyperparamRateLimitSet(epochs)); } /// If owner is `Some`, record last-blocks for the provided `TransactionType`s. pub fn record_owner_rl( maybe_owner: Option<::AccountId>, netuid: NetUid, txs: &[TransactionType], ) { if let Some(who) = maybe_owner { let now = Self::get_current_block_as_u64(); for tx in txs { tx.set_last_block_on_subnet::(&who, netuid, now); } } } // ======================== // ==== Global Setters ==== // ======================== /// Unchecked tempo write used by tests, precompiles, and internal helpers. /// Does NOT reset `LastEpochBlock` — that is the responsibility of /// `AdminUtils::sudo_set_tempo` (owner-or-root), which performs the cycle /// reset explicitly via `apply_tempo_with_cycle_reset`. pub fn set_tempo_unchecked(netuid: NetUid, tempo: u16) { Tempo::::insert(netuid, tempo); Self::deposit_event(Event::TempoSet(netuid, tempo)); } /// Sets `Tempo` and resets the state-based scheduler anchor `LastEpochBlock` /// to the current block pub fn apply_tempo_with_cycle_reset(netuid: NetUid, tempo: u16) { Self::set_tempo_unchecked(netuid, tempo); let now = Self::get_current_block_as_u64(); LastEpochBlock::::insert(netuid, now); } pub fn set_last_adjustment_block(netuid: NetUid, last_adjustment_block: u64) { LastAdjustmentBlock::::insert(netuid, last_adjustment_block); } pub fn set_blocks_since_last_step(netuid: NetUid, blocks_since_last_step: u64) { BlocksSinceLastStep::::insert(netuid, blocks_since_last_step); } pub fn set_registrations_this_block(netuid: NetUid, registrations_this_block: u16) { RegistrationsThisBlock::::insert(netuid, registrations_this_block); } pub fn set_last_mechanism_step_block(netuid: NetUid, last_mechanism_step_block: u64) { LastMechansimStepBlock::::insert(netuid, last_mechanism_step_block); } pub fn set_registrations_this_interval(netuid: NetUid, registrations_this_interval: u16) { RegistrationsThisInterval::::insert(netuid, registrations_this_interval); } pub fn set_pow_registrations_this_interval( netuid: NetUid, pow_registrations_this_interval: u16, ) { POWRegistrationsThisInterval::::insert(netuid, pow_registrations_this_interval); } pub fn set_burn_registrations_this_interval( netuid: NetUid, burn_registrations_this_interval: u16, ) { BurnRegistrationsThisInterval::::insert(netuid, burn_registrations_this_interval); } // ======================== // ==== Global Getters ==== // ======================== pub fn get_current_block_as_u64() -> u64 { TryInto::try_into(>::block_number()) .ok() .expect("blockchain will not exceed 2^64 blocks; QED.") } // ============================== // ==== YumaConsensus params ==== // ============================== /// Deprecated: Rank is no longer computed during epoch. Always returns empty. pub fn get_rank(_netuid: NetUid) -> Vec { Vec::new() } /// Deprecated: Trust is no longer computed during epoch. Always returns empty. pub fn get_trust(_netuid: NetUid) -> Vec { Vec::new() } pub fn get_active(netuid: NetUid) -> Vec { Active::::get(netuid) } pub fn get_emission(netuid: NetUid) -> Vec { Emission::::get(netuid) } pub fn get_consensus(netuid: NetUid) -> Vec { Consensus::::get(netuid) .into_iter() .map(PerU16::deconstruct) .collect() } pub fn get_incentive(netuid: NetUidStorageIndex) -> Vec { Incentive::::get(netuid) .into_iter() .map(PerU16::deconstruct) .collect() } pub fn get_dividends(netuid: NetUid) -> Vec { Dividends::::get(netuid) .into_iter() .map(PerU16::deconstruct) .collect() } /// Fetch LastUpdate for `netuid` and ensure its length is at least `get_subnetwork_n(netuid)`, /// padding with zeros if needed. Returns the (possibly padded) vector. pub fn get_last_update(netuid_index: NetUidStorageIndex) -> Vec { let netuid = Self::get_netuid(netuid_index); let target_len = Self::get_subnetwork_n(netuid) as usize; let mut v = LastUpdate::::get(netuid_index); if v.len() < target_len { v.resize(target_len, 0); } v } /// Deprecated: PruningScores is no longer computed during epoch. Always returns empty. pub fn get_pruning_score(_netuid: NetUid) -> Vec { Vec::new() } pub fn get_validator_trust(netuid: NetUid) -> Vec { ValidatorTrust::::get(netuid) .into_iter() .map(PerU16::deconstruct) .collect() } pub fn get_validator_permit(netuid: NetUid) -> Vec { ValidatorPermit::::get(netuid) } // ================================== // ==== YumaConsensus UID params ==== // ================================== pub fn set_last_update_for_uid(netuid: NetUidStorageIndex, uid: u16, last_update: u64) { let mut updated_last_update_vec = Self::get_last_update(netuid); let Some(updated_last_update) = updated_last_update_vec.get_mut(uid as usize) else { return; }; *updated_last_update = last_update; LastUpdate::::insert(netuid, updated_last_update_vec); } pub fn set_active_for_uid(netuid: NetUid, uid: u16, active: bool) { let mut updated_active_vec = Self::get_active(netuid); let Some(updated_active) = updated_active_vec.get_mut(uid as usize) else { return; }; *updated_active = active; Active::::insert(netuid, updated_active_vec); } pub fn set_validator_permit_for_uid(netuid: NetUid, uid: u16, validator_permit: bool) { let mut updated_validator_permits = Self::get_validator_permit(netuid); let Some(updated_validator_permit) = updated_validator_permits.get_mut(uid as usize) else { return; }; *updated_validator_permit = validator_permit; ValidatorPermit::::insert(netuid, updated_validator_permits); } pub fn set_stake_threshold(min_stake: u64) { StakeThreshold::::put(min_stake); Self::deposit_event(Event::StakeThresholdSet(min_stake)); } /// Deprecated: Rank is no longer computed. Always returns 0. pub fn get_rank_for_uid(_netuid: NetUid, _uid: u16) -> u16 { 0 } /// Deprecated: Trust is no longer computed. Always returns 0. pub fn get_trust_for_uid(_netuid: NetUid, _uid: u16) -> u16 { 0 } pub fn get_emission_for_uid(netuid: NetUid, uid: u16) -> AlphaBalance { let vec = Emission::::get(netuid); vec.get(uid as usize).copied().unwrap_or_default() } pub fn get_active_for_uid(netuid: NetUid, uid: u16) -> bool { let vec = Active::::get(netuid); vec.get(uid as usize).copied().unwrap_or(false) } pub fn get_consensus_for_uid(netuid: NetUid, uid: u16) -> u16 { let vec = Consensus::::get(netuid); vec.get(uid as usize) .copied() .unwrap_or_default() .deconstruct() } pub fn get_incentive_for_uid(netuid: NetUidStorageIndex, uid: u16) -> u16 { let vec = Incentive::::get(netuid); vec.get(uid as usize) .copied() .unwrap_or_default() .deconstruct() } pub fn get_dividends_for_uid(netuid: NetUid, uid: u16) -> u16 { let vec = Dividends::::get(netuid); vec.get(uid as usize) .copied() .unwrap_or_default() .deconstruct() } pub fn get_last_update_for_uid(netuid: NetUidStorageIndex, uid: u16) -> u64 { let vec = LastUpdate::::get(netuid); vec.get(uid as usize).copied().unwrap_or(0) } /// Deprecated: PruningScores is no longer computed. Always returns u16::MAX. pub fn get_pruning_score_for_uid(_netuid: NetUid, _uid: u16) -> u16 { u16::MAX } pub fn get_validator_trust_for_uid(netuid: NetUid, uid: u16) -> u16 { let vec = ValidatorTrust::::get(netuid); vec.get(uid as usize) .copied() .unwrap_or_default() .deconstruct() } pub fn get_validator_permit_for_uid(netuid: NetUid, uid: u16) -> bool { let vec = ValidatorPermit::::get(netuid); vec.get(uid as usize).copied().unwrap_or(false) } pub fn get_stake_threshold() -> u64 { StakeThreshold::::get() } // ============================ // ==== Subnetwork Getters ==== // ============================ pub fn get_tempo(netuid: NetUid) -> u16 { Tempo::::get(netuid) } pub fn get_last_adjustment_block(netuid: NetUid) -> u64 { LastAdjustmentBlock::::get(netuid) } pub fn get_blocks_since_last_step(netuid: NetUid) -> u64 { BlocksSinceLastStep::::get(netuid) } pub fn get_difficulty(netuid: NetUid) -> U256 { U256::from(Self::get_difficulty_as_u64(netuid)) } pub fn get_registrations_this_block(netuid: NetUid) -> u16 { RegistrationsThisBlock::::get(netuid) } pub fn get_last_mechanism_step_block(netuid: NetUid) -> u64 { LastMechansimStepBlock::::get(netuid) } pub fn get_registrations_this_interval(netuid: NetUid) -> u16 { RegistrationsThisInterval::::get(netuid) } pub fn get_pow_registrations_this_interval(netuid: NetUid) -> u16 { POWRegistrationsThisInterval::::get(netuid) } pub fn get_burn_registrations_this_interval(netuid: NetUid) -> u16 { BurnRegistrationsThisInterval::::get(netuid) } pub fn get_neuron_block_at_registration(netuid: NetUid, neuron_uid: u16) -> u64 { BlockAtRegistration::::get(netuid, neuron_uid) } /// Returns the minimum number of non-immortal & non-immune UIDs that must remain in a subnet. pub fn get_min_non_immune_uids(netuid: NetUid) -> u16 { MinNonImmuneUids::::get(netuid) } /// Sets the minimum number of non-immortal & non-immune UIDs that must remain in a subnet. pub fn set_min_non_immune_uids(netuid: NetUid, min: u16) { MinNonImmuneUids::::insert(netuid, min); Self::deposit_event(Event::MinNonImmuneUidsSet(netuid, min)); } // ======================== // ===== Take checks ====== // ======================== pub fn do_take_checks(coldkey: &T::AccountId, hotkey: &T::AccountId) -> Result<(), Error> { // Ensure we are delegating a known key. ensure!( Self::hotkey_account_exists(hotkey), Error::::HotKeyAccountNotExists ); // Ensure that the coldkey is the owner. ensure!( Self::coldkey_owns_hotkey(coldkey, hotkey), Error::::NonAssociatedColdKey ); Ok(()) } // ======================== // === Token Management === // ======================== pub fn set_subnet_locked_balance(netuid: NetUid, amount: TaoBalance) { SubnetLocked::::insert(netuid, amount); } pub fn get_subnet_locked_balance(netuid: NetUid) -> TaoBalance { SubnetLocked::::get(netuid) } pub fn get_total_subnet_locked() -> TaoBalance { let mut total_subnet_locked: u64 = 0; for (_, locked) in SubnetLocked::::iter() { total_subnet_locked.saturating_accrue(locked.into()); } total_subnet_locked.into() } pub fn set_recycle_or_burn(netuid: NetUid, recycle_or_burn: RecycleOrBurnEnum) { RecycleOrBurn::::insert(netuid, recycle_or_burn); } // ======================== // ========= Sudo ========= // ======================== // Per-block epoch cap (dynamic tempo throttle) pub fn get_max_epochs_per_block() -> u8 { MaxEpochsPerBlock::::get() } pub fn set_max_epochs_per_block(max_epochs_per_block: u8) { MaxEpochsPerBlock::::put(max_epochs_per_block); Self::deposit_event(Event::MaxEpochsPerBlockSet(max_epochs_per_block)); } // Configure tx rate limiting pub fn get_tx_rate_limit() -> u64 { TxRateLimit::::get() } pub fn set_tx_rate_limit(tx_rate_limit: u64) { TxRateLimit::::put(tx_rate_limit); Self::deposit_event(Event::TxRateLimitSet(tx_rate_limit)); } pub fn get_tx_delegate_take_rate_limit() -> u64 { TxDelegateTakeRateLimit::::get() } pub fn set_tx_delegate_take_rate_limit(tx_rate_limit: u64) { TxDelegateTakeRateLimit::::put(tx_rate_limit); Self::deposit_event(Event::TxDelegateTakeRateLimitSet(tx_rate_limit)); } pub fn set_min_delegate_take(take: PerU16) { MinDelegateTake::::put(take); Self::deposit_event(Event::MinDelegateTakeSet(take)); } pub fn set_max_delegate_take(take: PerU16) { MaxDelegateTake::::put(take); Self::deposit_event(Event::MaxDelegateTakeSet(take)); } pub fn get_min_delegate_take() -> u16 { MinDelegateTake::::get().deconstruct() } pub fn get_max_delegate_take() -> u16 { MaxDelegateTake::::get().deconstruct() } pub fn get_default_delegate_take() -> u16 { // Default to maximum MaxDelegateTake::::get().deconstruct() } // get_default_childkey_take pub fn get_default_childkey_take() -> u16 { // Default to maximum MinChildkeyTake::::get().deconstruct() } pub fn get_tx_childkey_take_rate_limit() -> u64 { TxChildkeyTakeRateLimit::::get() } pub fn set_tx_childkey_take_rate_limit(tx_rate_limit: u64) { TxChildkeyTakeRateLimit::::put(tx_rate_limit); Self::deposit_event(Event::TxChildKeyTakeRateLimitSet(tx_rate_limit)); } pub fn set_min_childkey_take(take: PerU16) { MinChildkeyTake::::put(take); Self::deposit_event(Event::MinChildKeyTakeSet(take)); } pub fn set_min_childkey_take_for_subnet(netuid: NetUid, take: PerU16) { MinChildkeyTakePerSubnet::::insert(netuid, take); Self::deposit_event(Event::MinChildKeyTakePerSubnetSet(netuid, take)); } pub fn set_max_childkey_take(take: PerU16) { MaxChildkeyTake::::put(take); Self::deposit_event(Event::MaxChildKeyTakeSet(take)); } pub fn get_min_childkey_take() -> u16 { MinChildkeyTake::::get().deconstruct() } pub fn get_min_childkey_take_for_subnet(netuid: NetUid) -> u16 { MinChildkeyTakePerSubnet::::get(netuid).deconstruct() } pub fn get_effective_min_childkey_take(netuid: NetUid) -> u16 { Self::get_min_childkey_take().max(Self::get_min_childkey_take_for_subnet(netuid)) } pub fn get_max_childkey_take() -> u16 { MaxChildkeyTake::::get().deconstruct() } pub fn get_serving_rate_limit(netuid: NetUid) -> u64 { ServingRateLimit::::get(netuid) } pub fn set_serving_rate_limit(netuid: NetUid, serving_rate_limit: u64) { ServingRateLimit::::insert(netuid, serving_rate_limit); Self::deposit_event(Event::ServingRateLimitSet(netuid, serving_rate_limit)); } pub fn get_min_difficulty(netuid: NetUid) -> u64 { MinDifficulty::::get(netuid) } pub fn set_min_difficulty(netuid: NetUid, min_difficulty: u64) { MinDifficulty::::insert(netuid, min_difficulty); Self::deposit_event(Event::MinDifficultySet(netuid, min_difficulty)); } pub fn get_max_difficulty(netuid: NetUid) -> u64 { MaxDifficulty::::get(netuid) } pub fn set_max_difficulty(netuid: NetUid, max_difficulty: u64) { MaxDifficulty::::insert(netuid, max_difficulty); Self::deposit_event(Event::MaxDifficultySet(netuid, max_difficulty)); } pub fn get_weights_version_key(netuid: NetUid) -> u64 { WeightsVersionKey::::get(netuid) } pub fn set_weights_version_key(netuid: NetUid, weights_version_key: u64) { WeightsVersionKey::::insert(netuid, weights_version_key); Self::deposit_event(Event::WeightsVersionKeySet(netuid, weights_version_key)); } pub fn get_weights_set_rate_limit(netuid: NetUid) -> u64 { WeightsSetRateLimit::::get(netuid) } pub fn set_weights_set_rate_limit(netuid: NetUid, weights_set_rate_limit: u64) { WeightsSetRateLimit::::insert(netuid, weights_set_rate_limit); Self::deposit_event(Event::WeightsSetRateLimitSet( netuid, weights_set_rate_limit, )); } pub fn get_adjustment_interval(netuid: NetUid) -> u16 { AdjustmentInterval::::get(netuid) } pub fn set_adjustment_interval(netuid: NetUid, adjustment_interval: u16) { AdjustmentInterval::::insert(netuid, adjustment_interval); Self::deposit_event(Event::AdjustmentIntervalSet(netuid, adjustment_interval)); } pub fn get_adjustment_alpha(netuid: NetUid) -> u64 { AdjustmentAlpha::::get(netuid) } pub fn set_adjustment_alpha(netuid: NetUid, adjustment_alpha: u64) { AdjustmentAlpha::::insert(netuid, adjustment_alpha); Self::deposit_event(Event::AdjustmentAlphaSet(netuid, adjustment_alpha)); } pub fn set_validator_prune_len(netuid: NetUid, validator_prune_len: u64) { ValidatorPruneLen::::insert(netuid, validator_prune_len); Self::deposit_event(Event::ValidatorPruneLenSet(netuid, validator_prune_len)); } pub fn get_scaling_law_power(netuid: NetUid) -> u16 { ScalingLawPower::::get(netuid) } pub fn set_scaling_law_power(netuid: NetUid, scaling_law_power: u16) { ScalingLawPower::::insert(netuid, scaling_law_power); Self::deposit_event(Event::ScalingLawPowerSet(netuid, scaling_law_power)); } #[inline(always)] pub const fn get_max_weight_limit(_netuid: NetUid) -> u16 { u16::MAX } pub fn get_immunity_period(netuid: NetUid) -> u16 { ImmunityPeriod::::get(netuid) } pub fn set_immunity_period(netuid: NetUid, immunity_period: u16) { ImmunityPeriod::::insert(netuid, immunity_period); Self::deposit_event(Event::ImmunityPeriodSet(netuid, immunity_period)); } /// Check if a neuron is in immunity based on the current block pub fn get_neuron_is_immune(netuid: NetUid, uid: u16) -> bool { let registered_at = Self::get_neuron_block_at_registration(netuid, uid); let current_block = Self::get_current_block_as_u64(); let immunity_period = Self::get_immunity_period(netuid); current_block.saturating_sub(registered_at) < u64::from(immunity_period) } pub fn get_min_allowed_weights(netuid: NetUid) -> u16 { MinAllowedWeights::::get(netuid) } pub fn set_min_allowed_weights(netuid: NetUid, min_allowed_weights: u16) { MinAllowedWeights::::insert(netuid, min_allowed_weights); Self::deposit_event(Event::MinAllowedWeightSet(netuid, min_allowed_weights)); } pub fn get_min_allowed_uids(netuid: NetUid) -> u16 { MinAllowedUids::::get(netuid) } pub fn set_min_allowed_uids(netuid: NetUid, min_allowed: u16) { MinAllowedUids::::insert(netuid, min_allowed); Self::deposit_event(Event::MinAllowedUidsSet(netuid, min_allowed)); } pub fn get_max_allowed_uids(netuid: NetUid) -> u16 { MaxAllowedUids::::get(netuid) } pub fn set_max_allowed_uids(netuid: NetUid, max_allowed: u16) { MaxAllowedUids::::insert(netuid, max_allowed); Self::deposit_event(Event::MaxAllowedUidsSet(netuid, max_allowed)); } pub fn get_kappa(netuid: NetUid) -> u16 { Kappa::::get(netuid) } pub fn set_kappa(netuid: NetUid, kappa: u16) { Kappa::::insert(netuid, kappa); Self::deposit_event(Event::KappaSet(netuid, kappa)); } pub fn get_commit_reveal_weights_enabled(netuid: NetUid) -> bool { CommitRevealWeightsEnabled::::get(netuid) } pub fn set_commit_reveal_weights_enabled(netuid: NetUid, enabled: bool) { CommitRevealWeightsEnabled::::set(netuid, enabled); Self::deposit_event(Event::CommitRevealEnabled(netuid, enabled)); } pub fn get_commit_reveal_weights_version() -> u16 { CommitRevealWeightsVersion::::get() } pub fn set_commit_reveal_weights_version(version: u16) { CommitRevealWeightsVersion::::set(version); Self::deposit_event(Event::CommitRevealVersionSet(version)); } pub fn get_rho(netuid: NetUid) -> u16 { Rho::::get(netuid) } pub fn set_rho(netuid: NetUid, rho: u16) { Rho::::insert(netuid, rho); } pub fn get_activity_cutoff(netuid: NetUid) -> u16 { ActivityCutoff::::get(netuid) } pub fn set_activity_cutoff(netuid: NetUid, activity_cutoff: u16) { ActivityCutoff::::insert(netuid, activity_cutoff); Self::deposit_event(Event::ActivityCutoffSet(netuid, activity_cutoff)); } /// Effective activity cutoff in blocks, derived from `ActivityCutoffFactorMilli` and `Tempo`. /// `cutoff_blocks = (factor × tempo) / 1000`, clamped to ≥ 1. pub fn get_activity_cutoff_blocks(netuid: NetUid) -> u64 { let factor_milli = ActivityCutoffFactorMilli::::get(netuid) as u64; let tempo = Self::get_tempo(netuid) as u64; factor_milli .saturating_mul(tempo) .checked_div(1000) .unwrap_or(0) .max(1) } pub fn get_activity_cutoff_factor_milli(netuid: NetUid) -> u32 { ActivityCutoffFactorMilli::::get(netuid) } pub fn set_activity_cutoff_factor_milli(netuid: NetUid, factor_milli: u32) { ActivityCutoffFactorMilli::::insert(netuid, factor_milli); Self::deposit_event(Event::ActivityCutoffFactorMilliSet { netuid, factor_milli, }); } // Registration Toggle utils pub fn get_network_registration_allowed(netuid: NetUid) -> bool { NetworkRegistrationAllowed::::get(netuid) } pub fn set_network_registration_allowed(netuid: NetUid, registration_allowed: bool) { NetworkRegistrationAllowed::::insert(netuid, registration_allowed); Self::deposit_event(Event::RegistrationAllowed(netuid, registration_allowed)); } pub fn get_network_pow_registration_allowed(netuid: NetUid) -> bool { NetworkPowRegistrationAllowed::::get(netuid) } pub fn set_network_pow_registration_allowed(netuid: NetUid, registration_allowed: bool) { NetworkPowRegistrationAllowed::::insert(netuid, registration_allowed); Self::deposit_event(Event::PowRegistrationAllowed(netuid, registration_allowed)); } pub fn get_target_registrations_per_interval(netuid: NetUid) -> u16 { TargetRegistrationsPerInterval::::get(netuid) } pub fn set_target_registrations_per_interval( netuid: NetUid, target_registrations_per_interval: u16, ) { TargetRegistrationsPerInterval::::insert(netuid, target_registrations_per_interval); Self::deposit_event(Event::RegistrationPerIntervalSet( netuid, target_registrations_per_interval, )); } pub fn get_burn(netuid: NetUid) -> TaoBalance { Burn::::get(netuid) } pub fn set_burn(netuid: NetUid, burn: TaoBalance) { Burn::::insert(netuid, burn); } pub fn get_min_burn(netuid: NetUid) -> TaoBalance { MinBurn::::get(netuid) } pub fn set_min_burn(netuid: NetUid, min_burn: TaoBalance) { MinBurn::::insert(netuid, min_burn); Self::deposit_event(Event::MinBurnSet(netuid, min_burn)); } pub fn get_max_burn(netuid: NetUid) -> TaoBalance { MaxBurn::::get(netuid) } pub fn set_max_burn(netuid: NetUid, max_burn: TaoBalance) { MaxBurn::::insert(netuid, max_burn); Self::deposit_event(Event::MaxBurnSet(netuid, max_burn)); } pub fn get_difficulty_as_u64(netuid: NetUid) -> u64 { Difficulty::::get(netuid) } pub fn set_difficulty(netuid: NetUid, difficulty: u64) { Difficulty::::insert(netuid, difficulty); Self::deposit_event(Event::DifficultySet(netuid, difficulty)); } pub fn get_max_allowed_validators(netuid: NetUid) -> u16 { MaxAllowedValidators::::get(netuid) } pub fn set_max_allowed_validators(netuid: NetUid, max_allowed_validators: u16) { MaxAllowedValidators::::insert(netuid, max_allowed_validators); Self::deposit_event(Event::MaxAllowedValidatorsSet( netuid, max_allowed_validators, )); } pub fn get_bonds_moving_average(netuid: NetUid) -> u64 { BondsMovingAverage::::get(netuid) } pub fn set_bonds_moving_average(netuid: NetUid, bonds_moving_average: u64) { BondsMovingAverage::::insert(netuid, bonds_moving_average); Self::deposit_event(Event::BondsMovingAverageSet(netuid, bonds_moving_average)); } pub fn get_bonds_penalty(netuid: NetUid) -> u16 { BondsPenalty::::get(netuid) } pub fn set_bonds_penalty(netuid: NetUid, bonds_penalty: u16) { BondsPenalty::::insert(netuid, bonds_penalty); Self::deposit_event(Event::BondsPenaltySet(netuid, bonds_penalty)); } pub fn get_bonds_reset(netuid: NetUid) -> bool { BondsResetOn::::get(netuid) } pub fn set_bonds_reset(netuid: NetUid, bonds_reset: bool) { BondsResetOn::::insert(netuid, bonds_reset); Self::deposit_event(Event::BondsResetOnSet(netuid, bonds_reset)); } pub fn get_max_registrations_per_block(netuid: NetUid) -> u16 { MaxRegistrationsPerBlock::::get(netuid) } pub fn set_max_registrations_per_block(netuid: NetUid, max_registrations_per_block: u16) { MaxRegistrationsPerBlock::::insert(netuid, max_registrations_per_block); Self::deposit_event(Event::MaxRegistrationsPerBlockSet( netuid, max_registrations_per_block, )); } pub fn get_subnet_owner(netuid: NetUid) -> T::AccountId { SubnetOwner::::get(netuid) } pub fn get_subnet_owner_cut() -> u16 { SubnetOwnerCut::::get() } pub fn get_float_subnet_owner_cut() -> U96F32 { U96F32::saturating_from_num(SubnetOwnerCut::::get()) .safe_div(U96F32::saturating_from_num(u16::MAX)) } pub fn set_subnet_owner_cut(subnet_owner_cut: u16) { SubnetOwnerCut::::set(subnet_owner_cut); Self::deposit_event(Event::SubnetOwnerCutSet(subnet_owner_cut)); } pub fn get_owned_hotkeys(coldkey: &T::AccountId) -> Vec { OwnedHotkeys::::get(coldkey) } pub fn get_all_staked_hotkeys(coldkey: &T::AccountId) -> Vec { StakingHotkeys::::get(coldkey) } pub fn get_rao_recycled(netuid: NetUid) -> TaoBalance { RAORecycledForRegistration::::get(netuid) } pub fn set_rao_recycled(netuid: NetUid, rao_recycled: TaoBalance) { RAORecycledForRegistration::::insert(netuid, rao_recycled); Self::deposit_event(Event::RAORecycledForRegistrationSet(netuid, rao_recycled)); } pub fn increase_rao_recycled(netuid: NetUid, inc_rao_recycled: TaoBalance) { let curr_rao_recycled = Self::get_rao_recycled(netuid); let rao_recycled = curr_rao_recycled.saturating_add(inc_rao_recycled); Self::set_rao_recycled(netuid, rao_recycled); } pub fn is_subnet_owner(address: &T::AccountId) -> bool { SubnetOwner::::iter_values().any(|owner| *address == owner) } /// The NominatorMinRequiredStake is the factor by which we multiply /// the DefaultMinStake to get nominator minimum stake. With DefaulMinStake /// of 0.001 TAO and NominatorMinRequiredStake of 100_000_000, the /// minimum nomination stake will be 0.1 TAO. pub fn get_nominator_min_required_stake() -> u64 { // Get the factor (It is stored in per-million format) let factor = NominatorMinRequiredStake::::get(); // Return the default minimum stake multiplied by factor // 21M * 10^9 * 10^6 fits u64, hence no need for fixed type usage here DefaultMinStake::::get() .to_u64() .saturating_mul(factor) .safe_div(1_000_000) } pub fn set_nominator_min_required_stake(min_stake: u64) { NominatorMinRequiredStake::::put(min_stake); } pub fn get_key_swap_cost() -> TaoBalance { T::KeySwapCost::get().into() } pub fn get_alpha_values(netuid: NetUid) -> (u16, u16) { AlphaValues::::get(netuid) } pub fn set_alpha_values_32(netuid: NetUid, low: I32F32, high: I32F32) { let low = (low.saturating_mul(I32F32::saturating_from_num(u16::MAX))).saturating_to_num::(); let high = (high.saturating_mul(I32F32::saturating_from_num(u16::MAX))).saturating_to_num::(); AlphaValues::::insert(netuid, (low, high)); } pub fn get_alpha_values_32(netuid: NetUid) -> (I32F32, I32F32) { let (alpha_low, alpha_high): (u16, u16) = AlphaValues::::get(netuid); let converted_low = I32F32::saturating_from_num(alpha_low).safe_div(I32F32::saturating_from_num(u16::MAX)); let converted_high = I32F32::saturating_from_num(alpha_high).safe_div(I32F32::saturating_from_num(u16::MAX)); (converted_low, converted_high) } pub fn set_alpha_sigmoid_steepness(netuid: NetUid, steepness: i16) { AlphaSigmoidSteepness::::insert(netuid, steepness); } pub fn get_alpha_sigmoid_steepness(netuid: NetUid) -> I32F32 { let alpha = AlphaSigmoidSteepness::::get(netuid); I32F32::saturating_from_num(alpha) } pub fn set_liquid_alpha_enabled(netuid: NetUid, enabled: bool) { LiquidAlphaOn::::set(netuid, enabled); } pub fn get_liquid_alpha_enabled(netuid: NetUid) -> bool { LiquidAlphaOn::::get(netuid) } pub fn set_yuma3_enabled(netuid: NetUid, enabled: bool) { Yuma3On::::set(netuid, enabled); } pub fn get_yuma3_enabled(netuid: NetUid) -> bool { Yuma3On::::get(netuid) } pub fn get_subtoken_enabled(netuid: NetUid) -> bool { SubtokenEnabled::::get(netuid) } pub fn get_transfer_toggle(netuid: NetUid) -> bool { TransferToggle::::get(netuid) } pub fn set_coldkey_swap_announcement_delay(duration: BlockNumberFor) { ColdkeySwapAnnouncementDelay::::set(duration); Self::deposit_event(Event::ColdkeySwapAnnouncementDelaySet(duration)); } pub fn set_coldkey_swap_reannouncement_delay(duration: BlockNumberFor) { ColdkeySwapReannouncementDelay::::set(duration); Self::deposit_event(Event::ColdkeySwapReannouncementDelaySet(duration)); } /// Set the duration for dissolve network /// /// # Arguments /// /// * `duration`: The blocks for dissolve network execution. /// /// # Effects /// /// * Update the DissolveNetworkScheduleDuration storage. /// * Emits a DissolveNetworkScheduleDurationSet evnet. pub fn set_dissolve_network_schedule_duration(duration: BlockNumberFor) { DissolveNetworkScheduleDuration::::set(duration); Self::deposit_event(Event::DissolveNetworkScheduleDurationSet(duration)); } /// Set the owner hotkey for a subnet. /// /// # Arguments /// /// * `netuid`: The unique identifier for the subnet. /// * `hotkey`: The new hotkey for the subnet owner. /// /// # Effects /// /// * Update the SubnetOwnerHotkey storage. /// * Emits a SubnetOwnerHotkeySet event. pub fn set_subnet_owner_hotkey(netuid: NetUid, hotkey: &T::AccountId) -> DispatchResult { // Ensure that hotkey is not a special account ensure!( Self::is_subnet_account_id(hotkey).is_none(), Error::::CannotUseSystemAccount ); SubnetOwnerHotkey::::insert(netuid, hotkey.clone()); Self::deposit_event(Event::SubnetOwnerHotkeySet(netuid, hotkey.clone())); Ok(()) } // Get the uid of the Owner Hotkey for a subnet. pub fn get_owner_uid(netuid: NetUid) -> Option { match SubnetOwnerHotkey::::try_get(netuid) { Ok(owner_hotkey) => Uids::::get(netuid, &owner_hotkey), Err(_) => None, } } /// Set the per-subnet limit (for the given `netuid`) on the number of **owner-immune** /// neurons (UIDs). /// /// The value must lie within the inclusive bounds defined by [`MinImmuneOwnerUidsLimit`] /// and [`MaxImmuneOwnerUidsLimit`]. If the bound check fails, this returns /// [`Error::::InvalidValue`] and leaves storage unchanged. /// /// # Arguments /// * `netuid`: Identifier of the subnet to update. /// * `limit`: New inclusive upper bound for the count of owner-immune UIDs on this subnet. /// /// # Returns /// * `Ok(())` on success (value written to storage). /// * `Err(Error::::InvalidValue)` if `limit` is outside `[MinImmuneOwnerUidsLimit, MaxImmuneOwnerUidsLimit]`. pub fn set_owner_immune_neuron_limit(netuid: NetUid, limit: u16) -> DispatchResult { ensure!( limit >= MinImmuneOwnerUidsLimit::::get() && limit <= MaxImmuneOwnerUidsLimit::::get(), Error::::InvalidValue ); ImmuneOwnerUidsLimit::::insert(netuid, limit); Ok(()) } /// Fetches the max number of subnet /// /// # Returns /// * `u16`: The max number of subnet /// pub fn get_max_subnets() -> u16 { SubnetLimit::::get() } /// Sets the max number of subnet pub fn set_max_subnets(limit: u16) { SubnetLimit::::put(limit); Self::deposit_event(Event::SubnetLimitSet(limit)); } /// Sets TAO flow cutoff value (A) pub fn set_tao_flow_cutoff(flow_cutoff: I64F64) { TaoFlowCutoff::::set(flow_cutoff); } /// Sets TAO flow normalization exponent (p) pub fn set_tao_flow_normalization_exponent(exponent: U64F64) { FlowNormExponent::::set(exponent); } /// Sets TAO flow smoothing factor (alpha) pub fn set_tao_flow_smoothing_factor(smoothing_factor: u64) { FlowEmaSmoothingFactor::::set(smoothing_factor); } /// Enables or disables net TAO flow (protocol cost deduction from emission shares). pub fn set_net_tao_flow_enabled(enabled: bool) { NetTaoFlowEnabled::::set(enabled); } /// Multiply an integer `value` by a Q32 fixed-point factor. /// /// Q32 means: /// 1.0 == 1 << 32 /// 0.5 == 1 << 31 /// /// Safe / non-panicking: /// * uses saturating u128 multiplication /// * clamps back into u64 range pub fn mul_by_q32(value: u64, factor_q32: u64) -> u64 { let product: u128 = (value as u128).saturating_mul(factor_q32 as u128); let shifted: u128 = product >> 32; core::cmp::min(shifted, u64::MAX as u128) as u64 } /// Exponentiation-by-squaring for Q32 values. /// /// Returns `base_q32 ^ exp` in Q32. /// /// Safe / non-panicking: /// * uses `mul_by_q32`, which is saturating/clamped pub fn pow_q32(base_q32: u64, exp: u16) -> u64 { let mut result: u64 = 1u64 << 32; // 1.0 in Q32 let mut factor: u64 = base_q32; let mut power: u32 = u32::from(exp); while power > 0 { if (power & 1) == 1 { result = Self::mul_by_q32(result, factor); } power >>= 1; if power > 0 { factor = Self::mul_by_q32(factor, factor); } } result } /// Returns the per-block decay factor `f` in Q32 pub fn decay_factor_q32(half_life: u16) -> u64 { if half_life == 0 { return 1u64 << 32; // 1.0 } let one_q32: u64 = 1u64 << 32; let half_q32: u64 = 1u64 << 31; // 0.5 let mut lo: u64 = 0; let mut hi: u64 = one_q32; while lo.saturating_add(1) < hi { let span: u64 = hi.saturating_sub(lo); let mid: u64 = lo.saturating_add(span >> 1); let mid_pow: u64 = Self::pow_q32(mid, half_life); if mid_pow > half_q32 { hi = mid; } else { lo = mid; } } lo } }