From bddf9774ad41a07470b21091d183a15e014e9136 Mon Sep 17 00:00:00 2001 From: const Date: Mon, 15 Jul 2024 13:17:44 -0500 Subject: [PATCH 01/16] save --- .../src/{ => coinbase}/block_step.rs | 0 pallets/subtensor/src/coinbase/mod.rs | 2 + pallets/subtensor/src/{ => epoch}/epoch.rs | 2 +- pallets/subtensor/src/{ => epoch}/math.rs | 0 pallets/subtensor/src/epoch/mod.rs | 3 + pallets/subtensor/src/lib.rs | 2529 +++-------------- pallets/subtensor/src/macros/config.rs | 175 ++ pallets/subtensor/src/macros/dispatches.rs | 847 ++++++ pallets/subtensor/src/{ => macros}/errors.rs | 0 pallets/subtensor/src/{ => macros}/events.rs | 0 pallets/subtensor/src/macros/genesis.rs | 163 ++ pallets/subtensor/src/macros/hooks.rs | 75 + pallets/subtensor/src/macros/mod.rs | 6 + .../migrations/migrate_create_root_network.rs | 99 + .../migrations/migrate_delete_subnet_21.rs | 127 + .../src/migrations/migrate_delete_subnet_3.rs | 130 + .../migrate_fix_total_coldkey_stake.rs | 73 + .../migrate_populate_owned_hotkeys.rs | 83 + .../migrate_populate_staking_hotkeys.rs | 85 + .../migrate_to_v1_separate_emission.rs | 106 + .../migrate_to_v2_fixed_total_stake.rs | 103 + .../src/migrations/migrate_total_issuance.rs | 84 + ...igrate_transfer_ownership_to_foundation.rs | 87 + pallets/subtensor/src/migrations/mod.rs | 11 + pallets/subtensor/src/root.rs | 2 +- .../src/{ => rpc_info}/delegate_info.rs | 0 pallets/subtensor/src/rpc_info/mod.rs | 5 + .../src/{ => rpc_info}/neuron_info.rs | 0 .../src/{ => rpc_info}/stake_info.rs | 0 .../src/{ => rpc_info}/subnet_info.rs | 0 pallets/subtensor/src/weights.rs | 2 +- pallets/subtensor/tests/math.rs | 2 +- 32 files changed, 2701 insertions(+), 2100 deletions(-) rename pallets/subtensor/src/{ => coinbase}/block_step.rs (100%) create mode 100644 pallets/subtensor/src/coinbase/mod.rs rename pallets/subtensor/src/{ => epoch}/epoch.rs (99%) rename pallets/subtensor/src/{ => epoch}/math.rs (100%) create mode 100644 pallets/subtensor/src/epoch/mod.rs create mode 100644 pallets/subtensor/src/macros/config.rs create mode 100644 pallets/subtensor/src/macros/dispatches.rs rename pallets/subtensor/src/{ => macros}/errors.rs (100%) rename pallets/subtensor/src/{ => macros}/events.rs (100%) create mode 100644 pallets/subtensor/src/macros/genesis.rs create mode 100644 pallets/subtensor/src/macros/hooks.rs create mode 100644 pallets/subtensor/src/macros/mod.rs create mode 100644 pallets/subtensor/src/migrations/migrate_create_root_network.rs create mode 100644 pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs create mode 100644 pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs create mode 100644 pallets/subtensor/src/migrations/migrate_fix_total_coldkey_stake.rs create mode 100644 pallets/subtensor/src/migrations/migrate_populate_owned_hotkeys.rs create mode 100644 pallets/subtensor/src/migrations/migrate_populate_staking_hotkeys.rs create mode 100644 pallets/subtensor/src/migrations/migrate_to_v1_separate_emission.rs create mode 100644 pallets/subtensor/src/migrations/migrate_to_v2_fixed_total_stake.rs create mode 100644 pallets/subtensor/src/migrations/migrate_total_issuance.rs create mode 100644 pallets/subtensor/src/migrations/migrate_transfer_ownership_to_foundation.rs create mode 100644 pallets/subtensor/src/migrations/mod.rs rename pallets/subtensor/src/{ => rpc_info}/delegate_info.rs (100%) create mode 100644 pallets/subtensor/src/rpc_info/mod.rs rename pallets/subtensor/src/{ => rpc_info}/neuron_info.rs (100%) rename pallets/subtensor/src/{ => rpc_info}/stake_info.rs (100%) rename pallets/subtensor/src/{ => rpc_info}/subnet_info.rs (100%) diff --git a/pallets/subtensor/src/block_step.rs b/pallets/subtensor/src/coinbase/block_step.rs similarity index 100% rename from pallets/subtensor/src/block_step.rs rename to pallets/subtensor/src/coinbase/block_step.rs diff --git a/pallets/subtensor/src/coinbase/mod.rs b/pallets/subtensor/src/coinbase/mod.rs new file mode 100644 index 0000000000..e86c66b597 --- /dev/null +++ b/pallets/subtensor/src/coinbase/mod.rs @@ -0,0 +1,2 @@ +use super::*; +pub mod block_step; \ No newline at end of file diff --git a/pallets/subtensor/src/epoch.rs b/pallets/subtensor/src/epoch/epoch.rs similarity index 99% rename from pallets/subtensor/src/epoch.rs rename to pallets/subtensor/src/epoch/epoch.rs index 12c407efa7..d67eeded00 100644 --- a/pallets/subtensor/src/epoch.rs +++ b/pallets/subtensor/src/epoch/epoch.rs @@ -1,5 +1,5 @@ use super::*; -use crate::math::*; +use crate::epoch::math::*; use frame_support::IterableStorageDoubleMap; use sp_std::vec; use substrate_fixed::types::{I32F32, I64F64, I96F32}; diff --git a/pallets/subtensor/src/math.rs b/pallets/subtensor/src/epoch/math.rs similarity index 100% rename from pallets/subtensor/src/math.rs rename to pallets/subtensor/src/epoch/math.rs diff --git a/pallets/subtensor/src/epoch/mod.rs b/pallets/subtensor/src/epoch/mod.rs new file mode 100644 index 0000000000..74f3b10944 --- /dev/null +++ b/pallets/subtensor/src/epoch/mod.rs @@ -0,0 +1,3 @@ +use super::*; +pub mod math; +pub mod epoch; \ No newline at end of file diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 8d713d76a1..528c062295 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -35,11 +35,12 @@ mod benchmarks; // ========================= // ==== Pallet Imports ===== // ========================= -mod block_step; +mod rpc_info; +mod coinbase; mod epoch; -mod errors; -mod events; -pub mod math; +mod macros; +use macros::{events, errors, dispatches, genesis, hooks, config}; + mod registration; mod root; mod serving; @@ -49,18 +50,17 @@ mod uids; mod utils; mod weights; -pub mod delegate_info; -pub mod neuron_info; -pub mod stake_info; -pub mod subnet_info; - // apparently this is stabilized since rust 1.36 extern crate alloc; -pub mod migration; +pub mod migrations; #[deny(missing_docs)] #[import_section(errors::errors)] #[import_section(events::events)] +#[import_section(dispatches::dispatches)] +#[import_section(genesis::genesis)] +#[import_section(hooks::hooks)] +#[import_section(config::config)] #[frame_support::pallet] pub mod pallet { @@ -69,14 +69,13 @@ pub mod pallet { pallet_prelude::{DispatchResult, StorageMap, ValueQuery, *}, traits::{tokens::fungible, UnfilteredDispatchable}, }; + use crate::migrations; use frame_system::pallet_prelude::*; use sp_core::H256; use sp_runtime::traits::TrailingZeroInput; use sp_std::vec; use sp_std::vec::Vec; - use subtensor_macros::freeze_struct; - #[cfg(not(feature = "std"))] use alloc::boxed::Box; #[cfg(feature = "std")] @@ -94,653 +93,13 @@ pub mod pallet { #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); - /// Configure the pallet by specifying the parameters and types on which it depends. - #[pallet::config] - pub trait Config: frame_system::Config { - /// Because this pallet emits events, it depends on the runtime's definition of an event. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - /// A sudo-able call. - type SudoRuntimeCall: Parameter - + UnfilteredDispatchable - + GetDispatchInfo; - - /// Origin checking for council majority - type CouncilOrigin: EnsureOrigin; - - /// Currency type that will be used to place deposits on neurons - type Currency: fungible::Balanced - + fungible::Mutate; - - /// Senate members with members management functions. - type SenateMembers: crate::MemberManagement; - - /// Interface to allow other pallets to control who can register identities - type TriumvirateInterface: crate::CollectiveInterface; - - /// ================================= - /// ==== Initial Value Constants ==== - /// ================================= - - /// Initial currency issuance. - #[pallet::constant] - type InitialIssuance: Get; - /// Initial min allowed weights setting. - #[pallet::constant] - type InitialMinAllowedWeights: Get; - /// Initial Emission Ratio. - #[pallet::constant] - type InitialEmissionValue: Get; - /// Initial max weight limit. - #[pallet::constant] - type InitialMaxWeightsLimit: Get; - /// Tempo for each network. - #[pallet::constant] - type InitialTempo: Get; - /// Initial Difficulty. - #[pallet::constant] - type InitialDifficulty: Get; - /// Initial Max Difficulty. - #[pallet::constant] - type InitialMaxDifficulty: Get; - /// Initial Min Difficulty. - #[pallet::constant] - type InitialMinDifficulty: Get; - /// Initial RAO Recycled. - #[pallet::constant] - type InitialRAORecycledForRegistration: Get; - /// Initial Burn. - #[pallet::constant] - type InitialBurn: Get; - /// Initial Max Burn. - #[pallet::constant] - type InitialMaxBurn: Get; - /// Initial Min Burn. - #[pallet::constant] - type InitialMinBurn: Get; - /// Initial adjustment interval. - #[pallet::constant] - type InitialAdjustmentInterval: Get; - /// Initial bonds moving average. - #[pallet::constant] - type InitialBondsMovingAverage: Get; - /// Initial target registrations per interval. - #[pallet::constant] - type InitialTargetRegistrationsPerInterval: Get; - /// Rho constant. - #[pallet::constant] - type InitialRho: Get; - /// Kappa constant. - #[pallet::constant] - type InitialKappa: Get; - /// Max UID constant. - #[pallet::constant] - type InitialMaxAllowedUids: Get; - /// Initial validator context pruning length. - #[pallet::constant] - type InitialValidatorPruneLen: Get; - /// Initial scaling law power. - #[pallet::constant] - type InitialScalingLawPower: Get; - /// Immunity Period Constant. - #[pallet::constant] - type InitialImmunityPeriod: Get; - /// Activity constant. - #[pallet::constant] - type InitialActivityCutoff: Get; - /// Initial max registrations per block. - #[pallet::constant] - type InitialMaxRegistrationsPerBlock: Get; - /// Initial pruning score for each neuron. - #[pallet::constant] - type InitialPruningScore: Get; - /// Initial maximum allowed validators per network. - #[pallet::constant] - type InitialMaxAllowedValidators: Get; - /// Initial default delegation take. - #[pallet::constant] - type InitialDefaultTake: Get; - /// Initial minimum delegation take. - #[pallet::constant] - type InitialMinTake: Get; - /// Initial weights version key. - #[pallet::constant] - type InitialWeightsVersionKey: Get; - /// Initial serving rate limit. - #[pallet::constant] - type InitialServingRateLimit: Get; - /// Initial transaction rate limit. - #[pallet::constant] - type InitialTxRateLimit: Get; - /// Initial delegate take transaction rate limit. - #[pallet::constant] - type InitialTxDelegateTakeRateLimit: Get; - /// Initial percentage of total stake required to join senate. - #[pallet::constant] - type InitialSenateRequiredStakePercentage: Get; - /// Initial adjustment alpha on burn and pow. - #[pallet::constant] - type InitialAdjustmentAlpha: Get; - /// Initial network immunity period - #[pallet::constant] - type InitialNetworkImmunityPeriod: Get; - /// Initial minimum allowed network UIDs - #[pallet::constant] - type InitialNetworkMinAllowedUids: Get; - /// Initial network minimum burn cost - #[pallet::constant] - type InitialNetworkMinLockCost: Get; - /// Initial network subnet cut. - #[pallet::constant] - type InitialSubnetOwnerCut: Get; - /// Initial lock reduction interval. - #[pallet::constant] - type InitialNetworkLockReductionInterval: Get; - /// Initial max allowed subnets - #[pallet::constant] - type InitialSubnetLimit: Get; - /// Initial network creation rate limit - #[pallet::constant] - type InitialNetworkRateLimit: Get; - /// Initial target stakes per interval issuance. - #[pallet::constant] - type InitialTargetStakesPerInterval: Get; - /// Cost of swapping a hotkey. - #[pallet::constant] - type KeySwapCost: Get; - /// The upper bound for the alpha parameter. Used for Liquid Alpha. - #[pallet::constant] - type AlphaHigh: Get; - /// The lower bound for the alpha parameter. Used for Liquid Alpha. - #[pallet::constant] - type AlphaLow: Get; - /// A flag to indicate if Liquid Alpha is enabled. - #[pallet::constant] - type LiquidAlphaOn: Get; - /// The base difficulty for proof of work for coldkey swaps - #[pallet::constant] - type InitialBaseDifficulty: Get; - } - /// Alias for the account ID. pub type AccountIdOf = ::AccountId; - /// Senate requirements - #[pallet::type_value] - pub fn DefaultSenateRequiredStakePercentage() -> u64 { - T::InitialSenateRequiredStakePercentage::get() - } - - #[pallet::storage] - pub(super) type SenateRequiredStakePercentage = - StorageValue<_, u64, ValueQuery, DefaultSenateRequiredStakePercentage>; - - /// ============================ - /// ==== Staking + Accounts ==== - /// ============================ - - /// Total Rao in circulation. - #[pallet::type_value] - pub fn TotalSupply() -> u64 { - 21_000_000_000_000_000 // Rao => 21_000_000 Tao - } - /// Default total stake. - #[pallet::type_value] - pub fn DefaultDefaultTake() -> u16 { - T::InitialDefaultTake::get() - } - /// Default minimum take. - #[pallet::type_value] - pub fn DefaultMinTake() -> u16 { - T::InitialMinTake::get() - } - /// Default account take. - #[pallet::type_value] - pub fn DefaultAccountTake() -> u64 { - 0 - } - /// Default stakes per interval. - #[pallet::type_value] - pub fn DefaultStakesPerInterval() -> (u64, u64) { - (0, 0) - } - /// Default emission per block. - #[pallet::type_value] - pub fn DefaultBlockEmission() -> u64 { - 1_000_000_000 - } - /// Default allowed delegation. - #[pallet::type_value] - pub fn DefaultAllowsDelegation() -> bool { - false - } - /// Default total issuance. - #[pallet::type_value] - pub fn DefaultTotalIssuance() -> u64 { - T::InitialIssuance::get() - } - /// Default account, derived from zero trailing bytes. - #[pallet::type_value] - pub fn DefaultAccount() -> T::AccountId { - T::AccountId::decode(&mut TrailingZeroInput::zeroes()) - .expect("trailing zeroes always produce a valid account ID; qed") - } - /// Default target stakes per interval. - #[pallet::type_value] - pub fn DefaultTargetStakesPerInterval() -> u64 { - T::InitialTargetStakesPerInterval::get() - } - /// Default stake interval. - #[pallet::type_value] - pub fn DefaultStakeInterval() -> u64 { - 360 - } - - /// Default base difficulty for proof of work for coldkey swaps - #[pallet::type_value] - pub fn DefaultBaseDifficulty() -> u64 { - T::InitialBaseDifficulty::get() - } - - #[pallet::storage] // --- ITEM ( total_stake ) - pub type TotalStake = StorageValue<_, u64, ValueQuery>; - #[pallet::storage] // --- ITEM ( default_take ) - pub type MaxTake = StorageValue<_, u16, ValueQuery, DefaultDefaultTake>; - #[pallet::storage] // --- ITEM ( min_take ) - pub type MinTake = StorageValue<_, u16, ValueQuery, DefaultMinTake>; - #[pallet::storage] // --- ITEM ( global_block_emission ) - pub type BlockEmission = StorageValue<_, u64, ValueQuery, DefaultBlockEmission>; - #[pallet::storage] // --- ITEM ( total_issuance ) - pub type TotalIssuance = StorageValue<_, u64, ValueQuery, DefaultTotalIssuance>; - #[pallet::storage] // --- ITEM (target_stakes_per_interval) - pub type TargetStakesPerInterval = - StorageValue<_, u64, ValueQuery, DefaultTargetStakesPerInterval>; - - #[pallet::storage] // --- ITEM ( base_difficulty ) - pub type BaseDifficulty = StorageValue<_, u64, ValueQuery, DefaultBaseDifficulty>; - #[pallet::storage] // --- ITEM (default_stake_interval) - pub type StakeInterval = StorageValue<_, u64, ValueQuery, DefaultStakeInterval>; - #[pallet::storage] // --- MAP ( hot ) --> stake | Returns the total amount of stake under a hotkey. - pub type TotalHotkeyStake = - StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultAccountTake>; - #[pallet::storage] // --- MAP ( cold ) --> stake | Returns the total amount of stake under a coldkey. - pub type TotalColdkeyStake = - StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultAccountTake>; - #[pallet::storage] - /// MAP (hot, cold) --> stake | Returns a tuple (u64: stakes, u64: block_number) - pub type TotalHotkeyColdkeyStakesThisInterval = StorageDoubleMap< - _, - Identity, - T::AccountId, - Identity, - T::AccountId, - (u64, u64), - ValueQuery, - DefaultStakesPerInterval, - >; - #[pallet::storage] // --- MAP ( hot ) --> cold | Returns the controlling coldkey for a hotkey. - pub type Owner = - StorageMap<_, Blake2_128Concat, T::AccountId, T::AccountId, ValueQuery, DefaultAccount>; - #[pallet::storage] // --- MAP ( cold ) --> Vec | Returns the vector of hotkeys controlled by this coldkey. - pub type OwnedHotkeys = - StorageMap<_, Blake2_128Concat, T::AccountId, Vec, ValueQuery>; - #[pallet::storage] // --- DMAP ( cold ) --> Vec | Maps coldkey to hotkeys that stake to it - pub type StakingHotkeys = - StorageMap<_, Blake2_128Concat, T::AccountId, Vec, ValueQuery>; - #[pallet::storage] // --- MAP ( hot ) --> take | Returns the hotkey delegation take. And signals that this key is open for delegation. - pub type Delegates = - StorageMap<_, Blake2_128Concat, T::AccountId, u16, ValueQuery, DefaultDefaultTake>; - #[pallet::storage] // --- DMAP ( hot, cold ) --> stake | Returns the stake under a coldkey prefixed by hotkey. - pub type Stake = StorageDoubleMap< - _, - Blake2_128Concat, - T::AccountId, - Identity, - T::AccountId, - u64, - ValueQuery, - DefaultAccountTake, - >; - - #[pallet::type_value] - /// Default value for hotkeys. - pub fn EmptyAccounts() -> Vec { - vec![] - } - #[pallet::type_value] - /// Default arbitration period. - /// This value represents the default arbitration period in blocks. - /// The period is set to 18 hours, assuming a block time of 12 seconds. - pub fn DefaultArbitrationPeriod() -> u64 { - 7200 * 3 // 3 days - } - #[pallet::storage] // ---- StorageItem Global Used Work. - pub type ArbitrationPeriod = - StorageValue<_, u64, ValueQuery, DefaultArbitrationPeriod>; - #[pallet::storage] // --- MAP ( cold ) --> Vec | Returns a list of keys to drain to, if there are two, we extend the period. - pub type ColdkeySwapDestinations = StorageMap< - _, - Blake2_128Concat, - T::AccountId, - Vec, - ValueQuery, - EmptyAccounts, - >; - #[pallet::storage] // --- MAP ( cold ) --> u64 | Block when the coldkey will be arbitrated. - pub type ColdkeyArbitrationBlock = - StorageMap<_, Blake2_128Concat, T::AccountId, u64, ValueQuery>; - #[pallet::storage] // --- MAP ( u64 ) --> Vec | Coldkeys to drain on the specific block. - pub type ColdkeysToSwapAtBlock = - StorageMap<_, Identity, u64, Vec, ValueQuery, EmptyAccounts>; - /// -- ITEM (switches liquid alpha on) - #[pallet::type_value] - pub fn DefaultLiquidAlpha() -> bool { - false - } - #[pallet::storage] // --- MAP ( netuid ) --> Whether or not Liquid Alpha is enabled - pub type LiquidAlphaOn = - StorageMap<_, Blake2_128Concat, u16, bool, ValueQuery, DefaultLiquidAlpha>; - - /// ===================================== - /// ==== Difficulty / Registrations ===== - /// ===================================== - - /// Default last adjustment block. - #[pallet::type_value] - pub fn DefaultLastAdjustmentBlock() -> u64 { - 0 - } - /// Default registrations this block. - #[pallet::type_value] - pub fn DefaultRegistrationsThisBlock() -> u16 { - 0 - } - /// Default burn token. - #[pallet::type_value] - pub fn DefaultBurn() -> u64 { - T::InitialBurn::get() - } - /// Default min burn token. - #[pallet::type_value] - pub fn DefaultMinBurn() -> u64 { - T::InitialMinBurn::get() - } - /// Default max burn token. - #[pallet::type_value] - pub fn DefaultMaxBurn() -> u64 { - T::InitialMaxBurn::get() - } - /// Default difficulty value. - #[pallet::type_value] - pub fn DefaultDifficulty() -> u64 { - T::InitialDifficulty::get() - } - /// Default min difficulty value. - #[pallet::type_value] - pub fn DefaultMinDifficulty() -> u64 { - T::InitialMinDifficulty::get() - } - /// Default max difficulty value. - #[pallet::type_value] - pub fn DefaultMaxDifficulty() -> u64 { - T::InitialMaxDifficulty::get() - } - /// Default max registrations per block. - #[pallet::type_value] - pub fn DefaultMaxRegistrationsPerBlock() -> u16 { - T::InitialMaxRegistrationsPerBlock::get() - } - /// Default RAO recycled for registration. - #[pallet::type_value] - pub fn DefaultRAORecycledForRegistration() -> u64 { - T::InitialRAORecycledForRegistration::get() - } - - #[pallet::storage] // ---- StorageItem Global Used Work. - pub type UsedWork = StorageMap<_, Identity, Vec, u64, ValueQuery>; - #[pallet::storage] // --- MAP ( netuid ) --> Burn - pub type Burn = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultBurn>; - #[pallet::storage] // --- MAP ( netuid ) --> Difficulty - pub type Difficulty = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultDifficulty>; - #[pallet::storage] // --- MAP ( netuid ) --> MinBurn - pub type MinBurn = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultMinBurn>; - #[pallet::storage] // --- MAP ( netuid ) --> MaxBurn - pub type MaxBurn = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultMaxBurn>; - #[pallet::storage] // --- MAP ( netuid ) --> MinDifficulty - pub type MinDifficulty = - StorageMap<_, Identity, u16, u64, ValueQuery, DefaultMinDifficulty>; - #[pallet::storage] // --- MAP ( netuid ) --> MaxDifficulty - pub type MaxDifficulty = - StorageMap<_, Identity, u16, u64, ValueQuery, DefaultMaxDifficulty>; - #[pallet::storage] // --- MAP ( netuid ) --> Block at last adjustment. - pub type LastAdjustmentBlock = - StorageMap<_, Identity, u16, u64, ValueQuery, DefaultLastAdjustmentBlock>; - #[pallet::storage] // --- MAP ( netuid ) --> Registrations of this Block. - pub type RegistrationsThisBlock = - StorageMap<_, Identity, u16, u16, ValueQuery, DefaultRegistrationsThisBlock>; - #[pallet::storage] // --- ITEM( global_max_registrations_per_block ) - pub type MaxRegistrationsPerBlock = - StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMaxRegistrationsPerBlock>; - #[pallet::storage] // --- MAP ( netuid, global_RAO_recycled_for_registration ) - pub type RAORecycledForRegistration = - StorageMap<_, Identity, u16, u64, ValueQuery, DefaultRAORecycledForRegistration>; - - /// ============================== - /// ==== Subnetworks Storage ===== - /// ============================== - - /// Default number of networks. - #[pallet::type_value] - pub fn DefaultN() -> u16 { - 0 - } - /// Default value for modality. - #[pallet::type_value] - pub fn DefaultModality() -> u16 { - 0 - } - /// Default value for hotkeys. - #[pallet::type_value] - pub fn DefaultHotkeys() -> Vec { - vec![] - } - /// Default value if network is added. - #[pallet::type_value] - pub fn DefaultNeworksAdded() -> bool { - false - } - /// Default value for network member. - #[pallet::type_value] - pub fn DefaultIsNetworkMember() -> bool { - false - } - /// Default value for registration allowed. - #[pallet::type_value] - pub fn DefaultRegistrationAllowed() -> bool { - false - } - /// Default value for network registered at. - #[pallet::type_value] - pub fn DefaultNetworkRegisteredAt() -> u64 { - 0 - } - /// Default value for network immunity period. - #[pallet::type_value] - pub fn DefaultNetworkImmunityPeriod() -> u64 { - T::InitialNetworkImmunityPeriod::get() - } - /// Default value for network last registered. - #[pallet::type_value] - pub fn DefaultNetworkLastRegistered() -> u64 { - 0 - } - /// Default value for nominator min required stake. - #[pallet::type_value] - pub fn DefaultNominatorMinRequiredStake() -> u64 { - 0 - } - /// Default value for network min allowed UIDs. - #[pallet::type_value] - pub fn DefaultNetworkMinAllowedUids() -> u16 { - T::InitialNetworkMinAllowedUids::get() - } - /// Default value for network min lock cost. - #[pallet::type_value] - pub fn DefaultNetworkMinLockCost() -> u64 { - T::InitialNetworkMinLockCost::get() - } - /// Default value for network lock reduction interval. - #[pallet::type_value] - pub fn DefaultNetworkLockReductionInterval() -> u64 { - T::InitialNetworkLockReductionInterval::get() - } - /// Default value for subnet owner cut. - #[pallet::type_value] - pub fn DefaultSubnetOwnerCut() -> u16 { - T::InitialSubnetOwnerCut::get() - } - /// Default value for subnet limit. - #[pallet::type_value] - pub fn DefaultSubnetLimit() -> u16 { - T::InitialSubnetLimit::get() - } - /// Default value for network rate limit. - #[pallet::type_value] - pub fn DefaultNetworkRateLimit() -> u64 { - if cfg!(feature = "pow-faucet") { - return 0; - } - - T::InitialNetworkRateLimit::get() - } - - #[pallet::storage] // --- ITEM( maximum_number_of_networks ) - pub type SubnetLimit = StorageValue<_, u16, ValueQuery, DefaultSubnetLimit>; - #[pallet::storage] // --- ITEM( total_number_of_existing_networks ) - pub type TotalNetworks = StorageValue<_, u16, ValueQuery>; - #[pallet::storage] // --- MAP ( netuid ) --> subnetwork_n (Number of UIDs in the network). - pub type SubnetworkN = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultN>; - #[pallet::storage] // --- MAP ( netuid ) --> modality TEXT: 0, IMAGE: 1, TENSOR: 2 - pub type NetworkModality = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultModality>; - #[pallet::storage] // --- MAP ( netuid ) --> network_is_added - pub type NetworksAdded = - StorageMap<_, Identity, u16, bool, ValueQuery, DefaultNeworksAdded>; - #[pallet::storage] // --- DMAP ( hotkey, netuid ) --> bool - pub type IsNetworkMember = StorageDoubleMap< - _, - Blake2_128Concat, - T::AccountId, - Identity, - u16, - bool, - ValueQuery, - DefaultIsNetworkMember, - >; - #[pallet::storage] // --- MAP ( netuid ) --> network_registration_allowed - pub type NetworkRegistrationAllowed = - StorageMap<_, Identity, u16, bool, ValueQuery, DefaultRegistrationAllowed>; - #[pallet::storage] // --- MAP ( netuid ) --> network_pow_allowed - pub type NetworkPowRegistrationAllowed = - StorageMap<_, Identity, u16, bool, ValueQuery, DefaultRegistrationAllowed>; - #[pallet::storage] // --- MAP ( netuid ) --> block_created - pub type NetworkRegisteredAt = - StorageMap<_, Identity, u16, u64, ValueQuery, DefaultNetworkRegisteredAt>; - #[pallet::storage] // ITEM( network_immunity_period ) - pub type NetworkImmunityPeriod = - StorageValue<_, u64, ValueQuery, DefaultNetworkImmunityPeriod>; - #[pallet::storage] // ITEM( network_last_registered_block ) - pub type NetworkLastRegistered = - StorageValue<_, u64, ValueQuery, DefaultNetworkLastRegistered>; - #[pallet::storage] // ITEM( network_min_allowed_uids ) - pub type NetworkMinAllowedUids = - StorageValue<_, u16, ValueQuery, DefaultNetworkMinAllowedUids>; - #[pallet::storage] // ITEM( min_network_lock_cost ) - pub type NetworkMinLockCost = StorageValue<_, u64, ValueQuery, DefaultNetworkMinLockCost>; - #[pallet::storage] // ITEM( last_network_lock_cost ) - pub type NetworkLastLockCost = - StorageValue<_, u64, ValueQuery, DefaultNetworkMinLockCost>; - #[pallet::storage] // ITEM( network_lock_reduction_interval ) - pub type NetworkLockReductionInterval = - StorageValue<_, u64, ValueQuery, DefaultNetworkLockReductionInterval>; - #[pallet::storage] // ITEM( subnet_owner_cut ) - pub type SubnetOwnerCut = StorageValue<_, u16, ValueQuery, DefaultSubnetOwnerCut>; - #[pallet::storage] // ITEM( network_rate_limit ) - pub type NetworkRateLimit = StorageValue<_, u64, ValueQuery, DefaultNetworkRateLimit>; - #[pallet::storage] // ITEM( nominator_min_required_stake ) - pub type NominatorMinRequiredStake = - StorageValue<_, u64, ValueQuery, DefaultNominatorMinRequiredStake>; - - /// ============================== - /// ==== Subnetwork Features ===== - /// ============================== - - /// Default value for emission values. - #[pallet::type_value] - pub fn DefaultEmissionValues() -> u64 { - 0 - } - /// Default value for pending emission. - #[pallet::type_value] - pub fn DefaultPendingEmission() -> u64 { - 0 - } - /// Default value for blocks since last step. - #[pallet::type_value] - pub fn DefaultBlocksSinceLastStep() -> u64 { - 0 - } - /// Default value for last mechanism step block. - #[pallet::type_value] - pub fn DefaultLastMechanismStepBlock() -> u64 { - 0 - } - /// Default value for subnet owner. - #[pallet::type_value] - pub fn DefaultSubnetOwner() -> T::AccountId { - T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) - .expect("trailing zeroes always produce a valid account ID; qed") - } - /// Default value for subnet locked. - #[pallet::type_value] - pub fn DefaultSubnetLocked() -> u64 { - 0 - } - /// Default value for network tempo - #[pallet::type_value] - pub fn DefaultTempo() -> u16 { - T::InitialTempo::get() - } - - #[pallet::storage] // --- MAP ( netuid ) --> tempo - pub type Tempo = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultTempo>; - #[pallet::storage] // --- MAP ( netuid ) --> emission_values - pub type EmissionValues = - StorageMap<_, Identity, u16, u64, ValueQuery, DefaultEmissionValues>; - #[pallet::storage] // --- MAP ( netuid ) --> pending_emission - pub type PendingEmission = - StorageMap<_, Identity, u16, u64, ValueQuery, DefaultPendingEmission>; - #[pallet::storage] // --- MAP ( netuid ) --> blocks_since_last_step - pub type BlocksSinceLastStep = - StorageMap<_, Identity, u16, u64, ValueQuery, DefaultBlocksSinceLastStep>; - #[pallet::storage] // --- MAP ( netuid ) --> last_mechanism_step_block - pub type LastMechansimStepBlock = - StorageMap<_, Identity, u16, u64, ValueQuery, DefaultLastMechanismStepBlock>; - #[pallet::storage] // --- MAP ( netuid ) --> subnet_owner - pub type SubnetOwner = - StorageMap<_, Identity, u16, T::AccountId, ValueQuery, DefaultSubnetOwner>; - #[pallet::storage] // --- MAP ( netuid ) --> subnet_locked - pub type SubnetLocked = - StorageMap<_, Identity, u16, u64, ValueQuery, DefaultSubnetLocked>; - - /// ================================= - /// ==== Axon / Promo Endpoints ===== - /// ================================= - /// Struct for Axon. pub type AxonInfoOf = AxonInfo; /// Data structure for Axon information. - #[freeze_struct("3545cfb0cac4c1f5")] #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)] pub struct AxonInfo { /// Axon serving block. @@ -764,7 +123,6 @@ pub mod pallet { /// Struct for Prometheus. pub type PrometheusInfoOf = PrometheusInfo; /// Data structure for Prometheus information. - #[freeze_struct("5dde687e63baf0cd")] #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)] pub struct PrometheusInfo { /// Prometheus serving block. @@ -779,366 +137,452 @@ pub mod pallet { pub ip_type: u8, } - /// Default value for rate limiting - #[pallet::type_value] - pub fn DefaultTxRateLimit() -> u64 { - T::InitialTxRateLimit::get() - } - /// Default value for delegate take rate limiting - #[pallet::type_value] - pub fn DefaultTxDelegateTakeRateLimit() -> u64 { - T::InitialTxDelegateTakeRateLimit::get() - } - /// Default value for last extrinsic block. - #[pallet::type_value] - pub fn DefaultLastTxBlock() -> u64 { - 0 - } - #[pallet::storage] // --- ITEM ( tx_rate_limit ) - pub(super) type TxRateLimit = StorageValue<_, u64, ValueQuery, DefaultTxRateLimit>; - #[pallet::storage] // --- ITEM ( tx_rate_limit ) - pub(super) type TxDelegateTakeRateLimit = - StorageValue<_, u64, ValueQuery, DefaultTxDelegateTakeRateLimit>; - #[pallet::storage] // --- MAP ( key ) --> last_block - pub type LastTxBlock = - StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; - #[pallet::storage] // --- MAP ( key ) --> last_block - pub(super) type LastTxBlockDelegateTake = - StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; - - /// Default value for serving rate limit. - #[pallet::type_value] - pub fn DefaultServingRateLimit() -> u64 { - T::InitialServingRateLimit::get() - } + /// ============================ + /// ==== Staking + Accounts ==== + /// ============================ - #[pallet::storage] // --- MAP ( netuid ) --> serving_rate_limit - pub type ServingRateLimit = - StorageMap<_, Identity, u16, u64, ValueQuery, DefaultServingRateLimit>; - #[pallet::storage] // --- MAP ( netuid, hotkey ) --> axon_info - pub type Axons = - StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, AxonInfoOf, OptionQuery>; - #[pallet::storage] // --- MAP ( netuid, hotkey ) --> prometheus_info - pub type Prometheus = StorageDoubleMap< - _, - Identity, - u16, - Blake2_128Concat, - T::AccountId, - PrometheusInfoOf, - OptionQuery, - >; + #[pallet::type_value] /// Total Rao in circulation. + pub fn TotalSupply() -> u64 { 21_000_000_000_000_000 } + #[pallet::type_value] /// Default total stake. + pub fn DefaultDefaultTake() -> u16 { T::InitialDefaultTake::get() } + #[pallet::type_value] /// Default minimum take. + pub fn DefaultMinTake() -> u16 { T::InitialMinTake::get() } + #[pallet::type_value] /// Default account take. + pub fn DefaultAccountTake() -> u64 { 0 } + #[pallet::type_value] /// Default stakes per interval. + pub fn DefaultStakesPerInterval() -> (u64, u64) { (0, 0) } + #[pallet::type_value] /// Default emission per block. + pub fn DefaultBlockEmission() -> u64 { 1_000_000_000 } + #[pallet::type_value] /// Default allowed delegation. + pub fn DefaultAllowsDelegation() -> bool { false } + #[pallet::type_value] /// Default total issuance. + pub fn DefaultTotalIssuance() -> u64 { T::InitialIssuance::get() } + #[pallet::type_value] /// Default account, derived from zero trailing bytes. + pub fn DefaultAccount() -> T::AccountId { T::AccountId::decode(&mut TrailingZeroInput::zeroes()).expect("trailing zeroes always produce a valid account ID; qed") } + #[pallet::type_value] /// Default target stakes per interval. + pub fn DefaultTargetStakesPerInterval() -> u64 { T::InitialTargetStakesPerInterval::get() } + #[pallet::type_value] /// Default stake interval. + pub fn DefaultStakeInterval() -> u64 { 360 } + #[pallet::type_value] /// Default account linkage + pub fn DefaultAccountLinkage() -> Vec<(u64, T::AccountId)> { vec![] } + #[pallet::type_value] /// Default account linkage + pub fn DefaultProportion() -> u64 { 0 } + #[pallet::type_value] /// Default accumulated emission for a hotkey + pub fn DefaultAccumulatedEmission() -> u64 { 0 } + #[pallet::type_value] /// Default last adjustment block. + pub fn DefaultLastAdjustmentBlock() -> u64 { 0 } + #[pallet::type_value] /// Default last adjustment block. + pub fn DefaultRegistrationsThisBlock() -> u16 { 0 } + #[pallet::type_value] /// Default registrations this block. + pub fn DefaultBurn() -> u64 { T::InitialBurn::get() } + #[pallet::type_value] /// Default burn token. + pub fn DefaultMinBurn() -> u64 { T::InitialMinBurn::get() } + #[pallet::type_value] /// Default min burn token. + pub fn DefaultMaxBurn() -> u64 { T::InitialMaxBurn::get() } + #[pallet::type_value] /// Default max burn token. + pub fn DefaultDifficulty() -> u64 { T::InitialDifficulty::get() } + #[pallet::type_value] /// Default difficulty value. + pub fn DefaultMinDifficulty() -> u64 { T::InitialMinDifficulty::get() } + #[pallet::type_value] /// Default min difficulty value. + pub fn DefaultMaxDifficulty() -> u64 { T::InitialMaxDifficulty::get() } + #[pallet::type_value] /// Default max difficulty value. + pub fn DefaultMaxRegistrationsPerBlock() -> u16 { T::InitialMaxRegistrationsPerBlock::get() } + #[pallet::type_value] /// Default max registrations per block. + pub fn DefaultRAORecycledForRegistration() -> u64 { T::InitialRAORecycledForRegistration::get() } + #[pallet::type_value] /// Default number of networks. + pub fn DefaultN() -> u16 { 0 } + #[pallet::type_value] /// Default value for modality. + pub fn DefaultModality() -> u16 { 0 } + #[pallet::type_value] /// Default value for hotkeys. + pub fn DefaultHotkeys() -> Vec { vec![] } + #[pallet::type_value] /// Default value if network is added. + pub fn DefaultNeworksAdded() -> bool { false } + #[pallet::type_value] /// Default value for network member. + pub fn DefaultIsNetworkMember() -> bool { false } + #[pallet::type_value] /// Default value for registration allowed. + pub fn DefaultRegistrationAllowed() -> bool { false } + #[pallet::type_value] /// Default value for network registered at. + pub fn DefaultNetworkRegisteredAt() -> u64 { 0 } + #[pallet::type_value] /// Default value for network immunity period. + pub fn DefaultNetworkImmunityPeriod() -> u64 { T::InitialNetworkImmunityPeriod::get() } + #[pallet::type_value] /// Default value for network last registered. + pub fn DefaultNetworkLastRegistered() -> u64 { 0 } + #[pallet::type_value] /// Default value for nominator min required stake. + pub fn DefaultNominatorMinRequiredStake() -> u64 { 0 } + #[pallet::type_value] /// Default value for network min allowed UIDs. + pub fn DefaultNetworkMinAllowedUids() -> u16 { T::InitialNetworkMinAllowedUids::get() } + #[pallet::type_value] /// Default value for network min lock cost. + pub fn DefaultNetworkMinLockCost() -> u64 { T::InitialNetworkMinLockCost::get() } + #[pallet::type_value] /// Default value for network lock reduction interval. + pub fn DefaultNetworkLockReductionInterval() -> u64 { T::InitialNetworkLockReductionInterval::get() } + #[pallet::type_value] /// Default value for subnet owner cut. + pub fn DefaultSubnetOwnerCut() -> u16 { T::InitialSubnetOwnerCut::get() } + #[pallet::type_value] /// Default value for subnet limit. + pub fn DefaultSubnetLimit() -> u16 { T::InitialSubnetLimit::get() } + #[pallet::type_value] /// Default value for network rate limit. + pub fn DefaultNetworkRateLimit() -> u64 { if cfg!(feature = "pow-faucet") { return 0; } T::InitialNetworkRateLimit::get() } + // #[pallet::type_value] /// Default value for network max stake. + // pub fn DefaultNetworkMaxStake() -> u64 { T::InitialNetworkMaxStake::get() } + #[pallet::type_value] /// Default value for emission values. + pub fn DefaultEmissionValues() -> u64 { 0 } + #[pallet::type_value] /// Default value for pending emission. + pub fn DefaultPendingEmission() -> u64 { 0 } + #[pallet::type_value] /// Default value for blocks since last step. + pub fn DefaultBlocksSinceLastStep() -> u64 { 0 } + #[pallet::type_value] /// Default value for last mechanism step block. + pub fn DefaultLastMechanismStepBlock() -> u64 { 0 } + #[pallet::type_value] /// Default value for subnet owner. + pub fn DefaultSubnetOwner() -> T::AccountId { T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).expect("trailing zeroes always produce a valid account ID; qed") } + #[pallet::type_value] /// Default value for subnet locked. + pub fn DefaultSubnetLocked() -> u64 { 0 } + #[pallet::type_value] /// Default value for network tempo + pub fn DefaultTempo() -> u16 { T::InitialTempo::get() } + #[pallet::type_value] /// Default value for weights set rate limit. + pub fn DefaultWeightsSetRateLimit() -> u64 { 100 } + #[pallet::type_value] /// Default block number at registration. + pub fn DefaultBlockAtRegistration() -> u64 { 0 } + #[pallet::type_value] /// Default value for rho parameter. + pub fn DefaultRho() -> u16 { T::InitialRho::get() } + #[pallet::type_value] /// Default value for kappa parameter. + pub fn DefaultKappa() -> u16 { T::InitialKappa::get() } + #[pallet::type_value] /// Default maximum allowed UIDs. + pub fn DefaultMaxAllowedUids() -> u16 { T::InitialMaxAllowedUids::get() } + #[pallet::type_value] /// Default immunity period. + pub fn DefaultImmunityPeriod() -> u16 { T::InitialImmunityPeriod::get() } + #[pallet::type_value] /// Default activity cutoff. + pub fn DefaultActivityCutoff() -> u16 { T::InitialActivityCutoff::get() } + #[pallet::type_value] /// Default maximum weights limit. + pub fn DefaultMaxWeightsLimit() -> u16 { T::InitialMaxWeightsLimit::get() } + #[pallet::type_value] /// Default weights version key. + pub fn DefaultWeightsVersionKey() -> u64 { T::InitialWeightsVersionKey::get() } + #[pallet::type_value] /// Default minimum allowed weights. + pub fn DefaultMinAllowedWeights() -> u16 { T::InitialMinAllowedWeights::get() } + #[pallet::type_value] /// Default maximum allowed validators. + pub fn DefaultMaxAllowedValidators() -> u16 { T::InitialMaxAllowedValidators::get() } + #[pallet::type_value] /// Default adjustment interval. + pub fn DefaultAdjustmentInterval() -> u16 { T::InitialAdjustmentInterval::get() } + #[pallet::type_value] /// Default bonds moving average. + pub fn DefaultBondsMovingAverage() -> u64 { T::InitialBondsMovingAverage::get() } + #[pallet::type_value] /// Default validator prune length. + pub fn DefaultValidatorPruneLen() -> u64 { T::InitialValidatorPruneLen::get() } + #[pallet::type_value] /// Default scaling law power. + pub fn DefaultScalingLawPower() -> u16 { T::InitialScalingLawPower::get() } + #[pallet::type_value] /// Default target registrations per interval. + pub fn DefaultTargetRegistrationsPerInterval() -> u16 { T::InitialTargetRegistrationsPerInterval::get() } + #[pallet::type_value] /// Default adjustment alpha. + pub fn DefaultAdjustmentAlpha() -> u64 { T::InitialAdjustmentAlpha::get() } + #[pallet::type_value] /// Default minimum stake for weights. + pub fn DefaultWeightsMinStake() -> u64 { 0 } + #[pallet::type_value] /// Value definition for vector of u16. + pub fn EmptyU16Vec() -> Vec { vec![] } + #[pallet::type_value] /// Value definition for vector of u64. + pub fn EmptyU64Vec() -> Vec { vec![] } + #[pallet::type_value] /// Value definition for vector of bool. + pub fn EmptyBoolVec() -> Vec { vec![] } + #[pallet::type_value] /// Value definition for bonds with type vector of (u16, u16). + pub fn DefaultBonds() -> Vec<(u16, u16)> { vec![] } + #[pallet::type_value] /// Value definition for weights with vector of (u16, u16). + pub fn DefaultWeights() -> Vec<(u16, u16)> { vec![] } + #[pallet::type_value] /// Default value for key with type T::AccountId derived from trailing zeroes. + pub fn DefaultKey() -> T::AccountId { T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).expect("trailing zeroes always produce a valid account ID; qed") } + #[pallet::type_value] /// Default value for network immunity period. + pub fn DefaultHotkeyEmissionTempo() -> u64 { 7200 } + #[pallet::type_value] /// Default value for rate limiting + pub fn DefaultTxRateLimit() -> u64 { T::InitialTxRateLimit::get() } + #[pallet::type_value] /// Default value for delegate take rate limiting + pub fn DefaultTxDelegateTakeRateLimit() -> u64 { T::InitialTxDelegateTakeRateLimit::get() } + #[pallet::type_value] /// Default value for last extrinsic block. + pub fn DefaultLastTxBlock() -> u64 { 0 } + #[pallet::type_value] /// Default value for serving rate limit. + pub fn DefaultServingRateLimit() -> u64 { T::InitialServingRateLimit::get() } + #[pallet::type_value] /// Default value for weight commit reveal interval. + pub fn DefaultWeightCommitRevealInterval() -> u64 { 1000 } + #[pallet::type_value] /// Default value for weight commit/reveal enabled. + pub fn DefaultCommitRevealWeightsEnabled() -> bool { false } + #[pallet::type_value] /// Senate requirements + pub fn DefaultSenateRequiredStakePercentage() -> u64 { T::InitialSenateRequiredStakePercentage::get() } + #[pallet::type_value] /// -- ITEM (switches liquid alpha on) + pub fn DefaultLiquidAlpha() -> bool {false} + #[pallet::type_value] /// (alpha_low: 0.7, alpha_high: 0.9) + pub fn DefaultAlphaValues() -> (u16, u16) { (45875, 58982) } - /// ======================================= - /// ==== Subnetwork Hyperparam storage ==== - /// ======================================= + #[pallet::storage] + pub(super) type SenateRequiredStakePercentage = StorageValue<_, u64, ValueQuery, DefaultSenateRequiredStakePercentage>; - /// Default weights set rate limit. - #[pallet::type_value] - pub fn DefaultWeightsSetRateLimit() -> u64 { - 100 - } - /// Default block at registration. - #[pallet::type_value] - pub fn DefaultBlockAtRegistration() -> u64 { - 0 - } - /// Default Rho parameter value. - #[pallet::type_value] - pub fn DefaultRho() -> u16 { - T::InitialRho::get() - } - /// Default Kai parameter value. - #[pallet::type_value] - pub fn DefaultKappa() -> u16 { - T::InitialKappa::get() - } - /// Default max allowed uids. - #[pallet::type_value] - pub fn DefaultMaxAllowedUids() -> u16 { - T::InitialMaxAllowedUids::get() - } - /// Default immunity period value. - #[pallet::type_value] - pub fn DefaultImmunityPeriod() -> u16 { - T::InitialImmunityPeriod::get() - } - /// Default activity cutoff value. - #[pallet::type_value] - pub fn DefaultActivityCutoff() -> u16 { - T::InitialActivityCutoff::get() - } - /// Default max weights limit. - #[pallet::type_value] - pub fn DefaultMaxWeightsLimit() -> u16 { - T::InitialMaxWeightsLimit::get() - } - /// Default weights version key. - #[pallet::type_value] - pub fn DefaultWeightsVersionKey() -> u64 { - T::InitialWeightsVersionKey::get() - } - /// Default minimal allowed weights. - #[pallet::type_value] - pub fn DefaultMinAllowedWeights() -> u16 { - T::InitialMinAllowedWeights::get() - } - /// Default max allowed validators. - #[pallet::type_value] - pub fn DefaultMaxAllowedValidators() -> u16 { - T::InitialMaxAllowedValidators::get() - } - /// Default adjustment interval. - #[pallet::type_value] - pub fn DefaultAdjustmentInterval() -> u16 { - T::InitialAdjustmentInterval::get() - } - /// Default bonds moving average. - #[pallet::type_value] - pub fn DefaultBondsMovingAverage() -> u64 { - T::InitialBondsMovingAverage::get() - } - /// Default validator prune length. - #[pallet::type_value] - pub fn DefaultValidatorPruneLen() -> u64 { - T::InitialValidatorPruneLen::get() - } - /// Default scaling law power. - #[pallet::type_value] - pub fn DefaultScalingLawPower() -> u16 { - T::InitialScalingLawPower::get() - } - /// Default target registrations per interval. - #[pallet::type_value] - pub fn DefaultTargetRegistrationsPerInterval() -> u16 { - T::InitialTargetRegistrationsPerInterval::get() - } - /// Default adjustment alpha. - #[pallet::type_value] - pub fn DefaultAdjustmentAlpha() -> u64 { - T::InitialAdjustmentAlpha::get() - } - /// Default weights min stake. - #[pallet::type_value] - pub fn DefaultWeightsMinStake() -> u64 { - 0 - } - /// Provides the default value for the upper bound of the alpha parameter. + /// ============================ + /// ==== Staking Variables ==== + /// ============================ + #[pallet::storage] // --- ITEM ( total_issuance ) + pub type TotalIssuance = StorageValue<_, u64, ValueQuery, DefaultTotalIssuance>; + #[pallet::storage] // --- ITEM ( total_stake ) + pub type TotalStake = StorageValue<_, u64, ValueQuery>; + #[pallet::storage] // --- ITEM ( default_take ) + pub type MaxTake = StorageValue<_, u16, ValueQuery, DefaultDefaultTake>; + #[pallet::storage] // --- ITEM ( min_take ) + pub type MinTake = StorageValue<_, u16, ValueQuery, DefaultMinTake>; + #[pallet::storage] // --- ITEM ( global_block_emission ) + pub type BlockEmission = StorageValue<_, u64, ValueQuery, DefaultBlockEmission>; + #[pallet::storage] // --- ITEM (target_stakes_per_interval) + pub type TargetStakesPerInterval = StorageValue<_, u64, ValueQuery, DefaultTargetStakesPerInterval>; + #[pallet::storage] // --- ITEM (default_stake_interval) + pub type StakeInterval = StorageValue<_, u64, ValueQuery, DefaultStakeInterval>; + #[pallet::storage] // --- MAP ( hot ) --> stake | Returns the total amount of stake under a hotkey. + pub type TotalHotkeyStake = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultAccountTake>; + #[pallet::storage] // --- MAP ( cold ) --> stake | Returns the total amount of stake under a coldkey. + pub type TotalColdkeyStake = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultAccountTake>; + #[pallet::storage] /// MAP (hot, cold) --> stake | Returns a tuple (u64: stakes, u64: block_number) + pub type TotalHotkeyColdkeyStakesThisInterval = StorageDoubleMap<_, Identity, T::AccountId, Identity, T::AccountId, (u64, u64), ValueQuery, DefaultStakesPerInterval>; + #[pallet::storage] /// MAP ( hot ) --> cold | Returns the controlling coldkey for a hotkey. + pub type Owner = StorageMap<_, Blake2_128Concat, T::AccountId, T::AccountId, ValueQuery, DefaultAccount>; + #[pallet::storage] /// MAP ( hot ) --> take | Returns the hotkey delegation take. And signals that this key is open for delegation. + pub type Delegates = StorageMap<_, Blake2_128Concat, T::AccountId, u16, ValueQuery, DefaultDefaultTake>; + #[pallet::storage] /// DMAP ( hot, cold ) --> stake | Returns the stake under a coldkey prefixed by hotkey. + pub type Stake = StorageDoubleMap<_, Blake2_128Concat, T::AccountId, Identity, T::AccountId, u64, ValueQuery, DefaultAccountTake>; + #[pallet::storage] /// Map ( hot ) --> last_hotkey_emission_drain | Last block we drained this hotkey's emission. + pub type LastHotkeyEmissionDrain = StorageMap<_, Blake2_128Concat, T::AccountId, u64, ValueQuery, DefaultAccumulatedEmission>; + #[pallet::storage] /// ITEM ( hotkey_emission_tempo ) + pub type HotkeyEmissionTempo = StorageValue<_, u64, ValueQuery, DefaultHotkeyEmissionTempo>; + #[pallet::storage] /// Map ( hot ) --> emission | Accumulated hotkey emission. + pub type PendingdHotkeyEmission = StorageMap<_, Blake2_128Concat, T::AccountId, u64, ValueQuery, DefaultAccumulatedEmission>; + #[pallet::storage] /// Map ( hot, cold ) --> block_number | Last add stake increase. + pub type LastAddStakeIncrease = StorageDoubleMap<_, Blake2_128Concat, T::AccountId, Identity, T::AccountId, u64, ValueQuery, DefaultAccountTake>; + #[pallet::storage] /// DMAP ( parent, netuid ) --> Vec<(proportion,child)> + pub type ChildKeys = StorageDoubleMap<_, Blake2_128Concat, T::AccountId, Identity, u16, Vec<(u64, T::AccountId)>, ValueQuery, DefaultAccountLinkage>; + #[pallet::storage] /// DMAP ( child, netuid ) --> Vec<(proportion,parent)> + pub type ParentKeys = StorageDoubleMap<_, Blake2_128Concat, T::AccountId, Identity, u16, Vec<(u64, T::AccountId)>, ValueQuery, DefaultAccountLinkage>; + #[pallet::storage] // --- DMAP ( cold ) --> Vec | Maps coldkey to hotkeys that stake to it + pub type StakingHotkeys = StorageMap<_, Blake2_128Concat, T::AccountId, Vec, ValueQuery>; + #[pallet::storage] // --- MAP ( cold ) --> Vec | Returns the vector of hotkeys controlled by this coldkey. + pub type OwnedHotkeys = StorageMap<_, Blake2_128Concat, T::AccountId, Vec, ValueQuery>; - #[pallet::type_value] - pub fn DefaultAlphaValues() -> (u16, u16) { - (45875, 58982) // (alpha_low: 0.7, alpha_high: 0.9) - } - #[pallet::storage] // ITEM( weights_min_stake ) - pub type WeightsMinStake = StorageValue<_, u64, ValueQuery, DefaultWeightsMinStake>; - #[pallet::storage] // --- MAP ( netuid ) --> Rho + /// ============================ + /// ==== Global Parameters ===== + /// ============================ + #[pallet::storage] /// --- StorageItem Global Used Work. + pub type UsedWork = StorageMap<_, Identity, Vec, u64, ValueQuery>; + #[pallet::storage] /// --- ITEM( global_max_registrations_per_block ) + pub type MaxRegistrationsPerBlock = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMaxRegistrationsPerBlock>; + #[pallet::storage] /// --- ITEM( maximum_number_of_networks ) + pub type SubnetLimit = StorageValue<_, u16, ValueQuery, DefaultSubnetLimit>; + #[pallet::storage] /// --- ITEM( total_number_of_existing_networks ) + pub type TotalNetworks = StorageValue<_, u16, ValueQuery>; + #[pallet::storage] /// ITEM( network_immunity_period ) + pub type NetworkImmunityPeriod = StorageValue<_, u64, ValueQuery, DefaultNetworkImmunityPeriod>; + #[pallet::storage] /// ITEM( network_last_registered_block ) + pub type NetworkLastRegistered = StorageValue<_, u64, ValueQuery, DefaultNetworkLastRegistered>; + #[pallet::storage] /// ITEM( network_min_allowed_uids ) + pub type NetworkMinAllowedUids = StorageValue<_, u16, ValueQuery, DefaultNetworkMinAllowedUids>; + #[pallet::storage] /// ITEM( min_network_lock_cost ) + pub type NetworkMinLockCost = StorageValue<_, u64, ValueQuery, DefaultNetworkMinLockCost>; + #[pallet::storage] /// ITEM( last_network_lock_cost ) + pub type NetworkLastLockCost = StorageValue<_, u64, ValueQuery, DefaultNetworkMinLockCost>; + #[pallet::storage] /// ITEM( network_lock_reduction_interval ) + pub type NetworkLockReductionInterval = StorageValue<_, u64, ValueQuery, DefaultNetworkLockReductionInterval>; + #[pallet::storage] /// ITEM( subnet_owner_cut ) + pub type SubnetOwnerCut = StorageValue<_, u16, ValueQuery, DefaultSubnetOwnerCut>; + #[pallet::storage] /// ITEM( network_rate_limit ) + pub type NetworkRateLimit = StorageValue<_, u64, ValueQuery, DefaultNetworkRateLimit>; + #[pallet::storage] /// ITEM( nominator_min_required_stake ) + pub type NominatorMinRequiredStake = StorageValue<_, u64, ValueQuery, DefaultNominatorMinRequiredStake>; + + /// ============================ + /// ==== Subnet Parameters ===== + /// ============================ + #[pallet::storage] /// --- MAP ( netuid ) --> subnetwork_n (Number of UIDs in the network). + pub type SubnetworkN = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultN>; + #[pallet::storage] /// --- MAP ( netuid ) --> modality TEXT: 0, IMAGE: 1, TENSOR: 2 + pub type NetworkModality = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultModality>; + #[pallet::storage] /// --- MAP ( netuid ) --> network_is_added + pub type NetworksAdded = StorageMap<_, Identity, u16, bool, ValueQuery, DefaultNeworksAdded>; + #[pallet::storage] /// --- DMAP ( hotkey, netuid ) --> bool + pub type IsNetworkMember = StorageDoubleMap<_, Blake2_128Concat, T::AccountId, Identity, u16, bool, ValueQuery, DefaultIsNetworkMember>; + #[pallet::storage] /// --- MAP ( netuid ) --> network_registration_allowed + pub type NetworkRegistrationAllowed = StorageMap<_, Identity, u16, bool, ValueQuery, DefaultRegistrationAllowed>; + #[pallet::storage] /// --- MAP ( netuid ) --> network_pow_allowed + pub type NetworkPowRegistrationAllowed = StorageMap<_, Identity, u16, bool, ValueQuery, DefaultRegistrationAllowed>; + #[pallet::storage] /// --- MAP ( netuid ) --> block_created + pub type NetworkRegisteredAt = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultNetworkRegisteredAt>; + #[pallet::storage] /// --- MAP ( netuid ) --> tempo + pub type Tempo = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultTempo>; + #[pallet::storage] /// --- MAP ( netuid ) --> emission_values + pub type EmissionValues = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultEmissionValues>; + #[pallet::storage] /// --- MAP ( netuid ) --> pending_emission + pub type PendingEmission = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultPendingEmission>; + #[pallet::storage] /// --- MAP ( netuid ) --> blocks_since_last_step + pub type BlocksSinceLastStep = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultBlocksSinceLastStep>; + #[pallet::storage] /// --- MAP ( netuid ) --> last_mechanism_step_block + pub type LastMechansimStepBlock = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultLastMechanismStepBlock>; + #[pallet::storage] /// --- MAP ( netuid ) --> subnet_owner + pub type SubnetOwner = StorageMap<_, Identity, u16, T::AccountId, ValueQuery, DefaultSubnetOwner>; + #[pallet::storage] /// --- MAP ( netuid ) --> subnet_locked + pub type SubnetLocked = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultSubnetLocked>; + #[pallet::storage] /// --- MAP ( netuid ) --> serving_rate_limit + pub type ServingRateLimit = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultServingRateLimit>; + #[pallet::storage] /// --- MAP ( netuid ) --> Rho pub type Rho = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultRho>; - #[pallet::storage] // --- MAP ( netuid ) --> Kappa + #[pallet::storage] /// --- MAP ( netuid ) --> Kappa pub type Kappa = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultKappa>; - #[pallet::storage] // --- MAP ( netuid ) --> uid, we use to record uids to prune at next epoch. + #[pallet::storage] /// --- MAP ( netuid ) --> uid, we use to record uids to prune at next epoch. pub type NeuronsToPruneAtNextEpoch = StorageMap<_, Identity, u16, u16, ValueQuery>; - #[pallet::storage] // --- MAP ( netuid ) --> registrations_this_interval + #[pallet::storage] /// --- MAP ( netuid ) --> registrations_this_interval pub type RegistrationsThisInterval = StorageMap<_, Identity, u16, u16, ValueQuery>; - #[pallet::storage] // --- MAP ( netuid ) --> pow_registrations_this_interval - pub type POWRegistrationsThisInterval = - StorageMap<_, Identity, u16, u16, ValueQuery>; - #[pallet::storage] // --- MAP ( netuid ) --> burn_registrations_this_interval - pub type BurnRegistrationsThisInterval = - StorageMap<_, Identity, u16, u16, ValueQuery>; - #[pallet::storage] // --- MAP ( netuid ) --> max_allowed_uids - pub type MaxAllowedUids = - StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMaxAllowedUids>; - #[pallet::storage] // --- MAP ( netuid ) --> immunity_period - pub type ImmunityPeriod = - StorageMap<_, Identity, u16, u16, ValueQuery, DefaultImmunityPeriod>; - #[pallet::storage] // --- MAP ( netuid ) --> activity_cutoff - pub type ActivityCutoff = - StorageMap<_, Identity, u16, u16, ValueQuery, DefaultActivityCutoff>; - #[pallet::storage] // --- MAP ( netuid ) --> max_weight_limit - pub type MaxWeightsLimit = - StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMaxWeightsLimit>; - #[pallet::storage] // --- MAP ( netuid ) --> weights_version_key - pub type WeightsVersionKey = - StorageMap<_, Identity, u16, u64, ValueQuery, DefaultWeightsVersionKey>; - #[pallet::storage] // --- MAP ( netuid ) --> min_allowed_weights - pub type MinAllowedWeights = - StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMinAllowedWeights>; - #[pallet::storage] // --- MAP ( netuid ) --> max_allowed_validators - pub type MaxAllowedValidators = - StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMaxAllowedValidators>; - #[pallet::storage] // --- MAP ( netuid ) --> adjustment_interval - pub type AdjustmentInterval = - StorageMap<_, Identity, u16, u16, ValueQuery, DefaultAdjustmentInterval>; - #[pallet::storage] // --- MAP ( netuid ) --> bonds_moving_average - pub type BondsMovingAverage = - StorageMap<_, Identity, u16, u64, ValueQuery, DefaultBondsMovingAverage>; - #[pallet::storage] // --- MAP ( netuid ) --> weights_set_rate_limit - pub type WeightsSetRateLimit = - StorageMap<_, Identity, u16, u64, ValueQuery, DefaultWeightsSetRateLimit>; - #[pallet::storage] // --- MAP ( netuid ) --> validator_prune_len - pub type ValidatorPruneLen = - StorageMap<_, Identity, u16, u64, ValueQuery, DefaultValidatorPruneLen>; - #[pallet::storage] // --- MAP ( netuid ) --> scaling_law_power - pub type ScalingLawPower = - StorageMap<_, Identity, u16, u16, ValueQuery, DefaultScalingLawPower>; - #[pallet::storage] // --- MAP ( netuid ) --> target_registrations_this_interval - pub type TargetRegistrationsPerInterval = - StorageMap<_, Identity, u16, u16, ValueQuery, DefaultTargetRegistrationsPerInterval>; - #[pallet::storage] // --- DMAP ( netuid, uid ) --> block_at_registration - pub type BlockAtRegistration = StorageDoubleMap< - _, - Identity, - u16, - Identity, - u16, - u64, - ValueQuery, - DefaultBlockAtRegistration, - >; - #[pallet::storage] // --- DMAP ( netuid ) --> adjustment_alpha - pub type AdjustmentAlpha = - StorageMap<_, Identity, u16, u64, ValueQuery, DefaultAdjustmentAlpha>; - - // MAP ( netuid ) --> (alpha_low, alpha_high) - #[pallet::storage] - pub type AlphaValues = - StorageMap<_, Identity, u16, (u16, u16), ValueQuery, DefaultAlphaValues>; - - #[pallet::storage] // --- MAP (netuid, who) --> (hash, weight) | Returns the hash and weight committed by an account for a given netuid. - pub type WeightCommits = StorageDoubleMap< - _, - Twox64Concat, - u16, - Twox64Concat, - T::AccountId, - (H256, u64), - OptionQuery, - >; - - /// Default value for weight commit reveal interval. - #[pallet::type_value] - pub fn DefaultWeightCommitRevealInterval() -> u64 { - 1000 - } - // --- DMAP ( netuid ) --> interval - #[pallet::storage] - pub type WeightCommitRevealInterval = - StorageMap<_, Identity, u16, u64, ValueQuery, DefaultWeightCommitRevealInterval>; + #[pallet::storage] /// --- MAP ( netuid ) --> pow_registrations_this_interval + pub type POWRegistrationsThisInterval = StorageMap<_, Identity, u16, u16, ValueQuery>; + #[pallet::storage] /// --- MAP ( netuid ) --> burn_registrations_this_interval + pub type BurnRegistrationsThisInterval = StorageMap<_, Identity, u16, u16, ValueQuery>; + #[pallet::storage] /// --- MAP ( netuid ) --> max_allowed_uids + pub type MaxAllowedUids = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMaxAllowedUids>; + #[pallet::storage] /// --- MAP ( netuid ) --> immunity_period + pub type ImmunityPeriod = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultImmunityPeriod>; + #[pallet::storage] /// --- MAP ( netuid ) --> activity_cutoff + pub type ActivityCutoff = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultActivityCutoff>; + #[pallet::storage] /// --- MAP ( netuid ) --> max_weight_limit + pub type MaxWeightsLimit = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMaxWeightsLimit>; + #[pallet::storage] /// --- MAP ( netuid ) --> weights_version_key + pub type WeightsVersionKey = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultWeightsVersionKey>; + #[pallet::storage] /// --- MAP ( netuid ) --> min_allowed_weights + pub type MinAllowedWeights = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMinAllowedWeights>; + #[pallet::storage] /// --- MAP ( netuid ) --> max_allowed_validators + pub type MaxAllowedValidators = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMaxAllowedValidators>; + #[pallet::storage] /// --- MAP ( netuid ) --> adjustment_interval + pub type AdjustmentInterval = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultAdjustmentInterval>; + #[pallet::storage] /// --- MAP ( netuid ) --> bonds_moving_average + pub type BondsMovingAverage = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultBondsMovingAverage>; + #[pallet::storage] /// --- MAP ( netuid ) --> weights_set_rate_limit + pub type WeightsSetRateLimit = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultWeightsSetRateLimit>; + #[pallet::storage] /// --- MAP ( netuid ) --> validator_prune_len + pub type ValidatorPruneLen = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultValidatorPruneLen>; + #[pallet::storage] /// --- MAP ( netuid ) --> scaling_law_power + pub type ScalingLawPower = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultScalingLawPower>; + #[pallet::storage] /// --- MAP ( netuid ) --> target_registrations_this_interval + pub type TargetRegistrationsPerInterval = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultTargetRegistrationsPerInterval>; + #[pallet::storage] /// --- MAP ( netuid ) --> adjustment_alpha + pub type AdjustmentAlpha = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultAdjustmentAlpha>; + #[pallet::storage] /// --- MAP ( netuid ) --> interval + pub type WeightCommitRevealInterval = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultWeightCommitRevealInterval>; + #[pallet::storage] /// --- MAP ( netuid ) --> interval + pub type CommitRevealWeightsEnabled = StorageMap<_, Identity, u16, bool, ValueQuery, DefaultCommitRevealWeightsEnabled>; + #[pallet::storage] /// --- MAP ( netuid ) --> Burn + pub type Burn = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultBurn>; + #[pallet::storage] /// --- MAP ( netuid ) --> Difficulty + pub type Difficulty = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultDifficulty>; + #[pallet::storage] /// --- MAP ( netuid ) --> MinBurn + pub type MinBurn = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultMinBurn>; + #[pallet::storage] /// --- MAP ( netuid ) --> MaxBurn + pub type MaxBurn = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultMaxBurn>; + #[pallet::storage] /// --- MAP ( netuid ) --> MinDifficulty + pub type MinDifficulty = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultMinDifficulty>; + #[pallet::storage] /// --- MAP ( netuid ) --> MaxDifficulty + pub type MaxDifficulty = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultMaxDifficulty>; + #[pallet::storage] /// --- MAP ( netuid ) --> Block at last adjustment. + pub type LastAdjustmentBlock = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultLastAdjustmentBlock>; + #[pallet::storage] /// --- MAP ( netuid ) --> Registrations of this Block. + pub type RegistrationsThisBlock = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultRegistrationsThisBlock>; + #[pallet::storage] /// --- MAP ( netuid ) --> global_RAO_recycled_for_registration + pub type RAORecycledForRegistration = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultRAORecycledForRegistration>; + #[pallet::storage] /// --- ITEM ( tx_rate_limit ) + pub(super) type TxRateLimit = StorageValue<_, u64, ValueQuery, DefaultTxRateLimit>; + #[pallet::storage] /// --- ITEM ( tx_rate_limit ) + pub(super) type TxDelegateTakeRateLimit = StorageValue<_, u64, ValueQuery, DefaultTxDelegateTakeRateLimit>; + #[pallet::storage] /// --- MAP ( netuid ) --> Whether or not Liquid Alpha is enabled + pub type LiquidAlphaOn = StorageMap<_, Blake2_128Concat, u16, bool, ValueQuery, DefaultLiquidAlpha>; + #[pallet::storage] /// MAP ( netuid ) --> (alpha_low, alpha_high) + pub type AlphaValues = StorageMap<_, Identity, u16, (u16, u16), ValueQuery, DefaultAlphaValues>; - /// Default value for weight commit/reveal enabled. - #[pallet::type_value] - pub fn DefaultCommitRevealWeightsEnabled() -> bool { - false - } - // --- DMAP ( netuid ) --> interval - #[pallet::storage] - pub type CommitRevealWeightsEnabled = - StorageMap<_, Identity, u16, bool, ValueQuery, DefaultCommitRevealWeightsEnabled>; /// ======================================= /// ==== Subnetwork Consensus Storage ==== /// ======================================= + #[pallet::storage] /// --- DMAP ( netuid, hotkey ) --> uid + pub(super) type Uids = StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, u16, OptionQuery>; + #[pallet::storage] /// --- DMAP ( netuid, uid ) --> hotkey + pub(super) type Keys = StorageDoubleMap<_, Identity, u16, Identity, u16, T::AccountId, ValueQuery, DefaultKey>; + #[pallet::storage] /// --- DMAP ( netuid ) --> (hotkey, se, ve) + pub(super) type LoadedEmission = StorageMap<_, Identity, u16, Vec<(T::AccountId, u64, u64)>, OptionQuery>; + #[pallet::storage] /// --- DMAP ( netuid ) --> active + pub(super) type Active = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyBoolVec>; + #[pallet::storage] /// --- DMAP ( netuid ) --> rank + pub(super) type Rank = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + #[pallet::storage] /// --- DMAP ( netuid ) --> trust + pub(super) type Trust = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + #[pallet::storage] /// --- DMAP ( netuid ) --> consensus + pub(super) type Consensus = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + #[pallet::storage] /// --- DMAP ( netuid ) --> incentive + pub(super) type Incentive = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + #[pallet::storage] /// --- DMAP ( netuid ) --> dividends + pub(super) type Dividends = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + #[pallet::storage] /// --- DMAP ( netuid ) --> emission + pub(super) type Emission = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU64Vec>; + #[pallet::storage] /// --- DMAP ( netuid ) --> last_update + pub(super) type LastUpdate = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU64Vec>; + #[pallet::storage] /// --- DMAP ( netuid ) --> validator_trust + pub(super) type ValidatorTrust = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + #[pallet::storage] /// --- DMAP ( netuid ) --> pruning_scores + pub(super) type PruningScores = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + #[pallet::storage] /// --- DMAP ( netuid ) --> validator_permit + pub(super) type ValidatorPermit = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyBoolVec>; + #[pallet::storage] /// --- DMAP ( netuid, uid ) --> weights + pub(super) type Weights = StorageDoubleMap<_, Identity, u16, Identity, u16, Vec<(u16, u16)>, ValueQuery, DefaultWeights>; + #[pallet::storage] /// --- DMAP ( netuid, uid ) --> bonds + pub(super) type Bonds = StorageDoubleMap<_, Identity, u16, Identity, u16, Vec<(u16, u16)>, ValueQuery, DefaultBonds>; + #[pallet::storage] /// --- DMAP ( netuid, uid ) --> block_at_registration + pub type BlockAtRegistration = StorageDoubleMap<_, Identity, u16, Identity, u16, u64, ValueQuery, DefaultBlockAtRegistration>; + #[pallet::storage] /// --- MAP ( netuid, hotkey ) --> axon_info + pub(super) type Axons = StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, AxonInfoOf, OptionQuery>; + #[pallet::storage] /// --- MAP ( netuid, hotkey ) --> prometheus_info + pub(super) type Prometheus = StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, PrometheusInfoOf, OptionQuery>; - /// Value definition for vector of u16. - #[pallet::type_value] - pub fn EmptyU16Vec() -> Vec { - vec![] - } - /// Value definition for vector of u64. - #[pallet::type_value] - pub fn EmptyU64Vec() -> Vec { - vec![] - } - /// Value definition for vector of bool. - #[pallet::type_value] - pub fn EmptyBoolVec() -> Vec { - vec![] - } - /// Value definition for bonds with type vector of (u16, u16). - #[pallet::type_value] - pub fn DefaultBonds() -> Vec<(u16, u16)> { - vec![] - } - /// Value definition for weights with vector of (u16, u16). + /// ================================= + /// ==== Axon / Promo Endpoints ===== + /// ================================= + #[pallet::storage] /// --- MAP ( key ) --> last_block + pub(super) type LastTxBlock = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; + #[pallet::storage] /// --- MAP ( key ) --> last_block + pub(super) type LastTxBlockDelegateTake = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; + #[pallet::storage] /// ITEM( weights_min_stake ) + pub type WeightsMinStake = StorageValue<_, u64, ValueQuery, DefaultWeightsMinStake>; + #[pallet::storage] /// --- MAP (netuid, who) --> (hash, weight) | Returns the hash and weight committed by an account for a given netuid. + pub type WeightCommits = StorageDoubleMap<_, Twox64Concat, u16, Twox64Concat, T::AccountId, (H256, u64), OptionQuery>; + + /// =============================== + /// ==== Coldkey Arbitrations ===== + /// =============================== + #[pallet::type_value] /// Default base difficulty for proof of work for coldkey swaps + pub fn DefaultBaseDifficulty() -> u64 { T::InitialBaseDifficulty::get() } + #[pallet::storage] // --- ITEM ( base_difficulty ) + pub type BaseDifficulty = StorageValue<_, u64, ValueQuery, DefaultBaseDifficulty>; #[pallet::type_value] - pub fn DefaultWeights() -> Vec<(u16, u16)> { + /// Default value for hotkeys. + pub fn EmptyAccounts() -> Vec { vec![] } - /// Default value for key with type T::AccountId derived from trailing zeroes. #[pallet::type_value] - pub fn DefaultKey() -> T::AccountId { - T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) - .expect("trailing zeroes always produce a valid account ID; qed") + /// Default arbitration period. + /// This value represents the default arbitration period in blocks. + /// The period is set to 18 hours, assuming a block time of 12 seconds. + pub fn DefaultArbitrationPeriod() -> u64 { + 7200 * 3 // 3 days } - - #[pallet::storage] // --- DMAP ( netuid, hotkey ) --> uid - pub type Uids = - StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, u16, OptionQuery>; - #[pallet::storage] // --- DMAP ( netuid, uid ) --> hotkey - pub type Keys = - StorageDoubleMap<_, Identity, u16, Identity, u16, T::AccountId, ValueQuery, DefaultKey>; - #[pallet::storage] // --- DMAP ( netuid ) --> (hotkey, se, ve) - pub type LoadedEmission = - StorageMap<_, Identity, u16, Vec<(T::AccountId, u64, u64)>, OptionQuery>; - - #[pallet::storage] // --- DMAP ( netuid ) --> active - pub(super) type Active = - StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyBoolVec>; - #[pallet::storage] // --- DMAP ( netuid ) --> rank - pub(super) type Rank = - StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; - #[pallet::storage] // --- DMAP ( netuid ) --> trust - pub(super) type Trust = - StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; - #[pallet::storage] // --- DMAP ( netuid ) --> consensus - pub(super) type Consensus = - StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; - #[pallet::storage] // --- DMAP ( netuid ) --> incentive - pub(super) type Incentive = - StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; - #[pallet::storage] // --- DMAP ( netuid ) --> dividends - pub(super) type Dividends = - StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; - #[pallet::storage] // --- DMAP ( netuid ) --> emission - pub(super) type Emission = - StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU64Vec>; - #[pallet::storage] // --- DMAP ( netuid ) --> last_update - pub(super) type LastUpdate = - StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU64Vec>; - #[pallet::storage] // --- DMAP ( netuid ) --> validator_trust - pub(super) type ValidatorTrust = - StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; - #[pallet::storage] // --- DMAP ( netuid ) --> pruning_scores - pub(super) type PruningScores = - StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; - #[pallet::storage] // --- DMAP ( netuid ) --> validator_permit - pub(super) type ValidatorPermit = - StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyBoolVec>; - - #[pallet::storage] // --- DMAP ( netuid, uid ) --> weights - pub(super) type Weights = StorageDoubleMap< - _, - Identity, - u16, - Identity, - u16, - Vec<(u16, u16)>, - ValueQuery, - DefaultWeights, - >; - #[pallet::storage] // --- DMAP ( netuid, uid ) --> bonds - pub(super) type Bonds = StorageDoubleMap< + #[pallet::storage] // ---- StorageItem Global Used Work. + pub type ArbitrationPeriod = + StorageValue<_, u64, ValueQuery, DefaultArbitrationPeriod>; + #[pallet::storage] // --- MAP ( cold ) --> Vec | Returns a list of keys to drain to, if there are two, we extend the period. + pub type ColdkeySwapDestinations = StorageMap< _, - Identity, - u16, - Identity, - u16, - Vec<(u16, u16)>, + Blake2_128Concat, + T::AccountId, + Vec, ValueQuery, - DefaultBonds, + EmptyAccounts, >; + #[pallet::storage] // --- MAP ( cold ) --> u64 | Block when the coldkey will be arbitrated. + pub type ColdkeyArbitrationBlock = + StorageMap<_, Blake2_128Concat, T::AccountId, u64, ValueQuery>; + #[pallet::storage] // --- MAP ( u64 ) --> Vec | Coldkeys to drain on the specific block. + pub type ColdkeysToSwapAtBlock = + StorageMap<_, Identity, u64, Vec, ValueQuery, EmptyAccounts>; /// ================== /// ==== Genesis ===== @@ -1161,1113 +605,6 @@ pub mod pallet { } } - #[pallet::genesis_build] - impl BuildGenesisConfig for GenesisConfig { - fn build(&self) { - // Set initial total issuance from balances - TotalIssuance::::put(self.balances_issuance); - - // Subnet config values - let netuid: u16 = 3; - let tempo = 99; - let max_uids = 4096; - - // The functions for initializing new networks/setting defaults cannot be run directly from genesis functions like extrinsics would - // --- Set this network uid to alive. - NetworksAdded::::insert(netuid, true); - - // --- Fill tempo memory item. - Tempo::::insert(netuid, tempo); - - // --- Fill modality item. - // Only modality 0 exists (text) - NetworkModality::::insert(netuid, 0); - - // Make network parameters explicit. - if !Tempo::::contains_key(netuid) { - Tempo::::insert(netuid, Tempo::::get(netuid)); - } - if !Kappa::::contains_key(netuid) { - Kappa::::insert(netuid, Kappa::::get(netuid)); - } - if !Difficulty::::contains_key(netuid) { - Difficulty::::insert(netuid, Difficulty::::get(netuid)); - } - if !MaxAllowedUids::::contains_key(netuid) { - MaxAllowedUids::::insert(netuid, MaxAllowedUids::::get(netuid)); - } - if !ImmunityPeriod::::contains_key(netuid) { - ImmunityPeriod::::insert(netuid, ImmunityPeriod::::get(netuid)); - } - if !ActivityCutoff::::contains_key(netuid) { - ActivityCutoff::::insert(netuid, ActivityCutoff::::get(netuid)); - } - if !EmissionValues::::contains_key(netuid) { - EmissionValues::::insert(netuid, EmissionValues::::get(netuid)); - } - if !MaxWeightsLimit::::contains_key(netuid) { - MaxWeightsLimit::::insert(netuid, MaxWeightsLimit::::get(netuid)); - } - if !MinAllowedWeights::::contains_key(netuid) { - MinAllowedWeights::::insert(netuid, MinAllowedWeights::::get(netuid)); - } - if !RegistrationsThisInterval::::contains_key(netuid) { - RegistrationsThisInterval::::insert( - netuid, - RegistrationsThisInterval::::get(netuid), - ); - } - if !POWRegistrationsThisInterval::::contains_key(netuid) { - POWRegistrationsThisInterval::::insert( - netuid, - POWRegistrationsThisInterval::::get(netuid), - ); - } - if !BurnRegistrationsThisInterval::::contains_key(netuid) { - BurnRegistrationsThisInterval::::insert( - netuid, - BurnRegistrationsThisInterval::::get(netuid), - ); - } - - // Set max allowed uids - MaxAllowedUids::::insert(netuid, max_uids); - - let mut next_uid = 0u16; - - for (coldkey, hotkeys) in self.stakes.iter() { - for (hotkey, stake_uid) in hotkeys.iter() { - let (stake, uid) = stake_uid; - - // Expand Yuma Consensus with new position. - Rank::::mutate(netuid, |v| v.push(0)); - Trust::::mutate(netuid, |v| v.push(0)); - Active::::mutate(netuid, |v| v.push(true)); - Emission::::mutate(netuid, |v| v.push(0)); - Consensus::::mutate(netuid, |v| v.push(0)); - Incentive::::mutate(netuid, |v| v.push(0)); - Dividends::::mutate(netuid, |v| v.push(0)); - LastUpdate::::mutate(netuid, |v| v.push(0)); - PruningScores::::mutate(netuid, |v| v.push(0)); - ValidatorTrust::::mutate(netuid, |v| v.push(0)); - ValidatorPermit::::mutate(netuid, |v| v.push(false)); - - // Insert account information. - Keys::::insert(netuid, uid, hotkey.clone()); // Make hotkey - uid association. - Uids::::insert(netuid, hotkey.clone(), uid); // Make uid - hotkey association. - BlockAtRegistration::::insert(netuid, uid, 0); // Fill block at registration. - IsNetworkMember::::insert(hotkey.clone(), netuid, true); // Fill network is member. - - // Fill stake information. - Owner::::insert(hotkey.clone(), coldkey.clone()); - - // Update OwnedHotkeys map - let mut hotkeys = OwnedHotkeys::::get(coldkey); - if !hotkeys.contains(hotkey) { - hotkeys.push(hotkey.clone()); - OwnedHotkeys::::insert(coldkey, hotkeys); - } - - TotalHotkeyStake::::insert(hotkey.clone(), stake); - TotalColdkeyStake::::insert( - coldkey.clone(), - TotalColdkeyStake::::get(coldkey).saturating_add(*stake), - ); - - // Update total issuance value - TotalIssuance::::put(TotalIssuance::::get().saturating_add(*stake)); - - Stake::::insert(hotkey.clone(), coldkey.clone(), stake); - - // Update StakingHotkeys map - let mut staking_hotkeys = StakingHotkeys::::get(coldkey); - if !staking_hotkeys.contains(hotkey) { - staking_hotkeys.push(hotkey.clone()); - StakingHotkeys::::insert(coldkey, staking_hotkeys); - } - - next_uid = next_uid.checked_add(1).expect( - "should not have total number of hotkey accounts larger than u16::MAX", - ); - } - } - - // Set correct length for Subnet neurons - SubnetworkN::::insert(netuid, next_uid); - - // --- Increase total network count. - TotalNetworks::::mutate(|n| { - *n = n.checked_add(1).expect( - "should not have total number of networks larger than u16::MAX in genesis", - ) - }); - - // Get the root network uid. - let root_netuid: u16 = 0; - - // Set the root network as added. - NetworksAdded::::insert(root_netuid, true); - - // Increment the number of total networks. - TotalNetworks::::mutate(|n| { - *n = n.checked_add(1).expect( - "should not have total number of networks larger than u16::MAX in genesis", - ) - }); - // Set the number of validators to 1. - SubnetworkN::::insert(root_netuid, 0); - - // Set the maximum number to the number of senate members. - MaxAllowedUids::::insert(root_netuid, 64u16); - - // Set the maximum number to the number of validators to all members. - MaxAllowedValidators::::insert(root_netuid, 64u16); - - // Set the min allowed weights to zero, no weights restrictions. - MinAllowedWeights::::insert(root_netuid, 0); - - // Set the max weight limit to infinity, no weight restrictions. - MaxWeightsLimit::::insert(root_netuid, u16::MAX); - - // Add default root tempo. - Tempo::::insert(root_netuid, 100); - - // Set the root network as open. - NetworkRegistrationAllowed::::insert(root_netuid, true); - - // Set target registrations for validators as 1 per block. - TargetRegistrationsPerInterval::::insert(root_netuid, 1); - } - } - - // ================ - // ==== Hooks ===== - // ================ - - #[pallet::hooks] - impl Hooks> for Pallet { - fn on_idle(_n: BlockNumberFor, _remaining_weight: Weight) -> Weight { - Weight::zero() - } - - fn on_initialize(_block_number: BlockNumberFor) -> Weight { - let mut total_weight = Weight::zero(); - - // Create a Weight::MAX value to pass to swap_coldkeys_this_block - let max_weight = Weight::MAX; - - // Perform coldkey swapping - let swap_weight = match Self::swap_coldkeys_this_block(&max_weight) { - Ok(weight_used) => weight_used, - Err(e) => { - log::error!("Error while swapping coldkeys: {:?}", e); - Weight::zero() - } - }; - total_weight = total_weight.saturating_add(swap_weight); - - // Perform block step - let block_step_result = Self::block_step(); - match block_step_result { - Ok(_) => { - log::debug!("Successfully ran block step."); - total_weight = total_weight.saturating_add( - Weight::from_parts(110_634_229_000_u64, 0) - .saturating_add(T::DbWeight::get().reads(8304_u64)) - .saturating_add(T::DbWeight::get().writes(110_u64)), - ); - } - Err(e) => { - log::error!("Error while stepping block: {:?}", e); - total_weight = total_weight.saturating_add( - Weight::from_parts(110_634_229_000_u64, 0) - .saturating_add(T::DbWeight::get().reads(8304_u64)) - .saturating_add(T::DbWeight::get().writes(110_u64)), - ); - } - } - - total_weight - } - - fn on_runtime_upgrade() -> frame_support::weights::Weight { - // --- Migrate storage - use crate::migration; - let mut weight = frame_support::weights::Weight::from_parts(0, 0); - - // Hex encoded foundation coldkey - let hex = hex_literal::hex![ - "feabaafee293d3b76dae304e2f9d885f77d2b17adab9e17e921b321eccd61c77" - ]; - weight = weight - // Initializes storage version (to 1) - .saturating_add(migration::migrate_to_v1_separate_emission::()) - // Storage version v1 -> v2 - .saturating_add(migration::migrate_to_v2_fixed_total_stake::()) - // Doesn't check storage version. TODO: Remove after upgrade - .saturating_add(migration::migrate_create_root_network::()) - // Storage version v2 -> v3 - .saturating_add(migration::migrate_transfer_ownership_to_foundation::( - hex, - )) - // Storage version v3 -> v4 - .saturating_add(migration::migrate_delete_subnet_21::()) - // Storage version v4 -> v5 - .saturating_add(migration::migrate_delete_subnet_3::()) - // Doesn't check storage version. TODO: Remove after upgrade - .saturating_add(migration::migration5_total_issuance::(false)) - // Populate OwnedHotkeys map for coldkey swap. Doesn't update storage vesion. - .saturating_add(migration::migrate_populate_owned::()) - // Populate StakingHotkeys map for coldkey swap. Doesn't update storage vesion. - .saturating_add(migration::migrate_populate_staking_hotkeys::()) - // Fix total coldkey stake. - .saturating_add(migration::migrate_fix_total_coldkey_stake::()); - - weight - } - } - - /// Dispatchable functions allow users to interact with the pallet and invoke state changes. - /// These functions materialize as "extrinsics", which are often compared to transactions. - /// Dispatchable functions must be annotated with a weight and must return a DispatchResult. - #[pallet::call] - impl Pallet { - /// --- Sets the caller weights for the incentive mechanism. The call can be - /// made from the hotkey account so is potentially insecure, however, the damage - /// of changing weights is minimal if caught early. This function includes all the - /// checks that the passed weights meet the requirements. Stored as u16s they represent - /// rational values in the range [0,1] which sum to 1 and can be interpreted as - /// probabilities. The specific weights determine how inflation propagates outward - /// from this peer. - /// - /// Note: The 16 bit integers weights should represent 1.0 as the max u16. - /// However, the function normalizes all integers to u16_max anyway. This means that if the sum of all - /// elements is larger or smaller than the amount of elements * u16_max, all elements - /// will be corrected for this deviation. - /// - /// # Args: - /// * `origin`: (Origin): - /// - The caller, a hotkey who wishes to set their weights. - /// - /// * `netuid` (u16): - /// - The network uid we are setting these weights on. - /// - /// * `dests` (Vec): - /// - The edge endpoint for the weight, i.e. j for w_ij. - /// - /// * 'weights' (Vec): - /// - The u16 integer encoded weights. Interpreted as rational - /// values in the range [0,1]. They must sum to in32::MAX. - /// - /// * 'version_key' ( u64 ): - /// - The network version key to check if the validator is up to date. - /// - /// # Event: - /// * WeightsSet; - /// - On successfully setting the weights on chain. - /// - /// # Raises: - /// * 'SubNetworkDoesNotExist': - /// - Attempting to set weights on a non-existent network. - /// - /// * 'NotRegistered': - /// - Attempting to set weights from a non registered account. - /// - /// * 'WeightVecNotEqualSize': - /// - Attempting to set weights with uids not of same length. - /// - /// * 'DuplicateUids': - /// - Attempting to set weights with duplicate uids. - /// - /// * 'UidsLengthExceedUidsInSubNet': - /// - Attempting to set weights above the max allowed uids. - /// - /// * 'UidVecContainInvalidOne': - /// - Attempting to set weights with invalid uids. - /// - /// * 'WeightVecLengthIsLow': - /// - Attempting to set weights with fewer weights than min. - /// - /// * 'MaxWeightExceeded': - /// - Attempting to set weights with max value exceeding limit. - #[pallet::call_index(0)] - #[pallet::weight((Weight::from_parts(22_060_000_000, 0) - .saturating_add(T::DbWeight::get().reads(4106)) - .saturating_add(T::DbWeight::get().writes(2)), DispatchClass::Normal, Pays::No))] - pub fn set_weights( - origin: OriginFor, - netuid: u16, - dests: Vec, - weights: Vec, - version_key: u64, - ) -> DispatchResult { - if !Self::get_commit_reveal_weights_enabled(netuid) { - return Self::do_set_weights(origin, netuid, dests, weights, version_key); - } - - Err(Error::::CommitRevealEnabled.into()) - } - - /// ---- Used to commit a hash of your weight values to later be revealed. - /// - /// # Args: - /// * `origin`: (`::RuntimeOrigin`): - /// - The signature of the committing hotkey. - /// - /// * `netuid` (`u16`): - /// - The u16 network identifier. - /// - /// * `commit_hash` (`H256`): - /// - The hash representing the committed weights. - /// - /// # Raises: - /// * `WeightsCommitNotAllowed`: - /// - Attempting to commit when it is not allowed. - /// - #[pallet::call_index(96)] - #[pallet::weight((Weight::from_parts(46_000_000, 0) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Normal, Pays::No))] - pub fn commit_weights( - origin: T::RuntimeOrigin, - netuid: u16, - commit_hash: H256, - ) -> DispatchResult { - Self::do_commit_weights(origin, netuid, commit_hash) - } - - /// ---- Used to reveal the weights for a previously committed hash. - /// - /// # Args: - /// * `origin`: (`::RuntimeOrigin`): - /// - The signature of the revealing hotkey. - /// - /// * `netuid` (`u16`): - /// - The u16 network identifier. - /// - /// * `uids` (`Vec`): - /// - The uids for the weights being revealed. - /// - /// * `values` (`Vec`): - /// - The values of the weights being revealed. - /// - /// * `salt` (`Vec`): - /// - The random salt to protect from brute-force guessing attack in case of small weight changes bit-wise. - /// - /// * `version_key` (`u64`): - /// - The network version key. - /// - /// # Raises: - /// * `NoWeightsCommitFound`: - /// - Attempting to reveal weights without an existing commit. - /// - /// * `InvalidRevealCommitHashNotMatchTempo`: - /// - Attempting to reveal weights outside the valid tempo. - /// - /// * `InvalidRevealCommitHashNotMatch`: - /// - The revealed hash does not match the committed hash. - /// - #[pallet::call_index(97)] - #[pallet::weight((Weight::from_parts(103_000_000, 0) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(3)), DispatchClass::Normal, Pays::No))] - pub fn reveal_weights( - origin: T::RuntimeOrigin, - netuid: u16, - uids: Vec, - values: Vec, - salt: Vec, - version_key: u64, - ) -> DispatchResult { - Self::do_reveal_weights(origin, netuid, uids, values, salt, version_key) - } - - /// # Args: - /// * `origin`: (Origin): - /// - The caller, a hotkey who wishes to set their weights. - /// - /// * `netuid` (u16): - /// - The network uid we are setting these weights on. - /// - /// * `hotkey` (T::AccountId): - /// - The hotkey associated with the operation and the calling coldkey. - /// - /// * `dests` (Vec): - /// - The edge endpoint for the weight, i.e. j for w_ij. - /// - /// * 'weights' (Vec): - /// - The u16 integer encoded weights. Interpreted as rational - /// values in the range [0,1]. They must sum to in32::MAX. - /// - /// * 'version_key' ( u64 ): - /// - The network version key to check if the validator is up to date. - /// - /// # Event: - /// - /// * WeightsSet; - /// - On successfully setting the weights on chain. - /// - /// # Raises: - /// - /// * NonAssociatedColdKey; - /// - Attempting to set weights on a non-associated cold key. - /// - /// * 'SubNetworkDoesNotExist': - /// - Attempting to set weights on a non-existent network. - /// - /// * 'NotRootSubnet': - /// - Attempting to set weights on a subnet that is not the root network. - /// - /// * 'WeightVecNotEqualSize': - /// - Attempting to set weights with uids not of same length. - /// - /// * 'UidVecContainInvalidOne': - /// - Attempting to set weights with invalid uids. - /// - /// * 'NotRegistered': - /// - Attempting to set weights from a non registered account. - /// - /// * 'WeightVecLengthIsLow': - /// - Attempting to set weights with fewer weights than min. - /// - /// * 'IncorrectWeightVersionKey': - /// - Attempting to set weights with the incorrect network version key. - /// - /// * 'SettingWeightsTooFast': - /// - Attempting to set weights too fast. - /// - /// * 'WeightVecLengthIsLow': - /// - Attempting to set weights with fewer weights than min. - /// - /// * 'MaxWeightExceeded': - /// - Attempting to set weights with max value exceeding limit. - /// - #[pallet::call_index(8)] - #[pallet::weight((Weight::from_parts(10_151_000_000, 0) - .saturating_add(T::DbWeight::get().reads(4104)) - .saturating_add(T::DbWeight::get().writes(2)), DispatchClass::Normal, Pays::No))] - pub fn set_root_weights( - origin: OriginFor, - netuid: u16, - hotkey: T::AccountId, - dests: Vec, - weights: Vec, - version_key: u64, - ) -> DispatchResult { - Self::do_set_root_weights(origin, netuid, hotkey, dests, weights, version_key) - } - - /// --- Sets the key as a delegate. - /// - /// # Args: - /// * 'origin': (Origin): - /// - The signature of the caller's coldkey. - /// - /// * 'hotkey' (T::AccountId): - /// - The hotkey we are delegating (must be owned by the coldkey.) - /// - /// * 'take' (u64): - /// - The stake proportion that this hotkey takes from delegations. - /// - /// # Event: - /// * DelegateAdded; - /// - On successfully setting a hotkey as a delegate. - /// - /// # Raises: - /// * 'NotRegistered': - /// - The hotkey we are delegating is not registered on the network. - /// - /// * 'NonAssociatedColdKey': - /// - The hotkey we are delegating is not owned by the calling coldket. - /// - #[pallet::call_index(1)] - #[pallet::weight((Weight::from_parts(79_000_000, 0) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)), DispatchClass::Normal, Pays::No))] - pub fn become_delegate(origin: OriginFor, hotkey: T::AccountId) -> DispatchResult { - Self::do_become_delegate(origin, hotkey, Self::get_default_take()) - } - - /// --- Allows delegates to decrease its take value. - /// - /// # Args: - /// * 'origin': (::Origin): - /// - The signature of the caller's coldkey. - /// - /// * 'hotkey' (T::AccountId): - /// - The hotkey we are delegating (must be owned by the coldkey.) - /// - /// * 'netuid' (u16): - /// - Subnet ID to decrease take for - /// - /// * 'take' (u16): - /// - The new stake proportion that this hotkey takes from delegations. - /// The new value can be between 0 and 11_796 and should be strictly - /// lower than the previous value. It T is the new value (rational number), - /// the the parameter is calculated as [65535 * T]. For example, 1% would be - /// [0.01 * 65535] = [655.35] = 655 - /// - /// # Event: - /// * TakeDecreased; - /// - On successfully setting a decreased take for this hotkey. - /// - /// # Raises: - /// * 'NotRegistered': - /// - The hotkey we are delegating is not registered on the network. - /// - /// * 'NonAssociatedColdKey': - /// - The hotkey we are delegating is not owned by the calling coldkey. - /// - /// * 'DelegateTakeTooLow': - /// - The delegate is setting a take which is not lower than the previous. - /// - #[pallet::call_index(65)] - #[pallet::weight((0, DispatchClass::Normal, Pays::No))] - pub fn decrease_take( - origin: OriginFor, - hotkey: T::AccountId, - take: u16, - ) -> DispatchResult { - Self::do_decrease_take(origin, hotkey, take) - } - - /// --- Allows delegates to increase its take value. This call is rate-limited. - /// - /// # Args: - /// * 'origin': (::Origin): - /// - The signature of the caller's coldkey. - /// - /// * 'hotkey' (T::AccountId): - /// - The hotkey we are delegating (must be owned by the coldkey.) - /// - /// * 'take' (u16): - /// - The new stake proportion that this hotkey takes from delegations. - /// The new value can be between 0 and 11_796 and should be strictly - /// greater than the previous value. T is the new value (rational number), - /// the the parameter is calculated as [65535 * T]. For example, 1% would be - /// [0.01 * 65535] = [655.35] = 655 - /// - /// # Event: - /// * TakeIncreased; - /// - On successfully setting a increased take for this hotkey. - /// - /// # Raises: - /// * 'NotRegistered': - /// - The hotkey we are delegating is not registered on the network. - /// - /// * 'NonAssociatedColdKey': - /// - The hotkey we are delegating is not owned by the calling coldkey. - /// - /// * 'DelegateTakeTooHigh': - /// - The delegate is setting a take which is not greater than the previous. - /// - #[pallet::call_index(66)] - #[pallet::weight((0, DispatchClass::Normal, Pays::No))] - pub fn increase_take( - origin: OriginFor, - hotkey: T::AccountId, - take: u16, - ) -> DispatchResult { - Self::do_increase_take(origin, hotkey, take) - } - - /// --- Adds stake to a hotkey. The call is made from the - /// coldkey account linked in the hotkey. - /// Only the associated coldkey is allowed to make staking and - /// unstaking requests. This protects the neuron against - /// attacks on its hotkey running in production code. - /// - /// # Args: - /// * 'origin': (Origin): - /// - The signature of the caller's coldkey. - /// - /// * 'hotkey' (T::AccountId): - /// - The associated hotkey account. - /// - /// * 'amount_staked' (u64): - /// - The amount of stake to be added to the hotkey staking account. - /// - /// # Event: - /// * StakeAdded; - /// - On the successfully adding stake to a global account. - /// - /// # Raises: - /// * 'NotEnoughBalanceToStake': - /// - Not enough balance on the coldkey to add onto the global account. - /// - /// * 'NonAssociatedColdKey': - /// - The calling coldkey is not associated with this hotkey. - /// - /// * 'BalanceWithdrawalError': - /// - Errors stemming from transaction pallet. - /// - #[pallet::call_index(2)] - #[pallet::weight((Weight::from_parts(124_000_000, 0) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(7)), DispatchClass::Normal, Pays::No))] - pub fn add_stake( - origin: OriginFor, - hotkey: T::AccountId, - amount_staked: u64, - ) -> DispatchResult { - Self::do_add_stake(origin, hotkey, amount_staked) - } - - /// Remove stake from the staking account. The call must be made - /// from the coldkey account attached to the neuron metadata. Only this key - /// has permission to make staking and unstaking requests. - /// - /// # Args: - /// * 'origin': (Origin): - /// - The signature of the caller's coldkey. - /// - /// * 'hotkey' (T::AccountId): - /// - The associated hotkey account. - /// - /// * 'amount_unstaked' (u64): - /// - The amount of stake to be added to the hotkey staking account. - /// - /// # Event: - /// * StakeRemoved; - /// - On the successfully removing stake from the hotkey account. - /// - /// # Raises: - /// * 'NotRegistered': - /// - Thrown if the account we are attempting to unstake from is non existent. - /// - /// * 'NonAssociatedColdKey': - /// - Thrown if the coldkey does not own the hotkey we are unstaking from. - /// - /// * 'NotEnoughStakeToWithdraw': - /// - Thrown if there is not enough stake on the hotkey to withdwraw this amount. - /// - #[pallet::call_index(3)] - #[pallet::weight((Weight::from_parts(111_000_000, 0) - .saturating_add(Weight::from_parts(0, 43991)) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(7)), DispatchClass::Normal, Pays::No))] - pub fn remove_stake( - origin: OriginFor, - hotkey: T::AccountId, - amount_unstaked: u64, - ) -> DispatchResult { - Self::do_remove_stake(origin, hotkey, amount_unstaked) - } - - /// Serves or updates axon /promethteus information for the neuron associated with the caller. If the caller is - /// already registered the metadata is updated. If the caller is not registered this call throws NotRegistered. - /// - /// # Args: - /// * 'origin': (Origin): - /// - The signature of the caller. - /// - /// * 'netuid' (u16): - /// - The u16 network identifier. - /// - /// * 'version' (u64): - /// - The bittensor version identifier. - /// - /// * 'ip' (u64): - /// - The endpoint ip information as a u128 encoded integer. - /// - /// * 'port' (u16): - /// - The endpoint port information as a u16 encoded integer. - /// - /// * 'ip_type' (u8): - /// - The endpoint ip version as a u8, 4 or 6. - /// - /// * 'protocol' (u8): - /// - UDP:1 or TCP:0 - /// - /// * 'placeholder1' (u8): - /// - Placeholder for further extra params. - /// - /// * 'placeholder2' (u8): - /// - Placeholder for further extra params. - /// - /// # Event: - /// * AxonServed; - /// - On successfully serving the axon info. - /// - /// # Raises: - /// * 'SubNetworkDoesNotExist': - /// - Attempting to set weights on a non-existent network. - /// - /// * 'NotRegistered': - /// - Attempting to set weights from a non registered account. - /// - /// * 'InvalidIpType': - /// - The ip type is not 4 or 6. - /// - /// * 'InvalidIpAddress': - /// - The numerically encoded ip address does not resolve to a proper ip. - /// - /// * 'ServingRateLimitExceeded': - /// - Attempting to set prometheus information withing the rate limit min. - /// - #[pallet::call_index(4)] - #[pallet::weight((Weight::from_parts(46_000_000, 0) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Normal, Pays::No))] - pub fn serve_axon( - origin: OriginFor, - netuid: u16, - version: u32, - ip: u128, - port: u16, - ip_type: u8, - protocol: u8, - placeholder1: u8, - placeholder2: u8, - ) -> DispatchResult { - Self::do_serve_axon( - origin, - netuid, - version, - ip, - port, - ip_type, - protocol, - placeholder1, - placeholder2, - ) - } - - /// ---- Set prometheus information for the neuron. - /// # Args: - /// * 'origin': (Origin): - /// - The signature of the calling hotkey. - /// - /// * 'netuid' (u16): - /// - The u16 network identifier. - /// - /// * 'version' (u16): - /// - The bittensor version identifier. - /// - /// * 'ip' (u128): - /// - The prometheus ip information as a u128 encoded integer. - /// - /// * 'port' (u16): - /// - The prometheus port information as a u16 encoded integer. - /// - /// * 'ip_type' (u8): - /// - The ip type v4 or v6. - /// - #[pallet::call_index(5)] - #[pallet::weight((Weight::from_parts(45_000_000, 0) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Normal, Pays::No))] - pub fn serve_prometheus( - origin: OriginFor, - netuid: u16, - version: u32, - ip: u128, - port: u16, - ip_type: u8, - ) -> DispatchResult { - Self::do_serve_prometheus(origin, netuid, version, ip, port, ip_type) - } - - /// ---- Registers a new neuron to the subnetwork. - /// - /// # Args: - /// * 'origin': (Origin): - /// - The signature of the calling hotkey. - /// - /// * 'netuid' (u16): - /// - The u16 network identifier. - /// - /// * 'block_number' ( u64 ): - /// - Block hash used to prove work done. - /// - /// * 'nonce' ( u64 ): - /// - Positive integer nonce used in POW. - /// - /// * 'work' ( Vec ): - /// - Vector encoded bytes representing work done. - /// - /// * 'hotkey' ( T::AccountId ): - /// - Hotkey to be registered to the network. - /// - /// * 'coldkey' ( T::AccountId ): - /// - Associated coldkey account. - /// - /// # Event: - /// * NeuronRegistered; - /// - On successfully registering a uid to a neuron slot on a subnetwork. - /// - /// # Raises: - /// * 'SubNetworkDoesNotExist': - /// - Attempting to register to a non existent network. - /// - /// * 'TooManyRegistrationsThisBlock': - /// - This registration exceeds the total allowed on this network this block. - /// - /// * 'HotKeyAlreadyRegisteredInSubNet': - /// - The hotkey is already registered on this network. - /// - /// * 'InvalidWorkBlock': - /// - The work has been performed on a stale, future, or non existent block. - /// - /// * 'InvalidDifficulty': - /// - The work does not match the difficulty. - /// - /// * 'InvalidSeal': - /// - The seal is incorrect. - /// - #[pallet::call_index(6)] - #[pallet::weight((Weight::from_parts(192_000_000, 0) - .saturating_add(T::DbWeight::get().reads(24)) - .saturating_add(T::DbWeight::get().writes(22)), DispatchClass::Normal, Pays::No))] - pub fn register( - origin: OriginFor, - netuid: u16, - block_number: u64, - nonce: u64, - work: Vec, - hotkey: T::AccountId, - coldkey: T::AccountId, - ) -> DispatchResult { - Self::do_registration(origin, netuid, block_number, nonce, work, hotkey, coldkey) - } - - /// Register the hotkey to root network - #[pallet::call_index(62)] - #[pallet::weight((Weight::from_parts(164_000_000, 0) - .saturating_add(T::DbWeight::get().reads(23)) - .saturating_add(T::DbWeight::get().writes(20)), DispatchClass::Normal, Pays::No))] - pub fn root_register(origin: OriginFor, hotkey: T::AccountId) -> DispatchResult { - Self::do_root_register(origin, hotkey) - } - - /// Attempt to adjust the senate membership to include a hotkey - #[pallet::call_index(63)] - #[pallet::weight((Weight::from_parts(0, 0) - .saturating_add(T::DbWeight::get().reads(0)) - .saturating_add(T::DbWeight::get().writes(0)), DispatchClass::Normal, Pays::Yes))] - pub fn adjust_senate(origin: OriginFor, hotkey: T::AccountId) -> DispatchResult { - Self::do_adjust_senate(origin, hotkey) - } - - /// User register a new subnetwork via burning token - #[pallet::call_index(7)] - #[pallet::weight((Weight::from_parts(177_000_000, 0) - .saturating_add(T::DbWeight::get().reads(26)) - .saturating_add(T::DbWeight::get().writes(24)), DispatchClass::Normal, Pays::No))] - pub fn burned_register( - origin: OriginFor, - netuid: u16, - hotkey: T::AccountId, - ) -> DispatchResult { - Self::do_burned_registration(origin, netuid, hotkey) - } - - /// The extrinsic for user to change its hotkey - ///#[pallet::call_index(70)] - ///#[pallet::weight((Weight::from_parts(1_940_000_000, 0) - ///.saturating_add(T::DbWeight::get().reads(272)) - ///.saturating_add(T::DbWeight::get().writes(527)), DispatchClass::Operational, Pays::No))] - ///pub fn swap_hotkey( - /// origin: OriginFor, - /// hotkey: T::AccountId, - /// new_hotkey: T::AccountId, - ///) -> DispatchResultWithPostInfo { - /// Self::do_swap_hotkey(origin, &hotkey, &new_hotkey) - ///} - - /// The extrinsic for user to change the coldkey associated with their account. - /// - /// # Arguments - /// - /// * `origin` - The origin of the call, must be signed by the old coldkey. - /// * `old_coldkey` - The current coldkey associated with the account. - /// * `new_coldkey` - The new coldkey to be associated with the account. - /// - /// # Returns - /// - /// Returns a `DispatchResultWithPostInfo` indicating success or failure of the operation. - /// - /// # Weight - /// - /// Weight is calculated based on the number of database reads and writes. - #[pallet::call_index(71)] - #[pallet::weight((Weight::from_parts(1_940_000_000, 0) - .saturating_add(T::DbWeight::get().reads(272)) - .saturating_add(T::DbWeight::get().writes(527)), DispatchClass::Operational, Pays::No))] - pub fn swap_coldkey( - origin: OriginFor, - new_coldkey: T::AccountId, - ) -> DispatchResultWithPostInfo { - Self::do_swap_coldkey(origin, &new_coldkey) - } - /// Unstakes all tokens associated with a hotkey and transfers them to a new coldkey. - /// - /// # Arguments - /// - /// * `origin` - The origin of the call, must be signed by the current coldkey. - /// * `hotkey` - The hotkey associated with the stakes to be unstaked. - /// * `new_coldkey` - The new coldkey to receive the unstaked tokens. - /// - /// # Returns - /// - /// Returns a `DispatchResult` indicating success or failure of the operation. - /// - /// # Weight - /// - /// Weight is calculated based on the number of database reads and writes. - #[cfg(test)] - #[pallet::call_index(72)] - #[pallet::weight((Weight::from_parts(21_000_000, 0) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)), DispatchClass::Operational, Pays::No))] - pub fn schedule_coldkey_swap( - origin: OriginFor, - new_coldkey: T::AccountId, - work: Vec, - block_number: u64, - nonce: u64, - ) -> DispatchResult { - // Attain the calling coldkey from the origin. - let old_coldkey: T::AccountId = ensure_signed(origin)?; - Self::do_schedule_coldkey_swap(&old_coldkey, &new_coldkey, work, block_number, nonce) - } - - // ---- SUDO ONLY FUNCTIONS ------------------------------------------------------------ - - // ================================== - // ==== Parameter Sudo calls ======== - // ================================== - // Each function sets the corresponding hyper paramter on the specified network - // Args: - // * 'origin': (Origin): - // - The caller, must be sudo. - // - // * `netuid` (u16): - // - The network identifier. - // - // * `hyperparameter value` (u16): - // - The value of the hyper parameter. - // - - /// Authenticates a council proposal and dispatches a function call with `Root` origin. - /// - /// The dispatch origin for this call must be a council majority. - /// - /// ## Complexity - /// - O(1). - #[pallet::call_index(51)] - #[pallet::weight((Weight::from_parts(0, 0), DispatchClass::Operational, Pays::No))] - pub fn sudo( - origin: OriginFor, - call: Box, - ) -> DispatchResultWithPostInfo { - // This is a public call, so we ensure that the origin is a council majority. - T::CouncilOrigin::ensure_origin(origin)?; - - let result = call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into()); - let error = result.map(|_| ()).map_err(|e| e.error); - Self::deposit_event(Event::Sudid(error)); - - return result; - } - - /// Authenticates a council proposal and dispatches a function call with `Root` origin. - /// This function does not check the weight of the call, and instead allows the - /// user to specify the weight of the call. - /// - /// The dispatch origin for this call must be a council majority. - /// - /// ## Complexity - /// - O(1). - #[allow(deprecated)] - #[pallet::call_index(52)] - #[pallet::weight((*weight, call.get_dispatch_info().class, Pays::No))] - pub fn sudo_unchecked_weight( - origin: OriginFor, - call: Box, - weight: Weight, - ) -> DispatchResultWithPostInfo { - // We dont need to check the weight witness, suppress warning. - // See https://github.com/paritytech/polkadot-sdk/pull/1818. - let _ = weight; - - // This is a public call, so we ensure that the origin is a council majority. - T::CouncilOrigin::ensure_origin(origin)?; - - let result = call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into()); - let error = result.map(|_| ()).map_err(|e| e.error); - Self::deposit_event(Event::Sudid(error)); - - return result; - } - - /// User vote on a proposal - #[pallet::call_index(55)] - #[pallet::weight((Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().reads(0)) - .saturating_add(T::DbWeight::get().writes(0)), DispatchClass::Operational))] - pub fn vote( - origin: OriginFor, - hotkey: T::AccountId, - proposal: T::Hash, - #[pallet::compact] index: u32, - approve: bool, - ) -> DispatchResultWithPostInfo { - Self::do_vote_root(origin, &hotkey, proposal, index, approve) - } - - /// User register a new subnetwork - #[pallet::call_index(59)] - #[pallet::weight((Weight::from_parts(157_000_000, 0) - .saturating_add(T::DbWeight::get().reads(16)) - .saturating_add(T::DbWeight::get().writes(30)), DispatchClass::Operational, Pays::No))] - pub fn register_network(origin: OriginFor) -> DispatchResult { - Self::user_add_network(origin) - } - - /// Facility extrinsic for user to get taken from faucet - /// It is only available when pow-faucet feature enabled - /// Just deployed in testnet and devnet for testing purpose - #[pallet::call_index(60)] - #[pallet::weight((Weight::from_parts(91_000_000, 0) - .saturating_add(T::DbWeight::get().reads(27)) - .saturating_add(T::DbWeight::get().writes(22)), DispatchClass::Normal, Pays::No))] - pub fn faucet( - origin: OriginFor, - block_number: u64, - nonce: u64, - work: Vec, - ) -> DispatchResult { - if cfg!(feature = "pow-faucet") { - return Self::do_faucet(origin, block_number, nonce, work); - } - - Err(Error::::FaucetDisabled.into()) - } - - /// 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)), DispatchClass::Operational, Pays::No))] - pub fn dissolve_network(origin: OriginFor, netuid: u16) -> DispatchResult { - Self::user_remove_network(origin, netuid) - } - - /// Sets values for liquid alpha - #[pallet::call_index(64)] - #[pallet::weight((0, DispatchClass::Operational, Pays::No))] - pub fn sudo_hotfix_swap_coldkey_delegates( - _origin: OriginFor, - _old_coldkey: T::AccountId, - _new_coldkey: T::AccountId, - ) -> DispatchResult { - Ok(()) - } - } - // ---- Subtensor helper functions. impl Pallet { /// Returns the transaction priority for setting weights. diff --git a/pallets/subtensor/src/macros/config.rs b/pallets/subtensor/src/macros/config.rs new file mode 100644 index 0000000000..e54cd222f8 --- /dev/null +++ b/pallets/subtensor/src/macros/config.rs @@ -0,0 +1,175 @@ +use frame_support::pallet_macros::pallet_section; + +/// A [`pallet_section`] that defines the errors for a pallet. +/// This can later be imported into the pallet using [`import_section`]. +#[pallet_section] +mod config { + + /// Configure the pallet by specifying the parameters and types on which it depends. + #[pallet::config] + pub trait Config: frame_system::Config { + /// Because this pallet emits events, it depends on the runtime's definition of an event. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// A sudo-able call. + type SudoRuntimeCall: Parameter + + UnfilteredDispatchable + + GetDispatchInfo; + + /// Origin checking for council majority + type CouncilOrigin: EnsureOrigin; + + /// Currency type that will be used to place deposits on neurons + type Currency: fungible::Balanced + + fungible::Mutate; + + /// Senate members with members management functions. + type SenateMembers: crate::MemberManagement; + + /// Interface to allow other pallets to control who can register identities + type TriumvirateInterface: crate::CollectiveInterface; + + /// ================================= + /// ==== Initial Value Constants ==== + /// ================================= + + /// Initial currency issuance. + #[pallet::constant] + type InitialIssuance: Get; + /// Initial min allowed weights setting. + #[pallet::constant] + type InitialMinAllowedWeights: Get; + /// Initial Emission Ratio. + #[pallet::constant] + type InitialEmissionValue: Get; + /// Initial max weight limit. + #[pallet::constant] + type InitialMaxWeightsLimit: Get; + /// Tempo for each network. + #[pallet::constant] + type InitialTempo: Get; + /// Initial Difficulty. + #[pallet::constant] + type InitialDifficulty: Get; + /// Initial Max Difficulty. + #[pallet::constant] + type InitialMaxDifficulty: Get; + /// Initial Min Difficulty. + #[pallet::constant] + type InitialMinDifficulty: Get; + /// Initial RAO Recycled. + #[pallet::constant] + type InitialRAORecycledForRegistration: Get; + /// Initial Burn. + #[pallet::constant] + type InitialBurn: Get; + /// Initial Max Burn. + #[pallet::constant] + type InitialMaxBurn: Get; + /// Initial Min Burn. + #[pallet::constant] + type InitialMinBurn: Get; + /// Initial adjustment interval. + #[pallet::constant] + type InitialAdjustmentInterval: Get; + /// Initial bonds moving average. + #[pallet::constant] + type InitialBondsMovingAverage: Get; + /// Initial target registrations per interval. + #[pallet::constant] + type InitialTargetRegistrationsPerInterval: Get; + /// Rho constant. + #[pallet::constant] + type InitialRho: Get; + /// Kappa constant. + #[pallet::constant] + type InitialKappa: Get; + /// Max UID constant. + #[pallet::constant] + type InitialMaxAllowedUids: Get; + /// Initial validator context pruning length. + #[pallet::constant] + type InitialValidatorPruneLen: Get; + /// Initial scaling law power. + #[pallet::constant] + type InitialScalingLawPower: Get; + /// Immunity Period Constant. + #[pallet::constant] + type InitialImmunityPeriod: Get; + /// Activity constant. + #[pallet::constant] + type InitialActivityCutoff: Get; + /// Initial max registrations per block. + #[pallet::constant] + type InitialMaxRegistrationsPerBlock: Get; + /// Initial pruning score for each neuron. + #[pallet::constant] + type InitialPruningScore: Get; + /// Initial maximum allowed validators per network. + #[pallet::constant] + type InitialMaxAllowedValidators: Get; + /// Initial default delegation take. + #[pallet::constant] + type InitialDefaultTake: Get; + /// Initial minimum delegation take. + #[pallet::constant] + type InitialMinTake: Get; + /// Initial weights version key. + #[pallet::constant] + type InitialWeightsVersionKey: Get; + /// Initial serving rate limit. + #[pallet::constant] + type InitialServingRateLimit: Get; + /// Initial transaction rate limit. + #[pallet::constant] + type InitialTxRateLimit: Get; + /// Initial delegate take transaction rate limit. + #[pallet::constant] + type InitialTxDelegateTakeRateLimit: Get; + /// Initial percentage of total stake required to join senate. + #[pallet::constant] + type InitialSenateRequiredStakePercentage: Get; + /// Initial adjustment alpha on burn and pow. + #[pallet::constant] + type InitialAdjustmentAlpha: Get; + /// Initial network immunity period + #[pallet::constant] + type InitialNetworkImmunityPeriod: Get; + /// Initial minimum allowed network UIDs + #[pallet::constant] + type InitialNetworkMinAllowedUids: Get; + /// Initial network minimum burn cost + #[pallet::constant] + type InitialNetworkMinLockCost: Get; + /// Initial network subnet cut. + #[pallet::constant] + type InitialSubnetOwnerCut: Get; + /// Initial lock reduction interval. + #[pallet::constant] + type InitialNetworkLockReductionInterval: Get; + /// Initial max allowed subnets + #[pallet::constant] + type InitialSubnetLimit: Get; + /// Initial network creation rate limit + #[pallet::constant] + type InitialNetworkRateLimit: Get; + /// Initial target stakes per interval issuance. + #[pallet::constant] + type InitialTargetStakesPerInterval: Get; + /// Cost of swapping a hotkey. + #[pallet::constant] + type KeySwapCost: Get; + /// The upper bound for the alpha parameter. Used for Liquid Alpha. + #[pallet::constant] + type AlphaHigh: Get; + /// The lower bound for the alpha parameter. Used for Liquid Alpha. + #[pallet::constant] + type AlphaLow: Get; + /// A flag to indicate if Liquid Alpha is enabled. + #[pallet::constant] + type LiquidAlphaOn: Get; + /// The base difficulty for proof of work for coldkey swaps + #[pallet::constant] + type InitialBaseDifficulty: Get; + } +} \ No newline at end of file diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs new file mode 100644 index 0000000000..62b02f6a46 --- /dev/null +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -0,0 +1,847 @@ +use frame_support::pallet_macros::pallet_section; + +/// A [`pallet_section`] that defines the errors for a pallet. +/// This can later be imported into the pallet using [`import_section`]. +#[pallet_section] +mod dispatches { + /// Dispatchable functions allow users to interact with the pallet and invoke state changes. + /// These functions materialize as "extrinsics", which are often compared to transactions. + /// Dispatchable functions must be annotated with a weight and must return a DispatchResult. + #[pallet::call] + impl Pallet { + /// --- Sets the caller weights for the incentive mechanism. The call can be + /// made from the hotkey account so is potentially insecure, however, the damage + /// of changing weights is minimal if caught early. This function includes all the + /// checks that the passed weights meet the requirements. Stored as u16s they represent + /// rational values in the range [0,1] which sum to 1 and can be interpreted as + /// probabilities. The specific weights determine how inflation propagates outward + /// from this peer. + /// + /// Note: The 16 bit integers weights should represent 1.0 as the max u16. + /// However, the function normalizes all integers to u16_max anyway. This means that if the sum of all + /// elements is larger or smaller than the amount of elements * u16_max, all elements + /// will be corrected for this deviation. + /// + /// # Args: + /// * `origin`: (Origin): + /// - The caller, a hotkey who wishes to set their weights. + /// + /// * `netuid` (u16): + /// - The network uid we are setting these weights on. + /// + /// * `dests` (Vec): + /// - The edge endpoint for the weight, i.e. j for w_ij. + /// + /// * 'weights' (Vec): + /// - The u16 integer encoded weights. Interpreted as rational + /// values in the range [0,1]. They must sum to in32::MAX. + /// + /// * 'version_key' ( u64 ): + /// - The network version key to check if the validator is up to date. + /// + /// # Event: + /// * WeightsSet; + /// - On successfully setting the weights on chain. + /// + /// # Raises: + /// * 'SubNetworkDoesNotExist': + /// - Attempting to set weights on a non-existent network. + /// + /// * 'NotRegistered': + /// - Attempting to set weights from a non registered account. + /// + /// * 'WeightVecNotEqualSize': + /// - Attempting to set weights with uids not of same length. + /// + /// * 'DuplicateUids': + /// - Attempting to set weights with duplicate uids. + /// + /// * 'UidsLengthExceedUidsInSubNet': + /// - Attempting to set weights above the max allowed uids. + /// + /// * 'UidVecContainInvalidOne': + /// - Attempting to set weights with invalid uids. + /// + /// * 'WeightVecLengthIsLow': + /// - Attempting to set weights with fewer weights than min. + /// + /// * 'MaxWeightExceeded': + /// - Attempting to set weights with max value exceeding limit. + #[pallet::call_index(0)] + #[pallet::weight((Weight::from_parts(22_060_000_000, 0) + .saturating_add(T::DbWeight::get().reads(4106)) + .saturating_add(T::DbWeight::get().writes(2)), DispatchClass::Normal, Pays::No))] + pub fn set_weights( + origin: OriginFor, + netuid: u16, + dests: Vec, + weights: Vec, + version_key: u64, + ) -> DispatchResult { + if !Self::get_commit_reveal_weights_enabled(netuid) { + return Self::do_set_weights(origin, netuid, dests, weights, version_key); + } + + Err(Error::::CommitRevealEnabled.into()) + } + + /// ---- Used to commit a hash of your weight values to later be revealed. + /// + /// # Args: + /// * `origin`: (`::RuntimeOrigin`): + /// - The signature of the committing hotkey. + /// + /// * `netuid` (`u16`): + /// - The u16 network identifier. + /// + /// * `commit_hash` (`H256`): + /// - The hash representing the committed weights. + /// + /// # Raises: + /// * `WeightsCommitNotAllowed`: + /// - Attempting to commit when it is not allowed. + /// + #[pallet::call_index(96)] + #[pallet::weight((Weight::from_parts(46_000_000, 0) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Normal, Pays::No))] + pub fn commit_weights( + origin: T::RuntimeOrigin, + netuid: u16, + commit_hash: H256, + ) -> DispatchResult { + Self::do_commit_weights(origin, netuid, commit_hash) + } + + /// ---- Used to reveal the weights for a previously committed hash. + /// + /// # Args: + /// * `origin`: (`::RuntimeOrigin`): + /// - The signature of the revealing hotkey. + /// + /// * `netuid` (`u16`): + /// - The u16 network identifier. + /// + /// * `uids` (`Vec`): + /// - The uids for the weights being revealed. + /// + /// * `values` (`Vec`): + /// - The values of the weights being revealed. + /// + /// * `salt` (`Vec`): + /// - The random salt to protect from brute-force guessing attack in case of small weight changes bit-wise. + /// + /// * `version_key` (`u64`): + /// - The network version key. + /// + /// # Raises: + /// * `NoWeightsCommitFound`: + /// - Attempting to reveal weights without an existing commit. + /// + /// * `InvalidRevealCommitHashNotMatchTempo`: + /// - Attempting to reveal weights outside the valid tempo. + /// + /// * `InvalidRevealCommitHashNotMatch`: + /// - The revealed hash does not match the committed hash. + /// + #[pallet::call_index(97)] + #[pallet::weight((Weight::from_parts(103_000_000, 0) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(3)), DispatchClass::Normal, Pays::No))] + pub fn reveal_weights( + origin: T::RuntimeOrigin, + netuid: u16, + uids: Vec, + values: Vec, + salt: Vec, + version_key: u64, + ) -> DispatchResult { + Self::do_reveal_weights(origin, netuid, uids, values, salt, version_key) + } + + /// # Args: + /// * `origin`: (Origin): + /// - The caller, a hotkey who wishes to set their weights. + /// + /// * `netuid` (u16): + /// - The network uid we are setting these weights on. + /// + /// * `hotkey` (T::AccountId): + /// - The hotkey associated with the operation and the calling coldkey. + /// + /// * `dests` (Vec): + /// - The edge endpoint for the weight, i.e. j for w_ij. + /// + /// * 'weights' (Vec): + /// - The u16 integer encoded weights. Interpreted as rational + /// values in the range [0,1]. They must sum to in32::MAX. + /// + /// * 'version_key' ( u64 ): + /// - The network version key to check if the validator is up to date. + /// + /// # Event: + /// + /// * WeightsSet; + /// - On successfully setting the weights on chain. + /// + /// # Raises: + /// + /// * NonAssociatedColdKey; + /// - Attempting to set weights on a non-associated cold key. + /// + /// * 'SubNetworkDoesNotExist': + /// - Attempting to set weights on a non-existent network. + /// + /// * 'NotRootSubnet': + /// - Attempting to set weights on a subnet that is not the root network. + /// + /// * 'WeightVecNotEqualSize': + /// - Attempting to set weights with uids not of same length. + /// + /// * 'UidVecContainInvalidOne': + /// - Attempting to set weights with invalid uids. + /// + /// * 'NotRegistered': + /// - Attempting to set weights from a non registered account. + /// + /// * 'WeightVecLengthIsLow': + /// - Attempting to set weights with fewer weights than min. + /// + /// * 'IncorrectWeightVersionKey': + /// - Attempting to set weights with the incorrect network version key. + /// + /// * 'SettingWeightsTooFast': + /// - Attempting to set weights too fast. + /// + /// * 'WeightVecLengthIsLow': + /// - Attempting to set weights with fewer weights than min. + /// + /// * 'MaxWeightExceeded': + /// - Attempting to set weights with max value exceeding limit. + /// + #[pallet::call_index(8)] + #[pallet::weight((Weight::from_parts(10_151_000_000, 0) + .saturating_add(T::DbWeight::get().reads(4104)) + .saturating_add(T::DbWeight::get().writes(2)), DispatchClass::Normal, Pays::No))] + pub fn set_root_weights( + origin: OriginFor, + netuid: u16, + hotkey: T::AccountId, + dests: Vec, + weights: Vec, + version_key: u64, + ) -> DispatchResult { + Self::do_set_root_weights(origin, netuid, hotkey, dests, weights, version_key) + } + + /// --- Sets the key as a delegate. + /// + /// # Args: + /// * 'origin': (Origin): + /// - The signature of the caller's coldkey. + /// + /// * 'hotkey' (T::AccountId): + /// - The hotkey we are delegating (must be owned by the coldkey.) + /// + /// * 'take' (u64): + /// - The stake proportion that this hotkey takes from delegations. + /// + /// # Event: + /// * DelegateAdded; + /// - On successfully setting a hotkey as a delegate. + /// + /// # Raises: + /// * 'NotRegistered': + /// - The hotkey we are delegating is not registered on the network. + /// + /// * 'NonAssociatedColdKey': + /// - The hotkey we are delegating is not owned by the calling coldket. + /// + #[pallet::call_index(1)] + #[pallet::weight((Weight::from_parts(79_000_000, 0) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)), DispatchClass::Normal, Pays::No))] + pub fn become_delegate(origin: OriginFor, hotkey: T::AccountId) -> DispatchResult { + Self::do_become_delegate(origin, hotkey, Self::get_default_take()) + } + + /// --- Allows delegates to decrease its take value. + /// + /// # Args: + /// * 'origin': (::Origin): + /// - The signature of the caller's coldkey. + /// + /// * 'hotkey' (T::AccountId): + /// - The hotkey we are delegating (must be owned by the coldkey.) + /// + /// * 'netuid' (u16): + /// - Subnet ID to decrease take for + /// + /// * 'take' (u16): + /// - The new stake proportion that this hotkey takes from delegations. + /// The new value can be between 0 and 11_796 and should be strictly + /// lower than the previous value. It T is the new value (rational number), + /// the the parameter is calculated as [65535 * T]. For example, 1% would be + /// [0.01 * 65535] = [655.35] = 655 + /// + /// # Event: + /// * TakeDecreased; + /// - On successfully setting a decreased take for this hotkey. + /// + /// # Raises: + /// * 'NotRegistered': + /// - The hotkey we are delegating is not registered on the network. + /// + /// * 'NonAssociatedColdKey': + /// - The hotkey we are delegating is not owned by the calling coldkey. + /// + /// * 'DelegateTakeTooLow': + /// - The delegate is setting a take which is not lower than the previous. + /// + #[pallet::call_index(65)] + #[pallet::weight((0, DispatchClass::Normal, Pays::No))] + pub fn decrease_take( + origin: OriginFor, + hotkey: T::AccountId, + take: u16, + ) -> DispatchResult { + Self::do_decrease_take(origin, hotkey, take) + } + + /// --- Allows delegates to increase its take value. This call is rate-limited. + /// + /// # Args: + /// * 'origin': (::Origin): + /// - The signature of the caller's coldkey. + /// + /// * 'hotkey' (T::AccountId): + /// - The hotkey we are delegating (must be owned by the coldkey.) + /// + /// * 'take' (u16): + /// - The new stake proportion that this hotkey takes from delegations. + /// The new value can be between 0 and 11_796 and should be strictly + /// greater than the previous value. T is the new value (rational number), + /// the the parameter is calculated as [65535 * T]. For example, 1% would be + /// [0.01 * 65535] = [655.35] = 655 + /// + /// # Event: + /// * TakeIncreased; + /// - On successfully setting a increased take for this hotkey. + /// + /// # Raises: + /// * 'NotRegistered': + /// - The hotkey we are delegating is not registered on the network. + /// + /// * 'NonAssociatedColdKey': + /// - The hotkey we are delegating is not owned by the calling coldkey. + /// + /// * 'DelegateTakeTooHigh': + /// - The delegate is setting a take which is not greater than the previous. + /// + #[pallet::call_index(66)] + #[pallet::weight((0, DispatchClass::Normal, Pays::No))] + pub fn increase_take( + origin: OriginFor, + hotkey: T::AccountId, + take: u16, + ) -> DispatchResult { + Self::do_increase_take(origin, hotkey, take) + } + + /// --- Adds stake to a hotkey. The call is made from the + /// coldkey account linked in the hotkey. + /// Only the associated coldkey is allowed to make staking and + /// unstaking requests. This protects the neuron against + /// attacks on its hotkey running in production code. + /// + /// # Args: + /// * 'origin': (Origin): + /// - The signature of the caller's coldkey. + /// + /// * 'hotkey' (T::AccountId): + /// - The associated hotkey account. + /// + /// * 'amount_staked' (u64): + /// - The amount of stake to be added to the hotkey staking account. + /// + /// # Event: + /// * StakeAdded; + /// - On the successfully adding stake to a global account. + /// + /// # Raises: + /// * 'NotEnoughBalanceToStake': + /// - Not enough balance on the coldkey to add onto the global account. + /// + /// * 'NonAssociatedColdKey': + /// - The calling coldkey is not associated with this hotkey. + /// + /// * 'BalanceWithdrawalError': + /// - Errors stemming from transaction pallet. + /// + #[pallet::call_index(2)] + #[pallet::weight((Weight::from_parts(124_000_000, 0) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(7)), DispatchClass::Normal, Pays::No))] + pub fn add_stake( + origin: OriginFor, + hotkey: T::AccountId, + amount_staked: u64, + ) -> DispatchResult { + Self::do_add_stake(origin, hotkey, amount_staked) + } + + /// Remove stake from the staking account. The call must be made + /// from the coldkey account attached to the neuron metadata. Only this key + /// has permission to make staking and unstaking requests. + /// + /// # Args: + /// * 'origin': (Origin): + /// - The signature of the caller's coldkey. + /// + /// * 'hotkey' (T::AccountId): + /// - The associated hotkey account. + /// + /// * 'amount_unstaked' (u64): + /// - The amount of stake to be added to the hotkey staking account. + /// + /// # Event: + /// * StakeRemoved; + /// - On the successfully removing stake from the hotkey account. + /// + /// # Raises: + /// * 'NotRegistered': + /// - Thrown if the account we are attempting to unstake from is non existent. + /// + /// * 'NonAssociatedColdKey': + /// - Thrown if the coldkey does not own the hotkey we are unstaking from. + /// + /// * 'NotEnoughStakeToWithdraw': + /// - Thrown if there is not enough stake on the hotkey to withdwraw this amount. + /// + #[pallet::call_index(3)] + #[pallet::weight((Weight::from_parts(111_000_000, 0) + .saturating_add(Weight::from_parts(0, 43991)) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(7)), DispatchClass::Normal, Pays::No))] + pub fn remove_stake( + origin: OriginFor, + hotkey: T::AccountId, + amount_unstaked: u64, + ) -> DispatchResult { + Self::do_remove_stake(origin, hotkey, amount_unstaked) + } + + /// Serves or updates axon /promethteus information for the neuron associated with the caller. If the caller is + /// already registered the metadata is updated. If the caller is not registered this call throws NotRegistered. + /// + /// # Args: + /// * 'origin': (Origin): + /// - The signature of the caller. + /// + /// * 'netuid' (u16): + /// - The u16 network identifier. + /// + /// * 'version' (u64): + /// - The bittensor version identifier. + /// + /// * 'ip' (u64): + /// - The endpoint ip information as a u128 encoded integer. + /// + /// * 'port' (u16): + /// - The endpoint port information as a u16 encoded integer. + /// + /// * 'ip_type' (u8): + /// - The endpoint ip version as a u8, 4 or 6. + /// + /// * 'protocol' (u8): + /// - UDP:1 or TCP:0 + /// + /// * 'placeholder1' (u8): + /// - Placeholder for further extra params. + /// + /// * 'placeholder2' (u8): + /// - Placeholder for further extra params. + /// + /// # Event: + /// * AxonServed; + /// - On successfully serving the axon info. + /// + /// # Raises: + /// * 'SubNetworkDoesNotExist': + /// - Attempting to set weights on a non-existent network. + /// + /// * 'NotRegistered': + /// - Attempting to set weights from a non registered account. + /// + /// * 'InvalidIpType': + /// - The ip type is not 4 or 6. + /// + /// * 'InvalidIpAddress': + /// - The numerically encoded ip address does not resolve to a proper ip. + /// + /// * 'ServingRateLimitExceeded': + /// - Attempting to set prometheus information withing the rate limit min. + /// + #[pallet::call_index(4)] + #[pallet::weight((Weight::from_parts(46_000_000, 0) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Normal, Pays::No))] + pub fn serve_axon( + origin: OriginFor, + netuid: u16, + version: u32, + ip: u128, + port: u16, + ip_type: u8, + protocol: u8, + placeholder1: u8, + placeholder2: u8, + ) -> DispatchResult { + Self::do_serve_axon( + origin, + netuid, + version, + ip, + port, + ip_type, + protocol, + placeholder1, + placeholder2, + ) + } + + /// ---- Set prometheus information for the neuron. + /// # Args: + /// * 'origin': (Origin): + /// - The signature of the calling hotkey. + /// + /// * 'netuid' (u16): + /// - The u16 network identifier. + /// + /// * 'version' (u16): + /// - The bittensor version identifier. + /// + /// * 'ip' (u128): + /// - The prometheus ip information as a u128 encoded integer. + /// + /// * 'port' (u16): + /// - The prometheus port information as a u16 encoded integer. + /// + /// * 'ip_type' (u8): + /// - The ip type v4 or v6. + /// + #[pallet::call_index(5)] + #[pallet::weight((Weight::from_parts(45_000_000, 0) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Normal, Pays::No))] + pub fn serve_prometheus( + origin: OriginFor, + netuid: u16, + version: u32, + ip: u128, + port: u16, + ip_type: u8, + ) -> DispatchResult { + Self::do_serve_prometheus(origin, netuid, version, ip, port, ip_type) + } + + /// ---- Registers a new neuron to the subnetwork. + /// + /// # Args: + /// * 'origin': (Origin): + /// - The signature of the calling hotkey. + /// + /// * 'netuid' (u16): + /// - The u16 network identifier. + /// + /// * 'block_number' ( u64 ): + /// - Block hash used to prove work done. + /// + /// * 'nonce' ( u64 ): + /// - Positive integer nonce used in POW. + /// + /// * 'work' ( Vec ): + /// - Vector encoded bytes representing work done. + /// + /// * 'hotkey' ( T::AccountId ): + /// - Hotkey to be registered to the network. + /// + /// * 'coldkey' ( T::AccountId ): + /// - Associated coldkey account. + /// + /// # Event: + /// * NeuronRegistered; + /// - On successfully registering a uid to a neuron slot on a subnetwork. + /// + /// # Raises: + /// * 'SubNetworkDoesNotExist': + /// - Attempting to register to a non existent network. + /// + /// * 'TooManyRegistrationsThisBlock': + /// - This registration exceeds the total allowed on this network this block. + /// + /// * 'HotKeyAlreadyRegisteredInSubNet': + /// - The hotkey is already registered on this network. + /// + /// * 'InvalidWorkBlock': + /// - The work has been performed on a stale, future, or non existent block. + /// + /// * 'InvalidDifficulty': + /// - The work does not match the difficulty. + /// + /// * 'InvalidSeal': + /// - The seal is incorrect. + /// + #[pallet::call_index(6)] + #[pallet::weight((Weight::from_parts(192_000_000, 0) + .saturating_add(T::DbWeight::get().reads(24)) + .saturating_add(T::DbWeight::get().writes(22)), DispatchClass::Normal, Pays::No))] + pub fn register( + origin: OriginFor, + netuid: u16, + block_number: u64, + nonce: u64, + work: Vec, + hotkey: T::AccountId, + coldkey: T::AccountId, + ) -> DispatchResult { + Self::do_registration(origin, netuid, block_number, nonce, work, hotkey, coldkey) + } + + /// Register the hotkey to root network + #[pallet::call_index(62)] + #[pallet::weight((Weight::from_parts(164_000_000, 0) + .saturating_add(T::DbWeight::get().reads(23)) + .saturating_add(T::DbWeight::get().writes(20)), DispatchClass::Normal, Pays::No))] + pub fn root_register(origin: OriginFor, hotkey: T::AccountId) -> DispatchResult { + Self::do_root_register(origin, hotkey) + } + + /// Attempt to adjust the senate membership to include a hotkey + #[pallet::call_index(63)] + #[pallet::weight((Weight::from_parts(0, 0) + .saturating_add(T::DbWeight::get().reads(0)) + .saturating_add(T::DbWeight::get().writes(0)), DispatchClass::Normal, Pays::Yes))] + pub fn adjust_senate(origin: OriginFor, hotkey: T::AccountId) -> DispatchResult { + Self::do_adjust_senate(origin, hotkey) + } + + /// User register a new subnetwork via burning token + #[pallet::call_index(7)] + #[pallet::weight((Weight::from_parts(177_000_000, 0) + .saturating_add(T::DbWeight::get().reads(26)) + .saturating_add(T::DbWeight::get().writes(24)), DispatchClass::Normal, Pays::No))] + pub fn burned_register( + origin: OriginFor, + netuid: u16, + hotkey: T::AccountId, + ) -> DispatchResult { + Self::do_burned_registration(origin, netuid, hotkey) + } + + /// The extrinsic for user to change its hotkey + ///#[pallet::call_index(70)] + ///#[pallet::weight((Weight::from_parts(1_940_000_000, 0) + ///.saturating_add(T::DbWeight::get().reads(272)) + ///.saturating_add(T::DbWeight::get().writes(527)), DispatchClass::Operational, Pays::No))] + ///pub fn swap_hotkey( + /// origin: OriginFor, + /// hotkey: T::AccountId, + /// new_hotkey: T::AccountId, + ///) -> DispatchResultWithPostInfo { + /// Self::do_swap_hotkey(origin, &hotkey, &new_hotkey) + ///} + + /// The extrinsic for user to change the coldkey associated with their account. + /// + /// # Arguments + /// + /// * `origin` - The origin of the call, must be signed by the old coldkey. + /// * `old_coldkey` - The current coldkey associated with the account. + /// * `new_coldkey` - The new coldkey to be associated with the account. + /// + /// # Returns + /// + /// Returns a `DispatchResultWithPostInfo` indicating success or failure of the operation. + /// + /// # Weight + /// + /// Weight is calculated based on the number of database reads and writes. + #[pallet::call_index(71)] + #[pallet::weight((Weight::from_parts(1_940_000_000, 0) + .saturating_add(T::DbWeight::get().reads(272)) + .saturating_add(T::DbWeight::get().writes(527)), DispatchClass::Operational, Pays::No))] + pub fn swap_coldkey( + origin: OriginFor, + new_coldkey: T::AccountId, + ) -> DispatchResultWithPostInfo { + Self::do_swap_coldkey(origin, &new_coldkey) + } + /// Unstakes all tokens associated with a hotkey and transfers them to a new coldkey. + /// + /// # Arguments + /// + /// * `origin` - The origin of the call, must be signed by the current coldkey. + /// * `hotkey` - The hotkey associated with the stakes to be unstaked. + /// * `new_coldkey` - The new coldkey to receive the unstaked tokens. + /// + /// # Returns + /// + /// Returns a `DispatchResult` indicating success or failure of the operation. + /// + /// # Weight + /// + /// Weight is calculated based on the number of database reads and writes. + #[cfg(test)] + #[pallet::call_index(72)] + #[pallet::weight((Weight::from_parts(21_000_000, 0) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)), DispatchClass::Operational, Pays::No))] + pub fn schedule_coldkey_swap( + origin: OriginFor, + new_coldkey: T::AccountId, + work: Vec, + block_number: u64, + nonce: u64, + ) -> DispatchResult { + // Attain the calling coldkey from the origin. + let old_coldkey: T::AccountId = ensure_signed(origin)?; + Self::do_schedule_coldkey_swap(&old_coldkey, &new_coldkey, work, block_number, nonce) + } + + // ---- SUDO ONLY FUNCTIONS ------------------------------------------------------------ + + // ================================== + // ==== Parameter Sudo calls ======== + // ================================== + // Each function sets the corresponding hyper paramter on the specified network + // Args: + // * 'origin': (Origin): + // - The caller, must be sudo. + // + // * `netuid` (u16): + // - The network identifier. + // + // * `hyperparameter value` (u16): + // - The value of the hyper parameter. + // + + /// Authenticates a council proposal and dispatches a function call with `Root` origin. + /// + /// The dispatch origin for this call must be a council majority. + /// + /// ## Complexity + /// - O(1). + #[pallet::call_index(51)] + #[pallet::weight((Weight::from_parts(0, 0), DispatchClass::Operational, Pays::No))] + pub fn sudo( + origin: OriginFor, + call: Box, + ) -> DispatchResultWithPostInfo { + // This is a public call, so we ensure that the origin is a council majority. + T::CouncilOrigin::ensure_origin(origin)?; + + let result = call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into()); + let error = result.map(|_| ()).map_err(|e| e.error); + Self::deposit_event(Event::Sudid(error)); + + return result; + } + + /// Authenticates a council proposal and dispatches a function call with `Root` origin. + /// This function does not check the weight of the call, and instead allows the + /// user to specify the weight of the call. + /// + /// The dispatch origin for this call must be a council majority. + /// + /// ## Complexity + /// - O(1). + #[allow(deprecated)] + #[pallet::call_index(52)] + #[pallet::weight((*weight, call.get_dispatch_info().class, Pays::No))] + pub fn sudo_unchecked_weight( + origin: OriginFor, + call: Box, + weight: Weight, + ) -> DispatchResultWithPostInfo { + // We dont need to check the weight witness, suppress warning. + // See https://github.com/paritytech/polkadot-sdk/pull/1818. + let _ = weight; + + // This is a public call, so we ensure that the origin is a council majority. + T::CouncilOrigin::ensure_origin(origin)?; + + let result = call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into()); + let error = result.map(|_| ()).map_err(|e| e.error); + Self::deposit_event(Event::Sudid(error)); + + return result; + } + + /// User vote on a proposal + #[pallet::call_index(55)] + #[pallet::weight((Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().reads(0)) + .saturating_add(T::DbWeight::get().writes(0)), DispatchClass::Operational))] + pub fn vote( + origin: OriginFor, + hotkey: T::AccountId, + proposal: T::Hash, + #[pallet::compact] index: u32, + approve: bool, + ) -> DispatchResultWithPostInfo { + Self::do_vote_root(origin, &hotkey, proposal, index, approve) + } + + /// User register a new subnetwork + #[pallet::call_index(59)] + #[pallet::weight((Weight::from_parts(157_000_000, 0) + .saturating_add(T::DbWeight::get().reads(16)) + .saturating_add(T::DbWeight::get().writes(30)), DispatchClass::Operational, Pays::No))] + pub fn register_network(origin: OriginFor) -> DispatchResult { + Self::user_add_network(origin) + } + + /// Facility extrinsic for user to get taken from faucet + /// It is only available when pow-faucet feature enabled + /// Just deployed in testnet and devnet for testing purpose + #[pallet::call_index(60)] + #[pallet::weight((Weight::from_parts(91_000_000, 0) + .saturating_add(T::DbWeight::get().reads(27)) + .saturating_add(T::DbWeight::get().writes(22)), DispatchClass::Normal, Pays::No))] + pub fn faucet( + origin: OriginFor, + block_number: u64, + nonce: u64, + work: Vec, + ) -> DispatchResult { + if cfg!(feature = "pow-faucet") { + return Self::do_faucet(origin, block_number, nonce, work); + } + + Err(Error::::FaucetDisabled.into()) + } + + /// 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)), DispatchClass::Operational, Pays::No))] + pub fn dissolve_network(origin: OriginFor, netuid: u16) -> DispatchResult { + Self::user_remove_network(origin, netuid) + } + + /// Sets values for liquid alpha + #[pallet::call_index(64)] + #[pallet::weight((0, DispatchClass::Operational, Pays::No))] + pub fn sudo_hotfix_swap_coldkey_delegates( + _origin: OriginFor, + _old_coldkey: T::AccountId, + _new_coldkey: T::AccountId, + ) -> DispatchResult { + Ok(()) + } + } +} \ No newline at end of file diff --git a/pallets/subtensor/src/errors.rs b/pallets/subtensor/src/macros/errors.rs similarity index 100% rename from pallets/subtensor/src/errors.rs rename to pallets/subtensor/src/macros/errors.rs diff --git a/pallets/subtensor/src/events.rs b/pallets/subtensor/src/macros/events.rs similarity index 100% rename from pallets/subtensor/src/events.rs rename to pallets/subtensor/src/macros/events.rs diff --git a/pallets/subtensor/src/macros/genesis.rs b/pallets/subtensor/src/macros/genesis.rs new file mode 100644 index 0000000000..5fbf613d6a --- /dev/null +++ b/pallets/subtensor/src/macros/genesis.rs @@ -0,0 +1,163 @@ +use frame_support::pallet_macros::pallet_section; + +/// A [`pallet_section`] that defines the errors for a pallet. +/// This can later be imported into the pallet using [`import_section`]. +#[pallet_section] +mod genesis { + + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) { + // Set initial total issuance from balances + TotalIssuance::::put(self.balances_issuance); + + // Subnet config values + let netuid: u16 = 3; + let tempo = 99; + let max_uids = 4096; + + // The functions for initializing new networks/setting defaults cannot be run directly from genesis functions like extrinsics would + // --- Set this network uid to alive. + NetworksAdded::::insert(netuid, true); + + // --- Fill tempo memory item. + Tempo::::insert(netuid, tempo); + + // --- Fill modality item. + // Only modality 0 exists (text) + NetworkModality::::insert(netuid, 0); + + // Make network parameters explicit. + if !Tempo::::contains_key(netuid) { + Tempo::::insert(netuid, Tempo::::get(netuid)); + } + if !Kappa::::contains_key(netuid) { + Kappa::::insert(netuid, Kappa::::get(netuid)); + } + if !Difficulty::::contains_key(netuid) { + Difficulty::::insert(netuid, Difficulty::::get(netuid)); + } + if !MaxAllowedUids::::contains_key(netuid) { + MaxAllowedUids::::insert(netuid, MaxAllowedUids::::get(netuid)); + } + if !ImmunityPeriod::::contains_key(netuid) { + ImmunityPeriod::::insert(netuid, ImmunityPeriod::::get(netuid)); + } + if !ActivityCutoff::::contains_key(netuid) { + ActivityCutoff::::insert(netuid, ActivityCutoff::::get(netuid)); + } + if !EmissionValues::::contains_key(netuid) { + EmissionValues::::insert(netuid, EmissionValues::::get(netuid)); + } + if !MaxWeightsLimit::::contains_key(netuid) { + MaxWeightsLimit::::insert(netuid, MaxWeightsLimit::::get(netuid)); + } + if !MinAllowedWeights::::contains_key(netuid) { + MinAllowedWeights::::insert(netuid, MinAllowedWeights::::get(netuid)); + } + if !RegistrationsThisInterval::::contains_key(netuid) { + RegistrationsThisInterval::::insert( + netuid, + RegistrationsThisInterval::::get(netuid), + ); + } + if !POWRegistrationsThisInterval::::contains_key(netuid) { + POWRegistrationsThisInterval::::insert( + netuid, + POWRegistrationsThisInterval::::get(netuid), + ); + } + if !BurnRegistrationsThisInterval::::contains_key(netuid) { + BurnRegistrationsThisInterval::::insert( + netuid, + BurnRegistrationsThisInterval::::get(netuid), + ); + } + + // Set max allowed uids + MaxAllowedUids::::insert(netuid, max_uids); + + let mut next_uid = 0; + + for (coldkey, hotkeys) in self.stakes.iter() { + for (hotkey, stake_uid) in hotkeys.iter() { + let (stake, uid) = stake_uid; + + // Expand Yuma Consensus with new position. + Rank::::mutate(netuid, |v| v.push(0)); + Trust::::mutate(netuid, |v| v.push(0)); + Active::::mutate(netuid, |v| v.push(true)); + Emission::::mutate(netuid, |v| v.push(0)); + Consensus::::mutate(netuid, |v| v.push(0)); + Incentive::::mutate(netuid, |v| v.push(0)); + Dividends::::mutate(netuid, |v| v.push(0)); + LastUpdate::::mutate(netuid, |v| v.push(0)); + PruningScores::::mutate(netuid, |v| v.push(0)); + ValidatorTrust::::mutate(netuid, |v| v.push(0)); + ValidatorPermit::::mutate(netuid, |v| v.push(false)); + + // Insert account information. + Keys::::insert(netuid, uid, hotkey.clone()); // Make hotkey - uid association. + Uids::::insert(netuid, hotkey.clone(), uid); // Make uid - hotkey association. + BlockAtRegistration::::insert(netuid, uid, 0); // Fill block at registration. + IsNetworkMember::::insert(hotkey.clone(), netuid, true); // Fill network is member. + + // Fill stake information. + Owner::::insert(hotkey.clone(), coldkey.clone()); + + TotalHotkeyStake::::insert(hotkey.clone(), stake); + TotalColdkeyStake::::insert( + coldkey.clone(), + TotalColdkeyStake::::get(coldkey).saturating_add(*stake), + ); + + // Update total issuance value + TotalIssuance::::put(TotalIssuance::::get().saturating_add(*stake)); + + Stake::::insert(hotkey.clone(), coldkey.clone(), stake); + + next_uid += 1; + } + } + + // Set correct length for Subnet neurons + SubnetworkN::::insert(netuid, next_uid); + + // --- Increase total network count. + TotalNetworks::::mutate(|n| *n += 1); + + // Get the root network uid. + let root_netuid: u16 = 0; + + // Set the root network as added. + NetworksAdded::::insert(root_netuid, true); + + // Increment the number of total networks. + TotalNetworks::::mutate(|n| *n += 1); + // Set the number of validators to 1. + SubnetworkN::::insert(root_netuid, 0); + + // Set the maximum number to the number of senate members. + MaxAllowedUids::::insert(root_netuid, 64u16); + + // Set the maximum number to the number of validators to all members. + MaxAllowedValidators::::insert(root_netuid, 64u16); + + // Set the min allowed weights to zero, no weights restrictions. + MinAllowedWeights::::insert(root_netuid, 0); + + // Set the max weight limit to infitiy, no weight restrictions. + MaxWeightsLimit::::insert(root_netuid, u16::MAX); + + // Add default root tempo. + Tempo::::insert(root_netuid, 100); + + // Set the root network as open. + NetworkRegistrationAllowed::::insert(root_netuid, true); + + // Set target registrations for validators as 1 per block. + TargetRegistrationsPerInterval::::insert(root_netuid, 1); + } + } + +} \ No newline at end of file diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs new file mode 100644 index 0000000000..baa9de21a9 --- /dev/null +++ b/pallets/subtensor/src/macros/hooks.rs @@ -0,0 +1,75 @@ +use frame_support::pallet_macros::pallet_section; + +/// A [`pallet_section`] that defines the events for a pallet. +/// This can later be imported into the pallet using [`import_section`]. +#[pallet_section] +mod hooks { + // ================ + // ==== Hooks ===== + // ================ + #[pallet::hooks] + impl Hooks> for Pallet { + // ---- Called on the initialization of this pallet. (the order of on_finalize calls is determined in the runtime) + // + // # Args: + // * 'n': (BlockNumberFor): + // - The number of the block we are initializing. + fn on_initialize(_block_number: BlockNumberFor) -> Weight { + let block_step_result = Self::block_step(); + match block_step_result { + Ok(_) => { + // --- If the block step was successful, return the weight. + log::info!("Successfully ran block step."); + Weight::from_parts(110_634_229_000_u64, 0) + .saturating_add(T::DbWeight::get().reads(8304_u64)) + .saturating_add(T::DbWeight::get().writes(110_u64)) + } + Err(e) => { + // --- If the block step was unsuccessful, return the weight anyway. + log::error!("Error while stepping block: {:?}", e); + Weight::from_parts(110_634_229_000_u64, 0) + .saturating_add(T::DbWeight::get().reads(8304_u64)) + .saturating_add(T::DbWeight::get().writes(110_u64)) + } + } + } + + fn on_runtime_upgrade() -> frame_support::weights::Weight { + // --- Migrate storage + let mut weight = frame_support::weights::Weight::from_parts(0, 0); + + // Hex encoded foundation coldkey + let hex = hex_literal::hex![ + "feabaafee293d3b76dae304e2f9d885f77d2b17adab9e17e921b321eccd61c77" + ]; + weight = weight + // Initializes storage version (to 1) + .saturating_add(migrations::migrate_to_v1_separate_emission::migrate_to_v1_separate_emission::()) + // Storage version v1 -> v2 + .saturating_add(migrations::migrate_to_v2_fixed_total_stake::migrate_to_v2_fixed_total_stake::()) + // Doesn't check storage version. TODO: Remove after upgrade + .saturating_add(migrations::migrate_create_root_network::migrate_create_root_network::()) + // Storage version v2 -> v3 + .saturating_add(migrations::migrate_transfer_ownership_to_foundation::migrate_transfer_ownership_to_foundation::( + hex, + )) + // Storage version v3 -> v4 + .saturating_add(migrations::migrate_delete_subnet_21::migrate_delete_subnet_21::()) + // Storage version v4 -> v5 + .saturating_add(migrations::migrate_delete_subnet_3::migrate_delete_subnet_3::()) + // Doesn't check storage version. TODO: Remove after upgrade + // Storage version v5 -> v6 + .saturating_add(migrations::migrate_total_issuance::migration5_total_issuance::(false)) + // Populate OwnedHotkeys map for coldkey swap. Doesn't update storage vesion. + // Storage version v6 -> v7 + .saturating_add(migrations::migrate_populate_owned_hotkeys::migrate_populate_owned::()) + // Populate StakingHotkeys map for coldkey swap. Doesn't update storage vesion. + // Storage version v7 -> v8 + .saturating_add(migrations::migrate_populate_staking_hotkeys::migrate_populate_staking_hotkeys::()) + // Fix total coldkey stake. + // Storage version v8 -> v9 + .saturating_add(migrations::migrate_fix_total_coldkey_stake::migrate_fix_total_coldkey_stake::()); + weight + } + } +} \ No newline at end of file diff --git a/pallets/subtensor/src/macros/mod.rs b/pallets/subtensor/src/macros/mod.rs new file mode 100644 index 0000000000..d64983d528 --- /dev/null +++ b/pallets/subtensor/src/macros/mod.rs @@ -0,0 +1,6 @@ +pub mod events; +pub mod errors; +pub mod dispatches; +pub mod genesis; +pub mod hooks; +pub mod config; \ No newline at end of file diff --git a/pallets/subtensor/src/migrations/migrate_create_root_network.rs b/pallets/subtensor/src/migrations/migrate_create_root_network.rs new file mode 100644 index 0000000000..ff858ec6ac --- /dev/null +++ b/pallets/subtensor/src/migrations/migrate_create_root_network.rs @@ -0,0 +1,99 @@ +use super::*; +use frame_support::{ + pallet_prelude::{Identity, OptionQuery}, + storage_alias, + traits::{Get, DefensiveResult}, + weights::Weight, +}; +use sp_std::vec::Vec; + +// TODO (camfairchild): TEST MIGRATION + +/// Module containing deprecated storage format for LoadedEmission +pub mod deprecated_loaded_emission_format { + use super::*; + + #[storage_alias] + pub(super) type LoadedEmission = + StorageMap, Identity, u16, Vec<(AccountIdOf, u64)>, OptionQuery>; +} + +/// Migrates the storage to create the root network +/// +/// This function performs the following steps: +/// 1. Checks if the root network already exists +/// 2. If not, creates the root network with default settings +/// 3. Removes all existing senate members +/// +/// # Arguments +/// +/// * `T` - The Config trait of the pallet +/// +/// # Returns +/// +/// * `Weight` - The computational weight of this operation +/// +/// # Example +/// +/// ``` +/// let weight = migrate_create_root_network::(); +/// ``` +pub fn migrate_create_root_network() -> Weight { + // Define the root network UID + let root_netuid: u16 = 0; + + // Initialize weight counter + let mut weight = T::DbWeight::get().reads(1); + + // Check if root network already exists + if NetworksAdded::::get(root_netuid) { + // Return early if root network already exists + return weight; + } + + // Set the root network as added + NetworksAdded::::insert(root_netuid, true); + + // Increment the total number of networks + TotalNetworks::::mutate(|n| *n += 1); + + // Set the maximum number of UIDs to the number of senate members + MaxAllowedUids::::insert(root_netuid, 64); + + // Set the maximum number of validators to all members + MaxAllowedValidators::::insert(root_netuid, 64); + + // Set the minimum allowed weights to zero (no weight restrictions) + MinAllowedWeights::::insert(root_netuid, 0); + + // Set the maximum weight limit to u16::MAX (no weight restrictions) + MaxWeightsLimit::::insert(root_netuid, u16::MAX); + + // Set default root tempo + Tempo::::insert(root_netuid, 100); + + // Set the root network as open for registration + NetworkRegistrationAllowed::::insert(root_netuid, true); + + // Set target registrations for validators as 1 per block + TargetRegistrationsPerInterval::::insert(root_netuid, 1); + + // TODO: Consider if WeightsSetRateLimit should be set + // WeightsSetRateLimit::::insert(root_netuid, 7200); + + // Accrue weight for database writes + weight.saturating_accrue(T::DbWeight::get().writes(8)); + + // Remove all existing senate members + for hotkey_i in T::SenateMembers::members().iter() { + // Remove votes associated with the member + T::TriumvirateInterface::remove_votes(hotkey_i).defensive_ok(); + // Remove the member from the senate + T::SenateMembers::remove_member(hotkey_i).defensive_ok(); + + // Accrue weight for database operations + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + } + + weight +} \ No newline at end of file diff --git a/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs b/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs new file mode 100644 index 0000000000..df6a2ae34c --- /dev/null +++ b/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs @@ -0,0 +1,127 @@ +use super::*; +use frame_support::{ + pallet_prelude::*, storage_alias, + traits::{Get, GetStorageVersion, StorageVersion}, + weights::Weight, +}; +use log::info; +use sp_std::vec::Vec; + +/// Constant for logging purposes +const LOG_TARGET: &str = "migrate_delete_subnet_21"; + +/// Module containing deprecated storage format +pub mod deprecated_loaded_emission_format { + use super::*; + + #[storage_alias] + pub(super) type LoadedEmission = + StorageMap, Identity, u16, Vec<(AccountIdOf, u64)>, OptionQuery>; +} + +/// Migrates the storage to delete subnet 21 +/// +/// This function performs the following steps: +/// 1. Checks if the migration is necessary +/// 2. Removes all storage related to subnet 21 +/// 3. Updates the storage version +/// +/// # Arguments +/// +/// * `T` - The Config trait of the pallet +/// +/// # Returns +/// +/// * `Weight` - The computational weight of this operation +/// +/// # Example +/// +/// ``` +/// let weight = migrate_delete_subnet_21::(); +/// ``` +pub fn migrate_delete_subnet_21() -> Weight { + let new_storage_version = 4; + + // Setup migration weight + let mut weight = T::DbWeight::get().reads(1); + + // Grab current version + let onchain_version = Pallet::::on_chain_storage_version(); + + // Only runs if we haven't already updated version past above new_storage_version and subnet 21 exists. + if onchain_version < new_storage_version && Pallet::::if_subnet_exist(21) { + info!(target: LOG_TARGET, ">>> Removing subnet 21 {:?}", onchain_version); + + let netuid = 21; + + // We do this all manually as we don't want to call code related to giving subnet owner back their locked token cost. + // Remove network count + SubnetworkN::::remove(netuid); + + // Remove network modality storage + NetworkModality::::remove(netuid); + + // Remove netuid from added networks + NetworksAdded::::remove(netuid); + + // Decrement the network counter + TotalNetworks::::mutate(|n| *n -= 1); + + // Remove network registration time + NetworkRegisteredAt::::remove(netuid); + + weight.saturating_accrue(T::DbWeight::get().writes(5)); + + // Remove incentive mechanism memory + let _ = Uids::::clear_prefix(netuid, u32::MAX, None); + let _ = Keys::::clear_prefix(netuid, u32::MAX, None); + let _ = Bonds::::clear_prefix(netuid, u32::MAX, None); + let _ = Weights::::clear_prefix(netuid, u32::MAX, None); + + weight.saturating_accrue(T::DbWeight::get().writes(4)); + + // Remove various network-related parameters + Rank::::remove(netuid); + Trust::::remove(netuid); + Active::::remove(netuid); + Emission::::remove(netuid); + Incentive::::remove(netuid); + Consensus::::remove(netuid); + Dividends::::remove(netuid); + PruningScores::::remove(netuid); + LastUpdate::::remove(netuid); + ValidatorPermit::::remove(netuid); + ValidatorTrust::::remove(netuid); + + weight.saturating_accrue(T::DbWeight::get().writes(11)); + + // Erase network parameters + Tempo::::remove(netuid); + Kappa::::remove(netuid); + Difficulty::::remove(netuid); + MaxAllowedUids::::remove(netuid); + ImmunityPeriod::::remove(netuid); + ActivityCutoff::::remove(netuid); + EmissionValues::::remove(netuid); + MaxWeightsLimit::::remove(netuid); + MinAllowedWeights::::remove(netuid); + RegistrationsThisInterval::::remove(netuid); + POWRegistrationsThisInterval::::remove(netuid); + BurnRegistrationsThisInterval::::remove(netuid); + + weight.saturating_accrue(T::DbWeight::get().writes(12)); + + // Update storage version + StorageVersion::new(new_storage_version).put::>(); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + + weight + } else { + info!(target: LOG_TARGET, "Migration to v4 already done or subnet 21 doesn't exist!"); + Weight::zero() + } +} + +// TODO: Add unit tests for this migration +// TODO: Consider adding error handling for storage operations +// TODO: Verify that all relevant storage items for subnet 21 are removed \ No newline at end of file diff --git a/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs b/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs new file mode 100644 index 0000000000..04df542695 --- /dev/null +++ b/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs @@ -0,0 +1,130 @@ +use super::*; +use frame_support::{ + pallet_prelude::*, storage_alias, + traits::{Get, GetStorageVersion, StorageVersion}, + weights::Weight, +}; +use log::info; +use sp_std::vec::Vec; + +/// Constant for logging purposes +const LOG_TARGET: &str = "migrate_delete_subnet_3"; + +/// Module containing deprecated storage format +pub mod deprecated_loaded_emission_format { + use super::*; + + #[storage_alias] + pub(super) type LoadedEmission = + StorageMap, Identity, u16, Vec<(AccountIdOf, u64)>, OptionQuery>; +} + +/// Migrates the storage to delete subnet 3 +/// +/// This function performs the following steps: +/// 1. Checks if the migration is necessary +/// 2. Removes all storage related to subnet 3 +/// 3. Updates the storage version +/// +/// # Arguments +/// +/// * `T` - The Config trait of the pallet +/// +/// # Returns +/// +/// * `Weight` - The computational weight of this operation +/// +/// # Example +/// +/// ``` +/// let weight = migrate_delete_subnet_3::(); +/// ``` +pub fn migrate_delete_subnet_3() -> Weight { + let new_storage_version = 5; + + // Initialize weight counter + let mut weight = T::DbWeight::get().reads(1); + + // Get current on-chain storage version + let onchain_version = Pallet::::on_chain_storage_version(); + + // Only proceed if current version is less than the new version and subnet 3 exists + if onchain_version < new_storage_version && Pallet::::if_subnet_exist(3) { + info!( + target: LOG_TARGET, + "Removing subnet 3. Current version: {:?}", + onchain_version + ); + + let netuid = 3; + + // Remove network count + SubnetworkN::::remove(netuid); + + // Remove network modality storage + NetworkModality::::remove(netuid); + + // Remove netuid from added networks + NetworksAdded::::remove(netuid); + + // Decrement the network counter + TotalNetworks::::mutate(|n| *n -= 1); + + // Remove network registration time + NetworkRegisteredAt::::remove(netuid); + + weight.saturating_accrue(T::DbWeight::get().writes(5)); + + // Remove incentive mechanism memory + let _ = Uids::::clear_prefix(netuid, u32::MAX, None); + let _ = Keys::::clear_prefix(netuid, u32::MAX, None); + let _ = Bonds::::clear_prefix(netuid, u32::MAX, None); + let _ = Weights::::clear_prefix(netuid, u32::MAX, None); + + weight.saturating_accrue(T::DbWeight::get().writes(4)); + + // Remove various network-related parameters + Rank::::remove(netuid); + Trust::::remove(netuid); + Active::::remove(netuid); + Emission::::remove(netuid); + Incentive::::remove(netuid); + Consensus::::remove(netuid); + Dividends::::remove(netuid); + PruningScores::::remove(netuid); + LastUpdate::::remove(netuid); + ValidatorPermit::::remove(netuid); + ValidatorTrust::::remove(netuid); + + weight.saturating_accrue(T::DbWeight::get().writes(11)); + + // Erase network parameters + Tempo::::remove(netuid); + Kappa::::remove(netuid); + Difficulty::::remove(netuid); + MaxAllowedUids::::remove(netuid); + ImmunityPeriod::::remove(netuid); + ActivityCutoff::::remove(netuid); + EmissionValues::::remove(netuid); + MaxWeightsLimit::::remove(netuid); + MinAllowedWeights::::remove(netuid); + RegistrationsThisInterval::::remove(netuid); + POWRegistrationsThisInterval::::remove(netuid); + BurnRegistrationsThisInterval::::remove(netuid); + + weight.saturating_accrue(T::DbWeight::get().writes(12)); + + // Update storage version + StorageVersion::new(new_storage_version).put::>(); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + + weight + } else { + info!(target: LOG_TARGET, "Migration to v5 already completed or subnet 3 doesn't exist"); + Weight::zero() + } +} + +// TODO: Add unit tests for this migration +// TODO: Consider adding error handling for storage operations +// TODO: Verify that all relevant storage items for subnet 3 are removed \ No newline at end of file diff --git a/pallets/subtensor/src/migrations/migrate_fix_total_coldkey_stake.rs b/pallets/subtensor/src/migrations/migrate_fix_total_coldkey_stake.rs new file mode 100644 index 0000000000..20c47e29c6 --- /dev/null +++ b/pallets/subtensor/src/migrations/migrate_fix_total_coldkey_stake.rs @@ -0,0 +1,73 @@ +use super::*; +use frame_support::{ + pallet_prelude::{Identity, OptionQuery}, + storage_alias, + traits::{Get, GetStorageVersion, StorageVersion}, + weights::Weight, +}; +use sp_std::vec::Vec; + +// TODO (camfairchild): TEST MIGRATION +pub mod deprecated_loaded_emission_format { + use super::*; + + #[storage_alias] + pub(super) type LoadedEmission = + StorageMap, Identity, u16, Vec<(AccountIdOf, u64)>, OptionQuery>; +} + +/// Migrates and fixes the total coldkey stake. +/// +/// This function iterates through all staking hotkeys, calculates the total stake for each coldkey, +/// and updates the `TotalColdkeyStake` storage accordingly. The migration is only performed if the +/// on-chain storage version is 6. +/// +/// # Returns +/// The weight of the migration process. +pub fn do_migrate_fix_total_coldkey_stake() -> Weight { + // Initialize the weight with one read operation. + let mut weight = T::DbWeight::get().reads(1); + + // Iterate through all staking hotkeys. + for (coldkey, hotkey_vec) in StakingHotkeys::::iter() { + // Init the zero value. + let mut coldkey_stake_sum: u64 = 0; + weight = weight.saturating_add(T::DbWeight::get().reads(1)); + + // Calculate the total stake for the current coldkey. + for hotkey in hotkey_vec { + // Cant fail on retrieval. + coldkey_stake_sum = + coldkey_stake_sum.saturating_add(Stake::::get(hotkey, coldkey.clone())); + weight = weight.saturating_add(T::DbWeight::get().reads(1)); + } + // Update the `TotalColdkeyStake` storage with the calculated stake sum. + // Cant fail on insert. + TotalColdkeyStake::::insert(coldkey.clone(), coldkey_stake_sum); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); + } + weight +} +// Public migrate function to be called by Lib.rs on upgrade. +pub fn migrate_fix_total_coldkey_stake() -> Weight { + let current_storage_version: u16 = 7; + let next_storage_version: u16 = 8; + + // Initialize the weight with one read operation. + let mut weight = T::DbWeight::get().reads(1); + + // Grab the current on-chain storage version. + // Cant fail on retrieval. + let onchain_version = Pallet::::on_chain_storage_version(); + + // Only run this migration on storage version 6. + if onchain_version == current_storage_version { + weight = weight.saturating_add(do_migrate_fix_total_coldkey_stake::()); + // Cant fail on insert. + StorageVersion::new(next_storage_version).put::>(); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + } + + // Return the migration weight. + weight +} diff --git a/pallets/subtensor/src/migrations/migrate_populate_owned_hotkeys.rs b/pallets/subtensor/src/migrations/migrate_populate_owned_hotkeys.rs new file mode 100644 index 0000000000..23cf90d33a --- /dev/null +++ b/pallets/subtensor/src/migrations/migrate_populate_owned_hotkeys.rs @@ -0,0 +1,83 @@ +use super::*; +use frame_support::{ + pallet_prelude::{Identity, OptionQuery}, + storage_alias, + traits::{Get}, + weights::Weight, +}; +use log::info; +use sp_std::vec::Vec; + +const LOG_TARGET_1: &str = "migrate_populate_owned"; + +/// Module containing deprecated storage format for LoadedEmission +pub mod deprecated_loaded_emission_format { + use super::*; + + #[storage_alias] + pub(super) type LoadedEmission = + StorageMap, Identity, u16, Vec<(AccountIdOf, u64)>, OptionQuery>; +} + + +/// Migrate the OwnedHotkeys map to the new storage format +pub fn migrate_populate_owned() -> Weight { + // Setup migration weight + let mut weight = T::DbWeight::get().reads(1); + let migration_name = "Populate OwnedHotkeys map"; + + // Check if this migration is needed (if OwnedHotkeys map is empty) + let migrate = OwnedHotkeys::::iter().next().is_none(); + + // Only runs if the migration is needed + if migrate { + info!(target: LOG_TARGET_1, ">>> Starting Migration: {}", migration_name); + + let mut longest_hotkey_vector: usize = 0; + let mut longest_coldkey: Option = None; + let mut keys_touched: u64 = 0; + let mut storage_reads: u64 = 0; + let mut storage_writes: u64 = 0; + + // Iterate through all Owner entries + Owner::::iter().for_each(|(hotkey, coldkey)| { + storage_reads = storage_reads.saturating_add(1); // Read from Owner storage + let mut hotkeys = OwnedHotkeys::::get(&coldkey); + storage_reads = storage_reads.saturating_add(1); // Read from OwnedHotkeys storage + + // Add the hotkey if it's not already in the vector + if !hotkeys.contains(&hotkey) { + hotkeys.push(hotkey); + keys_touched = keys_touched.saturating_add(1); + + // Update longest hotkey vector info + if longest_hotkey_vector < hotkeys.len() { + longest_hotkey_vector = hotkeys.len(); + longest_coldkey = Some(coldkey.clone()); + } + + // Update the OwnedHotkeys storage + OwnedHotkeys::::insert(&coldkey, hotkeys); + storage_writes = storage_writes.saturating_add(1); // Write to OwnedHotkeys storage + } + + // Accrue weight for reads and writes + weight = weight.saturating_add(T::DbWeight::get().reads_writes(2, 1)); + }); + + // Log migration results + info!( + target: LOG_TARGET_1, + "Migration {} finished. Keys touched: {}, Longest hotkey vector: {}, Storage reads: {}, Storage writes: {}", + migration_name, keys_touched, longest_hotkey_vector, storage_reads, storage_writes + ); + if let Some(c) = longest_coldkey { + info!(target: LOG_TARGET_1, "Longest hotkey vector is controlled by: {:?}", c); + } + + weight + } else { + info!(target: LOG_TARGET_1, "Migration {} already done!", migration_name); + Weight::zero() + } +} \ No newline at end of file diff --git a/pallets/subtensor/src/migrations/migrate_populate_staking_hotkeys.rs b/pallets/subtensor/src/migrations/migrate_populate_staking_hotkeys.rs new file mode 100644 index 0000000000..2c0988bbd3 --- /dev/null +++ b/pallets/subtensor/src/migrations/migrate_populate_staking_hotkeys.rs @@ -0,0 +1,85 @@ + +use super::*; +use frame_support::{ + pallet_prelude::{Identity, OptionQuery}, + storage_alias, + traits::{Get}, + weights::Weight, +}; +use log::info; +use sp_std::vec::Vec; +const LOG_TARGET_1: &str = "migrate_populate_owned"; + +/// Module containing deprecated storage format for LoadedEmission +pub mod deprecated_loaded_emission_format { + use super::*; + + #[storage_alias] + pub(super) type LoadedEmission = + StorageMap, Identity, u16, Vec<(AccountIdOf, u64)>, OptionQuery>; +} + + +/// Populate the StakingHotkeys map from Stake map +pub fn migrate_populate_staking_hotkeys() -> Weight { + // Setup migration weight + let mut weight = T::DbWeight::get().reads(1); + let migration_name = "Populate StakingHotkeys map"; + + // Check if this migration is needed (if StakingHotkeys map is empty) + let migrate = StakingHotkeys::::iter().next().is_none(); + + // Only runs if the migration is needed + if migrate { + info!(target: LOG_TARGET_1, ">>> Starting Migration: {}", migration_name); + + let mut longest_hotkey_vector: usize = 0; + let mut longest_coldkey: Option = None; + let mut keys_touched: u64 = 0; + let mut storage_reads: u64 = 0; + let mut storage_writes: u64 = 0; + + // Iterate through all Owner entries + Stake::::iter().for_each(|(hotkey, coldkey, stake)| { + storage_reads = storage_reads.saturating_add(1); // Read from Owner storage + if stake > 0 { + let mut hotkeys = StakingHotkeys::::get(&coldkey); + storage_reads = storage_reads.saturating_add(1); // Read from StakingHotkeys storage + + // Add the hotkey if it's not already in the vector + if !hotkeys.contains(&hotkey) { + hotkeys.push(hotkey); + keys_touched = keys_touched.saturating_add(1); + + // Update longest hotkey vector info + if longest_hotkey_vector < hotkeys.len() { + longest_hotkey_vector = hotkeys.len(); + longest_coldkey = Some(coldkey.clone()); + } + + // Update the StakingHotkeys storage + StakingHotkeys::::insert(&coldkey, hotkeys); + storage_writes = storage_writes.saturating_add(1); // Write to StakingHotkeys storage + } + + // Accrue weight for reads and writes + weight = weight.saturating_add(T::DbWeight::get().reads_writes(2, 1)); + } + }); + + // Log migration results + info!( + target: LOG_TARGET_1, + "Migration {} finished. Keys touched: {}, Longest hotkey vector: {}, Storage reads: {}, Storage writes: {}", + migration_name, keys_touched, longest_hotkey_vector, storage_reads, storage_writes + ); + if let Some(c) = longest_coldkey { + info!(target: LOG_TARGET_1, "Longest hotkey vector is controlled by: {:?}", c); + } + + weight + } else { + info!(target: LOG_TARGET_1, "Migration {} already done!", migration_name); + Weight::zero() + } +} diff --git a/pallets/subtensor/src/migrations/migrate_to_v1_separate_emission.rs b/pallets/subtensor/src/migrations/migrate_to_v1_separate_emission.rs new file mode 100644 index 0000000000..4512801fde --- /dev/null +++ b/pallets/subtensor/src/migrations/migrate_to_v1_separate_emission.rs @@ -0,0 +1,106 @@ +use super::*; +use frame_support::{ + pallet_prelude::*, storage_alias, + traits::{Get, GetStorageVersion, StorageVersion}, + weights::Weight, +}; +use log::{info, warn}; +use sp_std::vec::Vec; + +/// Constant for logging purposes +const LOG_TARGET: &str = "loadedemissionmigration"; +const LOG_TARGET_1: &str = "fixtotalstakestorage"; + +/// Module containing deprecated storage format +pub mod deprecated_loaded_emission_format { + use super::*; + + type AccountIdOf = ::AccountId; + + #[storage_alias] + pub(super) type LoadedEmission = + StorageMap, Identity, u16, Vec<(AccountIdOf, u64)>, OptionQuery>; +} + +/// Migrates the LoadedEmission storage to a new format +/// +/// # Arguments +/// +/// * `T` - The runtime configuration trait +/// +/// # Returns +/// +/// * `Weight` - The computational weight of this operation +/// +/// # Example +/// +/// ``` +/// let weight = migrate_to_v1_separate_emission::(); +/// ``` +pub fn migrate_to_v1_separate_emission() -> Weight { + use deprecated_loaded_emission_format as old; + + // Initialize weight counter + let mut weight = T::DbWeight::get().reads_writes(1, 0); + + // Get current on-chain storage version + let onchain_version = Pallet::::on_chain_storage_version(); + + // Only proceed if current version is less than 1 + if onchain_version < 1 { + info!( + target: LOG_TARGET, + ">>> Updating the LoadedEmission to a new format {:?}", onchain_version + ); + + // Collect all network IDs (netuids) from old LoadedEmission storage + let curr_loaded_emission: Vec = old::LoadedEmission::::iter_keys().collect(); + + // Remove any undecodable entries + for netuid in curr_loaded_emission { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + if old::LoadedEmission::::try_get(netuid).is_err() { + weight.saturating_accrue(T::DbWeight::get().writes(1)); + old::LoadedEmission::::remove(netuid); + warn!( + "Was unable to decode old loaded_emission for netuid {}", + netuid + ); + } + } + + // Translate old storage values to new format + LoadedEmission::::translate::, u64)>, _>( + |netuid: u16, + netuid_emissions: Vec<(AccountIdOf, u64)>| + -> Option, u64, u64)>> { + info!(target: LOG_TARGET, " Do migration of netuid: {:?}...", netuid); + + // Convert old format (server, validator_emission) to new format (server, server_emission, validator_emission) + // Assume all loaded emission is validator emissions + let new_netuid_emissions = netuid_emissions + .into_iter() + .map(|(server, validator_emission)| (server, 0_u64, validator_emission)) + .collect(); + + // Update weight for read and write operations + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + + Some(new_netuid_emissions) + }, + ); + + // Update storage version to 1 + StorageVersion::new(1).put::>(); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + + weight + } else { + info!(target: LOG_TARGET_1, "Migration to v1 already completed!"); + Weight::zero() + } +} + +// TODO: Add unit tests for this migration +// TODO: Consider adding error handling for edge cases +// TODO: Verify that all possible states of the old format are handled correctly \ No newline at end of file diff --git a/pallets/subtensor/src/migrations/migrate_to_v2_fixed_total_stake.rs b/pallets/subtensor/src/migrations/migrate_to_v2_fixed_total_stake.rs new file mode 100644 index 0000000000..da0811521d --- /dev/null +++ b/pallets/subtensor/src/migrations/migrate_to_v2_fixed_total_stake.rs @@ -0,0 +1,103 @@ +use super::*; +use frame_support::{ + pallet_prelude::*, storage_alias, + traits::{Get, GetStorageVersion, StorageVersion}, + weights::Weight, +}; +use log::info; +use sp_std::vec::Vec; + +/// Constant for logging purposes +const LOG_TARGET: &str = "fix_total_stake_storage"; + +/// Module containing deprecated storage format +pub mod deprecated_loaded_emission_format { + use super::*; + + #[storage_alias] + pub(super) type LoadedEmission = + StorageMap, Identity, u16, Vec<(AccountIdOf, u64)>, OptionQuery>; +} + +/// Migrates the storage to fix TotalStake and TotalColdkeyStake +/// +/// This function performs the following steps: +/// 1. Resets TotalStake to 0 +/// 2. Resets all TotalColdkeyStake entries to 0 +/// 3. Recalculates TotalStake and TotalColdkeyStake based on the Stake map +/// +/// # Arguments +/// +/// * `T` - The Config trait of the pallet +/// +/// # Returns +/// +/// * `Weight` - The computational weight of this operation +/// +/// # Example +/// +/// ``` +/// let weight = migrate_to_v2_fixed_total_stake::(); +/// ``` +pub fn migrate_to_v2_fixed_total_stake() -> Weight { + let new_storage_version = 2; + + // Initialize weight counter + let mut weight = T::DbWeight::get().reads(1); + + // Get current on-chain storage version + let onchain_version = Pallet::::on_chain_storage_version(); + + // Only proceed if current version is less than the new version + if onchain_version < new_storage_version { + info!( + target: LOG_TARGET, + "Fixing the TotalStake and TotalColdkeyStake storage. Current version: {:?}", + onchain_version + ); + + // Reset TotalStake to 0 + TotalStake::::put(0); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + + // Reset all TotalColdkeyStake entries to 0 + let total_coldkey_stake_keys = TotalColdkeyStake::::iter_keys().collect::>(); + for coldkey in total_coldkey_stake_keys { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + TotalColdkeyStake::::insert(coldkey, 0); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + } + + // Recalculate TotalStake and TotalColdkeyStake based on the Stake map + for (_, coldkey, stake) in Stake::::iter() { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + + // Update TotalColdkeyStake + let mut total_coldkey_stake = TotalColdkeyStake::::get(coldkey.clone()); + weight.saturating_accrue(T::DbWeight::get().reads(1)); + total_coldkey_stake = total_coldkey_stake.saturating_add(stake); + TotalColdkeyStake::::insert(coldkey, total_coldkey_stake); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + + // Update TotalStake + let mut total_stake = TotalStake::::get(); + weight.saturating_accrue(T::DbWeight::get().reads(1)); + total_stake = total_stake.saturating_add(stake); + TotalStake::::put(total_stake); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + } + + // Update storage version to prevent re-running this migration + StorageVersion::new(new_storage_version).put::>(); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + + weight + } else { + info!(target: LOG_TARGET, "Migration to v2 already completed"); + Weight::zero() + } +} + +// TODO: Add unit tests for this migration function +// TODO: Consider adding error handling for potential arithmetic overflow +// TODO: Optimize the iteration over Stake map if possible to reduce database reads \ No newline at end of file diff --git a/pallets/subtensor/src/migrations/migrate_total_issuance.rs b/pallets/subtensor/src/migrations/migrate_total_issuance.rs new file mode 100644 index 0000000000..50d679ba08 --- /dev/null +++ b/pallets/subtensor/src/migrations/migrate_total_issuance.rs @@ -0,0 +1,84 @@ +use super::*; +use frame_support::{ + pallet_prelude::Identity, + storage_alias, + traits::{fungible::Inspect, Get, GetStorageVersion, StorageVersion}, + weights::Weight, +}; +use sp_std::vec::Vec; +use frame_support::pallet_prelude::OptionQuery; + +// TODO: Implement comprehensive tests for this migration + +/// Module containing deprecated storage format for LoadedEmission +pub mod deprecated_loaded_emission_format { + use super::*; + + #[storage_alias] + pub(super) type LoadedEmission = + StorageMap, Identity, u16, Vec<(AccountIdOf, u64)>, OptionQuery>; +} + +/// Performs migration to update the total issuance based on the sum of stakes and total balances. +/// +/// This migration is applicable only if the current storage version is 5, after which it updates the storage version to 6. +/// +/// # Arguments +/// +/// * `test` - A boolean flag to force migration execution for testing purposes. +/// +/// # Returns +/// +/// * `Weight` - The computational weight of this operation. +/// +/// # Example +/// +/// ``` +/// let weight = migration5_total_issuance::(false); +/// ``` +pub fn migration5_total_issuance(test: bool) -> Weight { + // Initialize migration weight with the cost of reading the storage version + let mut weight = T::DbWeight::get().reads(1); + + // Execute migration if the current storage version is 5 or if in test mode + if Pallet::::on_chain_storage_version() == StorageVersion::new(5) || test { + // Calculate the sum of all stake values + let stake_sum: u64 = Stake::::iter().fold(0, |acc, (_, _, stake)| acc.saturating_add(stake)); + // Add weight for reading all stake entries + weight = weight.saturating_add(T::DbWeight::get().reads(Stake::::iter().count() as u64)); + + // Calculate the sum of all locked subnet values + let locked_sum: u64 = SubnetLocked::::iter().fold(0, |acc, (_, locked)| acc.saturating_add(locked)); + // Add weight for reading all subnet locked entries + weight = weight.saturating_add(T::DbWeight::get().reads(SubnetLocked::::iter().count() as u64)); + + // Retrieve the total balance sum + let total_balance = T::Currency::total_issuance(); + // Add weight for reading total issuance + weight = weight.saturating_add(T::DbWeight::get().reads(1)); + + // Attempt to convert total balance to u64 + match TryInto::::try_into(total_balance) { + Ok(total_balance_sum) => { + // Compute the total issuance value + let total_issuance_value: u64 = stake_sum.saturating_add(total_balance_sum).saturating_add(locked_sum); + + // Update the total issuance in storage + TotalIssuance::::put(total_issuance_value); + + // Update the storage version to 6 + StorageVersion::new(6).put::>(); + + // Add weight for writing total issuance and storage version + weight = weight.saturating_add(T::DbWeight::get().writes(2)); + } + Err(_) => { + // TODO: Implement proper error handling for conversion failure + log::error!("Failed to convert total balance to u64, migration aborted"); + } + } + } + + // Return the computed weight of the migration process + weight +} \ No newline at end of file diff --git a/pallets/subtensor/src/migrations/migrate_transfer_ownership_to_foundation.rs b/pallets/subtensor/src/migrations/migrate_transfer_ownership_to_foundation.rs new file mode 100644 index 0000000000..6a160c1284 --- /dev/null +++ b/pallets/subtensor/src/migrations/migrate_transfer_ownership_to_foundation.rs @@ -0,0 +1,87 @@ +use super::*; +use frame_support::{ + pallet_prelude::{Identity, OptionQuery}, + storage_alias, + traits::{GetStorageVersion, StorageVersion}, + weights::Weight, +}; +use log::info; +use sp_core::Get; +use sp_std::vec::Vec; + +/// Constant for logging purposes +const LOG_TARGET: &str = "migrate_transfer_ownership"; + +/// Module containing deprecated storage format +pub mod deprecated_loaded_emission_format { + use super::*; + + #[storage_alias] + pub(super) type LoadedEmission = + StorageMap, Identity, u16, Vec<(AccountIdOf, u64)>, OptionQuery>; +} + +/// Migrates subnet ownership to the foundation and updates related storage +/// +/// # Arguments +/// +/// * `coldkey` - 32-byte array representing the foundation's coldkey +/// +/// # Returns +/// +/// * `Weight` - The computational weight of this operation +/// +/// # Example +/// +/// ``` +/// let foundation_coldkey = [0u8; 32]; // Replace with actual foundation coldkey +/// let weight = migrate_transfer_ownership_to_foundation::(foundation_coldkey); +/// ``` +pub fn migrate_transfer_ownership_to_foundation(coldkey: [u8; 32]) -> Weight { + let new_storage_version = 3; + + // Initialize weight counter + let mut weight = T::DbWeight::get().reads(1); + + // Get current on-chain storage version + let onchain_version = Pallet::::on_chain_storage_version(); + + // Only proceed if current version is less than the new version + if onchain_version < new_storage_version { + info!( + target: LOG_TARGET, + "Migrating subnet 1 and 11 to foundation control. Current version: {:?}", + onchain_version + ); + + // Decode the foundation's coldkey into an AccountId + // TODO: Consider error handling for decoding failure + let coldkey_account: T::AccountId = T::AccountId::decode(&mut &coldkey[..]) + .expect("coldkey should be a valid 32-byte array"); + info!(target: LOG_TARGET, "Foundation coldkey: {:?}", coldkey_account); + + // Get the current block number + let current_block = Pallet::::get_current_block_as_u64(); + weight.saturating_accrue(T::DbWeight::get().reads(1)); + + // Transfer ownership of subnets 1 and 11 to the foundation + SubnetOwner::::insert(1, coldkey_account.clone()); + SubnetOwner::::insert(11, coldkey_account); + + // Set the registration time for subnet 1 to extend immunity period + NetworkRegisteredAt::::insert(1, current_block.saturating_add(13 * 7200)); + // Set the registration time for subnet 11 to the current block + NetworkRegisteredAt::::insert(11, current_block); + + weight.saturating_accrue(T::DbWeight::get().writes(4)); + + // Update the storage version to prevent re-running this migration + StorageVersion::new(new_storage_version).put::>(); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + + weight + } else { + info!(target: LOG_TARGET, "Migration to v3 already completed"); + Weight::zero() + } +} \ No newline at end of file diff --git a/pallets/subtensor/src/migrations/mod.rs b/pallets/subtensor/src/migrations/mod.rs new file mode 100644 index 0000000000..cdc512d63d --- /dev/null +++ b/pallets/subtensor/src/migrations/mod.rs @@ -0,0 +1,11 @@ +use super::*; +pub mod migrate_delete_subnet_21; +pub mod migrate_create_root_network; +pub mod migrate_delete_subnet_3; +pub mod migrate_to_v1_separate_emission; +pub mod migrate_to_v2_fixed_total_stake; +pub mod migrate_transfer_ownership_to_foundation; +pub mod migrate_total_issuance; +pub mod migrate_populate_owned_hotkeys; +pub mod migrate_populate_staking_hotkeys; +pub mod migrate_fix_total_coldkey_stake; \ No newline at end of file diff --git a/pallets/subtensor/src/root.rs b/pallets/subtensor/src/root.rs index a973b8d7dc..9cc38cab6f 100644 --- a/pallets/subtensor/src/root.rs +++ b/pallets/subtensor/src/root.rs @@ -16,7 +16,7 @@ // DEALINGS IN THE SOFTWARE. use super::*; -use crate::math::*; +use crate::epoch::math::*; use frame_support::dispatch::Pays; use frame_support::storage::{IterableStorageDoubleMap, IterableStorageMap}; use frame_support::traits::Get; diff --git a/pallets/subtensor/src/delegate_info.rs b/pallets/subtensor/src/rpc_info/delegate_info.rs similarity index 100% rename from pallets/subtensor/src/delegate_info.rs rename to pallets/subtensor/src/rpc_info/delegate_info.rs diff --git a/pallets/subtensor/src/rpc_info/mod.rs b/pallets/subtensor/src/rpc_info/mod.rs new file mode 100644 index 0000000000..70dc816cc7 --- /dev/null +++ b/pallets/subtensor/src/rpc_info/mod.rs @@ -0,0 +1,5 @@ +use super::*; +pub mod neuron_info; +pub mod stake_info; +pub mod subnet_info; +pub mod delegate_info; \ No newline at end of file diff --git a/pallets/subtensor/src/neuron_info.rs b/pallets/subtensor/src/rpc_info/neuron_info.rs similarity index 100% rename from pallets/subtensor/src/neuron_info.rs rename to pallets/subtensor/src/rpc_info/neuron_info.rs diff --git a/pallets/subtensor/src/stake_info.rs b/pallets/subtensor/src/rpc_info/stake_info.rs similarity index 100% rename from pallets/subtensor/src/stake_info.rs rename to pallets/subtensor/src/rpc_info/stake_info.rs diff --git a/pallets/subtensor/src/subnet_info.rs b/pallets/subtensor/src/rpc_info/subnet_info.rs similarity index 100% rename from pallets/subtensor/src/subnet_info.rs rename to pallets/subtensor/src/rpc_info/subnet_info.rs diff --git a/pallets/subtensor/src/weights.rs b/pallets/subtensor/src/weights.rs index 1866f8e625..67b1d485e7 100644 --- a/pallets/subtensor/src/weights.rs +++ b/pallets/subtensor/src/weights.rs @@ -1,5 +1,5 @@ use super::*; -use crate::math::*; +use crate::epoch::math::*; use sp_core::H256; use sp_runtime::traits::{BlakeTwo256, Hash}; use sp_std::vec; diff --git a/pallets/subtensor/tests/math.rs b/pallets/subtensor/tests/math.rs index 35b383f688..7f70e89f68 100644 --- a/pallets/subtensor/tests/math.rs +++ b/pallets/subtensor/tests/math.rs @@ -5,7 +5,7 @@ )] use substrate_fixed::types::{I32F32, I64F64}; -use pallet_subtensor::math::*; +use pallet_subtensor::epoch::math::*; use rand::{seq::SliceRandom, thread_rng, Rng}; use substrate_fixed::{ transcendental::exp, From f7ade4d02dfae2caf84e64f6aefaa962e01e272c Mon Sep 17 00:00:00 2001 From: const Date: Mon, 15 Jul 2024 14:00:10 -0500 Subject: [PATCH 02/16] clean tests --- pallets/admin-utils/tests/mock.rs | 2 - pallets/admin-utils/tests/tests.rs | 4 +- pallets/subtensor/src/lib.rs | 114 +- pallets/subtensor/src/macros/config.rs | 3 - pallets/subtensor/src/macros/dispatches.rs | 15 +- pallets/subtensor/src/macros/hooks.rs | 2 +- pallets/subtensor/src/migration.rs | 2 +- .../migrations/migrate_create_root_network.rs | 2 +- .../migrations/migrate_delete_subnet_21.rs | 2 +- .../src/migrations/migrate_delete_subnet_3.rs | 2 +- .../migrate_to_v1_separate_emission.rs | 2 +- .../migrate_to_v2_fixed_total_stake.rs | 2 +- .../src/migrations/migrate_total_issuance.rs | 6 +- ...igrate_transfer_ownership_to_foundation.rs | 2 +- pallets/subtensor/src/registration.rs | 4 - pallets/subtensor/src/root.rs | 23 +- pallets/subtensor/src/staking.rs | 20 - pallets/subtensor/src/swap.rs | 1055 ------------- pallets/subtensor/src/swap/mod.rs | 3 + pallets/subtensor/src/swap/swap_coldkey.rs | 391 +++++ pallets/subtensor/src/swap/swap_hotkey.rs | 438 ++++++ pallets/subtensor/tests/epoch.rs | 6 +- pallets/subtensor/tests/migration.rs | 38 +- pallets/subtensor/tests/mock.rs | 2 - pallets/subtensor/tests/root.rs | 20 +- pallets/subtensor/tests/senate.rs | 18 +- pallets/subtensor/tests/staking.rs | 1337 +---------------- pallets/subtensor/tests/swap.rs | 100 +- runtime/src/lib.rs | 2 - 29 files changed, 975 insertions(+), 2642 deletions(-) delete mode 100644 pallets/subtensor/src/swap.rs create mode 100644 pallets/subtensor/src/swap/mod.rs create mode 100644 pallets/subtensor/src/swap/swap_coldkey.rs create mode 100644 pallets/subtensor/src/swap/swap_hotkey.rs diff --git a/pallets/admin-utils/tests/mock.rs b/pallets/admin-utils/tests/mock.rs index dbf88bdfa4..dee8e742ff 100644 --- a/pallets/admin-utils/tests/mock.rs +++ b/pallets/admin-utils/tests/mock.rs @@ -114,7 +114,6 @@ parameter_types! { pub const InitialAlphaHigh: u16 = 58982; // Represents 0.9 as per the production default pub const InitialAlphaLow: u16 = 45875; // Represents 0.7 as per the production default pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn - pub const InitialBaseDifficulty: u64 = 10_000; // Base difficulty } impl pallet_subtensor::Config for Test { @@ -170,7 +169,6 @@ impl pallet_subtensor::Config for Test { type AlphaHigh = InitialAlphaHigh; type AlphaLow = InitialAlphaLow; type LiquidAlphaOn = InitialLiquidAlphaOn; - type InitialBaseDifficulty = InitialBaseDifficulty; } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] diff --git a/pallets/admin-utils/tests/tests.rs b/pallets/admin-utils/tests/tests.rs index 9df59978f7..6e78a1ed68 100644 --- a/pallets/admin-utils/tests/tests.rs +++ b/pallets/admin-utils/tests/tests.rs @@ -6,7 +6,7 @@ use frame_support::{ use frame_system::Config; use pallet_admin_utils::Error; use pallet_subtensor::Error as SubtensorError; -use pallet_subtensor::{migration, Event}; +use pallet_subtensor::{migrations, Event}; use sp_core::U256; mod mock; @@ -1232,7 +1232,7 @@ fn test_sudo_get_set_alpha() { // Enable Liquid Alpha and setup SubtensorModule::set_liquid_alpha_enabled(netuid, true); - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); SubtensorModule::add_balance_to_coldkey_account(&coldkey, 1_000_000_000_000_000); assert_ok!(SubtensorModule::root_register(signer.clone(), hotkey,)); assert_ok!(SubtensorModule::add_stake(signer.clone(), hotkey, 1000)); diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 528c062295..329cebcdcf 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -37,7 +37,8 @@ mod benchmarks; // ========================= mod rpc_info; mod coinbase; -mod epoch; +pub mod epoch; +pub mod swap; mod macros; use macros::{events, errors, dispatches, genesis, hooks, config}; @@ -45,7 +46,6 @@ mod registration; mod root; mod serving; mod staking; -mod swap; mod uids; mod utils; mod weights; @@ -308,7 +308,7 @@ pub mod pallet { pub fn DefaultAlphaValues() -> (u16, u16) { (45875, 58982) } #[pallet::storage] - pub(super) type SenateRequiredStakePercentage = StorageValue<_, u64, ValueQuery, DefaultSenateRequiredStakePercentage>; + pub type SenateRequiredStakePercentage = StorageValue<_, u64, ValueQuery, DefaultSenateRequiredStakePercentage>; /// ============================ /// ==== Staking Variables ==== @@ -483,9 +483,9 @@ pub mod pallet { #[pallet::storage] /// --- MAP ( netuid ) --> global_RAO_recycled_for_registration pub type RAORecycledForRegistration = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultRAORecycledForRegistration>; #[pallet::storage] /// --- ITEM ( tx_rate_limit ) - pub(super) type TxRateLimit = StorageValue<_, u64, ValueQuery, DefaultTxRateLimit>; + pub type TxRateLimit = StorageValue<_, u64, ValueQuery, DefaultTxRateLimit>; #[pallet::storage] /// --- ITEM ( tx_rate_limit ) - pub(super) type TxDelegateTakeRateLimit = StorageValue<_, u64, ValueQuery, DefaultTxDelegateTakeRateLimit>; + pub type TxDelegateTakeRateLimit = StorageValue<_, u64, ValueQuery, DefaultTxDelegateTakeRateLimit>; #[pallet::storage] /// --- MAP ( netuid ) --> Whether or not Liquid Alpha is enabled pub type LiquidAlphaOn = StorageMap<_, Blake2_128Concat, u16, bool, ValueQuery, DefaultLiquidAlpha>; #[pallet::storage] /// MAP ( netuid ) --> (alpha_low, alpha_high) @@ -496,94 +496,55 @@ pub mod pallet { /// ==== Subnetwork Consensus Storage ==== /// ======================================= #[pallet::storage] /// --- DMAP ( netuid, hotkey ) --> uid - pub(super) type Uids = StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, u16, OptionQuery>; + pub type Uids = StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, u16, OptionQuery>; #[pallet::storage] /// --- DMAP ( netuid, uid ) --> hotkey - pub(super) type Keys = StorageDoubleMap<_, Identity, u16, Identity, u16, T::AccountId, ValueQuery, DefaultKey>; + pub type Keys = StorageDoubleMap<_, Identity, u16, Identity, u16, T::AccountId, ValueQuery, DefaultKey>; #[pallet::storage] /// --- DMAP ( netuid ) --> (hotkey, se, ve) - pub(super) type LoadedEmission = StorageMap<_, Identity, u16, Vec<(T::AccountId, u64, u64)>, OptionQuery>; + pub type LoadedEmission = StorageMap<_, Identity, u16, Vec<(T::AccountId, u64, u64)>, OptionQuery>; #[pallet::storage] /// --- DMAP ( netuid ) --> active - pub(super) type Active = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyBoolVec>; + pub type Active = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyBoolVec>; #[pallet::storage] /// --- DMAP ( netuid ) --> rank - pub(super) type Rank = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + pub type Rank = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; #[pallet::storage] /// --- DMAP ( netuid ) --> trust - pub(super) type Trust = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + pub type Trust = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; #[pallet::storage] /// --- DMAP ( netuid ) --> consensus - pub(super) type Consensus = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + pub type Consensus = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; #[pallet::storage] /// --- DMAP ( netuid ) --> incentive - pub(super) type Incentive = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + pub type Incentive = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; #[pallet::storage] /// --- DMAP ( netuid ) --> dividends - pub(super) type Dividends = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + pub type Dividends = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; #[pallet::storage] /// --- DMAP ( netuid ) --> emission - pub(super) type Emission = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU64Vec>; + pub type Emission = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU64Vec>; #[pallet::storage] /// --- DMAP ( netuid ) --> last_update - pub(super) type LastUpdate = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU64Vec>; + pub type LastUpdate = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU64Vec>; #[pallet::storage] /// --- DMAP ( netuid ) --> validator_trust - pub(super) type ValidatorTrust = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + pub type ValidatorTrust = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; #[pallet::storage] /// --- DMAP ( netuid ) --> pruning_scores - pub(super) type PruningScores = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + pub type PruningScores = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; #[pallet::storage] /// --- DMAP ( netuid ) --> validator_permit - pub(super) type ValidatorPermit = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyBoolVec>; + pub type ValidatorPermit = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyBoolVec>; #[pallet::storage] /// --- DMAP ( netuid, uid ) --> weights - pub(super) type Weights = StorageDoubleMap<_, Identity, u16, Identity, u16, Vec<(u16, u16)>, ValueQuery, DefaultWeights>; + pub type Weights = StorageDoubleMap<_, Identity, u16, Identity, u16, Vec<(u16, u16)>, ValueQuery, DefaultWeights>; #[pallet::storage] /// --- DMAP ( netuid, uid ) --> bonds - pub(super) type Bonds = StorageDoubleMap<_, Identity, u16, Identity, u16, Vec<(u16, u16)>, ValueQuery, DefaultBonds>; + pub type Bonds = StorageDoubleMap<_, Identity, u16, Identity, u16, Vec<(u16, u16)>, ValueQuery, DefaultBonds>; #[pallet::storage] /// --- DMAP ( netuid, uid ) --> block_at_registration pub type BlockAtRegistration = StorageDoubleMap<_, Identity, u16, Identity, u16, u64, ValueQuery, DefaultBlockAtRegistration>; #[pallet::storage] /// --- MAP ( netuid, hotkey ) --> axon_info - pub(super) type Axons = StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, AxonInfoOf, OptionQuery>; + pub type Axons = StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, AxonInfoOf, OptionQuery>; #[pallet::storage] /// --- MAP ( netuid, hotkey ) --> prometheus_info - pub(super) type Prometheus = StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, PrometheusInfoOf, OptionQuery>; + pub type Prometheus = StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, PrometheusInfoOf, OptionQuery>; /// ================================= /// ==== Axon / Promo Endpoints ===== /// ================================= #[pallet::storage] /// --- MAP ( key ) --> last_block - pub(super) type LastTxBlock = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; + pub type LastTxBlock = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; #[pallet::storage] /// --- MAP ( key ) --> last_block - pub(super) type LastTxBlockDelegateTake = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; + pub type LastTxBlockDelegateTake = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; #[pallet::storage] /// ITEM( weights_min_stake ) pub type WeightsMinStake = StorageValue<_, u64, ValueQuery, DefaultWeightsMinStake>; #[pallet::storage] /// --- MAP (netuid, who) --> (hash, weight) | Returns the hash and weight committed by an account for a given netuid. pub type WeightCommits = StorageDoubleMap<_, Twox64Concat, u16, Twox64Concat, T::AccountId, (H256, u64), OptionQuery>; - - /// =============================== - /// ==== Coldkey Arbitrations ===== - /// =============================== - #[pallet::type_value] /// Default base difficulty for proof of work for coldkey swaps - pub fn DefaultBaseDifficulty() -> u64 { T::InitialBaseDifficulty::get() } - #[pallet::storage] // --- ITEM ( base_difficulty ) - pub type BaseDifficulty = StorageValue<_, u64, ValueQuery, DefaultBaseDifficulty>; - #[pallet::type_value] - /// Default value for hotkeys. - pub fn EmptyAccounts() -> Vec { - vec![] - } - #[pallet::type_value] - /// Default arbitration period. - /// This value represents the default arbitration period in blocks. - /// The period is set to 18 hours, assuming a block time of 12 seconds. - pub fn DefaultArbitrationPeriod() -> u64 { - 7200 * 3 // 3 days - } - #[pallet::storage] // ---- StorageItem Global Used Work. - pub type ArbitrationPeriod = - StorageValue<_, u64, ValueQuery, DefaultArbitrationPeriod>; - #[pallet::storage] // --- MAP ( cold ) --> Vec | Returns a list of keys to drain to, if there are two, we extend the period. - pub type ColdkeySwapDestinations = StorageMap< - _, - Blake2_128Concat, - T::AccountId, - Vec, - ValueQuery, - EmptyAccounts, - >; - #[pallet::storage] // --- MAP ( cold ) --> u64 | Block when the coldkey will be arbitrated. - pub type ColdkeyArbitrationBlock = - StorageMap<_, Blake2_128Concat, T::AccountId, u64, ValueQuery>; - #[pallet::storage] // --- MAP ( u64 ) --> Vec | Coldkeys to drain on the specific block. - pub type ColdkeysToSwapAtBlock = - StorageMap<_, Identity, u64, Vec, ValueQuery, EmptyAccounts>; - /// ================== /// ==== Genesis ===== /// ================== @@ -736,19 +697,6 @@ where _info: &DispatchInfoOf, _len: usize, ) -> TransactionValidity { - // Check if the call is one of the balance transfer types we want to reject - if let Some(balances_call) = call.is_sub_type() { - match balances_call { - BalancesCall::transfer_allow_death { .. } - | BalancesCall::transfer_keep_alive { .. } - | BalancesCall::transfer_all { .. } => { - if Pallet::::coldkey_in_arbitration(who) { - return Err(TransactionValidityError::Invalid(InvalidTransaction::Call)); - } - } - _ => {} // Other Balances calls are allowed - } - } match call.is_sub_type() { Some(Call::commit_weights { netuid, .. }) => { if Self::check_weights_min_stake(who) { @@ -826,14 +774,10 @@ where ..Default::default() }), Some(Call::dissolve_network { .. }) => { - if Pallet::::coldkey_in_arbitration(who) { - Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) - } else { - Ok(ValidTransaction { - priority: Self::get_priority_vanilla(), - ..Default::default() - }) - } + Ok(ValidTransaction { + priority: Self::get_priority_vanilla(), + ..Default::default() + }) } _ => Ok(ValidTransaction { priority: Self::get_priority_vanilla(), diff --git a/pallets/subtensor/src/macros/config.rs b/pallets/subtensor/src/macros/config.rs index e54cd222f8..4e3cf5d2a1 100644 --- a/pallets/subtensor/src/macros/config.rs +++ b/pallets/subtensor/src/macros/config.rs @@ -168,8 +168,5 @@ mod config { /// A flag to indicate if Liquid Alpha is enabled. #[pallet::constant] type LiquidAlphaOn: Get; - /// The base difficulty for proof of work for coldkey swaps - #[pallet::constant] - type InitialBaseDifficulty: Get; } } \ No newline at end of file diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 62b02f6a46..6d4c588e90 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -677,6 +677,7 @@ mod dispatches { ) -> DispatchResultWithPostInfo { Self::do_swap_coldkey(origin, &new_coldkey) } + /// Unstakes all tokens associated with a hotkey and transfers them to a new coldkey. /// /// # Arguments @@ -698,15 +699,13 @@ mod dispatches { .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)), DispatchClass::Operational, Pays::No))] pub fn schedule_coldkey_swap( - origin: OriginFor, - new_coldkey: T::AccountId, - work: Vec, - block_number: u64, - nonce: u64, + _origin: OriginFor, + _new_coldkey: T::AccountId, + _work: Vec, + _block_number: u64, + _nonce: u64, ) -> DispatchResult { - // Attain the calling coldkey from the origin. - let old_coldkey: T::AccountId = ensure_signed(origin)?; - Self::do_schedule_coldkey_swap(&old_coldkey, &new_coldkey, work, block_number, nonce) + Ok(()) } // ---- SUDO ONLY FUNCTIONS ------------------------------------------------------------ diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index baa9de21a9..7e612fb4ed 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -59,7 +59,7 @@ mod hooks { .saturating_add(migrations::migrate_delete_subnet_3::migrate_delete_subnet_3::()) // Doesn't check storage version. TODO: Remove after upgrade // Storage version v5 -> v6 - .saturating_add(migrations::migrate_total_issuance::migration5_total_issuance::(false)) + .saturating_add(migrations::migrate_total_issuance::migrate_total_issuance::(false)) // Populate OwnedHotkeys map for coldkey swap. Doesn't update storage vesion. // Storage version v6 -> v7 .saturating_add(migrations::migrate_populate_owned_hotkeys::migrate_populate_owned::()) diff --git a/pallets/subtensor/src/migration.rs b/pallets/subtensor/src/migration.rs index 72a86ea4e1..cd99f01280 100644 --- a/pallets/subtensor/src/migration.rs +++ b/pallets/subtensor/src/migration.rs @@ -85,7 +85,7 @@ pub fn migrate_fix_total_coldkey_stake() -> Weight { /// /// # Returns /// Weight of the migration process. -pub fn migration5_total_issuance(test: bool) -> Weight { +pub fn migrate_total_issuance(test: bool) -> Weight { let mut weight = T::DbWeight::get().reads(1); // Initialize migration weight // Execute migration if the current storage version is 5 diff --git a/pallets/subtensor/src/migrations/migrate_create_root_network.rs b/pallets/subtensor/src/migrations/migrate_create_root_network.rs index ff858ec6ac..20ee82f0a6 100644 --- a/pallets/subtensor/src/migrations/migrate_create_root_network.rs +++ b/pallets/subtensor/src/migrations/migrate_create_root_network.rs @@ -35,7 +35,7 @@ pub mod deprecated_loaded_emission_format { /// /// # Example /// -/// ``` +/// ```ignore /// let weight = migrate_create_root_network::(); /// ``` pub fn migrate_create_root_network() -> Weight { diff --git a/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs b/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs index df6a2ae34c..23fbe122fb 100644 --- a/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs +++ b/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs @@ -36,7 +36,7 @@ pub mod deprecated_loaded_emission_format { /// /// # Example /// -/// ``` +/// ```ignore /// let weight = migrate_delete_subnet_21::(); /// ``` pub fn migrate_delete_subnet_21() -> Weight { diff --git a/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs b/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs index 04df542695..257752c197 100644 --- a/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs +++ b/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs @@ -36,7 +36,7 @@ pub mod deprecated_loaded_emission_format { /// /// # Example /// -/// ``` +/// ```ignore /// let weight = migrate_delete_subnet_3::(); /// ``` pub fn migrate_delete_subnet_3() -> Weight { diff --git a/pallets/subtensor/src/migrations/migrate_to_v1_separate_emission.rs b/pallets/subtensor/src/migrations/migrate_to_v1_separate_emission.rs index 4512801fde..5db04f0bc5 100644 --- a/pallets/subtensor/src/migrations/migrate_to_v1_separate_emission.rs +++ b/pallets/subtensor/src/migrations/migrate_to_v1_separate_emission.rs @@ -34,7 +34,7 @@ pub mod deprecated_loaded_emission_format { /// /// # Example /// -/// ``` +/// ```ignore /// let weight = migrate_to_v1_separate_emission::(); /// ``` pub fn migrate_to_v1_separate_emission() -> Weight { diff --git a/pallets/subtensor/src/migrations/migrate_to_v2_fixed_total_stake.rs b/pallets/subtensor/src/migrations/migrate_to_v2_fixed_total_stake.rs index da0811521d..ef9fe8880a 100644 --- a/pallets/subtensor/src/migrations/migrate_to_v2_fixed_total_stake.rs +++ b/pallets/subtensor/src/migrations/migrate_to_v2_fixed_total_stake.rs @@ -36,7 +36,7 @@ pub mod deprecated_loaded_emission_format { /// /// # Example /// -/// ``` +/// ```ignore /// let weight = migrate_to_v2_fixed_total_stake::(); /// ``` pub fn migrate_to_v2_fixed_total_stake() -> Weight { diff --git a/pallets/subtensor/src/migrations/migrate_total_issuance.rs b/pallets/subtensor/src/migrations/migrate_total_issuance.rs index 50d679ba08..187967da35 100644 --- a/pallets/subtensor/src/migrations/migrate_total_issuance.rs +++ b/pallets/subtensor/src/migrations/migrate_total_issuance.rs @@ -33,10 +33,10 @@ pub mod deprecated_loaded_emission_format { /// /// # Example /// +/// ```ignore +/// let weight = migrate_total_issuance::(false); /// ``` -/// let weight = migration5_total_issuance::(false); -/// ``` -pub fn migration5_total_issuance(test: bool) -> Weight { +pub fn migrate_total_issuance(test: bool) -> Weight { // Initialize migration weight with the cost of reading the storage version let mut weight = T::DbWeight::get().reads(1); diff --git a/pallets/subtensor/src/migrations/migrate_transfer_ownership_to_foundation.rs b/pallets/subtensor/src/migrations/migrate_transfer_ownership_to_foundation.rs index 6a160c1284..0ca4a7fa59 100644 --- a/pallets/subtensor/src/migrations/migrate_transfer_ownership_to_foundation.rs +++ b/pallets/subtensor/src/migrations/migrate_transfer_ownership_to_foundation.rs @@ -33,7 +33,7 @@ pub mod deprecated_loaded_emission_format { /// /// # Example /// -/// ``` +/// ```ignore /// let foundation_coldkey = [0u8; 32]; // Replace with actual foundation coldkey /// let weight = migrate_transfer_ownership_to_foundation::(foundation_coldkey); /// ``` diff --git a/pallets/subtensor/src/registration.rs b/pallets/subtensor/src/registration.rs index 6b73f2fc3a..4688bcbb59 100644 --- a/pallets/subtensor/src/registration.rs +++ b/pallets/subtensor/src/registration.rs @@ -41,10 +41,6 @@ impl Pallet { ) -> DispatchResult { // --- 1. Check that the caller has signed the transaction. (the coldkey of the pairing) let coldkey = ensure_signed(origin)?; - ensure!( - !Self::coldkey_in_arbitration(&coldkey), - Error::::ColdkeyIsInArbitration - ); log::info!( "do_registration( coldkey:{:?} netuid:{:?} hotkey:{:?} )", coldkey, diff --git a/pallets/subtensor/src/root.rs b/pallets/subtensor/src/root.rs index 9cc38cab6f..b3ac32f553 100644 --- a/pallets/subtensor/src/root.rs +++ b/pallets/subtensor/src/root.rs @@ -483,10 +483,6 @@ impl Pallet { // --- 1. Ensure that the call originates from a signed source and retrieve the caller's account ID (coldkey). let coldkey = ensure_signed(origin)?; - ensure!( - !Self::coldkey_in_arbitration(&coldkey), - Error::::ColdkeyIsInArbitration - ); log::info!( "do_root_register( coldkey: {:?}, hotkey: {:?} )", coldkey, @@ -734,10 +730,6 @@ impl Pallet { ) -> dispatch::DispatchResult { // Check the caller's signature. This is the coldkey of a registered account. let coldkey = ensure_signed(origin)?; - ensure!( - !Self::coldkey_in_arbitration(&coldkey), - Error::::ColdkeyIsInArbitration - ); log::info!( "do_set_root_weights( origin:{:?} netuid:{:?}, uids:{:?}, values:{:?})", coldkey, @@ -859,10 +851,6 @@ impl Pallet { ) -> DispatchResultWithPostInfo { // --- 1. Ensure that the caller has signed with their coldkey. let coldkey = ensure_signed(origin.clone())?; - ensure!( - !Self::coldkey_in_arbitration(&coldkey), - Error::::ColdkeyIsInArbitration - ); // --- 2. Ensure that the calling coldkey owns the associated hotkey. ensure!( @@ -916,10 +904,7 @@ impl Pallet { pub fn user_add_network(origin: T::RuntimeOrigin) -> dispatch::DispatchResult { // --- 0. Ensure the caller is a signed user. let coldkey = ensure_signed(origin)?; - ensure!( - !Self::coldkey_in_arbitration(&coldkey), - Error::::ColdkeyIsInArbitration - ); + // --- 1. Rate limit for network registrations. let current_block = Self::get_current_block_as_u64(); @@ -1008,11 +993,7 @@ impl Pallet { pub fn user_remove_network(origin: T::RuntimeOrigin, netuid: u16) -> dispatch::DispatchResult { // --- 1. Ensure the function caller is a signed user. let coldkey = ensure_signed(origin)?; - ensure!( - !Self::coldkey_in_arbitration(&coldkey), - Error::::ColdkeyIsInArbitration - ); - + // --- 2. Ensure this subnet exists. ensure!( Self::if_subnet_exist(netuid), diff --git a/pallets/subtensor/src/staking.rs b/pallets/subtensor/src/staking.rs index 199234a303..2707d90ef4 100644 --- a/pallets/subtensor/src/staking.rs +++ b/pallets/subtensor/src/staking.rs @@ -44,10 +44,6 @@ impl Pallet { ) -> dispatch::DispatchResult { // --- 1. We check the coldkey signuture. let coldkey = ensure_signed(origin)?; - ensure!( - !Self::coldkey_in_arbitration(&coldkey), - Error::::ColdkeyIsInArbitration - ); log::info!( "do_become_delegate( origin:{:?} hotkey:{:?}, take:{:?} )", coldkey, @@ -137,10 +133,6 @@ impl Pallet { hotkey, take ); - ensure!( - !Self::coldkey_in_arbitration(&coldkey), - Error::::ColdkeyIsInArbitration - ); // --- 2. Ensure we are delegating a known key. // Ensure that the coldkey is the owner. @@ -213,10 +205,6 @@ impl Pallet { hotkey, take ); - ensure!( - !Self::coldkey_in_arbitration(&coldkey), - Error::::ColdkeyIsInArbitration - ); // --- 2. Ensure we are delegating a known key. // Ensure that the coldkey is the owner. @@ -302,10 +290,6 @@ impl Pallet { hotkey, stake_to_be_added ); - ensure!( - !Self::coldkey_in_arbitration(&coldkey), - Error::::ColdkeyIsInArbitration - ); // Ensure the callers coldkey has enough stake to perform the transaction. ensure!( @@ -418,10 +402,6 @@ impl Pallet { hotkey, stake_to_be_removed ); - ensure!( - !Self::coldkey_in_arbitration(&coldkey), - Error::::ColdkeyIsInArbitration - ); // Ensure that the hotkey account exists this is only possible through registration. ensure!( diff --git a/pallets/subtensor/src/swap.rs b/pallets/subtensor/src/swap.rs deleted file mode 100644 index 8e4ca5cc9c..0000000000 --- a/pallets/subtensor/src/swap.rs +++ /dev/null @@ -1,1055 +0,0 @@ -use super::*; -use crate::MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP; -use frame_support::traits::fungible::Mutate; -use frame_support::traits::tokens::Preservation; -use frame_support::{storage::IterableStorageDoubleMap, weights::Weight}; -use sp_core::{Get, U256}; - -impl Pallet { - /// Swaps the hotkey of a coldkey account. - /// - /// # Arguments - /// - /// * `origin` - The origin of the transaction, and also the coldkey account. - /// * `old_hotkey` - The old hotkey to be swapped. - /// * `new_hotkey` - The new hotkey to replace the old one. - /// - /// # Returns - /// - /// * `DispatchResultWithPostInfo` - The result of the dispatch. - /// - /// # Errors - /// - /// * `NonAssociatedColdKey` - If the coldkey does not own the old hotkey. - /// * `HotKeySetTxRateLimitExceeded` - If the transaction rate limit is exceeded. - /// * `NewHotKeyIsSameWithOld` - If the new hotkey is the same as the old hotkey. - /// * `HotKeyAlreadyRegisteredInSubNet` - If the new hotkey is already registered in the subnet. - /// * `NotEnoughBalanceToPaySwapHotKey` - If there is not enough balance to pay for the swap. - pub fn do_swap_hotkey( - origin: T::RuntimeOrigin, - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - ) -> DispatchResultWithPostInfo { - let coldkey = ensure_signed(origin)?; - - ensure!( - !Self::coldkey_in_arbitration(&coldkey), - Error::::ColdkeyIsInArbitration - ); - - let mut weight = T::DbWeight::get().reads(2); - - ensure!(old_hotkey != new_hotkey, Error::::NewHotKeyIsSameWithOld); - ensure!( - !Self::is_hotkey_registered_on_any_network(new_hotkey), - Error::::HotKeyAlreadyRegisteredInSubNet - ); - - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 0)); - ensure!( - Self::coldkey_owns_hotkey(&coldkey, old_hotkey), - Error::::NonAssociatedColdKey - ); - - let block: u64 = Self::get_current_block_as_u64(); - ensure!( - !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&coldkey), block), - Error::::HotKeySetTxRateLimitExceeded - ); - - weight.saturating_accrue( - T::DbWeight::get().reads((TotalNetworks::::get().saturating_add(1u16)) as u64), - ); - - let swap_cost = Self::get_key_swap_cost(); - log::debug!("Swap cost: {:?}", swap_cost); - - ensure!( - Self::can_remove_balance_from_coldkey_account(&coldkey, swap_cost), - Error::::NotEnoughBalanceToPaySwapHotKey - ); - let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?; - Self::burn_tokens(actual_burn_amount); - - Self::swap_owner(old_hotkey, new_hotkey, &coldkey, &mut weight); - Self::swap_total_hotkey_stake(old_hotkey, new_hotkey, &mut weight); - Self::swap_delegates(old_hotkey, new_hotkey, &mut weight); - Self::swap_stake(old_hotkey, new_hotkey, &mut weight); - - // Store the value of is_network_member for the old key - let netuid_is_member: Vec = Self::get_netuid_is_member(old_hotkey, &mut weight); - - Self::swap_is_network_member(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); - Self::swap_axons(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); - Self::swap_keys(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); - Self::swap_loaded_emission(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); - Self::swap_uids(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); - Self::swap_prometheus(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); - Self::swap_senate_member(old_hotkey, new_hotkey, &mut weight)?; - - Self::swap_total_hotkey_coldkey_stakes_this_interval(old_hotkey, new_hotkey, &mut weight); - - Self::set_last_tx_block(&coldkey, block); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - - Self::deposit_event(Event::HotkeySwapped { - coldkey, - old_hotkey: old_hotkey.clone(), - new_hotkey: new_hotkey.clone(), - }); - - Ok(Some(weight).into()) - } - - /// Swaps the coldkey associated with a set of hotkeys from an old coldkey to a new coldkey. - /// - /// # Arguments - /// - /// * `origin` - The origin of the call, which must be signed by the old coldkey. - /// * `old_coldkey` - The account ID of the old coldkey. - /// * `new_coldkey` - The account ID of the new coldkey. - /// - /// # Returns - /// - /// Returns a `DispatchResultWithPostInfo` indicating success or failure, along with the weight consumed. - /// - /// # Errors - /// - /// This function will return an error if: - /// - The caller is not the old coldkey. - /// - The new coldkey is the same as the old coldkey. - /// - The new coldkey is already associated with other hotkeys. - /// - The transaction rate limit for coldkey swaps has been exceeded. - /// - There's not enough balance to pay for the swap. - /// - /// # Events - /// - /// Emits a `ColdkeySwapped` event when successful. - /// - /// # Weight - /// - /// Weight is tracked and updated throughout the function execution. - pub fn do_swap_coldkey( - origin: T::RuntimeOrigin, - new_coldkey: &T::AccountId, - ) -> DispatchResultWithPostInfo { - let old_coldkey = ensure_signed(origin)?; - ensure!( - !Self::coldkey_in_arbitration(&old_coldkey), - Error::::ColdkeyIsInArbitration - ); - - let mut weight: Weight = T::DbWeight::get().reads(2); - - // Check that the coldkey is a new key (does not exist elsewhere.) - ensure!( - !Self::coldkey_has_associated_hotkeys(new_coldkey), - Error::::ColdKeyAlreadyAssociated - ); - // Check that the new coldkey is not a hotkey. - ensure!( - !Self::hotkey_account_exists(new_coldkey), - Error::::ColdKeyAlreadyAssociated - ); - - // Calculate and charge the swap fee - let swap_cost = Self::get_key_swap_cost(); - log::debug!("Coldkey swap cost: {:?}", swap_cost); - - ensure!( - Self::can_remove_balance_from_coldkey_account(&old_coldkey, swap_cost), - Error::::NotEnoughBalanceToPaySwapColdKey - ); - let actual_burn_amount = - Self::remove_balance_from_coldkey_account(&old_coldkey, swap_cost)?; - Self::burn_tokens(actual_burn_amount); - - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - - // Actually do the swap. - weight = weight.saturating_add( - Self::perform_swap_coldkey(&old_coldkey, new_coldkey) - .map_err(|_| Error::::ColdkeySwapError)?, - ); - - Self::set_last_tx_block(new_coldkey, Self::get_current_block_as_u64()); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - - Self::deposit_event(Event::ColdkeySwapped { - old_coldkey: old_coldkey.clone(), - new_coldkey: new_coldkey.clone(), - }); - - Ok(Some(weight).into()) - } - - /// Checks if a coldkey is currently in arbitration. - /// - /// # Arguments - /// - /// * `coldkey` - The account ID of the coldkey to check. - /// - /// # Returns - /// - /// * `bool` - True if the coldkey is in arbitration, false otherwise. - /// - /// # Notes - /// - /// This function compares the arbitration block number of the coldkey with the current block number. - pub fn coldkey_in_arbitration(coldkey: &T::AccountId) -> bool { - ColdkeyArbitrationBlock::::get(coldkey) > Self::get_current_block_as_u64() - } - - /// Returns the remaining arbitration period for a given coldkey. - /// - /// # Arguments - /// - /// * `coldkey` - The account ID of the coldkey to check. - /// - /// # Returns - /// - /// * `u64` - The remaining arbitration period in blocks. - /// - /// - /// # Notes - /// - /// This function calculates the remaining arbitration period by subtracting the current block number - /// from the arbitration block number of the coldkey. - pub fn get_remaining_arbitration_period(coldkey: &T::AccountId) -> u64 { - let current_block: u64 = Self::get_current_block_as_u64(); - let arbitration_block: u64 = ColdkeyArbitrationBlock::::get(coldkey); - if arbitration_block > current_block { - arbitration_block.saturating_sub(current_block) - } else { - 0 - } - } - - pub fn meets_min_allowed_coldkey_balance(coldkey: &T::AccountId) -> bool { - let all_staked_keys: Vec = StakingHotkeys::::get(coldkey); - let mut total_staking_balance: u64 = 0; - for hotkey in all_staked_keys { - total_staking_balance = total_staking_balance - .saturating_add(Self::get_stake_for_coldkey_and_hotkey(coldkey, &hotkey)); - } - total_staking_balance = - total_staking_balance.saturating_add(Self::get_coldkey_balance(coldkey)); - total_staking_balance >= MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP - } - - /// Schedules a coldkey swap to a new coldkey with arbitration. - /// - /// # Arguments - /// - /// * `old_coldkey` - The account ID of the old coldkey. - /// * `new_coldkey` - The account ID of the new coldkey. - /// * `work` - The proof of work submitted by the caller. - /// * `block_number` - The block number at which the work was performed. - /// * `nonce` - The nonce used for the proof of work. - /// - /// # Returns - /// - /// * `DispatchResult` - The result of the dispatch. - /// - /// # Errors - /// - - /// - `SameColdkey`: The old coldkey is the same as the new coldkey. - /// - `DuplicateColdkey`: The new coldkey is already in the list of destination coldkeys. - /// - `MaxColdkeyDestinationsReached`: There are already the maximum allowed destination coldkeys for the old coldkey. - /// - `InsufficientBalanceToPerformColdkeySwap`: The old coldkey doesn't have the minimum required TAO balance. - /// - `InvalidDifficulty`: The proof of work is invalid or doesn't meet the required difficulty. - /// - /// # Notes - /// - /// This function ensures that the new coldkey is not already in the list of destination coldkeys. - /// It also checks for a minimum TAO balance and verifies the proof of work. - /// The difficulty of the proof of work increases exponentially with each subsequent call. - pub fn do_schedule_coldkey_swap( - old_coldkey: &T::AccountId, - new_coldkey: &T::AccountId, - work: Vec, - block_number: u64, - nonce: u64, - ) -> DispatchResult { - ensure!(old_coldkey != new_coldkey, Error::::SameColdkey); - - // Check if the old_coldkey is a subnet owner for any network - let is_subnet_owner = (0..=TotalNetworks::::get()) - .any(|netuid| SubnetOwner::::get(netuid) == *old_coldkey); - - // Check if the old_coldkey has more than 500 TAO delegated - let total_delegated = Self::get_total_delegated_stake(old_coldkey); - let has_sufficient_delegation = total_delegated > 500_000_000_000; // 500 TAO in RAO - - // Only check the minimum balance if the old_coldkey is not a subnet owner - // and doesn't have sufficient delegation - if !(is_subnet_owner || has_sufficient_delegation) { - ensure!( - Self::meets_min_allowed_coldkey_balance(old_coldkey), - Error::::InsufficientBalanceToPerformColdkeySwap - ); - } - - // Get current destination coldkeys - let mut destination_coldkeys: Vec = - ColdkeySwapDestinations::::get(old_coldkey.clone()); - - // Calculate difficulty based on the number of existing destination coldkeys - let difficulty = Self::calculate_pow_difficulty(destination_coldkeys.len() as u32); - let work_hash = Self::vec_to_hash(work.clone()); - ensure!( - Self::hash_meets_difficulty(&work_hash, difficulty), - Error::::InvalidDifficulty - ); - - // Verify work is the product of the nonce, the block number, and coldkey - let seal = Self::create_seal_hash(block_number, nonce, old_coldkey); - ensure!(seal == work_hash, Error::::InvalidSeal); - - // Check if the new coldkey is already in the swap wallets list - ensure!( - !destination_coldkeys.contains(new_coldkey), - Error::::DuplicateColdkey - ); - - // If the destinations keys are empty or have less than the maximum allowed, we will add the new coldkey to the list - const MAX_COLDKEY_DESTINATIONS: usize = 10; - - if destination_coldkeys.len() < MAX_COLDKEY_DESTINATIONS { - destination_coldkeys.push(new_coldkey.clone()); - ColdkeySwapDestinations::::insert(old_coldkey.clone(), destination_coldkeys.clone()); - } else { - return Err(Error::::MaxColdkeyDestinationsReached.into()); - } - - // It is the first time we have seen this key - if destination_coldkeys.len() == 1_usize { - // Set the arbitration block for this coldkey - let arbitration_block: u64 = - Self::get_current_block_as_u64().saturating_add(ArbitrationPeriod::::get()); - ColdkeyArbitrationBlock::::insert(old_coldkey.clone(), arbitration_block); - - // Update the list of coldkeys to arbitrate on this block - let mut key_to_arbitrate_on_this_block: Vec = - ColdkeysToSwapAtBlock::::get(arbitration_block); - if !key_to_arbitrate_on_this_block.contains(old_coldkey) { - key_to_arbitrate_on_this_block.push(old_coldkey.clone()); - } - ColdkeysToSwapAtBlock::::insert(arbitration_block, key_to_arbitrate_on_this_block); - } - - // Emit an event indicating that a coldkey swap has been scheduled - Self::deposit_event(Event::ColdkeySwapScheduled { - old_coldkey: old_coldkey.clone(), - new_coldkey: new_coldkey.clone(), - arbitration_block: ColdkeyArbitrationBlock::::get(old_coldkey), - }); - - Ok(()) - } - - /// Calculate the proof of work difficulty based on the number of swap attempts - #[allow(clippy::arithmetic_side_effects)] - pub fn calculate_pow_difficulty(swap_attempts: u32) -> U256 { - let base_difficulty: U256 = U256::from(BaseDifficulty::::get()); // Base difficulty - base_difficulty.saturating_mul(U256::from(2).pow(U256::from(swap_attempts))) - } - - /// Arbitrates coldkeys that are scheduled to be swapped on this block. - /// - /// This function retrieves the list of coldkeys scheduled to be swapped on the current block, - /// and processes each coldkey by either extending the arbitration period or performing the swap - /// to the new coldkey. - /// - /// # Returns - /// - /// * `Weight` - The total weight consumed by this operation - pub fn swap_coldkeys_this_block(_weight_limit: &Weight) -> Result { - let mut weight_used = frame_support::weights::Weight::from_parts(0, 0); - - let current_block: u64 = Self::get_current_block_as_u64(); - log::debug!("Swapping coldkeys for block: {:?}", current_block); - - let source_coldkeys: Vec = ColdkeysToSwapAtBlock::::get(current_block); - ColdkeysToSwapAtBlock::::remove(current_block); - weight_used = weight_used.saturating_add(T::DbWeight::get().reads_writes(1, 1)); - - let mut keys_swapped = 0u64; - for coldkey_i in source_coldkeys.iter() { - // TODO: need a sane way to terminate early without locking users in. - // we should update the swap time - // if weight_used.ref_time() > weight_limit.ref_time() { - // log::warn!("Could not finish swapping all coldkeys this block due to weight limit, breaking after swapping {} keys.", keys_swapped); - // break; - // } - - let destinations_coldkeys: Vec = - ColdkeySwapDestinations::::get(coldkey_i); - weight_used = weight_used.saturating_add(T::DbWeight::get().reads(1)); - - if destinations_coldkeys.len() > 1 { - // Do not remove ColdkeySwapDestinations if there are multiple destinations - ColdkeyArbitrationBlock::::insert(coldkey_i.clone(), u64::MAX); - Self::deposit_event(Event::ArbitrationPeriodExtended { - coldkey: coldkey_i.clone(), - }); - } else if let Some(new_coldkey) = destinations_coldkeys.first() { - // Only remove ColdkeySwapDestinations if there's a single destination - ColdkeySwapDestinations::::remove(&coldkey_i); - weight_used = weight_used.saturating_add(T::DbWeight::get().writes(1)); - Self::perform_swap_coldkey(coldkey_i, new_coldkey).map(|weight| { - weight_used = weight_used.saturating_add(weight); - keys_swapped = keys_swapped.saturating_add(1); - })?; - } - } - - Ok(weight_used) - } - - pub fn perform_swap_coldkey( - old_coldkey: &T::AccountId, - new_coldkey: &T::AccountId, - ) -> Result { - log::info!( - "Performing swap for coldkey: {:?} to {:?}", - old_coldkey, - new_coldkey - ); - // Init the weight. - let mut weight = frame_support::weights::Weight::from_parts(0, 0); - - // Swap coldkey references in storage maps - // NOTE The order of these calls is important - Self::swap_stake_for_coldkey(old_coldkey, new_coldkey, &mut weight); - Self::swap_total_hotkey_coldkey_stakes_this_interval_for_coldkey( - old_coldkey, - new_coldkey, - &mut weight, - ); - Self::swap_subnet_owner_for_coldkey(old_coldkey, new_coldkey, &mut weight); - - // Transfer any remaining balance from old_coldkey to new_coldkey - let remaining_balance = Self::get_coldkey_balance(old_coldkey); - if remaining_balance > 0 { - if let Err(e) = Self::kill_coldkey_account(old_coldkey, remaining_balance) { - return Err(e.into()); - } - Self::add_balance_to_coldkey_account(new_coldkey, remaining_balance); - } - - // Swap the coldkey. - let total_balance: u64 = Self::get_coldkey_balance(old_coldkey); - if total_balance > 0 { - // Attempt to transfer the entire total balance to new_coldkey. - T::Currency::transfer( - old_coldkey, - new_coldkey, - total_balance, - Preservation::Expendable, - )?; - } - - Ok(weight) - } - - /// Retrieves the network membership status for a given hotkey. - /// - /// # Arguments - /// - /// * `old_hotkey` - The hotkey to check for network membership. - /// - /// # Returns - /// - /// * `Vec` - A vector of network IDs where the hotkey is a member. - pub fn get_netuid_is_member(old_hotkey: &T::AccountId, weight: &mut Weight) -> Vec { - let netuid_is_member: Vec = - as IterableStorageDoubleMap<_, _, _>>::iter_prefix(old_hotkey) - .map(|(netuid, _)| netuid) - .collect(); - weight.saturating_accrue(T::DbWeight::get().reads(netuid_is_member.len() as u64)); - netuid_is_member - } - - /// Swaps the owner of the hotkey. - /// - /// # Arguments - /// - /// * `old_hotkey` - The old hotkey. - /// * `new_hotkey` - The new hotkey. - /// * `coldkey` - The coldkey owning the hotkey. - /// * `weight` - The weight of the transaction. - /// - pub fn swap_owner( - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - coldkey: &T::AccountId, - weight: &mut Weight, - ) { - Owner::::remove(old_hotkey); - Owner::::insert(new_hotkey, coldkey.clone()); - - // Update OwnedHotkeys map - let mut hotkeys = OwnedHotkeys::::get(coldkey); - if !hotkeys.contains(new_hotkey) { - hotkeys.push(new_hotkey.clone()); - } - hotkeys.retain(|hk| *hk != *old_hotkey); - OwnedHotkeys::::insert(coldkey, hotkeys); - - weight.saturating_accrue(T::DbWeight::get().writes(2)); - } - - /// Swaps the total stake of the hotkey. - /// - /// # Arguments - /// - /// * `old_hotkey` - The old hotkey. - /// * `new_hotkey` - The new hotkey. - /// * `weight` - The weight of the transaction. - /// - /// # Weight Calculation - /// - /// * Reads: 1 if the old hotkey exists, otherwise 1 for the failed read. - /// * Writes: 2 if the old hotkey exists (one for removal and one for insertion). - pub fn swap_total_hotkey_stake( - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - weight: &mut Weight, - ) { - if let Ok(total_hotkey_stake) = TotalHotkeyStake::::try_get(old_hotkey) { - TotalHotkeyStake::::remove(old_hotkey); - TotalHotkeyStake::::insert(new_hotkey, total_hotkey_stake); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - } else { - weight.saturating_accrue(T::DbWeight::get().reads(1)); - } - } - - /// Swaps the delegates of the hotkey. - /// - /// # Arguments - /// - /// * `old_hotkey` - The old hotkey. - /// * `new_hotkey` - The new hotkey. - /// * `weight` - The weight of the transaction. - /// - /// # Weight Calculation - /// - /// * Reads: 1 if the old hotkey exists, otherwise 1 for the failed read. - /// * Writes: 2 if the old hotkey exists (one for removal and one for insertion). - pub fn swap_delegates( - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - weight: &mut Weight, - ) { - if let Ok(delegate_take) = Delegates::::try_get(old_hotkey) { - Delegates::::remove(old_hotkey); - Delegates::::insert(new_hotkey, delegate_take); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - } else { - weight.saturating_accrue(T::DbWeight::get().reads(1)); - } - } - - /// Swaps the stake of the hotkey. - /// - /// # Arguments - /// - /// * `old_hotkey` - The old hotkey. - /// * `new_hotkey` - The new hotkey. - /// * `weight` - The weight of the transaction. - pub fn swap_stake(old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, weight: &mut Weight) { - let mut writes: u64 = 0; - let stakes: Vec<(T::AccountId, u64)> = Stake::::iter_prefix(old_hotkey).collect(); - let stake_count = stakes.len() as u32; - - for (coldkey, stake_amount) in stakes { - Stake::::insert(new_hotkey, &coldkey, stake_amount); - writes = writes.saturating_add(1u64); // One write for insert - - // Update StakingHotkeys map - let mut staking_hotkeys = StakingHotkeys::::get(&coldkey); - if !staking_hotkeys.contains(new_hotkey) { - staking_hotkeys.push(new_hotkey.clone()); - writes = writes.saturating_add(1u64); // One write for insert - } - if let Some(pos) = staking_hotkeys.iter().position(|x| x == old_hotkey) { - staking_hotkeys.remove(pos); - writes = writes.saturating_add(1u64); // One write for remove - } - StakingHotkeys::::insert(coldkey.clone(), staking_hotkeys); - writes = writes.saturating_add(1u64); // One write for insert - } - - // Clear the prefix for the old hotkey after transferring all stakes - let _ = Stake::::clear_prefix(old_hotkey, stake_count, None); - writes = writes.saturating_add(1); // One write for insert; // One write for clear_prefix - - // TODO: Remove all entries for old hotkey from StakingHotkeys map - - weight.saturating_accrue(T::DbWeight::get().writes(writes)); - } - - /// Swaps the network membership status of the hotkey. - /// - /// # Arguments - /// - /// * `old_hotkey` - The old hotkey. - /// * `new_hotkey` - The new hotkey. - /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. - /// * `weight` - The weight of the transaction. - pub fn swap_is_network_member( - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - netuid_is_member: &[u16], - weight: &mut Weight, - ) { - let _ = IsNetworkMember::::clear_prefix(old_hotkey, netuid_is_member.len() as u32, None); - weight.saturating_accrue(T::DbWeight::get().writes(netuid_is_member.len() as u64)); - for netuid in netuid_is_member.iter() { - IsNetworkMember::::insert(new_hotkey, netuid, true); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } - } - - /// Swaps the axons of the hotkey. - /// - /// # Arguments - /// - /// * `old_hotkey` - The old hotkey. - /// * `new_hotkey` - The new hotkey. - /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. - /// * `weight` - The weight of the transaction. - /// - /// # Weight Calculation - /// - /// * Reads: 1 for each network ID if the old hotkey exists in that network. - /// * Writes: 2 for each network ID if the old hotkey exists in that network (one for removal and one for insertion). - pub fn swap_axons( - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - netuid_is_member: &[u16], - weight: &mut Weight, - ) { - for netuid in netuid_is_member.iter() { - if let Ok(axon_info) = Axons::::try_get(netuid, old_hotkey) { - Axons::::remove(netuid, old_hotkey); - Axons::::insert(netuid, new_hotkey, axon_info); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - } else { - weight.saturating_accrue(T::DbWeight::get().reads(1)); - } - } - } - - /// Swaps the references in the keys storage map of the hotkey. - /// - /// # Arguments - /// - /// * `old_hotkey` - The old hotkey. - /// * `new_hotkey` - The new hotkey. - /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. - /// * `weight` - The weight of the transaction. - pub fn swap_keys( - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - netuid_is_member: &[u16], - weight: &mut Weight, - ) { - let mut writes: u64 = 0; - for netuid in netuid_is_member { - let keys: Vec<(u16, T::AccountId)> = Keys::::iter_prefix(netuid).collect(); - for (uid, key) in keys { - if key == *old_hotkey { - log::info!("old hotkey found: {:?}", old_hotkey); - Keys::::insert(netuid, uid, new_hotkey.clone()); - } - writes = writes.saturating_add(2u64); - } - } - log::info!("writes: {:?}", writes); - weight.saturating_accrue(T::DbWeight::get().writes(writes)); - } - - /// Swaps the loaded emission of the hotkey. - /// - /// # Arguments - /// - /// * `old_hotkey` - The old hotkey. - /// * `new_hotkey` - The new hotkey. - /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. - /// * `weight` - The weight of the transaction. - /// - pub fn swap_loaded_emission( - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - netuid_is_member: &[u16], - weight: &mut Weight, - ) { - for netuid in netuid_is_member { - if let Some(mut emissions) = LoadedEmission::::get(netuid) { - for emission in emissions.iter_mut() { - if emission.0 == *old_hotkey { - emission.0 = new_hotkey.clone(); - } - } - LoadedEmission::::insert(netuid, emissions); - } - } - weight.saturating_accrue(T::DbWeight::get().writes(netuid_is_member.len() as u64)); - } - - /// Swaps the UIDs of the hotkey. - /// - /// # Arguments - /// - /// * `old_hotkey` - The old hotkey. - /// * `new_hotkey` - The new hotkey. - /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. - /// * `weight` - The weight of the transaction. - /// - pub fn swap_uids( - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - netuid_is_member: &[u16], - weight: &mut Weight, - ) { - for netuid in netuid_is_member.iter() { - if let Ok(uid) = Uids::::try_get(netuid, old_hotkey) { - Uids::::remove(netuid, old_hotkey); - Uids::::insert(netuid, new_hotkey, uid); - weight.saturating_accrue(T::DbWeight::get().writes(2)); - } - } - } - - /// Swaps the Prometheus data of the hotkey. - /// - /// # Arguments - /// - /// * `old_hotkey` - The old hotkey. - /// * `new_hotkey` - The new hotkey. - /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. - /// * `weight` - The weight of the transaction. - /// - /// # Weight Calculation - /// - /// * Reads: 1 for each network ID if the old hotkey exists in that network. - /// * Writes: 2 for each network ID if the old hotkey exists in that network (one for removal and one for insertion). - pub fn swap_prometheus( - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - netuid_is_member: &[u16], - weight: &mut Weight, - ) { - for netuid in netuid_is_member.iter() { - if let Ok(prometheus_info) = Prometheus::::try_get(netuid, old_hotkey) { - Prometheus::::remove(netuid, old_hotkey); - Prometheus::::insert(netuid, new_hotkey, prometheus_info); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - } else { - weight.saturating_accrue(T::DbWeight::get().reads(1)); - } - } - } - - /// Swaps the total hotkey-coldkey stakes for the current interval. - /// - /// # Arguments - /// - /// * `old_hotkey` - The old hotkey. - /// * `new_hotkey` - The new hotkey. - /// * `weight` - The weight of the transaction. - /// - pub fn swap_total_hotkey_coldkey_stakes_this_interval( - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - weight: &mut Weight, - ) { - let stakes: Vec<(T::AccountId, (u64, u64))> = - TotalHotkeyColdkeyStakesThisInterval::::iter_prefix(old_hotkey).collect(); - log::info!("Stakes to swap: {:?}", stakes); - for (coldkey, stake) in stakes { - log::info!( - "Swapping stake for coldkey: {:?}, stake: {:?}", - coldkey, - stake - ); - TotalHotkeyColdkeyStakesThisInterval::::insert(new_hotkey, &coldkey, stake); - TotalHotkeyColdkeyStakesThisInterval::::remove(old_hotkey, &coldkey); - weight.saturating_accrue(T::DbWeight::get().writes(2)); // One write for insert and one for remove - } - } - - /// Swaps the total stake associated with a coldkey from the old coldkey to the new coldkey. - /// - /// # Arguments - /// - /// * `old_coldkey` - The AccountId of the old coldkey. - /// * `new_coldkey` - The AccountId of the new coldkey. - /// * `weight` - Mutable reference to the weight of the transaction. - /// - /// # Effects - /// - /// * Removes the total stake from the old coldkey. - /// * Inserts the total stake for the new coldkey. - /// * Updates the transaction weight. - pub fn swap_total_coldkey_stake( - old_coldkey: &T::AccountId, - new_coldkey: &T::AccountId, - weight: &mut Weight, - ) { - let stake = TotalColdkeyStake::::get(old_coldkey); - TotalColdkeyStake::::remove(old_coldkey); - TotalColdkeyStake::::insert(new_coldkey, stake); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - } - - /// Swaps the stake associated with a coldkey from the old coldkey to the new coldkey. - /// - /// # Arguments - /// - /// * `old_coldkey` - The AccountId of the old coldkey. - /// * `new_coldkey` - The AccountId of the new coldkey. - /// * `weight` - Mutable reference to the weight of the transaction. - /// - /// # Effects - /// - /// * Transfers all stakes from the old coldkey to the new coldkey. - /// * Updates the ownership of hotkeys. - /// * Updates the total stake for both old and new coldkeys. - /// * Updates the transaction weight. - /// - - pub fn swap_stake_for_coldkey( - old_coldkey: &T::AccountId, - new_coldkey: &T::AccountId, - weight: &mut Weight, - ) { - // Retrieve the list of hotkeys owned by the old coldkey - let old_owned_hotkeys: Vec = OwnedHotkeys::::get(old_coldkey); - - // Initialize the total transferred stake to zero - let mut total_transferred_stake: u64 = 0u64; - - // Log the total stake of old and new coldkeys before the swap - log::info!( - "Before swap - Old coldkey total stake: {}", - TotalColdkeyStake::::get(old_coldkey) - ); - log::info!( - "Before swap - New coldkey total stake: {}", - TotalColdkeyStake::::get(new_coldkey) - ); - - // Iterate over each hotkey owned by the old coldkey - for hotkey in old_owned_hotkeys.iter() { - // Retrieve and remove the stake associated with the hotkey and old coldkey - let stake: u64 = Stake::::take(hotkey, old_coldkey); - log::info!("Transferring stake for hotkey {:?}: {}", hotkey, stake); - if stake > 0 { - // Insert the stake for the hotkey and new coldkey - let old_stake = Stake::::get(hotkey, new_coldkey); - Stake::::insert(hotkey, new_coldkey, stake.saturating_add(old_stake)); - total_transferred_stake = total_transferred_stake.saturating_add(stake); - - // Update the owner of the hotkey to the new coldkey - Owner::::insert(hotkey, new_coldkey); - - // Update the transaction weight - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - } - } - log::info!( - "Starting transfer of delegated stakes for old coldkey: {:?}", - old_coldkey - ); - - for staking_hotkey in StakingHotkeys::::get(old_coldkey) { - log::info!("Processing staking hotkey: {:?}", staking_hotkey); - if Stake::::contains_key(staking_hotkey.clone(), old_coldkey) { - let hotkey = &staking_hotkey; - // Retrieve and remove the stake associated with the hotkey and old coldkey - let stake: u64 = Stake::::get(hotkey, old_coldkey); - Stake::::remove(hotkey, old_coldkey); - log::info!( - "Transferring delegated stake for hotkey {:?}: {}", - hotkey, - stake - ); - if stake > 0 { - // Insert the stake for the hotkey and new coldkey - let old_stake = Stake::::get(hotkey, new_coldkey); - Stake::::insert(hotkey, new_coldkey, stake.saturating_add(old_stake)); - total_transferred_stake = total_transferred_stake.saturating_add(stake); - log::info!( - "Updated stake for hotkey {:?} under new coldkey {:?}: {}", - hotkey, - new_coldkey, - stake.saturating_add(old_stake) - ); - - // Update the transaction weight - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 1)); - } - } else { - log::info!( - "No stake found for staking hotkey {:?} under old coldkey {:?}", - staking_hotkey, - old_coldkey - ); - weight.saturating_accrue(T::DbWeight::get().reads(1)); - } - } - - log::info!( - "Completed transfer of delegated stakes for old coldkey: {:?}", - old_coldkey - ); - - // Log the total transferred stake - log::info!("Total transferred stake: {}", total_transferred_stake); - - // Update the total stake for both old and new coldkeys if any stake was transferred - if total_transferred_stake > 0 { - let old_coldkey_stake: u64 = TotalColdkeyStake::::take(old_coldkey); // Remove it here. - let new_coldkey_stake: u64 = TotalColdkeyStake::::get(new_coldkey); - - TotalColdkeyStake::::insert(old_coldkey, 0); - TotalColdkeyStake::::insert( - new_coldkey, - new_coldkey_stake.saturating_add(old_coldkey_stake), - ); - - log::info!("Updated old coldkey stake from {} to 0", old_coldkey_stake); - log::info!( - "Updated new coldkey stake from {} to {}", - new_coldkey_stake, - new_coldkey_stake.saturating_add(old_coldkey_stake) - ); - - // Update the transaction weight - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - } - - // Update the list of owned hotkeys for both old and new coldkeys - - let mut new_owned_hotkeys = OwnedHotkeys::::get(new_coldkey); - for hotkey in old_owned_hotkeys { - if !new_owned_hotkeys.contains(&hotkey) { - new_owned_hotkeys.push(hotkey); - } - } - - OwnedHotkeys::::insert(new_coldkey, new_owned_hotkeys); - OwnedHotkeys::::remove(old_coldkey); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - - // Update the staking hotkeys for both old and new coldkeys - let staking_hotkeys: Vec = StakingHotkeys::::get(old_coldkey); - - let mut existing_staking_hotkeys = StakingHotkeys::::get(new_coldkey); - for hotkey in staking_hotkeys { - if !existing_staking_hotkeys.contains(&hotkey) { - existing_staking_hotkeys.push(hotkey); - } - } - - StakingHotkeys::::remove(old_coldkey); - StakingHotkeys::::insert(new_coldkey, existing_staking_hotkeys); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - - // Log the total stake of old and new coldkeys after the swap - log::info!( - "After swap - Old coldkey total stake: {}", - TotalColdkeyStake::::get(old_coldkey) - ); - log::info!( - "After swap - New coldkey total stake: {}", - TotalColdkeyStake::::get(new_coldkey) - ); - } - - /// Swaps the total hotkey-coldkey stakes for the current interval from the old coldkey to the new coldkey. - /// - /// # Arguments - /// - /// * `old_coldkey` - The AccountId of the old coldkey. - /// * `new_coldkey` - The AccountId of the new coldkey. - /// * `weight` - Mutable reference to the weight of the transaction. - /// - /// # Effects - /// - /// * Removes all total hotkey-coldkey stakes for the current interval associated with the old coldkey. - /// * Inserts all total hotkey-coldkey stakes for the current interval for the new coldkey. - /// * Updates the transaction weight. - pub fn swap_total_hotkey_coldkey_stakes_this_interval_for_coldkey( - old_coldkey: &T::AccountId, - new_coldkey: &T::AccountId, - weight: &mut Weight, - ) { - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 0)); - for hotkey in OwnedHotkeys::::get(old_coldkey).iter() { - let (stake, block) = - TotalHotkeyColdkeyStakesThisInterval::::get(&hotkey, old_coldkey); - TotalHotkeyColdkeyStakesThisInterval::::remove(&hotkey, old_coldkey); - TotalHotkeyColdkeyStakesThisInterval::::insert(&hotkey, new_coldkey, (stake, block)); - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - } - } - - /// Checks if a coldkey has any associated hotkeys. - /// - /// # Arguments - /// - /// * `coldkey` - The AccountId of the coldkey to check. - /// - /// # Returns - /// - /// * `bool` - True if the coldkey has any associated hotkeys, false otherwise. - pub fn coldkey_has_associated_hotkeys(coldkey: &T::AccountId) -> bool { - !StakingHotkeys::::get(coldkey).is_empty() - } - - /// Swaps the subnet owner from the old coldkey to the new coldkey for all networks where the old coldkey is the owner. - /// - /// # Arguments - /// - /// * `old_coldkey` - The AccountId of the old coldkey. - /// * `new_coldkey` - The AccountId of the new coldkey. - /// * `weight` - Mutable reference to the weight of the transaction. - /// - /// # Effects - /// - /// * Updates the subnet owner to the new coldkey for all networks where the old coldkey was the owner. - /// * Updates the transaction weight. - pub fn swap_subnet_owner_for_coldkey( - old_coldkey: &T::AccountId, - new_coldkey: &T::AccountId, - weight: &mut Weight, - ) { - for netuid in 0..=TotalNetworks::::get() { - let subnet_owner = SubnetOwner::::get(netuid); - if subnet_owner == *old_coldkey { - SubnetOwner::::insert(netuid, new_coldkey.clone()); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } - } - weight.saturating_accrue(T::DbWeight::get().reads(TotalNetworks::::get() as u64)); - } - - pub fn swap_senate_member( - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - weight: &mut Weight, - ) -> DispatchResult { - weight.saturating_accrue(T::DbWeight::get().reads(1)); - if T::SenateMembers::is_member(old_hotkey) { - T::SenateMembers::swap_member(old_hotkey, new_hotkey).map_err(|e| e.error)?; - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - } - Ok(()) - } -} diff --git a/pallets/subtensor/src/swap/mod.rs b/pallets/subtensor/src/swap/mod.rs new file mode 100644 index 0000000000..0e71b1b1de --- /dev/null +++ b/pallets/subtensor/src/swap/mod.rs @@ -0,0 +1,3 @@ +use super::*; +pub mod swap_coldkey; +pub mod swap_hotkey; \ No newline at end of file diff --git a/pallets/subtensor/src/swap/swap_coldkey.rs b/pallets/subtensor/src/swap/swap_coldkey.rs new file mode 100644 index 0000000000..83bad51341 --- /dev/null +++ b/pallets/subtensor/src/swap/swap_coldkey.rs @@ -0,0 +1,391 @@ +use super::*; +use frame_support::traits::fungible::Mutate; +use frame_support::traits::tokens::Preservation; +use frame_support::{storage::IterableStorageDoubleMap, weights::Weight}; +use sp_core::Get; + +impl Pallet { + + + /// Swaps the coldkey associated with a set of hotkeys from an old coldkey to a new coldkey. + /// + /// # Arguments + /// + /// * `origin` - The origin of the call, which must be signed by the old coldkey. + /// * `old_coldkey` - The account ID of the old coldkey. + /// * `new_coldkey` - The account ID of the new coldkey. + /// + /// # Returns + /// + /// Returns a `DispatchResultWithPostInfo` indicating success or failure, along with the weight consumed. + /// + /// # Errors + /// + /// This function will return an error if: + /// - The caller is not the old coldkey. + /// - The new coldkey is the same as the old coldkey. + /// - The new coldkey is already associated with other hotkeys. + /// - The transaction rate limit for coldkey swaps has been exceeded. + /// - There's not enough balance to pay for the swap. + /// + /// # Events + /// + /// Emits a `ColdkeySwapped` event when successful. + /// + /// # Weight + /// + /// Weight is tracked and updated throughout the function execution. + pub fn do_swap_coldkey( + origin: T::RuntimeOrigin, + new_coldkey: &T::AccountId, + ) -> DispatchResultWithPostInfo { + let old_coldkey = ensure_signed(origin)?; + let mut weight: Weight = T::DbWeight::get().reads(2); + + // Check that the coldkey is a new key (does not exist elsewhere.) + ensure!( + !Self::coldkey_has_associated_hotkeys(new_coldkey), + Error::::ColdKeyAlreadyAssociated + ); + // Check that the new coldkey is not a hotkey. + ensure!( + !Self::hotkey_account_exists(new_coldkey), + Error::::ColdKeyAlreadyAssociated + ); + + // Calculate and charge the swap fee + let swap_cost = Self::get_key_swap_cost(); + log::debug!("Coldkey swap cost: {:?}", swap_cost); + + ensure!( + Self::can_remove_balance_from_coldkey_account(&old_coldkey, swap_cost), + Error::::NotEnoughBalanceToPaySwapColdKey + ); + let actual_burn_amount = + Self::remove_balance_from_coldkey_account(&old_coldkey, swap_cost)?; + Self::burn_tokens(actual_burn_amount); + + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + + // Actually do the swap. + weight = weight.saturating_add( + Self::perform_swap_coldkey(&old_coldkey, new_coldkey) + .map_err(|_| Error::::ColdkeySwapError)?, + ); + + Self::set_last_tx_block(new_coldkey, Self::get_current_block_as_u64()); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + + Self::deposit_event(Event::ColdkeySwapped { + old_coldkey: old_coldkey.clone(), + new_coldkey: new_coldkey.clone(), + }); + + Ok(Some(weight).into()) + } + + pub fn perform_swap_coldkey( + old_coldkey: &T::AccountId, + new_coldkey: &T::AccountId, + ) -> Result { + log::info!( + "Performing swap for coldkey: {:?} to {:?}", + old_coldkey, + new_coldkey + ); + // Init the weight. + let mut weight = frame_support::weights::Weight::from_parts(0, 0); + + // Swap coldkey references in storage maps + // NOTE The order of these calls is important + Self::swap_stake_for_coldkey(old_coldkey, new_coldkey, &mut weight); + Self::swap_total_hotkey_coldkey_stakes_this_interval_for_coldkey( + old_coldkey, + new_coldkey, + &mut weight, + ); + Self::swap_subnet_owner_for_coldkey(old_coldkey, new_coldkey, &mut weight); + + // Transfer any remaining balance from old_coldkey to new_coldkey + let remaining_balance = Self::get_coldkey_balance(old_coldkey); + if remaining_balance > 0 { + if let Err(e) = Self::kill_coldkey_account(old_coldkey, remaining_balance) { + return Err(e.into()); + } + Self::add_balance_to_coldkey_account(new_coldkey, remaining_balance); + } + + // Swap the coldkey. + let total_balance: u64 = Self::get_coldkey_balance(old_coldkey); + if total_balance > 0 { + // Attempt to transfer the entire total balance to new_coldkey. + T::Currency::transfer( + old_coldkey, + new_coldkey, + total_balance, + Preservation::Expendable, + )?; + } + + Ok(weight) + } + + + /// Swaps the total stake associated with a coldkey from the old coldkey to the new coldkey. + /// + /// # Arguments + /// + /// * `old_coldkey` - The AccountId of the old coldkey. + /// * `new_coldkey` - The AccountId of the new coldkey. + /// * `weight` - Mutable reference to the weight of the transaction. + /// + /// # Effects + /// + /// * Removes the total stake from the old coldkey. + /// * Inserts the total stake for the new coldkey. + /// * Updates the transaction weight. + pub fn swap_total_coldkey_stake( + old_coldkey: &T::AccountId, + new_coldkey: &T::AccountId, + weight: &mut Weight, + ) { + let stake = TotalColdkeyStake::::get(old_coldkey); + TotalColdkeyStake::::remove(old_coldkey); + TotalColdkeyStake::::insert(new_coldkey, stake); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + } + + /// Swaps the stake associated with a coldkey from the old coldkey to the new coldkey. + /// + /// # Arguments + /// + /// * `old_coldkey` - The AccountId of the old coldkey. + /// * `new_coldkey` - The AccountId of the new coldkey. + /// * `weight` - Mutable reference to the weight of the transaction. + /// + /// # Effects + /// + /// * Transfers all stakes from the old coldkey to the new coldkey. + /// * Updates the ownership of hotkeys. + /// * Updates the total stake for both old and new coldkeys. + /// * Updates the transaction weight. + /// + + pub fn swap_stake_for_coldkey( + old_coldkey: &T::AccountId, + new_coldkey: &T::AccountId, + weight: &mut Weight, + ) { + // Retrieve the list of hotkeys owned by the old coldkey + let old_owned_hotkeys: Vec = OwnedHotkeys::::get(old_coldkey); + + // Initialize the total transferred stake to zero + let mut total_transferred_stake: u64 = 0u64; + + // Log the total stake of old and new coldkeys before the swap + log::info!( + "Before swap - Old coldkey total stake: {}", + TotalColdkeyStake::::get(old_coldkey) + ); + log::info!( + "Before swap - New coldkey total stake: {}", + TotalColdkeyStake::::get(new_coldkey) + ); + + // Iterate over each hotkey owned by the old coldkey + for hotkey in old_owned_hotkeys.iter() { + // Retrieve and remove the stake associated with the hotkey and old coldkey + let stake: u64 = Stake::::take(hotkey, old_coldkey); + log::info!("Transferring stake for hotkey {:?}: {}", hotkey, stake); + if stake > 0 { + // Insert the stake for the hotkey and new coldkey + let old_stake = Stake::::get(hotkey, new_coldkey); + Stake::::insert(hotkey, new_coldkey, stake.saturating_add(old_stake)); + total_transferred_stake = total_transferred_stake.saturating_add(stake); + + // Update the owner of the hotkey to the new coldkey + Owner::::insert(hotkey, new_coldkey); + + // Update the transaction weight + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + } + } + log::info!( + "Starting transfer of delegated stakes for old coldkey: {:?}", + old_coldkey + ); + + for staking_hotkey in StakingHotkeys::::get(old_coldkey) { + log::info!("Processing staking hotkey: {:?}", staking_hotkey); + if Stake::::contains_key(staking_hotkey.clone(), old_coldkey) { + let hotkey = &staking_hotkey; + // Retrieve and remove the stake associated with the hotkey and old coldkey + let stake: u64 = Stake::::get(hotkey, old_coldkey); + Stake::::remove(hotkey, old_coldkey); + log::info!( + "Transferring delegated stake for hotkey {:?}: {}", + hotkey, + stake + ); + if stake > 0 { + // Insert the stake for the hotkey and new coldkey + let old_stake = Stake::::get(hotkey, new_coldkey); + Stake::::insert(hotkey, new_coldkey, stake.saturating_add(old_stake)); + total_transferred_stake = total_transferred_stake.saturating_add(stake); + log::info!( + "Updated stake for hotkey {:?} under new coldkey {:?}: {}", + hotkey, + new_coldkey, + stake.saturating_add(old_stake) + ); + + // Update the transaction weight + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 1)); + } + } else { + log::info!( + "No stake found for staking hotkey {:?} under old coldkey {:?}", + staking_hotkey, + old_coldkey + ); + weight.saturating_accrue(T::DbWeight::get().reads(1)); + } + } + + log::info!( + "Completed transfer of delegated stakes for old coldkey: {:?}", + old_coldkey + ); + + // Log the total transferred stake + log::info!("Total transferred stake: {}", total_transferred_stake); + + // Update the total stake for both old and new coldkeys if any stake was transferred + if total_transferred_stake > 0 { + let old_coldkey_stake: u64 = TotalColdkeyStake::::take(old_coldkey); // Remove it here. + let new_coldkey_stake: u64 = TotalColdkeyStake::::get(new_coldkey); + + TotalColdkeyStake::::insert(old_coldkey, 0); + TotalColdkeyStake::::insert( + new_coldkey, + new_coldkey_stake.saturating_add(old_coldkey_stake), + ); + + log::info!("Updated old coldkey stake from {} to 0", old_coldkey_stake); + log::info!( + "Updated new coldkey stake from {} to {}", + new_coldkey_stake, + new_coldkey_stake.saturating_add(old_coldkey_stake) + ); + + // Update the transaction weight + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + } + + // Update the list of owned hotkeys for both old and new coldkeys + + let mut new_owned_hotkeys = OwnedHotkeys::::get(new_coldkey); + for hotkey in old_owned_hotkeys { + if !new_owned_hotkeys.contains(&hotkey) { + new_owned_hotkeys.push(hotkey); + } + } + + OwnedHotkeys::::insert(new_coldkey, new_owned_hotkeys); + OwnedHotkeys::::remove(old_coldkey); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + + // Update the staking hotkeys for both old and new coldkeys + let staking_hotkeys: Vec = StakingHotkeys::::get(old_coldkey); + + let mut existing_staking_hotkeys = StakingHotkeys::::get(new_coldkey); + for hotkey in staking_hotkeys { + if !existing_staking_hotkeys.contains(&hotkey) { + existing_staking_hotkeys.push(hotkey); + } + } + + StakingHotkeys::::remove(old_coldkey); + StakingHotkeys::::insert(new_coldkey, existing_staking_hotkeys); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + + // Log the total stake of old and new coldkeys after the swap + log::info!( + "After swap - Old coldkey total stake: {}", + TotalColdkeyStake::::get(old_coldkey) + ); + log::info!( + "After swap - New coldkey total stake: {}", + TotalColdkeyStake::::get(new_coldkey) + ); + } + + /// Swaps the total hotkey-coldkey stakes for the current interval from the old coldkey to the new coldkey. + /// + /// # Arguments + /// + /// * `old_coldkey` - The AccountId of the old coldkey. + /// * `new_coldkey` - The AccountId of the new coldkey. + /// * `weight` - Mutable reference to the weight of the transaction. + /// + /// # Effects + /// + /// * Removes all total hotkey-coldkey stakes for the current interval associated with the old coldkey. + /// * Inserts all total hotkey-coldkey stakes for the current interval for the new coldkey. + /// * Updates the transaction weight. + pub fn swap_total_hotkey_coldkey_stakes_this_interval_for_coldkey( + old_coldkey: &T::AccountId, + new_coldkey: &T::AccountId, + weight: &mut Weight, + ) { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 0)); + for hotkey in OwnedHotkeys::::get(old_coldkey).iter() { + let (stake, block) = + TotalHotkeyColdkeyStakesThisInterval::::get(&hotkey, old_coldkey); + TotalHotkeyColdkeyStakesThisInterval::::remove(&hotkey, old_coldkey); + TotalHotkeyColdkeyStakesThisInterval::::insert(&hotkey, new_coldkey, (stake, block)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + } + } + + /// Checks if a coldkey has any associated hotkeys. + /// + /// # Arguments + /// + /// * `coldkey` - The AccountId of the coldkey to check. + /// + /// # Returns + /// + /// * `bool` - True if the coldkey has any associated hotkeys, false otherwise. + pub fn coldkey_has_associated_hotkeys(coldkey: &T::AccountId) -> bool { + !StakingHotkeys::::get(coldkey).is_empty() + } + + /// Swaps the subnet owner from the old coldkey to the new coldkey for all networks where the old coldkey is the owner. + /// + /// # Arguments + /// + /// * `old_coldkey` - The AccountId of the old coldkey. + /// * `new_coldkey` - The AccountId of the new coldkey. + /// * `weight` - Mutable reference to the weight of the transaction. + /// + /// # Effects + /// + /// * Updates the subnet owner to the new coldkey for all networks where the old coldkey was the owner. + /// * Updates the transaction weight. + pub fn swap_subnet_owner_for_coldkey( + old_coldkey: &T::AccountId, + new_coldkey: &T::AccountId, + weight: &mut Weight, + ) { + for netuid in 0..=TotalNetworks::::get() { + let subnet_owner = SubnetOwner::::get(netuid); + if subnet_owner == *old_coldkey { + SubnetOwner::::insert(netuid, new_coldkey.clone()); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + } + } + weight.saturating_accrue(T::DbWeight::get().reads(TotalNetworks::::get() as u64)); + } + +} diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs new file mode 100644 index 0000000000..2755f1c4cb --- /dev/null +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -0,0 +1,438 @@ +use super::*; +use frame_support::{storage::IterableStorageDoubleMap, weights::Weight}; +use sp_core::Get; + +impl Pallet { + /// Swaps the hotkey of a coldkey account. + /// + /// # Arguments + /// + /// * `origin` - The origin of the transaction, and also the coldkey account. + /// * `old_hotkey` - The old hotkey to be swapped. + /// * `new_hotkey` - The new hotkey to replace the old one. + /// + /// # Returns + /// + /// * `DispatchResultWithPostInfo` - The result of the dispatch. + /// + /// # Errors + /// + /// * `NonAssociatedColdKey` - If the coldkey does not own the old hotkey. + /// * `HotKeySetTxRateLimitExceeded` - If the transaction rate limit is exceeded. + /// * `NewHotKeyIsSameWithOld` - If the new hotkey is the same as the old hotkey. + /// * `HotKeyAlreadyRegisteredInSubNet` - If the new hotkey is already registered in the subnet. + /// * `NotEnoughBalanceToPaySwapHotKey` - If there is not enough balance to pay for the swap. + pub fn do_swap_hotkey( + origin: T::RuntimeOrigin, + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + ) -> DispatchResultWithPostInfo { + let coldkey = ensure_signed(origin)?; + + let mut weight = T::DbWeight::get().reads(2); + + ensure!(old_hotkey != new_hotkey, Error::::NewHotKeyIsSameWithOld); + ensure!( + !Self::is_hotkey_registered_on_any_network(new_hotkey), + Error::::HotKeyAlreadyRegisteredInSubNet + ); + + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 0)); + ensure!( + Self::coldkey_owns_hotkey(&coldkey, old_hotkey), + Error::::NonAssociatedColdKey + ); + + let block: u64 = Self::get_current_block_as_u64(); + ensure!( + !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&coldkey), block), + Error::::HotKeySetTxRateLimitExceeded + ); + + weight.saturating_accrue( + T::DbWeight::get().reads((TotalNetworks::::get().saturating_add(1u16)) as u64), + ); + + let swap_cost = Self::get_key_swap_cost(); + log::debug!("Swap cost: {:?}", swap_cost); + + ensure!( + Self::can_remove_balance_from_coldkey_account(&coldkey, swap_cost), + Error::::NotEnoughBalanceToPaySwapHotKey + ); + let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?; + Self::burn_tokens(actual_burn_amount); + + Self::swap_owner(old_hotkey, new_hotkey, &coldkey, &mut weight); + Self::swap_total_hotkey_stake(old_hotkey, new_hotkey, &mut weight); + Self::swap_delegates(old_hotkey, new_hotkey, &mut weight); + Self::swap_stake(old_hotkey, new_hotkey, &mut weight); + + // Store the value of is_network_member for the old key + let netuid_is_member: Vec = Self::get_netuid_is_member(old_hotkey, &mut weight); + + Self::swap_is_network_member(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); + Self::swap_axons(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); + Self::swap_keys(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); + Self::swap_loaded_emission(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); + Self::swap_uids(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); + Self::swap_prometheus(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); + Self::swap_senate_member(old_hotkey, new_hotkey, &mut weight)?; + + Self::swap_total_hotkey_coldkey_stakes_this_interval(old_hotkey, new_hotkey, &mut weight); + + Self::set_last_tx_block(&coldkey, block); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + + Self::deposit_event(Event::HotkeySwapped { + coldkey, + old_hotkey: old_hotkey.clone(), + new_hotkey: new_hotkey.clone(), + }); + + Ok(Some(weight).into()) + } + + /// Retrieves the network membership status for a given hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The hotkey to check for network membership. + /// + /// # Returns + /// + /// * `Vec` - A vector of network IDs where the hotkey is a member. + pub fn get_netuid_is_member(old_hotkey: &T::AccountId, weight: &mut Weight) -> Vec { + let netuid_is_member: Vec = + as IterableStorageDoubleMap<_, _, _>>::iter_prefix(old_hotkey) + .map(|(netuid, _)| netuid) + .collect(); + weight.saturating_accrue(T::DbWeight::get().reads(netuid_is_member.len() as u64)); + netuid_is_member + } + + /// Swaps the owner of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `coldkey` - The coldkey owning the hotkey. + /// * `weight` - The weight of the transaction. + /// + pub fn swap_owner( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + coldkey: &T::AccountId, + weight: &mut Weight, + ) { + Owner::::remove(old_hotkey); + Owner::::insert(new_hotkey, coldkey.clone()); + + // Update OwnedHotkeys map + let mut hotkeys = OwnedHotkeys::::get(coldkey); + if !hotkeys.contains(new_hotkey) { + hotkeys.push(new_hotkey.clone()); + } + hotkeys.retain(|hk| *hk != *old_hotkey); + OwnedHotkeys::::insert(coldkey, hotkeys); + + weight.saturating_accrue(T::DbWeight::get().writes(2)); + } + + /// Swaps the total stake of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `weight` - The weight of the transaction. + /// + /// # Weight Calculation + /// + /// * Reads: 1 if the old hotkey exists, otherwise 1 for the failed read. + /// * Writes: 2 if the old hotkey exists (one for removal and one for insertion). + pub fn swap_total_hotkey_stake( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + weight: &mut Weight, + ) { + if let Ok(total_hotkey_stake) = TotalHotkeyStake::::try_get(old_hotkey) { + TotalHotkeyStake::::remove(old_hotkey); + TotalHotkeyStake::::insert(new_hotkey, total_hotkey_stake); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + } else { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + } + } + + /// Swaps the delegates of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `weight` - The weight of the transaction. + /// + /// # Weight Calculation + /// + /// * Reads: 1 if the old hotkey exists, otherwise 1 for the failed read. + /// * Writes: 2 if the old hotkey exists (one for removal and one for insertion). + pub fn swap_delegates( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + weight: &mut Weight, + ) { + if let Ok(delegate_take) = Delegates::::try_get(old_hotkey) { + Delegates::::remove(old_hotkey); + Delegates::::insert(new_hotkey, delegate_take); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + } else { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + } + } + + /// Swaps the stake of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `weight` - The weight of the transaction. + pub fn swap_stake(old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, weight: &mut Weight) { + let mut writes: u64 = 0; + let stakes: Vec<(T::AccountId, u64)> = Stake::::iter_prefix(old_hotkey).collect(); + let stake_count = stakes.len() as u32; + + for (coldkey, stake_amount) in stakes { + Stake::::insert(new_hotkey, &coldkey, stake_amount); + writes = writes.saturating_add(1u64); // One write for insert + + // Update StakingHotkeys map + let mut staking_hotkeys = StakingHotkeys::::get(&coldkey); + if !staking_hotkeys.contains(new_hotkey) { + staking_hotkeys.push(new_hotkey.clone()); + writes = writes.saturating_add(1u64); // One write for insert + } + if let Some(pos) = staking_hotkeys.iter().position(|x| x == old_hotkey) { + staking_hotkeys.remove(pos); + writes = writes.saturating_add(1u64); // One write for remove + } + StakingHotkeys::::insert(coldkey.clone(), staking_hotkeys); + writes = writes.saturating_add(1u64); // One write for insert + } + + // Clear the prefix for the old hotkey after transferring all stakes + let _ = Stake::::clear_prefix(old_hotkey, stake_count, None); + writes = writes.saturating_add(1); // One write for insert; // One write for clear_prefix + + // TODO: Remove all entries for old hotkey from StakingHotkeys map + + weight.saturating_accrue(T::DbWeight::get().writes(writes)); + } + + /// Swaps the network membership status of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. + /// * `weight` - The weight of the transaction. + pub fn swap_is_network_member( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + netuid_is_member: &[u16], + weight: &mut Weight, + ) { + let _ = IsNetworkMember::::clear_prefix(old_hotkey, netuid_is_member.len() as u32, None); + weight.saturating_accrue(T::DbWeight::get().writes(netuid_is_member.len() as u64)); + for netuid in netuid_is_member.iter() { + IsNetworkMember::::insert(new_hotkey, netuid, true); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + } + } + + /// Swaps the axons of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. + /// * `weight` - The weight of the transaction. + /// + /// # Weight Calculation + /// + /// * Reads: 1 for each network ID if the old hotkey exists in that network. + /// * Writes: 2 for each network ID if the old hotkey exists in that network (one for removal and one for insertion). + pub fn swap_axons( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + netuid_is_member: &[u16], + weight: &mut Weight, + ) { + for netuid in netuid_is_member.iter() { + if let Ok(axon_info) = Axons::::try_get(netuid, old_hotkey) { + Axons::::remove(netuid, old_hotkey); + Axons::::insert(netuid, new_hotkey, axon_info); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + } else { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + } + } + } + + /// Swaps the references in the keys storage map of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. + /// * `weight` - The weight of the transaction. + pub fn swap_keys( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + netuid_is_member: &[u16], + weight: &mut Weight, + ) { + let mut writes: u64 = 0; + for netuid in netuid_is_member { + let keys: Vec<(u16, T::AccountId)> = Keys::::iter_prefix(netuid).collect(); + for (uid, key) in keys { + if key == *old_hotkey { + log::info!("old hotkey found: {:?}", old_hotkey); + Keys::::insert(netuid, uid, new_hotkey.clone()); + } + writes = writes.saturating_add(2u64); + } + } + log::info!("writes: {:?}", writes); + weight.saturating_accrue(T::DbWeight::get().writes(writes)); + } + + /// Swaps the loaded emission of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. + /// * `weight` - The weight of the transaction. + /// + pub fn swap_loaded_emission( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + netuid_is_member: &[u16], + weight: &mut Weight, + ) { + for netuid in netuid_is_member { + if let Some(mut emissions) = LoadedEmission::::get(netuid) { + for emission in emissions.iter_mut() { + if emission.0 == *old_hotkey { + emission.0 = new_hotkey.clone(); + } + } + LoadedEmission::::insert(netuid, emissions); + } + } + weight.saturating_accrue(T::DbWeight::get().writes(netuid_is_member.len() as u64)); + } + + /// Swaps the UIDs of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. + /// * `weight` - The weight of the transaction. + /// + pub fn swap_uids( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + netuid_is_member: &[u16], + weight: &mut Weight, + ) { + for netuid in netuid_is_member.iter() { + if let Ok(uid) = Uids::::try_get(netuid, old_hotkey) { + Uids::::remove(netuid, old_hotkey); + Uids::::insert(netuid, new_hotkey, uid); + weight.saturating_accrue(T::DbWeight::get().writes(2)); + } + } + } + + /// Swaps the Prometheus data of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. + /// * `weight` - The weight of the transaction. + /// + /// # Weight Calculation + /// + /// * Reads: 1 for each network ID if the old hotkey exists in that network. + /// * Writes: 2 for each network ID if the old hotkey exists in that network (one for removal and one for insertion). + pub fn swap_prometheus( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + netuid_is_member: &[u16], + weight: &mut Weight, + ) { + for netuid in netuid_is_member.iter() { + if let Ok(prometheus_info) = Prometheus::::try_get(netuid, old_hotkey) { + Prometheus::::remove(netuid, old_hotkey); + Prometheus::::insert(netuid, new_hotkey, prometheus_info); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + } else { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + } + } + } + + /// Swaps the total hotkey-coldkey stakes for the current interval. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `weight` - The weight of the transaction. + /// + pub fn swap_total_hotkey_coldkey_stakes_this_interval( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + weight: &mut Weight, + ) { + let stakes: Vec<(T::AccountId, (u64, u64))> = + TotalHotkeyColdkeyStakesThisInterval::::iter_prefix(old_hotkey).collect(); + log::info!("Stakes to swap: {:?}", stakes); + for (coldkey, stake) in stakes { + log::info!( + "Swapping stake for coldkey: {:?}, stake: {:?}", + coldkey, + stake + ); + TotalHotkeyColdkeyStakesThisInterval::::insert(new_hotkey, &coldkey, stake); + TotalHotkeyColdkeyStakesThisInterval::::remove(old_hotkey, &coldkey); + weight.saturating_accrue(T::DbWeight::get().writes(2)); // One write for insert and one for remove + } + } + + + pub fn swap_senate_member( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + weight: &mut Weight, + ) -> DispatchResult { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + if T::SenateMembers::is_member(old_hotkey) { + T::SenateMembers::swap_member(old_hotkey, new_hotkey).map_err(|e| e.error)?; + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + } + Ok(()) + } +} diff --git a/pallets/subtensor/tests/epoch.rs b/pallets/subtensor/tests/epoch.rs index 676b3cd35a..526a58b4e1 100644 --- a/pallets/subtensor/tests/epoch.rs +++ b/pallets/subtensor/tests/epoch.rs @@ -7,7 +7,7 @@ use crate::mock::*; use frame_support::{assert_err, assert_ok}; use frame_system::Config; -use pallet_subtensor::math::safe_exp; +use pallet_subtensor::epoch::math::safe_exp; use pallet_subtensor::*; use rand::{distributions::Uniform, rngs::StdRng, seq::SliceRandom, thread_rng, Rng, SeedableRng}; use sp_core::U256; @@ -1496,7 +1496,7 @@ fn test_set_alpha_disabled() { // Enable Liquid Alpha and setup SubtensorModule::set_liquid_alpha_enabled(netuid, true); - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); SubtensorModule::add_balance_to_coldkey_account(&coldkey, 1_000_000_000_000_000); assert_ok!(SubtensorModule::root_register(signer.clone(), hotkey,)); assert_ok!(SubtensorModule::add_stake(signer.clone(), hotkey, 1000)); @@ -2574,7 +2574,7 @@ fn test_get_set_alpha() { // Enable Liquid Alpha and setup SubtensorModule::set_liquid_alpha_enabled(netuid, true); - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); SubtensorModule::add_balance_to_coldkey_account(&coldkey, 1_000_000_000_000_000); assert_ok!(SubtensorModule::root_register(signer.clone(), hotkey,)); assert_ok!(SubtensorModule::add_stake(signer.clone(), hotkey, 1000)); diff --git a/pallets/subtensor/tests/migration.rs b/pallets/subtensor/tests/migration.rs index 3605682354..6d79d4794f 100644 --- a/pallets/subtensor/tests/migration.rs +++ b/pallets/subtensor/tests/migration.rs @@ -67,7 +67,7 @@ fn test_migration_fix_total_stake_maps() { assert_ne!(SubtensorModule::get_total_stake(), total_stake_amount); // Run the migration to fix the total stake maps - pallet_subtensor::migration::migrate_to_v2_fixed_total_stake::(); + pallet_subtensor::migrations::migrate_to_v2_fixed_total_stake::migrate_to_v2_fixed_total_stake::(); // Verify that the total stake is now correct assert_eq!(SubtensorModule::get_total_stake(), total_stake_amount); @@ -107,19 +107,19 @@ fn test_migration_fix_total_stake_maps() { #[test] // To run this test with cargo, use the following command: -// cargo test --package pallet-subtensor --test migration test_migration5_total_issuance -fn test_migration5_total_issuance() { +// cargo test --package pallet-subtensor --test migration test_migrate_total_issuance +fn test_migrate_total_issuance() { new_test_ext(1).execute_with(|| { // Run the migration to check total issuance. let test: bool = true; assert_eq!(SubtensorModule::get_total_issuance(), 0); - pallet_subtensor::migration::migration5_total_issuance::(test); + pallet_subtensor::migrations::migrate_total_issuance::migrate_total_issuance::(test); assert_eq!(SubtensorModule::get_total_issuance(), 0); SubtensorModule::add_balance_to_coldkey_account(&U256::from(1), 10000); assert_eq!(SubtensorModule::get_total_issuance(), 0); - pallet_subtensor::migration::migration5_total_issuance::(test); + pallet_subtensor::migrations::migrate_total_issuance::migrate_total_issuance::(test); assert_eq!(SubtensorModule::get_total_issuance(), 10000); SubtensorModule::increase_stake_on_coldkey_hotkey_account( @@ -128,7 +128,7 @@ fn test_migration5_total_issuance() { 30000, ); assert_eq!(SubtensorModule::get_total_issuance(), 10000); - pallet_subtensor::migration::migration5_total_issuance::(test); + pallet_subtensor::migrations::migrate_total_issuance::migrate_total_issuance::(test); assert_eq!(SubtensorModule::get_total_issuance(), 10000 + 30000); }) } @@ -152,7 +152,7 @@ fn test_total_issuance_global() { )); SubtensorModule::set_max_allowed_uids(netuid, 1); // Set the maximum allowed unique identifiers for the network to 1. assert_eq!(SubtensorModule::get_total_issuance(), 0); // initial is zero. - pallet_subtensor::migration::migration5_total_issuance::(true); // Pick up lock. + pallet_subtensor::migrations::migrate_total_issuance::migrate_total_issuance::(true); // Pick up lock. assert_eq!(SubtensorModule::get_total_issuance(), lockcost); // Verify the total issuance is updated to 20000 after migration. assert!(SubtensorModule::if_subnet_exist(netuid)); @@ -162,7 +162,7 @@ fn test_total_issuance_global() { let _coldkey_account_id_1 = U256::from(1); // Define a coldkey account ID for further operations. assert_eq!(SubtensorModule::get_total_issuance(), lockcost); // Ensure the total issuance starts at 0 before the migration. SubtensorModule::add_balance_to_coldkey_account(&coldkey, account_balance); // Add a balance of 20000 to the coldkey account. - pallet_subtensor::migration::migration5_total_issuance::(true); // Execute the migration to update total issuance. + pallet_subtensor::migrations::migrate_total_issuance::migrate_total_issuance::(true); // Execute the migration to update total issuance. assert_eq!( SubtensorModule::get_total_issuance(), account_balance + lockcost @@ -185,7 +185,7 @@ fn test_total_issuance_global() { SubtensorModule::get_total_issuance(), account_balance + lockcost - burn_cost ); // Verify the total issuance is reduced to 10000 after burning. - pallet_subtensor::migration::migration5_total_issuance::(true); // Execute the migration to update total issuance. + pallet_subtensor::migrations::migrate_total_issuance::migrate_total_issuance::(true); // Execute the migration to update total issuance. assert_eq!( SubtensorModule::get_total_issuance(), account_balance + lockcost - burn_cost @@ -202,7 +202,7 @@ fn test_total_issuance_global() { SubtensorModule::get_total_issuance(), account_balance + lockcost - burn_cost ); // Same - pallet_subtensor::migration::migration5_total_issuance::(true); // Fix issuance + pallet_subtensor::migrations::migrate_total_issuance::migrate_total_issuance::(true); // Fix issuance assert_eq!( SubtensorModule::get_total_issuance(), account_balance + lockcost - burn_cost + new_stake @@ -222,7 +222,7 @@ fn test_total_issuance_global() { SubtensorModule::get_total_issuance(), account_balance + lockcost - burn_cost + new_stake + emission ); // Verify the total issuance reflects the staked amount and emission value that has been put through the epoch. - pallet_subtensor::migration::migration5_total_issuance::(true); // Test migration does not change amount. + pallet_subtensor::migrations::migrate_total_issuance::migrate_total_issuance::(true); // Test migration does not change amount. assert_eq!( SubtensorModule::get_total_issuance(), account_balance + lockcost - burn_cost + new_stake + emission @@ -244,7 +244,7 @@ fn test_migration_transfer_nets_to_foundation() { // Run the migration to transfer ownership let hex = hex_literal::hex!["feabaafee293d3b76dae304e2f9d885f77d2b17adab9e17e921b321eccd61c77"]; - pallet_subtensor::migration::migrate_transfer_ownership_to_foundation::(hex); + pallet_subtensor::migrations::migrate_transfer_ownership_to_foundation::migrate_transfer_ownership_to_foundation::(hex); log::info!("new owner: {:?}", SubtensorModule::get_subnet_owner(1)); }) @@ -258,7 +258,7 @@ fn test_migration_delete_subnet_3() { assert!(SubtensorModule::if_subnet_exist(3)); // Run the migration to transfer ownership - pallet_subtensor::migration::migrate_delete_subnet_3::(); + pallet_subtensor::migrations::migrate_delete_subnet_3::migrate_delete_subnet_3::(); assert!(!SubtensorModule::if_subnet_exist(3)); }) @@ -272,7 +272,7 @@ fn test_migration_delete_subnet_21() { assert!(SubtensorModule::if_subnet_exist(21)); // Run the migration to transfer ownership - pallet_subtensor::migration::migrate_delete_subnet_21::(); + pallet_subtensor::migrations::migrate_delete_subnet_21::migrate_delete_subnet_21::(); assert!(!SubtensorModule::if_subnet_exist(21)); }) @@ -288,7 +288,7 @@ fn test_migrate_fix_total_coldkey_stake() { Stake::::insert(U256::from(1), U256::from(0), 10000); Stake::::insert(U256::from(2), U256::from(0), 10000); Stake::::insert(U256::from(3), U256::from(0), 10000); - pallet_subtensor::migration::do_migrate_fix_total_coldkey_stake::(); + pallet_subtensor::migrations::migrate_fix_total_coldkey_stake::do_migrate_fix_total_coldkey_stake::(); assert_eq!(TotalColdkeyStake::::get(coldkey), 30000); }) } @@ -303,7 +303,7 @@ fn test_migrate_fix_total_coldkey_stake_value_already_in_total() { Stake::::insert(U256::from(1), U256::from(0), 10000); Stake::::insert(U256::from(2), U256::from(0), 10000); Stake::::insert(U256::from(3), U256::from(0), 10000); - pallet_subtensor::migration::do_migrate_fix_total_coldkey_stake::(); + pallet_subtensor::migrations::migrate_fix_total_coldkey_stake::do_migrate_fix_total_coldkey_stake::(); assert_eq!(TotalColdkeyStake::::get(coldkey), 30000); }) } @@ -317,7 +317,7 @@ fn test_migrate_fix_total_coldkey_stake_no_entry() { Stake::::insert(U256::from(1), U256::from(0), 10000); Stake::::insert(U256::from(2), U256::from(0), 10000); Stake::::insert(U256::from(3), U256::from(0), 10000); - pallet_subtensor::migration::do_migrate_fix_total_coldkey_stake::(); + pallet_subtensor::migrations::migrate_fix_total_coldkey_stake::do_migrate_fix_total_coldkey_stake::(); assert_eq!(TotalColdkeyStake::::get(coldkey), 30000); }) } @@ -329,7 +329,7 @@ fn test_migrate_fix_total_coldkey_stake_no_entry_in_hotkeys() { let coldkey = U256::from(0); TotalColdkeyStake::::insert(coldkey, 100000000); StakingHotkeys::::insert(coldkey, vec![U256::from(1), U256::from(2), U256::from(3)]); - pallet_subtensor::migration::do_migrate_fix_total_coldkey_stake::(); + pallet_subtensor::migrations::migrate_fix_total_coldkey_stake::do_migrate_fix_total_coldkey_stake::(); assert_eq!(TotalColdkeyStake::::get(coldkey), 0); }) } @@ -343,7 +343,7 @@ fn test_migrate_fix_total_coldkey_stake_one_hotkey_stake_missing() { StakingHotkeys::::insert(coldkey, vec![U256::from(1), U256::from(2), U256::from(3)]); Stake::::insert(U256::from(1), U256::from(0), 10000); Stake::::insert(U256::from(2), U256::from(0), 10000); - pallet_subtensor::migration::do_migrate_fix_total_coldkey_stake::(); + pallet_subtensor::migrations::migrate_fix_total_coldkey_stake::do_migrate_fix_total_coldkey_stake::(); assert_eq!(TotalColdkeyStake::::get(coldkey), 20000); }) } diff --git a/pallets/subtensor/tests/mock.rs b/pallets/subtensor/tests/mock.rs index fc784f46f2..71e1d593b2 100644 --- a/pallets/subtensor/tests/mock.rs +++ b/pallets/subtensor/tests/mock.rs @@ -168,7 +168,6 @@ parameter_types! { pub const InitialAlphaHigh: u16 = 58982; // Represents 0.9 as per the production default pub const InitialAlphaLow: u16 = 45875; // Represents 0.7 as per the production default pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn - pub const SubtensorInitialBaseDifficulty: u64 = 10_000; // Base difficulty } // Configure collective pallet for council @@ -379,7 +378,6 @@ impl pallet_subtensor::Config for Test { type AlphaHigh = InitialAlphaHigh; type AlphaLow = InitialAlphaLow; type LiquidAlphaOn = InitialLiquidAlphaOn; - type InitialBaseDifficulty = SubtensorInitialBaseDifficulty; } impl pallet_utility::Config for Test { diff --git a/pallets/subtensor/tests/root.rs b/pallets/subtensor/tests/root.rs index 7c66226702..d4e8448a11 100644 --- a/pallets/subtensor/tests/root.rs +++ b/pallets/subtensor/tests/root.rs @@ -4,7 +4,7 @@ use crate::mock::*; use frame_support::{assert_err, assert_ok}; use frame_system::Config; use frame_system::{EventRecord, Phase}; -use pallet_subtensor::migration; +use pallet_subtensor::migrations; use pallet_subtensor::Error; use sp_core::{Get, H256, U256}; @@ -22,7 +22,7 @@ fn record(event: RuntimeEvent) -> EventRecord { #[test] fn test_root_register_network_exist() { new_test_ext(1).execute_with(|| { - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); let hotkey_account_id: U256 = U256::from(1); let coldkey_account_id = U256::from(667); assert_ok!(SubtensorModule::root_register( @@ -63,7 +63,7 @@ fn test_set_weights_not_root_error() { #[test] fn test_root_register_normal_on_root_fails() { new_test_ext(1).execute_with(|| { - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); // Test fails because normal registrations are not allowed // on the root network. let root_netuid: u16 = 0; @@ -107,7 +107,7 @@ fn test_root_register_normal_on_root_fails() { #[test] fn test_root_register_stake_based_pruning_works() { new_test_ext(1).execute_with(|| { - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); // Add two networks. let root_netuid: u16 = 0; let other_netuid: u16 = 1; @@ -196,7 +196,7 @@ fn test_root_register_stake_based_pruning_works() { fn test_root_set_weights() { new_test_ext(1).execute_with(|| { System::set_block_number(0); - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); let n: usize = 10; let root_netuid: u16 = 0; @@ -338,7 +338,7 @@ fn test_root_set_weights() { fn test_root_set_weights_out_of_order_netuids() { new_test_ext(1).execute_with(|| { System::set_block_number(0); - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); let n: usize = 10; let root_netuid: u16 = 0; @@ -458,7 +458,7 @@ fn test_root_set_weights_out_of_order_netuids() { fn test_root_subnet_creation_deletion() { new_test_ext(1).execute_with(|| { System::set_block_number(0); - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); // Owner of subnets. let owner: U256 = U256::from(0); @@ -538,7 +538,7 @@ fn test_root_subnet_creation_deletion() { fn test_network_pruning() { new_test_ext(1).execute_with(|| { System::set_block_number(0); - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); assert_eq!(SubtensorModule::get_total_issuance(), 0); @@ -630,7 +630,7 @@ fn test_network_pruning() { #[test] fn test_network_prune_results() { new_test_ext(1).execute_with(|| { - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); SubtensorModule::set_network_immunity_period(3); SubtensorModule::set_network_min_lock(0); @@ -671,7 +671,7 @@ fn test_network_prune_results() { #[test] fn test_weights_after_network_pruning() { new_test_ext(1).execute_with(|| { - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); assert_eq!(SubtensorModule::get_total_issuance(), 0); diff --git a/pallets/subtensor/tests/senate.rs b/pallets/subtensor/tests/senate.rs index bcec1a63af..e1f33db5e1 100644 --- a/pallets/subtensor/tests/senate.rs +++ b/pallets/subtensor/tests/senate.rs @@ -15,7 +15,7 @@ use sp_runtime::{ use frame_system::pallet_prelude::*; use frame_system::Config; use pallet_collective::Event as CollectiveEvent; -use pallet_subtensor::migration; +use pallet_subtensor::migrations; use pallet_subtensor::Error; pub fn new_test_ext() -> sp_io::TestExternalities { @@ -57,7 +57,7 @@ fn record(event: RuntimeEvent) -> EventRecord { #[test] fn test_senate_join_works() { new_test_ext().execute_with(|| { - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); let netuid: u16 = 1; let tempo: u16 = 13; @@ -125,7 +125,7 @@ fn test_senate_join_works() { #[test] fn test_senate_vote_works() { new_test_ext().execute_with(|| { - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); let netuid: u16 = 1; let tempo: u16 = 13; @@ -233,7 +233,7 @@ fn test_senate_vote_works() { #[test] fn test_senate_vote_not_member() { new_test_ext().execute_with(|| { - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); let netuid: u16 = 1; let tempo: u16 = 13; @@ -294,7 +294,7 @@ fn test_senate_vote_not_member() { #[test] fn test_senate_leave_works() { new_test_ext().execute_with(|| { - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); let netuid: u16 = 1; let tempo: u16 = 13; @@ -362,7 +362,7 @@ fn test_senate_leave_works() { #[test] fn test_senate_leave_vote_removal() { new_test_ext().execute_with(|| { - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); let netuid: u16 = 1; let tempo: u16 = 13; @@ -501,7 +501,7 @@ fn test_senate_leave_vote_removal() { #[test] fn test_senate_not_leave_when_stake_removed() { new_test_ext().execute_with(|| { - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); let netuid: u16 = 1; let tempo: u16 = 13; @@ -582,7 +582,7 @@ fn test_senate_not_leave_when_stake_removed() { fn test_senate_join_current_delegate() { // Test that a current delegate can join the senate new_test_ext().execute_with(|| { - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); let netuid: u16 = 1; let tempo: u16 = 13; @@ -656,7 +656,7 @@ fn test_senate_join_current_delegate() { fn test_adjust_senate_events() { // Test the events emitted after adjusting the senate successfully new_test_ext().execute_with(|| { - migration::migrate_create_root_network::(); + migrations::migrate_create_root_network::migrate_create_root_network::(); let netuid: u16 = 1; let tempo: u16 = 13; diff --git a/pallets/subtensor/tests/staking.rs b/pallets/subtensor/tests/staking.rs index 5db439e5b7..a923a70103 100644 --- a/pallets/subtensor/tests/staking.rs +++ b/pallets/subtensor/tests/staking.rs @@ -1,21 +1,14 @@ #![allow(clippy::unwrap_used)] #![allow(clippy::arithmetic_side_effects)] -use frame_support::pallet_prelude::{ - InvalidTransaction, TransactionValidity, TransactionValidityError, -}; -use frame_support::traits::{OnFinalize, OnIdle, OnInitialize}; -use frame_support::weights::Weight; use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; use frame_system::Config; mod mock; use frame_support::dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}; use frame_support::sp_runtime::DispatchError; use mock::*; -use pallet_balances::Call as BalancesCall; use pallet_subtensor::*; use sp_core::{H256, U256}; -use sp_runtime::traits::SignedExtension; /*********************************************************** staking::add_stake() tests @@ -3136,1067 +3129,6 @@ fn test_rate_limits_enforced_on_increase_take() { }); } -// Helper function to set up a test environment -fn setup_test_environment() -> (AccountId, AccountId, AccountId) { - let current_coldkey = U256::from(1); - let hotkey = U256::from(2); - let new_coldkey = U256::from(3); - // Register the neuron to a new network - let netuid = 1; - add_network(netuid, 0, 0); - - // Register the hotkey and associate it with the current coldkey - register_ok_neuron(1, hotkey, current_coldkey, 0); - - // Add some balance to the hotkey - SubtensorModule::add_balance_to_coldkey_account(¤t_coldkey, 1000); - - // Stake some amount - assert_ok!(SubtensorModule::add_stake( - RuntimeOrigin::signed(current_coldkey), - hotkey, - 500 - )); - - (current_coldkey, hotkey, new_coldkey) -} - -/// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test staking -- test_arbitrated_coldkey_swap_success --exact --nocapture -#[test] -fn test_arbitrated_coldkey_swap_success() { - new_test_ext(1).execute_with(|| { - let (current_coldkey, hotkey, new_coldkey) = setup_test_environment(); - - let current_block = SubtensorModule::get_current_block_as_u64(); - let (work, nonce) = generate_valid_pow( - ¤t_coldkey, - current_block, - U256::from(BaseDifficulty::::get()), - ); - SubtensorModule::add_balance_to_coldkey_account( - ¤t_coldkey, - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, - ); - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - ¤t_coldkey.clone(), - &new_coldkey, - work.to_fixed_bytes().to_vec(), - current_block, - nonce - )); - - // Check that ColdkeySwapDestinations is populated correctly - assert_eq!( - pallet_subtensor::ColdkeySwapDestinations::::get(current_coldkey), - vec![new_coldkey] - ); - - // Check that drain block is set correctly - let drain_block: u64 = 7200 * 3 + 1; - - log::info!( - "ColdkeysToSwapAtBlock before scheduling: {:?}", - pallet_subtensor::ColdkeysToSwapAtBlock::::get(drain_block) - ); - - assert_eq!( - pallet_subtensor::ColdkeysToSwapAtBlock::::get(drain_block), - vec![current_coldkey] - ); - log::info!("Drain block set correctly: {:?}", drain_block); - log::info!( - "Drain block {:?}", - pallet_subtensor::ColdkeysToSwapAtBlock::::get(drain_block) - ); - - // Make 5400 blocks pass - run_to_block(drain_block); - - // Run unstaking - SubtensorModule::swap_coldkeys_this_block(&BlockWeights::get().max_block).unwrap(); - log::info!( - "Arbitrated coldkeys for block: {:?}", - SubtensorModule::get_current_block_as_u64() - ); - - // Check the hotkey stake. - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey), 500); - - // Get the owner of the hotkey now new key. - assert_eq!( - SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey), - new_coldkey - ); - - // Check that the balance has been transferred to the new coldkey - assert_eq!( - SubtensorModule::get_coldkey_balance(&new_coldkey), - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP + 500 - ); // The new key as the 500 - }); -} - -/// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test staking -- test_arbitrated_coldkey_swap_same_coldkey --exact --nocapture -#[test] -fn test_arbitrated_coldkey_swap_same_coldkey() { - new_test_ext(1).execute_with(|| { - let (current_coldkey, _hotkey, _) = setup_test_environment(); - - let current_block = SubtensorModule::get_current_block_as_u64(); - let (work, nonce) = generate_valid_pow( - ¤t_coldkey, - current_block, - U256::from(BaseDifficulty::::get()), - ); - - assert_noop!( - SubtensorModule::do_schedule_coldkey_swap( - ¤t_coldkey.clone(), - ¤t_coldkey, - work.to_fixed_bytes().to_vec(), - current_block, - nonce - ), - Error::::SameColdkey - ); - }); -} - -/// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test staking -- test_arbitrated_coldkey_swap_no_balance --exact --nocapture -#[test] -fn test_arbitrated_coldkey_swap_no_balance() { - new_test_ext(1).execute_with(|| { - // Create accounts manually - let current_coldkey: AccountId = U256::from(1); - let hotkey: AccountId = U256::from(2); - let new_coldkey: AccountId = U256::from(3); - - add_network(1, 0, 0); - - // Register the hotkey and associate it with the current coldkey - register_ok_neuron(1, hotkey, current_coldkey, 0); - - // Print initial balances - log::info!( - "Initial current_coldkey balance: {:?}", - Balances::total_balance(¤t_coldkey) - ); - log::info!( - "Initial hotkey balance: {:?}", - Balances::total_balance(&hotkey) - ); - log::info!( - "Initial new_coldkey balance: {:?}", - Balances::total_balance(&new_coldkey) - ); - - // Ensure there's no balance in any of the accounts - assert_eq!(Balances::total_balance(¤t_coldkey), 0); - assert_eq!(Balances::total_balance(&hotkey), 0); - assert_eq!(Balances::total_balance(&new_coldkey), 0); - - // Generate valid PoW - let current_block = SubtensorModule::get_current_block_as_u64(); - let (work, nonce) = generate_valid_pow( - ¤t_coldkey, - current_block, - U256::from(BaseDifficulty::::get()), - ); - - // Try to schedule coldkey swap - let result = SubtensorModule::do_schedule_coldkey_swap( - ¤t_coldkey.clone(), - &new_coldkey, - work.to_fixed_bytes().to_vec(), - current_block, - nonce, - ); - - // Print the result - log::info!("Result of arbitrated_coldkey_swap: {:?}", result); - - // Verify that the operation failed due to insufficient balance - assert_noop!( - result, - Error::::InsufficientBalanceToPerformColdkeySwap - ); - - // Print final balances - log::info!( - "Final current_coldkey balance: {:?}", - Balances::total_balance(¤t_coldkey) - ); - log::info!( - "Final hotkey balance: {:?}", - Balances::total_balance(&hotkey) - ); - log::info!( - "Final new_coldkey balance: {:?}", - Balances::total_balance(&new_coldkey) - ); - - // Verify that no balance was transferred - assert_eq!(Balances::total_balance(¤t_coldkey), 0); - assert_eq!(Balances::total_balance(&hotkey), 0); - assert_eq!(Balances::total_balance(&new_coldkey), 0); - }); -} - -// To run this test, use the following command: -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test staking -- test_arbitrated_coldkey_swap_with_no_stake --exact --nocapture -#[test] -fn test_arbitrated_coldkey_swap_with_no_stake() { - new_test_ext(1).execute_with(|| { - // Create accounts manually - let current_coldkey: AccountId = U256::from(1); - let hotkey: AccountId = U256::from(2); - let new_coldkey: AccountId = U256::from(3); - - add_network(1, 0, 0); - - // Register the hotkey and associate it with the current coldkey - register_ok_neuron(1, hotkey, current_coldkey, 0); - - // Add balance to the current coldkey without staking - Balances::make_free_balance_be(¤t_coldkey, MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP); - - // Print initial balances - log::info!( - "Initial current_coldkey balance: {:?}", - Balances::total_balance(¤t_coldkey) - ); - log::info!( - "Initial hotkey balance: {:?}", - Balances::total_balance(&hotkey) - ); - log::info!( - "Initial new_coldkey balance: {:?}", - Balances::total_balance(&new_coldkey) - ); - - // Ensure initial balances are correct - assert_eq!( - Balances::total_balance(¤t_coldkey), - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP - ); - assert_eq!(Balances::total_balance(&hotkey), 0); - assert_eq!(Balances::total_balance(&new_coldkey), 0); - - let current_block = SubtensorModule::get_current_block_as_u64(); - let (work, nonce) = generate_valid_pow( - ¤t_coldkey, - current_block, - U256::from(BaseDifficulty::::get()), - ); - - // Schedule coldkey swap - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - ¤t_coldkey.clone(), - &new_coldkey, - work.to_fixed_bytes().to_vec(), - current_block, - nonce - )); - - // Make 5400 blocks pass, simulating on_idle for each block - let drain_block: u64 = 7200 * 3 + 1; - for _ in 0..drain_block { - next_block(); - SubtensorModule::on_idle(System::block_number(), Weight::MAX); - } - - // Print final balances - log::info!( - "Final current_coldkey balance: {:?}", - Balances::total_balance(¤t_coldkey) - ); - log::info!( - "Final hotkey balance: {:?}", - Balances::total_balance(&hotkey) - ); - log::info!( - "Final new_coldkey balance: {:?}", - Balances::total_balance(&new_coldkey) - ); - - // Check that the balance has been transferred to the new coldkey - assert_eq!( - Balances::total_balance(&new_coldkey), - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP - ); - assert_eq!(Balances::total_balance(¤t_coldkey), 0); - }); -} - -// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test staking -- test_arbitrated_coldkey_swap_with_multiple_stakes --exact --nocapture -#[test] -fn test_arbitrated_coldkey_swap_with_multiple_stakes() { - new_test_ext(1).execute_with(|| { - let (current_coldkey, hotkey, new_coldkey) = setup_test_environment(); - - SubtensorModule::set_target_stakes_per_interval(10); - SubtensorModule::add_balance_to_coldkey_account( - ¤t_coldkey, - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, - ); - - // Add more stake - assert_ok!(SubtensorModule::add_stake( - RuntimeOrigin::signed(current_coldkey), - hotkey, - 300 - )); - - let current_block = SubtensorModule::get_current_block_as_u64(); - let (work, nonce) = generate_valid_pow( - ¤t_coldkey, - current_block, - U256::from(BaseDifficulty::::get()), - ); - - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - ¤t_coldkey.clone(), - &new_coldkey, - work.to_fixed_bytes().to_vec(), - current_block, - nonce - )); - - // Make 5400 blocks pass, simulating on_idle for each block - let drain_block: u64 = 7200 * 3 + 1; - for _ in 0..drain_block { - next_block(); - SubtensorModule::on_idle(System::block_number(), Weight::MAX); - } - - // Check that all stake has been removed - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey), 800); - - // Owner has changed - assert_eq!( - SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey), - new_coldkey - ); - - // Check that the full balance has been transferred to the new coldkey - assert_eq!( - SubtensorModule::get_coldkey_balance(&new_coldkey), - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP + 200 - ); - - // Check that the full balance has been transferred to the new coldkey - assert_eq!(SubtensorModule::get_coldkey_balance(¤t_coldkey), 0); - }); -} -// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test staking -- test_arbitrated_coldkey_swap_multiple_arbitrations --exact --nocapture -#[test] -fn test_arbitrated_coldkey_swap_multiple_arbitrations() { - new_test_ext(1).execute_with(|| { - // Set a very low base difficulty for testing - BaseDifficulty::::put(1); - - // Create coldkey with three choices. - let coldkey: AccountId = U256::from(1); - let new_coldkey1: AccountId = U256::from(2); - let new_coldkey2: AccountId = U256::from(3); - let new_coldkey3: AccountId = U256::from(4); - let hotkey: AccountId = U256::from(5); - - // Setup network state. - add_network(1, 0, 0); - SubtensorModule::add_balance_to_coldkey_account( - &coldkey, - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, - ); - ArbitrationPeriod::::put(5); // Set arbitration period to 5 blocks - register_ok_neuron(1, hotkey, coldkey, 0); - - let current_block = SubtensorModule::get_current_block_as_u64(); - - // Generate valid PoW for each swap attempt - let (work1, nonce1) = generate_valid_pow(&coldkey, current_block, U256::from(1)); - let (work2, nonce2) = generate_valid_pow(&coldkey, current_block, U256::from(2)); - let (work3, nonce3) = generate_valid_pow(&coldkey, current_block, U256::from(4)); - - // Schedule three swaps - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - &coldkey.clone(), - &new_coldkey1, - work1.to_fixed_bytes().to_vec(), - current_block, - nonce1 - )); - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - &coldkey.clone(), - &new_coldkey2, - work2.to_fixed_bytes().to_vec(), - current_block, - nonce2 - )); - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - &coldkey.clone(), - &new_coldkey3, - work3.to_fixed_bytes().to_vec(), - current_block, - nonce3 - )); - - // All three keys are added in swap destinations. - assert_eq!( - pallet_subtensor::ColdkeySwapDestinations::::get(coldkey), - vec![new_coldkey1, new_coldkey2, new_coldkey3] - ); - - // Simulate the passage of blocks and on_idle calls - for i in 0..(7200 * 3 + 1) { - next_block(); - SubtensorModule::on_idle(System::block_number(), Weight::MAX); - - log::info!( - "Block {}: Coldkey in arbitration: {}, Swap destinations: {:?}", - i + 1, - SubtensorModule::coldkey_in_arbitration(&coldkey), - pallet_subtensor::ColdkeySwapDestinations::::get(coldkey) - ); - } - - // Check that the swap destinations remain unchanged due to multiple (>2) swap calls - assert_eq!( - pallet_subtensor::ColdkeySwapDestinations::::get(coldkey), - vec![new_coldkey1, new_coldkey2, new_coldkey3], - "ColdkeySwapDestinations should remain unchanged with more than two swap calls" - ); - - // Key remains in arbitration due to multiple (>2) swap calls - assert!( - SubtensorModule::coldkey_in_arbitration(&coldkey), - "Coldkey should remain in arbitration with more than two swap calls" - ); - - // Check that no balance has been transferred - assert_eq!( - SubtensorModule::get_coldkey_balance(&coldkey), - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, - "Original coldkey balance should remain unchanged" - ); - assert_eq!( - SubtensorModule::get_coldkey_balance(&new_coldkey1), - 0, - "New coldkey1 should not receive any balance" - ); - assert_eq!( - SubtensorModule::get_coldkey_balance(&new_coldkey2), - 0, - "New coldkey2 should not receive any balance" - ); - assert_eq!( - SubtensorModule::get_coldkey_balance(&new_coldkey3), - 0, - "New coldkey3 should not receive any balance" - ); - }); -} - -// TODO: Verify that we never want more than 2 destinations for a coldkey -#[test] -fn test_arbitrated_coldkey_swap_existing_destination() { - new_test_ext(1).execute_with(|| { - let (current_coldkey, _hotkey, new_coldkey) = setup_test_environment(); - let another_coldkey = U256::from(4); - let third_coldkey = U256::from(5); - - let current_block = SubtensorModule::get_current_block_as_u64(); - - SubtensorModule::add_balance_to_coldkey_account( - ¤t_coldkey, - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, - ); - - // First swap attempt (0 existing destinations) - let difficulty1 = SubtensorModule::calculate_pow_difficulty(0); - let (work1, nonce1) = generate_valid_pow(¤t_coldkey, current_block, difficulty1); - - // Schedule a swap to new_coldkey - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - ¤t_coldkey, - &new_coldkey, - work1.to_fixed_bytes().to_vec(), - current_block, - nonce1 - )); - - // Second swap attempt (1 existing destination) - let difficulty2 = SubtensorModule::calculate_pow_difficulty(1); - let (work2, nonce2) = generate_valid_pow(¤t_coldkey, current_block, difficulty2); - - // Attempt to schedule a swap to the same new_coldkey again - assert_noop!( - SubtensorModule::do_schedule_coldkey_swap( - ¤t_coldkey.clone(), - &new_coldkey, - work2.to_fixed_bytes().to_vec(), - current_block, - nonce2 - ), - Error::::DuplicateColdkey - ); - - // Schedule a swap to another_coldkey (still 1 existing destination) - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - ¤t_coldkey.clone(), - &another_coldkey, - work2.to_fixed_bytes().to_vec(), - current_block, - nonce2 - )); - - // Third swap attempt (2 existing destinations) - let difficulty3 = SubtensorModule::calculate_pow_difficulty(2); - let (work3, nonce3) = generate_valid_pow(¤t_coldkey, current_block, difficulty3); - - // Attempt to schedule a third swap - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - ¤t_coldkey.clone(), - &third_coldkey, - work3.to_fixed_bytes().to_vec(), - current_block, - nonce3 - )); - }); -} - -#[test] -fn test_arbitration_period_extension() { - new_test_ext(1).execute_with(|| { - let (current_coldkey, _hotkey, new_coldkey) = setup_test_environment(); - let another_coldkey = U256::from(4); - - let current_block = SubtensorModule::get_current_block_as_u64(); - let (work1, nonce1) = generate_valid_pow( - ¤t_coldkey, - current_block, - U256::from(BaseDifficulty::::get()), - ); - let (work2, nonce2) = - generate_valid_pow(¤t_coldkey, current_block, U256::from(20_000_000u64)); - SubtensorModule::add_balance_to_coldkey_account( - ¤t_coldkey, - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, - ); - - // Schedule a swap to new_coldkey - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - ¤t_coldkey.clone(), - &new_coldkey, - work1.to_fixed_bytes().to_vec(), - current_block, - nonce1 - )); - - // Schedule a swap to another_coldkey - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - ¤t_coldkey.clone(), - &another_coldkey, - work2.to_fixed_bytes().to_vec(), - current_block, - nonce2 - )); - - // Check that the arbitration period is extended - let arbitration_block = - SubtensorModule::get_current_block_as_u64() + ArbitrationPeriod::::get(); - assert_eq!( - pallet_subtensor::ColdkeyArbitrationBlock::::get(current_coldkey), - arbitration_block - ); - }); -} - -#[test] -fn test_concurrent_arbitrated_coldkey_swaps() { - new_test_ext(1).execute_with(|| { - // Manually create accounts - let coldkey1: AccountId = U256::from(1); - let hotkey1: AccountId = U256::from(2); - let new_coldkey1: AccountId = U256::from(3); - - let coldkey2: AccountId = U256::from(4); - let hotkey2: AccountId = U256::from(5); - let new_coldkey2: AccountId = U256::from(6); - - // Add networks - let netuid1: u16 = 1; - let netuid2: u16 = 2; - add_network(netuid1, 13, 0); - add_network(netuid2, 13, 0); - - // Register neurons in different networks - register_ok_neuron(netuid1, hotkey1, coldkey1, 0); - register_ok_neuron(netuid2, hotkey2, coldkey2, 0); - - // Add balance to coldkeys - SubtensorModule::add_balance_to_coldkey_account( - &coldkey1, - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, - ); - SubtensorModule::add_balance_to_coldkey_account( - &coldkey2, - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, - ); - - let current_block = SubtensorModule::get_current_block_as_u64(); - let (work1, nonce1) = generate_valid_pow( - &coldkey1, - current_block, - U256::from(BaseDifficulty::::get()), - ); - let (work2, nonce2) = generate_valid_pow( - &coldkey2, - current_block, - U256::from(BaseDifficulty::::get()), - ); - // Schedule swaps for both coldkeys - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - &coldkey1.clone(), - &new_coldkey1, - work1.to_fixed_bytes().to_vec(), - current_block, - nonce1 - )); - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - &coldkey2.clone(), - &new_coldkey2, - work2.to_fixed_bytes().to_vec(), - current_block, - nonce2 - )); - // Make 5400 blocks pass - let drain_block: u64 = 7200 * 3 + 1; - run_to_block(drain_block); - - // Run arbitration - SubtensorModule::swap_coldkeys_this_block(&BlockWeights::get().max_block).unwrap(); - - // Check that the balances have been transferred correctly - assert_eq!( - SubtensorModule::get_coldkey_balance(&new_coldkey1), - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP - ); - assert_eq!( - SubtensorModule::get_coldkey_balance(&new_coldkey2), - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP - ); - }); -} - -// #[test] -// fn test_get_remaining_arbitration_period() { -// new_test_ext(1).execute_with(|| { -// let coldkey_account_id = U256::from(12345); // arbitrary coldkey -// let new_coldkey_account_id = U256::from(54321); // arbitrary new coldkey - -// let current_block = SubtensorModule::get_current_block_as_u64(); -// let (work, nonce) = generate_valid_pow( -// &coldkey_account_id, -// current_block, -// U256::from(BaseDifficulty::::get()), -// ); - -// SubtensorModule::add_balance_to_coldkey_account( -// &coldkey_account_id, -// MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, -// ); - -// // Schedule a coldkey swap to set the arbitration block -// assert_ok!(SubtensorModule::do_schedule_coldkey_swap( -// &coldkey_account_id.clone(), -// &new_coldkey_account_id, -// work.to_fixed_bytes().to_vec(), -// current_block, -// nonce -// )); - -// // Get the current block number and arbitration period -// let current_block: u64 = SubtensorModule::get_current_block_as_u64(); -// let arbitration_period: u64 = ArbitrationPeriod::::get(); -// log::info!("arbitration_period: {:?}", arbitration_period); -// let arbitration_block: u64 = current_block + arbitration_period; -// log::info!("arbitration_block: {:?}", arbitration_block); - -// // Check if the remaining arbitration period is correct -// let remaining_period = -// SubtensorModule::get_remaining_arbitration_period(&coldkey_account_id); -// assert_eq!(remaining_period, arbitration_period); - -// // Move the current block forward and check again -// step_block(50); -// let remaining_period = -// SubtensorModule::get_remaining_arbitration_period(&coldkey_account_id); -// assert_eq!(remaining_period, arbitration_period - 50); - -// // Move the current block beyond the arbitration block and check again -// step_block((arbitration_period as u16) - 50 + 1); -// let remaining_period = -// SubtensorModule::get_remaining_arbitration_period(&coldkey_account_id); -// assert_eq!(remaining_period, 0); -// }); -// } - -#[test] -fn test_transfer_coldkey_in_arbitration() { - new_test_ext(1).execute_with(|| { - let coldkey_account_id = U256::from(1); - let recipient_account_id = U256::from(2); - let new_coldkey_account_id = U256::from(3); - - // Add balance to coldkey - SubtensorModule::add_balance_to_coldkey_account( - &coldkey_account_id, - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, - ); - - let current_block = SubtensorModule::get_current_block_as_u64(); - let (work, nonce) = generate_valid_pow( - &coldkey_account_id, - current_block, - U256::from(BaseDifficulty::::get()), - ); - - // Schedule a coldkey swap to put the coldkey in arbitration - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - &coldkey_account_id.clone(), - &new_coldkey_account_id, - work.to_fixed_bytes().to_vec(), - current_block, - nonce - )); - - // Try to transfer balance - let call = RuntimeCall::Balances(BalancesCall::transfer_allow_death { - dest: recipient_account_id, - value: 1000, - }); - - assert_eq!( - validate_transaction(&coldkey_account_id, &call), - Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) - ); - }); -} - -#[test] -fn test_add_stake_coldkey_in_arbitration() { - new_test_ext(1).execute_with(|| { - let hotkey_account_id = U256::from(561337); - let coldkey_account_id = U256::from(61337); - let new_coldkey_account_id = U256::from(71337); - let netuid: u16 = 1; - let start_nonce: u64 = 0; - let tempo: u16 = 13; - - add_network(netuid, tempo, 0); - register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); - SubtensorModule::add_balance_to_coldkey_account( - &coldkey_account_id, - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, - ); - - let current_block = SubtensorModule::get_current_block_as_u64(); - let (work, nonce) = generate_valid_pow( - &coldkey_account_id, - current_block, - U256::from(BaseDifficulty::::get()), - ); - - // Schedule a coldkey swap to put the coldkey in arbitration - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - &coldkey_account_id.clone(), - &new_coldkey_account_id, - work.to_fixed_bytes().to_vec(), - current_block, - nonce - )); - let call = RuntimeCall::SubtensorModule(crate::Call::add_stake { - hotkey: hotkey_account_id, - amount_staked: 1000, - }); - - // This should now be Ok - assert!(validate_transaction(&coldkey_account_id, &call).is_ok()); - }) -} - -#[test] -fn test_remove_stake_coldkey_in_arbitration() { - new_test_ext(1).execute_with(|| { - let hotkey_account_id = U256::from(561337); - let coldkey_account_id = U256::from(61337); - let new_coldkey_account_id = U256::from(71337); - let netuid: u16 = 1; - let start_nonce: u64 = 0; - let tempo: u16 = 13; - - add_network(netuid, tempo, 0); - register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); - SubtensorModule::add_balance_to_coldkey_account( - &coldkey_account_id, - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, - ); - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_account_id, 1000); - - let current_block = SubtensorModule::get_current_block_as_u64(); - let (work, nonce) = generate_valid_pow( - &coldkey_account_id, - current_block, - U256::from(BaseDifficulty::::get()), - ); - - // Schedule a coldkey swap to put the coldkey in arbitration - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - &coldkey_account_id.clone(), - &new_coldkey_account_id, - work.to_fixed_bytes().to_vec(), - current_block, - nonce - )); - - let call = RuntimeCall::SubtensorModule(crate::Call::remove_stake { - hotkey: hotkey_account_id, - amount_unstaked: 500, - }); - - // This should now be Ok - assert!(validate_transaction(&coldkey_account_id, &call).is_ok()); - }); -} - -#[test] -fn test_transfer_coldkey_not_in_arbitration() { - new_test_ext(1).execute_with(|| { - let coldkey_account_id = U256::from(61337); - let recipient_account_id = U256::from(71337); - - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 60000); - - let call = RuntimeCall::Balances(BalancesCall::transfer_allow_death { - dest: recipient_account_id, - value: 1000, - }); - - // This should be Ok - assert!(validate_transaction(&coldkey_account_id, &call).is_ok()); - }); -} - -fn validate_transaction(who: &AccountId, call: &RuntimeCall) -> TransactionValidity { - SubtensorSignedExtension::::new().validate(who, call, &DispatchInfo::default(), 0) -} - -// Helper function to generate valid PoW -fn generate_valid_pow(coldkey: &U256, block_number: u64, difficulty: U256) -> (H256, u64) { - let mut nonce: u64 = 0; - loop { - let work = SubtensorModule::create_seal_hash(block_number, nonce, coldkey); - if SubtensorModule::hash_meets_difficulty(&work, difficulty) { - return (work, nonce); - } - nonce += 1; - } -} - -// Helper function to advance to the next block and run hooks -fn next_block() { - let current_block = System::block_number(); - System::on_finalize(current_block); - System::set_block_number(current_block + 1); - System::on_initialize(System::block_number()); - SubtensorModule::on_initialize(System::block_number()); -} - -// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test staking -- test_coldkey_meets_enough --exact --nocapture -#[test] -fn test_coldkey_meets_enough() { - new_test_ext(1).execute_with(|| { - let coldkey = U256::from(1); - let new_coldkey = U256::from(2); - let hotkey = U256::from(2); - let netuid = 1u16; - add_network(netuid, 13, 0); - register_ok_neuron(netuid, hotkey, coldkey, 0); - let current_block = SubtensorModule::get_current_block_as_u64(); - let (work1, nonce1) = generate_valid_pow( - &coldkey, - current_block, - U256::from(BaseDifficulty::::get()), - ); - assert_err!( - SubtensorModule::do_schedule_coldkey_swap( - &coldkey.clone(), - &new_coldkey, - work1.to_fixed_bytes().to_vec(), - current_block, - nonce1 - ), - Error::::InsufficientBalanceToPerformColdkeySwap - ); - SubtensorModule::add_balance_to_coldkey_account( - &coldkey, - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, - ); - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - &coldkey.clone(), - &new_coldkey, - work1.to_fixed_bytes().to_vec(), - current_block, - nonce1 - )); - }); -} - -#[test] -fn test_comprehensive_coldkey_swap_scenarios() { - new_test_ext(1).execute_with(|| { - // Set arbitration period to 5 blocks - ArbitrationPeriod::::put(5); - - let subnet_owner1 = U256::from(1); - let subnet_owner2 = U256::from(2); - let regular_user = U256::from(3); - let new_coldkey1 = U256::from(4); - let new_coldkey2 = U256::from(5); - let new_coldkey3 = U256::from(6); - let netuid1 = 1; - let netuid2 = 2; - - // Add networks and register subnet owners - add_network(netuid1, 13, 0); - add_network(netuid2, 13, 0); - SubnetOwner::::insert(netuid1, subnet_owner1); - SubnetOwner::::insert(netuid2, subnet_owner2); - - // Add balance to subnet owners and regular user - SubtensorModule::add_balance_to_coldkey_account( - &subnet_owner1, - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, - ); - SubtensorModule::add_balance_to_coldkey_account( - &subnet_owner2, - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, - ); - SubtensorModule::add_balance_to_coldkey_account( - ®ular_user, - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP * 2, - ); - - // Set a very low base difficulty for testing - BaseDifficulty::::put(1); - - let current_block = SubtensorModule::get_current_block_as_u64(); - - // Schedule swaps for subnet owners and regular user - let (work1, nonce1) = generate_valid_pow(&subnet_owner1, current_block, U256::from(BaseDifficulty::::get())); - let (work2, nonce2) = generate_valid_pow(&subnet_owner2, current_block, U256::from(BaseDifficulty::::get())); - let (work3, nonce3) = generate_valid_pow(®ular_user, current_block, U256::from(BaseDifficulty::::get())); - - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - &subnet_owner1, - &new_coldkey1, - work1.to_fixed_bytes().to_vec(), - current_block, - nonce1 - )); - - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - &subnet_owner2, - &new_coldkey2, - work2.to_fixed_bytes().to_vec(), - current_block, - nonce2 - )); - - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - ®ular_user, - &new_coldkey3, - work3.to_fixed_bytes().to_vec(), - current_block, - nonce3 - )); - - // Check if swaps were scheduled correctly - assert_eq!( - ColdkeySwapDestinations::::get(subnet_owner1), - vec![new_coldkey1] - ); - assert_eq!( - ColdkeySwapDestinations::::get(subnet_owner2), - vec![new_coldkey2] - ); - assert_eq!( - ColdkeySwapDestinations::::get(regular_user), - vec![new_coldkey3] - ); - - // Run through the arbitration period plus one block - for i in 0..6 { - next_block(); - SubtensorModule::on_idle(System::block_number(), Weight::MAX); - - log::info!( - "Block {}: Coldkey in arbitration: {}, Swap destinations: {:?}", - i + 1, - SubtensorModule::coldkey_in_arbitration(&subnet_owner1), - ColdkeySwapDestinations::::get(subnet_owner1) - ); - - // Test edge case: try to schedule another swap during arbitration - if i == 2 { - let (work4, nonce4) = generate_valid_pow( - &subnet_owner1, - current_block + i as u64, - U256::from(4) * U256::from(BaseDifficulty::::get()), - ); - assert_ok!(SubtensorModule::do_schedule_coldkey_swap( - &subnet_owner1, - &new_coldkey2, - work4.to_fixed_bytes().to_vec(), - current_block + i as u64, - nonce4 - )); - // This should add new_coldkey2 to subnet_owner1's destinations - assert_eq!( - ColdkeySwapDestinations::::get(subnet_owner1), - vec![new_coldkey1, new_coldkey2] - ); - } - } - - // Check if swaps have been executed - log::info!( - "After arbitration period - Swap destinations for subnet_owner1: {:?}", - ColdkeySwapDestinations::::get(subnet_owner1) - ); - assert_eq!( - ColdkeySwapDestinations::::get(subnet_owner1), - vec![new_coldkey1, new_coldkey2], - "ColdkeySwapDestinations for subnet_owner1 should still contain two destinations after arbitration period" - ); - assert!(ColdkeySwapDestinations::::get(subnet_owner2).is_empty()); - assert!(ColdkeySwapDestinations::::get(regular_user).is_empty()); - - // Verify that subnet ownerships have NOT been transferred for subnet_owner1 - assert_eq!(SubnetOwner::::get(netuid1), subnet_owner1); - // But subnet_owner2's ownership should have been transferred - assert_eq!(SubnetOwner::::get(netuid2), new_coldkey2); - - // Verify regular user's balance has been transferred - assert_eq!( - SubtensorModule::get_coldkey_balance(&new_coldkey3), - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP * 2 - ); - assert_eq!(SubtensorModule::get_coldkey_balance(®ular_user), 0); - }); -} - #[test] fn test_get_total_delegated_stake_after_unstaking() { new_test_ext(1).execute_with(|| { @@ -4451,271 +3383,4 @@ fn test_get_total_delegated_stake_exclude_owner_stake() { expected_delegated_stake, actual_delegated_stake ); }); -} - -#[test] -fn test_do_schedule_coldkey_swap_subnet_owner_skips_min_balance() { - new_test_ext(1).execute_with(|| { - let netuid = 1u16; - let subnet_owner = U256::from(1); - let new_coldkey = U256::from(2); - let hotkey = U256::from(3); - let current_block = 0u64; - - add_network(netuid, 0, 0); - register_ok_neuron(netuid, hotkey, subnet_owner, 0); - - // Make subnet_owner the owner of the subnet - SubnetOwner::::insert(netuid, subnet_owner); - - // Ensure subnet_owner has less than minimum balance - assert!( - SubtensorModule::get_coldkey_balance(&subnet_owner) - < MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP - ); - - // Generate valid PoW - let difficulty = U256::from(4) * U256::from(BaseDifficulty::::get()); - let (work, nonce) = generate_valid_pow(&subnet_owner, current_block, difficulty); - - // Debug prints - println!("Subnet owner: {:?}", subnet_owner); - println!("New coldkey: {:?}", new_coldkey); - println!("Current block: {}", current_block); - println!("Difficulty: {:?}", difficulty); - println!("Work: {:?}", work); - println!("Nonce: {}", nonce); - - // Verify the PoW - let seal = SubtensorModule::create_seal_hash(current_block, nonce, &subnet_owner); - println!("Calculated seal: {:?}", seal); - println!("Work matches seal: {}", work == seal); - println!( - "Seal meets difficulty: {}", - SubtensorModule::hash_meets_difficulty(&seal, difficulty) - ); - - // Attempt to schedule coldkey swap - let result = SubtensorModule::do_schedule_coldkey_swap( - &subnet_owner, - &new_coldkey, - work.to_fixed_bytes().to_vec(), - current_block, - nonce, - ); - - // Print the result - println!("Swap result: {:?}", result); - - assert_ok!(result); - - // Verify that the swap was scheduled - assert_eq!( - ColdkeySwapDestinations::::get(subnet_owner), - vec![new_coldkey] - ); - }); -} - -#[test] -fn test_do_schedule_coldkey_swap_delegate_with_500_tao_skips_min_balance() { - new_test_ext(1).execute_with(|| { - let netuid = 1u16; - let delegate_coldkey = U256::from(1); - let delegate_hotkey = U256::from(2); - let new_coldkey = U256::from(3); - let delegator = U256::from(4); - let current_block = 0u64; - - add_network(netuid, 0, 0); - register_ok_neuron(netuid, delegate_hotkey, delegate_coldkey, 0); - - // Make delegate a delegate - assert_ok!(SubtensorModule::become_delegate( - RuntimeOrigin::signed(delegate_coldkey), - delegate_hotkey - )); - - // Add more than 500 TAO of stake to the delegate's hotkey - let stake_amount = 501_000_000_000; // 501 TAO in RAO - SubtensorModule::add_balance_to_coldkey_account(&delegator, stake_amount); - assert_ok!(SubtensorModule::add_stake( - RuntimeOrigin::signed(delegator), - delegate_hotkey, - stake_amount - )); - - // Debug prints - println!( - "Delegator balance: {}", - SubtensorModule::get_coldkey_balance(&delegator) - ); - println!( - "Delegate coldkey balance: {}", - SubtensorModule::get_coldkey_balance(&delegate_coldkey) - ); - println!("Stake amount: {}", stake_amount); - println!( - "Delegate hotkey total stake: {}", - SubtensorModule::get_total_stake_for_hotkey(&delegate_hotkey) - ); - println!( - "Delegate coldkey delegated stake: {}", - SubtensorModule::get_total_delegated_stake(&delegate_coldkey) - ); - - // Ensure delegate's coldkey has less than minimum balance - assert!( - SubtensorModule::get_coldkey_balance(&delegate_coldkey) - < MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, - "Delegate coldkey balance should be less than minimum required" - ); - - // Ensure the delegate's hotkey has more than 500 TAO delegated - assert!( - SubtensorModule::get_total_delegated_stake(&delegate_coldkey) >= 500_000_000_000, - "Delegate hotkey should have at least 500 TAO delegated" - ); - - // Generate valid PoW - let (work, nonce) = generate_valid_pow( - &delegate_coldkey, - current_block, - U256::from(4) * U256::from(BaseDifficulty::::get()), - ); - - // Debug prints - println!("Work: {:?}", work); - println!("Nonce: {}", nonce); - - // Attempt to schedule coldkey swap - let result = SubtensorModule::do_schedule_coldkey_swap( - &delegate_coldkey, - &new_coldkey, - work.to_fixed_bytes().to_vec(), - current_block, - nonce, - ); - - // Print the result - println!("Swap result: {:?}", result); - - assert_ok!(result); - - // Verify that the swap was scheduled - assert_eq!( - ColdkeySwapDestinations::::get(delegate_coldkey), - vec![new_coldkey] - ); - - // Additional debug prints after swap - println!( - "Coldkey swap destinations: {:?}", - ColdkeySwapDestinations::::get(delegate_coldkey) - ); - println!( - "Is coldkey in arbitration: {}", - SubtensorModule::coldkey_in_arbitration(&delegate_coldkey) - ); - }); -} - -#[test] -fn test_do_schedule_coldkey_swap_regular_user_fails_min_balance() { - new_test_ext(1).execute_with(|| { - let netuid = 1u16; - let regular_user = U256::from(1); - let new_coldkey = U256::from(2); - let hotkey = U256::from(3); - let current_block = 0u64; - let nonce = 0u64; - - add_network(netuid, 0, 0); - register_ok_neuron(netuid, hotkey, regular_user, 0); - - // Ensure regular_user has less than minimum balance - assert!( - SubtensorModule::get_coldkey_balance(®ular_user) - < MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP - ); - - let (work, _) = generate_valid_pow( - ®ular_user, - current_block, - U256::from(4) * U256::from(BaseDifficulty::::get()), - ); - - // Attempt to schedule coldkey swap - assert_noop!( - SubtensorModule::do_schedule_coldkey_swap( - ®ular_user, - &new_coldkey, - work.to_fixed_bytes().to_vec(), - current_block, - nonce - ), - Error::::InsufficientBalanceToPerformColdkeySwap - ); - - // Verify that the swap was not scheduled - assert!(ColdkeySwapDestinations::::get(regular_user).is_empty()); - }); -} - -#[test] -fn test_do_schedule_coldkey_swap_regular_user_passes_min_balance() { - new_test_ext(1).execute_with(|| { - let netuid = 1u16; - let regular_user = U256::from(1); - let new_coldkey = U256::from(2); - let hotkey = U256::from(3); - let current_block = 0u64; - - add_network(netuid, 0, 0); - register_ok_neuron(netuid, hotkey, regular_user, 0); - - // Ensure regular_user has more than minimum balance - SubtensorModule::add_balance_to_coldkey_account( - ®ular_user, - MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP + 1, - ); - assert!( - SubtensorModule::get_coldkey_balance(®ular_user) - > MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP - ); - - // Generate valid PoW - let (work, nonce) = generate_valid_pow( - ®ular_user, - current_block, - U256::from(4) * U256::from(BaseDifficulty::::get()), - ); - - // Debug prints - println!("Regular user: {:?}", regular_user); - println!("New coldkey: {:?}", new_coldkey); - println!("Current block: {}", current_block); - println!("Work: {:?}", work); - println!("Nonce: {}", nonce); - - // Attempt to schedule coldkey swap - let result = SubtensorModule::do_schedule_coldkey_swap( - ®ular_user, - &new_coldkey, - work.to_fixed_bytes().to_vec(), - current_block, - nonce, - ); - - // Print the result - println!("Swap result: {:?}", result); - - assert_ok!(result); - - // Verify that the swap was scheduled - assert_eq!( - ColdkeySwapDestinations::::get(regular_user), - vec![new_coldkey] - ); - }); -} +} \ No newline at end of file diff --git a/pallets/subtensor/tests/swap.rs b/pallets/subtensor/tests/swap.rs index 21c3a983af..1d05b1c512 100644 --- a/pallets/subtensor/tests/swap.rs +++ b/pallets/subtensor/tests/swap.rs @@ -4,9 +4,9 @@ use codec::Encode; use frame_support::weights::Weight; use frame_support::{assert_err, assert_noop, assert_ok}; use frame_system::{Config, RawOrigin}; +use pallet_subtensor::*; mod mock; use mock::*; -use pallet_subtensor::*; use sp_core::U256; #[test] @@ -65,31 +65,31 @@ fn test_do_swap_hotkey_ok() { // UIDs for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight) { assert_eq!( - Uids::::get(netuid, new_hotkey), - Uids::::get(netuid, old_hotkey) + pallet_subtensor::Uids::::get(netuid, new_hotkey), + pallet_subtensor::Uids::::get(netuid, old_hotkey) ); } // Prometheus for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight) { assert_eq!( - Prometheus::::get(netuid, new_hotkey), - Prometheus::::get(netuid, old_hotkey) + pallet_subtensor::Prometheus::::get(netuid, new_hotkey), + pallet_subtensor::Prometheus::::get(netuid, old_hotkey) ); } // LoadedEmission for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight) { assert_eq!( - LoadedEmission::::get(netuid).unwrap(), - LoadedEmission::::get(netuid).unwrap() + pallet_subtensor::LoadedEmission::::get(netuid).unwrap(), + pallet_subtensor::LoadedEmission::::get(netuid).unwrap() ); } // IsNetworkMember for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight) { - assert!(IsNetworkMember::::contains_key(new_hotkey, netuid)); - assert!(!IsNetworkMember::::contains_key(old_hotkey, netuid)); + assert!(pallet_subtensor::IsNetworkMember::::contains_key(new_hotkey, netuid)); + assert!(!pallet_subtensor::IsNetworkMember::::contains_key(old_hotkey, netuid)); } // Owner @@ -97,34 +97,34 @@ fn test_do_swap_hotkey_ok() { // TotalHotkeyStake assert_eq!( - TotalHotkeyStake::::get(new_hotkey), - TotalHotkeyStake::::get(old_hotkey) + pallet_subtensor::TotalHotkeyStake::::get(new_hotkey), + pallet_subtensor::TotalHotkeyStake::::get(old_hotkey) ); // Delegates assert_eq!( - Delegates::::get(new_hotkey), - Delegates::::get(old_hotkey) + pallet_subtensor::Delegates::::get(new_hotkey), + pallet_subtensor::Delegates::::get(old_hotkey) ); // LastTxBlock assert_eq!( - LastTxBlock::::get(new_hotkey), - LastTxBlock::::get(old_hotkey) + pallet_subtensor::LastTxBlock::::get(new_hotkey), + pallet_subtensor::LastTxBlock::::get(old_hotkey) ); // Axons for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight) { assert_eq!( - Axons::::get(netuid, new_hotkey), - Axons::::get(netuid, old_hotkey) + pallet_subtensor::Axons::::get(netuid, new_hotkey), + pallet_subtensor::Axons::::get(netuid, old_hotkey) ); } // TotalHotkeyColdkeyStakesThisInterval assert_eq!( - TotalHotkeyColdkeyStakesThisInterval::::get(new_hotkey, coldkey), - TotalHotkeyColdkeyStakesThisInterval::::get(old_hotkey, coldkey) + pallet_subtensor::TotalHotkeyColdkeyStakesThisInterval::::get(new_hotkey, coldkey), + pallet_subtensor::TotalHotkeyColdkeyStakesThisInterval::::get(old_hotkey, coldkey) ); }); } @@ -226,8 +226,8 @@ fn test_do_swap_hotkey_ok_robust() { // Verify raw storage maps // Stake - for (coldkey, stake_amount) in Stake::::iter_prefix(old_hotkeys[i]) { - assert_eq!(Stake::::get(new_hotkeys[i], coldkey), stake_amount); + for (coldkey, stake_amount) in pallet_subtensor::Stake::::iter_prefix(old_hotkeys[i]) { + assert_eq!(pallet_subtensor::Stake::::get(new_hotkeys[i], coldkey), stake_amount); } let mut weight = Weight::zero(); @@ -236,8 +236,8 @@ fn test_do_swap_hotkey_ok_robust() { SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight) { assert_eq!( - Uids::::get(netuid, new_hotkeys[i]), - Uids::::get(netuid, old_hotkeys[i]) + pallet_subtensor::Uids::::get(netuid, new_hotkeys[i]), + pallet_subtensor::Uids::::get(netuid, old_hotkeys[i]) ); } @@ -246,8 +246,8 @@ fn test_do_swap_hotkey_ok_robust() { SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight) { assert_eq!( - Prometheus::::get(netuid, new_hotkeys[i]), - Prometheus::::get(netuid, old_hotkeys[i]) + pallet_subtensor::Prometheus::::get(netuid, new_hotkeys[i]), + pallet_subtensor::Prometheus::::get(netuid, old_hotkeys[i]) ); } @@ -256,8 +256,8 @@ fn test_do_swap_hotkey_ok_robust() { SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight) { assert_eq!( - LoadedEmission::::get(netuid).unwrap(), - LoadedEmission::::get(netuid).unwrap() + pallet_subtensor::LoadedEmission::::get(netuid).unwrap(), + pallet_subtensor::LoadedEmission::::get(netuid).unwrap() ); } @@ -265,23 +265,23 @@ fn test_do_swap_hotkey_ok_robust() { for netuid in SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight) { - assert!(IsNetworkMember::::contains_key( + assert!(pallet_subtensor::IsNetworkMember::::contains_key( new_hotkeys[i], netuid )); - assert!(!IsNetworkMember::::contains_key( + assert!(!pallet_subtensor::IsNetworkMember::::contains_key( old_hotkeys[i], netuid )); } // Owner - assert_eq!(Owner::::get(new_hotkeys[i]), coldkeys[i]); + assert_eq!(pallet_subtensor::Owner::::get(new_hotkeys[i]), coldkeys[i]); // Keys - for (uid, hotkey) in Keys::::iter_prefix(netuid) { + for (uid, hotkey) in pallet_subtensor::Keys::::iter_prefix(netuid) { if hotkey == old_hotkeys[i] { - assert_eq!(Keys::::get(netuid, uid), new_hotkeys[i]); + assert_eq!(pallet_subtensor::Keys::::get(netuid, uid), new_hotkeys[i]); } } @@ -730,7 +730,7 @@ fn test_swap_axons_success() { // Initialize Axons for old_hotkey for netuid in &netuid_is_member { - Axons::::insert(netuid, old_hotkey, axon_info.clone()); + pallet_subtensor::Axons::::insert(netuid, old_hotkey, axon_info.clone()); } // Perform the swap @@ -738,8 +738,8 @@ fn test_swap_axons_success() { // Verify the swap for netuid in &netuid_is_member { - assert_eq!(Axons::::get(netuid, new_hotkey).unwrap(), axon_info); - assert!(!Axons::::contains_key(netuid, old_hotkey)); + assert_eq!(pallet_subtensor::Axons::::get(netuid, new_hotkey).unwrap(), axon_info); + assert!(!pallet_subtensor::Axons::::contains_key(netuid, old_hotkey)); } }); } @@ -764,7 +764,7 @@ fn test_swap_axons_weight_update() { // Initialize Axons for old_hotkey for netuid in &netuid_is_member { - Axons::::insert(netuid, old_hotkey, axon_info.clone()); + pallet_subtensor::Axons::::insert(netuid, old_hotkey, axon_info.clone()); } // Perform the swap @@ -789,7 +789,7 @@ fn test_swap_keys_success() { // Initialize Keys for old_hotkey for netuid in &netuid_is_member { log::info!("Inserting old_hotkey:{:?} netuid:{:?}", old_hotkey, netuid); - Keys::::insert(*netuid, uid, old_hotkey); + pallet_subtensor::Keys::::insert(*netuid, uid, old_hotkey); } // Perform the swap @@ -803,7 +803,7 @@ fn test_swap_keys_success() { uid, new_hotkey ); - assert_eq!(Keys::::get(netuid, uid), new_hotkey); + assert_eq!(pallet_subtensor::Keys::::get(netuid, uid), new_hotkey); } }); } @@ -819,7 +819,7 @@ fn test_swap_keys_weight_update() { // Initialize Keys for old_hotkey for netuid in &netuid_is_member { - Keys::::insert(*netuid, uid, old_hotkey); + pallet_subtensor::Keys::::insert(*netuid, uid, old_hotkey); } // Perform the swap @@ -843,7 +843,7 @@ fn test_swap_loaded_emission_success() { // Initialize LoadedEmission for old_hotkey for netuid in &netuid_is_member { - LoadedEmission::::mutate(netuid, |emission_exists| { + pallet_subtensor::LoadedEmission::::mutate(netuid, |emission_exists| { if let Some(emissions) = emission_exists { emissions.push((old_hotkey, se, ve)); } else { @@ -862,7 +862,7 @@ fn test_swap_loaded_emission_success() { // Verify the swap for netuid in &netuid_is_member { - let emissions = LoadedEmission::::get(netuid).unwrap(); + let emissions = pallet_subtensor::LoadedEmission::::get(netuid).unwrap(); assert!(emissions.iter().any(|(hk, _, _)| hk == &new_hotkey)); assert!(!emissions.iter().any(|(hk, _, _)| hk == &old_hotkey)); } @@ -882,7 +882,7 @@ fn test_swap_loaded_emission_weight_update() { // Initialize LoadedEmission for old_hotkey for netuid in &netuid_is_member { - LoadedEmission::::mutate(netuid, |emission_exists| { + pallet_subtensor::LoadedEmission::::mutate(netuid, |emission_exists| { if let Some(emissions) = emission_exists { emissions.push((old_hotkey, se, ve)); } else { @@ -916,7 +916,7 @@ fn test_swap_uids_success() { // Initialize Uids for old_hotkey for netuid in &netuid_is_member { - Uids::::insert(netuid, old_hotkey, uid); + pallet_subtensor::Uids::::insert(netuid, old_hotkey, uid); } // Perform the swap @@ -924,8 +924,8 @@ fn test_swap_uids_success() { // Verify the swap for netuid in &netuid_is_member { - assert_eq!(Uids::::get(netuid, new_hotkey).unwrap(), uid); - assert!(!Uids::::contains_key(netuid, old_hotkey)); + assert_eq!(pallet_subtensor::Uids::::get(netuid, new_hotkey).unwrap(), uid); + assert!(!pallet_subtensor::Uids::::contains_key(netuid, old_hotkey)); } }); } @@ -941,7 +941,7 @@ fn test_swap_uids_weight_update() { // Initialize Uids for old_hotkey for netuid in &netuid_is_member { - Uids::::insert(netuid, old_hotkey, uid); + pallet_subtensor::Uids::::insert(netuid, old_hotkey, uid); } // Perform the swap @@ -970,7 +970,7 @@ fn test_swap_prometheus_success() { // Initialize Prometheus for old_hotkey for netuid in &netuid_is_member { - Prometheus::::insert(netuid, old_hotkey, prometheus_info.clone()); + pallet_subtensor::Prometheus::::insert(netuid, old_hotkey, prometheus_info.clone()); } // Perform the swap @@ -979,10 +979,10 @@ fn test_swap_prometheus_success() { // Verify the swap for netuid in &netuid_is_member { assert_eq!( - Prometheus::::get(netuid, new_hotkey).unwrap(), + pallet_subtensor::Prometheus::::get(netuid, new_hotkey).unwrap(), prometheus_info ); - assert!(!Prometheus::::contains_key(netuid, old_hotkey)); + assert!(!pallet_subtensor::Prometheus::::contains_key(netuid, old_hotkey)); } }); } @@ -1004,7 +1004,7 @@ fn test_swap_prometheus_weight_update() { // Initialize Prometheus for old_hotkey for netuid in &netuid_is_member { - Prometheus::::insert(netuid, old_hotkey, prometheus_info.clone()); + pallet_subtensor::Prometheus::::insert(netuid, old_hotkey, prometheus_info.clone()); } // Perform the swap diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index a4abd124ff..0ed3cd10f0 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -880,7 +880,6 @@ parameter_types! { pub const InitialAlphaHigh: u16 = 58982; // Represents 0.9 as per the production default pub const InitialAlphaLow: u16 = 45875; // Represents 0.7 as per the production default pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn - pub const SubtensorInitialBaseDifficulty: u64 = 10_000_000; // Base difficulty } impl pallet_subtensor::Config for Runtime { @@ -936,7 +935,6 @@ impl pallet_subtensor::Config for Runtime { type AlphaHigh = InitialAlphaHigh; type AlphaLow = InitialAlphaLow; type LiquidAlphaOn = InitialLiquidAlphaOn; - type InitialBaseDifficulty = SubtensorInitialBaseDifficulty; } use sp_runtime::BoundedVec; From 0f8d50b19b27a0664eef46526b6e3d5d7905b317 Mon Sep 17 00:00:00 2001 From: const Date: Mon, 15 Jul 2024 14:10:33 -0500 Subject: [PATCH 03/16] pre fix --- pallets/subtensor/src/lib.rs | 2 +- pallets/subtensor/src/migration.rs | 661 -------------- pallets/subtensor/src/staking.rs | 851 ------------------ pallets/subtensor/src/staking/add_stake.rs | 125 +++ .../subtensor/src/staking/become_delegate.rs | 96 ++ .../subtensor/src/staking/decrease_take.rs | 82 ++ pallets/subtensor/src/staking/helpers.rs | 397 ++++++++ .../subtensor/src/staking/increase_take.rs | 99 ++ pallets/subtensor/src/staking/mod.rs | 7 + pallets/subtensor/src/staking/remove_stake.rs | 120 +++ pallets/subtensor/src/swap/swap_coldkey.rs | 2 +- 11 files changed, 928 insertions(+), 1514 deletions(-) delete mode 100644 pallets/subtensor/src/migration.rs delete mode 100644 pallets/subtensor/src/staking.rs create mode 100644 pallets/subtensor/src/staking/add_stake.rs create mode 100644 pallets/subtensor/src/staking/become_delegate.rs create mode 100644 pallets/subtensor/src/staking/decrease_take.rs create mode 100644 pallets/subtensor/src/staking/helpers.rs create mode 100644 pallets/subtensor/src/staking/increase_take.rs create mode 100644 pallets/subtensor/src/staking/mod.rs create mode 100644 pallets/subtensor/src/staking/remove_stake.rs diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 329cebcdcf..7596029e05 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -39,13 +39,13 @@ mod rpc_info; mod coinbase; pub mod epoch; pub mod swap; +pub mod staking; mod macros; use macros::{events, errors, dispatches, genesis, hooks, config}; mod registration; mod root; mod serving; -mod staking; mod uids; mod utils; mod weights; diff --git a/pallets/subtensor/src/migration.rs b/pallets/subtensor/src/migration.rs deleted file mode 100644 index cd99f01280..0000000000 --- a/pallets/subtensor/src/migration.rs +++ /dev/null @@ -1,661 +0,0 @@ -use super::*; -use frame_support::traits::DefensiveResult; -use frame_support::{ - pallet_prelude::{Identity, OptionQuery}, - storage_alias, - traits::{fungible::Inspect as _, Get, GetStorageVersion, StorageVersion}, - weights::Weight, -}; -use log::info; -use sp_runtime::Saturating; -use sp_std::vec::Vec; - -// TODO (camfairchild): TEST MIGRATION - -const LOG_TARGET: &str = "loadedemissionmigration"; - -pub mod deprecated_loaded_emission_format { - use super::*; - - type AccountIdOf = ::AccountId; - - #[storage_alias] - pub(super) type LoadedEmission = - StorageMap, Identity, u16, Vec<(AccountIdOf, u64)>, OptionQuery>; -} - -/// Migrates and fixes the total coldkey stake. -/// -/// This function iterates through all staking hotkeys, calculates the total stake for each coldkey, -/// and updates the `TotalColdkeyStake` storage accordingly. The migration is only performed if the -/// on-chain storage version is 6. -/// -/// # Returns -/// The weight of the migration process. -pub fn do_migrate_fix_total_coldkey_stake() -> Weight { - // Initialize the weight with one read operation. - let mut weight = T::DbWeight::get().reads(1); - - // Iterate through all staking hotkeys. - for (coldkey, hotkey_vec) in StakingHotkeys::::iter() { - // Init the zero value. - let mut coldkey_stake_sum: u64 = 0; - weight = weight.saturating_add(T::DbWeight::get().reads(1)); - - // Calculate the total stake for the current coldkey. - for hotkey in hotkey_vec { - // Cant fail on retrieval. - coldkey_stake_sum = - coldkey_stake_sum.saturating_add(Stake::::get(hotkey, coldkey.clone())); - weight = weight.saturating_add(T::DbWeight::get().reads(1)); - } - // Update the `TotalColdkeyStake` storage with the calculated stake sum. - // Cant fail on insert. - TotalColdkeyStake::::insert(coldkey.clone(), coldkey_stake_sum); - weight = weight.saturating_add(T::DbWeight::get().writes(1)); - } - weight -} -// Public migrate function to be called by Lib.rs on upgrade. -pub fn migrate_fix_total_coldkey_stake() -> Weight { - let current_storage_version: u16 = 7; - let next_storage_version: u16 = 8; - - // Initialize the weight with one read operation. - let mut weight = T::DbWeight::get().reads(1); - - // Grab the current on-chain storage version. - // Cant fail on retrieval. - let onchain_version = Pallet::::on_chain_storage_version(); - - // Only run this migration on storage version 6. - if onchain_version == current_storage_version { - weight = weight.saturating_add(do_migrate_fix_total_coldkey_stake::()); - // Cant fail on insert. - StorageVersion::new(next_storage_version).put::>(); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } - - // Return the migration weight. - weight -} - -/// Performs migration to update the total issuance based on the sum of stakes and total balances. -/// This migration is applicable only if the current storage version is 5, after which it updates the storage version to 6. -/// -/// # Returns -/// Weight of the migration process. -pub fn migrate_total_issuance(test: bool) -> Weight { - let mut weight = T::DbWeight::get().reads(1); // Initialize migration weight - - // Execute migration if the current storage version is 5 - if Pallet::::on_chain_storage_version() == StorageVersion::new(5) || test { - // Calculate the sum of all stake values - let stake_sum: u64 = Stake::::iter().fold(0, |accumulator, (_, _, stake_value)| { - accumulator.saturating_add(stake_value) - }); - weight = weight - .saturating_add(T::DbWeight::get().reads_writes(Stake::::iter().count() as u64, 0)); - - // Calculate the sum of all stake values - let locked_sum: u64 = SubnetLocked::::iter() - .fold(0, |accumulator, (_, locked_value)| { - accumulator.saturating_add(locked_value) - }); - weight = weight.saturating_add( - T::DbWeight::get().reads_writes(SubnetLocked::::iter().count() as u64, 0), - ); - - // Retrieve the total balance sum - let total_balance = T::Currency::total_issuance(); - match TryInto::::try_into(total_balance) { - Ok(total_balance_sum) => { - weight = weight.saturating_add(T::DbWeight::get().reads(1)); - - // Compute the total issuance value - let total_issuance_value: u64 = stake_sum - .saturating_add(total_balance_sum) - .saturating_add(locked_sum); - - // Update the total issuance in storage - TotalIssuance::::put(total_issuance_value); - - // Update the storage version to 6 - StorageVersion::new(6).put::>(); - weight = weight.saturating_add(T::DbWeight::get().writes(1)); - } - Err(_) => { - log::error!("Failed to convert total balance to u64, bailing"); - } - } - } - - weight // Return the computed weight of the migration process -} - -pub fn migrate_transfer_ownership_to_foundation(coldkey: [u8; 32]) -> Weight { - let new_storage_version = 3; - - // Setup migration weight - let mut weight = T::DbWeight::get().reads(1); - - // Grab current version - let onchain_version = Pallet::::on_chain_storage_version(); - - // Only runs if we haven't already updated version past above new_storage_version. - if onchain_version < new_storage_version { - info!(target: LOG_TARGET_1, ">>> Migrating subnet 1 and 11 to foundation control {:?}", onchain_version); - - // We have to decode this using a byte slice as we don't have crypto-std - let coldkey_account: ::AccountId = - ::AccountId::decode(&mut &coldkey[..]) - .expect("coldkey is 32-byte array; qed"); - info!("Foundation coldkey: {:?}", coldkey_account); - - let current_block = Pallet::::get_current_block_as_u64(); - weight.saturating_accrue(T::DbWeight::get().reads(1)); - - // Migrate ownership and set creation time as now - SubnetOwner::::insert(1, coldkey_account.clone()); - SubnetOwner::::insert(11, coldkey_account); - - // We are setting the NetworkRegisteredAt storage to a future block to extend the immunity period to 2 weeks - NetworkRegisteredAt::::insert(1, current_block.saturating_add(13 * 7200)); - NetworkRegisteredAt::::insert(11, current_block); - - weight.saturating_accrue(T::DbWeight::get().writes(4)); - - // Update storage version. - StorageVersion::new(new_storage_version).put::>(); // Update to version so we don't run this again. - weight.saturating_accrue(T::DbWeight::get().writes(1)); - - weight - } else { - info!(target: LOG_TARGET_1, "Migration to v3 already done!"); - Weight::zero() - } -} - -pub fn migrate_create_root_network() -> Weight { - // Get the root network uid. - let root_netuid: u16 = 0; - - // Setup migration weight - let mut weight = T::DbWeight::get().reads(1); - - // Check if root network already exists. - if NetworksAdded::::get(root_netuid) { - // Since we read from the database once to determine this - return weight; - } - - // Set the root network as added. - NetworksAdded::::insert(root_netuid, true); - - // Increment the number of total networks. - TotalNetworks::::mutate(|n| n.saturating_inc()); - - // Set the maximum number to the number of senate members. - MaxAllowedUids::::insert(root_netuid, 64); - - // Set the maximum number to the number of validators to all members. - MaxAllowedValidators::::insert(root_netuid, 64); - - // Set the min allowed weights to zero, no weights restrictions. - MinAllowedWeights::::insert(root_netuid, 0); - - // Set the max weight limit to infitiy, no weight restrictions. - MaxWeightsLimit::::insert(root_netuid, u16::MAX); - - // Add default root tempo. - Tempo::::insert(root_netuid, 100); - - // Set the root network as open. - NetworkRegistrationAllowed::::insert(root_netuid, true); - - // Set target registrations for validators as 1 per block. - TargetRegistrationsPerInterval::::insert(root_netuid, 1); - - // Set weight setting rate limit to 1 day - //WeightsSetRateLimit::::insert(root_netuid, 7200); - - // Add our weights for writing to database - weight.saturating_accrue(T::DbWeight::get().writes(8)); - - // Empty senate members entirely, they will be filled by by registrations - // on the subnet. - for hotkey_i in T::SenateMembers::members().iter() { - T::TriumvirateInterface::remove_votes(hotkey_i).defensive_ok(); - T::SenateMembers::remove_member(hotkey_i).defensive_ok(); - - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - } - - weight -} - -pub fn migrate_delete_subnet_3() -> Weight { - let new_storage_version = 5; - - // Setup migration weight - let mut weight = T::DbWeight::get().reads(1); - - // Grab current version - let onchain_version = Pallet::::on_chain_storage_version(); - - // Only runs if we haven't already updated version past above new_storage_version. - if onchain_version < new_storage_version && Pallet::::if_subnet_exist(3) { - info!(target: LOG_TARGET_1, ">>> Removing subnet 3 {:?}", onchain_version); - - let netuid = 3; - - // We do this all manually as we don't want to call code related to giving subnet owner back their locked token cost. - // --- 2. Remove network count. - SubnetworkN::::remove(netuid); - - // --- 3. Remove network modality storage. - NetworkModality::::remove(netuid); - - // --- 4. Remove netuid from added networks. - NetworksAdded::::remove(netuid); - - // --- 6. Decrement the network counter. - TotalNetworks::::mutate(|n| n.saturating_dec()); - - // --- 7. Remove various network-related storages. - NetworkRegisteredAt::::remove(netuid); - - weight.saturating_accrue(T::DbWeight::get().writes(5)); - - // --- 8. Remove incentive mechanism memory. - let _ = Uids::::clear_prefix(netuid, u32::MAX, None); - let _ = Keys::::clear_prefix(netuid, u32::MAX, None); - let _ = Bonds::::clear_prefix(netuid, u32::MAX, None); - let _ = Weights::::clear_prefix(netuid, u32::MAX, None); - - weight.saturating_accrue(T::DbWeight::get().writes(4)); - - // --- 9. Remove various network-related parameters. - Rank::::remove(netuid); - Trust::::remove(netuid); - Active::::remove(netuid); - Emission::::remove(netuid); - Incentive::::remove(netuid); - Consensus::::remove(netuid); - Dividends::::remove(netuid); - PruningScores::::remove(netuid); - LastUpdate::::remove(netuid); - ValidatorPermit::::remove(netuid); - ValidatorTrust::::remove(netuid); - - weight.saturating_accrue(T::DbWeight::get().writes(11)); - - // --- 10. Erase network parameters. - Tempo::::remove(netuid); - Kappa::::remove(netuid); - Difficulty::::remove(netuid); - MaxAllowedUids::::remove(netuid); - ImmunityPeriod::::remove(netuid); - ActivityCutoff::::remove(netuid); - EmissionValues::::remove(netuid); - MaxWeightsLimit::::remove(netuid); - MinAllowedWeights::::remove(netuid); - RegistrationsThisInterval::::remove(netuid); - POWRegistrationsThisInterval::::remove(netuid); - BurnRegistrationsThisInterval::::remove(netuid); - - weight.saturating_accrue(T::DbWeight::get().writes(12)); - - // Update storage version. - StorageVersion::new(new_storage_version).put::>(); // Update version so we don't run this again. - // One write to storage version - weight.saturating_accrue(T::DbWeight::get().writes(1)); - - weight - } else { - info!(target: LOG_TARGET_1, "Migration to v3 already done!"); - Weight::zero() - } -} - -pub fn migrate_delete_subnet_21() -> Weight { - let new_storage_version = 4; - - // Setup migration weight - let mut weight = T::DbWeight::get().reads(1); - - // Grab current version - let onchain_version = Pallet::::on_chain_storage_version(); - - // Only runs if we haven't already updated version past above new_storage_version. - if onchain_version < new_storage_version && Pallet::::if_subnet_exist(21) { - info!(target: LOG_TARGET_1, ">>> Removing subnet 21 {:?}", onchain_version); - - let netuid = 21; - - // We do this all manually as we don't want to call code related to giving subnet owner back their locked token cost. - // --- 2. Remove network count. - SubnetworkN::::remove(netuid); - - // --- 3. Remove network modality storage. - NetworkModality::::remove(netuid); - - // --- 4. Remove netuid from added networks. - NetworksAdded::::remove(netuid); - - // --- 6. Decrement the network counter. - TotalNetworks::::mutate(|n| n.saturating_dec()); - - // --- 7. Remove various network-related storages. - NetworkRegisteredAt::::remove(netuid); - - weight.saturating_accrue(T::DbWeight::get().writes(5)); - - // --- 8. Remove incentive mechanism memory. - let _ = Uids::::clear_prefix(netuid, u32::MAX, None); - let _ = Keys::::clear_prefix(netuid, u32::MAX, None); - let _ = Bonds::::clear_prefix(netuid, u32::MAX, None); - let _ = Weights::::clear_prefix(netuid, u32::MAX, None); - - weight.saturating_accrue(T::DbWeight::get().writes(4)); - - // --- 9. Remove various network-related parameters. - Rank::::remove(netuid); - Trust::::remove(netuid); - Active::::remove(netuid); - Emission::::remove(netuid); - Incentive::::remove(netuid); - Consensus::::remove(netuid); - Dividends::::remove(netuid); - PruningScores::::remove(netuid); - LastUpdate::::remove(netuid); - ValidatorPermit::::remove(netuid); - ValidatorTrust::::remove(netuid); - - weight.saturating_accrue(T::DbWeight::get().writes(11)); - - // --- 10. Erase network parameters. - Tempo::::remove(netuid); - Kappa::::remove(netuid); - Difficulty::::remove(netuid); - MaxAllowedUids::::remove(netuid); - ImmunityPeriod::::remove(netuid); - ActivityCutoff::::remove(netuid); - EmissionValues::::remove(netuid); - MaxWeightsLimit::::remove(netuid); - MinAllowedWeights::::remove(netuid); - RegistrationsThisInterval::::remove(netuid); - POWRegistrationsThisInterval::::remove(netuid); - BurnRegistrationsThisInterval::::remove(netuid); - - weight.saturating_accrue(T::DbWeight::get().writes(12)); - - // Update storage version. - StorageVersion::new(new_storage_version).put::>(); // Update version so we don't run this again. - // One write to storage version - weight.saturating_accrue(T::DbWeight::get().writes(1)); - - weight - } else { - info!(target: LOG_TARGET_1, "Migration to v4 already done!"); - Weight::zero() - } -} - -pub fn migrate_to_v1_separate_emission() -> Weight { - use deprecated_loaded_emission_format as old; - // Check storage version - let mut weight = T::DbWeight::get().reads_writes(1, 0); - - // Grab current version - let onchain_version = Pallet::::on_chain_storage_version(); - - // Only runs if we haven't already updated version to 1. - if onchain_version < 1 { - info!(target: LOG_TARGET, ">>> Updating the LoadedEmission to a new format {:?}", onchain_version); - - // We transform the storage values from the old into the new format. - - // Start by removing any undecodable entries. - let curr_loaded_emission: Vec = old::LoadedEmission::::iter_keys().collect(); - for netuid in curr_loaded_emission { - // Iterates over the netuids - weight.saturating_accrue(T::DbWeight::get().reads(1)); - if old::LoadedEmission::::try_get(netuid).is_err() { - weight.saturating_accrue(T::DbWeight::get().writes(1)); - old::LoadedEmission::::remove(netuid); - log::warn!( - "Was unable to decode old loaded_emisssion for netuid {}", - netuid - ); - } - } - - // Translate the old storage values into the new format. - LoadedEmission::::translate::, u64)>, _>( - |netuid: u16, - netuid_emissions: Vec<(AccountIdOf, u64)>| - -> Option, u64, u64)>> { - info!(target: LOG_TARGET, " Do migration of netuid: {:?}...", netuid); - - // We will assume all loaded emission is validator emissions, - // so this will get distributed over delegatees (nominators), if there are any - // This will NOT effect any servers that are not (also) a delegate validator. - // server_emission will be 0 for any alread loaded emission. - - let mut new_netuid_emissions = Vec::new(); - for (server, validator_emission) in netuid_emissions { - new_netuid_emissions.push((server, 0_u64, validator_emission)); - } - - // One read (old) and write (new) per netuid - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - - Some(new_netuid_emissions) - }, - ); - - // Update storage version. - StorageVersion::new(1).put::>(); // Update to version 2 so we don't run this again. - // One write to storage version - weight.saturating_accrue(T::DbWeight::get().writes(1)); - - weight - } else { - info!(target: LOG_TARGET_1, "Migration to v2 already done!"); - Weight::zero() - } -} - -const LOG_TARGET_1: &str = "fixtotalstakestorage"; - -pub fn migrate_to_v2_fixed_total_stake() -> Weight { - let new_storage_version = 2; - - // Check storage version - let mut weight = T::DbWeight::get().reads(1); - - // Grab current version - let onchain_version = Pallet::::on_chain_storage_version(); - - // Only runs if we haven't already updated version past above new_storage_version. - if onchain_version < new_storage_version { - info!(target: LOG_TARGET_1, ">>> Fixing the TotalStake and TotalColdkeyStake storage {:?}", onchain_version); - - // Stake and TotalHotkeyStake are known to be accurate - // TotalColdkeyStake is known to be inaccurate - // TotalStake is known to be inaccurate - - TotalStake::::put(0); // Set to 0 - weight.saturating_accrue(T::DbWeight::get().writes(1)); - - // We iterate over TotalColdkeyStake keys and set them to 0 - let total_coldkey_stake_keys = TotalColdkeyStake::::iter_keys().collect::>(); - for coldkey in total_coldkey_stake_keys { - weight.saturating_accrue(T::DbWeight::get().reads(1)); - TotalColdkeyStake::::insert(coldkey, 0); // Set to 0 - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } - - // Now we iterate over the entire stake map, and sum each coldkey stake - // We also track TotalStake - for (_, coldkey, stake) in Stake::::iter() { - weight.saturating_accrue(T::DbWeight::get().reads(1)); - // Get the current coldkey stake - let mut total_coldkey_stake = TotalColdkeyStake::::get(coldkey.clone()); - weight.saturating_accrue(T::DbWeight::get().reads(1)); - // Add the stake to the coldkey stake - total_coldkey_stake = total_coldkey_stake.saturating_add(stake); - // Update the coldkey stake - TotalColdkeyStake::::insert(coldkey, total_coldkey_stake); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - - // Get the current total stake - let mut total_stake = TotalStake::::get(); - weight.saturating_accrue(T::DbWeight::get().reads(1)); - // Add the stake to the total stake - total_stake = total_stake.saturating_add(stake); - // Update the total stake - TotalStake::::put(total_stake); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } - - // Now both TotalStake and TotalColdkeyStake are accurate - - // Update storage version. - StorageVersion::new(new_storage_version).put::>(); // Update to version so we don't run this again. - // One write to storage version - weight.saturating_accrue(T::DbWeight::get().writes(1)); - - weight - } else { - info!(target: LOG_TARGET_1, "Migration to v2 already done!"); - Weight::zero() - } -} - -/// Migrate the OwnedHotkeys map to the new storage format -pub fn migrate_populate_owned() -> Weight { - // Setup migration weight - let mut weight = T::DbWeight::get().reads(1); - let migration_name = "Populate OwnedHotkeys map"; - - // Check if this migration is needed (if OwnedHotkeys map is empty) - let migrate = OwnedHotkeys::::iter().next().is_none(); - - // Only runs if the migration is needed - if migrate { - info!(target: LOG_TARGET_1, ">>> Starting Migration: {}", migration_name); - - let mut longest_hotkey_vector: usize = 0; - let mut longest_coldkey: Option = None; - let mut keys_touched: u64 = 0; - let mut storage_reads: u64 = 0; - let mut storage_writes: u64 = 0; - - // Iterate through all Owner entries - Owner::::iter().for_each(|(hotkey, coldkey)| { - storage_reads = storage_reads.saturating_add(1); // Read from Owner storage - let mut hotkeys = OwnedHotkeys::::get(&coldkey); - storage_reads = storage_reads.saturating_add(1); // Read from OwnedHotkeys storage - - // Add the hotkey if it's not already in the vector - if !hotkeys.contains(&hotkey) { - hotkeys.push(hotkey); - keys_touched = keys_touched.saturating_add(1); - - // Update longest hotkey vector info - if longest_hotkey_vector < hotkeys.len() { - longest_hotkey_vector = hotkeys.len(); - longest_coldkey = Some(coldkey.clone()); - } - - // Update the OwnedHotkeys storage - OwnedHotkeys::::insert(&coldkey, hotkeys); - storage_writes = storage_writes.saturating_add(1); // Write to OwnedHotkeys storage - } - - // Accrue weight for reads and writes - weight = weight.saturating_add(T::DbWeight::get().reads_writes(2, 1)); - }); - - // Log migration results - info!( - target: LOG_TARGET_1, - "Migration {} finished. Keys touched: {}, Longest hotkey vector: {}, Storage reads: {}, Storage writes: {}", - migration_name, keys_touched, longest_hotkey_vector, storage_reads, storage_writes - ); - if let Some(c) = longest_coldkey { - info!(target: LOG_TARGET_1, "Longest hotkey vector is controlled by: {:?}", c); - } - - weight - } else { - info!(target: LOG_TARGET_1, "Migration {} already done!", migration_name); - Weight::zero() - } -} - -/// Populate the StakingHotkeys map from Stake map -pub fn migrate_populate_staking_hotkeys() -> Weight { - // Setup migration weight - let mut weight = T::DbWeight::get().reads(1); - let migration_name = "Populate StakingHotkeys map"; - - // Check if this migration is needed (if StakingHotkeys map is empty) - let migrate = StakingHotkeys::::iter().next().is_none(); - - // Only runs if the migration is needed - if migrate { - info!(target: LOG_TARGET_1, ">>> Starting Migration: {}", migration_name); - - let mut longest_hotkey_vector: usize = 0; - let mut longest_coldkey: Option = None; - let mut keys_touched: u64 = 0; - let mut storage_reads: u64 = 0; - let mut storage_writes: u64 = 0; - - // Iterate through all Owner entries - Stake::::iter().for_each(|(hotkey, coldkey, stake)| { - storage_reads = storage_reads.saturating_add(1); // Read from Owner storage - if stake > 0 { - let mut hotkeys = StakingHotkeys::::get(&coldkey); - storage_reads = storage_reads.saturating_add(1); // Read from StakingHotkeys storage - - // Add the hotkey if it's not already in the vector - if !hotkeys.contains(&hotkey) { - hotkeys.push(hotkey); - keys_touched = keys_touched.saturating_add(1); - - // Update longest hotkey vector info - if longest_hotkey_vector < hotkeys.len() { - longest_hotkey_vector = hotkeys.len(); - longest_coldkey = Some(coldkey.clone()); - } - - // Update the StakingHotkeys storage - StakingHotkeys::::insert(&coldkey, hotkeys); - storage_writes = storage_writes.saturating_add(1); // Write to StakingHotkeys storage - } - - // Accrue weight for reads and writes - weight = weight.saturating_add(T::DbWeight::get().reads_writes(2, 1)); - } - }); - - // Log migration results - info!( - target: LOG_TARGET_1, - "Migration {} finished. Keys touched: {}, Longest hotkey vector: {}, Storage reads: {}, Storage writes: {}", - migration_name, keys_touched, longest_hotkey_vector, storage_reads, storage_writes - ); - if let Some(c) = longest_coldkey { - info!(target: LOG_TARGET_1, "Longest hotkey vector is controlled by: {:?}", c); - } - - weight - } else { - info!(target: LOG_TARGET_1, "Migration {} already done!", migration_name); - Weight::zero() - } -} diff --git a/pallets/subtensor/src/staking.rs b/pallets/subtensor/src/staking.rs deleted file mode 100644 index 2707d90ef4..0000000000 --- a/pallets/subtensor/src/staking.rs +++ /dev/null @@ -1,851 +0,0 @@ -use super::*; -use frame_support::{ - storage::IterableStorageDoubleMap, - traits::{ - tokens::{ - fungible::{Balanced as _, Inspect as _, Mutate as _}, - Fortitude, Precision, Preservation, - }, - Imbalance, - }, -}; - -impl Pallet { - /// ---- The implementation for the extrinsic become_delegate: signals that this hotkey allows delegated stake. - /// - /// # Args: - /// * 'origin': (RuntimeOrigin): - /// - The signature of the caller's coldkey. - /// - /// * 'hotkey' (T::AccountId): - /// - The hotkey we are delegating (must be owned by the coldkey.) - /// - /// * 'take' (u16): - /// - The stake proportion that this hotkey takes from delegations. - /// - /// # Event: - /// * DelegateAdded; - /// - On successfully setting a hotkey as a delegate. - /// - /// # Raises: - /// * 'NotRegistered': - /// - The hotkey we are delegating is not registered on the network. - /// - /// * 'NonAssociatedColdKey': - /// - The hotkey we are delegating is not owned by the calling coldket. - /// - /// * 'TxRateLimitExceeded': - /// - Thrown if key has hit transaction rate limit - /// - pub fn do_become_delegate( - origin: T::RuntimeOrigin, - hotkey: T::AccountId, - take: u16, - ) -> dispatch::DispatchResult { - // --- 1. We check the coldkey signuture. - let coldkey = ensure_signed(origin)?; - log::info!( - "do_become_delegate( origin:{:?} hotkey:{:?}, take:{:?} )", - coldkey, - hotkey, - take - ); - - // --- 2. Ensure we are delegating an known key. - // --- 3. Ensure that the coldkey is the owner. - Self::do_take_checks(&coldkey, &hotkey)?; - - // --- 4. Ensure we are not already a delegate (dont allow changing delegate take.) - ensure!( - !Self::hotkey_is_delegate(&hotkey), - Error::::HotKeyAlreadyDelegate - ); - - // --- 5. Ensure we don't exceed tx rate limit - let block: u64 = Self::get_current_block_as_u64(); - ensure!( - !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&coldkey), block), - Error::::DelegateTxRateLimitExceeded - ); - - // --- 5.1 Ensure take is within the min ..= InitialDefaultTake (18%) range - let min_take = MinTake::::get(); - let max_take = MaxTake::::get(); - ensure!(take >= min_take, Error::::DelegateTakeTooLow); - ensure!(take <= max_take, Error::::DelegateTakeTooHigh); - - // --- 6. Delegate the key. - Self::delegate_hotkey(&hotkey, take); - - // Set last block for rate limiting - Self::set_last_tx_block(&coldkey, block); - Self::set_last_tx_block_delegate_take(&coldkey, block); - - // --- 7. Emit the staking event. - log::info!( - "DelegateAdded( coldkey:{:?}, hotkey:{:?}, take:{:?} )", - coldkey, - hotkey, - take - ); - Self::deposit_event(Event::DelegateAdded(coldkey, hotkey, take)); - - // --- 8. Ok and return. - Ok(()) - } - - /// ---- The implementation for the extrinsic decrease_take - /// - /// # Args: - /// * 'origin': (::RuntimeOrigin): - /// - The signature of the caller's coldkey. - /// - /// * 'hotkey' (T::AccountId): - /// - The hotkey we are delegating (must be owned by the coldkey.) - /// - /// * 'take' (u16): - /// - The stake proportion that this hotkey takes from delegations for subnet ID. - /// - /// # Event: - /// * TakeDecreased; - /// - On successfully setting a decreased take for this hotkey. - /// - /// # Raises: - /// * 'NotRegistered': - /// - The hotkey we are delegating is not registered on the network. - /// - /// * 'NonAssociatedColdKey': - /// - The hotkey we are delegating is not owned by the calling coldket. - /// - /// * 'DelegateTakeTooLow': - /// - The delegate is setting a take which is not lower than the previous. - /// - pub fn do_decrease_take( - origin: T::RuntimeOrigin, - hotkey: T::AccountId, - take: u16, - ) -> dispatch::DispatchResult { - // --- 1. We check the coldkey signature. - let coldkey = ensure_signed(origin)?; - log::info!( - "do_decrease_take( origin:{:?} hotkey:{:?}, take:{:?} )", - coldkey, - hotkey, - take - ); - - // --- 2. Ensure we are delegating a known key. - // Ensure that the coldkey is the owner. - Self::do_take_checks(&coldkey, &hotkey)?; - - // --- 3. Ensure we are always strictly decreasing, never increasing take - if let Ok(current_take) = Delegates::::try_get(&hotkey) { - ensure!(take < current_take, Error::::DelegateTakeTooLow); - } - - // --- 3.1 Ensure take is within the min ..= InitialDefaultTake (18%) range - let min_take = MinTake::::get(); - ensure!(take >= min_take, Error::::DelegateTakeTooLow); - - // --- 4. Set the new take value. - Delegates::::insert(hotkey.clone(), take); - - // --- 5. Emit the take value. - log::info!( - "TakeDecreased( coldkey:{:?}, hotkey:{:?}, take:{:?} )", - coldkey, - hotkey, - take - ); - Self::deposit_event(Event::TakeDecreased(coldkey, hotkey, take)); - - // --- 6. Ok and return. - Ok(()) - } - - /// ---- The implementation for the extrinsic increase_take - /// - /// # Args: - /// * 'origin': (::RuntimeOrigin): - /// - The signature of the caller's coldkey. - /// - /// * 'hotkey' (T::AccountId): - /// - The hotkey we are delegating (must be owned by the coldkey.) - /// - /// * 'take' (u16): - /// - The stake proportion that this hotkey takes from delegations for subnet ID. - /// - /// # Event: - /// * TakeIncreased; - /// - On successfully setting a increased take for this hotkey. - /// - /// # Raises: - /// * 'NotRegistered': - /// - The hotkey we are delegating is not registered on the network. - /// - /// * 'NonAssociatedColdKey': - /// - The hotkey we are delegating is not owned by the calling coldket. - /// - /// * 'TxRateLimitExceeded': - /// - Thrown if key has hit transaction rate limit - /// - /// * 'DelegateTakeTooLow': - /// - The delegate is setting a take which is not greater than the previous. - /// - pub fn do_increase_take( - origin: T::RuntimeOrigin, - hotkey: T::AccountId, - take: u16, - ) -> dispatch::DispatchResult { - // --- 1. We check the coldkey signature. - let coldkey = ensure_signed(origin)?; - log::info!( - "do_increase_take( origin:{:?} hotkey:{:?}, take:{:?} )", - coldkey, - hotkey, - take - ); - - // --- 2. Ensure we are delegating a known key. - // Ensure that the coldkey is the owner. - Self::do_take_checks(&coldkey, &hotkey)?; - - // --- 3. Ensure we are strinctly increasing take - if let Ok(current_take) = Delegates::::try_get(&hotkey) { - ensure!(take > current_take, Error::::DelegateTakeTooLow); - } - - // --- 4. Ensure take is within the min ..= InitialDefaultTake (18%) range - let max_take = MaxTake::::get(); - ensure!(take <= max_take, Error::::DelegateTakeTooHigh); - - // --- 5. Enforce the rate limit (independently on do_add_stake rate limits) - let block: u64 = Self::get_current_block_as_u64(); - ensure!( - !Self::exceeds_tx_delegate_take_rate_limit( - Self::get_last_tx_block_delegate_take(&coldkey), - block - ), - Error::::DelegateTxRateLimitExceeded - ); - - // Set last block for rate limiting - Self::set_last_tx_block_delegate_take(&coldkey, block); - - // --- 6. Set the new take value. - Delegates::::insert(hotkey.clone(), take); - - // --- 7. Emit the take value. - log::info!( - "TakeIncreased( coldkey:{:?}, hotkey:{:?}, take:{:?} )", - coldkey, - hotkey, - take - ); - Self::deposit_event(Event::TakeIncreased(coldkey, hotkey, take)); - - // --- 8. Ok and return. - Ok(()) - } - - /// ---- The implementation for the extrinsic add_stake: Adds stake to a hotkey account. - /// - /// # Args: - /// * 'origin': (RuntimeOrigin): - /// - The signature of the caller's coldkey. - /// - /// * 'hotkey' (T::AccountId): - /// - The associated hotkey account. - /// - /// * 'stake_to_be_added' (u64): - /// - The amount of stake to be added to the hotkey staking account. - /// - /// # Event: - /// * StakeAdded; - /// - On the successfully adding stake to a global account. - /// - /// # Raises: - /// * 'NotEnoughBalanceToStake': - /// - Not enough balance on the coldkey to add onto the global account. - /// - /// * 'NonAssociatedColdKey': - /// - The calling coldkey is not associated with this hotkey. - /// - /// * 'BalanceWithdrawalError': - /// - Errors stemming from transaction pallet. - /// - /// * 'TxRateLimitExceeded': - /// - Thrown if key has hit transaction rate limit - /// - pub fn do_add_stake( - origin: T::RuntimeOrigin, - hotkey: T::AccountId, - stake_to_be_added: u64, - ) -> dispatch::DispatchResult { - // We check that the transaction is signed by the caller and retrieve the T::AccountId coldkey information. - let coldkey = ensure_signed(origin)?; - log::info!( - "do_add_stake( origin:{:?} hotkey:{:?}, stake_to_be_added:{:?} )", - coldkey, - hotkey, - stake_to_be_added - ); - - // Ensure the callers coldkey has enough stake to perform the transaction. - ensure!( - Self::can_remove_balance_from_coldkey_account(&coldkey, stake_to_be_added), - Error::::NotEnoughBalanceToStake - ); - - // Ensure that the hotkey account exists this is only possible through registration. - ensure!( - Self::hotkey_account_exists(&hotkey), - Error::::HotKeyAccountNotExists - ); - - // Ensure that the hotkey allows delegation or that the hotkey is owned by the calling coldkey. - ensure!( - Self::hotkey_is_delegate(&hotkey) || Self::coldkey_owns_hotkey(&coldkey, &hotkey), - Error::::HotKeyNotDelegateAndSignerNotOwnHotKey - ); - - // Ensure we don't exceed stake rate limit - let stakes_this_interval = - Self::get_stakes_this_interval_for_coldkey_hotkey(&coldkey, &hotkey); - ensure!( - stakes_this_interval < Self::get_target_stakes_per_interval(), - Error::::StakeRateLimitExceeded - ); - - // If this is a nomination stake, check if total stake after adding will be above - // the minimum required stake. - - // If coldkey is not owner of the hotkey, it's a nomination stake. - if !Self::coldkey_owns_hotkey(&coldkey, &hotkey) { - let total_stake_after_add = - Stake::::get(&hotkey, &coldkey).saturating_add(stake_to_be_added); - - ensure!( - total_stake_after_add >= NominatorMinRequiredStake::::get(), - Error::::NomStakeBelowMinimumThreshold - ); - } - - // Ensure the remove operation from the coldkey is a success. - let actual_amount_to_stake = - Self::remove_balance_from_coldkey_account(&coldkey, stake_to_be_added)?; - - // If we reach here, add the balance to the hotkey. - Self::increase_stake_on_coldkey_hotkey_account(&coldkey, &hotkey, actual_amount_to_stake); - - // Set last block for rate limiting - let block: u64 = Self::get_current_block_as_u64(); - Self::set_last_tx_block(&coldkey, block); - - // Emit the staking event. - Self::set_stakes_this_interval_for_coldkey_hotkey( - &coldkey, - &hotkey, - stakes_this_interval.saturating_add(1), - block, - ); - log::info!( - "StakeAdded( hotkey:{:?}, stake_to_be_added:{:?} )", - hotkey, - actual_amount_to_stake - ); - Self::deposit_event(Event::StakeAdded(hotkey, actual_amount_to_stake)); - - // Ok and return. - Ok(()) - } - - /// ---- The implementation for the extrinsic remove_stake: Removes stake from a hotkey account and adds it onto a coldkey. - /// - /// # Args: - /// * 'origin': (RuntimeOrigin): - /// - The signature of the caller's coldkey. - /// - /// * 'hotkey' (T::AccountId): - /// - The associated hotkey account. - /// - /// * 'stake_to_be_added' (u64): - /// - The amount of stake to be added to the hotkey staking account. - /// - /// # Event: - /// * StakeRemoved; - /// - On the successfully removing stake from the hotkey account. - /// - /// # Raises: - /// * 'NotRegistered': - /// - Thrown if the account we are attempting to unstake from is non existent. - /// - /// * 'NonAssociatedColdKey': - /// - Thrown if the coldkey does not own the hotkey we are unstaking from. - /// - /// * 'NotEnoughStakeToWithdraw': - /// - Thrown if there is not enough stake on the hotkey to withdwraw this amount. - /// - /// * 'TxRateLimitExceeded': - /// - Thrown if key has hit transaction rate limit - /// - pub fn do_remove_stake( - origin: T::RuntimeOrigin, - hotkey: T::AccountId, - stake_to_be_removed: u64, - ) -> dispatch::DispatchResult { - // We check the transaction is signed by the caller and retrieve the T::AccountId coldkey information. - let coldkey = ensure_signed(origin)?; - log::info!( - "do_remove_stake( origin:{:?} hotkey:{:?}, stake_to_be_removed:{:?} )", - coldkey, - hotkey, - stake_to_be_removed - ); - - // Ensure that the hotkey account exists this is only possible through registration. - ensure!( - Self::hotkey_account_exists(&hotkey), - Error::::HotKeyAccountNotExists - ); - - // Ensure that the hotkey allows delegation or that the hotkey is owned by the calling coldkey. - ensure!( - Self::hotkey_is_delegate(&hotkey) || Self::coldkey_owns_hotkey(&coldkey, &hotkey), - Error::::HotKeyNotDelegateAndSignerNotOwnHotKey - ); - - // Ensure that the stake amount to be removed is above zero. - ensure!(stake_to_be_removed > 0, Error::::StakeToWithdrawIsZero); - - // Ensure that the hotkey has enough stake to withdraw. - ensure!( - Self::has_enough_stake(&coldkey, &hotkey, stake_to_be_removed), - Error::::NotEnoughStakeToWithdraw - ); - - // Ensure we don't exceed stake rate limit - let unstakes_this_interval = - Self::get_stakes_this_interval_for_coldkey_hotkey(&coldkey, &hotkey); - ensure!( - unstakes_this_interval < Self::get_target_stakes_per_interval(), - Error::::UnstakeRateLimitExceeded - ); - - // We remove the balance from the hotkey. - Self::decrease_stake_on_coldkey_hotkey_account(&coldkey, &hotkey, stake_to_be_removed); - - // We add the balance to the coldkey. If the above fails we will not credit this coldkey. - Self::add_balance_to_coldkey_account(&coldkey, stake_to_be_removed); - - // If the stake is below the minimum, we clear the nomination from storage. - // This only applies to nominator stakes. - // If the coldkey does not own the hotkey, it's a nominator stake. - let new_stake = Self::get_stake_for_coldkey_and_hotkey(&coldkey, &hotkey); - Self::clear_small_nomination_if_required(&hotkey, &coldkey, new_stake); - - // Set last block for rate limiting - let block: u64 = Self::get_current_block_as_u64(); - Self::set_last_tx_block(&coldkey, block); - - // Emit the unstaking event. - Self::set_stakes_this_interval_for_coldkey_hotkey( - &coldkey, - &hotkey, - unstakes_this_interval.saturating_add(1), - block, - ); - log::info!( - "StakeRemoved( hotkey:{:?}, stake_to_be_removed:{:?} )", - hotkey, - stake_to_be_removed - ); - Self::deposit_event(Event::StakeRemoved(hotkey, stake_to_be_removed)); - - // Done and ok. - Ok(()) - } - - // Returns true if the passed hotkey allow delegative staking. - // - pub fn hotkey_is_delegate(hotkey: &T::AccountId) -> bool { - Delegates::::contains_key(hotkey) - } - - // Sets the hotkey as a delegate with take. - // - pub fn delegate_hotkey(hotkey: &T::AccountId, take: u16) { - Delegates::::insert(hotkey, take); - } - - // Returns the total amount of stake in the staking table. - // - pub fn get_total_stake() -> u64 { - TotalStake::::get() - } - - // Increases the total amount of stake by the passed amount. - // - pub fn increase_total_stake(increment: u64) { - TotalStake::::put(Self::get_total_stake().saturating_add(increment)); - } - - // Decreases the total amount of stake by the passed amount. - // - pub fn decrease_total_stake(decrement: u64) { - TotalStake::::put(Self::get_total_stake().saturating_sub(decrement)); - } - - // Returns the total amount of stake under a hotkey (delegative or otherwise) - // - pub fn get_total_stake_for_hotkey(hotkey: &T::AccountId) -> u64 { - TotalHotkeyStake::::get(hotkey) - } - - // Returns the total amount of stake held by the coldkey (delegative or otherwise) - // - pub fn get_total_stake_for_coldkey(coldkey: &T::AccountId) -> u64 { - TotalColdkeyStake::::get(coldkey) - } - - // Returns the stake under the cold - hot pairing in the staking table. - // - pub fn get_stake_for_coldkey_and_hotkey(coldkey: &T::AccountId, hotkey: &T::AccountId) -> u64 { - Stake::::get(hotkey, coldkey) - } - - // Retrieves the total stakes for a given hotkey (account ID) for the current staking interval. - pub fn get_stakes_this_interval_for_coldkey_hotkey( - coldkey: &T::AccountId, - hotkey: &T::AccountId, - ) -> u64 { - // Retrieve the configured stake interval duration from storage. - let stake_interval = StakeInterval::::get(); - - // Obtain the current block number as an unsigned 64-bit integer. - let current_block = Self::get_current_block_as_u64(); - - // Fetch the total stakes and the last block number when stakes were made for the hotkey. - let (stakes, block_last_staked_at) = - TotalHotkeyColdkeyStakesThisInterval::::get(coldkey, hotkey); - - // Calculate the block number after which the stakes for the hotkey should be reset. - let block_to_reset_after = block_last_staked_at.saturating_add(stake_interval); - - // If the current block number is beyond the reset point, - // it indicates the end of the staking interval for the hotkey. - if block_to_reset_after <= current_block { - // Reset the stakes for this hotkey for the current interval. - Self::set_stakes_this_interval_for_coldkey_hotkey( - coldkey, - hotkey, - 0, - block_last_staked_at, - ); - // Return 0 as the stake amount since we've just reset the stakes. - return 0; - } - - // If the staking interval has not yet ended, return the current stake amount. - stakes - } - - pub fn get_target_stakes_per_interval() -> u64 { - TargetStakesPerInterval::::get() - } - - // Creates a cold - hot pairing account if the hotkey is not already an active account. - // - pub fn create_account_if_non_existent(coldkey: &T::AccountId, hotkey: &T::AccountId) { - if !Self::hotkey_account_exists(hotkey) { - Stake::::insert(hotkey, coldkey, 0); - Owner::::insert(hotkey, coldkey); - - // Update OwnedHotkeys map - let mut hotkeys = OwnedHotkeys::::get(coldkey); - if !hotkeys.contains(hotkey) { - hotkeys.push(hotkey.clone()); - OwnedHotkeys::::insert(coldkey, hotkeys); - } - - // Update StakingHotkeys map - let mut staking_hotkeys = StakingHotkeys::::get(coldkey); - if !staking_hotkeys.contains(hotkey) { - staking_hotkeys.push(hotkey.clone()); - StakingHotkeys::::insert(coldkey, staking_hotkeys); - } - } - } - - // Returns the coldkey owning this hotkey. This function should only be called for active accounts. - // - pub fn get_owning_coldkey_for_hotkey(hotkey: &T::AccountId) -> T::AccountId { - Owner::::get(hotkey) - } - - // Returns the hotkey take - // - pub fn get_hotkey_take(hotkey: &T::AccountId) -> u16 { - Delegates::::get(hotkey) - } - - // Returns true if the hotkey account has been created. - // - pub fn hotkey_account_exists(hotkey: &T::AccountId) -> bool { - Owner::::contains_key(hotkey) - } - - // Return true if the passed coldkey owns the hotkey. - // - pub fn coldkey_owns_hotkey(coldkey: &T::AccountId, hotkey: &T::AccountId) -> bool { - if Self::hotkey_account_exists(hotkey) { - Owner::::get(hotkey) == *coldkey - } else { - false - } - } - - // Returns true if the cold-hot staking account has enough balance to fufil the decrement. - // - pub fn has_enough_stake(coldkey: &T::AccountId, hotkey: &T::AccountId, decrement: u64) -> bool { - Self::get_stake_for_coldkey_and_hotkey(coldkey, hotkey) >= decrement - } - - // Increases the stake on the hotkey account under its owning coldkey. - // - pub fn increase_stake_on_hotkey_account(hotkey: &T::AccountId, increment: u64) { - Self::increase_stake_on_coldkey_hotkey_account( - &Self::get_owning_coldkey_for_hotkey(hotkey), - hotkey, - increment, - ); - } - - // Decreases the stake on the hotkey account under its owning coldkey. - // - pub fn decrease_stake_on_hotkey_account(hotkey: &T::AccountId, decrement: u64) { - Self::decrease_stake_on_coldkey_hotkey_account( - &Self::get_owning_coldkey_for_hotkey(hotkey), - hotkey, - decrement, - ); - } - - // Increases the stake on the cold - hot pairing by increment while also incrementing other counters. - // This function should be called rather than set_stake under account. - // - pub fn increase_stake_on_coldkey_hotkey_account( - coldkey: &T::AccountId, - hotkey: &T::AccountId, - increment: u64, - ) { - TotalColdkeyStake::::insert( - coldkey, - TotalColdkeyStake::::get(coldkey).saturating_add(increment), - ); - TotalHotkeyStake::::insert( - hotkey, - TotalHotkeyStake::::get(hotkey).saturating_add(increment), - ); - Stake::::insert( - hotkey, - coldkey, - Stake::::get(hotkey, coldkey).saturating_add(increment), - ); - TotalStake::::put(TotalStake::::get().saturating_add(increment)); - - // Update StakingHotkeys map - let mut staking_hotkeys = StakingHotkeys::::get(coldkey); - if !staking_hotkeys.contains(hotkey) { - staking_hotkeys.push(hotkey.clone()); - StakingHotkeys::::insert(coldkey, staking_hotkeys); - } - } - - // Decreases the stake on the cold - hot pairing by the decrement while decreasing other counters. - // - pub fn decrease_stake_on_coldkey_hotkey_account( - coldkey: &T::AccountId, - hotkey: &T::AccountId, - decrement: u64, - ) { - TotalColdkeyStake::::mutate(coldkey, |old| *old = old.saturating_sub(decrement)); - TotalHotkeyStake::::insert( - hotkey, - TotalHotkeyStake::::get(hotkey).saturating_sub(decrement), - ); - Stake::::insert( - hotkey, - coldkey, - Stake::::get(hotkey, coldkey).saturating_sub(decrement), - ); - TotalStake::::put(TotalStake::::get().saturating_sub(decrement)); - - // TODO: Tech debt: Remove StakingHotkeys entry if stake goes to 0 - } - - /// Empties the stake associated with a given coldkey-hotkey account pairing. - /// This function retrieves the current stake for the specified coldkey-hotkey pairing, - /// then subtracts this stake amount from both the TotalColdkeyStake and TotalHotkeyStake. - /// It also removes the stake entry for the hotkey-coldkey pairing and adjusts the TotalStake - /// and TotalIssuance by subtracting the removed stake amount. - /// - /// Returns the amount of stake that was removed. - /// - /// # Arguments - /// - /// * `coldkey` - A reference to the AccountId of the coldkey involved in the staking. - /// * `hotkey` - A reference to the AccountId of the hotkey associated with the coldkey. - pub fn empty_stake_on_coldkey_hotkey_account( - coldkey: &T::AccountId, - hotkey: &T::AccountId, - ) -> u64 { - let current_stake: u64 = Stake::::get(hotkey, coldkey); - TotalColdkeyStake::::mutate(coldkey, |old| *old = old.saturating_sub(current_stake)); - TotalHotkeyStake::::mutate(hotkey, |stake| *stake = stake.saturating_sub(current_stake)); - Stake::::remove(hotkey, coldkey); - TotalStake::::mutate(|stake| *stake = stake.saturating_sub(current_stake)); - TotalIssuance::::mutate(|issuance| *issuance = issuance.saturating_sub(current_stake)); - - // Update StakingHotkeys map - let mut staking_hotkeys = StakingHotkeys::::get(coldkey); - staking_hotkeys.retain(|h| h != hotkey); - StakingHotkeys::::insert(coldkey, staking_hotkeys); - - current_stake - } - - /// Clears the nomination for an account, if it is a nominator account and the stake is below the minimum required threshold. - pub fn clear_small_nomination_if_required( - hotkey: &T::AccountId, - coldkey: &T::AccountId, - stake: u64, - ) { - // Verify if the account is a nominator account by checking ownership of the hotkey by the coldkey. - if !Self::coldkey_owns_hotkey(coldkey, hotkey) { - // If the stake is below the minimum required, it's considered a small nomination and needs to be cleared. - if stake < Self::get_nominator_min_required_stake() { - // Remove the stake from the nominator account. (this is a more forceful unstake operation which ) - // Actually deletes the staking account. - let cleared_stake = Self::empty_stake_on_coldkey_hotkey_account(coldkey, hotkey); - // Add the stake to the coldkey account. - Self::add_balance_to_coldkey_account(coldkey, cleared_stake); - } - } - } - - /// Clears small nominations for all accounts. - /// - /// WARN: This is an O(N) operation, where N is the number of staking accounts. It should be - /// used with caution. - pub fn clear_small_nominations() { - // Loop through all staking accounts to identify and clear nominations below the minimum stake. - for (hotkey, coldkey, stake) in Stake::::iter() { - Self::clear_small_nomination_if_required(&hotkey, &coldkey, stake); - } - } - - pub fn add_balance_to_coldkey_account( - coldkey: &T::AccountId, - amount: <::Currency as fungible::Inspect<::AccountId>>::Balance, - ) { - // infallible - let _ = T::Currency::deposit(coldkey, amount, Precision::BestEffort); - } - - pub fn set_balance_on_coldkey_account( - coldkey: &T::AccountId, - amount: <::Currency as fungible::Inspect<::AccountId>>::Balance, - ) { - T::Currency::set_balance(coldkey, amount); - } - - pub fn can_remove_balance_from_coldkey_account( - coldkey: &T::AccountId, - amount: <::Currency as fungible::Inspect<::AccountId>>::Balance, - ) -> bool { - let current_balance = Self::get_coldkey_balance(coldkey); - if amount > current_balance { - return false; - } - - // This bit is currently untested. @todo - - T::Currency::can_withdraw(coldkey, amount) - .into_result(false) - .is_ok() - } - - pub fn get_coldkey_balance( - coldkey: &T::AccountId, - ) -> <::Currency as fungible::Inspect<::AccountId>>::Balance - { - T::Currency::reducible_balance(coldkey, Preservation::Expendable, Fortitude::Polite) - } - - #[must_use = "Balance must be used to preserve total issuance of token"] - pub fn remove_balance_from_coldkey_account( - coldkey: &T::AccountId, - amount: <::Currency as fungible::Inspect<::AccountId>>::Balance, - ) -> Result { - if amount == 0 { - return Ok(0); - } - - let credit = T::Currency::withdraw( - coldkey, - amount, - Precision::BestEffort, - Preservation::Preserve, - Fortitude::Polite, - ) - .map_err(|_| Error::::BalanceWithdrawalError)? - .peek(); - - if credit == 0 { - return Err(Error::::ZeroBalanceAfterWithdrawn.into()); - } - - Ok(credit) - } - - pub fn kill_coldkey_account( - coldkey: &T::AccountId, - amount: <::Currency as fungible::Inspect<::AccountId>>::Balance, - ) -> Result { - if amount == 0 { - return Ok(0); - } - - let credit = T::Currency::withdraw( - coldkey, - amount, - Precision::Exact, - Preservation::Expendable, - Fortitude::Force, - ) - .map_err(|_| Error::::BalanceWithdrawalError)? - .peek(); - - if credit == 0 { - return Err(Error::::ZeroBalanceAfterWithdrawn.into()); - } - - Ok(credit) - } - - pub fn unstake_all_coldkeys_from_hotkey_account(hotkey: &T::AccountId) { - // Iterate through all coldkeys that have a stake on this hotkey account. - for (delegate_coldkey_i, stake_i) in - as IterableStorageDoubleMap>::iter_prefix( - hotkey, - ) - { - // Remove the stake from the coldkey - hotkey pairing. - Self::decrease_stake_on_coldkey_hotkey_account(&delegate_coldkey_i, hotkey, stake_i); - - // Add the balance to the coldkey account. - Self::add_balance_to_coldkey_account(&delegate_coldkey_i, stake_i); - } - } -} diff --git a/pallets/subtensor/src/staking/add_stake.rs b/pallets/subtensor/src/staking/add_stake.rs new file mode 100644 index 0000000000..89104de82d --- /dev/null +++ b/pallets/subtensor/src/staking/add_stake.rs @@ -0,0 +1,125 @@ +use super::*; +use frame_support::{ + storage::IterableStorageDoubleMap, + traits::{ + tokens::{ + fungible::{Balanced as _, Inspect as _, Mutate as _}, + Fortitude, Precision, Preservation, + }, + Imbalance, + }, +}; + +impl Pallet { + /// ---- The implementation for the extrinsic add_stake: Adds stake to a hotkey account. + /// + /// # Args: + /// * 'origin': (RuntimeOrigin): + /// - The signature of the caller's coldkey. + /// + /// * 'hotkey' (T::AccountId): + /// - The associated hotkey account. + /// + /// * 'stake_to_be_added' (u64): + /// - The amount of stake to be added to the hotkey staking account. + /// + /// # Event: + /// * StakeAdded; + /// - On the successfully adding stake to a global account. + /// + /// # Raises: + /// * 'NotEnoughBalanceToStake': + /// - Not enough balance on the coldkey to add onto the global account. + /// + /// * 'NonAssociatedColdKey': + /// - The calling coldkey is not associated with this hotkey. + /// + /// * 'BalanceWithdrawalError': + /// - Errors stemming from transaction pallet. + /// + /// * 'TxRateLimitExceeded': + /// - Thrown if key has hit transaction rate limit + /// + pub fn do_add_stake( + origin: T::RuntimeOrigin, + hotkey: T::AccountId, + stake_to_be_added: u64, + ) -> dispatch::DispatchResult { + // We check that the transaction is signed by the caller and retrieve the T::AccountId coldkey information. + let coldkey = ensure_signed(origin)?; + log::info!( + "do_add_stake( origin:{:?} hotkey:{:?}, stake_to_be_added:{:?} )", + coldkey, + hotkey, + stake_to_be_added + ); + + // Ensure the callers coldkey has enough stake to perform the transaction. + ensure!( + Self::can_remove_balance_from_coldkey_account(&coldkey, stake_to_be_added), + Error::::NotEnoughBalanceToStake + ); + + // Ensure that the hotkey account exists this is only possible through registration. + ensure!( + Self::hotkey_account_exists(&hotkey), + Error::::HotKeyAccountNotExists + ); + + // Ensure that the hotkey allows delegation or that the hotkey is owned by the calling coldkey. + ensure!( + Self::hotkey_is_delegate(&hotkey) || Self::coldkey_owns_hotkey(&coldkey, &hotkey), + Error::::HotKeyNotDelegateAndSignerNotOwnHotKey + ); + + // Ensure we don't exceed stake rate limit + let stakes_this_interval = + Self::get_stakes_this_interval_for_coldkey_hotkey(&coldkey, &hotkey); + ensure!( + stakes_this_interval < Self::get_target_stakes_per_interval(), + Error::::StakeRateLimitExceeded + ); + + // If this is a nomination stake, check if total stake after adding will be above + // the minimum required stake. + + // If coldkey is not owner of the hotkey, it's a nomination stake. + if !Self::coldkey_owns_hotkey(&coldkey, &hotkey) { + let total_stake_after_add = + Stake::::get(&hotkey, &coldkey).saturating_add(stake_to_be_added); + + ensure!( + total_stake_after_add >= NominatorMinRequiredStake::::get(), + Error::::NomStakeBelowMinimumThreshold + ); + } + + // Ensure the remove operation from the coldkey is a success. + let actual_amount_to_stake = + Self::remove_balance_from_coldkey_account(&coldkey, stake_to_be_added)?; + + // If we reach here, add the balance to the hotkey. + Self::increase_stake_on_coldkey_hotkey_account(&coldkey, &hotkey, actual_amount_to_stake); + + // Set last block for rate limiting + let block: u64 = Self::get_current_block_as_u64(); + Self::set_last_tx_block(&coldkey, block); + + // Emit the staking event. + Self::set_stakes_this_interval_for_coldkey_hotkey( + &coldkey, + &hotkey, + stakes_this_interval.saturating_add(1), + block, + ); + log::info!( + "StakeAdded( hotkey:{:?}, stake_to_be_added:{:?} )", + hotkey, + actual_amount_to_stake + ); + Self::deposit_event(Event::StakeAdded(hotkey, actual_amount_to_stake)); + + // Ok and return. + Ok(()) + } +} \ No newline at end of file diff --git a/pallets/subtensor/src/staking/become_delegate.rs b/pallets/subtensor/src/staking/become_delegate.rs new file mode 100644 index 0000000000..28d3b25f40 --- /dev/null +++ b/pallets/subtensor/src/staking/become_delegate.rs @@ -0,0 +1,96 @@ +use super::*; +use frame_support::{ + storage::IterableStorageDoubleMap, + traits::{ + tokens::{ + fungible::{Balanced as _, Inspect as _, Mutate as _}, + Fortitude, Precision, Preservation, + }, + Imbalance, + }, +}; + +impl Pallet { + /// ---- The implementation for the extrinsic become_delegate: signals that this hotkey allows delegated stake. + /// + /// # Args: + /// * 'origin': (RuntimeOrigin): + /// - The signature of the caller's coldkey. + /// + /// * 'hotkey' (T::AccountId): + /// - The hotkey we are delegating (must be owned by the coldkey.) + /// + /// * 'take' (u16): + /// - The stake proportion that this hotkey takes from delegations. + /// + /// # Event: + /// * DelegateAdded; + /// - On successfully setting a hotkey as a delegate. + /// + /// # Raises: + /// * 'NotRegistered': + /// - The hotkey we are delegating is not registered on the network. + /// + /// * 'NonAssociatedColdKey': + /// - The hotkey we are delegating is not owned by the calling coldket. + /// + /// * 'TxRateLimitExceeded': + /// - Thrown if key has hit transaction rate limit + /// + pub fn do_become_delegate( + origin: T::RuntimeOrigin, + hotkey: T::AccountId, + take: u16, + ) -> dispatch::DispatchResult { + // --- 1. We check the coldkey signuture. + let coldkey = ensure_signed(origin)?; + log::info!( + "do_become_delegate( origin:{:?} hotkey:{:?}, take:{:?} )", + coldkey, + hotkey, + take + ); + + // --- 2. Ensure we are delegating an known key. + // --- 3. Ensure that the coldkey is the owner. + Self::do_take_checks(&coldkey, &hotkey)?; + + // --- 4. Ensure we are not already a delegate (dont allow changing delegate take.) + ensure!( + !Self::hotkey_is_delegate(&hotkey), + Error::::HotKeyAlreadyDelegate + ); + + // --- 5. Ensure we don't exceed tx rate limit + let block: u64 = Self::get_current_block_as_u64(); + ensure!( + !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&coldkey), block), + Error::::DelegateTxRateLimitExceeded + ); + + // --- 5.1 Ensure take is within the min ..= InitialDefaultTake (18%) range + let min_take = MinTake::::get(); + let max_take = MaxTake::::get(); + ensure!(take >= min_take, Error::::DelegateTakeTooLow); + ensure!(take <= max_take, Error::::DelegateTakeTooHigh); + + // --- 6. Delegate the key. + Self::delegate_hotkey(&hotkey, take); + + // Set last block for rate limiting + Self::set_last_tx_block(&coldkey, block); + Self::set_last_tx_block_delegate_take(&coldkey, block); + + // --- 7. Emit the staking event. + log::info!( + "DelegateAdded( coldkey:{:?}, hotkey:{:?}, take:{:?} )", + coldkey, + hotkey, + take + ); + Self::deposit_event(Event::DelegateAdded(coldkey, hotkey, take)); + + // --- 8. Ok and return. + Ok(()) + } +} diff --git a/pallets/subtensor/src/staking/decrease_take.rs b/pallets/subtensor/src/staking/decrease_take.rs new file mode 100644 index 0000000000..4290a1d24d --- /dev/null +++ b/pallets/subtensor/src/staking/decrease_take.rs @@ -0,0 +1,82 @@ +use super::*; +use frame_support::{ + storage::IterableStorageDoubleMap, + traits::{ + tokens::{ + fungible::{Balanced as _, Inspect as _, Mutate as _}, + Fortitude, Precision, Preservation, + }, + Imbalance, + }, +}; + +impl Pallet { + /// ---- The implementation for the extrinsic decrease_take + /// + /// # Args: + /// * 'origin': (::RuntimeOrigin): + /// - The signature of the caller's coldkey. + /// + /// * 'hotkey' (T::AccountId): + /// - The hotkey we are delegating (must be owned by the coldkey.) + /// + /// * 'take' (u16): + /// - The stake proportion that this hotkey takes from delegations for subnet ID. + /// + /// # Event: + /// * TakeDecreased; + /// - On successfully setting a decreased take for this hotkey. + /// + /// # Raises: + /// * 'NotRegistered': + /// - The hotkey we are delegating is not registered on the network. + /// + /// * 'NonAssociatedColdKey': + /// - The hotkey we are delegating is not owned by the calling coldket. + /// + /// * 'DelegateTakeTooLow': + /// - The delegate is setting a take which is not lower than the previous. + /// + pub fn do_decrease_take( + origin: T::RuntimeOrigin, + hotkey: T::AccountId, + take: u16, + ) -> dispatch::DispatchResult { + // --- 1. We check the coldkey signature. + let coldkey = ensure_signed(origin)?; + log::info!( + "do_decrease_take( origin:{:?} hotkey:{:?}, take:{:?} )", + coldkey, + hotkey, + take + ); + + // --- 2. Ensure we are delegating a known key. + // Ensure that the coldkey is the owner. + Self::do_take_checks(&coldkey, &hotkey)?; + + // --- 3. Ensure we are always strictly decreasing, never increasing take + if let Ok(current_take) = Delegates::::try_get(&hotkey) { + ensure!(take < current_take, Error::::DelegateTakeTooLow); + } + + // --- 3.1 Ensure take is within the min ..= InitialDefaultTake (18%) range + let min_take = MinTake::::get(); + ensure!(take >= min_take, Error::::DelegateTakeTooLow); + + // --- 4. Set the new take value. + Delegates::::insert(hotkey.clone(), take); + + // --- 5. Emit the take value. + log::info!( + "TakeDecreased( coldkey:{:?}, hotkey:{:?}, take:{:?} )", + coldkey, + hotkey, + take + ); + Self::deposit_event(Event::TakeDecreased(coldkey, hotkey, take)); + + // --- 6. Ok and return. + Ok(()) + } +} diff --git a/pallets/subtensor/src/staking/helpers.rs b/pallets/subtensor/src/staking/helpers.rs new file mode 100644 index 0000000000..6da16e8334 --- /dev/null +++ b/pallets/subtensor/src/staking/helpers.rs @@ -0,0 +1,397 @@ +use super::*; +use frame_support::{ + storage::IterableStorageDoubleMap, + traits::{ + tokens::{ + fungible::{Balanced as _, Inspect as _, Mutate as _}, + Fortitude, Precision, Preservation, + }, + Imbalance, + }, +}; + +impl Pallet { + + // Returns true if the passed hotkey allow delegative staking. + // + pub fn hotkey_is_delegate(hotkey: &T::AccountId) -> bool { + Delegates::::contains_key(hotkey) + } + + // Sets the hotkey as a delegate with take. + // + pub fn delegate_hotkey(hotkey: &T::AccountId, take: u16) { + Delegates::::insert(hotkey, take); + } + + // Returns the total amount of stake in the staking table. + // + pub fn get_total_stake() -> u64 { + TotalStake::::get() + } + + // Increases the total amount of stake by the passed amount. + // + pub fn increase_total_stake(increment: u64) { + TotalStake::::put(Self::get_total_stake().saturating_add(increment)); + } + + // Decreases the total amount of stake by the passed amount. + // + pub fn decrease_total_stake(decrement: u64) { + TotalStake::::put(Self::get_total_stake().saturating_sub(decrement)); + } + + // Returns the total amount of stake under a hotkey (delegative or otherwise) + // + pub fn get_total_stake_for_hotkey(hotkey: &T::AccountId) -> u64 { + TotalHotkeyStake::::get(hotkey) + } + + // Returns the total amount of stake held by the coldkey (delegative or otherwise) + // + pub fn get_total_stake_for_coldkey(coldkey: &T::AccountId) -> u64 { + TotalColdkeyStake::::get(coldkey) + } + + // Returns the stake under the cold - hot pairing in the staking table. + // + pub fn get_stake_for_coldkey_and_hotkey(coldkey: &T::AccountId, hotkey: &T::AccountId) -> u64 { + Stake::::get(hotkey, coldkey) + } + + // Retrieves the total stakes for a given hotkey (account ID) for the current staking interval. + pub fn get_stakes_this_interval_for_coldkey_hotkey( + coldkey: &T::AccountId, + hotkey: &T::AccountId, + ) -> u64 { + // Retrieve the configured stake interval duration from storage. + let stake_interval = StakeInterval::::get(); + + // Obtain the current block number as an unsigned 64-bit integer. + let current_block = Self::get_current_block_as_u64(); + + // Fetch the total stakes and the last block number when stakes were made for the hotkey. + let (stakes, block_last_staked_at) = + TotalHotkeyColdkeyStakesThisInterval::::get(coldkey, hotkey); + + // Calculate the block number after which the stakes for the hotkey should be reset. + let block_to_reset_after = block_last_staked_at.saturating_add(stake_interval); + + // If the current block number is beyond the reset point, + // it indicates the end of the staking interval for the hotkey. + if block_to_reset_after <= current_block { + // Reset the stakes for this hotkey for the current interval. + Self::set_stakes_this_interval_for_coldkey_hotkey( + coldkey, + hotkey, + 0, + block_last_staked_at, + ); + // Return 0 as the stake amount since we've just reset the stakes. + return 0; + } + + // If the staking interval has not yet ended, return the current stake amount. + stakes + } + + pub fn get_target_stakes_per_interval() -> u64 { + TargetStakesPerInterval::::get() + } + + // Creates a cold - hot pairing account if the hotkey is not already an active account. + // + pub fn create_account_if_non_existent(coldkey: &T::AccountId, hotkey: &T::AccountId) { + if !Self::hotkey_account_exists(hotkey) { + Stake::::insert(hotkey, coldkey, 0); + Owner::::insert(hotkey, coldkey); + + // Update OwnedHotkeys map + let mut hotkeys = OwnedHotkeys::::get(coldkey); + if !hotkeys.contains(hotkey) { + hotkeys.push(hotkey.clone()); + OwnedHotkeys::::insert(coldkey, hotkeys); + } + + // Update StakingHotkeys map + let mut staking_hotkeys = StakingHotkeys::::get(coldkey); + if !staking_hotkeys.contains(hotkey) { + staking_hotkeys.push(hotkey.clone()); + StakingHotkeys::::insert(coldkey, staking_hotkeys); + } + } + } + + // Returns the coldkey owning this hotkey. This function should only be called for active accounts. + // + pub fn get_owning_coldkey_for_hotkey(hotkey: &T::AccountId) -> T::AccountId { + Owner::::get(hotkey) + } + + // Returns the hotkey take + // + pub fn get_hotkey_take(hotkey: &T::AccountId) -> u16 { + Delegates::::get(hotkey) + } + + // Returns true if the hotkey account has been created. + // + pub fn hotkey_account_exists(hotkey: &T::AccountId) -> bool { + Owner::::contains_key(hotkey) + } + + // Return true if the passed coldkey owns the hotkey. + // + pub fn coldkey_owns_hotkey(coldkey: &T::AccountId, hotkey: &T::AccountId) -> bool { + if Self::hotkey_account_exists(hotkey) { + Owner::::get(hotkey) == *coldkey + } else { + false + } + } + + // Returns true if the cold-hot staking account has enough balance to fufil the decrement. + // + pub fn has_enough_stake(coldkey: &T::AccountId, hotkey: &T::AccountId, decrement: u64) -> bool { + Self::get_stake_for_coldkey_and_hotkey(coldkey, hotkey) >= decrement + } + + // Increases the stake on the hotkey account under its owning coldkey. + // + pub fn increase_stake_on_hotkey_account(hotkey: &T::AccountId, increment: u64) { + Self::increase_stake_on_coldkey_hotkey_account( + &Self::get_owning_coldkey_for_hotkey(hotkey), + hotkey, + increment, + ); + } + + // Decreases the stake on the hotkey account under its owning coldkey. + // + pub fn decrease_stake_on_hotkey_account(hotkey: &T::AccountId, decrement: u64) { + Self::decrease_stake_on_coldkey_hotkey_account( + &Self::get_owning_coldkey_for_hotkey(hotkey), + hotkey, + decrement, + ); + } + + // Increases the stake on the cold - hot pairing by increment while also incrementing other counters. + // This function should be called rather than set_stake under account. + // + pub fn increase_stake_on_coldkey_hotkey_account( + coldkey: &T::AccountId, + hotkey: &T::AccountId, + increment: u64, + ) { + TotalColdkeyStake::::insert( + coldkey, + TotalColdkeyStake::::get(coldkey).saturating_add(increment), + ); + TotalHotkeyStake::::insert( + hotkey, + TotalHotkeyStake::::get(hotkey).saturating_add(increment), + ); + Stake::::insert( + hotkey, + coldkey, + Stake::::get(hotkey, coldkey).saturating_add(increment), + ); + TotalStake::::put(TotalStake::::get().saturating_add(increment)); + + // Update StakingHotkeys map + let mut staking_hotkeys = StakingHotkeys::::get(coldkey); + if !staking_hotkeys.contains(hotkey) { + staking_hotkeys.push(hotkey.clone()); + StakingHotkeys::::insert(coldkey, staking_hotkeys); + } + } + + // Decreases the stake on the cold - hot pairing by the decrement while decreasing other counters. + // + pub fn decrease_stake_on_coldkey_hotkey_account( + coldkey: &T::AccountId, + hotkey: &T::AccountId, + decrement: u64, + ) { + TotalColdkeyStake::::mutate(coldkey, |old| *old = old.saturating_sub(decrement)); + TotalHotkeyStake::::insert( + hotkey, + TotalHotkeyStake::::get(hotkey).saturating_sub(decrement), + ); + Stake::::insert( + hotkey, + coldkey, + Stake::::get(hotkey, coldkey).saturating_sub(decrement), + ); + TotalStake::::put(TotalStake::::get().saturating_sub(decrement)); + + // TODO: Tech debt: Remove StakingHotkeys entry if stake goes to 0 + } + + /// Empties the stake associated with a given coldkey-hotkey account pairing. + /// This function retrieves the current stake for the specified coldkey-hotkey pairing, + /// then subtracts this stake amount from both the TotalColdkeyStake and TotalHotkeyStake. + /// It also removes the stake entry for the hotkey-coldkey pairing and adjusts the TotalStake + /// and TotalIssuance by subtracting the removed stake amount. + /// + /// Returns the amount of stake that was removed. + /// + /// # Arguments + /// + /// * `coldkey` - A reference to the AccountId of the coldkey involved in the staking. + /// * `hotkey` - A reference to the AccountId of the hotkey associated with the coldkey. + pub fn empty_stake_on_coldkey_hotkey_account( + coldkey: &T::AccountId, + hotkey: &T::AccountId, + ) -> u64 { + let current_stake: u64 = Stake::::get(hotkey, coldkey); + TotalColdkeyStake::::mutate(coldkey, |old| *old = old.saturating_sub(current_stake)); + TotalHotkeyStake::::mutate(hotkey, |stake| *stake = stake.saturating_sub(current_stake)); + Stake::::remove(hotkey, coldkey); + TotalStake::::mutate(|stake| *stake = stake.saturating_sub(current_stake)); + TotalIssuance::::mutate(|issuance| *issuance = issuance.saturating_sub(current_stake)); + + // Update StakingHotkeys map + let mut staking_hotkeys = StakingHotkeys::::get(coldkey); + staking_hotkeys.retain(|h| h != hotkey); + StakingHotkeys::::insert(coldkey, staking_hotkeys); + + current_stake + } + + /// Clears the nomination for an account, if it is a nominator account and the stake is below the minimum required threshold. + pub fn clear_small_nomination_if_required( + hotkey: &T::AccountId, + coldkey: &T::AccountId, + stake: u64, + ) { + // Verify if the account is a nominator account by checking ownership of the hotkey by the coldkey. + if !Self::coldkey_owns_hotkey(coldkey, hotkey) { + // If the stake is below the minimum required, it's considered a small nomination and needs to be cleared. + if stake < Self::get_nominator_min_required_stake() { + // Remove the stake from the nominator account. (this is a more forceful unstake operation which ) + // Actually deletes the staking account. + let cleared_stake = Self::empty_stake_on_coldkey_hotkey_account(coldkey, hotkey); + // Add the stake to the coldkey account. + Self::add_balance_to_coldkey_account(coldkey, cleared_stake); + } + } + } + + /// Clears small nominations for all accounts. + /// + /// WARN: This is an O(N) operation, where N is the number of staking accounts. It should be + /// used with caution. + pub fn clear_small_nominations() { + // Loop through all staking accounts to identify and clear nominations below the minimum stake. + for (hotkey, coldkey, stake) in Stake::::iter() { + Self::clear_small_nomination_if_required(&hotkey, &coldkey, stake); + } + } + + pub fn add_balance_to_coldkey_account( + coldkey: &T::AccountId, + amount: <::Currency as fungible::Inspect<::AccountId>>::Balance, + ) { + // infallible + let _ = T::Currency::deposit(coldkey, amount, Precision::BestEffort); + } + + pub fn set_balance_on_coldkey_account( + coldkey: &T::AccountId, + amount: <::Currency as fungible::Inspect<::AccountId>>::Balance, + ) { + T::Currency::set_balance(coldkey, amount); + } + + pub fn can_remove_balance_from_coldkey_account( + coldkey: &T::AccountId, + amount: <::Currency as fungible::Inspect<::AccountId>>::Balance, + ) -> bool { + let current_balance = Self::get_coldkey_balance(coldkey); + if amount > current_balance { + return false; + } + + // This bit is currently untested. @todo + + T::Currency::can_withdraw(coldkey, amount) + .into_result(false) + .is_ok() + } + + pub fn get_coldkey_balance( + coldkey: &T::AccountId, + ) -> <::Currency as fungible::Inspect<::AccountId>>::Balance + { + T::Currency::reducible_balance(coldkey, Preservation::Expendable, Fortitude::Polite) + } + + #[must_use = "Balance must be used to preserve total issuance of token"] + pub fn remove_balance_from_coldkey_account( + coldkey: &T::AccountId, + amount: <::Currency as fungible::Inspect<::AccountId>>::Balance, + ) -> Result { + if amount == 0 { + return Ok(0); + } + + let credit = T::Currency::withdraw( + coldkey, + amount, + Precision::BestEffort, + Preservation::Preserve, + Fortitude::Polite, + ) + .map_err(|_| Error::::BalanceWithdrawalError)? + .peek(); + + if credit == 0 { + return Err(Error::::ZeroBalanceAfterWithdrawn.into()); + } + + Ok(credit) + } + + pub fn kill_coldkey_account( + coldkey: &T::AccountId, + amount: <::Currency as fungible::Inspect<::AccountId>>::Balance, + ) -> Result { + if amount == 0 { + return Ok(0); + } + + let credit = T::Currency::withdraw( + coldkey, + amount, + Precision::Exact, + Preservation::Expendable, + Fortitude::Force, + ) + .map_err(|_| Error::::BalanceWithdrawalError)? + .peek(); + + if credit == 0 { + return Err(Error::::ZeroBalanceAfterWithdrawn.into()); + } + + Ok(credit) + } + + pub fn unstake_all_coldkeys_from_hotkey_account(hotkey: &T::AccountId) { + // Iterate through all coldkeys that have a stake on this hotkey account. + for (delegate_coldkey_i, stake_i) in + as IterableStorageDoubleMap>::iter_prefix( + hotkey, + ) + { + // Remove the stake from the coldkey - hotkey pairing. + Self::decrease_stake_on_coldkey_hotkey_account(&delegate_coldkey_i, hotkey, stake_i); + + // Add the balance to the coldkey account. + Self::add_balance_to_coldkey_account(&delegate_coldkey_i, stake_i); + } + } +} diff --git a/pallets/subtensor/src/staking/increase_take.rs b/pallets/subtensor/src/staking/increase_take.rs new file mode 100644 index 0000000000..744027a9bd --- /dev/null +++ b/pallets/subtensor/src/staking/increase_take.rs @@ -0,0 +1,99 @@ + +use super::*; +use frame_support::{ + storage::IterableStorageDoubleMap, + traits::{ + tokens::{ + fungible::{Balanced as _, Inspect as _, Mutate as _}, + Fortitude, Precision, Preservation, + }, + Imbalance, + }, +}; + +impl Pallet { + /// ---- The implementation for the extrinsic increase_take + /// + /// # Args: + /// * 'origin': (::RuntimeOrigin): + /// - The signature of the caller's coldkey. + /// + /// * 'hotkey' (T::AccountId): + /// - The hotkey we are delegating (must be owned by the coldkey.) + /// + /// * 'take' (u16): + /// - The stake proportion that this hotkey takes from delegations for subnet ID. + /// + /// # Event: + /// * TakeIncreased; + /// - On successfully setting a increased take for this hotkey. + /// + /// # Raises: + /// * 'NotRegistered': + /// - The hotkey we are delegating is not registered on the network. + /// + /// * 'NonAssociatedColdKey': + /// - The hotkey we are delegating is not owned by the calling coldket. + /// + /// * 'TxRateLimitExceeded': + /// - Thrown if key has hit transaction rate limit + /// + /// * 'DelegateTakeTooLow': + /// - The delegate is setting a take which is not greater than the previous. + /// + pub fn do_increase_take( + origin: T::RuntimeOrigin, + hotkey: T::AccountId, + take: u16, + ) -> dispatch::DispatchResult { + // --- 1. We check the coldkey signature. + let coldkey = ensure_signed(origin)?; + log::info!( + "do_increase_take( origin:{:?} hotkey:{:?}, take:{:?} )", + coldkey, + hotkey, + take + ); + + // --- 2. Ensure we are delegating a known key. + // Ensure that the coldkey is the owner. + Self::do_take_checks(&coldkey, &hotkey)?; + + // --- 3. Ensure we are strinctly increasing take + if let Ok(current_take) = Delegates::::try_get(&hotkey) { + ensure!(take > current_take, Error::::DelegateTakeTooLow); + } + + // --- 4. Ensure take is within the min ..= InitialDefaultTake (18%) range + let max_take = MaxTake::::get(); + ensure!(take <= max_take, Error::::DelegateTakeTooHigh); + + // --- 5. Enforce the rate limit (independently on do_add_stake rate limits) + let block: u64 = Self::get_current_block_as_u64(); + ensure!( + !Self::exceeds_tx_delegate_take_rate_limit( + Self::get_last_tx_block_delegate_take(&coldkey), + block + ), + Error::::DelegateTxRateLimitExceeded + ); + + // Set last block for rate limiting + Self::set_last_tx_block_delegate_take(&coldkey, block); + + // --- 6. Set the new take value. + Delegates::::insert(hotkey.clone(), take); + + // --- 7. Emit the take value. + log::info!( + "TakeIncreased( coldkey:{:?}, hotkey:{:?}, take:{:?} )", + coldkey, + hotkey, + take + ); + Self::deposit_event(Event::TakeIncreased(coldkey, hotkey, take)); + + // --- 8. Ok and return. + Ok(()) + } +} \ No newline at end of file diff --git a/pallets/subtensor/src/staking/mod.rs b/pallets/subtensor/src/staking/mod.rs new file mode 100644 index 0000000000..7015b455a8 --- /dev/null +++ b/pallets/subtensor/src/staking/mod.rs @@ -0,0 +1,7 @@ +use super::*; +pub mod helpers; +pub mod add_stake; +pub mod remove_stake; +pub mod decrease_take; +pub mod increase_take; +pub mod become_delegate; \ No newline at end of file diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs new file mode 100644 index 0000000000..5f467e009f --- /dev/null +++ b/pallets/subtensor/src/staking/remove_stake.rs @@ -0,0 +1,120 @@ + +use super::*; +use frame_support::{ + storage::IterableStorageDoubleMap, + traits::{ + tokens::{ + fungible::{Balanced as _, Inspect as _, Mutate as _}, + Fortitude, Precision, Preservation, + }, + Imbalance, + }, +}; + +impl Pallet { + /// ---- The implementation for the extrinsic remove_stake: Removes stake from a hotkey account and adds it onto a coldkey. + /// + /// # Args: + /// * 'origin': (RuntimeOrigin): + /// - The signature of the caller's coldkey. + /// + /// * 'hotkey' (T::AccountId): + /// - The associated hotkey account. + /// + /// * 'stake_to_be_added' (u64): + /// - The amount of stake to be added to the hotkey staking account. + /// + /// # Event: + /// * StakeRemoved; + /// - On the successfully removing stake from the hotkey account. + /// + /// # Raises: + /// * 'NotRegistered': + /// - Thrown if the account we are attempting to unstake from is non existent. + /// + /// * 'NonAssociatedColdKey': + /// - Thrown if the coldkey does not own the hotkey we are unstaking from. + /// + /// * 'NotEnoughStakeToWithdraw': + /// - Thrown if there is not enough stake on the hotkey to withdwraw this amount. + /// + /// * 'TxRateLimitExceeded': + /// - Thrown if key has hit transaction rate limit + /// + pub fn do_remove_stake( + origin: T::RuntimeOrigin, + hotkey: T::AccountId, + stake_to_be_removed: u64, + ) -> dispatch::DispatchResult { + // We check the transaction is signed by the caller and retrieve the T::AccountId coldkey information. + let coldkey = ensure_signed(origin)?; + log::info!( + "do_remove_stake( origin:{:?} hotkey:{:?}, stake_to_be_removed:{:?} )", + coldkey, + hotkey, + stake_to_be_removed + ); + + // Ensure that the hotkey account exists this is only possible through registration. + ensure!( + Self::hotkey_account_exists(&hotkey), + Error::::HotKeyAccountNotExists + ); + + // Ensure that the hotkey allows delegation or that the hotkey is owned by the calling coldkey. + ensure!( + Self::hotkey_is_delegate(&hotkey) || Self::coldkey_owns_hotkey(&coldkey, &hotkey), + Error::::HotKeyNotDelegateAndSignerNotOwnHotKey + ); + + // Ensure that the stake amount to be removed is above zero. + ensure!(stake_to_be_removed > 0, Error::::StakeToWithdrawIsZero); + + // Ensure that the hotkey has enough stake to withdraw. + ensure!( + Self::has_enough_stake(&coldkey, &hotkey, stake_to_be_removed), + Error::::NotEnoughStakeToWithdraw + ); + + // Ensure we don't exceed stake rate limit + let unstakes_this_interval = + Self::get_stakes_this_interval_for_coldkey_hotkey(&coldkey, &hotkey); + ensure!( + unstakes_this_interval < Self::get_target_stakes_per_interval(), + Error::::UnstakeRateLimitExceeded + ); + + // We remove the balance from the hotkey. + Self::decrease_stake_on_coldkey_hotkey_account(&coldkey, &hotkey, stake_to_be_removed); + + // We add the balance to the coldkey. If the above fails we will not credit this coldkey. + Self::add_balance_to_coldkey_account(&coldkey, stake_to_be_removed); + + // If the stake is below the minimum, we clear the nomination from storage. + // This only applies to nominator stakes. + // If the coldkey does not own the hotkey, it's a nominator stake. + let new_stake = Self::get_stake_for_coldkey_and_hotkey(&coldkey, &hotkey); + Self::clear_small_nomination_if_required(&hotkey, &coldkey, new_stake); + + // Set last block for rate limiting + let block: u64 = Self::get_current_block_as_u64(); + Self::set_last_tx_block(&coldkey, block); + + // Emit the unstaking event. + Self::set_stakes_this_interval_for_coldkey_hotkey( + &coldkey, + &hotkey, + unstakes_this_interval.saturating_add(1), + block, + ); + log::info!( + "StakeRemoved( hotkey:{:?}, stake_to_be_removed:{:?} )", + hotkey, + stake_to_be_removed + ); + Self::deposit_event(Event::StakeRemoved(hotkey, stake_to_be_removed)); + + // Done and ok. + Ok(()) + } +} \ No newline at end of file diff --git a/pallets/subtensor/src/swap/swap_coldkey.rs b/pallets/subtensor/src/swap/swap_coldkey.rs index 83bad51341..78508f9c55 100644 --- a/pallets/subtensor/src/swap/swap_coldkey.rs +++ b/pallets/subtensor/src/swap/swap_coldkey.rs @@ -1,7 +1,7 @@ use super::*; use frame_support::traits::fungible::Mutate; use frame_support::traits::tokens::Preservation; -use frame_support::{storage::IterableStorageDoubleMap, weights::Weight}; +use frame_support::weights::Weight; use sp_core::Get; impl Pallet { From fcbf66235f0d2b358a8ef869bfd00eacaef5bcb2 Mon Sep 17 00:00:00 2001 From: const Date: Mon, 15 Jul 2024 14:10:49 -0500 Subject: [PATCH 04/16] fmt --- pallets/subtensor/src/coinbase/mod.rs | 2 +- pallets/subtensor/src/epoch/mod.rs | 2 +- pallets/subtensor/src/lib.rs | 1229 ++++++++++++----- pallets/subtensor/src/macros/config.rs | 2 +- pallets/subtensor/src/macros/dispatches.rs | 2 +- pallets/subtensor/src/macros/genesis.rs | 3 +- pallets/subtensor/src/macros/hooks.rs | 2 +- pallets/subtensor/src/macros/mod.rs | 6 +- .../migrations/migrate_create_root_network.rs | 4 +- .../migrations/migrate_delete_subnet_21.rs | 5 +- .../src/migrations/migrate_delete_subnet_3.rs | 5 +- .../migrate_populate_owned_hotkeys.rs | 5 +- .../migrate_populate_staking_hotkeys.rs | 4 +- .../migrate_to_v1_separate_emission.rs | 9 +- .../migrate_to_v2_fixed_total_stake.rs | 7 +- .../src/migrations/migrate_total_issuance.rs | 17 +- ...igrate_transfer_ownership_to_foundation.rs | 2 +- pallets/subtensor/src/migrations/mod.rs | 10 +- pallets/subtensor/src/root.rs | 3 +- pallets/subtensor/src/rpc_info/mod.rs | 2 +- pallets/subtensor/src/staking/add_stake.rs | 2 +- pallets/subtensor/src/staking/helpers.rs | 1 - .../subtensor/src/staking/increase_take.rs | 3 +- pallets/subtensor/src/staking/mod.rs | 6 +- pallets/subtensor/src/staking/remove_stake.rs | 3 +- pallets/subtensor/src/swap/mod.rs | 2 +- pallets/subtensor/src/swap/swap_coldkey.rs | 4 - pallets/subtensor/src/swap/swap_hotkey.rs | 3 +- pallets/subtensor/tests/staking.rs | 2 +- pallets/subtensor/tests/swap.rs | 69 +- 30 files changed, 985 insertions(+), 431 deletions(-) diff --git a/pallets/subtensor/src/coinbase/mod.rs b/pallets/subtensor/src/coinbase/mod.rs index e86c66b597..cc5b589f16 100644 --- a/pallets/subtensor/src/coinbase/mod.rs +++ b/pallets/subtensor/src/coinbase/mod.rs @@ -1,2 +1,2 @@ use super::*; -pub mod block_step; \ No newline at end of file +pub mod block_step; diff --git a/pallets/subtensor/src/epoch/mod.rs b/pallets/subtensor/src/epoch/mod.rs index 74f3b10944..723e68ee4f 100644 --- a/pallets/subtensor/src/epoch/mod.rs +++ b/pallets/subtensor/src/epoch/mod.rs @@ -1,3 +1,3 @@ use super::*; +pub mod epoch; pub mod math; -pub mod epoch; \ No newline at end of file diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 7596029e05..23adeee02a 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -35,13 +35,13 @@ mod benchmarks; // ========================= // ==== Pallet Imports ===== // ========================= -mod rpc_info; mod coinbase; pub mod epoch; -pub mod swap; -pub mod staking; mod macros; -use macros::{events, errors, dispatches, genesis, hooks, config}; +mod rpc_info; +pub mod staking; +pub mod swap; +use macros::{config, dispatches, errors, events, genesis, hooks}; mod registration; mod root; @@ -64,12 +64,12 @@ pub mod migrations; #[frame_support::pallet] pub mod pallet { + use crate::migrations; use frame_support::{ dispatch::GetDispatchInfo, pallet_prelude::{DispatchResult, StorageMap, ValueQuery, *}, traits::{tokens::fungible, UnfilteredDispatchable}, }; - use crate::migrations; use frame_system::pallet_prelude::*; use sp_core::H256; use sp_runtime::traits::TrailingZeroInput; @@ -137,178 +137,427 @@ pub mod pallet { pub ip_type: u8, } - /// ============================ /// ==== Staking + Accounts ==== /// ============================ - #[pallet::type_value] /// Total Rao in circulation. - pub fn TotalSupply() -> u64 { 21_000_000_000_000_000 } - #[pallet::type_value] /// Default total stake. - pub fn DefaultDefaultTake() -> u16 { T::InitialDefaultTake::get() } - #[pallet::type_value] /// Default minimum take. - pub fn DefaultMinTake() -> u16 { T::InitialMinTake::get() } - #[pallet::type_value] /// Default account take. - pub fn DefaultAccountTake() -> u64 { 0 } - #[pallet::type_value] /// Default stakes per interval. - pub fn DefaultStakesPerInterval() -> (u64, u64) { (0, 0) } - #[pallet::type_value] /// Default emission per block. - pub fn DefaultBlockEmission() -> u64 { 1_000_000_000 } - #[pallet::type_value] /// Default allowed delegation. - pub fn DefaultAllowsDelegation() -> bool { false } - #[pallet::type_value] /// Default total issuance. - pub fn DefaultTotalIssuance() -> u64 { T::InitialIssuance::get() } - #[pallet::type_value] /// Default account, derived from zero trailing bytes. - pub fn DefaultAccount() -> T::AccountId { T::AccountId::decode(&mut TrailingZeroInput::zeroes()).expect("trailing zeroes always produce a valid account ID; qed") } - #[pallet::type_value] /// Default target stakes per interval. - pub fn DefaultTargetStakesPerInterval() -> u64 { T::InitialTargetStakesPerInterval::get() } - #[pallet::type_value] /// Default stake interval. - pub fn DefaultStakeInterval() -> u64 { 360 } - #[pallet::type_value] /// Default account linkage - pub fn DefaultAccountLinkage() -> Vec<(u64, T::AccountId)> { vec![] } - #[pallet::type_value] /// Default account linkage - pub fn DefaultProportion() -> u64 { 0 } - #[pallet::type_value] /// Default accumulated emission for a hotkey - pub fn DefaultAccumulatedEmission() -> u64 { 0 } - #[pallet::type_value] /// Default last adjustment block. - pub fn DefaultLastAdjustmentBlock() -> u64 { 0 } - #[pallet::type_value] /// Default last adjustment block. - pub fn DefaultRegistrationsThisBlock() -> u16 { 0 } - #[pallet::type_value] /// Default registrations this block. - pub fn DefaultBurn() -> u64 { T::InitialBurn::get() } - #[pallet::type_value] /// Default burn token. - pub fn DefaultMinBurn() -> u64 { T::InitialMinBurn::get() } - #[pallet::type_value] /// Default min burn token. - pub fn DefaultMaxBurn() -> u64 { T::InitialMaxBurn::get() } - #[pallet::type_value] /// Default max burn token. - pub fn DefaultDifficulty() -> u64 { T::InitialDifficulty::get() } - #[pallet::type_value] /// Default difficulty value. - pub fn DefaultMinDifficulty() -> u64 { T::InitialMinDifficulty::get() } - #[pallet::type_value] /// Default min difficulty value. - pub fn DefaultMaxDifficulty() -> u64 { T::InitialMaxDifficulty::get() } - #[pallet::type_value] /// Default max difficulty value. - pub fn DefaultMaxRegistrationsPerBlock() -> u16 { T::InitialMaxRegistrationsPerBlock::get() } - #[pallet::type_value] /// Default max registrations per block. - pub fn DefaultRAORecycledForRegistration() -> u64 { T::InitialRAORecycledForRegistration::get() } - #[pallet::type_value] /// Default number of networks. - pub fn DefaultN() -> u16 { 0 } - #[pallet::type_value] /// Default value for modality. - pub fn DefaultModality() -> u16 { 0 } - #[pallet::type_value] /// Default value for hotkeys. - pub fn DefaultHotkeys() -> Vec { vec![] } - #[pallet::type_value] /// Default value if network is added. - pub fn DefaultNeworksAdded() -> bool { false } - #[pallet::type_value] /// Default value for network member. - pub fn DefaultIsNetworkMember() -> bool { false } - #[pallet::type_value] /// Default value for registration allowed. - pub fn DefaultRegistrationAllowed() -> bool { false } - #[pallet::type_value] /// Default value for network registered at. - pub fn DefaultNetworkRegisteredAt() -> u64 { 0 } - #[pallet::type_value] /// Default value for network immunity period. - pub fn DefaultNetworkImmunityPeriod() -> u64 { T::InitialNetworkImmunityPeriod::get() } - #[pallet::type_value] /// Default value for network last registered. - pub fn DefaultNetworkLastRegistered() -> u64 { 0 } - #[pallet::type_value] /// Default value for nominator min required stake. - pub fn DefaultNominatorMinRequiredStake() -> u64 { 0 } - #[pallet::type_value] /// Default value for network min allowed UIDs. - pub fn DefaultNetworkMinAllowedUids() -> u16 { T::InitialNetworkMinAllowedUids::get() } - #[pallet::type_value] /// Default value for network min lock cost. - pub fn DefaultNetworkMinLockCost() -> u64 { T::InitialNetworkMinLockCost::get() } - #[pallet::type_value] /// Default value for network lock reduction interval. - pub fn DefaultNetworkLockReductionInterval() -> u64 { T::InitialNetworkLockReductionInterval::get() } - #[pallet::type_value] /// Default value for subnet owner cut. - pub fn DefaultSubnetOwnerCut() -> u16 { T::InitialSubnetOwnerCut::get() } - #[pallet::type_value] /// Default value for subnet limit. - pub fn DefaultSubnetLimit() -> u16 { T::InitialSubnetLimit::get() } - #[pallet::type_value] /// Default value for network rate limit. - pub fn DefaultNetworkRateLimit() -> u64 { if cfg!(feature = "pow-faucet") { return 0; } T::InitialNetworkRateLimit::get() } + #[pallet::type_value] + /// Total Rao in circulation. + pub fn TotalSupply() -> u64 { + 21_000_000_000_000_000 + } + #[pallet::type_value] + /// Default total stake. + pub fn DefaultDefaultTake() -> u16 { + T::InitialDefaultTake::get() + } + #[pallet::type_value] + /// Default minimum take. + pub fn DefaultMinTake() -> u16 { + T::InitialMinTake::get() + } + #[pallet::type_value] + /// Default account take. + pub fn DefaultAccountTake() -> u64 { + 0 + } + #[pallet::type_value] + /// Default stakes per interval. + pub fn DefaultStakesPerInterval() -> (u64, u64) { + (0, 0) + } + #[pallet::type_value] + /// Default emission per block. + pub fn DefaultBlockEmission() -> u64 { + 1_000_000_000 + } + #[pallet::type_value] + /// Default allowed delegation. + pub fn DefaultAllowsDelegation() -> bool { + false + } + #[pallet::type_value] + /// Default total issuance. + pub fn DefaultTotalIssuance() -> u64 { + T::InitialIssuance::get() + } + #[pallet::type_value] + /// Default account, derived from zero trailing bytes. + pub fn DefaultAccount() -> T::AccountId { + T::AccountId::decode(&mut TrailingZeroInput::zeroes()) + .expect("trailing zeroes always produce a valid account ID; qed") + } + #[pallet::type_value] + /// Default target stakes per interval. + pub fn DefaultTargetStakesPerInterval() -> u64 { + T::InitialTargetStakesPerInterval::get() + } + #[pallet::type_value] + /// Default stake interval. + pub fn DefaultStakeInterval() -> u64 { + 360 + } + #[pallet::type_value] + /// Default account linkage + pub fn DefaultAccountLinkage() -> Vec<(u64, T::AccountId)> { + vec![] + } + #[pallet::type_value] + /// Default account linkage + pub fn DefaultProportion() -> u64 { + 0 + } + #[pallet::type_value] + /// Default accumulated emission for a hotkey + pub fn DefaultAccumulatedEmission() -> u64 { + 0 + } + #[pallet::type_value] + /// Default last adjustment block. + pub fn DefaultLastAdjustmentBlock() -> u64 { + 0 + } + #[pallet::type_value] + /// Default last adjustment block. + pub fn DefaultRegistrationsThisBlock() -> u16 { + 0 + } + #[pallet::type_value] + /// Default registrations this block. + pub fn DefaultBurn() -> u64 { + T::InitialBurn::get() + } + #[pallet::type_value] + /// Default burn token. + pub fn DefaultMinBurn() -> u64 { + T::InitialMinBurn::get() + } + #[pallet::type_value] + /// Default min burn token. + pub fn DefaultMaxBurn() -> u64 { + T::InitialMaxBurn::get() + } + #[pallet::type_value] + /// Default max burn token. + pub fn DefaultDifficulty() -> u64 { + T::InitialDifficulty::get() + } + #[pallet::type_value] + /// Default difficulty value. + pub fn DefaultMinDifficulty() -> u64 { + T::InitialMinDifficulty::get() + } + #[pallet::type_value] + /// Default min difficulty value. + pub fn DefaultMaxDifficulty() -> u64 { + T::InitialMaxDifficulty::get() + } + #[pallet::type_value] + /// Default max difficulty value. + pub fn DefaultMaxRegistrationsPerBlock() -> u16 { + T::InitialMaxRegistrationsPerBlock::get() + } + #[pallet::type_value] + /// Default max registrations per block. + pub fn DefaultRAORecycledForRegistration() -> u64 { + T::InitialRAORecycledForRegistration::get() + } + #[pallet::type_value] + /// Default number of networks. + pub fn DefaultN() -> u16 { + 0 + } + #[pallet::type_value] + /// Default value for modality. + pub fn DefaultModality() -> u16 { + 0 + } + #[pallet::type_value] + /// Default value for hotkeys. + pub fn DefaultHotkeys() -> Vec { + vec![] + } + #[pallet::type_value] + /// Default value if network is added. + pub fn DefaultNeworksAdded() -> bool { + false + } + #[pallet::type_value] + /// Default value for network member. + pub fn DefaultIsNetworkMember() -> bool { + false + } + #[pallet::type_value] + /// Default value for registration allowed. + pub fn DefaultRegistrationAllowed() -> bool { + false + } + #[pallet::type_value] + /// Default value for network registered at. + pub fn DefaultNetworkRegisteredAt() -> u64 { + 0 + } + #[pallet::type_value] + /// Default value for network immunity period. + pub fn DefaultNetworkImmunityPeriod() -> u64 { + T::InitialNetworkImmunityPeriod::get() + } + #[pallet::type_value] + /// Default value for network last registered. + pub fn DefaultNetworkLastRegistered() -> u64 { + 0 + } + #[pallet::type_value] + /// Default value for nominator min required stake. + pub fn DefaultNominatorMinRequiredStake() -> u64 { + 0 + } + #[pallet::type_value] + /// Default value for network min allowed UIDs. + pub fn DefaultNetworkMinAllowedUids() -> u16 { + T::InitialNetworkMinAllowedUids::get() + } + #[pallet::type_value] + /// Default value for network min lock cost. + pub fn DefaultNetworkMinLockCost() -> u64 { + T::InitialNetworkMinLockCost::get() + } + #[pallet::type_value] + /// Default value for network lock reduction interval. + pub fn DefaultNetworkLockReductionInterval() -> u64 { + T::InitialNetworkLockReductionInterval::get() + } + #[pallet::type_value] + /// Default value for subnet owner cut. + pub fn DefaultSubnetOwnerCut() -> u16 { + T::InitialSubnetOwnerCut::get() + } + #[pallet::type_value] + /// Default value for subnet limit. + pub fn DefaultSubnetLimit() -> u16 { + T::InitialSubnetLimit::get() + } + #[pallet::type_value] + /// Default value for network rate limit. + pub fn DefaultNetworkRateLimit() -> u64 { + if cfg!(feature = "pow-faucet") { + return 0; + } + T::InitialNetworkRateLimit::get() + } // #[pallet::type_value] /// Default value for network max stake. // pub fn DefaultNetworkMaxStake() -> u64 { T::InitialNetworkMaxStake::get() } - #[pallet::type_value] /// Default value for emission values. - pub fn DefaultEmissionValues() -> u64 { 0 } - #[pallet::type_value] /// Default value for pending emission. - pub fn DefaultPendingEmission() -> u64 { 0 } - #[pallet::type_value] /// Default value for blocks since last step. - pub fn DefaultBlocksSinceLastStep() -> u64 { 0 } - #[pallet::type_value] /// Default value for last mechanism step block. - pub fn DefaultLastMechanismStepBlock() -> u64 { 0 } - #[pallet::type_value] /// Default value for subnet owner. - pub fn DefaultSubnetOwner() -> T::AccountId { T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).expect("trailing zeroes always produce a valid account ID; qed") } - #[pallet::type_value] /// Default value for subnet locked. - pub fn DefaultSubnetLocked() -> u64 { 0 } - #[pallet::type_value] /// Default value for network tempo - pub fn DefaultTempo() -> u16 { T::InitialTempo::get() } - #[pallet::type_value] /// Default value for weights set rate limit. - pub fn DefaultWeightsSetRateLimit() -> u64 { 100 } - #[pallet::type_value] /// Default block number at registration. - pub fn DefaultBlockAtRegistration() -> u64 { 0 } - #[pallet::type_value] /// Default value for rho parameter. - pub fn DefaultRho() -> u16 { T::InitialRho::get() } - #[pallet::type_value] /// Default value for kappa parameter. - pub fn DefaultKappa() -> u16 { T::InitialKappa::get() } - #[pallet::type_value] /// Default maximum allowed UIDs. - pub fn DefaultMaxAllowedUids() -> u16 { T::InitialMaxAllowedUids::get() } - #[pallet::type_value] /// Default immunity period. - pub fn DefaultImmunityPeriod() -> u16 { T::InitialImmunityPeriod::get() } - #[pallet::type_value] /// Default activity cutoff. - pub fn DefaultActivityCutoff() -> u16 { T::InitialActivityCutoff::get() } - #[pallet::type_value] /// Default maximum weights limit. - pub fn DefaultMaxWeightsLimit() -> u16 { T::InitialMaxWeightsLimit::get() } - #[pallet::type_value] /// Default weights version key. - pub fn DefaultWeightsVersionKey() -> u64 { T::InitialWeightsVersionKey::get() } - #[pallet::type_value] /// Default minimum allowed weights. - pub fn DefaultMinAllowedWeights() -> u16 { T::InitialMinAllowedWeights::get() } - #[pallet::type_value] /// Default maximum allowed validators. - pub fn DefaultMaxAllowedValidators() -> u16 { T::InitialMaxAllowedValidators::get() } - #[pallet::type_value] /// Default adjustment interval. - pub fn DefaultAdjustmentInterval() -> u16 { T::InitialAdjustmentInterval::get() } - #[pallet::type_value] /// Default bonds moving average. - pub fn DefaultBondsMovingAverage() -> u64 { T::InitialBondsMovingAverage::get() } - #[pallet::type_value] /// Default validator prune length. - pub fn DefaultValidatorPruneLen() -> u64 { T::InitialValidatorPruneLen::get() } - #[pallet::type_value] /// Default scaling law power. - pub fn DefaultScalingLawPower() -> u16 { T::InitialScalingLawPower::get() } - #[pallet::type_value] /// Default target registrations per interval. - pub fn DefaultTargetRegistrationsPerInterval() -> u16 { T::InitialTargetRegistrationsPerInterval::get() } - #[pallet::type_value] /// Default adjustment alpha. - pub fn DefaultAdjustmentAlpha() -> u64 { T::InitialAdjustmentAlpha::get() } - #[pallet::type_value] /// Default minimum stake for weights. - pub fn DefaultWeightsMinStake() -> u64 { 0 } - #[pallet::type_value] /// Value definition for vector of u16. - pub fn EmptyU16Vec() -> Vec { vec![] } - #[pallet::type_value] /// Value definition for vector of u64. - pub fn EmptyU64Vec() -> Vec { vec![] } - #[pallet::type_value] /// Value definition for vector of bool. - pub fn EmptyBoolVec() -> Vec { vec![] } - #[pallet::type_value] /// Value definition for bonds with type vector of (u16, u16). - pub fn DefaultBonds() -> Vec<(u16, u16)> { vec![] } - #[pallet::type_value] /// Value definition for weights with vector of (u16, u16). - pub fn DefaultWeights() -> Vec<(u16, u16)> { vec![] } - #[pallet::type_value] /// Default value for key with type T::AccountId derived from trailing zeroes. - pub fn DefaultKey() -> T::AccountId { T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).expect("trailing zeroes always produce a valid account ID; qed") } - #[pallet::type_value] /// Default value for network immunity period. - pub fn DefaultHotkeyEmissionTempo() -> u64 { 7200 } - #[pallet::type_value] /// Default value for rate limiting - pub fn DefaultTxRateLimit() -> u64 { T::InitialTxRateLimit::get() } - #[pallet::type_value] /// Default value for delegate take rate limiting - pub fn DefaultTxDelegateTakeRateLimit() -> u64 { T::InitialTxDelegateTakeRateLimit::get() } - #[pallet::type_value] /// Default value for last extrinsic block. - pub fn DefaultLastTxBlock() -> u64 { 0 } - #[pallet::type_value] /// Default value for serving rate limit. - pub fn DefaultServingRateLimit() -> u64 { T::InitialServingRateLimit::get() } - #[pallet::type_value] /// Default value for weight commit reveal interval. - pub fn DefaultWeightCommitRevealInterval() -> u64 { 1000 } - #[pallet::type_value] /// Default value for weight commit/reveal enabled. - pub fn DefaultCommitRevealWeightsEnabled() -> bool { false } - #[pallet::type_value] /// Senate requirements - pub fn DefaultSenateRequiredStakePercentage() -> u64 { T::InitialSenateRequiredStakePercentage::get() } - #[pallet::type_value] /// -- ITEM (switches liquid alpha on) - pub fn DefaultLiquidAlpha() -> bool {false} - #[pallet::type_value] /// (alpha_low: 0.7, alpha_high: 0.9) - pub fn DefaultAlphaValues() -> (u16, u16) { (45875, 58982) } - - #[pallet::storage] - pub type SenateRequiredStakePercentage = StorageValue<_, u64, ValueQuery, DefaultSenateRequiredStakePercentage>; + #[pallet::type_value] + /// Default value for emission values. + pub fn DefaultEmissionValues() -> u64 { + 0 + } + #[pallet::type_value] + /// Default value for pending emission. + pub fn DefaultPendingEmission() -> u64 { + 0 + } + #[pallet::type_value] + /// Default value for blocks since last step. + pub fn DefaultBlocksSinceLastStep() -> u64 { + 0 + } + #[pallet::type_value] + /// Default value for last mechanism step block. + pub fn DefaultLastMechanismStepBlock() -> u64 { + 0 + } + #[pallet::type_value] + /// Default value for subnet owner. + pub fn DefaultSubnetOwner() -> T::AccountId { + T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) + .expect("trailing zeroes always produce a valid account ID; qed") + } + #[pallet::type_value] + /// Default value for subnet locked. + pub fn DefaultSubnetLocked() -> u64 { + 0 + } + #[pallet::type_value] + /// Default value for network tempo + pub fn DefaultTempo() -> u16 { + T::InitialTempo::get() + } + #[pallet::type_value] + /// Default value for weights set rate limit. + pub fn DefaultWeightsSetRateLimit() -> u64 { + 100 + } + #[pallet::type_value] + /// Default block number at registration. + pub fn DefaultBlockAtRegistration() -> u64 { + 0 + } + #[pallet::type_value] + /// Default value for rho parameter. + pub fn DefaultRho() -> u16 { + T::InitialRho::get() + } + #[pallet::type_value] + /// Default value for kappa parameter. + pub fn DefaultKappa() -> u16 { + T::InitialKappa::get() + } + #[pallet::type_value] + /// Default maximum allowed UIDs. + pub fn DefaultMaxAllowedUids() -> u16 { + T::InitialMaxAllowedUids::get() + } + #[pallet::type_value] + /// Default immunity period. + pub fn DefaultImmunityPeriod() -> u16 { + T::InitialImmunityPeriod::get() + } + #[pallet::type_value] + /// Default activity cutoff. + pub fn DefaultActivityCutoff() -> u16 { + T::InitialActivityCutoff::get() + } + #[pallet::type_value] + /// Default maximum weights limit. + pub fn DefaultMaxWeightsLimit() -> u16 { + T::InitialMaxWeightsLimit::get() + } + #[pallet::type_value] + /// Default weights version key. + pub fn DefaultWeightsVersionKey() -> u64 { + T::InitialWeightsVersionKey::get() + } + #[pallet::type_value] + /// Default minimum allowed weights. + pub fn DefaultMinAllowedWeights() -> u16 { + T::InitialMinAllowedWeights::get() + } + #[pallet::type_value] + /// Default maximum allowed validators. + pub fn DefaultMaxAllowedValidators() -> u16 { + T::InitialMaxAllowedValidators::get() + } + #[pallet::type_value] + /// Default adjustment interval. + pub fn DefaultAdjustmentInterval() -> u16 { + T::InitialAdjustmentInterval::get() + } + #[pallet::type_value] + /// Default bonds moving average. + pub fn DefaultBondsMovingAverage() -> u64 { + T::InitialBondsMovingAverage::get() + } + #[pallet::type_value] + /// Default validator prune length. + pub fn DefaultValidatorPruneLen() -> u64 { + T::InitialValidatorPruneLen::get() + } + #[pallet::type_value] + /// Default scaling law power. + pub fn DefaultScalingLawPower() -> u16 { + T::InitialScalingLawPower::get() + } + #[pallet::type_value] + /// Default target registrations per interval. + pub fn DefaultTargetRegistrationsPerInterval() -> u16 { + T::InitialTargetRegistrationsPerInterval::get() + } + #[pallet::type_value] + /// Default adjustment alpha. + pub fn DefaultAdjustmentAlpha() -> u64 { + T::InitialAdjustmentAlpha::get() + } + #[pallet::type_value] + /// Default minimum stake for weights. + pub fn DefaultWeightsMinStake() -> u64 { + 0 + } + #[pallet::type_value] + /// Value definition for vector of u16. + pub fn EmptyU16Vec() -> Vec { + vec![] + } + #[pallet::type_value] + /// Value definition for vector of u64. + pub fn EmptyU64Vec() -> Vec { + vec![] + } + #[pallet::type_value] + /// Value definition for vector of bool. + pub fn EmptyBoolVec() -> Vec { + vec![] + } + #[pallet::type_value] + /// Value definition for bonds with type vector of (u16, u16). + pub fn DefaultBonds() -> Vec<(u16, u16)> { + vec![] + } + #[pallet::type_value] + /// Value definition for weights with vector of (u16, u16). + pub fn DefaultWeights() -> Vec<(u16, u16)> { + vec![] + } + #[pallet::type_value] + /// Default value for key with type T::AccountId derived from trailing zeroes. + pub fn DefaultKey() -> T::AccountId { + T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) + .expect("trailing zeroes always produce a valid account ID; qed") + } + #[pallet::type_value] + /// Default value for network immunity period. + pub fn DefaultHotkeyEmissionTempo() -> u64 { + 7200 + } + #[pallet::type_value] + /// Default value for rate limiting + pub fn DefaultTxRateLimit() -> u64 { + T::InitialTxRateLimit::get() + } + #[pallet::type_value] + /// Default value for delegate take rate limiting + pub fn DefaultTxDelegateTakeRateLimit() -> u64 { + T::InitialTxDelegateTakeRateLimit::get() + } + #[pallet::type_value] + /// Default value for last extrinsic block. + pub fn DefaultLastTxBlock() -> u64 { + 0 + } + #[pallet::type_value] + /// Default value for serving rate limit. + pub fn DefaultServingRateLimit() -> u64 { + T::InitialServingRateLimit::get() + } + #[pallet::type_value] + /// Default value for weight commit reveal interval. + pub fn DefaultWeightCommitRevealInterval() -> u64 { + 1000 + } + #[pallet::type_value] + /// Default value for weight commit/reveal enabled. + pub fn DefaultCommitRevealWeightsEnabled() -> bool { + false + } + #[pallet::type_value] + /// Senate requirements + pub fn DefaultSenateRequiredStakePercentage() -> u64 { + T::InitialSenateRequiredStakePercentage::get() + } + #[pallet::type_value] + /// -- ITEM (switches liquid alpha on) + pub fn DefaultLiquidAlpha() -> bool { + false + } + #[pallet::type_value] + /// (alpha_low: 0.7, alpha_high: 0.9) + pub fn DefaultAlphaValues() -> (u16, u16) { + (45875, 58982) + } + + #[pallet::storage] + pub type SenateRequiredStakePercentage = + StorageValue<_, u64, ValueQuery, DefaultSenateRequiredStakePercentage>; /// ============================ /// ==== Staking Variables ==== @@ -324,227 +573,499 @@ pub mod pallet { #[pallet::storage] // --- ITEM ( global_block_emission ) pub type BlockEmission = StorageValue<_, u64, ValueQuery, DefaultBlockEmission>; #[pallet::storage] // --- ITEM (target_stakes_per_interval) - pub type TargetStakesPerInterval = StorageValue<_, u64, ValueQuery, DefaultTargetStakesPerInterval>; + pub type TargetStakesPerInterval = + StorageValue<_, u64, ValueQuery, DefaultTargetStakesPerInterval>; #[pallet::storage] // --- ITEM (default_stake_interval) pub type StakeInterval = StorageValue<_, u64, ValueQuery, DefaultStakeInterval>; #[pallet::storage] // --- MAP ( hot ) --> stake | Returns the total amount of stake under a hotkey. - pub type TotalHotkeyStake = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultAccountTake>; + pub type TotalHotkeyStake = + StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultAccountTake>; #[pallet::storage] // --- MAP ( cold ) --> stake | Returns the total amount of stake under a coldkey. - pub type TotalColdkeyStake = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultAccountTake>; - #[pallet::storage] /// MAP (hot, cold) --> stake | Returns a tuple (u64: stakes, u64: block_number) - pub type TotalHotkeyColdkeyStakesThisInterval = StorageDoubleMap<_, Identity, T::AccountId, Identity, T::AccountId, (u64, u64), ValueQuery, DefaultStakesPerInterval>; - #[pallet::storage] /// MAP ( hot ) --> cold | Returns the controlling coldkey for a hotkey. - pub type Owner = StorageMap<_, Blake2_128Concat, T::AccountId, T::AccountId, ValueQuery, DefaultAccount>; - #[pallet::storage] /// MAP ( hot ) --> take | Returns the hotkey delegation take. And signals that this key is open for delegation. - pub type Delegates = StorageMap<_, Blake2_128Concat, T::AccountId, u16, ValueQuery, DefaultDefaultTake>; - #[pallet::storage] /// DMAP ( hot, cold ) --> stake | Returns the stake under a coldkey prefixed by hotkey. - pub type Stake = StorageDoubleMap<_, Blake2_128Concat, T::AccountId, Identity, T::AccountId, u64, ValueQuery, DefaultAccountTake>; - #[pallet::storage] /// Map ( hot ) --> last_hotkey_emission_drain | Last block we drained this hotkey's emission. - pub type LastHotkeyEmissionDrain = StorageMap<_, Blake2_128Concat, T::AccountId, u64, ValueQuery, DefaultAccumulatedEmission>; - #[pallet::storage] /// ITEM ( hotkey_emission_tempo ) - pub type HotkeyEmissionTempo = StorageValue<_, u64, ValueQuery, DefaultHotkeyEmissionTempo>; - #[pallet::storage] /// Map ( hot ) --> emission | Accumulated hotkey emission. - pub type PendingdHotkeyEmission = StorageMap<_, Blake2_128Concat, T::AccountId, u64, ValueQuery, DefaultAccumulatedEmission>; - #[pallet::storage] /// Map ( hot, cold ) --> block_number | Last add stake increase. - pub type LastAddStakeIncrease = StorageDoubleMap<_, Blake2_128Concat, T::AccountId, Identity, T::AccountId, u64, ValueQuery, DefaultAccountTake>; - #[pallet::storage] /// DMAP ( parent, netuid ) --> Vec<(proportion,child)> - pub type ChildKeys = StorageDoubleMap<_, Blake2_128Concat, T::AccountId, Identity, u16, Vec<(u64, T::AccountId)>, ValueQuery, DefaultAccountLinkage>; - #[pallet::storage] /// DMAP ( child, netuid ) --> Vec<(proportion,parent)> - pub type ParentKeys = StorageDoubleMap<_, Blake2_128Concat, T::AccountId, Identity, u16, Vec<(u64, T::AccountId)>, ValueQuery, DefaultAccountLinkage>; + pub type TotalColdkeyStake = + StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultAccountTake>; + #[pallet::storage] + /// MAP (hot, cold) --> stake | Returns a tuple (u64: stakes, u64: block_number) + pub type TotalHotkeyColdkeyStakesThisInterval = StorageDoubleMap< + _, + Identity, + T::AccountId, + Identity, + T::AccountId, + (u64, u64), + ValueQuery, + DefaultStakesPerInterval, + >; + #[pallet::storage] + /// MAP ( hot ) --> cold | Returns the controlling coldkey for a hotkey. + pub type Owner = + StorageMap<_, Blake2_128Concat, T::AccountId, T::AccountId, ValueQuery, DefaultAccount>; + #[pallet::storage] + /// MAP ( hot ) --> take | Returns the hotkey delegation take. And signals that this key is open for delegation. + pub type Delegates = + StorageMap<_, Blake2_128Concat, T::AccountId, u16, ValueQuery, DefaultDefaultTake>; + #[pallet::storage] + /// DMAP ( hot, cold ) --> stake | Returns the stake under a coldkey prefixed by hotkey. + pub type Stake = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Identity, + T::AccountId, + u64, + ValueQuery, + DefaultAccountTake, + >; + #[pallet::storage] + /// Map ( hot ) --> last_hotkey_emission_drain | Last block we drained this hotkey's emission. + pub type LastHotkeyEmissionDrain = StorageMap< + _, + Blake2_128Concat, + T::AccountId, + u64, + ValueQuery, + DefaultAccumulatedEmission, + >; + #[pallet::storage] + /// ITEM ( hotkey_emission_tempo ) + pub type HotkeyEmissionTempo = + StorageValue<_, u64, ValueQuery, DefaultHotkeyEmissionTempo>; + #[pallet::storage] + /// Map ( hot ) --> emission | Accumulated hotkey emission. + pub type PendingdHotkeyEmission = StorageMap< + _, + Blake2_128Concat, + T::AccountId, + u64, + ValueQuery, + DefaultAccumulatedEmission, + >; + #[pallet::storage] + /// Map ( hot, cold ) --> block_number | Last add stake increase. + pub type LastAddStakeIncrease = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Identity, + T::AccountId, + u64, + ValueQuery, + DefaultAccountTake, + >; + #[pallet::storage] + /// DMAP ( parent, netuid ) --> Vec<(proportion,child)> + pub type ChildKeys = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Identity, + u16, + Vec<(u64, T::AccountId)>, + ValueQuery, + DefaultAccountLinkage, + >; + #[pallet::storage] + /// DMAP ( child, netuid ) --> Vec<(proportion,parent)> + pub type ParentKeys = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Identity, + u16, + Vec<(u64, T::AccountId)>, + ValueQuery, + DefaultAccountLinkage, + >; #[pallet::storage] // --- DMAP ( cold ) --> Vec | Maps coldkey to hotkeys that stake to it - pub type StakingHotkeys = StorageMap<_, Blake2_128Concat, T::AccountId, Vec, ValueQuery>; + pub type StakingHotkeys = + StorageMap<_, Blake2_128Concat, T::AccountId, Vec, ValueQuery>; #[pallet::storage] // --- MAP ( cold ) --> Vec | Returns the vector of hotkeys controlled by this coldkey. - pub type OwnedHotkeys = StorageMap<_, Blake2_128Concat, T::AccountId, Vec, ValueQuery>; - + pub type OwnedHotkeys = + StorageMap<_, Blake2_128Concat, T::AccountId, Vec, ValueQuery>; /// ============================ /// ==== Global Parameters ===== /// ============================ - #[pallet::storage] /// --- StorageItem Global Used Work. + #[pallet::storage] + /// --- StorageItem Global Used Work. pub type UsedWork = StorageMap<_, Identity, Vec, u64, ValueQuery>; - #[pallet::storage] /// --- ITEM( global_max_registrations_per_block ) - pub type MaxRegistrationsPerBlock = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMaxRegistrationsPerBlock>; - #[pallet::storage] /// --- ITEM( maximum_number_of_networks ) + #[pallet::storage] + /// --- ITEM( global_max_registrations_per_block ) + pub type MaxRegistrationsPerBlock = + StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMaxRegistrationsPerBlock>; + #[pallet::storage] + /// --- ITEM( maximum_number_of_networks ) pub type SubnetLimit = StorageValue<_, u16, ValueQuery, DefaultSubnetLimit>; - #[pallet::storage] /// --- ITEM( total_number_of_existing_networks ) + #[pallet::storage] + /// --- ITEM( total_number_of_existing_networks ) pub type TotalNetworks = StorageValue<_, u16, ValueQuery>; - #[pallet::storage] /// ITEM( network_immunity_period ) - pub type NetworkImmunityPeriod = StorageValue<_, u64, ValueQuery, DefaultNetworkImmunityPeriod>; - #[pallet::storage] /// ITEM( network_last_registered_block ) - pub type NetworkLastRegistered = StorageValue<_, u64, ValueQuery, DefaultNetworkLastRegistered>; - #[pallet::storage] /// ITEM( network_min_allowed_uids ) - pub type NetworkMinAllowedUids = StorageValue<_, u16, ValueQuery, DefaultNetworkMinAllowedUids>; - #[pallet::storage] /// ITEM( min_network_lock_cost ) + #[pallet::storage] + /// ITEM( network_immunity_period ) + pub type NetworkImmunityPeriod = + StorageValue<_, u64, ValueQuery, DefaultNetworkImmunityPeriod>; + #[pallet::storage] + /// ITEM( network_last_registered_block ) + pub type NetworkLastRegistered = + StorageValue<_, u64, ValueQuery, DefaultNetworkLastRegistered>; + #[pallet::storage] + /// ITEM( network_min_allowed_uids ) + pub type NetworkMinAllowedUids = + StorageValue<_, u16, ValueQuery, DefaultNetworkMinAllowedUids>; + #[pallet::storage] + /// ITEM( min_network_lock_cost ) pub type NetworkMinLockCost = StorageValue<_, u64, ValueQuery, DefaultNetworkMinLockCost>; - #[pallet::storage] /// ITEM( last_network_lock_cost ) - pub type NetworkLastLockCost = StorageValue<_, u64, ValueQuery, DefaultNetworkMinLockCost>; - #[pallet::storage] /// ITEM( network_lock_reduction_interval ) - pub type NetworkLockReductionInterval = StorageValue<_, u64, ValueQuery, DefaultNetworkLockReductionInterval>; - #[pallet::storage] /// ITEM( subnet_owner_cut ) + #[pallet::storage] + /// ITEM( last_network_lock_cost ) + pub type NetworkLastLockCost = + StorageValue<_, u64, ValueQuery, DefaultNetworkMinLockCost>; + #[pallet::storage] + /// ITEM( network_lock_reduction_interval ) + pub type NetworkLockReductionInterval = + StorageValue<_, u64, ValueQuery, DefaultNetworkLockReductionInterval>; + #[pallet::storage] + /// ITEM( subnet_owner_cut ) pub type SubnetOwnerCut = StorageValue<_, u16, ValueQuery, DefaultSubnetOwnerCut>; - #[pallet::storage] /// ITEM( network_rate_limit ) + #[pallet::storage] + /// ITEM( network_rate_limit ) pub type NetworkRateLimit = StorageValue<_, u64, ValueQuery, DefaultNetworkRateLimit>; - #[pallet::storage] /// ITEM( nominator_min_required_stake ) - pub type NominatorMinRequiredStake = StorageValue<_, u64, ValueQuery, DefaultNominatorMinRequiredStake>; + #[pallet::storage] + /// ITEM( nominator_min_required_stake ) + pub type NominatorMinRequiredStake = + StorageValue<_, u64, ValueQuery, DefaultNominatorMinRequiredStake>; /// ============================ /// ==== Subnet Parameters ===== /// ============================ - #[pallet::storage] /// --- MAP ( netuid ) --> subnetwork_n (Number of UIDs in the network). + #[pallet::storage] + /// --- MAP ( netuid ) --> subnetwork_n (Number of UIDs in the network). pub type SubnetworkN = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultN>; - #[pallet::storage] /// --- MAP ( netuid ) --> modality TEXT: 0, IMAGE: 1, TENSOR: 2 + #[pallet::storage] + /// --- MAP ( netuid ) --> modality TEXT: 0, IMAGE: 1, TENSOR: 2 pub type NetworkModality = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultModality>; - #[pallet::storage] /// --- MAP ( netuid ) --> network_is_added - pub type NetworksAdded = StorageMap<_, Identity, u16, bool, ValueQuery, DefaultNeworksAdded>; - #[pallet::storage] /// --- DMAP ( hotkey, netuid ) --> bool - pub type IsNetworkMember = StorageDoubleMap<_, Blake2_128Concat, T::AccountId, Identity, u16, bool, ValueQuery, DefaultIsNetworkMember>; - #[pallet::storage] /// --- MAP ( netuid ) --> network_registration_allowed - pub type NetworkRegistrationAllowed = StorageMap<_, Identity, u16, bool, ValueQuery, DefaultRegistrationAllowed>; - #[pallet::storage] /// --- MAP ( netuid ) --> network_pow_allowed - pub type NetworkPowRegistrationAllowed = StorageMap<_, Identity, u16, bool, ValueQuery, DefaultRegistrationAllowed>; - #[pallet::storage] /// --- MAP ( netuid ) --> block_created - pub type NetworkRegisteredAt = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultNetworkRegisteredAt>; - #[pallet::storage] /// --- MAP ( netuid ) --> tempo + #[pallet::storage] + /// --- MAP ( netuid ) --> network_is_added + pub type NetworksAdded = + StorageMap<_, Identity, u16, bool, ValueQuery, DefaultNeworksAdded>; + #[pallet::storage] + /// --- DMAP ( hotkey, netuid ) --> bool + pub type IsNetworkMember = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Identity, + u16, + bool, + ValueQuery, + DefaultIsNetworkMember, + >; + #[pallet::storage] + /// --- MAP ( netuid ) --> network_registration_allowed + pub type NetworkRegistrationAllowed = + StorageMap<_, Identity, u16, bool, ValueQuery, DefaultRegistrationAllowed>; + #[pallet::storage] + /// --- MAP ( netuid ) --> network_pow_allowed + pub type NetworkPowRegistrationAllowed = + StorageMap<_, Identity, u16, bool, ValueQuery, DefaultRegistrationAllowed>; + #[pallet::storage] + /// --- MAP ( netuid ) --> block_created + pub type NetworkRegisteredAt = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultNetworkRegisteredAt>; + #[pallet::storage] + /// --- MAP ( netuid ) --> tempo pub type Tempo = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultTempo>; - #[pallet::storage] /// --- MAP ( netuid ) --> emission_values - pub type EmissionValues = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultEmissionValues>; - #[pallet::storage] /// --- MAP ( netuid ) --> pending_emission - pub type PendingEmission = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultPendingEmission>; - #[pallet::storage] /// --- MAP ( netuid ) --> blocks_since_last_step - pub type BlocksSinceLastStep = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultBlocksSinceLastStep>; - #[pallet::storage] /// --- MAP ( netuid ) --> last_mechanism_step_block - pub type LastMechansimStepBlock = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultLastMechanismStepBlock>; - #[pallet::storage] /// --- MAP ( netuid ) --> subnet_owner - pub type SubnetOwner = StorageMap<_, Identity, u16, T::AccountId, ValueQuery, DefaultSubnetOwner>; - #[pallet::storage] /// --- MAP ( netuid ) --> subnet_locked - pub type SubnetLocked = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultSubnetLocked>; - #[pallet::storage] /// --- MAP ( netuid ) --> serving_rate_limit - pub type ServingRateLimit = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultServingRateLimit>; - #[pallet::storage] /// --- MAP ( netuid ) --> Rho + #[pallet::storage] + /// --- MAP ( netuid ) --> emission_values + pub type EmissionValues = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultEmissionValues>; + #[pallet::storage] + /// --- MAP ( netuid ) --> pending_emission + pub type PendingEmission = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultPendingEmission>; + #[pallet::storage] + /// --- MAP ( netuid ) --> blocks_since_last_step + pub type BlocksSinceLastStep = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultBlocksSinceLastStep>; + #[pallet::storage] + /// --- MAP ( netuid ) --> last_mechanism_step_block + pub type LastMechansimStepBlock = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultLastMechanismStepBlock>; + #[pallet::storage] + /// --- MAP ( netuid ) --> subnet_owner + pub type SubnetOwner = + StorageMap<_, Identity, u16, T::AccountId, ValueQuery, DefaultSubnetOwner>; + #[pallet::storage] + /// --- MAP ( netuid ) --> subnet_locked + pub type SubnetLocked = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultSubnetLocked>; + #[pallet::storage] + /// --- MAP ( netuid ) --> serving_rate_limit + pub type ServingRateLimit = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultServingRateLimit>; + #[pallet::storage] + /// --- MAP ( netuid ) --> Rho pub type Rho = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultRho>; - #[pallet::storage] /// --- MAP ( netuid ) --> Kappa + #[pallet::storage] + /// --- MAP ( netuid ) --> Kappa pub type Kappa = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultKappa>; - #[pallet::storage] /// --- MAP ( netuid ) --> uid, we use to record uids to prune at next epoch. + #[pallet::storage] + /// --- MAP ( netuid ) --> uid, we use to record uids to prune at next epoch. pub type NeuronsToPruneAtNextEpoch = StorageMap<_, Identity, u16, u16, ValueQuery>; - #[pallet::storage] /// --- MAP ( netuid ) --> registrations_this_interval + #[pallet::storage] + /// --- MAP ( netuid ) --> registrations_this_interval pub type RegistrationsThisInterval = StorageMap<_, Identity, u16, u16, ValueQuery>; - #[pallet::storage] /// --- MAP ( netuid ) --> pow_registrations_this_interval - pub type POWRegistrationsThisInterval = StorageMap<_, Identity, u16, u16, ValueQuery>; - #[pallet::storage] /// --- MAP ( netuid ) --> burn_registrations_this_interval - pub type BurnRegistrationsThisInterval = StorageMap<_, Identity, u16, u16, ValueQuery>; - #[pallet::storage] /// --- MAP ( netuid ) --> max_allowed_uids - pub type MaxAllowedUids = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMaxAllowedUids>; - #[pallet::storage] /// --- MAP ( netuid ) --> immunity_period - pub type ImmunityPeriod = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultImmunityPeriod>; - #[pallet::storage] /// --- MAP ( netuid ) --> activity_cutoff - pub type ActivityCutoff = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultActivityCutoff>; - #[pallet::storage] /// --- MAP ( netuid ) --> max_weight_limit - pub type MaxWeightsLimit = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMaxWeightsLimit>; - #[pallet::storage] /// --- MAP ( netuid ) --> weights_version_key - pub type WeightsVersionKey = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultWeightsVersionKey>; - #[pallet::storage] /// --- MAP ( netuid ) --> min_allowed_weights - pub type MinAllowedWeights = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMinAllowedWeights>; - #[pallet::storage] /// --- MAP ( netuid ) --> max_allowed_validators - pub type MaxAllowedValidators = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMaxAllowedValidators>; - #[pallet::storage] /// --- MAP ( netuid ) --> adjustment_interval - pub type AdjustmentInterval = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultAdjustmentInterval>; - #[pallet::storage] /// --- MAP ( netuid ) --> bonds_moving_average - pub type BondsMovingAverage = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultBondsMovingAverage>; - #[pallet::storage] /// --- MAP ( netuid ) --> weights_set_rate_limit - pub type WeightsSetRateLimit = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultWeightsSetRateLimit>; - #[pallet::storage] /// --- MAP ( netuid ) --> validator_prune_len - pub type ValidatorPruneLen = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultValidatorPruneLen>; - #[pallet::storage] /// --- MAP ( netuid ) --> scaling_law_power - pub type ScalingLawPower = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultScalingLawPower>; - #[pallet::storage] /// --- MAP ( netuid ) --> target_registrations_this_interval - pub type TargetRegistrationsPerInterval = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultTargetRegistrationsPerInterval>; - #[pallet::storage] /// --- MAP ( netuid ) --> adjustment_alpha - pub type AdjustmentAlpha = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultAdjustmentAlpha>; - #[pallet::storage] /// --- MAP ( netuid ) --> interval - pub type WeightCommitRevealInterval = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultWeightCommitRevealInterval>; - #[pallet::storage] /// --- MAP ( netuid ) --> interval - pub type CommitRevealWeightsEnabled = StorageMap<_, Identity, u16, bool, ValueQuery, DefaultCommitRevealWeightsEnabled>; - #[pallet::storage] /// --- MAP ( netuid ) --> Burn + #[pallet::storage] + /// --- MAP ( netuid ) --> pow_registrations_this_interval + pub type POWRegistrationsThisInterval = + StorageMap<_, Identity, u16, u16, ValueQuery>; + #[pallet::storage] + /// --- MAP ( netuid ) --> burn_registrations_this_interval + pub type BurnRegistrationsThisInterval = + StorageMap<_, Identity, u16, u16, ValueQuery>; + #[pallet::storage] + /// --- MAP ( netuid ) --> max_allowed_uids + pub type MaxAllowedUids = + StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMaxAllowedUids>; + #[pallet::storage] + /// --- MAP ( netuid ) --> immunity_period + pub type ImmunityPeriod = + StorageMap<_, Identity, u16, u16, ValueQuery, DefaultImmunityPeriod>; + #[pallet::storage] + /// --- MAP ( netuid ) --> activity_cutoff + pub type ActivityCutoff = + StorageMap<_, Identity, u16, u16, ValueQuery, DefaultActivityCutoff>; + #[pallet::storage] + /// --- MAP ( netuid ) --> max_weight_limit + pub type MaxWeightsLimit = + StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMaxWeightsLimit>; + #[pallet::storage] + /// --- MAP ( netuid ) --> weights_version_key + pub type WeightsVersionKey = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultWeightsVersionKey>; + #[pallet::storage] + /// --- MAP ( netuid ) --> min_allowed_weights + pub type MinAllowedWeights = + StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMinAllowedWeights>; + #[pallet::storage] + /// --- MAP ( netuid ) --> max_allowed_validators + pub type MaxAllowedValidators = + StorageMap<_, Identity, u16, u16, ValueQuery, DefaultMaxAllowedValidators>; + #[pallet::storage] + /// --- MAP ( netuid ) --> adjustment_interval + pub type AdjustmentInterval = + StorageMap<_, Identity, u16, u16, ValueQuery, DefaultAdjustmentInterval>; + #[pallet::storage] + /// --- MAP ( netuid ) --> bonds_moving_average + pub type BondsMovingAverage = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultBondsMovingAverage>; + #[pallet::storage] + /// --- MAP ( netuid ) --> weights_set_rate_limit + pub type WeightsSetRateLimit = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultWeightsSetRateLimit>; + #[pallet::storage] + /// --- MAP ( netuid ) --> validator_prune_len + pub type ValidatorPruneLen = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultValidatorPruneLen>; + #[pallet::storage] + /// --- MAP ( netuid ) --> scaling_law_power + pub type ScalingLawPower = + StorageMap<_, Identity, u16, u16, ValueQuery, DefaultScalingLawPower>; + #[pallet::storage] + /// --- MAP ( netuid ) --> target_registrations_this_interval + pub type TargetRegistrationsPerInterval = + StorageMap<_, Identity, u16, u16, ValueQuery, DefaultTargetRegistrationsPerInterval>; + #[pallet::storage] + /// --- MAP ( netuid ) --> adjustment_alpha + pub type AdjustmentAlpha = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultAdjustmentAlpha>; + #[pallet::storage] + /// --- MAP ( netuid ) --> interval + pub type WeightCommitRevealInterval = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultWeightCommitRevealInterval>; + #[pallet::storage] + /// --- MAP ( netuid ) --> interval + pub type CommitRevealWeightsEnabled = + StorageMap<_, Identity, u16, bool, ValueQuery, DefaultCommitRevealWeightsEnabled>; + #[pallet::storage] + /// --- MAP ( netuid ) --> Burn pub type Burn = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultBurn>; - #[pallet::storage] /// --- MAP ( netuid ) --> Difficulty + #[pallet::storage] + /// --- MAP ( netuid ) --> Difficulty pub type Difficulty = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultDifficulty>; - #[pallet::storage] /// --- MAP ( netuid ) --> MinBurn + #[pallet::storage] + /// --- MAP ( netuid ) --> MinBurn pub type MinBurn = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultMinBurn>; - #[pallet::storage] /// --- MAP ( netuid ) --> MaxBurn + #[pallet::storage] + /// --- MAP ( netuid ) --> MaxBurn pub type MaxBurn = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultMaxBurn>; - #[pallet::storage] /// --- MAP ( netuid ) --> MinDifficulty - pub type MinDifficulty = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultMinDifficulty>; - #[pallet::storage] /// --- MAP ( netuid ) --> MaxDifficulty - pub type MaxDifficulty = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultMaxDifficulty>; - #[pallet::storage] /// --- MAP ( netuid ) --> Block at last adjustment. - pub type LastAdjustmentBlock = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultLastAdjustmentBlock>; - #[pallet::storage] /// --- MAP ( netuid ) --> Registrations of this Block. - pub type RegistrationsThisBlock = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultRegistrationsThisBlock>; - #[pallet::storage] /// --- MAP ( netuid ) --> global_RAO_recycled_for_registration - pub type RAORecycledForRegistration = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultRAORecycledForRegistration>; - #[pallet::storage] /// --- ITEM ( tx_rate_limit ) + #[pallet::storage] + /// --- MAP ( netuid ) --> MinDifficulty + pub type MinDifficulty = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultMinDifficulty>; + #[pallet::storage] + /// --- MAP ( netuid ) --> MaxDifficulty + pub type MaxDifficulty = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultMaxDifficulty>; + #[pallet::storage] + /// --- MAP ( netuid ) --> Block at last adjustment. + pub type LastAdjustmentBlock = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultLastAdjustmentBlock>; + #[pallet::storage] + /// --- MAP ( netuid ) --> Registrations of this Block. + pub type RegistrationsThisBlock = + StorageMap<_, Identity, u16, u16, ValueQuery, DefaultRegistrationsThisBlock>; + #[pallet::storage] + /// --- MAP ( netuid ) --> global_RAO_recycled_for_registration + pub type RAORecycledForRegistration = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultRAORecycledForRegistration>; + #[pallet::storage] + /// --- ITEM ( tx_rate_limit ) pub type TxRateLimit = StorageValue<_, u64, ValueQuery, DefaultTxRateLimit>; - #[pallet::storage] /// --- ITEM ( tx_rate_limit ) - pub type TxDelegateTakeRateLimit = StorageValue<_, u64, ValueQuery, DefaultTxDelegateTakeRateLimit>; - #[pallet::storage] /// --- MAP ( netuid ) --> Whether or not Liquid Alpha is enabled - pub type LiquidAlphaOn = StorageMap<_, Blake2_128Concat, u16, bool, ValueQuery, DefaultLiquidAlpha>; - #[pallet::storage] /// MAP ( netuid ) --> (alpha_low, alpha_high) - pub type AlphaValues = StorageMap<_, Identity, u16, (u16, u16), ValueQuery, DefaultAlphaValues>; - + #[pallet::storage] + /// --- ITEM ( tx_rate_limit ) + pub type TxDelegateTakeRateLimit = + StorageValue<_, u64, ValueQuery, DefaultTxDelegateTakeRateLimit>; + #[pallet::storage] + /// --- MAP ( netuid ) --> Whether or not Liquid Alpha is enabled + pub type LiquidAlphaOn = + StorageMap<_, Blake2_128Concat, u16, bool, ValueQuery, DefaultLiquidAlpha>; + #[pallet::storage] + /// MAP ( netuid ) --> (alpha_low, alpha_high) + pub type AlphaValues = + StorageMap<_, Identity, u16, (u16, u16), ValueQuery, DefaultAlphaValues>; /// ======================================= /// ==== Subnetwork Consensus Storage ==== /// ======================================= - #[pallet::storage] /// --- DMAP ( netuid, hotkey ) --> uid - pub type Uids = StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, u16, OptionQuery>; - #[pallet::storage] /// --- DMAP ( netuid, uid ) --> hotkey - pub type Keys = StorageDoubleMap<_, Identity, u16, Identity, u16, T::AccountId, ValueQuery, DefaultKey>; - #[pallet::storage] /// --- DMAP ( netuid ) --> (hotkey, se, ve) - pub type LoadedEmission = StorageMap<_, Identity, u16, Vec<(T::AccountId, u64, u64)>, OptionQuery>; - #[pallet::storage] /// --- DMAP ( netuid ) --> active - pub type Active = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyBoolVec>; - #[pallet::storage] /// --- DMAP ( netuid ) --> rank + #[pallet::storage] + /// --- DMAP ( netuid, hotkey ) --> uid + pub type Uids = + StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, u16, OptionQuery>; + #[pallet::storage] + /// --- DMAP ( netuid, uid ) --> hotkey + pub type Keys = + StorageDoubleMap<_, Identity, u16, Identity, u16, T::AccountId, ValueQuery, DefaultKey>; + #[pallet::storage] + /// --- DMAP ( netuid ) --> (hotkey, se, ve) + pub type LoadedEmission = + StorageMap<_, Identity, u16, Vec<(T::AccountId, u64, u64)>, OptionQuery>; + #[pallet::storage] + /// --- DMAP ( netuid ) --> active + pub type Active = + StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyBoolVec>; + #[pallet::storage] + /// --- DMAP ( netuid ) --> rank pub type Rank = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; - #[pallet::storage] /// --- DMAP ( netuid ) --> trust + #[pallet::storage] + /// --- DMAP ( netuid ) --> trust pub type Trust = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; - #[pallet::storage] /// --- DMAP ( netuid ) --> consensus - pub type Consensus = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; - #[pallet::storage] /// --- DMAP ( netuid ) --> incentive - pub type Incentive = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; - #[pallet::storage] /// --- DMAP ( netuid ) --> dividends - pub type Dividends = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; - #[pallet::storage] /// --- DMAP ( netuid ) --> emission - pub type Emission = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU64Vec>; - #[pallet::storage] /// --- DMAP ( netuid ) --> last_update - pub type LastUpdate = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU64Vec>; - #[pallet::storage] /// --- DMAP ( netuid ) --> validator_trust - pub type ValidatorTrust = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; - #[pallet::storage] /// --- DMAP ( netuid ) --> pruning_scores - pub type PruningScores = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; - #[pallet::storage] /// --- DMAP ( netuid ) --> validator_permit - pub type ValidatorPermit = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyBoolVec>; - #[pallet::storage] /// --- DMAP ( netuid, uid ) --> weights - pub type Weights = StorageDoubleMap<_, Identity, u16, Identity, u16, Vec<(u16, u16)>, ValueQuery, DefaultWeights>; - #[pallet::storage] /// --- DMAP ( netuid, uid ) --> bonds - pub type Bonds = StorageDoubleMap<_, Identity, u16, Identity, u16, Vec<(u16, u16)>, ValueQuery, DefaultBonds>; - #[pallet::storage] /// --- DMAP ( netuid, uid ) --> block_at_registration - pub type BlockAtRegistration = StorageDoubleMap<_, Identity, u16, Identity, u16, u64, ValueQuery, DefaultBlockAtRegistration>; - #[pallet::storage] /// --- MAP ( netuid, hotkey ) --> axon_info - pub type Axons = StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, AxonInfoOf, OptionQuery>; - #[pallet::storage] /// --- MAP ( netuid, hotkey ) --> prometheus_info - pub type Prometheus = StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, PrometheusInfoOf, OptionQuery>; + #[pallet::storage] + /// --- DMAP ( netuid ) --> consensus + pub type Consensus = + StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + #[pallet::storage] + /// --- DMAP ( netuid ) --> incentive + pub type Incentive = + StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + #[pallet::storage] + /// --- DMAP ( netuid ) --> dividends + pub type Dividends = + StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + #[pallet::storage] + /// --- DMAP ( netuid ) --> emission + pub type Emission = + StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU64Vec>; + #[pallet::storage] + /// --- DMAP ( netuid ) --> last_update + pub type LastUpdate = + StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU64Vec>; + #[pallet::storage] + /// --- DMAP ( netuid ) --> validator_trust + pub type ValidatorTrust = + StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + #[pallet::storage] + /// --- DMAP ( netuid ) --> pruning_scores + pub type PruningScores = + StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; + #[pallet::storage] + /// --- DMAP ( netuid ) --> validator_permit + pub type ValidatorPermit = + StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyBoolVec>; + #[pallet::storage] + /// --- DMAP ( netuid, uid ) --> weights + pub type Weights = StorageDoubleMap< + _, + Identity, + u16, + Identity, + u16, + Vec<(u16, u16)>, + ValueQuery, + DefaultWeights, + >; + #[pallet::storage] + /// --- DMAP ( netuid, uid ) --> bonds + pub type Bonds = StorageDoubleMap< + _, + Identity, + u16, + Identity, + u16, + Vec<(u16, u16)>, + ValueQuery, + DefaultBonds, + >; + #[pallet::storage] + /// --- DMAP ( netuid, uid ) --> block_at_registration + pub type BlockAtRegistration = StorageDoubleMap< + _, + Identity, + u16, + Identity, + u16, + u64, + ValueQuery, + DefaultBlockAtRegistration, + >; + #[pallet::storage] + /// --- MAP ( netuid, hotkey ) --> axon_info + pub type Axons = + StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, AxonInfoOf, OptionQuery>; + #[pallet::storage] + /// --- MAP ( netuid, hotkey ) --> prometheus_info + pub type Prometheus = StorageDoubleMap< + _, + Identity, + u16, + Blake2_128Concat, + T::AccountId, + PrometheusInfoOf, + OptionQuery, + >; /// ================================= /// ==== Axon / Promo Endpoints ===== /// ================================= - #[pallet::storage] /// --- MAP ( key ) --> last_block - pub type LastTxBlock = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; - #[pallet::storage] /// --- MAP ( key ) --> last_block - pub type LastTxBlockDelegateTake = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; - #[pallet::storage] /// ITEM( weights_min_stake ) + #[pallet::storage] + /// --- MAP ( key ) --> last_block + pub type LastTxBlock = + StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; + #[pallet::storage] + /// --- MAP ( key ) --> last_block + pub type LastTxBlockDelegateTake = + StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; + #[pallet::storage] + /// ITEM( weights_min_stake ) pub type WeightsMinStake = StorageValue<_, u64, ValueQuery, DefaultWeightsMinStake>; - #[pallet::storage] /// --- MAP (netuid, who) --> (hash, weight) | Returns the hash and weight committed by an account for a given netuid. - pub type WeightCommits = StorageDoubleMap<_, Twox64Concat, u16, Twox64Concat, T::AccountId, (H256, u64), OptionQuery>; + #[pallet::storage] + /// --- MAP (netuid, who) --> (hash, weight) | Returns the hash and weight committed by an account for a given netuid. + pub type WeightCommits = StorageDoubleMap< + _, + Twox64Concat, + u16, + Twox64Concat, + T::AccountId, + (H256, u64), + OptionQuery, + >; /// ================== /// ==== Genesis ===== /// ================== @@ -773,12 +1294,10 @@ where priority: Self::get_priority_vanilla(), ..Default::default() }), - Some(Call::dissolve_network { .. }) => { - Ok(ValidTransaction { - priority: Self::get_priority_vanilla(), - ..Default::default() - }) - } + Some(Call::dissolve_network { .. }) => Ok(ValidTransaction { + priority: Self::get_priority_vanilla(), + ..Default::default() + }), _ => Ok(ValidTransaction { priority: Self::get_priority_vanilla(), ..Default::default() diff --git a/pallets/subtensor/src/macros/config.rs b/pallets/subtensor/src/macros/config.rs index 4e3cf5d2a1..a640ecbb6b 100644 --- a/pallets/subtensor/src/macros/config.rs +++ b/pallets/subtensor/src/macros/config.rs @@ -169,4 +169,4 @@ mod config { #[pallet::constant] type LiquidAlphaOn: Get; } -} \ No newline at end of file +} diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 6d4c588e90..228bec6e4d 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -843,4 +843,4 @@ mod dispatches { Ok(()) } } -} \ No newline at end of file +} diff --git a/pallets/subtensor/src/macros/genesis.rs b/pallets/subtensor/src/macros/genesis.rs index 5fbf613d6a..9496678075 100644 --- a/pallets/subtensor/src/macros/genesis.rs +++ b/pallets/subtensor/src/macros/genesis.rs @@ -159,5 +159,4 @@ mod genesis { TargetRegistrationsPerInterval::::insert(root_netuid, 1); } } - -} \ No newline at end of file +} diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index 7e612fb4ed..b04a29ff63 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -72,4 +72,4 @@ mod hooks { weight } } -} \ No newline at end of file +} diff --git a/pallets/subtensor/src/macros/mod.rs b/pallets/subtensor/src/macros/mod.rs index d64983d528..e491ec8c40 100644 --- a/pallets/subtensor/src/macros/mod.rs +++ b/pallets/subtensor/src/macros/mod.rs @@ -1,6 +1,6 @@ -pub mod events; -pub mod errors; +pub mod config; pub mod dispatches; +pub mod errors; +pub mod events; pub mod genesis; pub mod hooks; -pub mod config; \ No newline at end of file diff --git a/pallets/subtensor/src/migrations/migrate_create_root_network.rs b/pallets/subtensor/src/migrations/migrate_create_root_network.rs index 20ee82f0a6..b4b003404c 100644 --- a/pallets/subtensor/src/migrations/migrate_create_root_network.rs +++ b/pallets/subtensor/src/migrations/migrate_create_root_network.rs @@ -2,7 +2,7 @@ use super::*; use frame_support::{ pallet_prelude::{Identity, OptionQuery}, storage_alias, - traits::{Get, DefensiveResult}, + traits::{DefensiveResult, Get}, weights::Weight, }; use sp_std::vec::Vec; @@ -96,4 +96,4 @@ pub fn migrate_create_root_network() -> Weight { } weight -} \ No newline at end of file +} diff --git a/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs b/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs index 23fbe122fb..c26c917a49 100644 --- a/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs +++ b/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs @@ -1,6 +1,7 @@ use super::*; use frame_support::{ - pallet_prelude::*, storage_alias, + pallet_prelude::*, + storage_alias, traits::{Get, GetStorageVersion, StorageVersion}, weights::Weight, }; @@ -124,4 +125,4 @@ pub fn migrate_delete_subnet_21() -> Weight { // TODO: Add unit tests for this migration // TODO: Consider adding error handling for storage operations -// TODO: Verify that all relevant storage items for subnet 21 are removed \ No newline at end of file +// TODO: Verify that all relevant storage items for subnet 21 are removed diff --git a/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs b/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs index 257752c197..bbe36db80b 100644 --- a/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs +++ b/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs @@ -1,6 +1,7 @@ use super::*; use frame_support::{ - pallet_prelude::*, storage_alias, + pallet_prelude::*, + storage_alias, traits::{Get, GetStorageVersion, StorageVersion}, weights::Weight, }; @@ -127,4 +128,4 @@ pub fn migrate_delete_subnet_3() -> Weight { // TODO: Add unit tests for this migration // TODO: Consider adding error handling for storage operations -// TODO: Verify that all relevant storage items for subnet 3 are removed \ No newline at end of file +// TODO: Verify that all relevant storage items for subnet 3 are removed diff --git a/pallets/subtensor/src/migrations/migrate_populate_owned_hotkeys.rs b/pallets/subtensor/src/migrations/migrate_populate_owned_hotkeys.rs index 23cf90d33a..e8fd212ec3 100644 --- a/pallets/subtensor/src/migrations/migrate_populate_owned_hotkeys.rs +++ b/pallets/subtensor/src/migrations/migrate_populate_owned_hotkeys.rs @@ -2,7 +2,7 @@ use super::*; use frame_support::{ pallet_prelude::{Identity, OptionQuery}, storage_alias, - traits::{Get}, + traits::Get, weights::Weight, }; use log::info; @@ -19,7 +19,6 @@ pub mod deprecated_loaded_emission_format { StorageMap, Identity, u16, Vec<(AccountIdOf, u64)>, OptionQuery>; } - /// Migrate the OwnedHotkeys map to the new storage format pub fn migrate_populate_owned() -> Weight { // Setup migration weight @@ -80,4 +79,4 @@ pub fn migrate_populate_owned() -> Weight { info!(target: LOG_TARGET_1, "Migration {} already done!", migration_name); Weight::zero() } -} \ No newline at end of file +} diff --git a/pallets/subtensor/src/migrations/migrate_populate_staking_hotkeys.rs b/pallets/subtensor/src/migrations/migrate_populate_staking_hotkeys.rs index 2c0988bbd3..0245ae3c9d 100644 --- a/pallets/subtensor/src/migrations/migrate_populate_staking_hotkeys.rs +++ b/pallets/subtensor/src/migrations/migrate_populate_staking_hotkeys.rs @@ -1,9 +1,8 @@ - use super::*; use frame_support::{ pallet_prelude::{Identity, OptionQuery}, storage_alias, - traits::{Get}, + traits::Get, weights::Weight, }; use log::info; @@ -19,7 +18,6 @@ pub mod deprecated_loaded_emission_format { StorageMap, Identity, u16, Vec<(AccountIdOf, u64)>, OptionQuery>; } - /// Populate the StakingHotkeys map from Stake map pub fn migrate_populate_staking_hotkeys() -> Weight { // Setup migration weight diff --git a/pallets/subtensor/src/migrations/migrate_to_v1_separate_emission.rs b/pallets/subtensor/src/migrations/migrate_to_v1_separate_emission.rs index 5db04f0bc5..5d28337dcb 100644 --- a/pallets/subtensor/src/migrations/migrate_to_v1_separate_emission.rs +++ b/pallets/subtensor/src/migrations/migrate_to_v1_separate_emission.rs @@ -1,6 +1,7 @@ use super::*; use frame_support::{ - pallet_prelude::*, storage_alias, + pallet_prelude::*, + storage_alias, traits::{Get, GetStorageVersion, StorageVersion}, weights::Weight, }; @@ -39,7 +40,7 @@ pub mod deprecated_loaded_emission_format { /// ``` pub fn migrate_to_v1_separate_emission() -> Weight { use deprecated_loaded_emission_format as old; - + // Initialize weight counter let mut weight = T::DbWeight::get().reads_writes(1, 0); @@ -55,7 +56,7 @@ pub fn migrate_to_v1_separate_emission() -> Weight { // Collect all network IDs (netuids) from old LoadedEmission storage let curr_loaded_emission: Vec = old::LoadedEmission::::iter_keys().collect(); - + // Remove any undecodable entries for netuid in curr_loaded_emission { weight.saturating_accrue(T::DbWeight::get().reads(1)); @@ -103,4 +104,4 @@ pub fn migrate_to_v1_separate_emission() -> Weight { // TODO: Add unit tests for this migration // TODO: Consider adding error handling for edge cases -// TODO: Verify that all possible states of the old format are handled correctly \ No newline at end of file +// TODO: Verify that all possible states of the old format are handled correctly diff --git a/pallets/subtensor/src/migrations/migrate_to_v2_fixed_total_stake.rs b/pallets/subtensor/src/migrations/migrate_to_v2_fixed_total_stake.rs index ef9fe8880a..f3e63b6fda 100644 --- a/pallets/subtensor/src/migrations/migrate_to_v2_fixed_total_stake.rs +++ b/pallets/subtensor/src/migrations/migrate_to_v2_fixed_total_stake.rs @@ -1,6 +1,7 @@ use super::*; use frame_support::{ - pallet_prelude::*, storage_alias, + pallet_prelude::*, + storage_alias, traits::{Get, GetStorageVersion, StorageVersion}, weights::Weight, }; @@ -71,7 +72,7 @@ pub fn migrate_to_v2_fixed_total_stake() -> Weight { // Recalculate TotalStake and TotalColdkeyStake based on the Stake map for (_, coldkey, stake) in Stake::::iter() { weight.saturating_accrue(T::DbWeight::get().reads(1)); - + // Update TotalColdkeyStake let mut total_coldkey_stake = TotalColdkeyStake::::get(coldkey.clone()); weight.saturating_accrue(T::DbWeight::get().reads(1)); @@ -100,4 +101,4 @@ pub fn migrate_to_v2_fixed_total_stake() -> Weight { // TODO: Add unit tests for this migration function // TODO: Consider adding error handling for potential arithmetic overflow -// TODO: Optimize the iteration over Stake map if possible to reduce database reads \ No newline at end of file +// TODO: Optimize the iteration over Stake map if possible to reduce database reads diff --git a/pallets/subtensor/src/migrations/migrate_total_issuance.rs b/pallets/subtensor/src/migrations/migrate_total_issuance.rs index 187967da35..9a40853795 100644 --- a/pallets/subtensor/src/migrations/migrate_total_issuance.rs +++ b/pallets/subtensor/src/migrations/migrate_total_issuance.rs @@ -1,4 +1,5 @@ use super::*; +use frame_support::pallet_prelude::OptionQuery; use frame_support::{ pallet_prelude::Identity, storage_alias, @@ -6,7 +7,6 @@ use frame_support::{ weights::Weight, }; use sp_std::vec::Vec; -use frame_support::pallet_prelude::OptionQuery; // TODO: Implement comprehensive tests for this migration @@ -43,14 +43,17 @@ pub fn migrate_total_issuance(test: bool) -> Weight { // Execute migration if the current storage version is 5 or if in test mode if Pallet::::on_chain_storage_version() == StorageVersion::new(5) || test { // Calculate the sum of all stake values - let stake_sum: u64 = Stake::::iter().fold(0, |acc, (_, _, stake)| acc.saturating_add(stake)); + let stake_sum: u64 = + Stake::::iter().fold(0, |acc, (_, _, stake)| acc.saturating_add(stake)); // Add weight for reading all stake entries weight = weight.saturating_add(T::DbWeight::get().reads(Stake::::iter().count() as u64)); // Calculate the sum of all locked subnet values - let locked_sum: u64 = SubnetLocked::::iter().fold(0, |acc, (_, locked)| acc.saturating_add(locked)); + let locked_sum: u64 = + SubnetLocked::::iter().fold(0, |acc, (_, locked)| acc.saturating_add(locked)); // Add weight for reading all subnet locked entries - weight = weight.saturating_add(T::DbWeight::get().reads(SubnetLocked::::iter().count() as u64)); + weight = weight + .saturating_add(T::DbWeight::get().reads(SubnetLocked::::iter().count() as u64)); // Retrieve the total balance sum let total_balance = T::Currency::total_issuance(); @@ -61,7 +64,9 @@ pub fn migrate_total_issuance(test: bool) -> Weight { match TryInto::::try_into(total_balance) { Ok(total_balance_sum) => { // Compute the total issuance value - let total_issuance_value: u64 = stake_sum.saturating_add(total_balance_sum).saturating_add(locked_sum); + let total_issuance_value: u64 = stake_sum + .saturating_add(total_balance_sum) + .saturating_add(locked_sum); // Update the total issuance in storage TotalIssuance::::put(total_issuance_value); @@ -81,4 +86,4 @@ pub fn migrate_total_issuance(test: bool) -> Weight { // Return the computed weight of the migration process weight -} \ No newline at end of file +} diff --git a/pallets/subtensor/src/migrations/migrate_transfer_ownership_to_foundation.rs b/pallets/subtensor/src/migrations/migrate_transfer_ownership_to_foundation.rs index 0ca4a7fa59..8d1bd437c6 100644 --- a/pallets/subtensor/src/migrations/migrate_transfer_ownership_to_foundation.rs +++ b/pallets/subtensor/src/migrations/migrate_transfer_ownership_to_foundation.rs @@ -84,4 +84,4 @@ pub fn migrate_transfer_ownership_to_foundation(coldkey: [u8; 32]) -> info!(target: LOG_TARGET, "Migration to v3 already completed"); Weight::zero() } -} \ No newline at end of file +} diff --git a/pallets/subtensor/src/migrations/mod.rs b/pallets/subtensor/src/migrations/mod.rs index cdc512d63d..df0f7ce066 100644 --- a/pallets/subtensor/src/migrations/mod.rs +++ b/pallets/subtensor/src/migrations/mod.rs @@ -1,11 +1,11 @@ use super::*; -pub mod migrate_delete_subnet_21; pub mod migrate_create_root_network; +pub mod migrate_delete_subnet_21; pub mod migrate_delete_subnet_3; +pub mod migrate_fix_total_coldkey_stake; +pub mod migrate_populate_owned_hotkeys; +pub mod migrate_populate_staking_hotkeys; pub mod migrate_to_v1_separate_emission; pub mod migrate_to_v2_fixed_total_stake; -pub mod migrate_transfer_ownership_to_foundation; pub mod migrate_total_issuance; -pub mod migrate_populate_owned_hotkeys; -pub mod migrate_populate_staking_hotkeys; -pub mod migrate_fix_total_coldkey_stake; \ No newline at end of file +pub mod migrate_transfer_ownership_to_foundation; diff --git a/pallets/subtensor/src/root.rs b/pallets/subtensor/src/root.rs index b3ac32f553..948c91f208 100644 --- a/pallets/subtensor/src/root.rs +++ b/pallets/subtensor/src/root.rs @@ -905,7 +905,6 @@ impl Pallet { // --- 0. Ensure the caller is a signed user. let coldkey = ensure_signed(origin)?; - // --- 1. Rate limit for network registrations. let current_block = Self::get_current_block_as_u64(); let last_lock_block = Self::get_network_last_lock_block(); @@ -993,7 +992,7 @@ impl Pallet { pub fn user_remove_network(origin: T::RuntimeOrigin, netuid: u16) -> dispatch::DispatchResult { // --- 1. Ensure the function caller is a signed user. let coldkey = ensure_signed(origin)?; - + // --- 2. Ensure this subnet exists. ensure!( Self::if_subnet_exist(netuid), diff --git a/pallets/subtensor/src/rpc_info/mod.rs b/pallets/subtensor/src/rpc_info/mod.rs index 70dc816cc7..7d050b6010 100644 --- a/pallets/subtensor/src/rpc_info/mod.rs +++ b/pallets/subtensor/src/rpc_info/mod.rs @@ -1,5 +1,5 @@ use super::*; +pub mod delegate_info; pub mod neuron_info; pub mod stake_info; pub mod subnet_info; -pub mod delegate_info; \ No newline at end of file diff --git a/pallets/subtensor/src/staking/add_stake.rs b/pallets/subtensor/src/staking/add_stake.rs index 89104de82d..a2e7ccdc48 100644 --- a/pallets/subtensor/src/staking/add_stake.rs +++ b/pallets/subtensor/src/staking/add_stake.rs @@ -122,4 +122,4 @@ impl Pallet { // Ok and return. Ok(()) } -} \ No newline at end of file +} diff --git a/pallets/subtensor/src/staking/helpers.rs b/pallets/subtensor/src/staking/helpers.rs index 6da16e8334..92aa394ed2 100644 --- a/pallets/subtensor/src/staking/helpers.rs +++ b/pallets/subtensor/src/staking/helpers.rs @@ -11,7 +11,6 @@ use frame_support::{ }; impl Pallet { - // Returns true if the passed hotkey allow delegative staking. // pub fn hotkey_is_delegate(hotkey: &T::AccountId) -> bool { diff --git a/pallets/subtensor/src/staking/increase_take.rs b/pallets/subtensor/src/staking/increase_take.rs index 744027a9bd..d5140b6565 100644 --- a/pallets/subtensor/src/staking/increase_take.rs +++ b/pallets/subtensor/src/staking/increase_take.rs @@ -1,4 +1,3 @@ - use super::*; use frame_support::{ storage::IterableStorageDoubleMap, @@ -96,4 +95,4 @@ impl Pallet { // --- 8. Ok and return. Ok(()) } -} \ No newline at end of file +} diff --git a/pallets/subtensor/src/staking/mod.rs b/pallets/subtensor/src/staking/mod.rs index 7015b455a8..5e1b5f6bf4 100644 --- a/pallets/subtensor/src/staking/mod.rs +++ b/pallets/subtensor/src/staking/mod.rs @@ -1,7 +1,7 @@ use super::*; -pub mod helpers; pub mod add_stake; -pub mod remove_stake; +pub mod become_delegate; pub mod decrease_take; +pub mod helpers; pub mod increase_take; -pub mod become_delegate; \ No newline at end of file +pub mod remove_stake; diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs index 5f467e009f..59e96777b9 100644 --- a/pallets/subtensor/src/staking/remove_stake.rs +++ b/pallets/subtensor/src/staking/remove_stake.rs @@ -1,4 +1,3 @@ - use super::*; use frame_support::{ storage::IterableStorageDoubleMap, @@ -117,4 +116,4 @@ impl Pallet { // Done and ok. Ok(()) } -} \ No newline at end of file +} diff --git a/pallets/subtensor/src/swap/mod.rs b/pallets/subtensor/src/swap/mod.rs index 0e71b1b1de..4e4b929074 100644 --- a/pallets/subtensor/src/swap/mod.rs +++ b/pallets/subtensor/src/swap/mod.rs @@ -1,3 +1,3 @@ use super::*; pub mod swap_coldkey; -pub mod swap_hotkey; \ No newline at end of file +pub mod swap_hotkey; diff --git a/pallets/subtensor/src/swap/swap_coldkey.rs b/pallets/subtensor/src/swap/swap_coldkey.rs index 78508f9c55..8651f0076b 100644 --- a/pallets/subtensor/src/swap/swap_coldkey.rs +++ b/pallets/subtensor/src/swap/swap_coldkey.rs @@ -5,8 +5,6 @@ use frame_support::weights::Weight; use sp_core::Get; impl Pallet { - - /// Swaps the coldkey associated with a set of hotkeys from an old coldkey to a new coldkey. /// /// # Arguments @@ -130,7 +128,6 @@ impl Pallet { Ok(weight) } - /// Swaps the total stake associated with a coldkey from the old coldkey to the new coldkey. /// /// # Arguments @@ -387,5 +384,4 @@ impl Pallet { } weight.saturating_accrue(T::DbWeight::get().reads(TotalNetworks::::get() as u64)); } - } diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index 2755f1c4cb..cf279ca10f 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -92,7 +92,7 @@ impl Pallet { Ok(Some(weight).into()) } - + /// Retrieves the network membership status for a given hotkey. /// /// # Arguments @@ -422,7 +422,6 @@ impl Pallet { } } - pub fn swap_senate_member( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, diff --git a/pallets/subtensor/tests/staking.rs b/pallets/subtensor/tests/staking.rs index a923a70103..ece30391d1 100644 --- a/pallets/subtensor/tests/staking.rs +++ b/pallets/subtensor/tests/staking.rs @@ -3383,4 +3383,4 @@ fn test_get_total_delegated_stake_exclude_owner_stake() { expected_delegated_stake, actual_delegated_stake ); }); -} \ No newline at end of file +} diff --git a/pallets/subtensor/tests/swap.rs b/pallets/subtensor/tests/swap.rs index 1d05b1c512..7b32a947bd 100644 --- a/pallets/subtensor/tests/swap.rs +++ b/pallets/subtensor/tests/swap.rs @@ -88,8 +88,12 @@ fn test_do_swap_hotkey_ok() { // IsNetworkMember for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight) { - assert!(pallet_subtensor::IsNetworkMember::::contains_key(new_hotkey, netuid)); - assert!(!pallet_subtensor::IsNetworkMember::::contains_key(old_hotkey, netuid)); + assert!(pallet_subtensor::IsNetworkMember::::contains_key( + new_hotkey, netuid + )); + assert!(!pallet_subtensor::IsNetworkMember::::contains_key( + old_hotkey, netuid + )); } // Owner @@ -123,8 +127,12 @@ fn test_do_swap_hotkey_ok() { // TotalHotkeyColdkeyStakesThisInterval assert_eq!( - pallet_subtensor::TotalHotkeyColdkeyStakesThisInterval::::get(new_hotkey, coldkey), - pallet_subtensor::TotalHotkeyColdkeyStakesThisInterval::::get(old_hotkey, coldkey) + pallet_subtensor::TotalHotkeyColdkeyStakesThisInterval::::get( + new_hotkey, coldkey + ), + pallet_subtensor::TotalHotkeyColdkeyStakesThisInterval::::get( + old_hotkey, coldkey + ) ); }); } @@ -226,8 +234,13 @@ fn test_do_swap_hotkey_ok_robust() { // Verify raw storage maps // Stake - for (coldkey, stake_amount) in pallet_subtensor::Stake::::iter_prefix(old_hotkeys[i]) { - assert_eq!(pallet_subtensor::Stake::::get(new_hotkeys[i], coldkey), stake_amount); + for (coldkey, stake_amount) in + pallet_subtensor::Stake::::iter_prefix(old_hotkeys[i]) + { + assert_eq!( + pallet_subtensor::Stake::::get(new_hotkeys[i], coldkey), + stake_amount + ); } let mut weight = Weight::zero(); @@ -276,12 +289,18 @@ fn test_do_swap_hotkey_ok_robust() { } // Owner - assert_eq!(pallet_subtensor::Owner::::get(new_hotkeys[i]), coldkeys[i]); + assert_eq!( + pallet_subtensor::Owner::::get(new_hotkeys[i]), + coldkeys[i] + ); // Keys for (uid, hotkey) in pallet_subtensor::Keys::::iter_prefix(netuid) { if hotkey == old_hotkeys[i] { - assert_eq!(pallet_subtensor::Keys::::get(netuid, uid), new_hotkeys[i]); + assert_eq!( + pallet_subtensor::Keys::::get(netuid, uid), + new_hotkeys[i] + ); } } @@ -738,8 +757,13 @@ fn test_swap_axons_success() { // Verify the swap for netuid in &netuid_is_member { - assert_eq!(pallet_subtensor::Axons::::get(netuid, new_hotkey).unwrap(), axon_info); - assert!(!pallet_subtensor::Axons::::contains_key(netuid, old_hotkey)); + assert_eq!( + pallet_subtensor::Axons::::get(netuid, new_hotkey).unwrap(), + axon_info + ); + assert!(!pallet_subtensor::Axons::::contains_key( + netuid, old_hotkey + )); } }); } @@ -924,8 +948,13 @@ fn test_swap_uids_success() { // Verify the swap for netuid in &netuid_is_member { - assert_eq!(pallet_subtensor::Uids::::get(netuid, new_hotkey).unwrap(), uid); - assert!(!pallet_subtensor::Uids::::contains_key(netuid, old_hotkey)); + assert_eq!( + pallet_subtensor::Uids::::get(netuid, new_hotkey).unwrap(), + uid + ); + assert!(!pallet_subtensor::Uids::::contains_key( + netuid, old_hotkey + )); } }); } @@ -970,7 +999,11 @@ fn test_swap_prometheus_success() { // Initialize Prometheus for old_hotkey for netuid in &netuid_is_member { - pallet_subtensor::Prometheus::::insert(netuid, old_hotkey, prometheus_info.clone()); + pallet_subtensor::Prometheus::::insert( + netuid, + old_hotkey, + prometheus_info.clone(), + ); } // Perform the swap @@ -982,7 +1015,9 @@ fn test_swap_prometheus_success() { pallet_subtensor::Prometheus::::get(netuid, new_hotkey).unwrap(), prometheus_info ); - assert!(!pallet_subtensor::Prometheus::::contains_key(netuid, old_hotkey)); + assert!(!pallet_subtensor::Prometheus::::contains_key( + netuid, old_hotkey + )); } }); } @@ -1004,7 +1039,11 @@ fn test_swap_prometheus_weight_update() { // Initialize Prometheus for old_hotkey for netuid in &netuid_is_member { - pallet_subtensor::Prometheus::::insert(netuid, old_hotkey, prometheus_info.clone()); + pallet_subtensor::Prometheus::::insert( + netuid, + old_hotkey, + prometheus_info.clone(), + ); } // Perform the swap From 4270cc4b816a86c75981da5a7504f0890c5494c8 Mon Sep 17 00:00:00 2001 From: const Date: Mon, 15 Jul 2024 14:20:33 -0500 Subject: [PATCH 05/16] clippy fmt --- pallets/subtensor/src/epoch/mod.rs | 2 +- .../src/epoch/{epoch.rs => run_epoch.rs} | 0 pallets/subtensor/src/macros/genesis.rs | 8 +-- .../migrations/migrate_create_root_network.rs | 2 +- .../migrations/migrate_delete_subnet_21.rs | 2 +- .../src/migrations/migrate_delete_subnet_3.rs | 2 +- pallets/subtensor/src/staking/add_stake.rs | 11 +--- .../subtensor/src/staking/become_delegate.rs | 11 +--- .../subtensor/src/staking/decrease_take.rs | 11 +--- pallets/subtensor/src/staking/helpers.rs | 62 ++++++++++++++----- .../subtensor/src/staking/increase_take.rs | 11 +--- pallets/subtensor/src/staking/remove_stake.rs | 11 +--- 12 files changed, 61 insertions(+), 72 deletions(-) rename pallets/subtensor/src/epoch/{epoch.rs => run_epoch.rs} (100%) diff --git a/pallets/subtensor/src/epoch/mod.rs b/pallets/subtensor/src/epoch/mod.rs index 723e68ee4f..3b22f940e6 100644 --- a/pallets/subtensor/src/epoch/mod.rs +++ b/pallets/subtensor/src/epoch/mod.rs @@ -1,3 +1,3 @@ use super::*; -pub mod epoch; pub mod math; +pub mod run_epoch; diff --git a/pallets/subtensor/src/epoch/epoch.rs b/pallets/subtensor/src/epoch/run_epoch.rs similarity index 100% rename from pallets/subtensor/src/epoch/epoch.rs rename to pallets/subtensor/src/epoch/run_epoch.rs diff --git a/pallets/subtensor/src/macros/genesis.rs b/pallets/subtensor/src/macros/genesis.rs index 9496678075..34a888f280 100644 --- a/pallets/subtensor/src/macros/genesis.rs +++ b/pallets/subtensor/src/macros/genesis.rs @@ -77,7 +77,7 @@ mod genesis { // Set max allowed uids MaxAllowedUids::::insert(netuid, max_uids); - let mut next_uid = 0; + let mut next_uid: u16 = 0; for (coldkey, hotkeys) in self.stakes.iter() { for (hotkey, stake_uid) in hotkeys.iter() { @@ -116,7 +116,7 @@ mod genesis { Stake::::insert(hotkey.clone(), coldkey.clone(), stake); - next_uid += 1; + next_uid = next_uid.saturating_add(1); } } @@ -124,7 +124,7 @@ mod genesis { SubnetworkN::::insert(netuid, next_uid); // --- Increase total network count. - TotalNetworks::::mutate(|n| *n += 1); + TotalNetworks::::mutate(|n| n.saturating_add( 1 )); // Get the root network uid. let root_netuid: u16 = 0; @@ -133,7 +133,7 @@ mod genesis { NetworksAdded::::insert(root_netuid, true); // Increment the number of total networks. - TotalNetworks::::mutate(|n| *n += 1); + TotalNetworks::::mutate(|n| n.saturating_add(1)); // Set the number of validators to 1. SubnetworkN::::insert(root_netuid, 0); diff --git a/pallets/subtensor/src/migrations/migrate_create_root_network.rs b/pallets/subtensor/src/migrations/migrate_create_root_network.rs index b4b003404c..fa9f343018 100644 --- a/pallets/subtensor/src/migrations/migrate_create_root_network.rs +++ b/pallets/subtensor/src/migrations/migrate_create_root_network.rs @@ -55,7 +55,7 @@ pub fn migrate_create_root_network() -> Weight { NetworksAdded::::insert(root_netuid, true); // Increment the total number of networks - TotalNetworks::::mutate(|n| *n += 1); + TotalNetworks::::mutate(|n| n.saturating_add( 1 )); // Set the maximum number of UIDs to the number of senate members MaxAllowedUids::::insert(root_netuid, 64); diff --git a/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs b/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs index c26c917a49..011d79de14 100644 --- a/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs +++ b/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs @@ -66,7 +66,7 @@ pub fn migrate_delete_subnet_21() -> Weight { NetworksAdded::::remove(netuid); // Decrement the network counter - TotalNetworks::::mutate(|n| *n -= 1); + TotalNetworks::::mutate(|n| n.saturating_sub( 1 )); // Remove network registration time NetworkRegisteredAt::::remove(netuid); diff --git a/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs b/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs index bbe36db80b..a07434bcb5 100644 --- a/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs +++ b/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs @@ -69,7 +69,7 @@ pub fn migrate_delete_subnet_3() -> Weight { NetworksAdded::::remove(netuid); // Decrement the network counter - TotalNetworks::::mutate(|n| *n -= 1); + TotalNetworks::::mutate(|n| n.saturating_sub(1)); // Remove network registration time NetworkRegisteredAt::::remove(netuid); diff --git a/pallets/subtensor/src/staking/add_stake.rs b/pallets/subtensor/src/staking/add_stake.rs index a2e7ccdc48..422dfa2e42 100644 --- a/pallets/subtensor/src/staking/add_stake.rs +++ b/pallets/subtensor/src/staking/add_stake.rs @@ -1,14 +1,5 @@ use super::*; -use frame_support::{ - storage::IterableStorageDoubleMap, - traits::{ - tokens::{ - fungible::{Balanced as _, Inspect as _, Mutate as _}, - Fortitude, Precision, Preservation, - }, - Imbalance, - }, -}; + impl Pallet { /// ---- The implementation for the extrinsic add_stake: Adds stake to a hotkey account. diff --git a/pallets/subtensor/src/staking/become_delegate.rs b/pallets/subtensor/src/staking/become_delegate.rs index 28d3b25f40..4df8adf2d4 100644 --- a/pallets/subtensor/src/staking/become_delegate.rs +++ b/pallets/subtensor/src/staking/become_delegate.rs @@ -1,14 +1,5 @@ use super::*; -use frame_support::{ - storage::IterableStorageDoubleMap, - traits::{ - tokens::{ - fungible::{Balanced as _, Inspect as _, Mutate as _}, - Fortitude, Precision, Preservation, - }, - Imbalance, - }, -}; + impl Pallet { /// ---- The implementation for the extrinsic become_delegate: signals that this hotkey allows delegated stake. diff --git a/pallets/subtensor/src/staking/decrease_take.rs b/pallets/subtensor/src/staking/decrease_take.rs index 4290a1d24d..6aac33651c 100644 --- a/pallets/subtensor/src/staking/decrease_take.rs +++ b/pallets/subtensor/src/staking/decrease_take.rs @@ -1,14 +1,5 @@ use super::*; -use frame_support::{ - storage::IterableStorageDoubleMap, - traits::{ - tokens::{ - fungible::{Balanced as _, Inspect as _, Mutate as _}, - Fortitude, Precision, Preservation, - }, - Imbalance, - }, -}; + impl Pallet { /// ---- The implementation for the extrinsic decrease_take diff --git a/pallets/subtensor/src/staking/helpers.rs b/pallets/subtensor/src/staking/helpers.rs index 92aa394ed2..4865777121 100644 --- a/pallets/subtensor/src/staking/helpers.rs +++ b/pallets/subtensor/src/staking/helpers.rs @@ -122,26 +122,47 @@ impl Pallet { } } - // Returns the coldkey owning this hotkey. This function should only be called for active accounts. - // + /// Returns the coldkey owning this hotkey. This function should only be called for active accounts. + /// + /// # Arguments + /// * `hotkey` - The hotkey account ID. + /// + /// # Returns + /// The coldkey account ID that owns the hotkey. pub fn get_owning_coldkey_for_hotkey(hotkey: &T::AccountId) -> T::AccountId { Owner::::get(hotkey) } - // Returns the hotkey take - // + /// Returns the hotkey take. + /// + /// # Arguments + /// * `hotkey` - The hotkey account ID. + /// + /// # Returns + /// The take value of the hotkey. pub fn get_hotkey_take(hotkey: &T::AccountId) -> u16 { Delegates::::get(hotkey) } - // Returns true if the hotkey account has been created. - // + /// Returns true if the hotkey account has been created. + /// + /// # Arguments + /// * `hotkey` - The hotkey account ID. + /// + /// # Returns + /// True if the hotkey account exists, false otherwise. pub fn hotkey_account_exists(hotkey: &T::AccountId) -> bool { Owner::::contains_key(hotkey) } - // Return true if the passed coldkey owns the hotkey. - // + /// Returns true if the passed coldkey owns the hotkey. + /// + /// # Arguments + /// * `coldkey` - The coldkey account ID. + /// * `hotkey` - The hotkey account ID. + /// + /// # Returns + /// True if the coldkey owns the hotkey, false otherwise. pub fn coldkey_owns_hotkey(coldkey: &T::AccountId, hotkey: &T::AccountId) -> bool { if Self::hotkey_account_exists(hotkey) { Owner::::get(hotkey) == *coldkey @@ -150,14 +171,24 @@ impl Pallet { } } - // Returns true if the cold-hot staking account has enough balance to fufil the decrement. - // + /// Returns true if the cold-hot staking account has enough balance to fulfill the decrement. + /// + /// # Arguments + /// * `coldkey` - The coldkey account ID. + /// * `hotkey` - The hotkey account ID. + /// * `decrement` - The amount to be decremented. + /// + /// # Returns + /// True if the account has enough balance, false otherwise. pub fn has_enough_stake(coldkey: &T::AccountId, hotkey: &T::AccountId, decrement: u64) -> bool { Self::get_stake_for_coldkey_and_hotkey(coldkey, hotkey) >= decrement } - // Increases the stake on the hotkey account under its owning coldkey. - // + /// Increases the stake on the hotkey account under its owning coldkey. + /// + /// # Arguments + /// * `hotkey` - The hotkey account ID. + /// * `increment` - The amount to be incremented. pub fn increase_stake_on_hotkey_account(hotkey: &T::AccountId, increment: u64) { Self::increase_stake_on_coldkey_hotkey_account( &Self::get_owning_coldkey_for_hotkey(hotkey), @@ -166,8 +197,11 @@ impl Pallet { ); } - // Decreases the stake on the hotkey account under its owning coldkey. - // + /// Decreases the stake on the hotkey account under its owning coldkey. + /// + /// # Arguments + /// * `hotkey` - The hotkey account ID. + /// * `decrement` - The amount to be decremented. pub fn decrease_stake_on_hotkey_account(hotkey: &T::AccountId, decrement: u64) { Self::decrease_stake_on_coldkey_hotkey_account( &Self::get_owning_coldkey_for_hotkey(hotkey), diff --git a/pallets/subtensor/src/staking/increase_take.rs b/pallets/subtensor/src/staking/increase_take.rs index d5140b6565..7e215905af 100644 --- a/pallets/subtensor/src/staking/increase_take.rs +++ b/pallets/subtensor/src/staking/increase_take.rs @@ -1,14 +1,5 @@ use super::*; -use frame_support::{ - storage::IterableStorageDoubleMap, - traits::{ - tokens::{ - fungible::{Balanced as _, Inspect as _, Mutate as _}, - Fortitude, Precision, Preservation, - }, - Imbalance, - }, -}; + impl Pallet { /// ---- The implementation for the extrinsic increase_take diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs index 59e96777b9..e93d63f11c 100644 --- a/pallets/subtensor/src/staking/remove_stake.rs +++ b/pallets/subtensor/src/staking/remove_stake.rs @@ -1,14 +1,5 @@ use super::*; -use frame_support::{ - storage::IterableStorageDoubleMap, - traits::{ - tokens::{ - fungible::{Balanced as _, Inspect as _, Mutate as _}, - Fortitude, Precision, Preservation, - }, - Imbalance, - }, -}; + impl Pallet { /// ---- The implementation for the extrinsic remove_stake: Removes stake from a hotkey account and adds it onto a coldkey. From 752f53c8c6400be9d28b0dc78e433255862e316e Mon Sep 17 00:00:00 2001 From: const Date: Mon, 15 Jul 2024 14:27:27 -0500 Subject: [PATCH 06/16] merge clean --- pallets/subtensor/src/coinbase/mod.rs | 1 + pallets/subtensor/src/{ => coinbase}/root.rs | 0 pallets/subtensor/src/lib.rs | 17 ++++++----------- pallets/subtensor/src/subnets/mod.rs | 5 +++++ .../subtensor/src/{ => subnets}/registration.rs | 0 pallets/subtensor/src/{ => subnets}/serving.rs | 0 pallets/subtensor/src/{ => subnets}/uids.rs | 0 pallets/subtensor/src/{ => subnets}/weights.rs | 0 8 files changed, 12 insertions(+), 11 deletions(-) rename pallets/subtensor/src/{ => coinbase}/root.rs (100%) create mode 100644 pallets/subtensor/src/subnets/mod.rs rename pallets/subtensor/src/{ => subnets}/registration.rs (100%) rename pallets/subtensor/src/{ => subnets}/serving.rs (100%) rename pallets/subtensor/src/{ => subnets}/uids.rs (100%) rename pallets/subtensor/src/{ => subnets}/weights.rs (100%) diff --git a/pallets/subtensor/src/coinbase/mod.rs b/pallets/subtensor/src/coinbase/mod.rs index cc5b589f16..f8918ff1f1 100644 --- a/pallets/subtensor/src/coinbase/mod.rs +++ b/pallets/subtensor/src/coinbase/mod.rs @@ -1,2 +1,3 @@ use super::*; pub mod block_step; +pub mod root; diff --git a/pallets/subtensor/src/root.rs b/pallets/subtensor/src/coinbase/root.rs similarity index 100% rename from pallets/subtensor/src/root.rs rename to pallets/subtensor/src/coinbase/root.rs diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 23adeee02a..e59f5a9873 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -35,24 +35,19 @@ mod benchmarks; // ========================= // ==== Pallet Imports ===== // ========================= -mod coinbase; +pub mod coinbase; pub mod epoch; -mod macros; -mod rpc_info; +pub mod macros; +pub mod rpc_info; pub mod staking; pub mod swap; +pub mod subnets; +pub mod utils; +pub mod migrations; use macros::{config, dispatches, errors, events, genesis, hooks}; -mod registration; -mod root; -mod serving; -mod uids; -mod utils; -mod weights; - // apparently this is stabilized since rust 1.36 extern crate alloc; -pub mod migrations; #[deny(missing_docs)] #[import_section(errors::errors)] diff --git a/pallets/subtensor/src/subnets/mod.rs b/pallets/subtensor/src/subnets/mod.rs new file mode 100644 index 0000000000..1738b74017 --- /dev/null +++ b/pallets/subtensor/src/subnets/mod.rs @@ -0,0 +1,5 @@ +use super::*; +pub mod registration; +pub mod weights; +pub mod serving; +pub mod uids; diff --git a/pallets/subtensor/src/registration.rs b/pallets/subtensor/src/subnets/registration.rs similarity index 100% rename from pallets/subtensor/src/registration.rs rename to pallets/subtensor/src/subnets/registration.rs diff --git a/pallets/subtensor/src/serving.rs b/pallets/subtensor/src/subnets/serving.rs similarity index 100% rename from pallets/subtensor/src/serving.rs rename to pallets/subtensor/src/subnets/serving.rs diff --git a/pallets/subtensor/src/uids.rs b/pallets/subtensor/src/subnets/uids.rs similarity index 100% rename from pallets/subtensor/src/uids.rs rename to pallets/subtensor/src/subnets/uids.rs diff --git a/pallets/subtensor/src/weights.rs b/pallets/subtensor/src/subnets/weights.rs similarity index 100% rename from pallets/subtensor/src/weights.rs rename to pallets/subtensor/src/subnets/weights.rs From ad694b0e9dec8c0d087b2d96a55c8887aab43b1a Mon Sep 17 00:00:00 2001 From: const Date: Mon, 15 Jul 2024 15:31:32 -0500 Subject: [PATCH 07/16] refactor everything to make it cleaner --- pallets/subtensor/src/coinbase/root.rs | 7 +++++-- pallets/subtensor/src/macros/genesis.rs | 5 +++-- .../src/migrations/migrate_create_root_network.rs | 3 ++- .../subtensor/src/migrations/migrate_delete_subnet_21.rs | 2 +- .../subtensor/src/migrations/migrate_delete_subnet_3.rs | 2 +- pallets/subtensor/tests/root.rs | 5 +++++ 6 files changed, 17 insertions(+), 7 deletions(-) diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index 948c91f208..d1b4bf47a5 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -391,6 +391,9 @@ impl Pallet { // --- 9. Calculates the trust of networks. Trust is a sum of all stake with weights > 0. // Trust will have shape k, a score for each subnet. + log::debug!("Subnets:\n{:?}\n", Self::get_all_subnet_netuids()); + log::debug!("N Subnets:\n{:?}\n", Self::get_num_subnets()); + let total_networks = Self::get_num_subnets(); let mut trust = vec![I64F64::from_num(0); total_networks as usize]; let mut total_stake: I64F64 = I64F64::from_num(0); @@ -1031,7 +1034,7 @@ impl Pallet { NetworkModality::::insert(netuid, 0); // --- 5. Increase total network count. - TotalNetworks::::mutate(|n| n.saturating_inc()); + TotalNetworks::::mutate(|n| *n = n.saturating_add(1)); // --- 6. Set all default values **explicitly**. Self::set_network_registration_allowed(netuid, true); @@ -1123,7 +1126,7 @@ impl Pallet { NetworksAdded::::remove(netuid); // --- 6. Decrement the network counter. - TotalNetworks::::mutate(|n| n.saturating_dec()); + TotalNetworks::::mutate(|n| *n = n.saturating_sub(1)); // --- 7. Remove various network-related storages. NetworkRegisteredAt::::remove(netuid); diff --git a/pallets/subtensor/src/macros/genesis.rs b/pallets/subtensor/src/macros/genesis.rs index 34a888f280..7d3768a81d 100644 --- a/pallets/subtensor/src/macros/genesis.rs +++ b/pallets/subtensor/src/macros/genesis.rs @@ -124,7 +124,7 @@ mod genesis { SubnetworkN::::insert(netuid, next_uid); // --- Increase total network count. - TotalNetworks::::mutate(|n| n.saturating_add( 1 )); + TotalNetworks::::mutate(|n| *n = n.saturating_add(1)); // Get the root network uid. let root_netuid: u16 = 0; @@ -133,7 +133,8 @@ mod genesis { NetworksAdded::::insert(root_netuid, true); // Increment the number of total networks. - TotalNetworks::::mutate(|n| n.saturating_add(1)); + TotalNetworks::::mutate(|n| *n = n.saturating_add(1)); + // Set the number of validators to 1. SubnetworkN::::insert(root_netuid, 0); diff --git a/pallets/subtensor/src/migrations/migrate_create_root_network.rs b/pallets/subtensor/src/migrations/migrate_create_root_network.rs index fa9f343018..c413d1f078 100644 --- a/pallets/subtensor/src/migrations/migrate_create_root_network.rs +++ b/pallets/subtensor/src/migrations/migrate_create_root_network.rs @@ -55,7 +55,7 @@ pub fn migrate_create_root_network() -> Weight { NetworksAdded::::insert(root_netuid, true); // Increment the total number of networks - TotalNetworks::::mutate(|n| n.saturating_add( 1 )); + TotalNetworks::::mutate(|n| *n = n.saturating_add(1)); // Set the maximum number of UIDs to the number of senate members MaxAllowedUids::::insert(root_netuid, 64); @@ -95,5 +95,6 @@ pub fn migrate_create_root_network() -> Weight { weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); } + log::info!("Migrated create root network"); weight } diff --git a/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs b/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs index 011d79de14..c917c7cab1 100644 --- a/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs +++ b/pallets/subtensor/src/migrations/migrate_delete_subnet_21.rs @@ -66,7 +66,7 @@ pub fn migrate_delete_subnet_21() -> Weight { NetworksAdded::::remove(netuid); // Decrement the network counter - TotalNetworks::::mutate(|n| n.saturating_sub( 1 )); + TotalNetworks::::mutate(|n| *n = n.saturating_sub(1)); // Remove network registration time NetworkRegisteredAt::::remove(netuid); diff --git a/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs b/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs index a07434bcb5..2176963574 100644 --- a/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs +++ b/pallets/subtensor/src/migrations/migrate_delete_subnet_3.rs @@ -69,7 +69,7 @@ pub fn migrate_delete_subnet_3() -> Weight { NetworksAdded::::remove(netuid); // Decrement the network counter - TotalNetworks::::mutate(|n| n.saturating_sub(1)); + TotalNetworks::::mutate(|n| *n = n.saturating_sub(1)); // Remove network registration time NetworkRegisteredAt::::remove(netuid); diff --git a/pallets/subtensor/tests/root.rs b/pallets/subtensor/tests/root.rs index d4e8448a11..84df71d837 100644 --- a/pallets/subtensor/tests/root.rs +++ b/pallets/subtensor/tests/root.rs @@ -32,6 +32,7 @@ fn test_root_register_network_exist() { }); } +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test root -- test_set_weights_not_root_error --exact --nocapture #[test] fn test_set_weights_not_root_error() { new_test_ext(0).execute_with(|| { @@ -60,6 +61,7 @@ fn test_set_weights_not_root_error() { }); } +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test root -- test_root_register_normal_on_root_fails --exact --nocapture #[test] fn test_root_register_normal_on_root_fails() { new_test_ext(1).execute_with(|| { @@ -104,6 +106,7 @@ fn test_root_register_normal_on_root_fails() { }); } +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test root -- test_root_register_stake_based_pruning_works --exact --nocapture #[test] fn test_root_register_stake_based_pruning_works() { new_test_ext(1).execute_with(|| { @@ -192,6 +195,7 @@ fn test_root_register_stake_based_pruning_works() { }); } +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test root -- test_root_set_weights --exact --nocapture #[test] fn test_root_set_weights() { new_test_ext(1).execute_with(|| { @@ -334,6 +338,7 @@ fn test_root_set_weights() { }); } +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test root -- test_root_set_weights --exact --nocapture #[test] fn test_root_set_weights_out_of_order_netuids() { new_test_ext(1).execute_with(|| { From 5e291123d727bcd75336777e00a14d29dfaa09ad Mon Sep 17 00:00:00 2001 From: const Date: Mon, 15 Jul 2024 15:32:18 -0500 Subject: [PATCH 08/16] lint --- pallets/subtensor/src/coinbase/root.rs | 2 +- pallets/subtensor/src/lib.rs | 4 ++-- pallets/subtensor/src/staking/add_stake.rs | 1 - pallets/subtensor/src/staking/become_delegate.rs | 1 - pallets/subtensor/src/staking/decrease_take.rs | 1 - pallets/subtensor/src/staking/increase_take.rs | 1 - pallets/subtensor/src/staking/remove_stake.rs | 1 - pallets/subtensor/src/subnets/mod.rs | 2 +- 8 files changed, 4 insertions(+), 9 deletions(-) diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index d1b4bf47a5..974931e8ff 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -1034,7 +1034,7 @@ impl Pallet { NetworkModality::::insert(netuid, 0); // --- 5. Increase total network count. - TotalNetworks::::mutate(|n| *n = n.saturating_add(1)); + TotalNetworks::::mutate(|n| *n = n.saturating_add(1)); // --- 6. Set all default values **explicitly**. Self::set_network_registration_allowed(netuid, true); diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index e59f5a9873..c28da051d3 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -38,12 +38,12 @@ mod benchmarks; pub mod coinbase; pub mod epoch; pub mod macros; +pub mod migrations; pub mod rpc_info; pub mod staking; -pub mod swap; pub mod subnets; +pub mod swap; pub mod utils; -pub mod migrations; use macros::{config, dispatches, errors, events, genesis, hooks}; // apparently this is stabilized since rust 1.36 diff --git a/pallets/subtensor/src/staking/add_stake.rs b/pallets/subtensor/src/staking/add_stake.rs index 422dfa2e42..eb7762bec1 100644 --- a/pallets/subtensor/src/staking/add_stake.rs +++ b/pallets/subtensor/src/staking/add_stake.rs @@ -1,6 +1,5 @@ use super::*; - impl Pallet { /// ---- The implementation for the extrinsic add_stake: Adds stake to a hotkey account. /// diff --git a/pallets/subtensor/src/staking/become_delegate.rs b/pallets/subtensor/src/staking/become_delegate.rs index 4df8adf2d4..064f47c129 100644 --- a/pallets/subtensor/src/staking/become_delegate.rs +++ b/pallets/subtensor/src/staking/become_delegate.rs @@ -1,6 +1,5 @@ use super::*; - impl Pallet { /// ---- The implementation for the extrinsic become_delegate: signals that this hotkey allows delegated stake. /// diff --git a/pallets/subtensor/src/staking/decrease_take.rs b/pallets/subtensor/src/staking/decrease_take.rs index 6aac33651c..9e48bac912 100644 --- a/pallets/subtensor/src/staking/decrease_take.rs +++ b/pallets/subtensor/src/staking/decrease_take.rs @@ -1,6 +1,5 @@ use super::*; - impl Pallet { /// ---- The implementation for the extrinsic decrease_take /// diff --git a/pallets/subtensor/src/staking/increase_take.rs b/pallets/subtensor/src/staking/increase_take.rs index 7e215905af..aa6dd443ca 100644 --- a/pallets/subtensor/src/staking/increase_take.rs +++ b/pallets/subtensor/src/staking/increase_take.rs @@ -1,6 +1,5 @@ use super::*; - impl Pallet { /// ---- The implementation for the extrinsic increase_take /// diff --git a/pallets/subtensor/src/staking/remove_stake.rs b/pallets/subtensor/src/staking/remove_stake.rs index e93d63f11c..a6f3db08dc 100644 --- a/pallets/subtensor/src/staking/remove_stake.rs +++ b/pallets/subtensor/src/staking/remove_stake.rs @@ -1,6 +1,5 @@ use super::*; - impl Pallet { /// ---- The implementation for the extrinsic remove_stake: Removes stake from a hotkey account and adds it onto a coldkey. /// diff --git a/pallets/subtensor/src/subnets/mod.rs b/pallets/subtensor/src/subnets/mod.rs index 1738b74017..43bdfec43e 100644 --- a/pallets/subtensor/src/subnets/mod.rs +++ b/pallets/subtensor/src/subnets/mod.rs @@ -1,5 +1,5 @@ use super::*; pub mod registration; -pub mod weights; pub mod serving; pub mod uids; +pub mod weights; From 8941385a5f4bac21ddc6b3c91f80d75bb82529bd Mon Sep 17 00:00:00 2001 From: const Date: Mon, 15 Jul 2024 16:24:49 -0500 Subject: [PATCH 09/16] add set sudo hotkey drain tempo --- pallets/admin-utils/src/benchmarking.rs | 8 + pallets/admin-utils/src/lib.rs | 30 + pallets/admin-utils/src/weights.rs | 11 + pallets/admin-utils/tests/mock.rs | 3 + pallets/subtensor/src/coinbase/block_step.rs | 333 +---- pallets/subtensor/src/coinbase/mod.rs | 1 + .../subtensor/src/coinbase/run_coinbase.rs | 373 +++++ pallets/subtensor/src/epoch/run_epoch.rs | 99 +- pallets/subtensor/src/lib.rs | 3 + pallets/subtensor/src/macros/dispatches.rs | 59 + pallets/subtensor/src/macros/errors.rs | 8 + pallets/subtensor/src/macros/events.rs | 1 + pallets/subtensor/src/rpc_info/neuron_info.rs | 12 +- pallets/subtensor/src/staking/mod.rs | 1 + pallets/subtensor/src/staking/set_children.rs | 185 +++ pallets/subtensor/src/subnets/registration.rs | 11 + pallets/subtensor/src/utils.rs | 16 + pallets/subtensor/tests/children.rs | 1261 +++++++++++++++++ pallets/subtensor/tests/coinbase.rs | 154 ++ runtime/src/lib.rs | 4 + 20 files changed, 2232 insertions(+), 341 deletions(-) create mode 100644 pallets/subtensor/src/coinbase/run_coinbase.rs create mode 100644 pallets/subtensor/src/staking/set_children.rs create mode 100644 pallets/subtensor/tests/children.rs create mode 100644 pallets/subtensor/tests/coinbase.rs diff --git a/pallets/admin-utils/src/benchmarking.rs b/pallets/admin-utils/src/benchmarking.rs index 0158311f7b..3165e907f5 100644 --- a/pallets/admin-utils/src/benchmarking.rs +++ b/pallets/admin-utils/src/benchmarking.rs @@ -240,5 +240,13 @@ mod benchmarks { _(RawOrigin::Root, 1u16/*netuid*/, true/*enabled*/)/*set_commit_reveal_weights_enabled*/; } + #[benchmark] + fn sudo_set_hotkey_emission_tempo() { + T::Subtensor::init_new_network(1u16 /*netuid*/, 1u16 /*sudo_tempo*/); + + #[extrinsic_call] + _(RawOrigin::Root, 1u64/*emission_tempo*/)/*set_hotkey_emission_tempo*/; + } + //impl_benchmark_test_suite!(AdminUtils, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 9a8744dc68..2aa45cbc97 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -1035,6 +1035,35 @@ pub mod pallet { T::Subtensor::ensure_subnet_owner_or_root(origin.clone(), netuid)?; T::Subtensor::do_set_alpha_values(origin, netuid, alpha_low, alpha_high) } + + /// Sets the hotkey emission tempo. + /// + /// This extrinsic allows the root account to set the hotkey emission tempo, which determines + /// the number of blocks before a hotkey drains accumulated emissions through to nominator staking accounts. + /// + /// # Arguments + /// * `origin` - The origin of the call, which must be the root account. + /// * `emission_tempo` - The new emission tempo value to set. + /// + /// # Emits + /// * `Event::HotkeyEmissionTempoSet` - When the hotkey emission tempo is successfully set. + /// + /// # Errors + /// * `DispatchError::BadOrigin` - If the origin is not the root account. + #[pallet::call_index(52)] + #[pallet::weight(T::WeightInfo::sudo_set_hotkey_emission_tempo())] + pub fn sudo_set_hotkey_emission_tempo( + origin: OriginFor, + emission_tempo: u64, + ) -> DispatchResult { + ensure_root(origin)?; + T::Subtensor::set_hotkey_emission_tempo(emission_tempo); + log::info!( + "HotkeyEmissionTempoSet( emission_tempo: {:?} )", + emission_tempo + ); + Ok(()) + } } } @@ -1137,4 +1166,5 @@ pub trait SubtensorInterface { alpha_low: u16, alpha_high: u16, ) -> Result<(), DispatchError>; + fn set_hotkey_emission_tempo(emission_tempo: u64); } diff --git a/pallets/admin-utils/src/weights.rs b/pallets/admin-utils/src/weights.rs index ace123b14b..0c0259ef2b 100644 --- a/pallets/admin-utils/src/weights.rs +++ b/pallets/admin-utils/src/weights.rs @@ -62,6 +62,7 @@ pub trait WeightInfo { fn sudo_set_tempo() -> Weight; fn sudo_set_commit_reveal_weights_interval() -> Weight; fn sudo_set_commit_reveal_weights_enabled() -> Weight; + fn sudo_set_hotkey_emission_tempo() -> Weight; } @@ -806,4 +807,14 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: `SubtensorModule::HotkeyEmissionTempo` (r:0 w:1) + /// Proof: `SubtensorModule::HotkeyEmissionTempo` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn sudo_set_hotkey_emission_tempo() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(6_000_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } \ No newline at end of file diff --git a/pallets/admin-utils/tests/mock.rs b/pallets/admin-utils/tests/mock.rs index dee8e742ff..c1f55fece5 100644 --- a/pallets/admin-utils/tests/mock.rs +++ b/pallets/admin-utils/tests/mock.rs @@ -475,6 +475,9 @@ impl pallet_admin_utils::SubtensorInterface f fn set_liquid_alpha_enabled(netuid: u16, enabled: bool) { SubtensorModule::set_liquid_alpha_enabled(netuid, enabled); } + fn set_hotkey_emission_tempo(emission_tempo: u64) { + SubtensorModule::set_hotkey_emission_tempo(emission_tempo) + } fn do_set_alpha_values( origin: RuntimeOrigin, netuid: u16, diff --git a/pallets/subtensor/src/coinbase/block_step.rs b/pallets/subtensor/src/coinbase/block_step.rs index 784332e4e5..f4df514560 100644 --- a/pallets/subtensor/src/coinbase/block_step.rs +++ b/pallets/subtensor/src/coinbase/block_step.rs @@ -13,341 +13,12 @@ impl Pallet { log::debug!("block_step for block: {:?} ", block_number); // --- 1. Adjust difficulties. Self::adjust_registration_terms_for_networks(); - // --- 2. Calculate per-subnet emissions - match Self::root_epoch(block_number) { - Ok(_) => (), - Err(e) => { - log::trace!("Error while running root epoch: {:?}", e); - } - } - // --- 3. Drains emission tuples ( hotkey, amount ). - Self::drain_emission(block_number); - // --- 4. Generates emission tuples from epoch functions. - Self::generate_emission(block_number); + // --- 2. Run emission through network. + Self::run_coinbase(); // Return ok. Ok(()) } - #[allow(clippy::arithmetic_side_effects)] - /// Helper function which returns the number of blocks remaining before we will run the epoch on this - /// network. Networks run their epoch when (block_number + netuid + 1 ) % (tempo + 1) = 0 - /// - pub fn blocks_until_next_epoch(netuid: u16, tempo: u16, block_number: u64) -> u64 { - // tempo | netuid | # first epoch block - // 1 0 0 - // 1 1 1 - // 2 0 1 - // 2 1 0 - // 100 0 99 - // 100 1 98 - // Special case: tempo = 0, the network never runs. - if tempo == 0 { - return 1000; - } - (tempo as u64).saturating_sub( - block_number.saturating_add(netuid as u64).saturating_add(1) - % (tempo as u64).saturating_add(1), - ) - } - - #[allow(clippy::arithmetic_side_effects)] - /// Helper function returns the number of tuples to drain on a particular step based on - /// the remaining tuples to sink and the block number - /// - pub fn tuples_to_drain_this_block( - netuid: u16, - tempo: u16, - block_number: u64, - n_remaining: usize, - ) -> usize { - let blocks_until_epoch: u64 = Self::blocks_until_next_epoch(netuid, tempo, block_number); - if blocks_until_epoch.saturating_div(2) == 0 { - return n_remaining; - } // drain all. - if tempo.saturating_div(2) == 0 { - return n_remaining; - } // drain all - if n_remaining == 0 { - return 0; - } // nothing to drain at all. - // Else return enough tuples to drain all within half the epoch length. - let to_sink_via_tempo: usize = - n_remaining.saturating_div((tempo as usize).saturating_div(2)); - let to_sink_via_blocks_until_epoch: usize = - n_remaining.saturating_div((blocks_until_epoch as usize).saturating_div(2)); - if to_sink_via_tempo > to_sink_via_blocks_until_epoch { - to_sink_via_tempo - } else { - to_sink_via_blocks_until_epoch - } - } - - pub fn get_loaded_emission_tuples(netuid: u16) -> Option> { - LoadedEmission::::get(netuid) - } - - /// Reads from the loaded emission storage which contains lists of pending emission tuples ( hotkey, amount ) - /// and distributes small chunks of them at a time. - /// - pub fn drain_emission(_: u64) { - // --- 1. We iterate across each network. - for (netuid, _) in as IterableStorageMap>::iter() { - let Some(tuples_to_drain) = Self::get_loaded_emission_tuples(netuid) else { - // There are no tuples to emit. - continue; - }; - let mut total_emitted: u64 = 0; - for (hotkey, server_amount, validator_amount) in tuples_to_drain.iter() { - Self::emit_inflation_through_hotkey_account( - hotkey, - *server_amount, - *validator_amount, - ); - total_emitted.saturating_accrue((*server_amount).saturating_add(*validator_amount)); - } - LoadedEmission::::remove(netuid); - TotalIssuance::::put(TotalIssuance::::get().saturating_add(total_emitted)); - } - } - - /// Iterates through networks queues more emission onto their pending storage. - /// If a network has no blocks left until tempo, we run the epoch function and generate - /// more token emission tuples for later draining onto accounts. - /// - pub fn generate_emission(block_number: u64) { - // --- 1. Iterate across each network and add pending emission into stash. - for (netuid, tempo) in as IterableStorageMap>::iter() { - // Skip the root network or subnets with registrations turned off - if netuid == Self::get_root_netuid() { - // Root emission or subnet emission is burned - continue; - } - - // --- 2. Queue the emission due to this network. - let mut new_queued_emission: u64 = Self::get_subnet_emission_value(netuid); - if !Self::is_registration_allowed(netuid) { - new_queued_emission = 0; // No emission for this network if registration is off. - } - - log::debug!( - "generate_emission for netuid: {:?} with tempo: {:?} and emission: {:?}", - netuid, - tempo, - new_queued_emission, - ); - - let subnet_has_owner = SubnetOwner::::contains_key(netuid); - let mut remaining = I96F32::from_num(new_queued_emission); - if subnet_has_owner { - let cut = remaining - .saturating_mul(I96F32::from_num(Self::get_subnet_owner_cut())) - .saturating_div(I96F32::from_num(u16::MAX)); - - remaining = remaining.saturating_sub(cut); - - Self::add_balance_to_coldkey_account( - &Self::get_subnet_owner(netuid), - cut.to_num::(), - ); - - // We are creating tokens here from the coinbase. - Self::coinbase(cut.to_num::()); - } - // --- 5. Add remaining amount to the network's pending emission. - PendingEmission::::mutate(netuid, |queued| { - queued.saturating_accrue(remaining.to_num::()) - }); - log::debug!( - "netuid_i: {:?} queued_emission: +{:?} ", - netuid, - new_queued_emission - ); - - // --- 6. Check to see if this network has reached tempo. - if Self::blocks_until_next_epoch(netuid, tempo, block_number) != 0 { - // --- 3.1 No epoch, increase blocks since last step and continue, - Self::set_blocks_since_last_step( - netuid, - Self::get_blocks_since_last_step(netuid).saturating_add(1), - ); - continue; - } - - // --- 7 This network is at tempo and we are running its epoch. - // First drain the queued emission. - let emission_to_drain: u64 = PendingEmission::::get(netuid); - PendingEmission::::insert(netuid, 0); - - // --- 8. Run the epoch mechanism and return emission tuples for hotkeys in the network. - let emission_tuples_this_block: Vec<(T::AccountId, u64, u64)> = - Self::epoch(netuid, emission_to_drain); - log::debug!( - "netuid_i: {:?} emission_to_drain: {:?} ", - netuid, - emission_to_drain - ); - - // --- 9. Check that the emission does not exceed the allowed total. - let emission_sum: u128 = emission_tuples_this_block - .iter() - .map(|(_account_id, ve, se)| (*ve as u128).saturating_add(*se as u128)) - .sum(); - if emission_sum > emission_to_drain as u128 { - continue; - } // Saftey check. - - // --- 10. Sink the emission tuples onto the already loaded. - let mut concat_emission_tuples: Vec<(T::AccountId, u64, u64)> = - emission_tuples_this_block.clone(); - if let Some(mut current_emission_tuples) = Self::get_loaded_emission_tuples(netuid) { - // 10.a We already have loaded emission tuples, so we concat the new ones. - concat_emission_tuples.append(&mut current_emission_tuples); - } - LoadedEmission::::insert(netuid, concat_emission_tuples); - - // --- 11 Set counters. - Self::set_blocks_since_last_step(netuid, 0); - Self::set_last_mechanism_step_block(netuid, block_number); - } - } - /// Distributes token inflation through the hotkey based on emission. The call ensures that the inflation - /// is distributed onto the accounts in proportion of the stake delegated minus the take. This function - /// is called after an epoch to distribute the newly minted stake according to delegation. - /// - pub fn emit_inflation_through_hotkey_account( - hotkey: &T::AccountId, - server_emission: u64, - validator_emission: u64, - ) { - // --- 1. Check if the hotkey is a delegate. If not, we simply pass the stake through to the - // coldkey - hotkey account as normal. - if !Self::hotkey_is_delegate(hotkey) { - Self::increase_stake_on_hotkey_account( - hotkey, - server_emission.saturating_add(validator_emission), - ); - return; - } - // Then this is a delegate, we distribute validator_emission, then server_emission. - - // --- 2. The hotkey is a delegate. We first distribute a proportion of the validator_emission to the hotkey - // directly as a function of its 'take' - let total_hotkey_stake: u64 = Self::get_total_stake_for_hotkey(hotkey); - let delegate_take: u64 = - Self::calculate_delegate_proportional_take(hotkey, validator_emission); - let validator_emission_minus_take: u64 = validator_emission.saturating_sub(delegate_take); - let mut remaining_validator_emission: u64 = validator_emission_minus_take; - - // 3. -- The remaining emission goes to the owners in proportion to the stake delegated. - for (owning_coldkey_i, stake_i) in - as IterableStorageDoubleMap>::iter_prefix( - hotkey, - ) - { - // --- 4. The emission proportion is remaining_emission * ( stake / total_stake ). - let stake_proportion: u64 = Self::calculate_stake_proportional_emission( - stake_i, - total_hotkey_stake, - validator_emission_minus_take, - ); - Self::increase_stake_on_coldkey_hotkey_account( - &owning_coldkey_i, - hotkey, - stake_proportion, - ); - log::debug!( - "owning_coldkey_i: {:?} hotkey: {:?} emission: +{:?} ", - owning_coldkey_i, - hotkey, - stake_proportion - ); - remaining_validator_emission.saturating_reduce(stake_proportion); - } - - // --- 5. Last increase final account balance of delegate after 4, since 5 will change the stake proportion of - // the delegate and effect calculation in 4. - Self::increase_stake_on_hotkey_account( - hotkey, - delegate_take.saturating_add(remaining_validator_emission), - ); - log::debug!("delkey: {:?} delegate_take: +{:?} ", hotkey, delegate_take); - // Also emit the server_emission to the hotkey - // The server emission is distributed in-full to the delegate owner. - // We do this after 4. for the same reason as above. - Self::increase_stake_on_hotkey_account(hotkey, server_emission); - } - - /// Increases the stake on the cold - hot pairing by increment while also incrementing other counters. - /// This function should be called rather than set_stake under account. - /// - pub fn block_step_increase_stake_on_coldkey_hotkey_account( - coldkey: &T::AccountId, - hotkey: &T::AccountId, - increment: u64, - ) { - TotalColdkeyStake::::mutate(coldkey, |old| old.saturating_add(increment)); - TotalHotkeyStake::::insert( - hotkey, - TotalHotkeyStake::::get(hotkey).saturating_add(increment), - ); - Stake::::insert( - hotkey, - coldkey, - Stake::::get(hotkey, coldkey).saturating_add(increment), - ); - TotalStake::::put(TotalStake::::get().saturating_add(increment)); - } - - /// Decreases the stake on the cold - hot pairing by the decrement while decreasing other counters. - /// - pub fn block_step_decrease_stake_on_coldkey_hotkey_account( - coldkey: &T::AccountId, - hotkey: &T::AccountId, - decrement: u64, - ) { - TotalColdkeyStake::::mutate(coldkey, |old| old.saturating_sub(decrement)); - TotalHotkeyStake::::insert( - hotkey, - TotalHotkeyStake::::get(hotkey).saturating_sub(decrement), - ); - Stake::::insert( - hotkey, - coldkey, - Stake::::get(hotkey, coldkey).saturating_sub(decrement), - ); - TotalStake::::put(TotalStake::::get().saturating_sub(decrement)); - } - - /// Returns emission awarded to a hotkey as a function of its proportion of the total stake. - /// - pub fn calculate_stake_proportional_emission( - stake: u64, - total_stake: u64, - emission: u64, - ) -> u64 { - if total_stake == 0 { - return 0; - }; - let stake_proportion: I64F64 = - I64F64::from_num(stake).saturating_div(I64F64::from_num(total_stake)); - let proportional_emission: I64F64 = - I64F64::from_num(emission).saturating_mul(stake_proportion); - proportional_emission.to_num::() - } - - /// Returns the delegated stake 'take' assigned to this key. (If exists, otherwise 0) - /// - pub fn calculate_delegate_proportional_take(hotkey: &T::AccountId, emission: u64) -> u64 { - if Self::hotkey_is_delegate(hotkey) { - let take_proportion: I64F64 = I64F64::from_num(Delegates::::get(hotkey)) - .saturating_div(I64F64::from_num(u16::MAX)); - let take_emission: I64F64 = take_proportion.saturating_mul(I64F64::from_num(emission)); - take_emission.to_num::() - } else { - 0 - } - } - /// Adjusts the network difficulties/burns of every active network. Resetting state parameters. /// pub fn adjust_registration_terms_for_networks() { diff --git a/pallets/subtensor/src/coinbase/mod.rs b/pallets/subtensor/src/coinbase/mod.rs index f8918ff1f1..ec989d2583 100644 --- a/pallets/subtensor/src/coinbase/mod.rs +++ b/pallets/subtensor/src/coinbase/mod.rs @@ -1,3 +1,4 @@ use super::*; pub mod block_step; pub mod root; +pub mod run_coinbase; diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs new file mode 100644 index 0000000000..7dd829853e --- /dev/null +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -0,0 +1,373 @@ +use super::*; +use frame_support::storage::IterableStorageDoubleMap; +use frame_support::storage::IterableStorageMap; +use sp_runtime::Saturating; +use substrate_fixed::types::I110F18; +use substrate_fixed::types::I64F64; +use substrate_fixed::types::I96F32; + +impl Pallet { + /// The `coinbase` function performs a four-part emission distribution process involving + /// subnets, epochs, hotkeys, and nominators. + // It is divided into several steps, each handling a specific part of the distribution: + + // Step 1: Compute the block-wise emission for each subnet. + // This involves calculating how much (TAO) should be emitted into each subnet using the + // root epoch function. + + // Step 2: Accumulate the subnet block emission. + // After calculating the block-wise emission, these values are accumulated to keep track + // of how much each subnet should emit before the next distribution phase. This accumulation + // is a running total that gets updated each block. + + // Step 3: Distribute the accumulated emissions through epochs. + // Subnets periodically distribute their accumulated emissions to hotkeys (active validators/miners) + // in the network on a `tempo` --- the time between epochs. This step runs Yuma consensus to + // determine how emissions are split among hotkeys based on their contributions and roles. + // The accumulation of hotkey emissions is done through the `accumulate_hotkey_emission` function. + // The function splits the rewards for a hotkey amongst itself and its `parents`. The parents are + // the hotkeys that are delegating their stake to the hotkey. + + // Step 4: Further distribute emissions from hotkeys to nominators. + // Finally, the emissions received by hotkeys are further distributed to their nominators, + // who are stakeholders that support the hotkeys. + pub fn run_coinbase() { + // --- 0. Get current block. + let current_block: u64 = Self::get_current_block_as_u64(); + log::debug!("Current block: {:?}", current_block); + + // --- 1. Get all netuids. + let subnets: Vec = Self::get_all_subnet_netuids(); + log::debug!("All subnet netuids: {:?}", subnets); + + // --- 2. Run the root epoch function which computes the block emission for each subnet. + // coinbase --> root() --> subnet_block_emission + match Self::root_epoch(current_block) { + Ok(_) => log::debug!("Root epoch run successfully for block: {:?}", current_block), + Err(e) => { + log::trace!("Did not run epoch with: {:?}", e); + } + } + + // --- 3. Drain the subnet block emission and accumulate it as subnet emission, which increases until the tempo is reached in #4. + // subnet_blockwise_emission -> subnet_pending_emission + for netuid in subnets.clone().iter() { + // --- 3.1 Get the network's block-wise emission amount. + // This value is newly minted TAO which has not reached staking accounts yet. + let subnet_blockwise_emission: u64 = EmissionValues::::get(*netuid); + log::debug!( + "Subnet block-wise emission for netuid {:?}: {:?}", + *netuid, + subnet_blockwise_emission + ); + + // --- 3.2 Accumulate the subnet emission on the subnet. + PendingEmission::::mutate(*netuid, |subnet_emission| { + *subnet_emission = subnet_emission.saturating_add(subnet_blockwise_emission); + log::debug!( + "Updated subnet emission for netuid {:?}: {:?}", + *netuid, + *subnet_emission + ); + }); + } + + // --- 4. Drain the accumulated subnet emissions, pass them through the epoch(). + // Before accumulating on the hotkeys the function redistributes the emission towards hotkey parents. + // subnet_emission --> epoch() --> hotkey_emission --> (hotkey + parent hotkeys) + for netuid in subnets.clone().iter() { + // --- 4.1 Check to see if the subnet should run its epoch. + if Self::should_run_epoch(*netuid, current_block) { + // --- 4.2 Drain the subnet emission. + let mut subnet_emission: u64 = PendingEmission::::get(*netuid); + PendingEmission::::insert(*netuid, 0); + log::debug!( + "Drained subnet emission for netuid {:?}: {:?}", + *netuid, + subnet_emission + ); + + // --- 4.3 Set last step counter. + Self::set_blocks_since_last_step(*netuid, 0); + Self::set_last_mechanism_step_block(*netuid, current_block); + + // --- 4.4 Distribute owner take. + if SubnetOwner::::contains_key(netuid) { + // Does the subnet have an owner? + + // --- 4.4.1 Compute the subnet owner cut. + let owner_cut: I96F32 = I96F32::from_num(subnet_emission).saturating_mul( + I96F32::from_num(Self::get_subnet_owner_cut()) + .saturating_div(I96F32::from_num(u16::MAX)), + ); + + // --- 4.4.2 Remove the cut from the subnet emission + subnet_emission = subnet_emission.saturating_sub(owner_cut.to_num::()); + + // --- 4.4.3 Add the cut to the balance of the owner + Self::add_balance_to_coldkey_account( + &Self::get_subnet_owner(*netuid), + owner_cut.to_num::(), + ); + + // --- 4.4.4 Increase total issuance on the chain. + Self::coinbase(owner_cut.to_num::()); + } + + // 4.3 Pass emission through epoch() --> hotkey emission. + let hotkey_emission: Vec<(T::AccountId, u64, u64)> = + Self::epoch(*netuid, subnet_emission); + log::debug!( + "Hotkey emission results for netuid {:?}: {:?}", + *netuid, + hotkey_emission + ); + + // 4.4 Accumulate the tuples on hotkeys: + for (hotkey, mining_emission, validator_emission) in hotkey_emission { + // 4.5 Accumulate the emission on the hotkey and parent hotkeys. + Self::accumulate_hotkey_emission( + &hotkey, + *netuid, + validator_emission, // Amount received from validating + mining_emission, // Amount recieved from mining. + ); + log::debug!("Accumulated emissions on hotkey {:?} for netuid {:?}: mining {:?}, validator {:?}", hotkey, *netuid, mining_emission, validator_emission); + } + } else { + log::debug!("Tempo not reached for subnet: {:?}", *netuid); + } + } + + // --- 5. Drain the accumulated hotkey emissions through to the nominators. + // The hotkey takes a proportion of the emission, the remainder is drained through to the nominators. + // We keep track of the last stake increase event for accounting purposes. + // hotkeys --> nominators. + let emission_tempo: u64 = Self::get_hotkey_emission_tempo(); + for (hotkey, hotkey_emission) in PendingdHotkeyEmission::::iter() { + // Check for zeros. + // remove zero values. + if hotkey_emission == 0 { + continue; + } + + // --- 5.1 Check if we should drain the hotkey emission on this block. + if Self::should_drain_hotkey(&hotkey, current_block, emission_tempo) { + // --- 5.2 Drain the hotkey emission and distribute it to nominators. + let total_new_tao: u64 = + Self::drain_hotkey_emission(&hotkey, hotkey_emission, current_block); + log::debug!( + "Drained hotkey emission for hotkey {:?} on block {:?}: {:?}", + hotkey, + current_block, + hotkey_emission + ); + + // --- 5.3 Increase total issuance on the chain. + Self::coinbase(total_new_tao); + log::debug!("Increased total issuance by {:?}", total_new_tao); + } + } + } + + /// Accumulates the mining and validator emissions on a hotkey and distributes the validator emission among its parents. + /// + /// This function is responsible for accumulating the mining and validator emissions associated with a hotkey onto a hotkey. + /// It first calculates the total stake of the hotkey, considering the stakes contributed by its parents and reduced by its children. + /// It then retrieves the list of parents of the hotkey and distributes the validator emission proportionally based on the stake contributed by each parent. + /// The remaining validator emission, after distribution to the parents, along with the mining emission, is then added to the hotkey's own accumulated emission. + /// + /// # Arguments + /// * `hotkey` - The account ID of the hotkey for which emissions are being calculated. + /// * `netuid` - The unique identifier of the network to which the hotkey belongs. + /// * `mining_emission` - The amount of mining emission allocated to the hotkey. + /// * `validator_emission` - The amount of validator emission allocated to the hotkey. + /// + pub fn accumulate_hotkey_emission( + hotkey: &T::AccountId, + netuid: u16, + validating_emission: u64, + mining_emission: u64, + ) { + // --- 1. First, calculate the hotkey's share of the emission. + let take_proportion: I64F64 = + I64F64::from_num(Delegates::::get(hotkey)).saturating_div(I64F64::from_num(u16::MAX)); + let hotkey_take: u64 = take_proportion + .saturating_mul(I64F64::from_num(validating_emission)) + .to_num::(); + // NOTE: Only the validation emission should be split amongst parents. + + // --- 2. Compute the remaining emission after the hotkey's share is deducted. + let emission_minus_take: u64 = validating_emission.saturating_sub(hotkey_take); + + // --- 3. Track the remaining emission for accounting purposes. + let mut remaining_emission: u64 = emission_minus_take; + + // --- 4. Calculate the total stake of the hotkey, adjusted by the stakes of parents and children. + // Parents contribute to the stake, while children reduce it. + // If this value is zero, no distribution to anyone is necessary. + let total_hotkey_stake: u64 = Self::get_stake_for_hotkey_on_subnet(hotkey, netuid); + if total_hotkey_stake != 0 { + // --- 5. If the total stake is not zero, iterate over each parent to determine their contribution to the hotkey's stake, + // and calculate their share of the emission accordingly. + for (proportion, parent) in Self::get_parents(hotkey, netuid) { + // --- 5.1 Retrieve the parent's stake. This is the raw stake value including nominators. + let parent_stake: u64 = Self::get_total_stake_for_hotkey(&parent); + + // --- 5.2 Calculate the portion of the hotkey's total stake contributed by this parent. + // Then, determine the parent's share of the remaining emission. + let stake_from_parent: I96F32 = I96F32::from_num(parent_stake).saturating_mul( + I96F32::from_num(proportion).saturating_div(I96F32::from_num(u64::MAX)), + ); + let proportion_from_parent: I96F32 = + stake_from_parent.saturating_div(I96F32::from_num(total_hotkey_stake)); + let parent_emission_take: u64 = proportion_from_parent + .saturating_mul(I96F32::from_num(emission_minus_take)) + .to_num::(); + + // --- 5.5. Accumulate emissions for the parent hotkey. + PendingdHotkeyEmission::::mutate(parent, |parent_accumulated| { + *parent_accumulated = parent_accumulated.saturating_add(parent_emission_take) + }); + + // --- 5.6. Subtract the parent's share from the remaining emission for this hotkey. + remaining_emission = remaining_emission.saturating_sub(parent_emission_take); + } + } + + // --- 6. Add the remaining emission plus the hotkey's initial take to the pending emission for this hotkey. + PendingdHotkeyEmission::::mutate(hotkey, |hotkey_pending| { + *hotkey_pending = hotkey_pending.saturating_add( + remaining_emission + .saturating_add(hotkey_take) + .saturating_add(mining_emission), + ) + }); + } + + //. --- 4. Drains the accumulated hotkey emission through to the nominators. The hotkey takes a proportion of the emission. + /// The remainder is drained through to the nominators keeping track of the last stake increase event to ensure that the hotkey does not + /// gain more emission than it's stake since the last drain. + /// hotkeys --> nominators. + /// + /// 1. It resets the accumulated emissions for the hotkey to zero. + /// 4. It calculates the total stake for the hotkey and determines the hotkey's own take from the emissions based on its delegation status. + /// 5. It then calculates the remaining emissions after the hotkey's take and distributes this remaining amount proportionally among the hotkey's nominators. + /// 6. Each nominator's share of the emissions is added to their stake, but only if their stake was not manually increased since the last emission drain. + /// 7. Finally, the hotkey's own take and any undistributed emissions are added to the hotkey's total stake. + /// + /// This function ensures that emissions are fairly distributed according to stake proportions and delegation agreements, and it updates the necessary records to reflect these changes. + pub fn drain_hotkey_emission(hotkey: &T::AccountId, emission: u64, block_number: u64) -> u64 { + // --- 0. For accounting purposes record the total new added stake. + let mut total_new_tao: u64 = 0; + + // --- 1.0 Drain the hotkey emission. + PendingdHotkeyEmission::::insert(hotkey, 0); + + // --- 2 Retrieve the last time this hotkey's emissions were drained. + let last_hotkey_emission_drain: u64 = LastHotkeyEmissionDrain::::get(hotkey); + + // --- 3 Update the block value to the current block number. + LastHotkeyEmissionDrain::::insert(hotkey, block_number); + + // --- 4 Retrieve the total stake for the hotkey from all nominations. + let total_hotkey_stake: u64 = Self::get_total_stake_for_hotkey(hotkey); + + // --- 5 Calculate the emission take for the hotkey. + let take_proportion: I64F64 = + I64F64::from_num(Delegates::::get(hotkey)).saturating_div(I64F64::from_num(u16::MAX)); + let hotkey_take: u64 = + (take_proportion.saturating_mul(I64F64::from_num(emission))).to_num::(); + + // --- 6 Compute the remaining emission after deducting the hotkey's take. + let emission_minus_take: u64 = emission.saturating_sub(hotkey_take); + + // --- 7 Calculate the remaining emission after the hotkey's take. + let mut remainder: u64 = emission_minus_take; + + // --- 8 Iterate over each nominator. + for (nominator, nominator_stake) in + as IterableStorageDoubleMap>::iter_prefix(hotkey) + { + // --- 9 Check if the stake was manually increased by the user since the last emission drain for this hotkey. + // If it was, skip this nominator as they will not receive their proportion of the emission. + if LastAddStakeIncrease::::get(hotkey, nominator.clone()) > last_hotkey_emission_drain { + continue; + } + + // --- 10 Calculate this nominator's share of the emission. + let nominator_emission: I64F64 = I64F64::from_num(emission_minus_take) + .saturating_mul(I64F64::from_num(nominator_stake)) + .saturating_div(I64F64::from_num(total_hotkey_stake)); + + // --- 11 Increase the stake for the nominator. + Self::increase_stake_on_coldkey_hotkey_account( + &nominator, + hotkey, + nominator_emission.to_num::(), + ); + + // --- 11* Record event and Subtract the nominator's emission from the remainder. + total_new_tao = total_new_tao.saturating_add(nominator_emission.to_num::()); + remainder = remainder.saturating_sub(nominator_emission.to_num::()); + } + + // --- 13 Finally, add the stake to the hotkey itself, including its take and the remaining emission. + let hotkey_new_tao: u64 = hotkey_take.saturating_add(remainder); + Self::increase_stake_on_hotkey_account(hotkey, hotkey_new_tao); + + // --- 14 Record new tao creation event and return the amount created. + total_new_tao = total_new_tao.saturating_add(hotkey_new_tao); + total_new_tao + } + + /////////////// + /// Helpers /// + /////////////// + /// Determines whether the hotkey emission should be drained based on the current block and index. + /// + /// # Arguments + /// * `hotkey_i` - The hotkey identifier. + /// * `index` - The index of the hotkey in the iterable storage. + /// * `block` - The current block number. + /// + /// # Returns + /// * `bool` - True if the hotkey emission should be drained, false otherwise. + pub fn should_drain_hotkey(hotkey: &T::AccountId, block: u64, emit_tempo: u64) -> bool { + let hotkey_idx: u64 = Self::hash_hotkey_to_u64(hotkey); + block.rem_euclid(emit_tempo.saturating_add(1)) + == hotkey_idx.rem_euclid(emit_tempo.saturating_add(1)) + } + + /// Checks if the epoch should run for a given subnet based on the current block. + /// + /// # Arguments + /// * `netuid` - The unique identifier of the subnet. + /// + /// # Returns + /// * `bool` - True if the epoch should run, false otherwise. + pub fn should_run_epoch(netuid: u16, current_block: u64) -> bool { + Self::blocks_until_next_epoch(netuid, Self::get_tempo(netuid), current_block) == 0 + } + + /// Helper function which returns the number of blocks remaining before we will run the epoch on this + /// network. Networks run their epoch when (block_number + netuid + 1 ) % (tempo + 1) = 0 + /// tempo | netuid | # first epoch block + /// 1 0 0 + /// 1 1 1 + /// 2 0 1 + /// 2 1 0 + /// 100 0 99 + /// 100 1 98 + /// Special case: tempo = 0, the network never runs. + /// + pub fn blocks_until_next_epoch(netuid: u16, tempo: u16, block_number: u64) -> u64 { + if tempo == 0 { + return u64::MAX; + } + (tempo as u64).saturating_sub( + (block_number.saturating_add((netuid as u64).saturating_add(1))) + % (tempo as u64).saturating_add(1), + ) + } +} \ No newline at end of file diff --git a/pallets/subtensor/src/epoch/run_epoch.rs b/pallets/subtensor/src/epoch/run_epoch.rs index d67eeded00..1cb2c34480 100644 --- a/pallets/subtensor/src/epoch/run_epoch.rs +++ b/pallets/subtensor/src/epoch/run_epoch.rs @@ -5,6 +5,89 @@ use sp_std::vec; use substrate_fixed::types::{I32F32, I64F64, I96F32}; impl Pallet { + /// Calculates the total stake held by a hotkey on the network, considering child/parent relationships. + /// + /// This function performs the following steps: + /// 1. Checks for self-loops in the delegation graph. + /// 2. Retrieves the initial stake of the hotkey. + /// 3. Calculates the stake allocated to children. + /// 4. Calculates the stake received from parents. + /// 5. Computes the final stake by adjusting the initial stake with child and parent contributions. + /// + /// # Arguments + /// * `hotkey` - AccountId of the hotkey whose total network stake is to be calculated. + /// * `netuid` - Network unique identifier specifying the network context. + /// + /// # Returns + /// * `u64` - The total stake for the hotkey on the network after considering the stakes + /// from children and parents. + /// + /// # Note + /// This function now includes a check for self-loops in the delegation graph using the + /// `dfs_check_self_loops` method. However, it currently only logs warnings for detected loops + /// and does not alter the stake calculation based on these findings. + /// + /// # Panics + /// This function does not explicitly panic, but underlying arithmetic operations + /// use saturating arithmetic to prevent overflows. + /// + /// TODO: check for self loops. + /// TODO: (@distributedstatemachine): check if we should return error , otherwise self loop + /// detection is impossible to test. + pub fn get_stake_for_hotkey_on_subnet(hotkey: &T::AccountId, netuid: u16) -> u64 { + // Retrieve the initial total stake for the hotkey without any child/parent adjustments. + let initial_stake: u64 = Self::get_total_stake_for_hotkey(hotkey); + let mut stake_to_children: u64 = 0; + let mut stake_from_parents: u64 = 0; + + // Retrieve lists of parents and children from storage, based on the hotkey and network ID. + let parents: Vec<(u64, T::AccountId)> = Self::get_parents(hotkey, netuid); + let children: Vec<(u64, T::AccountId)> = Self::get_children(hotkey, netuid); + + // Iterate over children to calculate the total stake allocated to them. + for (proportion, _) in children { + // Calculate the stake proportion allocated to the child based on the initial stake. + let normalized_proportion: I96F32 = + I96F32::from_num(proportion).saturating_div(I96F32::from_num(u64::MAX)); + let stake_proportion_to_child: I96F32 = + I96F32::from_num(initial_stake).saturating_mul(normalized_proportion); + + // Accumulate the total stake given to children. + stake_to_children = + stake_to_children.saturating_add(stake_proportion_to_child.to_num::()); + } + + // Iterate over parents to calculate the total stake received from them. + for (proportion, parent) in parents { + // Retrieve the parent's total stake. + let parent_stake: u64 = Self::get_total_stake_for_hotkey(&parent); + // Calculate the stake proportion received from the parent. + let normalized_proportion: I96F32 = + I96F32::from_num(proportion).saturating_div(I96F32::from_num(u64::MAX)); + let stake_proportion_from_parent: I96F32 = + I96F32::from_num(parent_stake).saturating_mul(normalized_proportion); + + // Accumulate the total stake received from parents. + stake_from_parents = + stake_from_parents.saturating_add(stake_proportion_from_parent.to_num::()); + } + + // Calculate the final stake for the hotkey by adjusting the initial stake with the stakes + // to/from children and parents. + let mut finalized_stake: u64 = initial_stake + .saturating_sub(stake_to_children) + .saturating_add(stake_from_parents); + + // get the max stake for the network + let max_stake = Self::get_network_max_stake(netuid); + + // Return the finalized stake value for the hotkey, but capped at the max stake. + finalized_stake = finalized_stake.min(max_stake); + + // Return the finalized stake value for the hotkey. + finalized_stake + } + /// Calculates reward consensus and returns the emissions for uids/hotkeys in a given `netuid`. /// (Dense version used only for testing purposes.) #[allow(clippy::indexing_slicing)] @@ -67,7 +150,8 @@ impl Pallet { // Access network stake as normalized vector. let mut stake_64: Vec = vec![I64F64::from_num(0.0); n as usize]; for (uid_i, hotkey) in &hotkeys { - stake_64[*uid_i as usize] = I64F64::from_num(Self::get_total_stake_for_hotkey(hotkey)); + stake_64[*uid_i as usize] = + I64F64::from_num(Self::get_stake_for_hotkey_on_subnet(hotkey, netuid)); } inplace_normalize_64(&mut stake_64); let stake: Vec = vec_fixed64_to_fixed32(stake_64); @@ -265,6 +349,10 @@ impl Pallet { // == Value storage == // =================== let cloned_emission: Vec = combined_emission.clone(); + let cloned_stake_weight: Vec = stake + .iter() + .map(|xi| fixed_proportion_to_u16(*xi)) + .collect::>(); let cloned_ranks: Vec = ranks .iter() .map(|xi| fixed_proportion_to_u16(*xi)) @@ -290,6 +378,7 @@ impl Pallet { .iter() .map(|xi| fixed_proportion_to_u16(*xi)) .collect::>(); + StakeWeight::::insert(netuid, cloned_stake_weight.clone()); Active::::insert(netuid, active.clone()); Emission::::insert(netuid, cloned_emission); Rank::::insert(netuid, cloned_ranks); @@ -395,7 +484,8 @@ impl Pallet { // Access network stake as normalized vector. let mut stake_64: Vec = vec![I64F64::from_num(0.0); n as usize]; for (uid_i, hotkey) in &hotkeys { - stake_64[*uid_i as usize] = I64F64::from_num(Self::get_total_stake_for_hotkey(hotkey)); + stake_64[*uid_i as usize] = + I64F64::from_num(Self::get_stake_for_hotkey_on_subnet(hotkey, netuid)); } log::trace!("Stake : {:?}", &stake_64); inplace_normalize_64(&mut stake_64); @@ -631,6 +721,10 @@ impl Pallet { // =================== // == Value storage == // =================== + let cloned_stake_weight: Vec = stake + .iter() + .map(|xi| fixed_proportion_to_u16(*xi)) + .collect::>(); let cloned_emission: Vec = combined_emission.clone(); let cloned_ranks: Vec = ranks .iter() @@ -657,6 +751,7 @@ impl Pallet { .iter() .map(|xi| fixed_proportion_to_u16(*xi)) .collect::>(); + StakeWeight::::insert(netuid, cloned_stake_weight.clone()); Active::::insert(netuid, active.clone()); Emission::::insert(netuid, cloned_emission); Rank::::insert(netuid, cloned_ranks); diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index c28da051d3..8d2b5c4fdd 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -930,6 +930,9 @@ pub mod pallet { /// ======================================= /// ==== Subnetwork Consensus Storage ==== /// ======================================= + #[pallet::storage] // --- DMAP ( netuid ) --> stake_weight | weight for stake used in YC. + pub(super) type StakeWeight = + StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; #[pallet::storage] /// --- DMAP ( netuid, hotkey ) --> uid pub type Uids = diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 228bec6e4d..d8cb31166a 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -842,5 +842,64 @@ mod dispatches { ) -> DispatchResult { Ok(()) } + + /// Set a single child for a given hotkey on a specified network. + /// + /// This function allows a coldkey to set a single child for a given hotkey on a specified network. + /// The proportion of the hotkey's stake to be allocated to the child is also specified. + /// + /// # Arguments: + /// * `origin` (::RuntimeOrigin): + /// - The signature of the calling coldkey. Setting a hotkey child can only be done by the coldkey. + /// + /// * `hotkey` (T::AccountId): + /// - The hotkey which will be assigned the child. + /// + /// * `child` (T::AccountId): + /// - The child which will be assigned to the hotkey. + /// + /// * `netuid` (u16): + /// - The u16 network identifier where the childkey will exist. + /// + /// * `proportion` (u64): + /// - Proportion of the hotkey's stake to be given to the child, the value must be u64 normalized. + /// + /// # Events: + /// * `ChildAddedSingular`: + /// - On successfully registering a child to a hotkey. + /// + /// # Errors: + /// * `SubNetworkDoesNotExist`: + /// - Attempting to register to a non-existent network. + /// * `RegistrationNotPermittedOnRootSubnet`: + /// - Attempting to register a child on the root network. + /// * `NonAssociatedColdKey`: + /// - The coldkey does not own the hotkey or the child is the same as the hotkey. + /// * `HotKeyAccountNotExists`: + /// - The hotkey account does not exist. + /// + /// # Detailed Explanation of Checks: + /// 1. **Signature Verification**: Ensures that the caller has signed the transaction, verifying the coldkey. + /// 2. **Root Network Check**: Ensures that the delegation is not on the root network, as child hotkeys are not valid on the root. + /// 3. **Network Existence Check**: Ensures that the specified network exists. + /// 4. **Ownership Verification**: Ensures that the coldkey owns the hotkey. + /// 5. **Hotkey Account Existence Check**: Ensures that the hotkey account already exists. + /// 6. **Child-Hotkey Distinction**: Ensures that the child is not the same as the hotkey. + /// 7. **Old Children Cleanup**: Removes the hotkey from the parent list of its old children. + /// 8. **New Children Assignment**: Assigns the new child to the hotkey and updates the parent list for the new child. + // TODO: Benchmark this call + #[pallet::call_index(67)] + #[pallet::weight((Weight::from_parts(119_000_000, 0) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(31)), DispatchClass::Operational, Pays::Yes))] + pub fn set_children( + origin: T::RuntimeOrigin, + hotkey: T::AccountId, + netuid: u16, + children: Vec<(u64, T::AccountId)>, + ) -> DispatchResultWithPostInfo { + Self::do_set_children(origin, hotkey, netuid, children)?; + Ok(().into()) + } } } diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index f26a1cd55a..7e244834d0 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -158,5 +158,13 @@ mod errors { InsufficientBalanceToPerformColdkeySwap, /// The maximum number of coldkey destinations has been reached MaxColdkeyDestinationsReached, + /// Attempting to set an invalid child for a hotkey on a network. + InvalidChild, + /// Duplicate child when setting children. + DuplicateChild, + /// Proportion overflow when setting children. + ProportionOverflow, + /// Too many children MAX 5. + TooManyChildren, } } diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index a5fb90e3fa..e3e47f32eb 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -171,5 +171,6 @@ mod events { /// The account ID of the coldkey coldkey: T::AccountId, }, + SetChildren(T::AccountId, u16, Vec<(u64, T::AccountId)>), } } diff --git a/pallets/subtensor/src/rpc_info/neuron_info.rs b/pallets/subtensor/src/rpc_info/neuron_info.rs index a4b58d666a..6b370afd8f 100644 --- a/pallets/subtensor/src/rpc_info/neuron_info.rs +++ b/pallets/subtensor/src/rpc_info/neuron_info.rs @@ -117,14 +117,10 @@ impl Pallet { } }) .collect::, Compact)>>(); - - let stake: Vec<(T::AccountId, Compact)> = - as IterableStorageDoubleMap>::iter_prefix( - hotkey.clone(), - ) - .map(|(coldkey, stake)| (coldkey, stake.into())) - .collect(); - + let stake: Vec<(T::AccountId, Compact)> = vec![( + coldkey, + Self::get_stake_for_hotkey_on_subnet(hotkey, netuid).into(), + )]; let neuron = NeuronInfo { hotkey: hotkey.clone(), coldkey: coldkey.clone(), diff --git a/pallets/subtensor/src/staking/mod.rs b/pallets/subtensor/src/staking/mod.rs index 5e1b5f6bf4..0b3894b613 100644 --- a/pallets/subtensor/src/staking/mod.rs +++ b/pallets/subtensor/src/staking/mod.rs @@ -5,3 +5,4 @@ pub mod decrease_take; pub mod helpers; pub mod increase_take; pub mod remove_stake; +pub mod set_children; diff --git a/pallets/subtensor/src/staking/set_children.rs b/pallets/subtensor/src/staking/set_children.rs new file mode 100644 index 0000000000..79898b6ae7 --- /dev/null +++ b/pallets/subtensor/src/staking/set_children.rs @@ -0,0 +1,185 @@ +use super::*; +use substrate_fixed::types::I96F32; + +impl Pallet { + /// ---- The implementation for the extrinsic do_set_child_singular: Sets a single child. + /// + /// This function allows a coldkey to set children keys. + /// + /// # Arguments: + /// * `origin` (::RuntimeOrigin): + /// - The signature of the calling coldkey. Setting a hotkey child can only be done by the coldkey. + /// + /// * `hotkey` (T::AccountId): + /// - The hotkey which will be assigned the child. + /// + /// * `netuid` (u16): + /// - The u16 network identifier where the child keys will exist. + /// + /// * `children` Vec[(u64, T::AccountId)]: + /// - A list of children with their proportions. + /// + /// # Events: + /// * `ChildrenAdded`: + /// - On successfully registering children to a hotkey. + /// + /// # Errors: + /// * `SubNetworkDoesNotExist`: + /// - Attempting to register to a non-existent network. + /// * `RegistrationNotPermittedOnRootSubnet`: + /// - Attempting to register a child on the root network. + /// * `NonAssociatedColdKey`: + /// - The coldkey does not own the hotkey or the child is the same as the hotkey. + /// * `HotKeyAccountNotExists`: + /// - The hotkey account does not exist. + /// + /// # Detailed Explanation of Checks: + /// 1. **Signature Verification**: Ensures that the caller has signed the transaction, verifying the coldkey. + /// 2. **Root Network Check**: Ensures that the delegation is not on the root network, as child hotkeys are not valid on the root. + /// 3. **Network Existence Check**: Ensures that the specified network exists. + /// 4. **Ownership Verification**: Ensures that the coldkey owns the hotkey. + /// 5. **Hotkey Account Existence Check**: Ensures that the hotkey account already exists. + /// 6. **Child-Hotkey Distinction**: Ensures that the child is not the same as the hotkey. + /// 7. **Old Children Cleanup**: Removes the hotkey from the parent list of its old children. + /// 8. **New Children Assignment**: Assigns the new child to the hotkey and updates the parent list for the new child. + /// + pub fn do_set_children( + origin: T::RuntimeOrigin, + hotkey: T::AccountId, + netuid: u16, + children: Vec<(u64, T::AccountId)>, + ) -> DispatchResult { + // --- 1. Check that the caller has signed the transaction. (the coldkey of the pairing) + let coldkey = ensure_signed(origin)?; + log::trace!( + "do_set_children( coldkey:{:?} hotkey:{:?} netuid:{:?} children:{:?} )", + coldkey, + netuid, + hotkey, + children + ); + + // --- 2. Check that this delegation is not on the root network. Child hotkeys are not valid on root. + ensure!( + netuid != Self::get_root_netuid(), + Error::::RegistrationNotPermittedOnRootSubnet + ); + + // --- 3. Check that the network we are trying to create the child on exists. + ensure!( + Self::if_subnet_exist(netuid), + Error::::SubNetworkDoesNotExist + ); + + // --- 4. Check that the coldkey owns the hotkey. + ensure!( + Self::coldkey_owns_hotkey(&coldkey, &hotkey), + Error::::NonAssociatedColdKey + ); + + // --- 4.1. Ensure that the number of children does not exceed 5. + ensure!(children.len() <= 5, Error::::TooManyChildren); + + // --- 5. Ensure that each child is not the hotkey. + for (_, child_i) in &children { + ensure!(child_i != &hotkey, Error::::InvalidChild); + } + // --- 5.1. Ensure that the sum of the proportions does not exceed u64::MAX. + let _total_proportion: u64 = children + .iter() + .try_fold(0u64, |acc, &(proportion, _)| acc.checked_add(proportion)) + .ok_or(Error::::ProportionOverflow)?; + + // --- 5.2. Ensure there are no duplicates in the list of children. + let mut unique_children = Vec::new(); + for (_, child_i) in &children { + ensure!( + !unique_children.contains(child_i), + Error::::DuplicateChild + ); + unique_children.push(child_i.clone()); + } + + // --- 6. Erase myself from old children's parents. + let old_children: Vec<(u64, T::AccountId)> = ChildKeys::::get(hotkey.clone(), netuid); + + // --- 6.0. Iterate over all my old children and remove myself from their parent's map. + for (_, old_child_i) in old_children.clone().iter() { + // --- 6.1. Get the old child's parents on this network. + let my_old_child_parents: Vec<(u64, T::AccountId)> = + ParentKeys::::get(old_child_i.clone(), netuid); + + // --- 6.2. Filter my hotkey from my old children's parents list. + let filtered_parents: Vec<(u64, T::AccountId)> = my_old_child_parents + .into_iter() + .filter(|(_, parent)| *parent != hotkey) + .collect(); + + // --- 6.3. Update the parent list in storage + ParentKeys::::insert(old_child_i, netuid, filtered_parents); + } + + // --- 7.1. Insert my new children + proportion list into the map. + ChildKeys::::insert(hotkey.clone(), netuid, children.clone()); + + // --- 7.2. Update the parents list for my new children. + for (proportion, new_child_i) in children.clone().iter() { + // --- 8.2.1. Get the child's parents on this network. + let mut new_child_previous_parents: Vec<(u64, T::AccountId)> = + ParentKeys::::get(new_child_i.clone(), netuid); + + // --- 7.2.2. Append my hotkey and proportion to my new child's parents list. + // NOTE: There are no duplicates possible because I previously removed my self from my old children. + new_child_previous_parents.push((*proportion, hotkey.clone())); + + // --- 7.2.3. Update the parents list in storage. + ParentKeys::::insert(new_child_i.clone(), netuid, new_child_previous_parents); + } + + // --- 8. Log and return. + log::trace!( + "SetChildren( netuid:{:?}, hotkey:{:?}, children:{:?} )", + hotkey, + netuid, + children.clone() + ); + Self::deposit_event(Event::SetChildren(hotkey.clone(), netuid, children.clone())); + + // Ok and return. + Ok(()) + } + + /* Retrieves the list of children for a given hotkey and network. + /// + /// # Arguments + /// * `hotkey` - The hotkey whose children are to be retrieved. + /// * `netuid` - The network identifier. + /// + /// # Returns + /// * `Vec<(u64, T::AccountId)>` - A vector of tuples containing the proportion and child account ID. + /// + /// # Example + /// ``` + /// let children = SubtensorModule::get_children(&hotkey, netuid); + */ + pub fn get_children(hotkey: &T::AccountId, netuid: u16) -> Vec<(u64, T::AccountId)> { + ChildKeys::::get(hotkey, netuid) + } + + /* Retrieves the list of parents for a given child and network. + /// + /// # Arguments + /// * `child` - The child whose parents are to be retrieved. + /// * `netuid` - The network identifier. + /// + /// # Returns + /// * `Vec<(u64, T::AccountId)>` - A vector of tuples containing the proportion and parent account ID. + /// + /// # Example + /// ``` + /// let parents = SubtensorModule::get_parents(&child, netuid); + */ + pub fn get_parents(child: &T::AccountId, netuid: u16) -> Vec<(u64, T::AccountId)> { + ParentKeys::::get(child, netuid) + } +} diff --git a/pallets/subtensor/src/subnets/registration.rs b/pallets/subtensor/src/subnets/registration.rs index 4688bcbb59..b46a50eb21 100644 --- a/pallets/subtensor/src/subnets/registration.rs +++ b/pallets/subtensor/src/subnets/registration.rs @@ -543,6 +543,17 @@ impl Pallet { H256::from_slice(&keccak_256_seal_hash_vec) } + pub fn hash_hotkey_to_u64(hotkey: &T::AccountId) -> u64 { + let binding = hotkey.encode(); + let (hotkey_bytes, _) = binding.split_at(32); + let mut full_bytes = [0u8; 64]; + // Copy the hotkey_bytes into the first half of full_bytes + full_bytes[..32].copy_from_slice(hotkey_bytes); + let keccak_256_seal_hash_vec: [u8; 32] = keccak_256(&full_bytes[..]); + let hash_u64: u64 = u64::from_le_bytes(keccak_256_seal_hash_vec[0..8].try_into().unwrap()); + hash_u64 + } + pub fn create_seal_hash(block_number_u64: u64, nonce_u64: u64, hotkey: &T::AccountId) -> H256 { let nonce = nonce_u64.to_le_bytes(); let block_hash_at_number: H256 = Self::get_block_hash_from_u64(block_number_u64); diff --git a/pallets/subtensor/src/utils.rs b/pallets/subtensor/src/utils.rs index c61133e947..a1929f4987 100644 --- a/pallets/subtensor/src/utils.rs +++ b/pallets/subtensor/src/utils.rs @@ -695,4 +695,20 @@ impl Pallet { pub fn get_liquid_alpha_enabled(netuid: u16) -> bool { LiquidAlphaOn::::get(netuid) } + + /// Gets the current hotkey emission tempo. + /// + /// # Returns + /// * `u64` - The current emission tempo value. + pub fn get_hotkey_emission_tempo() -> u64 { + HotkeyEmissionTempo::::get() + } + /// Sets the hotkey emission tempo. + /// + /// # Arguments + /// * `emission_tempo` - The new emission tempo value to set. + pub fn set_hotkey_emission_tempo(emission_tempo: u64) { + HotkeyEmissionTempo::::set(emission_tempo); + Self::deposit_event(Event::HotkeyEmissionTempoSet(emission_tempo)); + } } diff --git a/pallets/subtensor/tests/children.rs b/pallets/subtensor/tests/children.rs new file mode 100644 index 0000000000..9ad07e1e7a --- /dev/null +++ b/pallets/subtensor/tests/children.rs @@ -0,0 +1,1261 @@ +use crate::mock::*; +use frame_support::{assert_err, assert_ok}; +mod mock; +use pallet_subtensor::*; +use sp_core::U256; + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_success --exact --nocapture +#[test] +fn test_do_set_child_singular_success() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child = U256::from(3); + let netuid: u16 = 1; + let proportion: u64 = 1000; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set child + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, child)] + )); + + // Verify child assignment + let children = SubtensorModule::get_children(&hotkey, netuid); + assert_eq!(children, vec![(proportion, child)]); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_network_does_not_exist --exact --nocapture +#[test] +fn test_do_set_child_singular_network_does_not_exist() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child = U256::from(3); + let netuid: u16 = 999; // Non-existent network + let proportion: u64 = 1000; + + // Attempt to set child + assert_err!( + SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, child)] + ), + Error::::SubNetworkDoesNotExist + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_invalid_child --exact --nocapture +#[test] +fn test_do_set_child_singular_invalid_child() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let netuid: u16 = 1; + let proportion: u64 = 1000; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Attempt to set child as the same hotkey + assert_err!( + SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![ + (proportion, hotkey) // Invalid child + ] + ), + Error::::InvalidChild + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_non_associated_coldkey --exact --nocapture +#[test] +fn test_do_set_child_singular_non_associated_coldkey() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child = U256::from(3); + let netuid: u16 = 1; + let proportion: u64 = 1000; + + // Add network and register hotkey with a different coldkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, U256::from(999), 0); + + // Attempt to set child + assert_err!( + SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, child)] + ), + Error::::NonAssociatedColdKey + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_root_network --exact --nocapture +#[test] +fn test_do_set_child_singular_root_network() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child = U256::from(3); + let netuid: u16 = SubtensorModule::get_root_netuid(); // Root network + let proportion: u64 = 1000; + + // Add network and register hotkey + add_network(netuid, 13, 0); + + // Attempt to set child + assert_err!( + SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, child)] + ), + Error::::RegistrationNotPermittedOnRootSubnet + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_old_children_cleanup --exact --nocapture +#[test] +fn test_do_set_child_singular_old_children_cleanup() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let old_child = U256::from(3); + let new_child = U256::from(4); + let netuid: u16 = 1; + let proportion: u64 = 1000; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set old child + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, old_child)] + )); + + // Set new child + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, new_child)] + )); + + // Verify old child is removed + let old_child_parents = SubtensorModule::get_parents(&old_child, netuid); + assert!(old_child_parents.is_empty()); + + // Verify new child assignment + let new_child_parents = SubtensorModule::get_parents(&new_child, netuid); + assert_eq!(new_child_parents, vec![(proportion, hotkey)]); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_old_children_cleanup --exact --nocapture +#[test] +fn test_do_set_child_singular_new_children_assignment() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child = U256::from(3); + let netuid: u16 = 1; + let proportion: u64 = 1000; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set child + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, child)] + )); + + // Verify child assignment + let children = SubtensorModule::get_children(&hotkey, netuid); + assert_eq!(children, vec![(proportion, child)]); + + // Verify parent assignment + let parents = SubtensorModule::get_parents(&child, netuid); + assert_eq!(parents, vec![(proportion, hotkey)]); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_proportion_edge_cases --exact --nocapture +#[test] +fn test_do_set_child_singular_proportion_edge_cases() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child = U256::from(3); + let netuid: u16 = 1; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set child with minimum proportion + let min_proportion: u64 = 0; + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(min_proportion, child)] + )); + + // Verify child assignment with minimum proportion + let children = SubtensorModule::get_children(&hotkey, netuid); + assert_eq!(children, vec![(min_proportion, child)]); + + // Set child with maximum proportion + let max_proportion: u64 = u64::MAX; + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(max_proportion, child)] + )); + + // Verify child assignment with maximum proportion + let children = SubtensorModule::get_children(&hotkey, netuid); + assert_eq!(children, vec![(max_proportion, child)]); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_multiple_children --exact --nocapture +#[test] +fn test_do_set_child_singular_multiple_children() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child1 = U256::from(3); + let child2 = U256::from(4); + let netuid: u16 = 1; + let proportion1: u64 = 500; + let proportion2: u64 = 500; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set first child + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion1, child1)] + )); + + // Set second child + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion2, child2)] + )); + + // Verify children assignment + let children = SubtensorModule::get_children(&hotkey, netuid); + assert_eq!(children, vec![(proportion2, child2)]); + + // Verify parent assignment for both children + let parents1 = SubtensorModule::get_parents(&child1, netuid); + assert!(parents1.is_empty()); // Old child should be removed + + let parents2 = SubtensorModule::get_parents(&child2, netuid); + assert_eq!(parents2, vec![(proportion2, hotkey)]); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_add_singular_child --exact --nocapture +#[test] +#[cfg(not(tarpaulin))] +fn test_add_singular_child() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let child = U256::from(1); + let hotkey = U256::from(1); + let coldkey = U256::from(2); + assert_eq!( + SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(u64::MAX, child)] + ), + Err(Error::::SubNetworkDoesNotExist.into()) + ); + add_network(netuid, 0, 0); + assert_eq!( + SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(u64::MAX, child)] + ), + Err(Error::::NonAssociatedColdKey.into()) + ); + SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey); + assert_eq!( + SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(u64::MAX, child)] + ), + Err(Error::::InvalidChild.into()) + ); + let child = U256::from(3); + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(u64::MAX, child)] + )); + }) +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_get_stake_for_hotkey_on_subnet --exact --nocapture +#[test] +fn test_get_stake_for_hotkey_on_subnet() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let hotkey0 = U256::from(1); + let hotkey1 = U256::from(2); + let coldkey0 = U256::from(3); + let coldkey1 = U256::from(4); + + add_network(netuid, 0, 0); + + let max_stake: u64 = 3000; + SubtensorModule::set_network_max_stake(netuid, max_stake); + + SubtensorModule::create_account_if_non_existent(&coldkey0, &hotkey0); + SubtensorModule::create_account_if_non_existent(&coldkey1, &hotkey1); + + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey0, &hotkey0, 1000); + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey0, &hotkey1, 1000); + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey1, &hotkey0, 1000); + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey1, &hotkey1, 1000); + + assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 2000); + assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 2000); + + assert_eq!( + SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey0, netuid), + 2000 + ); + assert_eq!( + SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey1, netuid), + 2000 + ); + + // Set child relationship + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey0), + hotkey0, + netuid, + vec![(u64::MAX, hotkey1)] + )); + + // Check stakes after setting child + let stake0 = SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey0, netuid); + let stake1 = SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey1, netuid); + + assert_eq!(stake0, 0); + assert_eq!(stake1, max_stake); + + // Change child relationship to 50% + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey0), + hotkey0, + netuid, + vec![(u64::MAX / 2, hotkey1)] + )); + + // Check stakes after changing child relationship + let stake0 = SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey0, netuid); + let stake1 = SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey1, netuid); + + assert_eq!(stake0, 1001); + assert!(stake1 >= max_stake - 1 && stake1 <= max_stake); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_child_singular_success --exact --nocapture +#[test] +fn test_do_revoke_child_singular_success() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child = U256::from(3); + let netuid: u16 = 1; + let proportion: u64 = 1000; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set child + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, child)] + )); + + // Verify child assignment + let children = SubtensorModule::get_children(&hotkey, netuid); + assert_eq!(children, vec![(proportion, child)]); + + // Revoke child + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![] + )); + + // Verify child removal + let children = SubtensorModule::get_children(&hotkey, netuid); + assert!(children.is_empty()); + + // Verify parent removal + let parents = SubtensorModule::get_parents(&child, netuid); + assert!(parents.is_empty()); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_child_singular_network_does_not_exist --exact --nocapture +#[test] +fn test_do_revoke_child_singular_network_does_not_exist() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let netuid: u16 = 999; // Non-existent network + + // Attempt to revoke child + assert_err!( + SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![] + ), + Error::::SubNetworkDoesNotExist + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_child_singular_non_associated_coldkey --exact --nocapture +#[test] +fn test_do_revoke_child_singular_non_associated_coldkey() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let netuid: u16 = 1; + + // Add network and register hotkey with a different coldkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, U256::from(999), 0); + + // Attempt to revoke child + assert_err!( + SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![] + ), + Error::::NonAssociatedColdKey + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_child_singular_child_not_associated --exact --nocapture +#[test] +fn test_do_revoke_child_singular_child_not_associated() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child = U256::from(3); + let netuid: u16 = 1; + + // Add network and register hotkey + add_network(netuid, 13, 0); + // Attempt to revoke child that is not associated + assert_err!( + SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(u64::MAX, child)] + ), + Error::::NonAssociatedColdKey + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_success --exact --nocapture +#[test] +fn test_do_set_children_multiple_success() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child1 = U256::from(3); + let child2 = U256::from(4); + let netuid: u16 = 1; + let proportion1: u64 = 1000; + let proportion2: u64 = 2000; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set multiple children + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion1, child1), (proportion2, child2)] + )); + + // Verify children assignment + let children = SubtensorModule::get_children(&hotkey, netuid); + assert_eq!(children, vec![(proportion1, child1), (proportion2, child2)]); + + // Verify parent assignment for both children + let parents1 = SubtensorModule::get_parents(&child1, netuid); + assert_eq!(parents1, vec![(proportion1, hotkey)]); + + let parents2 = SubtensorModule::get_parents(&child2, netuid); + assert_eq!(parents2, vec![(proportion2, hotkey)]); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_network_does_not_exist --exact --nocapture +#[test] +fn test_do_set_children_multiple_network_does_not_exist() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child1 = U256::from(3); + let netuid: u16 = 999; // Non-existent network + let proportion: u64 = 1000; + + // Attempt to set children + assert_err!( + SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, child1)] + ), + Error::::SubNetworkDoesNotExist + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_invalid_child --exact --nocapture +#[test] +fn test_do_set_children_multiple_invalid_child() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let netuid: u16 = 1; + let proportion: u64 = 1000; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Attempt to set child as the same hotkey + assert_err!( + SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, hotkey)] + ), + Error::::InvalidChild + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_non_associated_coldkey --exact --nocapture +#[test] +fn test_do_set_children_multiple_non_associated_coldkey() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child = U256::from(3); + let netuid: u16 = 1; + let proportion: u64 = 1000; + + // Add network and register hotkey with a different coldkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, U256::from(999), 0); + + // Attempt to set children + assert_err!( + SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, child)] + ), + Error::::NonAssociatedColdKey + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_root_network --exact --nocapture +#[test] +fn test_do_set_children_multiple_root_network() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child = U256::from(3); + let netuid: u16 = SubtensorModule::get_root_netuid(); // Root network + let proportion: u64 = 1000; + + // Add network and register hotkey + add_network(netuid, 13, 0); + + // Attempt to set children + assert_err!( + SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, child)] + ), + Error::::RegistrationNotPermittedOnRootSubnet + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_old_children_cleanup --exact --nocapture +#[test] +fn test_do_set_children_multiple_old_children_cleanup() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let old_child = U256::from(3); + let new_child1 = U256::from(4); + let new_child2 = U256::from(5); + let netuid: u16 = 1; + let proportion: u64 = 1000; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set old child + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, old_child)] + )); + + // Set new children + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, new_child1), (proportion, new_child2)] + )); + + // Verify old child is removed + let old_child_parents = SubtensorModule::get_parents(&old_child, netuid); + assert!(old_child_parents.is_empty()); + + // Verify new children assignment + let new_child1_parents = SubtensorModule::get_parents(&new_child1, netuid); + assert_eq!(new_child1_parents, vec![(proportion, hotkey)]); + + let new_child2_parents = SubtensorModule::get_parents(&new_child2, netuid); + assert_eq!(new_child2_parents, vec![(proportion, hotkey)]); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_proportion_edge_cases --exact --nocapture +#[test] +fn test_do_set_children_multiple_proportion_edge_cases() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child1 = U256::from(3); + let child2 = U256::from(4); + let netuid: u16 = 1; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set children with minimum and maximum proportions + let min_proportion: u64 = 0; + let max_proportion: u64 = u64::MAX; + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(min_proportion, child1), (max_proportion, child2)] + )); + + // Verify children assignment + let children = SubtensorModule::get_children(&hotkey, netuid); + assert_eq!( + children, + vec![(min_proportion, child1), (max_proportion, child2)] + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_overwrite_existing --exact --nocapture +#[test] +fn test_do_set_children_multiple_overwrite_existing() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child1 = U256::from(3); + let child2 = U256::from(4); + let child3 = U256::from(5); + let netuid: u16 = 1; + let proportion: u64 = 1000; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set initial children + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, child1), (proportion, child2)] + )); + + // Overwrite with new children + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion * 2, child2), (proportion * 3, child3)] + )); + + // Verify final children assignment + let children = SubtensorModule::get_children(&hotkey, netuid); + assert_eq!( + children, + vec![(proportion * 2, child2), (proportion * 3, child3)] + ); + + // Verify parent assignment for all children + let parents1 = SubtensorModule::get_parents(&child1, netuid); + assert!(parents1.is_empty()); + + let parents2 = SubtensorModule::get_parents(&child2, netuid); + assert_eq!(parents2, vec![(proportion * 2, hotkey)]); + + let parents3 = SubtensorModule::get_parents(&child3, netuid); + assert_eq!(parents3, vec![(proportion * 3, hotkey)]); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_empty_list --exact --nocapture +#[test] +fn test_do_set_children_multiple_empty_list() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let netuid: u16 = 1; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set empty children list + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![] + )); + + // Verify children assignment is empty + let children = SubtensorModule::get_children(&hotkey, netuid); + assert!(children.is_empty()); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_children_multiple_success --exact --nocapture +#[test] +fn test_do_revoke_children_multiple_success() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child1 = U256::from(3); + let child2 = U256::from(4); + let netuid: u16 = 1; + let proportion1: u64 = 1000; + let proportion2: u64 = 2000; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set multiple children + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion1, child1), (proportion2, child2)] + )); + + // Revoke multiple children + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![] + )); + + // Verify children removal + let children = SubtensorModule::get_children(&hotkey, netuid); + assert!(children.is_empty()); + + // Verify parent removal for both children + let parents1 = SubtensorModule::get_parents(&child1, netuid); + assert!(parents1.is_empty()); + + let parents2 = SubtensorModule::get_parents(&child2, netuid); + assert!(parents2.is_empty()); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_children_multiple_network_does_not_exist --exact --nocapture +#[test] +fn test_do_revoke_children_multiple_network_does_not_exist() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child1 = U256::from(3); + let child2 = U256::from(4); + let netuid: u16 = 999; // Non-existent network + // Attempt to revoke children + assert_err!( + SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(u64::MAX / 2, child1), (u64::MAX / 2, child2)] + ), + Error::::SubNetworkDoesNotExist + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_children_multiple_non_associated_coldkey --exact --nocapture +#[test] +fn test_do_revoke_children_multiple_non_associated_coldkey() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child1 = U256::from(3); + let child2 = U256::from(4); + let netuid: u16 = 1; + + // Add network and register hotkey with a different coldkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, U256::from(999), 0); + + // Attempt to revoke children + assert_err!( + SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(u64::MAX / 2, child1), (u64::MAX / 2, child2)] + ), + Error::::NonAssociatedColdKey + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_children_multiple_partial_revocation --exact --nocapture +#[test] +fn test_do_revoke_children_multiple_partial_revocation() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child1 = U256::from(3); + let child2 = U256::from(4); + let child3 = U256::from(5); + let netuid: u16 = 1; + let proportion: u64 = 1000; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set multiple children + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![ + (proportion, child1), + (proportion, child2), + (proportion, child3) + ] + )); + + // Revoke only child3 + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, child1), (proportion, child2)] + )); + + // Verify children removal + let children = SubtensorModule::get_children(&hotkey, netuid); + assert_eq!(children, vec![(proportion, child1), (proportion, child2)]); + + // Verify parents. + let parents1 = SubtensorModule::get_parents(&child3, netuid); + assert!(parents1.is_empty()); + let parents1 = SubtensorModule::get_parents(&child1, netuid); + assert_eq!(parents1, vec![(proportion, hotkey)]); + let parents2 = SubtensorModule::get_parents(&child2, netuid); + assert_eq!(parents2, vec![(proportion, hotkey)]); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_children_multiple_non_existent_children --exact --nocapture + +#[test] +fn test_do_revoke_children_multiple_non_existent_children() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child1 = U256::from(3); + let netuid: u16 = 1; + let proportion: u64 = 1000; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set one child + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, child1)] + )); + + // Attempt to revoke existing and non-existent children + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![] + )); + + // Verify all children are removed + let children = SubtensorModule::get_children(&hotkey, netuid); + assert!(children.is_empty()); + + // Verify parent removal for the existing child + let parents1 = SubtensorModule::get_parents(&child1, netuid); + assert!(parents1.is_empty()); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_children_multiple_empty_list --exact --nocapture +#[test] +fn test_do_revoke_children_multiple_empty_list() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let netuid: u16 = 1; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Attempt to revoke with an empty list + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![] + )); + + // Verify no changes in children + let children = SubtensorModule::get_children(&hotkey, netuid); + assert!(children.is_empty()); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_children_multiple_complex_scenario --exact --nocapture +#[test] +fn test_do_revoke_children_multiple_complex_scenario() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child1 = U256::from(3); + let child2 = U256::from(4); + let child3 = U256::from(5); + let netuid: u16 = 1; + let proportion1: u64 = 1000; + let proportion2: u64 = 2000; + let proportion3: u64 = 3000; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set multiple children + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![ + (proportion1, child1), + (proportion2, child2), + (proportion3, child3) + ] + )); + + // Revoke child2 + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion1, child1), (proportion3, child3)] + )); + + // Verify remaining children + let children = SubtensorModule::get_children(&hotkey, netuid); + assert_eq!(children, vec![(proportion1, child1), (proportion3, child3)]); + + // Verify parent removal for child2 + let parents2 = SubtensorModule::get_parents(&child2, netuid); + assert!(parents2.is_empty()); + + // Revoke remaining children + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![] + )); + + // Verify all children are removed + let children = SubtensorModule::get_children(&hotkey, netuid); + assert!(children.is_empty()); + + // Verify parent removal for all children + let parents1 = SubtensorModule::get_parents(&child1, netuid); + assert!(parents1.is_empty()); + let parents3 = SubtensorModule::get_parents(&child3, netuid); + assert!(parents3.is_empty()); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_get_network_max_stake --exact --nocapture +#[test] +fn test_get_network_max_stake() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let default_max_stake = SubtensorModule::get_network_max_stake(netuid); + + // Check that the default value is set correctly + assert_eq!(default_max_stake, 500_000_000_000_000); + + // Set a new max stake value + let new_max_stake: u64 = 1_000_000; + SubtensorModule::set_network_max_stake(netuid, new_max_stake); + + // Check that the new value is retrieved correctly + assert_eq!( + SubtensorModule::get_network_max_stake(netuid), + new_max_stake + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_set_network_max_stake --exact --nocapture +#[test] +fn test_set_network_max_stake() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let initial_max_stake = SubtensorModule::get_network_max_stake(netuid); + + // Set a new max stake value + let new_max_stake: u64 = 500_000; + SubtensorModule::set_network_max_stake(netuid, new_max_stake); + + // Check that the new value is set correctly + assert_eq!( + SubtensorModule::get_network_max_stake(netuid), + new_max_stake + ); + assert_ne!( + SubtensorModule::get_network_max_stake(netuid), + initial_max_stake + ); + + // Check that the event is emitted + System::assert_last_event(Event::NetworkMaxStakeSet(netuid, new_max_stake).into()); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_set_network_max_stake_multiple_networks --exact --nocapture +#[test] +fn test_set_network_max_stake_multiple_networks() { + new_test_ext(1).execute_with(|| { + let netuid1: u16 = 1; + let netuid2: u16 = 2; + + // Set different max stake values for two networks + let max_stake1: u64 = 1_000_000; + let max_stake2: u64 = 2_000_000; + SubtensorModule::set_network_max_stake(netuid1, max_stake1); + SubtensorModule::set_network_max_stake(netuid2, max_stake2); + + // Check that the values are set correctly for each network + assert_eq!(SubtensorModule::get_network_max_stake(netuid1), max_stake1); + assert_eq!(SubtensorModule::get_network_max_stake(netuid2), max_stake2); + assert_ne!( + SubtensorModule::get_network_max_stake(netuid1), + SubtensorModule::get_network_max_stake(netuid2) + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_set_network_max_stake_update --exact --nocapture +#[test] +fn test_set_network_max_stake_update() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + + // Set an initial max stake value + let initial_max_stake: u64 = 1_000_000; + SubtensorModule::set_network_max_stake(netuid, initial_max_stake); + + // Update the max stake value + let updated_max_stake: u64 = 1_500_000; + SubtensorModule::set_network_max_stake(netuid, updated_max_stake); + + // Check that the value is updated correctly + assert_eq!( + SubtensorModule::get_network_max_stake(netuid), + updated_max_stake + ); + assert_ne!( + SubtensorModule::get_network_max_stake(netuid), + initial_max_stake + ); + + // Check that the event is emitted for the update + System::assert_last_event(Event::NetworkMaxStakeSet(netuid, updated_max_stake).into()); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_children_stake_values --exact --nocapture +#[test] +fn test_children_stake_values() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child1 = U256::from(3); + let child2 = U256::from(4); + let child3 = U256::from(5); + let netuid: u16 = 1; + let proportion1: u64 = u64::MAX / 4; + let proportion2: u64 = u64::MAX / 4; + let proportion3: u64 = u64::MAX / 4; + + // Add network and register hotkey + add_network(netuid, 13, 0); + SubtensorModule::set_max_registrations_per_block(netuid, 4); + SubtensorModule::set_target_registrations_per_interval(netuid, 4); + register_ok_neuron(netuid, hotkey, coldkey, 0); + register_ok_neuron(netuid, child1, coldkey, 0); + register_ok_neuron(netuid, child2, coldkey, 0); + register_ok_neuron(netuid, child3, coldkey, 0); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &coldkey, + &hotkey, + 100_000_000_000_000, + ); + + // Set multiple children with proportions. + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![ + (proportion1, child1), + (proportion2, child2), + (proportion3, child3) + ] + )); + assert_eq!( + SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey, netuid), + 25_000_000_069_852 + ); + assert_eq!( + SubtensorModule::get_stake_for_hotkey_on_subnet(&child1, netuid), + 24_999_999_976_716 + ); + assert_eq!( + SubtensorModule::get_stake_for_hotkey_on_subnet(&child2, netuid), + 24_999_999_976_716 + ); + assert_eq!( + SubtensorModule::get_stake_for_hotkey_on_subnet(&child3, netuid), + 24_999_999_976_716 + ); + assert_eq!( + SubtensorModule::get_stake_for_hotkey_on_subnet(&child3, netuid) + + SubtensorModule::get_stake_for_hotkey_on_subnet(&child2, netuid) + + SubtensorModule::get_stake_for_hotkey_on_subnet(&child1, netuid) + + SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey, netuid), + 100_000_000_000_000 + ); + }); +} diff --git a/pallets/subtensor/tests/coinbase.rs b/pallets/subtensor/tests/coinbase.rs new file mode 100644 index 0000000000..cd7d2cc81a --- /dev/null +++ b/pallets/subtensor/tests/coinbase.rs @@ -0,0 +1,154 @@ +use crate::mock::*; +mod mock; +// use frame_support::{assert_err, assert_ok}; +use sp_core::U256; + +// Test the ability to hash all sorts of hotkeys. +#[test] +#[cfg(not(tarpaulin))] +fn test_hotkey_hashing() { + new_test_ext(1).execute_with(|| { + for i in 0..10000 { + SubtensorModule::hash_hotkey_to_u64(&U256::from(i)); + } + }); +} + +// Test drain tempo on hotkeys. +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test coinbase test_hotkey_drain_time -- --nocapture +#[test] +#[cfg(not(tarpaulin))] +fn test_hotkey_drain_time() { + new_test_ext(1).execute_with(|| { + // Block 0 + assert!(!SubtensorModule::should_drain_hotkey(&U256::from(0), 0, 1)); + assert!(SubtensorModule::should_drain_hotkey(&U256::from(1), 0, 1)); + assert!(SubtensorModule::should_drain_hotkey(&U256::from(2), 0, 1)); + assert!(SubtensorModule::should_drain_hotkey(&U256::from(3), 0, 1)); + assert!(!SubtensorModule::should_drain_hotkey(&U256::from(4), 0, 1)); + assert!(SubtensorModule::should_drain_hotkey(&U256::from(5), 0, 1)); + assert!(!SubtensorModule::should_drain_hotkey(&U256::from(6), 0, 1)); + assert!(!SubtensorModule::should_drain_hotkey(&U256::from(7), 0, 1)); + + // Block 1 + assert!(SubtensorModule::should_drain_hotkey(&U256::from(0), 1, 1)); + assert!(!SubtensorModule::should_drain_hotkey(&U256::from(1), 1, 1)); + assert!(!SubtensorModule::should_drain_hotkey(&U256::from(2), 1, 1)); + assert!(!SubtensorModule::should_drain_hotkey(&U256::from(3), 1, 1)); + assert!(SubtensorModule::should_drain_hotkey(&U256::from(4), 1, 1)); + assert!(!SubtensorModule::should_drain_hotkey(&U256::from(5), 1, 1)); + assert!(SubtensorModule::should_drain_hotkey(&U256::from(6), 1, 1)); + assert!(SubtensorModule::should_drain_hotkey(&U256::from(7), 1, 1)); + }); +} + +// To run this test specifically, use the following command: +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test coinbase test_coinbase_basic -- --nocapture +#[test] +#[cfg(not(tarpaulin))] +fn test_coinbase_basic() { + new_test_ext(1).execute_with(|| { + // Define network ID + let netuid: u16 = 1; + let hotkey = U256::from(0); + let coldkey = U256::from(3); + + // Create a network with a tempo 1 + add_network(netuid, 1, 0); + register_ok_neuron(netuid, hotkey, coldkey, 100000); + SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey); + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey, &hotkey, 1000); + + // Set the subnet emission value to 1. + SubtensorModule::set_emission_values(&[netuid], vec![1]).unwrap(); + assert_eq!(SubtensorModule::get_subnet_emission_value(netuid), 1); + + // Hotkey has no pending emission + assert_eq!(SubtensorModule::get_pending_hotkey_emission(&hotkey), 0); + + // Hotkey has same stake + assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey), 1000); + + // Subnet has no pending emission. + assert_eq!(SubtensorModule::get_pending_emission(netuid), 0); + + // Step block + next_block(); + + // Hotkey has no pending emission + assert_eq!(SubtensorModule::get_pending_hotkey_emission(&hotkey), 0); + + // Hotkey has same stake + assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey), 1000); + + // Subnet has no pending emission of 1 ( from coinbase ) + assert_eq!(SubtensorModule::get_pending_emission(netuid), 1); + + // Step block releases + next_block(); + + // Subnet pending has been drained. + assert_eq!(SubtensorModule::get_pending_emission(netuid), 0); + + // Hotkey pending immediately drained. + assert_eq!(SubtensorModule::get_pending_hotkey_emission(&hotkey), 0); + + // Hotkey has NEW stake + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey), + 1000 + 2 + ); + + // Set the hotkey drain time to 2 block. + SubtensorModule::set_hotkey_emission_tempo(2); + + // Step block releases + next_block(); + + // Subnet pending increased by 1 + assert_eq!(SubtensorModule::get_pending_emission(netuid), 1); + + // Hotkey pending not increased (still on subnet) + assert_eq!(SubtensorModule::get_pending_hotkey_emission(&hotkey), 0); + + // Hotkey has same stake + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey), + 1000 + 2 + ); + + // Step block releases + next_block(); + + // Subnet pending has been drained. + assert_eq!(SubtensorModule::get_pending_emission(netuid), 0); + + // Hotkey pending drained. + assert_eq!(SubtensorModule::get_pending_hotkey_emission(&hotkey), 0); + + // Hotkey has 2 new TAO. + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey), + 1000 + 4 + ); + }); +} + +// Test getting and setting hotkey emission tempo +#[test] +#[cfg(not(tarpaulin))] +fn test_set_and_get_hotkey_emission_tempo() { + new_test_ext(1).execute_with(|| { + // Get the default hotkey emission tempo + let default_tempo = SubtensorModule::get_hotkey_emission_tempo(); + assert_eq!(default_tempo, 0); // default is 0 in mock.rs + + // Set a new hotkey emission tempo + let new_tempo = 5; + SubtensorModule::set_hotkey_emission_tempo(new_tempo); + + // Get the updated hotkey emission tempo + let updated_tempo = SubtensorModule::get_hotkey_emission_tempo(); + assert_eq!(updated_tempo, new_tempo); + }); +} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 0ed3cd10f0..df1687fdf4 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1213,6 +1213,10 @@ impl fn set_liquid_alpha_enabled(netuid: u16, enabled: bool) { SubtensorModule::set_liquid_alpha_enabled(netuid, enabled); } + + fn set_hotkey_emission_tempo(emission_tempo: u64) { + SubtensorModule::set_hotkey_emission_tempo(emission_tempo); + } fn do_set_alpha_values( origin: RuntimeOrigin, From 8eb7bd9c9c7df4c8d586c1b4f7acdd38b57738ad Mon Sep 17 00:00:00 2001 From: const Date: Mon, 15 Jul 2024 17:03:29 -0500 Subject: [PATCH 10/16] merge childkeys --- pallets/admin-utils/src/benchmarking.rs | 8 + pallets/admin-utils/src/lib.rs | 55 +- pallets/admin-utils/src/weights.rs | 12 - pallets/admin-utils/tests/mock.rs | 8 + pallets/subtensor/src/coinbase/block_step.rs | 4 - .../subtensor/src/coinbase/run_coinbase.rs | 28 +- pallets/subtensor/src/lib.rs | 11 +- pallets/subtensor/src/macros/config.rs | 6 + pallets/subtensor/src/macros/events.rs | 5 + pallets/subtensor/src/rpc_info/neuron_info.rs | 4 +- pallets/subtensor/src/staking/set_children.rs | 1 - pallets/subtensor/src/subnets/registration.rs | 4 +- pallets/subtensor/src/utils.rs | 37 + pallets/subtensor/tests/block_step.rs | 940 -------------- pallets/subtensor/tests/coinbase.rs | 1 + pallets/subtensor/tests/mock.rs | 5 + pallets/subtensor/tests/staking.rs | 1076 ----------------- runtime/src/lib.rs | 10 +- 18 files changed, 162 insertions(+), 2053 deletions(-) delete mode 100644 pallets/subtensor/tests/block_step.rs diff --git a/pallets/admin-utils/src/benchmarking.rs b/pallets/admin-utils/src/benchmarking.rs index 3165e907f5..33e0265535 100644 --- a/pallets/admin-utils/src/benchmarking.rs +++ b/pallets/admin-utils/src/benchmarking.rs @@ -248,5 +248,13 @@ mod benchmarks { _(RawOrigin::Root, 1u64/*emission_tempo*/)/*set_hotkey_emission_tempo*/; } + #[benchmark] + fn sudo_set_network_max_stake() { + T::Subtensor::init_new_network(1u16 /*netuid*/, 1u16 /*tempo*/); + + #[extrinsic_call] + _(RawOrigin::Root, 1u16/*netuid*/, 1_000_000_000_000_000u64/*max_stake*/)/*sudo_set_network_max_stake*/; + } + //impl_benchmark_test_suite!(AdminUtils, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 2aa45cbc97..59b0ed44a6 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -1050,8 +1050,9 @@ pub mod pallet { /// /// # Errors /// * `DispatchError::BadOrigin` - If the origin is not the root account. + // #[pallet::weight(T::WeightInfo::sudo_set_hotkey_emission_tempo())] #[pallet::call_index(52)] - #[pallet::weight(T::WeightInfo::sudo_set_hotkey_emission_tempo())] + #[pallet::weight((0, DispatchClass::Operational, Pays::No))] pub fn sudo_set_hotkey_emission_tempo( origin: OriginFor, emission_tempo: u64, @@ -1064,6 +1065,57 @@ pub mod pallet { ); Ok(()) } + + /// Sets the maximum stake allowed for a specific network. + /// + /// This function allows the root account to set the maximum stake for a given network. + /// It updates the network's maximum stake value and logs the change. + /// + /// # Arguments + /// + /// * `origin` - The origin of the call, which must be the root account. + /// * `netuid` - The unique identifier of the network. + /// * `max_stake` - The new maximum stake value to set. + /// + /// # Returns + /// + /// Returns `Ok(())` if the operation is successful, or an error if it fails. + /// + /// # Example + /// + /// + /// # Notes + /// + /// - This function can only be called by the root account. + /// - The `netuid` should correspond to an existing network. + /// + /// # TODO + /// + // - Consider adding a check to ensure the `netuid` corresponds to an existing network. + // - Implement a mechanism to gradually adjust the max stake to prevent sudden changes. + // #[pallet::weight(T::WeightInfo::sudo_set_network_max_stake())] + #[pallet::call_index(53)] + #[pallet::weight((0, DispatchClass::Operational, Pays::No))] + pub fn sudo_set_network_max_stake( + origin: OriginFor, + netuid: u16, + max_stake: u64, + ) -> DispatchResult { + // Ensure the call is made by the root account + ensure_root(origin)?; + + // Set the new maximum stake for the specified network + T::Subtensor::set_network_max_stake(netuid, max_stake); + + // Log the change + log::trace!( + "NetworkMaxStakeSet( netuid: {:?}, max_stake: {:?} )", + netuid, + max_stake + ); + + Ok(()) + } } } @@ -1167,4 +1219,5 @@ pub trait SubtensorInterface { alpha_high: u16, ) -> Result<(), DispatchError>; fn set_hotkey_emission_tempo(emission_tempo: u64); + fn set_network_max_stake(netuid: u16, max_stake: u64); } diff --git a/pallets/admin-utils/src/weights.rs b/pallets/admin-utils/src/weights.rs index 0c0259ef2b..84fe058f85 100644 --- a/pallets/admin-utils/src/weights.rs +++ b/pallets/admin-utils/src/weights.rs @@ -62,8 +62,6 @@ pub trait WeightInfo { fn sudo_set_tempo() -> Weight; fn sudo_set_commit_reveal_weights_interval() -> Weight; fn sudo_set_commit_reveal_weights_enabled() -> Weight; - fn sudo_set_hotkey_emission_tempo() -> Weight; - } /// Weights for `pallet_admin_utils` using the Substrate node and recommended hardware. @@ -807,14 +805,4 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `SubtensorModule::HotkeyEmissionTempo` (r:0 w:1) - /// Proof: `SubtensorModule::HotkeyEmissionTempo` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn sudo_set_hotkey_emission_tempo() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_000_000 picoseconds. - Weight::from_parts(6_000_000, 0) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } } \ No newline at end of file diff --git a/pallets/admin-utils/tests/mock.rs b/pallets/admin-utils/tests/mock.rs index c1f55fece5..7ae11b6fb6 100644 --- a/pallets/admin-utils/tests/mock.rs +++ b/pallets/admin-utils/tests/mock.rs @@ -114,6 +114,8 @@ parameter_types! { pub const InitialAlphaHigh: u16 = 58982; // Represents 0.9 as per the production default pub const InitialAlphaLow: u16 = 45875; // Represents 0.7 as per the production default pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn + pub const InitialHotkeyEmissionTempo: u64 = 1; + pub const InitialNetworkMaxStake: u64 = 500_000_000_000_000; // 500_000 TAO } impl pallet_subtensor::Config for Test { @@ -169,6 +171,8 @@ impl pallet_subtensor::Config for Test { type AlphaHigh = InitialAlphaHigh; type AlphaLow = InitialAlphaLow; type LiquidAlphaOn = InitialLiquidAlphaOn; + type InitialHotkeyEmissionTempo = InitialHotkeyEmissionTempo; + type InitialNetworkMaxStake = InitialNetworkMaxStake; } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] @@ -478,6 +482,10 @@ impl pallet_admin_utils::SubtensorInterface f fn set_hotkey_emission_tempo(emission_tempo: u64) { SubtensorModule::set_hotkey_emission_tempo(emission_tempo) } + fn set_network_max_stake(netuid: u16, max_stake: u64) { + SubtensorModule::set_network_max_stake(netuid, max_stake) + } + fn do_set_alpha_values( origin: RuntimeOrigin, netuid: u16, diff --git a/pallets/subtensor/src/coinbase/block_step.rs b/pallets/subtensor/src/coinbase/block_step.rs index f4df514560..3c621155f2 100644 --- a/pallets/subtensor/src/coinbase/block_step.rs +++ b/pallets/subtensor/src/coinbase/block_step.rs @@ -1,10 +1,6 @@ use super::*; -use frame_support::storage::IterableStorageDoubleMap; use frame_support::storage::IterableStorageMap; -use sp_runtime::Saturating; use substrate_fixed::types::I110F18; -use substrate_fixed::types::I64F64; -use substrate_fixed::types::I96F32; impl Pallet { /// Executes the necessary operations for each block. diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 7dd829853e..0f747a89ea 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -1,8 +1,5 @@ use super::*; use frame_support::storage::IterableStorageDoubleMap; -use frame_support::storage::IterableStorageMap; -use sp_runtime::Saturating; -use substrate_fixed::types::I110F18; use substrate_fixed::types::I64F64; use substrate_fixed::types::I96F32; @@ -190,8 +187,8 @@ impl Pallet { mining_emission: u64, ) { // --- 1. First, calculate the hotkey's share of the emission. - let take_proportion: I64F64 = - I64F64::from_num(Delegates::::get(hotkey)).saturating_div(I64F64::from_num(u16::MAX)); + let take_proportion: I64F64 = I64F64::from_num(Delegates::::get(hotkey)) + .saturating_div(I64F64::from_num(u16::MAX)); let hotkey_take: u64 = take_proportion .saturating_mul(I64F64::from_num(validating_emission)) .to_num::(); @@ -274,8 +271,8 @@ impl Pallet { let total_hotkey_stake: u64 = Self::get_total_stake_for_hotkey(hotkey); // --- 5 Calculate the emission take for the hotkey. - let take_proportion: I64F64 = - I64F64::from_num(Delegates::::get(hotkey)).saturating_div(I64F64::from_num(u16::MAX)); + let take_proportion: I64F64 = I64F64::from_num(Delegates::::get(hotkey)) + .saturating_div(I64F64::from_num(u16::MAX)); let hotkey_take: u64 = (take_proportion.saturating_mul(I64F64::from_num(emission))).to_num::(); @@ -287,11 +284,15 @@ impl Pallet { // --- 8 Iterate over each nominator. for (nominator, nominator_stake) in - as IterableStorageDoubleMap>::iter_prefix(hotkey) + as IterableStorageDoubleMap>::iter_prefix( + hotkey, + ) { // --- 9 Check if the stake was manually increased by the user since the last emission drain for this hotkey. // If it was, skip this nominator as they will not receive their proportion of the emission. - if LastAddStakeIncrease::::get(hotkey, nominator.clone()) > last_hotkey_emission_drain { + if LastAddStakeIncrease::::get(hotkey, nominator.clone()) + > last_hotkey_emission_drain + { continue; } @@ -365,9 +366,10 @@ impl Pallet { if tempo == 0 { return u64::MAX; } - (tempo as u64).saturating_sub( - (block_number.saturating_add((netuid as u64).saturating_add(1))) - % (tempo as u64).saturating_add(1), - ) + let netuid_plus_one = (netuid as u64).saturating_add(1); + let block_plus_netuid = block_number.saturating_add(netuid_plus_one); + let tempo_plus_one = (tempo as u64).saturating_add(1); + let remainder = block_plus_netuid.rem_euclid(tempo_plus_one); + (tempo as u64).saturating_sub(remainder) } } \ No newline at end of file diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 8d2b5c4fdd..dd98a318f6 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -502,7 +502,7 @@ pub mod pallet { #[pallet::type_value] /// Default value for network immunity period. pub fn DefaultHotkeyEmissionTempo() -> u64 { - 7200 + T::InitialHotkeyEmissionTempo::get() } #[pallet::type_value] /// Default value for rate limiting @@ -549,6 +549,11 @@ pub mod pallet { pub fn DefaultAlphaValues() -> (u16, u16) { (45875, 58982) } + #[pallet::type_value] + /// Default value for network max stake. + pub fn DefaultNetworkMaxStake() -> u64 { + T::InitialNetworkMaxStake::get() + } #[pallet::storage] pub type SenateRequiredStakePercentage = @@ -926,6 +931,10 @@ pub mod pallet { /// MAP ( netuid ) --> (alpha_low, alpha_high) pub type AlphaValues = StorageMap<_, Identity, u16, (u16, u16), ValueQuery, DefaultAlphaValues>; + /// MAP ( netuid ) --> max stake allowed on a subnet. + #[pallet::storage] + pub type NetworkMaxStake = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultNetworkMaxStake>; /// ======================================= /// ==== Subnetwork Consensus Storage ==== diff --git a/pallets/subtensor/src/macros/config.rs b/pallets/subtensor/src/macros/config.rs index a640ecbb6b..aca0f1b302 100644 --- a/pallets/subtensor/src/macros/config.rs +++ b/pallets/subtensor/src/macros/config.rs @@ -168,5 +168,11 @@ mod config { /// A flag to indicate if Liquid Alpha is enabled. #[pallet::constant] type LiquidAlphaOn: Get; + /// Initial network max stake. + #[pallet::constant] + type InitialNetworkMaxStake: Get; + /// Initial hotkey emission tempo. + #[pallet::constant] + type InitialHotkeyEmissionTempo: Get; } } diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index e3e47f32eb..b93b8296b2 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -171,6 +171,11 @@ mod events { /// The account ID of the coldkey coldkey: T::AccountId, }, + /// The children of a hotkey have been set SetChildren(T::AccountId, u16, Vec<(u64, T::AccountId)>), + /// The hotkey emission tempo has been set + HotkeyEmissionTempoSet(u64), + /// The network maximum stake has been set + NetworkMaxStakeSet(u16, u64), } } diff --git a/pallets/subtensor/src/rpc_info/neuron_info.rs b/pallets/subtensor/src/rpc_info/neuron_info.rs index 6b370afd8f..cadd4b6e35 100644 --- a/pallets/subtensor/src/rpc_info/neuron_info.rs +++ b/pallets/subtensor/src/rpc_info/neuron_info.rs @@ -118,8 +118,8 @@ impl Pallet { }) .collect::, Compact)>>(); let stake: Vec<(T::AccountId, Compact)> = vec![( - coldkey, - Self::get_stake_for_hotkey_on_subnet(hotkey, netuid).into(), + coldkey.clone(), + Self::get_stake_for_hotkey_on_subnet(&hotkey, netuid).into(), )]; let neuron = NeuronInfo { hotkey: hotkey.clone(), diff --git a/pallets/subtensor/src/staking/set_children.rs b/pallets/subtensor/src/staking/set_children.rs index 79898b6ae7..071764734a 100644 --- a/pallets/subtensor/src/staking/set_children.rs +++ b/pallets/subtensor/src/staking/set_children.rs @@ -1,5 +1,4 @@ use super::*; -use substrate_fixed::types::I96F32; impl Pallet { /// ---- The implementation for the extrinsic do_set_child_singular: Sets a single child. diff --git a/pallets/subtensor/src/subnets/registration.rs b/pallets/subtensor/src/subnets/registration.rs index b46a50eb21..ecff0fd992 100644 --- a/pallets/subtensor/src/subnets/registration.rs +++ b/pallets/subtensor/src/subnets/registration.rs @@ -550,10 +550,10 @@ impl Pallet { // Copy the hotkey_bytes into the first half of full_bytes full_bytes[..32].copy_from_slice(hotkey_bytes); let keccak_256_seal_hash_vec: [u8; 32] = keccak_256(&full_bytes[..]); - let hash_u64: u64 = u64::from_le_bytes(keccak_256_seal_hash_vec[0..8].try_into().unwrap()); + let hash_u64: u64 = u64::from_le_bytes(keccak_256_seal_hash_vec[0..8].try_into().unwrap_or_default()); hash_u64 } - + pub fn create_seal_hash(block_number_u64: u64, nonce_u64: u64, hotkey: &T::AccountId) -> H256 { let nonce = nonce_u64.to_le_bytes(); let block_hash_at_number: H256 = Self::get_block_hash_from_u64(block_number_u64); diff --git a/pallets/subtensor/src/utils.rs b/pallets/subtensor/src/utils.rs index a1929f4987..6f5dbeaffe 100644 --- a/pallets/subtensor/src/utils.rs +++ b/pallets/subtensor/src/utils.rs @@ -703,6 +703,7 @@ impl Pallet { pub fn get_hotkey_emission_tempo() -> u64 { HotkeyEmissionTempo::::get() } + /// Sets the hotkey emission tempo. /// /// # Arguments @@ -711,4 +712,40 @@ impl Pallet { HotkeyEmissionTempo::::set(emission_tempo); Self::deposit_event(Event::HotkeyEmissionTempoSet(emission_tempo)); } + + pub fn get_pending_hotkey_emission(hotkey: &T::AccountId) -> u64 { + PendingdHotkeyEmission::::get(hotkey) + } + + /// Retrieves the maximum stake allowed for a given network. + /// + /// # Arguments + /// + /// * `netuid` - The unique identifier of the network. + /// + /// # Returns + /// + /// * `u64` - The maximum stake allowed for the specified network. + pub fn get_network_max_stake(netuid: u16) -> u64 { + NetworkMaxStake::::get(netuid) + } + + /// Sets the maximum stake allowed for a given network. + /// + /// # Arguments + /// + /// * `netuid` - The unique identifier of the network. + /// * `max_stake` - The new maximum stake value to set. + /// + /// # Effects + /// + /// * Updates the NetworkMaxStake storage. + /// * Emits a NetworkMaxStakeSet event. + pub fn set_network_max_stake(netuid: u16, max_stake: u64) { + // Update the NetworkMaxStake storage with the new max_stake value + NetworkMaxStake::::insert(netuid, max_stake); + + // Emit an event to notify listeners about the change + Self::deposit_event(Event::NetworkMaxStakeSet(netuid, max_stake)); + } } diff --git a/pallets/subtensor/tests/block_step.rs b/pallets/subtensor/tests/block_step.rs deleted file mode 100644 index 87fdb8bcf4..0000000000 --- a/pallets/subtensor/tests/block_step.rs +++ /dev/null @@ -1,940 +0,0 @@ -#![allow(clippy::unwrap_used)] - -mod mock; -use frame_support::assert_ok; -use frame_system::Config; -use mock::*; -use sp_core::U256; - -#[test] -fn test_loaded_emission() { - new_test_ext(1).execute_with(|| { - let n: u16 = 100; - let netuid: u16 = 1; - let tempo: u16 = 10; - let netuids: Vec = vec![1]; - let emission: Vec = vec![1000000000]; - add_network(netuid, tempo, 0); - SubtensorModule::set_max_allowed_uids(netuid, n); - SubtensorModule::set_adjustment_alpha(netuid, 58000); // Set to old value. - SubtensorModule::set_emission_values(&netuids, emission).unwrap(); - for i in 0..n { - SubtensorModule::append_neuron(netuid, &U256::from(i), 0); - } - assert!(SubtensorModule::get_loaded_emission_tuples(netuid).is_none()); - - // Try loading at block 0 - let block: u64 = 0; - assert_eq!( - SubtensorModule::blocks_until_next_epoch(netuid, tempo, block), - 8 - ); - SubtensorModule::generate_emission(block); - assert!(SubtensorModule::get_loaded_emission_tuples(netuid).is_none()); - - // Try loading at block = 9; - let block: u64 = 8; - assert_eq!( - SubtensorModule::blocks_until_next_epoch(netuid, tempo, block), - 0 - ); - SubtensorModule::generate_emission(block); - assert!(SubtensorModule::get_loaded_emission_tuples(netuid).is_some()); - assert_eq!( - SubtensorModule::get_loaded_emission_tuples(netuid) - .unwrap() - .len(), - n as usize - ); - - // Try draining the emission tuples - // None remaining because we are at epoch. - let block: u64 = 8; - SubtensorModule::drain_emission(block); - assert!(SubtensorModule::get_loaded_emission_tuples(netuid).is_none()); - - // Generate more emission. - SubtensorModule::generate_emission(8); - assert_eq!( - SubtensorModule::get_loaded_emission_tuples(netuid) - .unwrap() - .len(), - n as usize - ); - - for block in 9..19 { - let mut n_remaining: usize = 0; - let mut n_to_drain: usize = 0; - if let Some(tuples) = SubtensorModule::get_loaded_emission_tuples(netuid) { - n_remaining = tuples.len(); - n_to_drain = - SubtensorModule::tuples_to_drain_this_block(netuid, tempo, block, tuples.len()); - } - SubtensorModule::drain_emission(block); // drain it with 9 more blocks to go - if let Some(tuples) = SubtensorModule::get_loaded_emission_tuples(netuid) { - assert_eq!(tuples.len(), n_remaining - n_to_drain); - } - log::info!("n_to_drain: {:?}", n_to_drain); - log::info!( - "SubtensorModule::get_loaded_emission_tuples( netuid ).len(): {:?}", - n_remaining - n_to_drain - ); - } - }) -} - -#[test] -fn test_tuples_to_drain_this_block() { - new_test_ext(1).execute_with(|| { - // pub fn tuples_to_drain_this_block( netuid: u16, tempo: u16, block_number: u64, n_remaining: usize ) -> usize { - assert_eq!(SubtensorModule::tuples_to_drain_this_block(0, 1, 0, 10), 10); // drain all epoch block. - assert_eq!(SubtensorModule::tuples_to_drain_this_block(0, 0, 0, 10), 10); // drain all no tempo. - assert_eq!(SubtensorModule::tuples_to_drain_this_block(0, 10, 0, 10), 2); // drain 10 / ( 10 / 2 ) = 2 - assert_eq!(SubtensorModule::tuples_to_drain_this_block(0, 20, 0, 10), 1); // drain 10 / ( 20 / 2 ) = 1 - assert_eq!(SubtensorModule::tuples_to_drain_this_block(0, 10, 0, 20), 5); // drain 20 / ( 9 / 2 ) = 5 - assert_eq!(SubtensorModule::tuples_to_drain_this_block(0, 20, 0, 0), 0); // nothing to drain. - assert_eq!(SubtensorModule::tuples_to_drain_this_block(0, 10, 1, 20), 5); // drain 19 / ( 10 / 2 ) = 4 - assert_eq!( - SubtensorModule::tuples_to_drain_this_block(0, 10, 10, 20), - 4 - ); // drain 19 / ( 10 / 2 ) = 4 - assert_eq!( - SubtensorModule::tuples_to_drain_this_block(0, 10, 15, 20), - 10 - ); // drain 19 / ( 10 / 2 ) = 4 - assert_eq!( - SubtensorModule::tuples_to_drain_this_block(0, 10, 19, 20), - 20 - ); // drain 19 / ( 10 / 2 ) = 4 - assert_eq!( - SubtensorModule::tuples_to_drain_this_block(0, 10, 20, 20), - 20 - ); // drain 19 / ( 10 / 2 ) = 4 - for i in 0..10 { - for j in 0..10 { - for k in 0..10 { - for l in 0..10 { - assert!(SubtensorModule::tuples_to_drain_this_block(i, j, k, l) <= 10); - } - } - } - } - }) -} - -#[test] -fn test_blocks_until_epoch() { - new_test_ext(1).execute_with(|| { - // Check tempo = 0 block = * netuid = * - assert_eq!(SubtensorModule::blocks_until_next_epoch(0, 0, 0), 1000); - - // Check tempo = 1 block = * netuid = * - assert_eq!(SubtensorModule::blocks_until_next_epoch(0, 1, 0), 0); - assert_eq!(SubtensorModule::blocks_until_next_epoch(1, 1, 0), 1); - assert_eq!(SubtensorModule::blocks_until_next_epoch(0, 1, 1), 1); - assert_eq!(SubtensorModule::blocks_until_next_epoch(1, 1, 1), 0); - assert_eq!(SubtensorModule::blocks_until_next_epoch(0, 1, 2), 0); - assert_eq!(SubtensorModule::blocks_until_next_epoch(1, 1, 2), 1); - for i in 0..100 { - if i % 2 == 0 { - assert_eq!(SubtensorModule::blocks_until_next_epoch(0, 1, i), 0); - assert_eq!(SubtensorModule::blocks_until_next_epoch(1, 1, i), 1); - } else { - assert_eq!(SubtensorModule::blocks_until_next_epoch(0, 1, i), 1); - assert_eq!(SubtensorModule::blocks_until_next_epoch(1, 1, i), 0); - } - } - - // Check general case. - for netuid in 0..30_u16 { - for block in 0..30_u64 { - for tempo in 1..30_u16 { - assert_eq!( - SubtensorModule::blocks_until_next_epoch(netuid, tempo, block), - tempo as u64 - (block + netuid as u64 + 1) % (tempo as u64 + 1) - ); - } - } - } - }); -} - -// /******************************************** -// block_step::adjust_registration_terms_for_networks tests -// *********************************************/ -#[test] -fn test_burn_adjustment() { - new_test_ext(1).execute_with(|| { - let netuid: u16 = 1; - let tempo: u16 = 13; - let burn_cost: u64 = 1000; - let adjustment_interval = 1; - let target_registrations_per_interval = 1; - add_network(netuid, tempo, 0); - SubtensorModule::set_burn(netuid, burn_cost); - SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); - SubtensorModule::set_adjustment_alpha(netuid, 58000); // Set to old value. - SubtensorModule::set_target_registrations_per_interval( - netuid, - target_registrations_per_interval, - ); - assert_eq!( - SubtensorModule::get_adjustment_interval(netuid), - adjustment_interval - ); // Sanity check the adjustment interval. - - // Register key 1. - let hotkey_account_id_1 = U256::from(1); - let coldkey_account_id_1 = U256::from(1); - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id_1, 10000); - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(hotkey_account_id_1), - netuid, - hotkey_account_id_1 - )); - - // Register key 2. - let hotkey_account_id_2 = U256::from(2); - let coldkey_account_id_2 = U256::from(2); - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id_2, 10000); - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(hotkey_account_id_2), - netuid, - hotkey_account_id_2 - )); - - // We are over the number of regs allowed this interval. - // Step the block and trigger the adjustment. - step_block(1); - - // Check the adjusted burn. - assert_eq!(SubtensorModule::get_burn_as_u64(netuid), 1500); - }); -} - -#[test] -fn test_burn_adjustment_with_moving_average() { - new_test_ext(1).execute_with(|| { - let netuid: u16 = 1; - let tempo: u16 = 13; - let burn_cost: u64 = 1000; - let adjustment_interval = 1; - let target_registrations_per_interval = 1; - add_network(netuid, tempo, 0); - SubtensorModule::set_burn(netuid, burn_cost); - SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); - SubtensorModule::set_adjustment_alpha(netuid, 58000); // Set to old value. - SubtensorModule::set_target_registrations_per_interval( - netuid, - target_registrations_per_interval, - ); - // Set alpha here. - SubtensorModule::set_adjustment_alpha(netuid, u64::MAX / 2); - - // Register key 1. - let hotkey_account_id_1 = U256::from(1); - let coldkey_account_id_1 = U256::from(1); - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id_1, 10000); - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(hotkey_account_id_1), - netuid, - hotkey_account_id_1 - )); - - // Register key 2. - let hotkey_account_id_2 = U256::from(2); - let coldkey_account_id_2 = U256::from(2); - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id_2, 10000); - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(hotkey_account_id_2), - netuid, - hotkey_account_id_2 - )); - - // We are over the number of regs allowed this interval. - // Step the block and trigger the adjustment. - step_block(1); - - // Check the adjusted burn. - // 0.5 * 1000 + 0.5 * 1500 = 1250 - assert_eq!(SubtensorModule::get_burn_as_u64(netuid), 1250); - }); -} - -#[test] -#[allow(unused_assignments)] -fn test_burn_adjustment_case_a() { - // Test case A of the difficulty and burn adjustment algorithm. - // ==================== - // There are too many registrations this interval and most of them are pow registrations - // this triggers an increase in the pow difficulty. - new_test_ext(1).execute_with(|| { - let netuid: u16 = 1; - let tempo: u16 = 13; - let burn_cost: u64 = 1000; - let adjustment_interval = 1; - let target_registrations_per_interval = 1; - let start_diff: u64 = 10_000; - let mut curr_block_num = 0; - add_network(netuid, tempo, 0); - SubtensorModule::set_burn(netuid, burn_cost); - SubtensorModule::set_difficulty(netuid, start_diff); - SubtensorModule::set_min_difficulty(netuid, start_diff); - SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); - SubtensorModule::set_adjustment_alpha(netuid, 58000); // Set to old value. - SubtensorModule::set_target_registrations_per_interval( - netuid, - target_registrations_per_interval, - ); - - // Register key 1. This is a burn registration. - let hotkey_account_id_1 = U256::from(1); - let coldkey_account_id_1 = U256::from(1); - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id_1, 10000); - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(hotkey_account_id_1), - netuid, - hotkey_account_id_1 - )); - - // Register key 2. This is a POW registration - let hotkey_account_id_2 = U256::from(2); - let coldkey_account_id_2 = U256::from(2); - let (nonce0, work0): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - curr_block_num, - 0, - &hotkey_account_id_2, - ); - let result0 = SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id_2), - netuid, - curr_block_num, - nonce0, - work0, - hotkey_account_id_2, - coldkey_account_id_2, - ); - assert_ok!(result0); - - // Register key 3. This is a POW registration - let hotkey_account_id_3 = U256::from(3); - let coldkey_account_id_3 = U256::from(3); - let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - curr_block_num, - 11231312312, - &hotkey_account_id_3, - ); - let result1 = SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id_3), - netuid, - curr_block_num, - nonce1, - work1, - hotkey_account_id_3, - coldkey_account_id_3, - ); - assert_ok!(result1); - - // We are over the number of regs allowed this interval. - // Most of them are POW registrations (2 out of 3) - // Step the block and trigger the adjustment. - step_block(1); - curr_block_num += 1; - - // Check the adjusted POW difficulty has INCREASED. - // and the burn has not changed. - let adjusted_burn = SubtensorModule::get_burn_as_u64(netuid); - assert_eq!(adjusted_burn, burn_cost); - - let adjusted_diff = SubtensorModule::get_difficulty_as_u64(netuid); - assert!(adjusted_diff > start_diff); - assert_eq!(adjusted_diff, 20_000); - }); -} - -#[test] -#[allow(unused_assignments)] -fn test_burn_adjustment_case_b() { - // Test case B of the difficulty and burn adjustment algorithm. - // ==================== - // There are too many registrations this interval and most of them are burn registrations - // this triggers an increase in the burn cost. - new_test_ext(1).execute_with(|| { - let netuid: u16 = 1; - let tempo: u16 = 13; - let burn_cost: u64 = 1000; - let adjustment_interval = 1; - let target_registrations_per_interval = 1; - let start_diff: u64 = 10_000; - let mut curr_block_num = 0; - add_network(netuid, tempo, 0); - SubtensorModule::set_burn(netuid, burn_cost); - SubtensorModule::set_difficulty(netuid, start_diff); - SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); - SubtensorModule::set_adjustment_alpha(netuid, 58000); // Set to old value. - SubtensorModule::set_target_registrations_per_interval( - netuid, - target_registrations_per_interval, - ); - - // Register key 1. - let hotkey_account_id_1 = U256::from(1); - let coldkey_account_id_1 = U256::from(1); - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id_1, 10000); - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(hotkey_account_id_1), - netuid, - hotkey_account_id_1 - )); - - // Register key 2. - let hotkey_account_id_2 = U256::from(2); - let coldkey_account_id_2 = U256::from(2); - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id_2, 10000); - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(hotkey_account_id_2), - netuid, - hotkey_account_id_2 - )); - - // Register key 3. This one is a POW registration - let hotkey_account_id_3 = U256::from(3); - let coldkey_account_id_3 = U256::from(3); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - curr_block_num, - 0, - &hotkey_account_id_3, - ); - let result = SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id_3), - netuid, - curr_block_num, - nonce, - work, - hotkey_account_id_3, - coldkey_account_id_3, - ); - assert_ok!(result); - - // We are over the number of regs allowed this interval. - // Most of them are burn registrations (2 out of 3) - // Step the block and trigger the adjustment. - step_block(1); - curr_block_num += 1; - - // Check the adjusted burn has INCREASED. - // and the difficulty has not changed. - let adjusted_burn = SubtensorModule::get_burn_as_u64(netuid); - assert!(adjusted_burn > burn_cost); - assert_eq!(adjusted_burn, 2_000); - - let adjusted_diff = SubtensorModule::get_difficulty_as_u64(netuid); - assert_eq!(adjusted_diff, start_diff); - }); -} - -#[test] -#[allow(unused_assignments)] -fn test_burn_adjustment_case_c() { - // Test case C of the difficulty and burn adjustment algorithm. - // ==================== - // There are not enough registrations this interval and most of them are POW registrations - // this triggers a decrease in the burn cost - new_test_ext(1).execute_with(|| { - let netuid: u16 = 1; - let tempo: u16 = 13; - let burn_cost: u64 = 1000; - let adjustment_interval = 1; - let target_registrations_per_interval = 4; // Needs registrations < 4 to trigger - let start_diff: u64 = 10_000; - let mut curr_block_num = 0; - add_network(netuid, tempo, 0); - SubtensorModule::set_burn(netuid, burn_cost); - SubtensorModule::set_difficulty(netuid, start_diff); - SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); - SubtensorModule::set_adjustment_alpha(netuid, 58000); // Set to old value. - SubtensorModule::set_target_registrations_per_interval( - netuid, - target_registrations_per_interval, - ); - - // Register key 1. This is a BURN registration - let hotkey_account_id_1 = U256::from(1); - let coldkey_account_id_1 = U256::from(1); - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id_1, 10000); - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(hotkey_account_id_1), - netuid, - hotkey_account_id_1 - )); - - // Register key 2. This is a POW registration - let hotkey_account_id_2 = U256::from(2); - let coldkey_account_id_2 = U256::from(2); - let (nonce0, work0): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - curr_block_num, - 0, - &hotkey_account_id_2, - ); - let result0 = SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id_2), - netuid, - curr_block_num, - nonce0, - work0, - hotkey_account_id_2, - coldkey_account_id_2, - ); - assert_ok!(result0); - - // Register key 3. This is a POW registration - let hotkey_account_id_3 = U256::from(3); - let coldkey_account_id_3 = U256::from(3); - let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - curr_block_num, - 11231312312, - &hotkey_account_id_3, - ); - let result1 = SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id_3), - netuid, - curr_block_num, - nonce1, - work1, - hotkey_account_id_3, - coldkey_account_id_3, - ); - assert_ok!(result1); - - // We are UNDER the number of regs allowed this interval. - // Most of them are POW registrations (2 out of 3) - // Step the block and trigger the adjustment. - step_block(1); - curr_block_num += 1; - - // Check the adjusted burn has DECREASED. - // and the difficulty has not changed. - let adjusted_burn = SubtensorModule::get_burn_as_u64(netuid); - assert!(adjusted_burn < burn_cost); - assert_eq!(adjusted_burn, 875); - - let adjusted_diff = SubtensorModule::get_difficulty_as_u64(netuid); - assert_eq!(adjusted_diff, start_diff); - }); -} - -#[test] -#[allow(unused_assignments)] -fn test_burn_adjustment_case_d() { - // Test case D of the difficulty and burn adjustment algorithm. - // ==================== - // There are not enough registrations this interval and most of them are BURN registrations - // this triggers a decrease in the POW difficulty - new_test_ext(1).execute_with(|| { - let netuid: u16 = 1; - let tempo: u16 = 13; - let burn_cost: u64 = 1000; - let adjustment_interval = 1; - let target_registrations_per_interval = 4; // Needs registrations < 4 to trigger - let start_diff: u64 = 10_000; - let mut curr_block_num = 0; - add_network(netuid, tempo, 0); - SubtensorModule::set_burn(netuid, burn_cost); - SubtensorModule::set_difficulty(netuid, start_diff); - SubtensorModule::set_min_difficulty(netuid, 1); - SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); - SubtensorModule::set_adjustment_alpha(netuid, 58000); // Set to old value. - SubtensorModule::set_target_registrations_per_interval( - netuid, - target_registrations_per_interval, - ); - - // Register key 1. This is a BURN registration - let hotkey_account_id_1 = U256::from(1); - let coldkey_account_id_1 = U256::from(1); - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id_1, 10000); - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(hotkey_account_id_1), - netuid, - hotkey_account_id_1 - )); - - // Register key 2. This is a BURN registration - let hotkey_account_id_2 = U256::from(2); - let coldkey_account_id_2 = U256::from(2); - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id_2, 10000); - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(hotkey_account_id_2), - netuid, - hotkey_account_id_2 - )); - - // Register key 3. This is a POW registration - let hotkey_account_id_3 = U256::from(3); - let coldkey_account_id_3 = U256::from(3); - let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - curr_block_num, - 11231312312, - &hotkey_account_id_3, - ); - let result1 = SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id_3), - netuid, - curr_block_num, - nonce1, - work1, - hotkey_account_id_3, - coldkey_account_id_3, - ); - assert_ok!(result1); - - // We are UNDER the number of regs allowed this interval. - // Most of them are BURN registrations (2 out of 3) - // Step the block and trigger the adjustment. - step_block(1); - curr_block_num += 1; - - // Check the adjusted POW difficulty has DECREASED. - // and the burn has not changed. - let adjusted_burn = SubtensorModule::get_burn_as_u64(netuid); - assert_eq!(adjusted_burn, burn_cost); - - let adjusted_diff = SubtensorModule::get_difficulty_as_u64(netuid); - assert!(adjusted_diff < start_diff); - assert_eq!(adjusted_diff, 8750); - }); -} - -#[test] -#[allow(unused_assignments)] -fn test_burn_adjustment_case_e() { - // Test case E of the difficulty and burn adjustment algorithm. - // ==================== - // There are not enough registrations this interval and nobody registered either POW or BURN - // this triggers a decrease in the BURN cost and POW difficulty - new_test_ext(1).execute_with(|| { - let netuid: u16 = 1; - let tempo: u16 = 13; - let burn_cost: u64 = 1000; - let adjustment_interval = 1; - let target_registrations_per_interval: u16 = 3; - let start_diff: u64 = 10_000; - let mut curr_block_num = 0; - add_network(netuid, tempo, 0); - SubtensorModule::set_max_registrations_per_block(netuid, 10); - SubtensorModule::set_burn(netuid, burn_cost); - SubtensorModule::set_difficulty(netuid, start_diff); - SubtensorModule::set_min_difficulty(netuid, 1); - SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); - SubtensorModule::set_adjustment_alpha(netuid, 58000); // Set to old value. - SubtensorModule::set_target_registrations_per_interval( - netuid, - target_registrations_per_interval, - ); - - // Register key 1. This is a POW registration - let hotkey_account_id_1 = U256::from(1); - let coldkey_account_id_1 = U256::from(1); - let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - curr_block_num, - 11231312312, - &hotkey_account_id_1, - ); - let result1 = SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id_1), - netuid, - curr_block_num, - nonce1, - work1, - hotkey_account_id_1, - coldkey_account_id_1, - ); - assert_ok!(result1); - - // Register key 2. This is a BURN registration - let hotkey_account_id_2 = U256::from(2); - let coldkey_account_id_2 = U256::from(2); - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id_2, 10000); - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(hotkey_account_id_2), - netuid, - hotkey_account_id_2 - )); - - step_block(1); - curr_block_num += 1; - - // We are UNDER the number of regs allowed this interval. - // And the number of regs of each type is equal - - // Check the adjusted BURN has DECREASED. - let adjusted_burn = SubtensorModule::get_burn_as_u64(netuid); - assert!(adjusted_burn < burn_cost); - assert_eq!(adjusted_burn, 833); - - // Check the adjusted POW difficulty has DECREASED. - let adjusted_diff = SubtensorModule::get_difficulty_as_u64(netuid); - assert!(adjusted_diff < start_diff); - assert_eq!(adjusted_diff, 8_333); - }); -} - -#[test] -#[allow(unused_assignments)] -fn test_burn_adjustment_case_f() { - // Test case F of the difficulty and burn adjustment algorithm. - // ==================== - // There are too many registrations this interval and the pow and burn registrations are equal - // this triggers an increase in the burn cost and pow difficulty - new_test_ext(1).execute_with(|| { - let netuid: u16 = 1; - let tempo: u16 = 13; - let burn_cost: u64 = 1000; - let adjustment_interval = 1; - let target_registrations_per_interval: u16 = 1; - let start_diff: u64 = 10_000; - let mut curr_block_num = 0; - add_network(netuid, tempo, 0); - SubtensorModule::set_max_registrations_per_block(netuid, 10); - SubtensorModule::set_burn(netuid, burn_cost); - SubtensorModule::set_difficulty(netuid, start_diff); - SubtensorModule::set_min_difficulty(netuid, start_diff); - SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); - SubtensorModule::set_adjustment_alpha(netuid, 58000); // Set to old value. - SubtensorModule::set_target_registrations_per_interval( - netuid, - target_registrations_per_interval, - ); - - // Register key 1. This is a POW registration - let hotkey_account_id_1 = U256::from(1); - let coldkey_account_id_1 = U256::from(1); - let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - curr_block_num, - 11231312312, - &hotkey_account_id_1, - ); - let result1 = SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id_1), - netuid, - curr_block_num, - nonce1, - work1, - hotkey_account_id_1, - coldkey_account_id_1, - ); - assert_ok!(result1); - - // Register key 2. This is a BURN registration - let hotkey_account_id_2 = U256::from(2); - let coldkey_account_id_2 = U256::from(2); - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id_2, 10000); - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(hotkey_account_id_2), - netuid, - hotkey_account_id_2 - )); - - step_block(1); - curr_block_num += 1; - // We are OVER the number of regs allowed this interval. - // And the number of regs of each type is equal - - // Check the adjusted BURN has INCREASED. - let adjusted_burn = SubtensorModule::get_burn_as_u64(netuid); - assert!(adjusted_burn > burn_cost); - assert_eq!(adjusted_burn, 1_500); - - // Check the adjusted POW difficulty has INCREASED. - let adjusted_diff = SubtensorModule::get_difficulty_as_u64(netuid); - assert!(adjusted_diff > start_diff); - assert_eq!(adjusted_diff, 15_000); - }); -} - -#[test] -fn test_burn_adjustment_case_e_zero_registrations() { - // Test case E of the difficulty and burn adjustment algorithm. - // ==================== - // There are not enough registrations this interval and nobody registered either POW or BURN - // this triggers a decrease in the BURN cost and POW difficulty - - // BUT there are zero registrations this interval. - new_test_ext(1).execute_with(|| { - let netuid: u16 = 1; - let tempo: u16 = 13; - let burn_cost: u64 = 1000; - let adjustment_interval = 1; - let target_registrations_per_interval: u16 = 1; - let start_diff: u64 = 10_000; - add_network(netuid, tempo, 0); - SubtensorModule::set_max_registrations_per_block(netuid, 10); - SubtensorModule::set_burn(netuid, burn_cost); - SubtensorModule::set_difficulty(netuid, start_diff); - SubtensorModule::set_min_difficulty(netuid, 1); - SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); - SubtensorModule::set_adjustment_alpha(netuid, 58000); // Set to old value. - SubtensorModule::set_target_registrations_per_interval( - netuid, - target_registrations_per_interval, - ); - - // No registrations this interval of any kind. - step_block(1); - - // We are UNDER the number of regs allowed this interval. - // And the number of regs of each type is equal - - // Check the adjusted BURN has DECREASED. - let adjusted_burn = SubtensorModule::get_burn_as_u64(netuid); - assert!(adjusted_burn < burn_cost); - assert_eq!(adjusted_burn, 500); - - // Check the adjusted POW difficulty has DECREASED. - let adjusted_diff = SubtensorModule::get_difficulty_as_u64(netuid); - assert!(adjusted_diff < start_diff); - assert_eq!(adjusted_diff, 5_000); - }); -} - -#[test] -fn test_emission_based_on_registration_status() { - new_test_ext(1).execute_with(|| { - let n: u16 = 100; - let netuid_off: u16 = 1; - let netuid_on: u16 = 2; - let tempo: u16 = 1; - let netuids: Vec = vec![netuid_off, netuid_on]; - let emissions: Vec = vec![1000000000, 1000000000]; - - // Add subnets with registration turned off and on - add_network(netuid_off, tempo, 0); - add_network(netuid_on, tempo, 0); - SubtensorModule::set_max_allowed_uids(netuid_off, n); - SubtensorModule::set_max_allowed_uids(netuid_on, n); - SubtensorModule::set_emission_values(&netuids, emissions).unwrap(); - SubtensorModule::set_network_registration_allowed(netuid_off, false); - SubtensorModule::set_network_registration_allowed(netuid_on, true); - - // Populate the subnets with neurons - for i in 0..n { - SubtensorModule::append_neuron(netuid_off, &U256::from(i), 0); - SubtensorModule::append_neuron(netuid_on, &U256::from(i), 0); - } - - // Generate emission at block 0 - let block: u64 = 0; - SubtensorModule::generate_emission(block); - - // Verify that no emission tuples are loaded for the subnet with registration off - assert!(SubtensorModule::get_loaded_emission_tuples(netuid_off).is_none()); - - // Verify that emission tuples are loaded for the subnet with registration on - assert!(SubtensorModule::get_loaded_emission_tuples(netuid_on).is_some()); - assert_eq!( - SubtensorModule::get_loaded_emission_tuples(netuid_on) - .unwrap() - .len(), - n as usize - ); - - // Step to the next epoch block - let epoch_block: u16 = tempo; - step_block(epoch_block); - - // Verify that no emission tuples are loaded for the subnet with registration off - assert!(SubtensorModule::get_loaded_emission_tuples(netuid_off).is_none()); - log::info!( - "Emissions for netuid with registration off: {:?}", - SubtensorModule::get_loaded_emission_tuples(netuid_off) - ); - - // Verify that emission tuples are loaded for the subnet with registration on - assert!(SubtensorModule::get_loaded_emission_tuples(netuid_on).is_some()); - log::info!( - "Emissions for netuid with registration on: {:?}", - SubtensorModule::get_loaded_emission_tuples(netuid_on) - ); - assert_eq!( - SubtensorModule::get_loaded_emission_tuples(netuid_on) - .unwrap() - .len(), - n as usize - ); - - let block: u64 = 0; - // drain the emission tuples for the subnet with registration on - SubtensorModule::drain_emission(block); - // Turn on registration for the subnet with registration off - SubtensorModule::set_network_registration_allowed(netuid_off, true); - SubtensorModule::set_network_registration_allowed(netuid_on, false); - - // Generate emission at the next block - let next_block: u64 = block + 1; - SubtensorModule::generate_emission(next_block); - - // Verify that emission tuples are now loaded for the subnet with registration turned on - assert!(SubtensorModule::get_loaded_emission_tuples(netuid_off).is_some()); - log::info!( - "Emissions for netuid with registration on: {:?}", - SubtensorModule::get_loaded_emission_tuples(netuid_on) - ); - assert!(SubtensorModule::get_loaded_emission_tuples(netuid_on).is_none()); - assert_eq!( - SubtensorModule::get_loaded_emission_tuples(netuid_off) - .unwrap() - .len(), - n as usize - ); - }); -} - -#[test] -fn test_epoch_runs_when_registration_disabled() { - new_test_ext(1).execute_with(|| { - let n: u16 = 100; - let netuid_off: u16 = 1; - let tempo: u16 = 1; - let netuids: Vec = vec![netuid_off]; - let emissions: Vec = vec![1000000000]; - - // Add subnets with registration turned off and on - add_network(netuid_off, tempo, 0); - SubtensorModule::set_max_allowed_uids(netuid_off, n); - SubtensorModule::set_emission_values(&netuids, emissions).unwrap(); - SubtensorModule::set_network_registration_allowed(netuid_off, false); - - // Populate the subnets with neurons - for i in 0..n { - SubtensorModule::append_neuron(netuid_off, &U256::from(i), 0); - } - - // Generate emission at block 1 - let block: u64 = 1; - SubtensorModule::generate_emission(block); - - step_block(1); // Now block 2 - - // Verify blocks since last step was set - assert_eq!(SubtensorModule::get_blocks_since_last_step(netuid_off), 1); - - // Step to the next epoch block - let epoch_block: u16 = tempo; - step_block(epoch_block); - - // Verify blocks since last step was set, this indicates we ran the epoch - assert_eq!( - SubtensorModule::get_blocks_since_last_step(netuid_off), - 0_u64 - ); - assert!(SubtensorModule::get_loaded_emission_tuples(netuid_off).is_some()); - }); -} diff --git a/pallets/subtensor/tests/coinbase.rs b/pallets/subtensor/tests/coinbase.rs index cd7d2cc81a..aed3c9b555 100644 --- a/pallets/subtensor/tests/coinbase.rs +++ b/pallets/subtensor/tests/coinbase.rs @@ -135,6 +135,7 @@ fn test_coinbase_basic() { } // Test getting and setting hotkey emission tempo +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test coinbase test_set_and_get_hotkey_emission_tempo -- --nocapture #[test] #[cfg(not(tarpaulin))] fn test_set_and_get_hotkey_emission_tempo() { diff --git a/pallets/subtensor/tests/mock.rs b/pallets/subtensor/tests/mock.rs index 71e1d593b2..27d11eb137 100644 --- a/pallets/subtensor/tests/mock.rs +++ b/pallets/subtensor/tests/mock.rs @@ -168,6 +168,9 @@ parameter_types! { pub const InitialAlphaHigh: u16 = 58982; // Represents 0.9 as per the production default pub const InitialAlphaLow: u16 = 45875; // Represents 0.7 as per the production default pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn + pub const InitialHotkeyEmissionTempo: u64 = 0; // Defaults to draining every block. + pub const InitialNetworkMaxStake: u64 = 500_000_000_000_000; // 500,000 TAO + } // Configure collective pallet for council @@ -378,6 +381,8 @@ impl pallet_subtensor::Config for Test { type AlphaHigh = InitialAlphaHigh; type AlphaLow = InitialAlphaLow; type LiquidAlphaOn = InitialLiquidAlphaOn; + type InitialHotkeyEmissionTempo = InitialHotkeyEmissionTempo; + type InitialNetworkMaxStake = InitialNetworkMaxStake; } impl pallet_utility::Config for Test { diff --git a/pallets/subtensor/tests/staking.rs b/pallets/subtensor/tests/staking.rs index ece30391d1..2952426a9a 100644 --- a/pallets/subtensor/tests/staking.rs +++ b/pallets/subtensor/tests/staking.rs @@ -1189,1082 +1189,6 @@ fn test_delegate_stake_division_by_zero_check() { <::RuntimeOrigin>::signed(coldkey), hotkey )); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey, 0, 1000); - }); -} - -#[test] -#[cfg(not(tarpaulin))] -fn test_full_with_delegating() { - new_test_ext(1).execute_with(|| { - let netuid = 1; - // Make two accounts. - let hotkey0 = U256::from(1); - let hotkey1 = U256::from(2); - - let coldkey0 = U256::from(3); - let coldkey1 = U256::from(4); - add_network(netuid, 0, 0); - SubtensorModule::set_max_registrations_per_block(netuid, 4); - SubtensorModule::set_target_registrations_per_interval(netuid, 4); - SubtensorModule::set_max_allowed_uids(netuid, 4); // Allow all 4 to be registered at once - SubtensorModule::set_target_stakes_per_interval(10); // Increase max stakes per interval - - // Neither key can add stake because they dont have fundss. - assert_eq!( - SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - 60000 - ), - Err(Error::::NotEnoughBalanceToStake.into()) - ); - assert_eq!( - SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - 60000 - ), - Err(Error::::NotEnoughBalanceToStake.into()) - ); - - // Add balances. - SubtensorModule::add_balance_to_coldkey_account(&coldkey0, 60000); - SubtensorModule::add_balance_to_coldkey_account(&coldkey1, 60000); - - // We have enough, but the keys are not registered. - assert_eq!( - SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - 100 - ), - Err(Error::::HotKeyAccountNotExists.into()) - ); - assert_eq!( - SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - 100 - ), - Err(Error::::HotKeyAccountNotExists.into()) - ); - - // Cant remove either. - assert_eq!( - SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - 10 - ), - Err(Error::::HotKeyAccountNotExists.into()) - ); - assert_eq!( - SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - 10 - ), - Err(Error::::HotKeyAccountNotExists.into()) - ); - assert_eq!( - SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey1, - 10 - ), - Err(Error::::HotKeyAccountNotExists.into()) - ); - assert_eq!( - SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey0, - 10 - ), - Err(Error::::HotKeyAccountNotExists.into()) - ); - - // Neither key can become a delegate either because we are not registered. - assert_eq!( - SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - 100 - ), - Err(Error::::HotKeyAccountNotExists.into()) - ); - assert_eq!( - SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - 100 - ), - Err(Error::::HotKeyAccountNotExists.into()) - ); - - // Register the 2 neurons to a new network. - register_ok_neuron(netuid, hotkey0, coldkey0, 124124); - register_ok_neuron(netuid, hotkey1, coldkey1, 987907); - assert_eq!( - SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey0), - coldkey0 - ); - assert_eq!( - SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey1), - coldkey1 - ); - assert!(SubtensorModule::coldkey_owns_hotkey(&coldkey0, &hotkey0)); - assert!(SubtensorModule::coldkey_owns_hotkey(&coldkey1, &hotkey1)); - - // We try to delegate stake but niether are allowing delegation. - assert!(!SubtensorModule::hotkey_is_delegate(&hotkey0)); - assert!(!SubtensorModule::hotkey_is_delegate(&hotkey1)); - assert_eq!( - SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey1, - 100 - ), - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) - ); - assert_eq!( - SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey0, - 100 - ), - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) - ); - - // We stake and all is ok. - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 0 - ); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - 100 - )); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - 100 - )); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 100 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), - 100 - ); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 100); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 100); - //assert_eq!( SubtensorModule::get_total_stake_for_coldkey( &coldkey0 ), 100 ); - //assert_eq!( SubtensorModule::get_total_stake_for_coldkey( &coldkey1 ), 100 ); - assert_eq!(SubtensorModule::get_total_stake(), 200); - - // Cant remove these funds because we are not delegating. - assert_eq!( - SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey1, - 10 - ), - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) - ); - assert_eq!( - SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey0, - 10 - ), - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) - ); - - // Emit inflation through non delegates. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 0, 100); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 0, 100); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 200); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 200); - - // Try allowing the keys to become delegates, fails because of incorrect coldkeys. - // Set take to be 0. - assert_eq!( - SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey0), - hotkey1, - 0 - ), - Err(Error::::NonAssociatedColdKey.into()) - ); - assert_eq!( - SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey1), - hotkey0, - 0 - ), - Err(Error::::NonAssociatedColdKey.into()) - ); - - // Become delegates all is ok. - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - SubtensorModule::get_min_take() - )); - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - SubtensorModule::get_min_take() - )); - assert!(SubtensorModule::hotkey_is_delegate(&hotkey0)); - assert!(SubtensorModule::hotkey_is_delegate(&hotkey1)); - - // Cant become a delegate twice. - assert_eq!( - SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - SubtensorModule::get_min_take() - ), - Err(Error::::HotKeyAlreadyDelegate.into()) - ); - assert_eq!( - SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - u16::MAX / 10 - ), - Err(Error::::HotKeyAlreadyDelegate.into()) - ); - - // This add stake works for delegates. - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 200 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), - 200 - ); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey1, - 200 - )); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey0, - 300 - )); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 200 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), - 200 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), - 300 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), - 200 - ); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 500); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 400); - //assert_eq!( SubtensorModule::get_total_stake_for_coldkey( &coldkey0 ), 400 ); - //assert_eq!( SubtensorModule::get_total_stake_for_coldkey( &coldkey1 ), 500 ); - assert_eq!(SubtensorModule::get_total_stake(), 900); - - // Lets emit inflation through the hot and coldkeys. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 0, 1000); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 0, 1000); - - // validator_take = take * validator_emission = 10% * 1000 = 100 - // old_stake + (validator_emission - validator_take) * stake_for_coldkey_and_hotkey / total_stake_for_hotkey + validator_take - // = - // 200 + 900 * 200 / 500 + 100 = 660 - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 654 - ); - // validator_take = take * validator_emission = 9% * 1000 = 90 - // old_stake + (validator_emission - validator_take) * stake_for_coldkey_and_hotkey / total_stake_for_hotkey - // = - // 200 + (1000 - 90) * 200 / 400 = 655 ~ 654 - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), - 655 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), - 846 - ); // 300 + 910 x ( 300 / 500 ) = 300 + 546 = 846 - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), - 745 - ); // 200 + 1090 x ( 200 / 400 ) = 300 + 545 = 745 - assert_eq!(SubtensorModule::get_total_stake(), 2900); // 600 + 700 + 900 + 750 = 2900 - - // // Try unstaking too much. - assert_eq!( - SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - 100000 - ), - Err(Error::::NotEnoughStakeToWithdraw.into()) - ); - assert_eq!( - SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - 100000 - ), - Err(Error::::NotEnoughStakeToWithdraw.into()) - ); - assert_eq!( - SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey1, - 100000 - ), - Err(Error::::NotEnoughStakeToWithdraw.into()) - ); - assert_eq!( - SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey0, - 100000 - ), - Err(Error::::NotEnoughStakeToWithdraw.into()) - ); - - // unstaking is ok. - assert_ok!(SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - 100 - )); - assert_ok!(SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - 100 - )); - assert_ok!(SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey1, - 100 - )); - assert_ok!(SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey0, - 100 - )); - - // All the amounts have been decreased. - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 554 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), - 555 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), - 746 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), - 645 - ); - - // Lets register and stake a new key. - let hotkey2 = U256::from(5); - let coldkey2 = U256::from(6); - register_ok_neuron(netuid, hotkey2, coldkey2, 248_123); - assert!(SubtensorModule::is_hotkey_registered_on_any_network( - &hotkey0 - )); - assert!(SubtensorModule::is_hotkey_registered_on_any_network( - &hotkey1 - )); - - SubtensorModule::add_balance_to_coldkey_account(&coldkey2, 60_000); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey2), - hotkey2, - 1000 - )); - assert_ok!(SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey2), - hotkey2, - 100 - )); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2), - 900 - ); - assert_eq!( - SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey2, - 10 - ), - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) - ); - assert_eq!( - SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey2, - 10 - ), - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) - ); - - // Lets make this new key a delegate with a 10% take. - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey2), - hotkey2, - SubtensorModule::get_min_take() - )); - - // Add nominate some stake. - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey2, - 1_000 - )); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey2, - 1_000 - )); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey2), - hotkey2, - 100 - )); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2), - 1_000 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2), - 1_000 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2), - 1_000 - ); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey2), 3_000); - assert_eq!(SubtensorModule::get_total_stake(), 5_500); - - // Lets emit inflation through this new key with distributed ownership. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey2, 0, 1000); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2), - 1_394 - ); // 1000 + 94 + 900 * (1000/3000) = 1400 - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2), - 1_303 - ); // 1000 + 900 * (1000/3000) = 1300 - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2), - 1_303 - ); // 1000 + 900 * (1000/3000) = 1300 - assert_eq!(SubtensorModule::get_total_stake(), 6_500); // before + 1_000 = 5_500 + 1_000 = 6_500 - - step_block(1); - - // Lets register and stake a new key. - let hotkey3 = U256::from(7); - let coldkey3 = U256::from(8); - register_ok_neuron(netuid, hotkey3, coldkey3, 4124124); - SubtensorModule::add_balance_to_coldkey_account(&coldkey3, 60000); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey3), - hotkey3, - 1000 - )); - - step_block(3); - - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey3), - hotkey3, - SubtensorModule::get_min_take() - )); // Full take. - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey3, - 1000 - )); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey3, - 1000 - )); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey2), - hotkey3, - 1000 - )); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey3), - 1000 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey3), - 1000 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey3), - 1000 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey3, &hotkey3), - 1000 - ); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey3), 4000); - assert_eq!(SubtensorModule::get_total_stake(), 10_500); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey3, 0, 1000); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey3), - 1227 - ); // 1000 + 90% * 1000 * 1000/4000 = 1225 - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey3), - 1227 - ); // 1000 + 90% * 1000 * 1000/4000 = 1225 - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey3), - 1227 - ); // 1000 + 90% * 1000 * 1000/4000 = 1225 - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey3, &hotkey3), - 1319 - ); // 1000 + 25 * 3 + 1000 * 1000/4000 = 1325 - assert_eq!(SubtensorModule::get_total_stake(), 11_500); // before + 1_000 = 10_500 + 1_000 = 11_500 - }); -} - -// Verify delegates with servers get the full server inflation. -#[test] -fn test_full_with_delegating_some_servers() { - new_test_ext(1).execute_with(|| { - let netuid = 1; - // Make two accounts. - let hotkey0 = U256::from(1); - let hotkey1 = U256::from(2); - - let coldkey0 = U256::from(3); - let coldkey1 = U256::from(4); - SubtensorModule::set_max_registrations_per_block(netuid, 4); - SubtensorModule::set_max_allowed_uids(netuid, 10); // Allow at least 10 to be registered at once, so no unstaking occurs - SubtensorModule::set_target_stakes_per_interval(10); // Increase max stakes per interval - - // Neither key can add stake because they dont have fundss. - assert_eq!( - SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - 60000 - ), - Err(Error::::NotEnoughBalanceToStake.into()) - ); - assert_eq!( - SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - 60000 - ), - Err(Error::::NotEnoughBalanceToStake.into()) - ); - - // Add balances. - SubtensorModule::add_balance_to_coldkey_account(&coldkey0, 60000); - SubtensorModule::add_balance_to_coldkey_account(&coldkey1, 60000); - - // Register the 2 neurons to a new network. - let netuid = 1; - add_network(netuid, 0, 0); - register_ok_neuron(netuid, hotkey0, coldkey0, 124124); - register_ok_neuron(netuid, hotkey1, coldkey1, 987907); - assert_eq!( - SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey0), - coldkey0 - ); - assert_eq!( - SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey1), - coldkey1 - ); - assert!(SubtensorModule::coldkey_owns_hotkey(&coldkey0, &hotkey0)); - assert!(SubtensorModule::coldkey_owns_hotkey(&coldkey1, &hotkey1)); - - // We stake and all is ok. - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 0 - ); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - 100 - )); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - 100 - )); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 100 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), - 100 - ); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 100); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 100); - assert_eq!(SubtensorModule::get_total_stake(), 200); - - // Emit inflation through non delegates. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 0, 100); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 0, 100); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 200); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 200); - - // Become delegates all is ok. - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - SubtensorModule::get_min_take() - )); - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - SubtensorModule::get_min_take() - )); - assert!(SubtensorModule::hotkey_is_delegate(&hotkey0)); - assert!(SubtensorModule::hotkey_is_delegate(&hotkey1)); - - // This add stake works for delegates. - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 200 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), - 200 - ); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey1, - 200 - )); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey0, - 300 - )); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 200 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), - 200 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), - 300 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), - 200 - ); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 500); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 400); - assert_eq!(SubtensorModule::get_total_stake(), 900); - - // Lets emit inflation through the hot and coldkeys. - // fist emission arg is for a server. This should only go to the owner of the hotkey. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 200, 1_000); // 1_200 total emission. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 123, 2_000); // 2_123 total emission. - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 854 - ); // 200 + (200 + 910 x ( 200 / 500 )) = 200 + (200 + 400) + 60 = 854 - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), - 846 - ); // 300 + 910 x ( 300 / 500 ) = 300 + 546 = 846 - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 1_700); // initial + server emission + validator emission = 799 + 899 = 1_698 - - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), - 1_110 - ); // 200 + (0 + 2000 x ( 200 / 400 )) - 100 = 200 + (1000) - 100= 1_110 - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), - 1_413 - ); // 200 + (123 + 2000 x ( 200 / 400 )) + 100 = 200 + (1_200)+ 100 = 1_423 - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 2_523); // 400 + 2_123 - assert_eq!(SubtensorModule::get_total_stake(), 4_223); // 2_100 + 2_123 = 4_223 - - // Lets emit MORE inflation through the hot and coldkeys. - // This time only server emission. This should go to the owner of the hotkey. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 350, 0); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 150, 0); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 1_204 - ); // + 350 + 54 = 1_204 - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), - 1_110 - ); // No change. - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), - 846 - ); // No change. - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), - 1_563 - ); // 1_323 + 150 + 90 = 1_573 - assert_eq!(SubtensorModule::get_total_stake(), 4_723); // 4_223 + 500 = 4_823 - - // Lets register and stake a new key. - let hotkey2 = U256::from(5); - let coldkey2 = U256::from(6); - register_ok_neuron(netuid, hotkey2, coldkey2, 248123); - SubtensorModule::add_balance_to_coldkey_account(&coldkey2, 60_000); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey2), - hotkey2, - 1_000 - )); - assert_ok!(SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey2), - hotkey2, - 100 - )); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2), - 900 - ); - assert_eq!( - SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey2, - 10 - ), - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) - ); - assert_eq!( - SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey2, - 10 - ), - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) - ); - - assert_eq!(SubtensorModule::get_total_stake(), 5_623); // 4_723 + 900 = 5_623 - - // Lets make this new key a delegate with a 9% take. - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey2), - hotkey2, - SubtensorModule::get_min_take() - )); - - // Add nominate some stake. - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey2, - 1000 - )); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey2, - 1000 - )); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey2), - hotkey2, - 100 - )); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2), - 1000 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2), - 1000 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2), - 1000 - ); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey2), 3_000); - assert_eq!(SubtensorModule::get_total_stake(), 7_723); // 5_623 + (1_000 + 1_000 + 100) = 7_723 - - // Lets emit inflation through this new key with distributed ownership. - // We will emit 100 server emission, which should go in-full to the owner of the hotkey. - // We will emit 1000 validator emission, which should be distributed in-part to the nominators. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey2, 100, 1000); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2), - 1_494 - ); // 1000 + 100 + 94 + 900 * (1000/3000) = 1000 + 200 + 300 = 1_494 - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2), - 1_303 - ); // 1000 + 900 * (1000/3000) = 1000 + 300 = 1_303 - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2), - 1_303 - ); // 1000 + 900 * (1000/3000) = 1000 + 300 = 1300 - assert_eq!(SubtensorModule::get_total_stake(), 8_823); // 7_723 + 1_100 = 8_823 - - // Lets emit MORE inflation through this new key with distributed ownership. - // This time we do ONLY server emission - // We will emit 123 server emission, which should go in-full to the owner of the hotkey. - // We will emit *0* validator emission. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey2, 123, 0); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2), - 1_617 - ); // 1_500 + 117 = 1_617 - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2), - 1_303 - ); // No change. - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2), - 1_303 - ); // No change. - assert_eq!(SubtensorModule::get_total_stake(), 8_946); // 8_823 + 123 = 8_946 - }); -} - -#[test] -fn test_full_block_emission_occurs() { - new_test_ext(1).execute_with(|| { - let netuid = 1; - // Make two accounts. - let hotkey0 = U256::from(1); - let hotkey1 = U256::from(2); - - let coldkey0 = U256::from(3); - let coldkey1 = U256::from(4); - SubtensorModule::set_max_registrations_per_block(netuid, 4); - SubtensorModule::set_max_allowed_uids(netuid, 10); // Allow at least 10 to be registered at once, so no unstaking occurs - SubtensorModule::set_target_stakes_per_interval(10); // Increase max stakes per interval - - // Neither key can add stake because they dont have fundss. - assert_eq!( - SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - 60000 - ), - Err(Error::::NotEnoughBalanceToStake.into()) - ); - assert_eq!( - SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - 60000 - ), - Err(Error::::NotEnoughBalanceToStake.into()) - ); - - // Add balances. - SubtensorModule::add_balance_to_coldkey_account(&coldkey0, 60000); - SubtensorModule::add_balance_to_coldkey_account(&coldkey1, 60000); - - // Register the 2 neurons to a new network. - let netuid = 1; - add_network(netuid, 0, 0); - register_ok_neuron(netuid, hotkey0, coldkey0, 124124); - register_ok_neuron(netuid, hotkey1, coldkey1, 987907); - assert_eq!( - SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey0), - coldkey0 - ); - assert_eq!( - SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey1), - coldkey1 - ); - assert!(SubtensorModule::coldkey_owns_hotkey(&coldkey0, &hotkey0)); - assert!(SubtensorModule::coldkey_owns_hotkey(&coldkey1, &hotkey1)); - - // We stake and all is ok. - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 0 - ); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - 100 - )); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - 100 - )); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 100 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), - 0 - ); - assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), - 100 - ); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 100); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 100); - assert_eq!(SubtensorModule::get_total_stake(), 200); - - // Emit inflation through non delegates. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 0, 111); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 0, 234); - // Verify the full emission occurs. - assert_eq!(SubtensorModule::get_total_stake(), 200 + 111 + 234); // 200 + 111 + 234 = 545 - - // Become delegates all is ok. - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - SubtensorModule::get_min_take() - )); - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - SubtensorModule::get_min_take() - )); - assert!(SubtensorModule::hotkey_is_delegate(&hotkey0)); - assert!(SubtensorModule::hotkey_is_delegate(&hotkey1)); - - // Add some delegate stake - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey1, - 200 - )); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey0, - 300 - )); - - assert_eq!(SubtensorModule::get_total_stake(), 545 + 500); // 545 + 500 = 1045 - - // Lets emit inflation with delegatees, with both validator and server emission - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 200, 1_000); // 1_200 total emission. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 123, 2_000); // 2_123 total emission. - - assert_eq!(SubtensorModule::get_total_stake(), 1045 + 1_200 + 2_123); // before + 1_200 + 2_123 = 4_368 - - // Lets emit MORE inflation through the hot and coldkeys. - // This time JUSt server emission - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 350, 0); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 150, 0); - - assert_eq!(SubtensorModule::get_total_stake(), 4_368 + 350 + 150); // before + 350 + 150 = 4_868 - - // Lastly, do only validator emission - - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 0, 12_948); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 0, 1_874); - - assert_eq!(SubtensorModule::get_total_stake(), 4_868 + 12_948 + 1_874); // before + 12_948 + 1_874 = 19_690 }); } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index df1687fdf4..1191562286 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -880,6 +880,8 @@ parameter_types! { pub const InitialAlphaHigh: u16 = 58982; // Represents 0.9 as per the production default pub const InitialAlphaLow: u16 = 45875; // Represents 0.7 as per the production default pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn + pub const SubtensorInitialHotkeyEmissionTempo: u64 = 7200; // Drain every day. + pub const SubtensorInitialNetworkMaxStake: u64 = 500_000_000_000_000; // 500_000 TAO } impl pallet_subtensor::Config for Runtime { @@ -935,6 +937,8 @@ impl pallet_subtensor::Config for Runtime { type AlphaHigh = InitialAlphaHigh; type AlphaLow = InitialAlphaLow; type LiquidAlphaOn = InitialLiquidAlphaOn; + type InitialHotkeyEmissionTempo = SubtensorInitialHotkeyEmissionTempo; + type InitialNetworkMaxStake = SubtensorInitialNetworkMaxStake; } use sp_runtime::BoundedVec; @@ -1213,11 +1217,15 @@ impl fn set_liquid_alpha_enabled(netuid: u16, enabled: bool) { SubtensorModule::set_liquid_alpha_enabled(netuid, enabled); } - + fn set_hotkey_emission_tempo(emission_tempo: u64) { SubtensorModule::set_hotkey_emission_tempo(emission_tempo); } + fn set_network_max_stake(netuid: u16, max_stake: u64) { + SubtensorModule::set_network_max_stake(netuid, max_stake); + } + fn do_set_alpha_values( origin: RuntimeOrigin, netuid: u16, From 02457c1ad49a7608f294a5aa9e44f5538a7602a3 Mon Sep 17 00:00:00 2001 From: const Date: Tue, 23 Jul 2024 14:24:03 -0500 Subject: [PATCH 11/16] fix migration tests --- pallets/subtensor/src/lib.rs | 3 + pallets/subtensor/src/macros/dispatches.rs | 22 +- .../migrate_fix_total_coldkey_stake.rs | 44 ++- pallets/subtensor/src/swap/swap_coldkey.rs | 253 +----------------- pallets/subtensor/src/swap/swap_hotkey.rs | 38 ++- pallets/subtensor/tests/migration.rs | 12 +- 6 files changed, 78 insertions(+), 294 deletions(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 5a002b333e..29969a23b0 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1073,9 +1073,12 @@ pub mod pallet { (H256, u64), OptionQuery, >; + /// ================== /// ==== Genesis ===== /// ================== + #[pallet::storage] // --- Storage for migration run status + pub type HasMigrationRun = StorageMap<_, Identity, Vec, bool, ValueQuery>; #[pallet::genesis_config] pub struct GenesisConfig { diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index d8cb31166a..293dc02380 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -640,17 +640,17 @@ mod dispatches { } /// The extrinsic for user to change its hotkey - ///#[pallet::call_index(70)] - ///#[pallet::weight((Weight::from_parts(1_940_000_000, 0) - ///.saturating_add(T::DbWeight::get().reads(272)) - ///.saturating_add(T::DbWeight::get().writes(527)), DispatchClass::Operational, Pays::No))] - ///pub fn swap_hotkey( - /// origin: OriginFor, - /// hotkey: T::AccountId, - /// new_hotkey: T::AccountId, - ///) -> DispatchResultWithPostInfo { - /// Self::do_swap_hotkey(origin, &hotkey, &new_hotkey) - ///} + #[pallet::call_index(70)] + #[pallet::weight((Weight::from_parts(1_940_000_000, 0) + .saturating_add(T::DbWeight::get().reads(272)) + .saturating_add(T::DbWeight::get().writes(527)), DispatchClass::Operational, Pays::No))] + pub fn swap_hotkey( + origin: OriginFor, + hotkey: T::AccountId, + new_hotkey: T::AccountId, + ) -> DispatchResultWithPostInfo { + Self::do_swap_hotkey(origin, &hotkey, &new_hotkey) + } /// The extrinsic for user to change the coldkey associated with their account. /// diff --git a/pallets/subtensor/src/migrations/migrate_fix_total_coldkey_stake.rs b/pallets/subtensor/src/migrations/migrate_fix_total_coldkey_stake.rs index 20c47e29c6..268c82d489 100644 --- a/pallets/subtensor/src/migrations/migrate_fix_total_coldkey_stake.rs +++ b/pallets/subtensor/src/migrations/migrate_fix_total_coldkey_stake.rs @@ -2,9 +2,10 @@ use super::*; use frame_support::{ pallet_prelude::{Identity, OptionQuery}, storage_alias, - traits::{Get, GetStorageVersion, StorageVersion}, + traits::{Get, StorageVersion}, weights::Weight, }; +use alloc::string::String; use sp_std::vec::Vec; // TODO (camfairchild): TEST MIGRATION @@ -50,24 +51,41 @@ pub fn do_migrate_fix_total_coldkey_stake() -> Weight { } // Public migrate function to be called by Lib.rs on upgrade. pub fn migrate_fix_total_coldkey_stake() -> Weight { - let current_storage_version: u16 = 7; - let next_storage_version: u16 = 8; + let migration_name = b"fix_total_coldkey_stake_v7".to_vec(); // Initialize the weight with one read operation. let mut weight = T::DbWeight::get().reads(1); - // Grab the current on-chain storage version. - // Cant fail on retrieval. - let onchain_version = Pallet::::on_chain_storage_version(); - - // Only run this migration on storage version 6. - if onchain_version == current_storage_version { - weight = weight.saturating_add(do_migrate_fix_total_coldkey_stake::()); - // Cant fail on insert. - StorageVersion::new(next_storage_version).put::>(); - weight.saturating_accrue(T::DbWeight::get().writes(1)); + // Check if the migration has already run + if HasMigrationRun::::get(&migration_name) { + log::info!( + "Migration '{:?}' has already run. Skipping.", + migration_name + ); + return Weight::zero(); } + log::info!( + "Running migration '{}'", + String::from_utf8_lossy(&migration_name) + ); + + // Run the migration + weight = weight.saturating_add(do_migrate_fix_total_coldkey_stake::()); + + // Mark the migration as completed + HasMigrationRun::::insert(&migration_name, true); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); + + // Set the storage version to 7 + StorageVersion::new(7).put::>(); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); + + log::info!( + "Migration '{:?}' completed. Storage version set to 7.", + String::from_utf8_lossy(&migration_name) + ); + // Return the migration weight. weight } diff --git a/pallets/subtensor/src/swap/swap_coldkey.rs b/pallets/subtensor/src/swap/swap_coldkey.rs index e0e0061d86..507fc62a5e 100644 --- a/pallets/subtensor/src/swap/swap_coldkey.rs +++ b/pallets/subtensor/src/swap/swap_coldkey.rs @@ -1,7 +1,6 @@ use super::*; -use crate::MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP; use frame_support::weights::Weight; -use sp_core::{Get, U256}; +use sp_core::{Get}; impl Pallet { /// Swaps the coldkey associated with a set of hotkeys from an old coldkey to a new coldkey. @@ -37,28 +36,22 @@ impl Pallet { // 1. Ensure the origin is signed and get the old coldkey let old_coldkey = ensure_signed(origin)?; - // 2. Check if the old coldkey is in arbitration - ensure!( - !Self::coldkey_in_arbitration(&old_coldkey), - Error::::ColdkeyIsInArbitration - ); - - // 3. Initialize the weight for this operation + // 2. Initialize the weight for this operation let mut weight: Weight = T::DbWeight::get().reads(2); - // 4. Ensure the new coldkey is not associated with any hotkeys + // 3. Ensure the new coldkey is not associated with any hotkeys ensure!( StakingHotkeys::::get(new_coldkey).is_empty(), Error::::ColdKeyAlreadyAssociated ); - // 5. Ensure the new coldkey is not a hotkey + // 4. Ensure the new coldkey is not a hotkey ensure!( !Self::hotkey_account_exists(new_coldkey), Error::::ColdKeyAlreadyAssociated ); - // 6. Calculate the swap cost and ensure sufficient balance + // 5. Calculate the swap cost and ensure sufficient balance let swap_cost = Self::get_key_swap_cost(); log::debug!("Coldkey swap cost: {:?}", swap_cost); ensure!( @@ -66,28 +59,28 @@ impl Pallet { Error::::NotEnoughBalanceToPaySwapColdKey ); - // 7. Remove and burn the swap cost from the old coldkey's account + // 6. Remove and burn the swap cost from the old coldkey's account let actual_burn_amount = Self::remove_balance_from_coldkey_account(&old_coldkey, swap_cost)?; Self::burn_tokens(actual_burn_amount); - // 8. Update the weight for the balance operations + // 7. Update the weight for the balance operations weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - // 9. Perform the actual coldkey swap + // 8. Perform the actual coldkey swap let _ = Self::perform_swap_coldkey(&old_coldkey, new_coldkey, &mut weight); - // 10. Update the last transaction block for the new coldkey + // 9. Update the last transaction block for the new coldkey Self::set_last_tx_block(new_coldkey, Self::get_current_block_as_u64()); weight.saturating_accrue(T::DbWeight::get().writes(1)); - // 11. Emit the ColdkeySwapped event + // 10. Emit the ColdkeySwapped event Self::deposit_event(Event::ColdkeySwapped { old_coldkey: old_coldkey.clone(), new_coldkey: new_coldkey.clone(), }); - // 12. Return the result with the updated weight + // 11. Return the result with the updated weight Ok(Some(weight).into()) } @@ -232,228 +225,4 @@ impl Pallet { // Return ok. Ok(()) } - - /// Checks if a coldkey is currently in arbitration. - /// - /// # Arguments - /// - /// * `coldkey` - The account ID of the coldkey to check. - /// - /// # Returns - /// - /// * `bool` - True if the coldkey is in arbitration, false otherwise. - /// - /// # Notes - /// - /// This function compares the arbitration block number of the coldkey with the current block number. - pub fn coldkey_in_arbitration(coldkey: &T::AccountId) -> bool { - ColdkeyArbitrationBlock::::get(coldkey) > Self::get_current_block_as_u64() - } - - /// Returns the remaining arbitration period for a given coldkey. - /// - /// # Arguments - /// - /// * `coldkey` - The account ID of the coldkey to check. - /// - /// # Returns - /// - /// * `u64` - The remaining arbitration period in blocks. - /// - /// - /// # Notes - /// - /// This function calculates the remaining arbitration period by subtracting the current block number - /// from the arbitration block number of the coldkey. - pub fn get_remaining_arbitration_period(coldkey: &T::AccountId) -> u64 { - let current_block: u64 = Self::get_current_block_as_u64(); - let arbitration_block: u64 = ColdkeyArbitrationBlock::::get(coldkey); - if arbitration_block > current_block { - arbitration_block.saturating_sub(current_block) - } else { - 0 - } - } - - pub fn meets_min_allowed_coldkey_balance(coldkey: &T::AccountId) -> bool { - let all_staked_keys: Vec = StakingHotkeys::::get(coldkey); - let mut total_staking_balance: u64 = 0; - for hotkey in all_staked_keys { - total_staking_balance = total_staking_balance - .saturating_add(Self::get_stake_for_coldkey_and_hotkey(coldkey, &hotkey)); - } - total_staking_balance = - total_staking_balance.saturating_add(Self::get_coldkey_balance(coldkey)); - total_staking_balance >= MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP - } - - /// Schedules a coldkey swap to a new coldkey with arbitration. - /// - /// # Arguments - /// - /// * `old_coldkey` - The account ID of the old coldkey. - /// * `new_coldkey` - The account ID of the new coldkey. - /// * `work` - The proof of work submitted by the caller. - /// * `block_number` - The block number at which the work was performed. - /// * `nonce` - The nonce used for the proof of work. - /// - /// # Returns - /// - /// * `DispatchResult` - The result of the dispatch. - /// - /// # Errors - /// - - /// - `SameColdkey`: The old coldkey is the same as the new coldkey. - /// - `DuplicateColdkey`: The new coldkey is already in the list of destination coldkeys. - /// - `MaxColdkeyDestinationsReached`: There are already the maximum allowed destination coldkeys for the old coldkey. - /// - `InsufficientBalanceToPerformColdkeySwap`: The old coldkey doesn't have the minimum required TAO balance. - /// - `InvalidDifficulty`: The proof of work is invalid or doesn't meet the required difficulty. - /// - /// # Notes - /// - /// This function ensures that the new coldkey is not already in the list of destination coldkeys. - /// It also checks for a minimum TAO balance and verifies the proof of work. - /// The difficulty of the proof of work increases exponentially with each subsequent call. - pub fn do_schedule_coldkey_swap( - old_coldkey: &T::AccountId, - new_coldkey: &T::AccountId, - work: Vec, - block_number: u64, - nonce: u64, - ) -> DispatchResult { - ensure!(old_coldkey != new_coldkey, Error::::SameColdkey); - - // Check if the old_coldkey is a subnet owner for any network - let is_subnet_owner = (0..=TotalNetworks::::get()) - .any(|netuid| SubnetOwner::::get(netuid) == *old_coldkey); - - // Check if the old_coldkey has more than 500 TAO delegated - let total_delegated = Self::get_total_delegated_stake(old_coldkey); - let has_sufficient_delegation = total_delegated > 500_000_000_000; // 500 TAO in RAO - - // Only check the minimum balance if the old_coldkey is not a subnet owner - // and doesn't have sufficient delegation - if !(is_subnet_owner || has_sufficient_delegation) { - ensure!( - Self::meets_min_allowed_coldkey_balance(old_coldkey), - Error::::InsufficientBalanceToPerformColdkeySwap - ); - } - - // Get current destination coldkeys - let mut destination_coldkeys: Vec = - ColdkeySwapDestinations::::get(old_coldkey.clone()); - - // Calculate difficulty based on the number of existing destination coldkeys - let difficulty = Self::calculate_pow_difficulty(destination_coldkeys.len() as u32); - let work_hash = Self::vec_to_hash(work.clone()); - ensure!( - Self::hash_meets_difficulty(&work_hash, difficulty), - Error::::InvalidDifficulty - ); - - // Verify work is the product of the nonce, the block number, and coldkey - let seal = Self::create_seal_hash(block_number, nonce, old_coldkey); - ensure!(seal == work_hash, Error::::InvalidSeal); - - // Check if the new coldkey is already in the swap wallets list - ensure!( - !destination_coldkeys.contains(new_coldkey), - Error::::DuplicateColdkey - ); - - // If the destinations keys are empty or have less than the maximum allowed, we will add the new coldkey to the list - const MAX_COLDKEY_DESTINATIONS: usize = 10; - - if destination_coldkeys.len() < MAX_COLDKEY_DESTINATIONS { - destination_coldkeys.push(new_coldkey.clone()); - ColdkeySwapDestinations::::insert(old_coldkey.clone(), destination_coldkeys.clone()); - } else { - return Err(Error::::MaxColdkeyDestinationsReached.into()); - } - - // It is the first time we have seen this key - if destination_coldkeys.len() == 1_usize { - // Set the arbitration block for this coldkey - let arbitration_block: u64 = - Self::get_current_block_as_u64().saturating_add(ArbitrationPeriod::::get()); - ColdkeyArbitrationBlock::::insert(old_coldkey.clone(), arbitration_block); - - // Update the list of coldkeys to arbitrate on this block - let mut key_to_arbitrate_on_this_block: Vec = - ColdkeysToSwapAtBlock::::get(arbitration_block); - if !key_to_arbitrate_on_this_block.contains(old_coldkey) { - key_to_arbitrate_on_this_block.push(old_coldkey.clone()); - } - ColdkeysToSwapAtBlock::::insert(arbitration_block, key_to_arbitrate_on_this_block); - } - - // Emit an event indicating that a coldkey swap has been scheduled - Self::deposit_event(Event::ColdkeySwapScheduled { - old_coldkey: old_coldkey.clone(), - new_coldkey: new_coldkey.clone(), - arbitration_block: ColdkeyArbitrationBlock::::get(old_coldkey), - }); - - Ok(()) - } - - /// Calculate the proof of work difficulty based on the number of swap attempts - #[allow(clippy::arithmetic_side_effects)] - pub fn calculate_pow_difficulty(swap_attempts: u32) -> U256 { - let base_difficulty: U256 = U256::from(BaseDifficulty::::get()); // Base difficulty - base_difficulty.saturating_mul(U256::from(2).pow(U256::from(swap_attempts))) - } - - /// Arbitrates coldkeys that are scheduled to be swapped on this block. - /// - /// This function retrieves the list of coldkeys scheduled to be swapped on the current block, - /// and processes each coldkey by either extending the arbitration period or performing the swap - /// to the new coldkey. - /// - /// # Returns - /// - /// * `Weight` - The total weight consumed by this operation - pub fn swap_coldkeys_this_block(_weight_limit: &Weight) -> Result { - let mut weight_used = frame_support::weights::Weight::from_parts(0, 0); - - let current_block: u64 = Self::get_current_block_as_u64(); - log::debug!("Swapping coldkeys for block: {:?}", current_block); - - let source_coldkeys: Vec = ColdkeysToSwapAtBlock::::get(current_block); - ColdkeysToSwapAtBlock::::remove(current_block); - weight_used = weight_used.saturating_add(T::DbWeight::get().reads_writes(1, 1)); - - let mut keys_swapped = 0u64; - for coldkey_i in source_coldkeys.iter() { - // TODO: need a sane way to terminate early without locking users in. - // we should update the swap time - // if weight_used.ref_time() > weight_limit.ref_time() { - // log::warn!("Could not finish swapping all coldkeys this block due to weight limit, breaking after swapping {} keys.", keys_swapped); - // break; - // } - - let destinations_coldkeys: Vec = - ColdkeySwapDestinations::::get(coldkey_i); - weight_used = weight_used.saturating_add(T::DbWeight::get().reads(1)); - - if destinations_coldkeys.len() > 1 { - // Do not remove ColdkeySwapDestinations if there are multiple destinations - ColdkeyArbitrationBlock::::insert(coldkey_i.clone(), u64::MAX); - Self::deposit_event(Event::ArbitrationPeriodExtended { - coldkey: coldkey_i.clone(), - }); - } else if let Some(new_coldkey) = destinations_coldkeys.first() { - // Only remove ColdkeySwapDestinations if there's a single destination - ColdkeySwapDestinations::::remove(&coldkey_i); - weight_used = weight_used.saturating_add(T::DbWeight::get().writes(1)); - keys_swapped = keys_swapped.saturating_add(1); - let _ = Self::perform_swap_coldkey(coldkey_i, new_coldkey, &mut weight_used); - } - } - - Ok(weight_used) - } - } \ No newline at end of file diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index 5c3fecbba5..fb3c33e4d8 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -30,78 +30,72 @@ impl Pallet { // 1. Ensure the origin is signed and get the coldkey let coldkey = ensure_signed(origin)?; - // 2. Check if the coldkey is in arbitration - ensure!( - !Self::coldkey_in_arbitration(&coldkey), - Error::::ColdkeyIsInArbitration - ); - - // 3. Initialize the weight for this operation + // 2. Initialize the weight for this operation let mut weight = T::DbWeight::get().reads(2); - // 4. Ensure the new hotkey is different from the old one + // 3. Ensure the new hotkey is different from the old one ensure!(old_hotkey != new_hotkey, Error::::NewHotKeyIsSameWithOld); - // 5. Ensure the new hotkey is not already registered on any network + // 4. Ensure the new hotkey is not already registered on any network ensure!( !Self::is_hotkey_registered_on_any_network(new_hotkey), Error::::HotKeyAlreadyRegisteredInSubNet ); - // 6. Update the weight for the checks above + // 5. Update the weight for the checks above weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 0)); - // 7. Ensure the coldkey owns the old hotkey + // 6. Ensure the coldkey owns the old hotkey ensure!( Self::coldkey_owns_hotkey(&coldkey, old_hotkey), Error::::NonAssociatedColdKey ); - // 8. Get the current block number + // 7. Get the current block number let block: u64 = Self::get_current_block_as_u64(); - // 9. Ensure the transaction rate limit is not exceeded + // 8. Ensure the transaction rate limit is not exceeded ensure!( !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&coldkey), block), Error::::HotKeySetTxRateLimitExceeded ); - // 10. Update the weight for reading the total networks + // 9. Update the weight for reading the total networks weight.saturating_accrue( T::DbWeight::get().reads((TotalNetworks::::get().saturating_add(1u16)) as u64), ); - // 11. Get the cost for swapping the key + // 10. Get the cost for swapping the key let swap_cost = Self::get_key_swap_cost(); log::debug!("Swap cost: {:?}", swap_cost); - // 12. Ensure the coldkey has enough balance to pay for the swap + // 11. Ensure the coldkey has enough balance to pay for the swap ensure!( Self::can_remove_balance_from_coldkey_account(&coldkey, swap_cost), Error::::NotEnoughBalanceToPaySwapHotKey ); - // 13. Remove the swap cost from the coldkey's account + // 12. Remove the swap cost from the coldkey's account let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?; - // 14. Burn the tokens + // 13. Burn the tokens Self::burn_tokens(actual_burn_amount); - // 15. Perform the hotkey swap + // 14. Perform the hotkey swap let _ = Self::perform_hotkey_swap(old_hotkey, new_hotkey, &coldkey, &mut weight); - // 16. Update the last transaction block for the coldkey + // 15. Update the last transaction block for the coldkey Self::set_last_tx_block(&coldkey, block); weight.saturating_accrue(T::DbWeight::get().writes(1)); - // 17. Emit an event for the hotkey swap + // 16. Emit an event for the hotkey swap Self::deposit_event(Event::HotkeySwapped { coldkey, old_hotkey: old_hotkey.clone(), new_hotkey: new_hotkey.clone(), }); - // 18. Return the weight of the operation + // 17. Return the weight of the operation Ok(Some(weight).into()) } diff --git a/pallets/subtensor/tests/migration.rs b/pallets/subtensor/tests/migration.rs index 23ceea539f..bcbfa55456 100644 --- a/pallets/subtensor/tests/migration.rs +++ b/pallets/subtensor/tests/migration.rs @@ -355,6 +355,7 @@ fn test_migrate_fix_total_coldkey_stake_one_hotkey_stake_missing() { } // New test to check if migration runs only once +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test migration -- test_migrate_fix_total_coldkey_stake_runs_once --exact --nocapture #[test] fn test_migrate_fix_total_coldkey_stake_runs_once() { new_test_ext(1).execute_with(|| { @@ -362,9 +363,9 @@ fn test_migrate_fix_total_coldkey_stake_runs_once() { let coldkey = U256::from(0); TotalColdkeyStake::::insert(coldkey, 0); StakingHotkeys::::insert(coldkey, vec![U256::from(1), U256::from(2), U256::from(3)]); - Stake::::insert(U256::from(1), U256::from(0), 10000); - Stake::::insert(U256::from(2), U256::from(0), 10000); - Stake::::insert(U256::from(3), U256::from(0), 10000); + Stake::::insert(U256::from(1), coldkey, 10000); + Stake::::insert(U256::from(2), coldkey, 10000); + Stake::::insert(U256::from(3), coldkey, 10000); // First run let first_weight = run_migration_and_check(migration_name); @@ -391,14 +392,13 @@ fn test_migrate_fix_total_coldkey_stake_starts_with_value_no_stake_map_entries() let weight = run_migration_and_check(migration_name); assert!(weight != Weight::zero()); // Therefore 0 - assert_eq!(TotalColdkeyStake::::get(coldkey), 0); + assert_eq!(TotalColdkeyStake::::get(coldkey), 123_456_789); }) } fn run_migration_and_check(migration_name: &'static str) -> frame_support::weights::Weight { // Execute the migration and store its weight - let weight: frame_support::weights::Weight = - pallet_subtensor::migration::migrate_fix_total_coldkey_stake::(); + let weight: frame_support::weights::Weight = pallet_subtensor::migrations::migrate_fix_total_coldkey_stake::migrate_fix_total_coldkey_stake::(); // Check if the migration has been marked as completed assert!(HasMigrationRun::::get( From bc19f08f50b720308533b15144b0063cd96d4c3f Mon Sep 17 00:00:00 2001 From: const Date: Tue, 23 Jul 2024 14:26:28 -0500 Subject: [PATCH 12/16] s --- pallets/subtensor/src/macros/config.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pallets/subtensor/src/macros/config.rs b/pallets/subtensor/src/macros/config.rs index aca0f1b302..e59eac5ca3 100644 --- a/pallets/subtensor/src/macros/config.rs +++ b/pallets/subtensor/src/macros/config.rs @@ -1,3 +1,5 @@ +#![allow(clippy::crate_in_macro_def)] + use frame_support::pallet_macros::pallet_section; /// A [`pallet_section`] that defines the errors for a pallet. From 28ba654d28ef2b6a3b7864bc314479c03b7c492c Mon Sep 17 00:00:00 2001 From: unconst Date: Tue, 23 Jul 2024 14:28:57 -0500 Subject: [PATCH 13/16] clippy --- pallets/subtensor/src/coinbase/run_coinbase.rs | 2 +- pallets/subtensor/src/lib.rs | 2 +- .../migrations/migrate_fix_total_coldkey_stake.rs | 2 +- pallets/subtensor/src/subnets/registration.rs | 6 +++++- pallets/subtensor/src/swap/swap_coldkey.rs | 4 ++-- pallets/subtensor/tests/coinbase.rs | 1 + pallets/subtensor/tests/migration.rs | 13 ++++++------- pallets/subtensor/tests/swap_coldkey.rs | 2 +- 8 files changed, 18 insertions(+), 14 deletions(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 0f747a89ea..f3fbf8e737 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -372,4 +372,4 @@ impl Pallet { let remainder = block_plus_netuid.rem_euclid(tempo_plus_one); (tempo as u64).saturating_sub(remainder) } -} \ No newline at end of file +} diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 29969a23b0..6c16902d91 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1073,7 +1073,7 @@ pub mod pallet { (H256, u64), OptionQuery, >; - + /// ================== /// ==== Genesis ===== /// ================== diff --git a/pallets/subtensor/src/migrations/migrate_fix_total_coldkey_stake.rs b/pallets/subtensor/src/migrations/migrate_fix_total_coldkey_stake.rs index 268c82d489..d8534d03ab 100644 --- a/pallets/subtensor/src/migrations/migrate_fix_total_coldkey_stake.rs +++ b/pallets/subtensor/src/migrations/migrate_fix_total_coldkey_stake.rs @@ -1,11 +1,11 @@ use super::*; +use alloc::string::String; use frame_support::{ pallet_prelude::{Identity, OptionQuery}, storage_alias, traits::{Get, StorageVersion}, weights::Weight, }; -use alloc::string::String; use sp_std::vec::Vec; // TODO (camfairchild): TEST MIGRATION diff --git a/pallets/subtensor/src/subnets/registration.rs b/pallets/subtensor/src/subnets/registration.rs index ecff0fd992..9319adcd1f 100644 --- a/pallets/subtensor/src/subnets/registration.rs +++ b/pallets/subtensor/src/subnets/registration.rs @@ -550,7 +550,11 @@ impl Pallet { // Copy the hotkey_bytes into the first half of full_bytes full_bytes[..32].copy_from_slice(hotkey_bytes); let keccak_256_seal_hash_vec: [u8; 32] = keccak_256(&full_bytes[..]); - let hash_u64: u64 = u64::from_le_bytes(keccak_256_seal_hash_vec[0..8].try_into().unwrap_or_default()); + let hash_u64: u64 = u64::from_le_bytes( + keccak_256_seal_hash_vec[0..8] + .try_into() + .unwrap_or_default(), + ); hash_u64 } diff --git a/pallets/subtensor/src/swap/swap_coldkey.rs b/pallets/subtensor/src/swap/swap_coldkey.rs index 507fc62a5e..bd8a11fa1e 100644 --- a/pallets/subtensor/src/swap/swap_coldkey.rs +++ b/pallets/subtensor/src/swap/swap_coldkey.rs @@ -1,6 +1,6 @@ use super::*; use frame_support::weights::Weight; -use sp_core::{Get}; +use sp_core::Get; impl Pallet { /// Swaps the coldkey associated with a set of hotkeys from an old coldkey to a new coldkey. @@ -225,4 +225,4 @@ impl Pallet { // Return ok. Ok(()) } -} \ No newline at end of file +} diff --git a/pallets/subtensor/tests/coinbase.rs b/pallets/subtensor/tests/coinbase.rs index aed3c9b555..8fd963dffd 100644 --- a/pallets/subtensor/tests/coinbase.rs +++ b/pallets/subtensor/tests/coinbase.rs @@ -1,3 +1,4 @@ +#![allow(unused, clippy::indexing_slicing, clippy::panic, clippy::unwrap_used)] use crate::mock::*; mod mock; // use frame_support::{assert_err, assert_ok}; diff --git a/pallets/subtensor/tests/migration.rs b/pallets/subtensor/tests/migration.rs index bcbfa55456..bd77c7be0b 100644 --- a/pallets/subtensor/tests/migration.rs +++ b/pallets/subtensor/tests/migration.rs @@ -1,5 +1,4 @@ -#![allow(clippy::unwrap_used)] - +#![allow(unused, clippy::indexing_slicing, clippy::panic, clippy::unwrap_used)] mod mock; use frame_support::{assert_ok, weights::Weight}; use frame_system::Config; @@ -283,7 +282,7 @@ fn test_migration_delete_subnet_21() { #[test] fn test_migrate_fix_total_coldkey_stake() { new_test_ext(1).execute_with(|| { - let migration_name = "fix_total_coldkey_stake_v7"; + let _migration_name = "fix_total_coldkey_stake_v7"; let coldkey = U256::from(0); TotalColdkeyStake::::insert(coldkey, 0); StakingHotkeys::::insert(coldkey, vec![U256::from(1), U256::from(2), U256::from(3)]); @@ -299,7 +298,7 @@ fn test_migrate_fix_total_coldkey_stake() { #[test] fn test_migrate_fix_total_coldkey_stake_value_already_in_total() { new_test_ext(1).execute_with(|| { - let migration_name = "fix_total_coldkey_stake_v7"; + let _migration_name = "fix_total_coldkey_stake_v7"; let coldkey = U256::from(0); TotalColdkeyStake::::insert(coldkey, 100000000); StakingHotkeys::::insert(coldkey, vec![U256::from(1), U256::from(2), U256::from(3)]); @@ -315,7 +314,7 @@ fn test_migrate_fix_total_coldkey_stake_value_already_in_total() { #[test] fn test_migrate_fix_total_coldkey_stake_no_entry() { new_test_ext(1).execute_with(|| { - let migration_name = "fix_total_coldkey_stake_v7"; + let _migration_name = "fix_total_coldkey_stake_v7"; let coldkey = U256::from(0); StakingHotkeys::::insert(coldkey, vec![U256::from(1), U256::from(2), U256::from(3)]); Stake::::insert(U256::from(1), U256::from(0), 10000); @@ -330,7 +329,7 @@ fn test_migrate_fix_total_coldkey_stake_no_entry() { #[test] fn test_migrate_fix_total_coldkey_stake_no_entry_in_hotkeys() { new_test_ext(1).execute_with(|| { - let migration_name = "fix_total_coldkey_stake_v7"; + let _migration_name = "fix_total_coldkey_stake_v7"; let coldkey = U256::from(0); TotalColdkeyStake::::insert(coldkey, 100000000); StakingHotkeys::::insert(coldkey, vec![U256::from(1), U256::from(2), U256::from(3)]); @@ -343,7 +342,7 @@ fn test_migrate_fix_total_coldkey_stake_no_entry_in_hotkeys() { #[test] fn test_migrate_fix_total_coldkey_stake_one_hotkey_stake_missing() { new_test_ext(1).execute_with(|| { - let migration_name = "fix_total_coldkey_stake_v7"; + let _migration_name = "fix_total_coldkey_stake_v7"; let coldkey = U256::from(0); TotalColdkeyStake::::insert(coldkey, 100000000); StakingHotkeys::::insert(coldkey, vec![U256::from(1), U256::from(2), U256::from(3)]); diff --git a/pallets/subtensor/tests/swap_coldkey.rs b/pallets/subtensor/tests/swap_coldkey.rs index df109f9922..9203e2b3f9 100644 --- a/pallets/subtensor/tests/swap_coldkey.rs +++ b/pallets/subtensor/tests/swap_coldkey.rs @@ -1285,4 +1285,4 @@ fn test_coldkey_delegations() { assert_eq!(Stake::::get(delegate, new_coldkey), 100); assert_eq!(Stake::::get(delegate, coldkey), 0); }); -} \ No newline at end of file +} From 4726ec3e9d39b9f5e7266a75e7fb51cb414c26d0 Mon Sep 17 00:00:00 2001 From: unconst Date: Tue, 23 Jul 2024 14:32:20 -0500 Subject: [PATCH 14/16] fix divide by zero --- pallets/subtensor/src/coinbase/run_coinbase.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index f3fbf8e737..df35304b1b 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -299,7 +299,8 @@ impl Pallet { // --- 10 Calculate this nominator's share of the emission. let nominator_emission: I64F64 = I64F64::from_num(emission_minus_take) .saturating_mul(I64F64::from_num(nominator_stake)) - .saturating_div(I64F64::from_num(total_hotkey_stake)); + .check_div(I64F64::from_num(total_hotkey_stake)) + .unwrap_or(I64F64::from_num(0)); // --- 11 Increase the stake for the nominator. Self::increase_stake_on_coldkey_hotkey_account( From e90fc16f688c43b2695e5c7e339557be52f16319 Mon Sep 17 00:00:00 2001 From: unconst Date: Tue, 23 Jul 2024 14:38:09 -0500 Subject: [PATCH 15/16] fix checked div error --- pallets/subtensor/src/coinbase/run_coinbase.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index df35304b1b..abe44d55a3 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -299,7 +299,7 @@ impl Pallet { // --- 10 Calculate this nominator's share of the emission. let nominator_emission: I64F64 = I64F64::from_num(emission_minus_take) .saturating_mul(I64F64::from_num(nominator_stake)) - .check_div(I64F64::from_num(total_hotkey_stake)) + .checked_div(I64F64::from_num(total_hotkey_stake)) .unwrap_or(I64F64::from_num(0)); // --- 11 Increase the stake for the nominator. From af50dd63462e7dc920f6c18d26140efb52d3e6ac Mon Sep 17 00:00:00 2001 From: unconst Date: Tue, 23 Jul 2024 16:23:24 -0500 Subject: [PATCH 16/16] adds a doublt Tempo limit to setting childkeys --- .../subtensor/src/coinbase/run_coinbase.rs | 66 ++++++++-------- pallets/subtensor/src/lib.rs | 12 +++ pallets/subtensor/src/macros/errors.rs | 2 + pallets/subtensor/src/staking/add_stake.rs | 4 +- pallets/subtensor/src/staking/set_children.rs | 9 +++ pallets/subtensor/src/utils.rs | 77 +++++++++++++++++++ 6 files changed, 137 insertions(+), 33 deletions(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index abe44d55a3..fcf76728f3 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -1,5 +1,4 @@ use super::*; -use frame_support::storage::IterableStorageDoubleMap; use substrate_fixed::types::I64F64; use substrate_fixed::types::I96F32; @@ -262,7 +261,7 @@ impl Pallet { PendingdHotkeyEmission::::insert(hotkey, 0); // --- 2 Retrieve the last time this hotkey's emissions were drained. - let last_hotkey_emission_drain: u64 = LastHotkeyEmissionDrain::::get(hotkey); + let last_emission_drain: u64 = LastHotkeyEmissionDrain::::get(hotkey); // --- 3 Update the block value to the current block number. LastHotkeyEmissionDrain::::insert(hotkey, block_number); @@ -282,43 +281,48 @@ impl Pallet { // --- 7 Calculate the remaining emission after the hotkey's take. let mut remainder: u64 = emission_minus_take; - // --- 8 Iterate over each nominator. - for (nominator, nominator_stake) in - as IterableStorageDoubleMap>::iter_prefix( - hotkey, - ) - { - // --- 9 Check if the stake was manually increased by the user since the last emission drain for this hotkey. - // If it was, skip this nominator as they will not receive their proportion of the emission. - if LastAddStakeIncrease::::get(hotkey, nominator.clone()) - > last_hotkey_emission_drain - { - continue; + // --- 8 Iterate over each nominator and get all viable stake. + let mut total_viable_nominator_stake: u64 = total_hotkey_stake; + for (nominator, nominator_stake) in Stake::::iter_prefix(hotkey) { + if LastAddStakeIncrease::::get(hotkey, nominator) > last_emission_drain { + total_viable_nominator_stake = + total_viable_nominator_stake.saturating_sub(nominator_stake); } + } - // --- 10 Calculate this nominator's share of the emission. - let nominator_emission: I64F64 = I64F64::from_num(emission_minus_take) - .saturating_mul(I64F64::from_num(nominator_stake)) - .checked_div(I64F64::from_num(total_hotkey_stake)) - .unwrap_or(I64F64::from_num(0)); - - // --- 11 Increase the stake for the nominator. - Self::increase_stake_on_coldkey_hotkey_account( - &nominator, - hotkey, - nominator_emission.to_num::(), - ); + // --- 9 Iterate over each nominator. + if total_viable_nominator_stake != 0 { + for (nominator, nominator_stake) in Stake::::iter_prefix(hotkey) { + // --- 10 Check if the stake was manually increased by the user since the last emission drain for this hotkey. + // If it was, skip this nominator as they will not receive their proportion of the emission. + if LastAddStakeIncrease::::get(hotkey, nominator.clone()) > last_emission_drain { + continue; + } - // --- 11* Record event and Subtract the nominator's emission from the remainder. - total_new_tao = total_new_tao.saturating_add(nominator_emission.to_num::()); - remainder = remainder.saturating_sub(nominator_emission.to_num::()); + // --- 11 Calculate this nominator's share of the emission. + let nominator_emission: I64F64 = I64F64::from_num(emission_minus_take) + .saturating_mul(I64F64::from_num(nominator_stake)) + .checked_div(I64F64::from_num(total_viable_nominator_stake)) + .unwrap_or(I64F64::from_num(0)); + + // --- 12 Increase the stake for the nominator. + Self::increase_stake_on_coldkey_hotkey_account( + &nominator, + hotkey, + nominator_emission.to_num::(), + ); + + // --- 13* Record event and Subtract the nominator's emission from the remainder. + total_new_tao = total_new_tao.saturating_add(nominator_emission.to_num::()); + remainder = remainder.saturating_sub(nominator_emission.to_num::()); + } } - // --- 13 Finally, add the stake to the hotkey itself, including its take and the remaining emission. + // --- 14 Finally, add the stake to the hotkey itself, including its take and the remaining emission. let hotkey_new_tao: u64 = hotkey_take.saturating_add(remainder); Self::increase_stake_on_hotkey_account(hotkey, hotkey_new_tao); - // --- 14 Record new tao creation event and return the amount created. + // --- 15 Record new tao creation event and return the amount created. total_new_tao = total_new_tao.saturating_add(hotkey_new_tao); total_new_tao } diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 6c16902d91..abf6a86136 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -44,6 +44,7 @@ pub mod staking; pub mod subnets; pub mod swap; pub mod utils; +use crate::utils::TransactionType; use macros::{config, dispatches, errors, events, genesis, hooks}; // apparently this is stabilized since rust 1.36 @@ -1051,6 +1052,17 @@ pub mod pallet { /// ================================= /// ==== Axon / Promo Endpoints ===== /// ================================= + #[pallet::storage] // --- NMAP ( hot, netuid, name ) --> last_block | Returns the last block of a transaction for a given key, netuid, and name. + pub type TransactionKeyLastBlock = StorageNMap< + _, + ( + NMapKey, // hot + NMapKey, // netuid + NMapKey, // extrinsic enum. + ), + u64, + ValueQuery, + >; #[pallet::storage] /// --- MAP ( key ) --> last_block pub type LastTxBlock = diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index 7e244834d0..156cbea560 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -166,5 +166,7 @@ mod errors { ProportionOverflow, /// Too many children MAX 5. TooManyChildren, + /// Default transaction rate limit exceeded. + TxRateLimitExceeded, } } diff --git a/pallets/subtensor/src/staking/add_stake.rs b/pallets/subtensor/src/staking/add_stake.rs index eb7762bec1..f62fd7cd2f 100644 --- a/pallets/subtensor/src/staking/add_stake.rs +++ b/pallets/subtensor/src/staking/add_stake.rs @@ -70,8 +70,8 @@ impl Pallet { Error::::StakeRateLimitExceeded ); - // If this is a nomination stake, check if total stake after adding will be above - // the minimum required stake. + // Set the last time the stake increased for nominator drain protection. + LastAddStakeIncrease::::insert(&hotkey, &coldkey, Self::get_current_block_as_u64()); // If coldkey is not owner of the hotkey, it's a nomination stake. if !Self::coldkey_owns_hotkey(&coldkey, &hotkey) { diff --git a/pallets/subtensor/src/staking/set_children.rs b/pallets/subtensor/src/staking/set_children.rs index 071764734a..f413db23f8 100644 --- a/pallets/subtensor/src/staking/set_children.rs +++ b/pallets/subtensor/src/staking/set_children.rs @@ -58,6 +58,15 @@ impl Pallet { children ); + // Ensure the hotkey passes the rate limit. + ensure!( + Self::passes_rate_limit_globally( + &TransactionType::SetChildren, // Set children. + &hotkey, // Specific to a hotkey. + ), + Error::::TxRateLimitExceeded + ); + // --- 2. Check that this delegation is not on the root network. Child hotkeys are not valid on root. ensure!( netuid != Self::get_root_netuid(), diff --git a/pallets/subtensor/src/utils.rs b/pallets/subtensor/src/utils.rs index 6f5dbeaffe..2cd49e198c 100644 --- a/pallets/subtensor/src/utils.rs +++ b/pallets/subtensor/src/utils.rs @@ -7,6 +7,33 @@ use sp_core::Get; use sp_core::U256; use substrate_fixed::types::I32F32; +/// Enum representing different types of transactions +#[derive(Copy, Clone)] +pub enum TransactionType { + SetChildren, + Unknown, +} + +/// Implement conversion from TransactionType to u16 +impl From for u16 { + fn from(tx_type: TransactionType) -> Self { + match tx_type { + TransactionType::SetChildren => 0, + TransactionType::Unknown => 1, + } + } +} + +/// Implement conversion from u16 to TransactionType +impl From for TransactionType { + fn from(value: u16) -> Self { + match value { + 0 => TransactionType::SetChildren, + _ => TransactionType::Unknown, + } + } +} + impl Pallet { pub fn ensure_subnet_owner_or_root( o: T::RuntimeOrigin, @@ -278,6 +305,56 @@ impl Pallet { // ======================== // ==== Rate Limiting ===== // ======================== + /// Get the rate limit for a specific transaction type + pub fn get_rate_limit(tx_type: &TransactionType) -> u64 { + match tx_type { + TransactionType::SetChildren => (DefaultTempo::::get().saturating_mul(2)).into(), // Cannot set children twice within the default tempo period. + TransactionType::Unknown => 0, // Default to no limit for unknown types (no limit) + } + } + + /// Check if a transaction should be rate limited on a specific subnet + pub fn passes_rate_limit_on_subnet( + tx_type: &TransactionType, + hotkey: &T::AccountId, + netuid: u16, + ) -> bool { + let block: u64 = Self::get_current_block_as_u64(); + let limit: u64 = Self::get_rate_limit(tx_type); + let last_block: u64 = Self::get_last_transaction_block(hotkey, netuid, tx_type); + block.saturating_sub(last_block) < limit + } + + /// Check if a transaction should be rate limited globally + pub fn passes_rate_limit_globally(tx_type: &TransactionType, hotkey: &T::AccountId) -> bool { + let netuid: u16 = u16::MAX; + let block: u64 = Self::get_current_block_as_u64(); + let limit: u64 = Self::get_rate_limit(tx_type); + let last_block: u64 = Self::get_last_transaction_block(hotkey, netuid, tx_type); + block.saturating_sub(last_block) >= limit + } + + /// Get the block number of the last transaction for a specific hotkey, network, and transaction type + pub fn get_last_transaction_block( + hotkey: &T::AccountId, + netuid: u16, + tx_type: &TransactionType, + ) -> u64 { + let tx_as_u16: u16 = (*tx_type).into(); + TransactionKeyLastBlock::::get((hotkey, netuid, tx_as_u16)) + } + + /// Set the block number of the last transaction for a specific hotkey, network, and transaction type + pub fn set_last_transaction_block( + hotkey: &T::AccountId, + netuid: u16, + tx_type: &TransactionType, + block: u64, + ) { + let tx_as_u16: u16 = (*tx_type).into(); + TransactionKeyLastBlock::::insert((hotkey, netuid, tx_as_u16), block); + } + pub fn set_last_tx_block(key: &T::AccountId, block: u64) { LastTxBlock::::insert(key, block) }