diff --git a/node/build.rs b/node/build.rs index e3bfe3116b..f9d839f9be 100644 --- a/node/build.rs +++ b/node/build.rs @@ -1,7 +1,7 @@ use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; fn main() { - generate_cargo_keys(); + generate_cargo_keys(); - rerun_if_git_head_changed(); + rerun_if_git_head_changed(); } diff --git a/node/src/main.rs b/node/src/main.rs index 1bd65e7a88..a79d48b1be 100644 --- a/node/src/main.rs +++ b/node/src/main.rs @@ -4,12 +4,12 @@ mod chain_spec; #[macro_use] mod service; +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; mod cli; mod command; mod rpc; -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking; fn main() -> sc_cli::Result<()> { - command::run() + command::run() } diff --git a/node/tests/chain_spec.rs b/node/tests/chain_spec.rs index 2f2a9480cc..611a8450d3 100644 --- a/node/tests/chain_spec.rs +++ b/node/tests/chain_spec.rs @@ -52,4 +52,3 @@ fn test_authority_keys_from_seed_panics() { let bad_seed = ""; authority_keys_from_seed(bad_seed); } - diff --git a/pallets/collective/src/lib.rs b/pallets/collective/src/lib.rs index 0bf34014b0..63cb96decf 100644 --- a/pallets/collective/src/lib.rs +++ b/pallets/collective/src/lib.rs @@ -48,16 +48,16 @@ use sp_runtime::{traits::Hash, RuntimeDebug}; use sp_std::{marker::PhantomData, prelude::*, result}; use frame_support::{ - codec::{Decode, Encode, MaxEncodedLen}, - dispatch::{ - DispatchError, DispatchResultWithPostInfo, Dispatchable, GetDispatchInfo, Pays, - PostDispatchInfo - }, - ensure, - traits::{ - Backing, ChangeMembers, EnsureOrigin, Get, GetBacking, InitializeMembers, StorageVersion, - }, - weights::{OldWeight, Weight}, + codec::{Decode, Encode, MaxEncodedLen}, + dispatch::{ + DispatchError, DispatchResultWithPostInfo, Dispatchable, GetDispatchInfo, Pays, + PostDispatchInfo, + }, + ensure, + traits::{ + Backing, ChangeMembers, EnsureOrigin, Get, GetBacking, InitializeMembers, StorageVersion, + }, + weights::{OldWeight, Weight}, }; #[cfg(test)] @@ -83,32 +83,32 @@ pub type MemberCount = u32; /// Default voting strategy when a member is inactive. pub trait DefaultVote { - /// Get the default voting strategy, given: - /// - /// - Whether the prime member voted Aye. - /// - Raw number of yes votes. - /// - Raw number of no votes. - /// - Total number of member count. - fn default_vote( - prime_vote: Option, - yes_votes: MemberCount, - no_votes: MemberCount, - len: MemberCount, - ) -> bool; + /// Get the default voting strategy, given: + /// + /// - Whether the prime member voted Aye. + /// - Raw number of yes votes. + /// - Raw number of no votes. + /// - Total number of member count. + fn default_vote( + prime_vote: Option, + yes_votes: MemberCount, + no_votes: MemberCount, + len: MemberCount, + ) -> bool; } /// Set the prime member's vote as the default vote. pub struct PrimeDefaultVote; impl DefaultVote for PrimeDefaultVote { - fn default_vote( - prime_vote: Option, - _yes_votes: MemberCount, - _no_votes: MemberCount, - _len: MemberCount, - ) -> bool { - prime_vote.unwrap_or(false) - } + fn default_vote( + prime_vote: Option, + _yes_votes: MemberCount, + _no_votes: MemberCount, + _len: MemberCount, + ) -> bool { + prime_vote.unwrap_or(false) + } } /// First see if yes vote are over majority of the whole collective. If so, set the default vote @@ -116,15 +116,15 @@ impl DefaultVote for PrimeDefaultVote { pub struct MoreThanMajorityThenPrimeDefaultVote; impl DefaultVote for MoreThanMajorityThenPrimeDefaultVote { - fn default_vote( - prime_vote: Option, - yes_votes: MemberCount, - _no_votes: MemberCount, - len: MemberCount, - ) -> bool { - let more_than_majority = yes_votes * 2 > len; - more_than_majority || prime_vote.unwrap_or(false) - } + fn default_vote( + prime_vote: Option, + yes_votes: MemberCount, + _no_votes: MemberCount, + len: MemberCount, + ) -> bool { + let more_than_majority = yes_votes * 2 > len; + more_than_majority || prime_vote.unwrap_or(false) + } } /// Origin for the collective module. @@ -132,255 +132,271 @@ impl DefaultVote for MoreThanMajorityThenPrimeDefaultVote { #[scale_info(skip_type_params(I))] #[codec(mel_bound(AccountId: MaxEncodedLen))] pub enum RawOrigin { - /// It has been condoned by a given number of members of the collective from a given total. - Members(MemberCount, MemberCount), - /// It has been condoned by a single member of the collective. - Member(AccountId), - /// Dummy to manage the fact we have instancing. - _Phantom(PhantomData), + /// It has been condoned by a given number of members of the collective from a given total. + Members(MemberCount, MemberCount), + /// It has been condoned by a single member of the collective. + Member(AccountId), + /// Dummy to manage the fact we have instancing. + _Phantom(PhantomData), } impl GetBacking for RawOrigin { - fn get_backing(&self) -> Option { - match self { - RawOrigin::Members(n, d) => Some(Backing { approvals: *n, eligible: *d }), - _ => None, - } - } + fn get_backing(&self) -> Option { + match self { + RawOrigin::Members(n, d) => Some(Backing { + approvals: *n, + eligible: *d, + }), + _ => None, + } + } } /// Info for keeping track of a motion being voted on. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct Votes { - /// The proposal's unique index. - index: ProposalIndex, - /// The number of approval votes that are needed to pass the motion. - threshold: MemberCount, - /// The current set of voters that approved it. - ayes: Vec, - /// The current set of voters that rejected it. - nays: Vec, - /// The hard end time of this vote. - end: BlockNumber, + /// The proposal's unique index. + index: ProposalIndex, + /// The number of approval votes that are needed to pass the motion. + threshold: MemberCount, + /// The current set of voters that approved it. + ayes: Vec, + /// The current set of voters that rejected it. + nays: Vec, + /// The hard end time of this vote. + end: BlockNumber, } #[frame_support::pallet] pub mod pallet { - use super::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - - /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - #[pallet::storage_version(STORAGE_VERSION)] - #[pallet::without_storage_info] - pub struct Pallet(PhantomData<(T, I)>); - - #[pallet::config] - pub trait Config: frame_system::Config { - /// The runtime origin type. - type RuntimeOrigin: From>; - - /// The runtime call dispatch type. - type Proposal: Parameter - + Dispatchable< - RuntimeOrigin = >::RuntimeOrigin, - PostInfo = PostDispatchInfo, - > + From> - + GetDispatchInfo; - - /// The runtime event type. - type RuntimeEvent: From> - + IsType<::RuntimeEvent>; - - /// The time-out for council motions. - type MotionDuration: Get; - - /// Maximum number of proposals allowed to be active in parallel. - type MaxProposals: Get; - - /// The maximum number of members supported by the pallet. Used for weight estimation. - /// - /// NOTE: - /// + Benchmarks will need to be re-run and weights adjusted if this changes. - /// + This pallet assumes that dependents keep to the limit without enforcing it. - type MaxMembers: Get; - - /// Default vote strategy of this collective. - type DefaultVote: DefaultVote; - - /// Weight information for extrinsics in this pallet. - type WeightInfo: WeightInfo; - - /// Origin allowed to set collective members - type SetMembersOrigin: EnsureOrigin<::RuntimeOrigin>; - - /// Origin allowed to propose - type CanPropose: CanPropose; - - /// Origin allowed to vote - type CanVote: CanVote; - - /// Members to expect in a vote - type GetVotingMembers: GetVotingMembers; - } - - #[pallet::genesis_config] - pub struct GenesisConfig, I: 'static = ()> { - pub phantom: PhantomData, - pub members: Vec, - } - - #[cfg(feature = "std")] - impl, I: 'static> Default for GenesisConfig { - fn default() -> Self { - Self { phantom: Default::default(), members: Default::default() } - } - } - - #[pallet::genesis_build] - impl, I: 'static> GenesisBuild for GenesisConfig { - fn build(&self) { - use sp_std::collections::btree_set::BTreeSet; - let members_set: BTreeSet<_> = self.members.iter().collect(); - assert_eq!( - members_set.len(), - self.members.len(), - "Members cannot contain duplicate accounts." - ); - - Pallet::::initialize_members(&self.members) - } - } - - /// Origin for the collective pallet. - #[pallet::origin] - pub type Origin = RawOrigin<::AccountId, I>; - - /// The hashes of the active proposals. - #[pallet::storage] - #[pallet::getter(fn proposals)] - pub type Proposals, I: 'static = ()> = - StorageValue<_, BoundedVec, ValueQuery>; - - /// Actual proposal for a given hash, if it's current. - #[pallet::storage] - #[pallet::getter(fn proposal_of)] - pub type ProposalOf, I: 'static = ()> = - StorageMap<_, Identity, T::Hash, >::Proposal, OptionQuery>; - - /// Votes on a given proposal, if it is ongoing. - #[pallet::storage] - #[pallet::getter(fn voting)] - pub type Voting, I: 'static = ()> = - StorageMap<_, Identity, T::Hash, Votes, OptionQuery>; - - /// Proposals so far. - #[pallet::storage] - #[pallet::getter(fn proposal_count)] - pub type ProposalCount, I: 'static = ()> = StorageValue<_, u32, ValueQuery>; - - /// The current members of the collective. This is stored sorted (just by value). - #[pallet::storage] - #[pallet::getter(fn members)] - pub type Members, I: 'static = ()> = - StorageValue<_, Vec, ValueQuery>; - - /// The prime member that helps determine the default vote behavior in case of absentations. - #[pallet::storage] - #[pallet::getter(fn prime)] - pub type Prime, I: 'static = ()> = StorageValue<_, T::AccountId, OptionQuery>; - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event, I: 'static = ()> { - /// A motion (given hash) has been proposed (by given account) with a threshold (given - /// `MemberCount`). - Proposed { - account: T::AccountId, - proposal_index: ProposalIndex, - proposal_hash: T::Hash, - threshold: MemberCount, - }, - /// A motion (given hash) has been voted on by given account, leaving - /// a tally (yes votes and no votes given respectively as `MemberCount`). - Voted { - account: T::AccountId, - proposal_hash: T::Hash, - voted: bool, - yes: MemberCount, - no: MemberCount, - }, - /// A motion was approved by the required threshold. - Approved { proposal_hash: T::Hash }, - /// A motion was not approved by the required threshold. - Disapproved { proposal_hash: T::Hash }, - /// A motion was executed; result will be `Ok` if it returned without error. - Executed { proposal_hash: T::Hash, result: DispatchResult }, - /// A single member did some action; result will be `Ok` if it returned without error. - MemberExecuted { proposal_hash: T::Hash, result: DispatchResult }, - /// A proposal was closed because its threshold was reached or after its duration was up. - Closed { proposal_hash: T::Hash, yes: MemberCount, no: MemberCount }, - } - - #[pallet::error] - pub enum Error { - /// Account is not a member - NotMember, - /// Duplicate proposals not allowed - DuplicateProposal, - /// Proposal must exist - ProposalMissing, - /// Mismatched index - WrongIndex, - /// Duplicate vote ignored - DuplicateVote, - /// Members are already initialized! - AlreadyInitialized, - /// The close call was made too early, before the end of the voting. - TooEarly, - /// There can only be a maximum of `MaxProposals` active proposals. - TooManyProposals, - /// The given weight bound for the proposal was too low. - WrongProposalWeight, - /// The given length bound for the proposal was too low. - WrongProposalLength, - /// The given motion duration for the proposal was too low. - WrongDuration, - } - - // Note that councillor operations are assigned to the operational class. - #[pallet::call] - impl, I: 'static> Pallet { - /// Set the collective's membership. - /// - /// - `new_members`: The new member list. Be nice to the chain and provide it sorted. - /// - `prime`: The prime member whose vote sets the default. - /// - `old_count`: The upper bound for the previous number of members in storage. Used for - /// weight estimation. - /// - /// The dispatch of this call must be `SetMembersOrigin`. - /// - /// NOTE: Does not enforce the expected `MaxMembers` limit on the amount of members, but - /// the weight estimations rely on it to estimate dispatchable weight. - /// - /// # WARNING: - /// - /// The `pallet-collective` can also be managed by logic outside of the pallet through the - /// implementation of the trait [`ChangeMembers`]. - /// Any call to `set_members` must be careful that the member set doesn't get out of sync - /// with other logic managing the member set. - /// - /// ## Complexity: - /// - `O(MP + N)` where: - /// - `M` old-members-count (code- and governance-bounded) - /// - `N` new-members-count (code- and governance-bounded) - /// - `P` proposals-count (code-bounded) - #[pallet::call_index(0)] - #[pallet::weight(( + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::storage_version(STORAGE_VERSION)] + #[pallet::without_storage_info] + pub struct Pallet(PhantomData<(T, I)>); + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The runtime origin type. + type RuntimeOrigin: From>; + + /// The runtime call dispatch type. + type Proposal: Parameter + + Dispatchable< + RuntimeOrigin = >::RuntimeOrigin, + PostInfo = PostDispatchInfo, + > + From> + + GetDispatchInfo; + + /// The runtime event type. + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + + /// The time-out for council motions. + type MotionDuration: Get; + + /// Maximum number of proposals allowed to be active in parallel. + type MaxProposals: Get; + + /// The maximum number of members supported by the pallet. Used for weight estimation. + /// + /// NOTE: + /// + Benchmarks will need to be re-run and weights adjusted if this changes. + /// + This pallet assumes that dependents keep to the limit without enforcing it. + type MaxMembers: Get; + + /// Default vote strategy of this collective. + type DefaultVote: DefaultVote; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + + /// Origin allowed to set collective members + type SetMembersOrigin: EnsureOrigin<::RuntimeOrigin>; + + /// Origin allowed to propose + type CanPropose: CanPropose; + + /// Origin allowed to vote + type CanVote: CanVote; + + /// Members to expect in a vote + type GetVotingMembers: GetVotingMembers; + } + + #[pallet::genesis_config] + pub struct GenesisConfig, I: 'static = ()> { + pub phantom: PhantomData, + pub members: Vec, + } + + #[cfg(feature = "std")] + impl, I: 'static> Default for GenesisConfig { + fn default() -> Self { + Self { + phantom: Default::default(), + members: Default::default(), + } + } + } + + #[pallet::genesis_build] + impl, I: 'static> GenesisBuild for GenesisConfig { + fn build(&self) { + use sp_std::collections::btree_set::BTreeSet; + let members_set: BTreeSet<_> = self.members.iter().collect(); + assert_eq!( + members_set.len(), + self.members.len(), + "Members cannot contain duplicate accounts." + ); + + Pallet::::initialize_members(&self.members) + } + } + + /// Origin for the collective pallet. + #[pallet::origin] + pub type Origin = RawOrigin<::AccountId, I>; + + /// The hashes of the active proposals. + #[pallet::storage] + #[pallet::getter(fn proposals)] + pub type Proposals, I: 'static = ()> = + StorageValue<_, BoundedVec, ValueQuery>; + + /// Actual proposal for a given hash, if it's current. + #[pallet::storage] + #[pallet::getter(fn proposal_of)] + pub type ProposalOf, I: 'static = ()> = + StorageMap<_, Identity, T::Hash, >::Proposal, OptionQuery>; + + /// Votes on a given proposal, if it is ongoing. + #[pallet::storage] + #[pallet::getter(fn voting)] + pub type Voting, I: 'static = ()> = + StorageMap<_, Identity, T::Hash, Votes, OptionQuery>; + + /// Proposals so far. + #[pallet::storage] + #[pallet::getter(fn proposal_count)] + pub type ProposalCount, I: 'static = ()> = StorageValue<_, u32, ValueQuery>; + + /// The current members of the collective. This is stored sorted (just by value). + #[pallet::storage] + #[pallet::getter(fn members)] + pub type Members, I: 'static = ()> = + StorageValue<_, Vec, ValueQuery>; + + /// The prime member that helps determine the default vote behavior in case of absentations. + #[pallet::storage] + #[pallet::getter(fn prime)] + pub type Prime, I: 'static = ()> = StorageValue<_, T::AccountId, OptionQuery>; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event, I: 'static = ()> { + /// A motion (given hash) has been proposed (by given account) with a threshold (given + /// `MemberCount`). + Proposed { + account: T::AccountId, + proposal_index: ProposalIndex, + proposal_hash: T::Hash, + threshold: MemberCount, + }, + /// A motion (given hash) has been voted on by given account, leaving + /// a tally (yes votes and no votes given respectively as `MemberCount`). + Voted { + account: T::AccountId, + proposal_hash: T::Hash, + voted: bool, + yes: MemberCount, + no: MemberCount, + }, + /// A motion was approved by the required threshold. + Approved { proposal_hash: T::Hash }, + /// A motion was not approved by the required threshold. + Disapproved { proposal_hash: T::Hash }, + /// A motion was executed; result will be `Ok` if it returned without error. + Executed { + proposal_hash: T::Hash, + result: DispatchResult, + }, + /// A single member did some action; result will be `Ok` if it returned without error. + MemberExecuted { + proposal_hash: T::Hash, + result: DispatchResult, + }, + /// A proposal was closed because its threshold was reached or after its duration was up. + Closed { + proposal_hash: T::Hash, + yes: MemberCount, + no: MemberCount, + }, + } + + #[pallet::error] + pub enum Error { + /// Account is not a member + NotMember, + /// Duplicate proposals not allowed + DuplicateProposal, + /// Proposal must exist + ProposalMissing, + /// Mismatched index + WrongIndex, + /// Duplicate vote ignored + DuplicateVote, + /// Members are already initialized! + AlreadyInitialized, + /// The close call was made too early, before the end of the voting. + TooEarly, + /// There can only be a maximum of `MaxProposals` active proposals. + TooManyProposals, + /// The given weight bound for the proposal was too low. + WrongProposalWeight, + /// The given length bound for the proposal was too low. + WrongProposalLength, + /// The given motion duration for the proposal was too low. + WrongDuration, + } + + // Note that councillor operations are assigned to the operational class. + #[pallet::call] + impl, I: 'static> Pallet { + /// Set the collective's membership. + /// + /// - `new_members`: The new member list. Be nice to the chain and provide it sorted. + /// - `prime`: The prime member whose vote sets the default. + /// - `old_count`: The upper bound for the previous number of members in storage. Used for + /// weight estimation. + /// + /// The dispatch of this call must be `SetMembersOrigin`. + /// + /// NOTE: Does not enforce the expected `MaxMembers` limit on the amount of members, but + /// the weight estimations rely on it to estimate dispatchable weight. + /// + /// # WARNING: + /// + /// The `pallet-collective` can also be managed by logic outside of the pallet through the + /// implementation of the trait [`ChangeMembers`]. + /// Any call to `set_members` must be careful that the member set doesn't get out of sync + /// with other logic managing the member set. + /// + /// ## Complexity: + /// - `O(MP + N)` where: + /// - `M` old-members-count (code- and governance-bounded) + /// - `N` new-members-count (code- and governance-bounded) + /// - `P` proposals-count (code-bounded) + #[pallet::call_index(0)] + #[pallet::weight(( T::WeightInfo::set_members( *old_count, // M new_members.len() as u32, // N @@ -388,107 +404,110 @@ pub mod pallet { ), DispatchClass::Operational ))] - pub fn set_members( - origin: OriginFor, - new_members: Vec, - prime: Option, - old_count: MemberCount, - ) -> DispatchResultWithPostInfo { - T::SetMembersOrigin::ensure_origin(origin)?; - if new_members.len() > T::MaxMembers::get() as usize { - log::error!( - target: LOG_TARGET, - "New members count ({}) exceeds maximum amount of members expected ({}).", - new_members.len(), - T::MaxMembers::get(), - ); - } - - let old = Members::::get(); - if old.len() > old_count as usize { - log::warn!( - target: LOG_TARGET, - "Wrong count used to estimate set_members weight. expected ({}) vs actual ({})", - old_count, - old.len(), - ); - } - let mut new_members = new_members; - new_members.sort(); - >::set_members_sorted(&new_members, &old); - Prime::::set(prime); - - Ok(Some(T::WeightInfo::set_members( - old.len() as u32, // M - new_members.len() as u32, // N - T::MaxProposals::get(), // P - )) - .into()) - } - - /// Dispatch a proposal from a member using the `Member` origin. - /// - /// Origin must be a member of the collective. - /// - /// ## Complexity: - /// - `O(B + M + P)` where: - /// - `B` is `proposal` size in bytes (length-fee-bounded) - /// - `M` members-count (code-bounded) - /// - `P` complexity of dispatching `proposal` - #[pallet::call_index(1)] - #[pallet::weight(( + pub fn set_members( + origin: OriginFor, + new_members: Vec, + prime: Option, + old_count: MemberCount, + ) -> DispatchResultWithPostInfo { + T::SetMembersOrigin::ensure_origin(origin)?; + if new_members.len() > T::MaxMembers::get() as usize { + log::error!( + target: LOG_TARGET, + "New members count ({}) exceeds maximum amount of members expected ({}).", + new_members.len(), + T::MaxMembers::get(), + ); + } + + let old = Members::::get(); + if old.len() > old_count as usize { + log::warn!( + target: LOG_TARGET, + "Wrong count used to estimate set_members weight. expected ({}) vs actual ({})", + old_count, + old.len(), + ); + } + let mut new_members = new_members; + new_members.sort(); + >::set_members_sorted(&new_members, &old); + Prime::::set(prime); + + Ok(Some(T::WeightInfo::set_members( + old.len() as u32, // M + new_members.len() as u32, // N + T::MaxProposals::get(), // P + )) + .into()) + } + + /// Dispatch a proposal from a member using the `Member` origin. + /// + /// Origin must be a member of the collective. + /// + /// ## Complexity: + /// - `O(B + M + P)` where: + /// - `B` is `proposal` size in bytes (length-fee-bounded) + /// - `M` members-count (code-bounded) + /// - `P` complexity of dispatching `proposal` + #[pallet::call_index(1)] + #[pallet::weight(( T::WeightInfo::execute( *length_bound, // B T::MaxMembers::get(), // M ).saturating_add(proposal.get_dispatch_info().weight), // P DispatchClass::Operational ))] - pub fn execute( - origin: OriginFor, - proposal: Box<>::Proposal>, - #[pallet::compact] length_bound: u32, - ) -> DispatchResultWithPostInfo { - let who = ensure_signed(origin)?; - let members = Self::members(); - ensure!(members.contains(&who), Error::::NotMember); - - let proposal_len = proposal.encoded_size(); - ensure!(proposal_len <= length_bound as usize, Error::::WrongProposalLength); - - let proposal_hash = T::Hashing::hash_of(&proposal); - let result = proposal.dispatch(RawOrigin::Member(who).into()); - Self::deposit_event(Event::MemberExecuted { - proposal_hash, - result: result.map(|_| ()).map_err(|e| e.error), - }); - - Ok(get_result_weight(result) - .map(|w| { - T::WeightInfo::execute( - proposal_len as u32, // B - members.len() as u32, // M - ) - .saturating_add(w) // P - }) - .into()) - } - - /// Add a new proposal to either be voted on or executed directly. - /// - /// Requires the sender to be member. - /// - /// `threshold` determines whether `proposal` is executed directly (`threshold < 2`) - /// or put up for voting. - /// - /// ## Complexity - /// - `O(B + M + P1)` or `O(B + M + P2)` where: - /// - `B` is `proposal` size in bytes (length-fee-bounded) - /// - `M` is members-count (code- and governance-bounded) - /// - branching is influenced by `threshold` where: - /// - `P1` is proposal execution complexity (`threshold < 2`) - /// - `P2` is proposals-count (code-bounded) (`threshold >= 2`) - #[pallet::call_index(2)] - #[pallet::weight(( + pub fn execute( + origin: OriginFor, + proposal: Box<>::Proposal>, + #[pallet::compact] length_bound: u32, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + let members = Self::members(); + ensure!(members.contains(&who), Error::::NotMember); + + let proposal_len = proposal.encoded_size(); + ensure!( + proposal_len <= length_bound as usize, + Error::::WrongProposalLength + ); + + let proposal_hash = T::Hashing::hash_of(&proposal); + let result = proposal.dispatch(RawOrigin::Member(who).into()); + Self::deposit_event(Event::MemberExecuted { + proposal_hash, + result: result.map(|_| ()).map_err(|e| e.error), + }); + + Ok(get_result_weight(result) + .map(|w| { + T::WeightInfo::execute( + proposal_len as u32, // B + members.len() as u32, // M + ) + .saturating_add(w) // P + }) + .into()) + } + + /// Add a new proposal to either be voted on or executed directly. + /// + /// Requires the sender to be member. + /// + /// `threshold` determines whether `proposal` is executed directly (`threshold < 2`) + /// or put up for voting. + /// + /// ## Complexity + /// - `O(B + M + P1)` or `O(B + M + P2)` where: + /// - `B` is `proposal` size in bytes (length-fee-bounded) + /// - `M` is members-count (code- and governance-bounded) + /// - branching is influenced by `threshold` where: + /// - `P1` is proposal execution complexity (`threshold < 2`) + /// - `P2` is proposals-count (code-bounded) (`threshold >= 2`) + #[pallet::call_index(2)] + #[pallet::weight(( T::WeightInfo::propose_proposed( *length_bound, // B T::MaxMembers::get(), // M @@ -496,88 +515,91 @@ pub mod pallet { ), DispatchClass::Operational ))] - pub fn propose( - origin: OriginFor, - proposal: Box<>::Proposal>, - #[pallet::compact] length_bound: u32, - duration: T::BlockNumber, - ) -> DispatchResultWithPostInfo { - let who = ensure_signed(origin.clone())?; - ensure!(T::CanPropose::can_propose(&who), Error::::NotMember); - - ensure!(duration >= T::MotionDuration::get(), Error::::WrongDuration); - - let threshold = (T::GetVotingMembers::get_count() / 2) + 1; - - let members = Self::members(); - let (proposal_len, active_proposals) = - Self::do_propose_proposed(who, threshold, proposal, length_bound, duration)?; - - Ok(Some(T::WeightInfo::propose_proposed( - proposal_len as u32, // B - members.len() as u32, // M - active_proposals, // P2 - )) - .into()) - } - - /// Add an aye or nay vote for the sender to the given proposal. - /// - /// Requires the sender to be a member. - /// - /// Transaction fees will be waived if the member is voting on any particular proposal - /// for the first time and the call is successful. Subsequent vote changes will charge a - /// fee. - /// ## Complexity - /// - `O(M)` where `M` is members-count (code- and governance-bounded) - #[pallet::call_index(3)] - #[pallet::weight((T::WeightInfo::vote(T::MaxMembers::get()), DispatchClass::Operational))] - pub fn vote( - origin: OriginFor, - proposal: T::Hash, - #[pallet::compact] index: ProposalIndex, - approve: bool, - ) -> DispatchResultWithPostInfo { - let who = ensure_signed(origin.clone())?; - ensure!(T::CanVote::can_vote(&who), Error::::NotMember); - - let members = Self::members(); - // Detects first vote of the member in the motion - let is_account_voting_first_time = Self::do_vote(who, proposal, index, approve)?; - - if is_account_voting_first_time { - Ok((Some(T::WeightInfo::vote(members.len() as u32)), Pays::No).into()) - } else { - Ok((Some(T::WeightInfo::vote(members.len() as u32)), Pays::Yes).into()) - } - } - - /// Close a vote that is either approved, disapproved or whose voting period has ended. - /// - /// May be called by any signed account in order to finish voting and close the proposal. - /// - /// If called before the end of the voting period it will only close the vote if it is - /// has enough votes to be approved or disapproved. - /// - /// If called after the end of the voting period abstentions are counted as rejections - /// unless there is a prime member set and the prime member cast an approval. - /// - /// If the close operation completes successfully with disapproval, the transaction fee will - /// be waived. Otherwise execution of the approved operation will be charged to the caller. - /// - /// + `proposal_weight_bound`: The maximum amount of weight consumed by executing the closed - /// proposal. - /// + `length_bound`: The upper bound for the length of the proposal in storage. Checked via - /// `storage::read` so it is `size_of::() == 4` larger than the pure length. - /// - /// ## Complexity - /// - `O(B + M + P1 + P2)` where: - /// - `B` is `proposal` size in bytes (length-fee-bounded) - /// - `M` is members-count (code- and governance-bounded) - /// - `P1` is the complexity of `proposal` preimage. - /// - `P2` is proposal-count (code-bounded) - #[pallet::call_index(4)] - #[pallet::weight(( + pub fn propose( + origin: OriginFor, + proposal: Box<>::Proposal>, + #[pallet::compact] length_bound: u32, + duration: T::BlockNumber, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin.clone())?; + ensure!(T::CanPropose::can_propose(&who), Error::::NotMember); + + ensure!( + duration >= T::MotionDuration::get(), + Error::::WrongDuration + ); + + let threshold = (T::GetVotingMembers::get_count() / 2) + 1; + + let members = Self::members(); + let (proposal_len, active_proposals) = + Self::do_propose_proposed(who, threshold, proposal, length_bound, duration)?; + + Ok(Some(T::WeightInfo::propose_proposed( + proposal_len as u32, // B + members.len() as u32, // M + active_proposals, // P2 + )) + .into()) + } + + /// Add an aye or nay vote for the sender to the given proposal. + /// + /// Requires the sender to be a member. + /// + /// Transaction fees will be waived if the member is voting on any particular proposal + /// for the first time and the call is successful. Subsequent vote changes will charge a + /// fee. + /// ## Complexity + /// - `O(M)` where `M` is members-count (code- and governance-bounded) + #[pallet::call_index(3)] + #[pallet::weight((T::WeightInfo::vote(T::MaxMembers::get()), DispatchClass::Operational))] + pub fn vote( + origin: OriginFor, + proposal: T::Hash, + #[pallet::compact] index: ProposalIndex, + approve: bool, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin.clone())?; + ensure!(T::CanVote::can_vote(&who), Error::::NotMember); + + let members = Self::members(); + // Detects first vote of the member in the motion + let is_account_voting_first_time = Self::do_vote(who, proposal, index, approve)?; + + if is_account_voting_first_time { + Ok((Some(T::WeightInfo::vote(members.len() as u32)), Pays::No).into()) + } else { + Ok((Some(T::WeightInfo::vote(members.len() as u32)), Pays::Yes).into()) + } + } + + /// Close a vote that is either approved, disapproved or whose voting period has ended. + /// + /// May be called by any signed account in order to finish voting and close the proposal. + /// + /// If called before the end of the voting period it will only close the vote if it is + /// has enough votes to be approved or disapproved. + /// + /// If called after the end of the voting period abstentions are counted as rejections + /// unless there is a prime member set and the prime member cast an approval. + /// + /// If the close operation completes successfully with disapproval, the transaction fee will + /// be waived. Otherwise execution of the approved operation will be charged to the caller. + /// + /// + `proposal_weight_bound`: The maximum amount of weight consumed by executing the closed + /// proposal. + /// + `length_bound`: The upper bound for the length of the proposal in storage. Checked via + /// `storage::read` so it is `size_of::() == 4` larger than the pure length. + /// + /// ## Complexity + /// - `O(B + M + P1 + P2)` where: + /// - `B` is `proposal` size in bytes (length-fee-bounded) + /// - `M` is members-count (code- and governance-bounded) + /// - `P1` is the complexity of `proposal` preimage. + /// - `P2` is proposal-count (code-bounded) + #[pallet::call_index(4)] + #[pallet::weight(( { let b = *length_bound; let m = T::MaxMembers::get(); @@ -591,68 +613,68 @@ pub mod pallet { }, DispatchClass::Operational ))] - #[allow(deprecated)] - #[deprecated(note = "1D weight is used in this extrinsic, please migrate to `close`")] - pub fn close_old_weight( - origin: OriginFor, - proposal_hash: T::Hash, - #[pallet::compact] index: ProposalIndex, - #[pallet::compact] proposal_weight_bound: OldWeight, - #[pallet::compact] length_bound: u32, - ) -> DispatchResultWithPostInfo { - let proposal_weight_bound: Weight = proposal_weight_bound.into(); - let _ = ensure_signed(origin)?; - - Self::do_close(proposal_hash, index, proposal_weight_bound, length_bound) - } - - /// Disapprove a proposal, close, and remove it from the system, regardless of its current - /// state. - /// - /// Must be called by the Root origin. - /// - /// Parameters: - /// * `proposal_hash`: The hash of the proposal that should be disapproved. - /// - /// ## Complexity - /// O(P) where P is the number of max proposals - #[pallet::call_index(5)] - #[pallet::weight(T::WeightInfo::disapprove_proposal(T::MaxProposals::get()))] - pub fn disapprove_proposal( - origin: OriginFor, - proposal_hash: T::Hash, - ) -> DispatchResultWithPostInfo { - ensure_root(origin)?; - let proposal_count = Self::do_disapprove_proposal(proposal_hash); - Ok(Some(T::WeightInfo::disapprove_proposal(proposal_count)).into()) - } - - /// Close a vote that is either approved, disapproved or whose voting period has ended. - /// - /// May be called by any signed account in order to finish voting and close the proposal. - /// - /// If called before the end of the voting period it will only close the vote if it is - /// has enough votes to be approved or disapproved. - /// - /// If called after the end of the voting period abstentions are counted as rejections - /// unless there is a prime member set and the prime member cast an approval. - /// - /// If the close operation completes successfully with disapproval, the transaction fee will - /// be waived. Otherwise execution of the approved operation will be charged to the caller. - /// - /// + `proposal_weight_bound`: The maximum amount of weight consumed by executing the closed - /// proposal. - /// + `length_bound`: The upper bound for the length of the proposal in storage. Checked via - /// `storage::read` so it is `size_of::() == 4` larger than the pure length. - /// - /// ## Complexity - /// - `O(B + M + P1 + P2)` where: - /// - `B` is `proposal` size in bytes (length-fee-bounded) - /// - `M` is members-count (code- and governance-bounded) - /// - `P1` is the complexity of `proposal` preimage. - /// - `P2` is proposal-count (code-bounded) - #[pallet::call_index(6)] - #[pallet::weight(( + #[allow(deprecated)] + #[deprecated(note = "1D weight is used in this extrinsic, please migrate to `close`")] + pub fn close_old_weight( + origin: OriginFor, + proposal_hash: T::Hash, + #[pallet::compact] index: ProposalIndex, + #[pallet::compact] proposal_weight_bound: OldWeight, + #[pallet::compact] length_bound: u32, + ) -> DispatchResultWithPostInfo { + let proposal_weight_bound: Weight = proposal_weight_bound.into(); + let _ = ensure_signed(origin)?; + + Self::do_close(proposal_hash, index, proposal_weight_bound, length_bound) + } + + /// Disapprove a proposal, close, and remove it from the system, regardless of its current + /// state. + /// + /// Must be called by the Root origin. + /// + /// Parameters: + /// * `proposal_hash`: The hash of the proposal that should be disapproved. + /// + /// ## Complexity + /// O(P) where P is the number of max proposals + #[pallet::call_index(5)] + #[pallet::weight(T::WeightInfo::disapprove_proposal(T::MaxProposals::get()))] + pub fn disapprove_proposal( + origin: OriginFor, + proposal_hash: T::Hash, + ) -> DispatchResultWithPostInfo { + ensure_root(origin)?; + let proposal_count = Self::do_disapprove_proposal(proposal_hash); + Ok(Some(T::WeightInfo::disapprove_proposal(proposal_count)).into()) + } + + /// Close a vote that is either approved, disapproved or whose voting period has ended. + /// + /// May be called by any signed account in order to finish voting and close the proposal. + /// + /// If called before the end of the voting period it will only close the vote if it is + /// has enough votes to be approved or disapproved. + /// + /// If called after the end of the voting period abstentions are counted as rejections + /// unless there is a prime member set and the prime member cast an approval. + /// + /// If the close operation completes successfully with disapproval, the transaction fee will + /// be waived. Otherwise execution of the approved operation will be charged to the caller. + /// + /// + `proposal_weight_bound`: The maximum amount of weight consumed by executing the closed + /// proposal. + /// + `length_bound`: The upper bound for the length of the proposal in storage. Checked via + /// `storage::read` so it is `size_of::() == 4` larger than the pure length. + /// + /// ## Complexity + /// - `O(B + M + P1 + P2)` where: + /// - `B` is `proposal` size in bytes (length-fee-bounded) + /// - `M` is members-count (code- and governance-bounded) + /// - `P1` is the complexity of `proposal` preimage. + /// - `P2` is proposal-count (code-bounded) + #[pallet::call_index(6)] + #[pallet::weight(( { let b = *length_bound; let m = T::MaxMembers::get(); @@ -666,539 +688,596 @@ pub mod pallet { }, DispatchClass::Operational ))] - pub fn close( - origin: OriginFor, - proposal_hash: T::Hash, - #[pallet::compact] index: ProposalIndex, - proposal_weight_bound: Weight, - #[pallet::compact] length_bound: u32, - ) -> DispatchResultWithPostInfo { - let _ = ensure_signed(origin)?; - - Self::do_close(proposal_hash, index, proposal_weight_bound, length_bound) - } - } + pub fn close( + origin: OriginFor, + proposal_hash: T::Hash, + #[pallet::compact] index: ProposalIndex, + proposal_weight_bound: Weight, + #[pallet::compact] length_bound: u32, + ) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + + Self::do_close(proposal_hash, index, proposal_weight_bound, length_bound) + } + } } /// Return the weight of a dispatch call result as an `Option`. /// /// Will return the weight regardless of what the state of the result is. fn get_result_weight(result: DispatchResultWithPostInfo) -> Option { - match result { - Ok(post_info) => post_info.actual_weight, - Err(err) => err.post_info.actual_weight, - } + match result { + Ok(post_info) => post_info.actual_weight, + Err(err) => err.post_info.actual_weight, + } } impl, I: 'static> Pallet { - /// Check whether `who` is a member of the collective. - pub fn is_member(who: &T::AccountId) -> bool { - // Note: The dispatchables *do not* use this to check membership so make sure - // to update those if this is changed. - Self::members().contains(who) - } - - /// Execute immediately when adding a new proposal. - pub fn do_propose_execute( - proposal: Box<>::Proposal>, - length_bound: MemberCount, - ) -> Result<(u32, DispatchResultWithPostInfo), DispatchError> { - let proposal_len = proposal.encoded_size(); - ensure!(proposal_len <= length_bound as usize, Error::::WrongProposalLength); - - let proposal_hash = T::Hashing::hash_of(&proposal); - ensure!(!>::contains_key(proposal_hash), Error::::DuplicateProposal); - - let seats = Self::members().len() as MemberCount; - let result = proposal.dispatch(RawOrigin::Members(1, seats).into()); - Self::deposit_event(Event::Executed { - proposal_hash, - result: result.map(|_| ()).map_err(|e| e.error), - }); - Ok((proposal_len as u32, result)) - } - - /// Add a new proposal to be voted. - pub fn do_propose_proposed( - who: T::AccountId, - threshold: MemberCount, - proposal: Box<>::Proposal>, - length_bound: MemberCount, - duration: T::BlockNumber, - ) -> Result<(u32, u32), DispatchError> { - let proposal_len = proposal.encoded_size(); - ensure!(proposal_len <= length_bound as usize, Error::::WrongProposalLength); - - let proposal_hash = T::Hashing::hash_of(&proposal); - ensure!(!>::contains_key(proposal_hash), Error::::DuplicateProposal); - - let active_proposals = - >::try_mutate(|proposals| -> Result { - proposals.try_push(proposal_hash).map_err(|_| Error::::TooManyProposals)?; - Ok(proposals.len()) - })?; - - let index = Self::proposal_count(); - >::mutate(|i| *i += 1); - >::insert(proposal_hash, proposal); - let votes = { - let end = frame_system::Pallet::::block_number() + duration; - Votes { index, threshold, ayes: vec![], nays: vec![], end } - }; - >::insert(proposal_hash, votes); - - Self::deposit_event(Event::Proposed { - account: who, - proposal_index: index, - proposal_hash, - threshold, - }); - Ok((proposal_len as u32, active_proposals as u32)) - } - - /// Add an aye or nay vote for the member to the given proposal, returns true if it's the first - /// vote of the member in the motion - pub fn do_vote( - who: T::AccountId, - proposal: T::Hash, - index: ProposalIndex, - approve: bool, - ) -> Result { - let mut voting = Self::voting(&proposal).ok_or(Error::::ProposalMissing)?; - ensure!(voting.index == index, Error::::WrongIndex); - - let position_yes = voting.ayes.iter().position(|a| a == &who); - let position_no = voting.nays.iter().position(|a| a == &who); - - // Detects first vote of the member in the motion - let is_account_voting_first_time = position_yes.is_none() && position_no.is_none(); - - if approve { - if position_yes.is_none() { - voting.ayes.push(who.clone()); - } else { - return Err(Error::::DuplicateVote.into()) - } - if let Some(pos) = position_no { - voting.nays.swap_remove(pos); - } - } else { - if position_no.is_none() { - voting.nays.push(who.clone()); - } else { - return Err(Error::::DuplicateVote.into()) - } - if let Some(pos) = position_yes { - voting.ayes.swap_remove(pos); - } - } - - let yes_votes = voting.ayes.len() as MemberCount; - let no_votes = voting.nays.len() as MemberCount; - Self::deposit_event(Event::Voted { - account: who, - proposal_hash: proposal, - voted: approve, - yes: yes_votes, - no: no_votes, - }); - - Voting::::insert(&proposal, voting); - - Ok(is_account_voting_first_time) - } - - /// Close a vote that is either approved, disapproved or whose voting period has ended. - pub fn do_close( - proposal_hash: T::Hash, - index: ProposalIndex, - proposal_weight_bound: Weight, - length_bound: u32, - ) -> DispatchResultWithPostInfo { - let voting = Self::voting(&proposal_hash).ok_or(Error::::ProposalMissing)?; - ensure!(voting.index == index, Error::::WrongIndex); - - let mut no_votes = voting.nays.len() as MemberCount; - let mut yes_votes = voting.ayes.len() as MemberCount; - let seats = T::GetVotingMembers::get_count() as MemberCount; - let approved = yes_votes >= voting.threshold; - let disapproved = seats.saturating_sub(no_votes) < voting.threshold; - // Allow (dis-)approving the proposal as soon as there are enough votes. - if approved { - let (proposal, len) = Self::validate_and_get_proposal( - &proposal_hash, - length_bound, - proposal_weight_bound, - )?; - Self::deposit_event(Event::Closed { proposal_hash, yes: yes_votes, no: no_votes }); - let (proposal_weight, proposal_count) = - Self::do_approve_proposal(seats, yes_votes, proposal_hash, proposal); - return Ok(( - Some( - T::WeightInfo::close_early_approved(len as u32, seats, proposal_count) - .saturating_add(proposal_weight), - ), - Pays::Yes, - ) - .into()) - } else if disapproved { - Self::deposit_event(Event::Closed { proposal_hash, yes: yes_votes, no: no_votes }); - let proposal_count = Self::do_disapprove_proposal(proposal_hash); - return Ok(( - Some(T::WeightInfo::close_early_disapproved(seats, proposal_count)), - Pays::No, - ) - .into()) - } - - // Only allow actual closing of the proposal after the voting period has ended. - ensure!(frame_system::Pallet::::block_number() >= voting.end, Error::::TooEarly); - - let prime_vote = Self::prime().map(|who| voting.ayes.iter().any(|a| a == &who)); - - // default voting strategy. - let default = T::DefaultVote::default_vote(prime_vote, yes_votes, no_votes, seats); - - let abstentions = seats - (yes_votes + no_votes); - match default { - true => yes_votes += abstentions, - false => no_votes += abstentions, - } - let approved = yes_votes >= voting.threshold; - - if approved { - let (proposal, len) = Self::validate_and_get_proposal( - &proposal_hash, - length_bound, - proposal_weight_bound, - )?; - Self::deposit_event(Event::Closed { proposal_hash, yes: yes_votes, no: no_votes }); - let (proposal_weight, proposal_count) = - Self::do_approve_proposal(seats, yes_votes, proposal_hash, proposal); - Ok(( - Some( - T::WeightInfo::close_approved(len as u32, seats, proposal_count) - .saturating_add(proposal_weight), - ), - Pays::Yes, - ) - .into()) - } else { - Self::deposit_event(Event::Closed { proposal_hash, yes: yes_votes, no: no_votes }); - let proposal_count = Self::do_disapprove_proposal(proposal_hash); - Ok((Some(T::WeightInfo::close_disapproved(seats, proposal_count)), Pays::No).into()) - } - } - - /// Ensure that the right proposal bounds were passed and get the proposal from storage. - /// - /// Checks the length in storage via `storage::read` which adds an extra `size_of::() == 4` - /// to the length. - fn validate_and_get_proposal( - hash: &T::Hash, - length_bound: u32, - weight_bound: Weight, - ) -> Result<(>::Proposal, usize), DispatchError> { - let key = ProposalOf::::hashed_key_for(hash); - // read the length of the proposal storage entry directly - let proposal_len = - storage::read(&key, &mut [0; 0], 0).ok_or(Error::::ProposalMissing)?; - ensure!(proposal_len <= length_bound, Error::::WrongProposalLength); - let proposal = ProposalOf::::get(hash).ok_or(Error::::ProposalMissing)?; - let proposal_weight = proposal.get_dispatch_info().weight; - ensure!(proposal_weight.all_lte(weight_bound), Error::::WrongProposalWeight); - Ok((proposal, proposal_len as usize)) - } - - /// Weight: - /// If `approved`: - /// - the weight of `proposal` preimage. - /// - two events deposited. - /// - two removals, one mutation. - /// - computation and i/o `O(P + L)` where: - /// - `P` is number of active proposals, - /// - `L` is the encoded length of `proposal` preimage. - /// - /// If not `approved`: - /// - one event deposited. - /// Two removals, one mutation. - /// Computation and i/o `O(P)` where: - /// - `P` is number of active proposals - fn do_approve_proposal( - seats: MemberCount, - yes_votes: MemberCount, - proposal_hash: T::Hash, - proposal: >::Proposal, - ) -> (Weight, u32) { - Self::deposit_event(Event::Approved { proposal_hash }); - - let dispatch_weight = proposal.get_dispatch_info().weight; - let origin = RawOrigin::Members(yes_votes, seats).into(); - let result = proposal.dispatch(origin); - Self::deposit_event(Event::Executed { - proposal_hash, - result: result.map(|_| ()).map_err(|e| e.error), - }); - // default to the dispatch info weight for safety - let proposal_weight = get_result_weight(result).unwrap_or(dispatch_weight); // P1 - - let proposal_count = Self::remove_proposal(proposal_hash); - (proposal_weight, proposal_count) - } - - /// Removes a proposal from the pallet, and deposit the `Disapproved` event. - pub fn do_disapprove_proposal(proposal_hash: T::Hash) -> u32 { - // disapproved - Self::deposit_event(Event::Disapproved { proposal_hash }); - Self::remove_proposal(proposal_hash) - } - - // Removes a proposal from the pallet, cleaning up votes and the vector of proposals. - fn remove_proposal(proposal_hash: T::Hash) -> u32 { - // remove proposal and vote - ProposalOf::::remove(&proposal_hash); - Voting::::remove(&proposal_hash); - let num_proposals = Proposals::::mutate(|proposals| { - proposals.retain(|h| h != &proposal_hash); - proposals.len() + 1 // calculate weight based on original length - }); - num_proposals as u32 - } - - pub fn remove_votes(who: &T::AccountId) -> Result { - for h in Self::proposals().into_iter() { - >::mutate(h, |v| { - if let Some(mut votes) = v.take() { - votes.ayes = votes - .ayes - .into_iter() - .filter(|i| i != who) - .collect(); - votes.nays = votes - .nays - .into_iter() - .filter(|i| i != who) - .collect(); - *v = Some(votes); - } - }); - } - - Ok(true) - } - - pub fn has_voted(proposal: T::Hash, index: ProposalIndex, who: &T::AccountId) -> Result { - let voting = Self::voting(&proposal).ok_or(Error::::ProposalMissing)?; - ensure!(voting.index == index, Error::::WrongIndex); - - let position_yes = voting.ayes.iter().position(|a| a == who); - let position_no = voting.nays.iter().position(|a| a == who); - - Ok(position_yes.is_some() || position_no.is_some()) - } + /// Check whether `who` is a member of the collective. + pub fn is_member(who: &T::AccountId) -> bool { + // Note: The dispatchables *do not* use this to check membership so make sure + // to update those if this is changed. + Self::members().contains(who) + } + + /// Execute immediately when adding a new proposal. + pub fn do_propose_execute( + proposal: Box<>::Proposal>, + length_bound: MemberCount, + ) -> Result<(u32, DispatchResultWithPostInfo), DispatchError> { + let proposal_len = proposal.encoded_size(); + ensure!( + proposal_len <= length_bound as usize, + Error::::WrongProposalLength + ); + + let proposal_hash = T::Hashing::hash_of(&proposal); + ensure!( + !>::contains_key(proposal_hash), + Error::::DuplicateProposal + ); + + let seats = Self::members().len() as MemberCount; + let result = proposal.dispatch(RawOrigin::Members(1, seats).into()); + Self::deposit_event(Event::Executed { + proposal_hash, + result: result.map(|_| ()).map_err(|e| e.error), + }); + Ok((proposal_len as u32, result)) + } + + /// Add a new proposal to be voted. + pub fn do_propose_proposed( + who: T::AccountId, + threshold: MemberCount, + proposal: Box<>::Proposal>, + length_bound: MemberCount, + duration: T::BlockNumber, + ) -> Result<(u32, u32), DispatchError> { + let proposal_len = proposal.encoded_size(); + ensure!( + proposal_len <= length_bound as usize, + Error::::WrongProposalLength + ); + + let proposal_hash = T::Hashing::hash_of(&proposal); + ensure!( + !>::contains_key(proposal_hash), + Error::::DuplicateProposal + ); + + let active_proposals = + >::try_mutate(|proposals| -> Result { + proposals + .try_push(proposal_hash) + .map_err(|_| Error::::TooManyProposals)?; + Ok(proposals.len()) + })?; + + let index = Self::proposal_count(); + >::mutate(|i| *i += 1); + >::insert(proposal_hash, proposal); + let votes = { + let end = frame_system::Pallet::::block_number() + duration; + Votes { + index, + threshold, + ayes: vec![], + nays: vec![], + end, + } + }; + >::insert(proposal_hash, votes); + + Self::deposit_event(Event::Proposed { + account: who, + proposal_index: index, + proposal_hash, + threshold, + }); + Ok((proposal_len as u32, active_proposals as u32)) + } + + /// Add an aye or nay vote for the member to the given proposal, returns true if it's the first + /// vote of the member in the motion + pub fn do_vote( + who: T::AccountId, + proposal: T::Hash, + index: ProposalIndex, + approve: bool, + ) -> Result { + let mut voting = Self::voting(&proposal).ok_or(Error::::ProposalMissing)?; + ensure!(voting.index == index, Error::::WrongIndex); + + let position_yes = voting.ayes.iter().position(|a| a == &who); + let position_no = voting.nays.iter().position(|a| a == &who); + + // Detects first vote of the member in the motion + let is_account_voting_first_time = position_yes.is_none() && position_no.is_none(); + + if approve { + if position_yes.is_none() { + voting.ayes.push(who.clone()); + } else { + return Err(Error::::DuplicateVote.into()); + } + if let Some(pos) = position_no { + voting.nays.swap_remove(pos); + } + } else { + if position_no.is_none() { + voting.nays.push(who.clone()); + } else { + return Err(Error::::DuplicateVote.into()); + } + if let Some(pos) = position_yes { + voting.ayes.swap_remove(pos); + } + } + + let yes_votes = voting.ayes.len() as MemberCount; + let no_votes = voting.nays.len() as MemberCount; + Self::deposit_event(Event::Voted { + account: who, + proposal_hash: proposal, + voted: approve, + yes: yes_votes, + no: no_votes, + }); + + Voting::::insert(&proposal, voting); + + Ok(is_account_voting_first_time) + } + + /// Close a vote that is either approved, disapproved or whose voting period has ended. + pub fn do_close( + proposal_hash: T::Hash, + index: ProposalIndex, + proposal_weight_bound: Weight, + length_bound: u32, + ) -> DispatchResultWithPostInfo { + let voting = Self::voting(&proposal_hash).ok_or(Error::::ProposalMissing)?; + ensure!(voting.index == index, Error::::WrongIndex); + + let mut no_votes = voting.nays.len() as MemberCount; + let mut yes_votes = voting.ayes.len() as MemberCount; + let seats = T::GetVotingMembers::get_count() as MemberCount; + let approved = yes_votes >= voting.threshold; + let disapproved = seats.saturating_sub(no_votes) < voting.threshold; + // Allow (dis-)approving the proposal as soon as there are enough votes. + if approved { + let (proposal, len) = Self::validate_and_get_proposal( + &proposal_hash, + length_bound, + proposal_weight_bound, + )?; + Self::deposit_event(Event::Closed { + proposal_hash, + yes: yes_votes, + no: no_votes, + }); + let (proposal_weight, proposal_count) = + Self::do_approve_proposal(seats, yes_votes, proposal_hash, proposal); + return Ok(( + Some( + T::WeightInfo::close_early_approved(len as u32, seats, proposal_count) + .saturating_add(proposal_weight), + ), + Pays::Yes, + ) + .into()); + } else if disapproved { + Self::deposit_event(Event::Closed { + proposal_hash, + yes: yes_votes, + no: no_votes, + }); + let proposal_count = Self::do_disapprove_proposal(proposal_hash); + return Ok(( + Some(T::WeightInfo::close_early_disapproved( + seats, + proposal_count, + )), + Pays::No, + ) + .into()); + } + + // Only allow actual closing of the proposal after the voting period has ended. + ensure!( + frame_system::Pallet::::block_number() >= voting.end, + Error::::TooEarly + ); + + let prime_vote = Self::prime().map(|who| voting.ayes.iter().any(|a| a == &who)); + + // default voting strategy. + let default = T::DefaultVote::default_vote(prime_vote, yes_votes, no_votes, seats); + + let abstentions = seats - (yes_votes + no_votes); + match default { + true => yes_votes += abstentions, + false => no_votes += abstentions, + } + let approved = yes_votes >= voting.threshold; + + if approved { + let (proposal, len) = Self::validate_and_get_proposal( + &proposal_hash, + length_bound, + proposal_weight_bound, + )?; + Self::deposit_event(Event::Closed { + proposal_hash, + yes: yes_votes, + no: no_votes, + }); + let (proposal_weight, proposal_count) = + Self::do_approve_proposal(seats, yes_votes, proposal_hash, proposal); + Ok(( + Some( + T::WeightInfo::close_approved(len as u32, seats, proposal_count) + .saturating_add(proposal_weight), + ), + Pays::Yes, + ) + .into()) + } else { + Self::deposit_event(Event::Closed { + proposal_hash, + yes: yes_votes, + no: no_votes, + }); + let proposal_count = Self::do_disapprove_proposal(proposal_hash); + Ok(( + Some(T::WeightInfo::close_disapproved(seats, proposal_count)), + Pays::No, + ) + .into()) + } + } + + /// Ensure that the right proposal bounds were passed and get the proposal from storage. + /// + /// Checks the length in storage via `storage::read` which adds an extra `size_of::() == 4` + /// to the length. + fn validate_and_get_proposal( + hash: &T::Hash, + length_bound: u32, + weight_bound: Weight, + ) -> Result<(>::Proposal, usize), DispatchError> { + let key = ProposalOf::::hashed_key_for(hash); + // read the length of the proposal storage entry directly + let proposal_len = + storage::read(&key, &mut [0; 0], 0).ok_or(Error::::ProposalMissing)?; + ensure!( + proposal_len <= length_bound, + Error::::WrongProposalLength + ); + let proposal = ProposalOf::::get(hash).ok_or(Error::::ProposalMissing)?; + let proposal_weight = proposal.get_dispatch_info().weight; + ensure!( + proposal_weight.all_lte(weight_bound), + Error::::WrongProposalWeight + ); + Ok((proposal, proposal_len as usize)) + } + + /// Weight: + /// If `approved`: + /// - the weight of `proposal` preimage. + /// - two events deposited. + /// - two removals, one mutation. + /// - computation and i/o `O(P + L)` where: + /// - `P` is number of active proposals, + /// - `L` is the encoded length of `proposal` preimage. + /// + /// If not `approved`: + /// - one event deposited. + /// Two removals, one mutation. + /// Computation and i/o `O(P)` where: + /// - `P` is number of active proposals + fn do_approve_proposal( + seats: MemberCount, + yes_votes: MemberCount, + proposal_hash: T::Hash, + proposal: >::Proposal, + ) -> (Weight, u32) { + Self::deposit_event(Event::Approved { proposal_hash }); + + let dispatch_weight = proposal.get_dispatch_info().weight; + let origin = RawOrigin::Members(yes_votes, seats).into(); + let result = proposal.dispatch(origin); + Self::deposit_event(Event::Executed { + proposal_hash, + result: result.map(|_| ()).map_err(|e| e.error), + }); + // default to the dispatch info weight for safety + let proposal_weight = get_result_weight(result).unwrap_or(dispatch_weight); // P1 + + let proposal_count = Self::remove_proposal(proposal_hash); + (proposal_weight, proposal_count) + } + + /// Removes a proposal from the pallet, and deposit the `Disapproved` event. + pub fn do_disapprove_proposal(proposal_hash: T::Hash) -> u32 { + // disapproved + Self::deposit_event(Event::Disapproved { proposal_hash }); + Self::remove_proposal(proposal_hash) + } + + // Removes a proposal from the pallet, cleaning up votes and the vector of proposals. + fn remove_proposal(proposal_hash: T::Hash) -> u32 { + // remove proposal and vote + ProposalOf::::remove(&proposal_hash); + Voting::::remove(&proposal_hash); + let num_proposals = Proposals::::mutate(|proposals| { + proposals.retain(|h| h != &proposal_hash); + proposals.len() + 1 // calculate weight based on original length + }); + num_proposals as u32 + } + + pub fn remove_votes(who: &T::AccountId) -> Result { + for h in Self::proposals().into_iter() { + >::mutate(h, |v| { + if let Some(mut votes) = v.take() { + votes.ayes = votes.ayes.into_iter().filter(|i| i != who).collect(); + votes.nays = votes.nays.into_iter().filter(|i| i != who).collect(); + *v = Some(votes); + } + }); + } + + Ok(true) + } + + pub fn has_voted( + proposal: T::Hash, + index: ProposalIndex, + who: &T::AccountId, + ) -> Result { + let voting = Self::voting(&proposal).ok_or(Error::::ProposalMissing)?; + ensure!(voting.index == index, Error::::WrongIndex); + + let position_yes = voting.ayes.iter().position(|a| a == who); + let position_no = voting.nays.iter().position(|a| a == who); + + Ok(position_yes.is_some() || position_no.is_some()) + } } impl, I: 'static> ChangeMembers for Pallet { - /// Update the members of the collective. Votes are updated and the prime is reset. - /// - /// NOTE: Does not enforce the expected `MaxMembers` limit on the amount of members, but - /// the weight estimations rely on it to estimate dispatchable weight. - /// - /// ## Complexity - /// - `O(MP + N)` - /// - where `M` old-members-count (governance-bounded) - /// - where `N` new-members-count (governance-bounded) - /// - where `P` proposals-count - fn change_members_sorted( - _incoming: &[T::AccountId], - outgoing: &[T::AccountId], - new: &[T::AccountId], - ) { - if new.len() > T::MaxMembers::get() as usize { - log::error!( - target: LOG_TARGET, - "New members count ({}) exceeds maximum amount of members expected ({}).", - new.len(), - T::MaxMembers::get(), - ); - } - // remove accounts from all current voting in motions. - let mut outgoing = outgoing.to_vec(); - outgoing.sort(); - for h in Self::proposals().into_iter() { - >::mutate(h, |v| { - if let Some(mut votes) = v.take() { - votes.ayes = votes - .ayes - .into_iter() - .filter(|i| outgoing.binary_search(i).is_err()) - .collect(); - votes.nays = votes - .nays - .into_iter() - .filter(|i| outgoing.binary_search(i).is_err()) - .collect(); - *v = Some(votes); - } - }); - } - Members::::put(new); - Prime::::kill(); - } - - fn set_prime(prime: Option) { - Prime::::set(prime); - } - - fn get_prime() -> Option { - Prime::::get() - } + /// Update the members of the collective. Votes are updated and the prime is reset. + /// + /// NOTE: Does not enforce the expected `MaxMembers` limit on the amount of members, but + /// the weight estimations rely on it to estimate dispatchable weight. + /// + /// ## Complexity + /// - `O(MP + N)` + /// - where `M` old-members-count (governance-bounded) + /// - where `N` new-members-count (governance-bounded) + /// - where `P` proposals-count + fn change_members_sorted( + _incoming: &[T::AccountId], + outgoing: &[T::AccountId], + new: &[T::AccountId], + ) { + if new.len() > T::MaxMembers::get() as usize { + log::error!( + target: LOG_TARGET, + "New members count ({}) exceeds maximum amount of members expected ({}).", + new.len(), + T::MaxMembers::get(), + ); + } + // remove accounts from all current voting in motions. + let mut outgoing = outgoing.to_vec(); + outgoing.sort(); + for h in Self::proposals().into_iter() { + >::mutate(h, |v| { + if let Some(mut votes) = v.take() { + votes.ayes = votes + .ayes + .into_iter() + .filter(|i| outgoing.binary_search(i).is_err()) + .collect(); + votes.nays = votes + .nays + .into_iter() + .filter(|i| outgoing.binary_search(i).is_err()) + .collect(); + *v = Some(votes); + } + }); + } + Members::::put(new); + Prime::::kill(); + } + + fn set_prime(prime: Option) { + Prime::::set(prime); + } + + fn get_prime() -> Option { + Prime::::get() + } } impl, I: 'static> InitializeMembers for Pallet { - fn initialize_members(members: &[T::AccountId]) { - if !members.is_empty() { - assert!(>::get().is_empty(), "Members are already initialized!"); - >::put(members); - } - } + fn initialize_members(members: &[T::AccountId]) { + if !members.is_empty() { + assert!( + >::get().is_empty(), + "Members are already initialized!" + ); + >::put(members); + } + } } /// Ensure that the origin `o` represents at least `n` members. Returns `Ok` or an `Err` /// otherwise. pub fn ensure_members( - o: OuterOrigin, - n: MemberCount, + o: OuterOrigin, + n: MemberCount, ) -> result::Result where - OuterOrigin: Into, OuterOrigin>>, + OuterOrigin: Into, OuterOrigin>>, { - match o.into() { - Ok(RawOrigin::Members(x, _)) if x >= n => Ok(n), - _ => Err("bad origin: expected to be a threshold number of members"), - } + match o.into() { + Ok(RawOrigin::Members(x, _)) if x >= n => Ok(n), + _ => Err("bad origin: expected to be a threshold number of members"), + } } pub struct EnsureMember(PhantomData<(AccountId, I)>); impl< - O: Into, O>> + From>, - I, - AccountId: Decode, - > EnsureOrigin for EnsureMember + O: Into, O>> + From>, + I, + AccountId: Decode, + > EnsureOrigin for EnsureMember { - type Success = AccountId; - fn try_origin(o: O) -> Result { - o.into().and_then(|o| match o { - RawOrigin::Member(id) => Ok(id), - r => Err(O::from(r)), - }) - } - - #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { - let zero_account_id = - AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) - .expect("infinite length input; no invalid inputs for type; qed"); - Ok(O::from(RawOrigin::Member(zero_account_id))) - } + type Success = AccountId; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + RawOrigin::Member(id) => Ok(id), + r => Err(O::from(r)), + }) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + let zero_account_id = + AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) + .expect("infinite length input; no invalid inputs for type; qed"); + Ok(O::from(RawOrigin::Member(zero_account_id))) + } } pub struct EnsureMembers(PhantomData<(AccountId, I)>); impl< - O: Into, O>> + From>, - AccountId, - I, - const N: u32, - > EnsureOrigin for EnsureMembers + O: Into, O>> + From>, + AccountId, + I, + const N: u32, + > EnsureOrigin for EnsureMembers { - type Success = (MemberCount, MemberCount); - fn try_origin(o: O) -> Result { - o.into().and_then(|o| match o { - RawOrigin::Members(n, m) if n >= N => Ok((n, m)), - r => Err(O::from(r)), - }) - } - - #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { - Ok(O::from(RawOrigin::Members(N, N))) - } + type Success = (MemberCount, MemberCount); + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + RawOrigin::Members(n, m) if n >= N => Ok((n, m)), + r => Err(O::from(r)), + }) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(O::from(RawOrigin::Members(N, N))) + } } pub struct EnsureProportionMoreThan( - PhantomData<(AccountId, I)>, + PhantomData<(AccountId, I)>, ); impl< - O: Into, O>> + From>, - AccountId, - I, - const N: u32, - const D: u32, - > EnsureOrigin for EnsureProportionMoreThan + O: Into, O>> + From>, + AccountId, + I, + const N: u32, + const D: u32, + > EnsureOrigin for EnsureProportionMoreThan { - type Success = (); - fn try_origin(o: O) -> Result { - o.into().and_then(|o| match o { - RawOrigin::Members(n, m) if n * D > N * m => Ok(()), - r => Err(O::from(r)), - }) - } - - #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { - Ok(O::from(RawOrigin::Members(1u32, 0u32))) - } + type Success = (); + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + RawOrigin::Members(n, m) if n * D > N * m => Ok(()), + r => Err(O::from(r)), + }) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(O::from(RawOrigin::Members(1u32, 0u32))) + } } pub struct EnsureProportionAtLeast( - PhantomData<(AccountId, I)>, + PhantomData<(AccountId, I)>, ); impl< - O: Into, O>> + From>, - AccountId, - I, - const N: u32, - const D: u32, - > EnsureOrigin for EnsureProportionAtLeast + O: Into, O>> + From>, + AccountId, + I, + const N: u32, + const D: u32, + > EnsureOrigin for EnsureProportionAtLeast { - type Success = (); - fn try_origin(o: O) -> Result { - o.into().and_then(|o| match o { - RawOrigin::Members(n, m) if n * D >= N * m => Ok(()), - r => Err(O::from(r)), - }) - } - - #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { - Ok(O::from(RawOrigin::Members(0u32, 0u32))) - } + type Success = (); + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + RawOrigin::Members(n, m) if n * D >= N * m => Ok(()), + r => Err(O::from(r)), + }) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(O::from(RawOrigin::Members(0u32, 0u32))) + } } /// CanPropose pub trait CanPropose { - /// Check whether or not the passed AccountId can propose a new motion - fn can_propose(account: &AccountId) -> bool; + /// Check whether or not the passed AccountId can propose a new motion + fn can_propose(account: &AccountId) -> bool; } impl CanPropose for () { - fn can_propose(_: &T) -> bool {false} + fn can_propose(_: &T) -> bool { + false + } } /// CanVote pub trait CanVote { - /// Check whether or not the passed AccountId can vote on a motion - fn can_vote(account: &AccountId) -> bool; + /// Check whether or not the passed AccountId can vote on a motion + fn can_vote(account: &AccountId) -> bool; } impl CanVote for () { - fn can_vote(_: &T) -> bool {false} + fn can_vote(_: &T) -> bool { + false + } } pub trait GetVotingMembers { - fn get_count() -> MemberCount; + fn get_count() -> MemberCount; } impl GetVotingMembers for () { - fn get_count() -> MemberCount {0} -} \ No newline at end of file + fn get_count() -> MemberCount { + 0 + } +} diff --git a/pallets/subtensor/rpc/src/lib.rs b/pallets/subtensor/rpc/src/lib.rs index 0c3eb75b7a..f636362c3e 100644 --- a/pallets/subtensor/rpc/src/lib.rs +++ b/pallets/subtensor/rpc/src/lib.rs @@ -1,17 +1,14 @@ //! RPC interface for the custom Subtensor rpc methods use jsonrpsee::{ - core::RpcResult, - proc_macros::rpc, - types::error::{CallError, ErrorObject}, + core::RpcResult, + proc_macros::rpc, + types::error::{CallError, ErrorObject}, }; use sp_blockchain::HeaderBackend; -use sp_runtime::{ - traits::{Block as BlockT} -}; +use sp_runtime::traits::Block as BlockT; use std::sync::Arc; - use sp_api::ProvideRuntimeApi; pub use subtensor_custom_rpc_runtime_api::DelegateInfoRuntimeApi; @@ -20,209 +17,223 @@ pub use subtensor_custom_rpc_runtime_api::SubnetInfoRuntimeApi; #[rpc(client, server)] pub trait SubtensorCustomApi { - #[method(name = "delegateInfo_getDelegates")] - fn get_delegates(&self, at: Option) -> RpcResult>; - #[method(name = "delegateInfo_getDelegate")] - fn get_delegate(&self, delegate_account_vec: Vec, at: Option) -> RpcResult>; - #[method(name = "delegateInfo_getDelegated")] - fn get_delegated(&self, delegatee_account_vec: Vec, at: Option) -> RpcResult>; - - - #[method(name = "neuronInfo_getNeuronsLite")] - fn get_neurons_lite(&self, netuid: u16, at: Option) -> RpcResult>; - #[method(name = "neuronInfo_getNeuronLite")] - fn get_neuron_lite(&self, netuid: u16, uid: u16, at: Option) -> RpcResult>; - #[method(name = "neuronInfo_getNeurons")] - fn get_neurons(&self, netuid: u16, at: Option) -> RpcResult>; - #[method(name = "neuronInfo_getNeuron")] - fn get_neuron(&self, netuid: u16, uid: u16, at: Option) -> RpcResult>; - - #[method(name = "subnetInfo_getSubnetInfo")] - fn get_subnet_info(&self, netuid: u16, at: Option) -> RpcResult>; - #[method(name = "subnetInfo_getSubnetsInfo")] - fn get_subnets_info(&self, at: Option) -> RpcResult>; + #[method(name = "delegateInfo_getDelegates")] + fn get_delegates(&self, at: Option) -> RpcResult>; + #[method(name = "delegateInfo_getDelegate")] + fn get_delegate( + &self, + delegate_account_vec: Vec, + at: Option, + ) -> RpcResult>; + #[method(name = "delegateInfo_getDelegated")] + fn get_delegated( + &self, + delegatee_account_vec: Vec, + at: Option, + ) -> RpcResult>; + + #[method(name = "neuronInfo_getNeuronsLite")] + fn get_neurons_lite(&self, netuid: u16, at: Option) -> RpcResult>; + #[method(name = "neuronInfo_getNeuronLite")] + fn get_neuron_lite(&self, netuid: u16, uid: u16, at: Option) -> RpcResult>; + #[method(name = "neuronInfo_getNeurons")] + fn get_neurons(&self, netuid: u16, at: Option) -> RpcResult>; + #[method(name = "neuronInfo_getNeuron")] + fn get_neuron(&self, netuid: u16, uid: u16, at: Option) -> RpcResult>; + + #[method(name = "subnetInfo_getSubnetInfo")] + fn get_subnet_info(&self, netuid: u16, at: Option) -> RpcResult>; + #[method(name = "subnetInfo_getSubnetsInfo")] + fn get_subnets_info(&self, at: Option) -> RpcResult>; } pub struct SubtensorCustom { - /// Shared reference to the client. - client: Arc, - _marker: std::marker::PhantomData

, + /// Shared reference to the client. + client: Arc, + _marker: std::marker::PhantomData

, } impl SubtensorCustom { - /// Creates a new instance of the TransactionPayment Rpc helper. - pub fn new(client: Arc) -> Self { - Self { client, _marker: Default::default() } - } + /// Creates a new instance of the TransactionPayment Rpc helper. + pub fn new(client: Arc) -> Self { + Self { + client, + _marker: Default::default(), + } + } } /// Error type of this RPC api. pub enum Error { - /// The call to runtime failed. - RuntimeError, + /// The call to runtime failed. + RuntimeError, } impl From for i32 { - fn from(e: Error) -> i32 { - match e { - Error::RuntimeError => 1, - } - } + fn from(e: Error) -> i32 { + match e { + Error::RuntimeError => 1, + } + } } impl SubtensorCustomApiServer<::Hash> for SubtensorCustom where - Block: BlockT, - C: ProvideRuntimeApi + HeaderBackend + Send + Sync + 'static, - C::Api: DelegateInfoRuntimeApi, - C::Api: NeuronInfoRuntimeApi, - C::Api: SubnetInfoRuntimeApi, - { - fn get_delegates( - &self, - at: Option<::Hash> - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = at.unwrap_or_else(|| self.client.info().best_hash); - - api.get_delegates(at).map_err(|e| { - CallError::Custom(ErrorObject::owned( - Error::RuntimeError.into(), - "Unable to get delegates info.", - Some(e.to_string()), - )).into() - }) - } - - fn get_delegate( - &self, - delegate_account_vec: Vec, - at: Option<::Hash> - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = at.unwrap_or_else(|| self.client.info().best_hash); - - api.get_delegate(at, delegate_account_vec).map_err(|e| { - CallError::Custom(ErrorObject::owned( - Error::RuntimeError.into(), - "Unable to get delegate info.", - Some(e.to_string()), - )).into() - }) - } - - fn get_delegated( - &self, - delegatee_account_vec: Vec, - at: Option<::Hash> - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = at.unwrap_or_else(|| self.client.info().best_hash); - - api.get_delegated(at, delegatee_account_vec).map_err(|e| { - CallError::Custom(ErrorObject::owned( - Error::RuntimeError.into(), - "Unable to get delegated info.", - Some(e.to_string()), - )).into() - }) - } - - fn get_neurons_lite( - &self, - netuid: u16, - at: Option<::Hash> - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = at.unwrap_or_else(|| self.client.info().best_hash); - - api.get_neurons_lite(at, netuid).map_err(|e| { - CallError::Custom(ErrorObject::owned( - Error::RuntimeError.into(), - "Unable to get neurons lite info.", - Some(e.to_string()), - )).into() - }) - } - - fn get_neuron_lite( - &self, - netuid: u16, - uid: u16, - at: Option<::Hash> - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = at.unwrap_or_else(|| self.client.info().best_hash); - - api.get_neuron_lite(at, netuid, uid).map_err(|e| { - CallError::Custom(ErrorObject::owned( - Error::RuntimeError.into(), - "Unable to get neuron lite info.", - Some(e.to_string()), - )).into() - }) - } - - fn get_neurons( - &self, - netuid: u16, - at: Option<::Hash> - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = at.unwrap_or_else(|| self.client.info().best_hash); - - api.get_neurons(at, netuid).map_err(|e| { - CallError::Custom(ErrorObject::owned( - Error::RuntimeError.into(), - "Unable to get neurons info.", - Some(e.to_string()), - )).into() - }) - } - - fn get_neuron( - &self, - netuid: u16, - uid: u16, at: Option<::Hash> - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = at.unwrap_or_else(|| self.client.info().best_hash); - - api.get_neuron(at, netuid, uid).map_err(|e| { - CallError::Custom(ErrorObject::owned( - Error::RuntimeError.into(), - "Unable to get neuron info.", - Some(e.to_string()), - )).into() - }) - } - - fn get_subnet_info(&self, netuid: u16, at: Option<::Hash>) -> RpcResult> { - let api = self.client.runtime_api(); - let at = at.unwrap_or_else(|| self.client.info().best_hash); - - api.get_subnet_info(at, netuid).map_err(|e| { - CallError::Custom(ErrorObject::owned( - Error::RuntimeError.into(), - "Unable to get subnet info.", - Some(e.to_string()), - )).into() - }) - } - - fn get_subnets_info( - &self, - at: Option<::Hash> - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = at.unwrap_or_else(|| self.client.info().best_hash); - - api.get_subnets_info(at).map_err(|e| { - CallError::Custom(ErrorObject::owned( - Error::RuntimeError.into(), - "Unable to get subnets info.", - Some(e.to_string()), - )).into() - }) - } + Block: BlockT, + C: ProvideRuntimeApi + HeaderBackend + Send + Sync + 'static, + C::Api: DelegateInfoRuntimeApi, + C::Api: NeuronInfoRuntimeApi, + C::Api: SubnetInfoRuntimeApi, +{ + fn get_delegates(&self, at: Option<::Hash>) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_delegates(at).map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Unable to get delegates info.", + Some(e.to_string()), + )) + .into() + }) + } + + fn get_delegate( + &self, + delegate_account_vec: Vec, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_delegate(at, delegate_account_vec).map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Unable to get delegate info.", + Some(e.to_string()), + )) + .into() + }) + } + + fn get_delegated( + &self, + delegatee_account_vec: Vec, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_delegated(at, delegatee_account_vec).map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Unable to get delegated info.", + Some(e.to_string()), + )) + .into() + }) + } + + fn get_neurons_lite( + &self, + netuid: u16, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_neurons_lite(at, netuid).map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Unable to get neurons lite info.", + Some(e.to_string()), + )) + .into() + }) + } + + fn get_neuron_lite( + &self, + netuid: u16, + uid: u16, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_neuron_lite(at, netuid, uid).map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Unable to get neuron lite info.", + Some(e.to_string()), + )) + .into() + }) + } + + fn get_neurons(&self, netuid: u16, at: Option<::Hash>) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_neurons(at, netuid).map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Unable to get neurons info.", + Some(e.to_string()), + )) + .into() + }) + } + + fn get_neuron( + &self, + netuid: u16, + uid: u16, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_neuron(at, netuid, uid).map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Unable to get neuron info.", + Some(e.to_string()), + )) + .into() + }) + } + + fn get_subnet_info( + &self, + netuid: u16, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_subnet_info(at, netuid).map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Unable to get subnet info.", + Some(e.to_string()), + )) + .into() + }) + } + + fn get_subnets_info(&self, at: Option<::Hash>) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_subnets_info(at).map_err(|e| { + CallError::Custom(ErrorObject::owned( + Error::RuntimeError.into(), + "Unable to get subnets info.", + Some(e.to_string()), + )) + .into() + }) + } } diff --git a/pallets/subtensor/runtime-api/src/lib.rs b/pallets/subtensor/runtime-api/src/lib.rs index 5d356cd636..333f5c164f 100644 --- a/pallets/subtensor/runtime-api/src/lib.rs +++ b/pallets/subtensor/runtime-api/src/lib.rs @@ -5,21 +5,21 @@ use alloc::vec::Vec; // Here we declare the runtime API. It is implemented it the `impl` block in // src/neuron_info.rs, src/subnet_info.rs, and src/delegate_info.rs sp_api::decl_runtime_apis! { - pub trait DelegateInfoRuntimeApi { - fn get_delegates() -> Vec; - fn get_delegate( delegate_account_vec: Vec ) -> Vec; - fn get_delegated( delegatee_account_vec: Vec ) -> Vec; - } + pub trait DelegateInfoRuntimeApi { + fn get_delegates() -> Vec; + fn get_delegate( delegate_account_vec: Vec ) -> Vec; + fn get_delegated( delegatee_account_vec: Vec ) -> Vec; + } - pub trait NeuronInfoRuntimeApi { - fn get_neurons(netuid: u16) -> Vec; - fn get_neuron(netuid: u16, uid: u16) -> Vec; - fn get_neurons_lite(netuid: u16) -> Vec; - fn get_neuron_lite(netuid: u16, uid: u16) -> Vec; - } + pub trait NeuronInfoRuntimeApi { + fn get_neurons(netuid: u16) -> Vec; + fn get_neuron(netuid: u16, uid: u16) -> Vec; + fn get_neurons_lite(netuid: u16) -> Vec; + fn get_neuron_lite(netuid: u16, uid: u16) -> Vec; + } - pub trait SubnetInfoRuntimeApi { - fn get_subnet_info(netuid: u16) -> Vec; - fn get_subnets_info() -> Vec; - } -} \ No newline at end of file + pub trait SubnetInfoRuntimeApi { + fn get_subnet_info(netuid: u16) -> Vec; + fn get_subnets_info() -> Vec; + } +} diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 9d4a60e004..d614781605 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -5,43 +5,23 @@ // pub use pallet::*; -use frame_system::{ - self as system, - ensure_signed -}; +use frame_system::{self as system, ensure_signed}; use frame_support::{ - dispatch, - dispatch::{ - DispatchInfo, - PostDispatchInfo, - DispatchResult, - DispatchError - }, ensure, - traits::{ - Currency, - ExistenceRequirement, - tokens::WithdrawReasons, - IsSubType, - } + dispatch, + dispatch::{DispatchError, DispatchInfo, DispatchResult, PostDispatchInfo}, + ensure, + traits::{tokens::WithdrawReasons, Currency, ExistenceRequirement, IsSubType}, }; -use sp_std::marker::PhantomData; use codec::{Decode, Encode}; +use frame_support::sp_runtime::transaction_validity::ValidTransaction; +use scale_info::TypeInfo; use sp_runtime::{ - traits::{ - Dispatchable, - DispatchInfoOf, - SignedExtension, - PostDispatchInfoOf, - }, - transaction_validity::{ - TransactionValidity, - TransactionValidityError - } + traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension}, + transaction_validity::{TransactionValidity, TransactionValidityError}, }; -use scale_info::TypeInfo; -use frame_support::sp_runtime::transaction_validity::ValidTransaction; +use sp_std::marker::PhantomData; // ============================ // ==== Benchmark Imports ===== @@ -58,12 +38,12 @@ mod epoch; mod math; mod networks; mod registration; +mod senate; mod serving; mod staking; -mod utils; mod uids; +mod utils; mod weights; -mod senate; pub mod delegate_info; pub mod neuron_info; @@ -75,1629 +55,1998 @@ mod migration; #[frame_support::pallet] pub mod pallet { - use frame_support::{ - dispatch::GetDispatchInfo, - pallet_prelude::{*, StorageMap, DispatchResult} - }; - use frame_system::pallet_prelude::*; - use frame_support::traits::{Currency, UnfilteredDispatchable}; - use frame_support::sp_std::vec; - use frame_support::inherent::Vec; - - #[cfg(not(feature = "std"))] - use alloc::boxed::Box; - #[cfg(feature = "std")] - use sp_std::prelude::Box; - - // Tracks version for migrations. Should be monotonic with respect to the - // order of migrations. (i.e. always increasing) - const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] - #[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: Currency + Send + Sync; - - type SenateMembers: crate::MemberManagement; - - type TriumvirateInterface: crate::CollectiveInterface; - - // ================================= - // ==== Initial Value Constants ==== - // ================================= - #[pallet::constant] // Initial currency issuance. - type InitialIssuance: Get; - #[pallet::constant] // Initial min allowed weights setting. - type InitialMinAllowedWeights: Get; - #[pallet::constant] // Initial Emission Ratio. - type InitialEmissionValue: Get; - #[pallet::constant] // Initial max weight limit. - type InitialMaxWeightsLimit: Get; - #[pallet::constant] // Tempo for each network. - type InitialTempo: Get; - #[pallet::constant] // Initial Difficulty. - type InitialDifficulty: Get; - #[pallet::constant] // Initial Max Difficulty. - type InitialMaxDifficulty: Get; - #[pallet::constant] // Initial Min Difficulty. - type InitialMinDifficulty: Get; - #[pallet::constant] // Initial RAO Recycled. - type InitialRAORecycledForRegistration: Get; - #[pallet::constant] // Initial Burn. - type InitialBurn: Get; - #[pallet::constant] // Initial Max Burn. - type InitialMaxBurn: Get; - #[pallet::constant] // Initial Min Burn. - type InitialMinBurn: Get; - #[pallet::constant] // Initial adjustment interval. - type InitialAdjustmentInterval: Get; - #[pallet::constant] // Initial bonds moving average. - type InitialBondsMovingAverage: Get; - #[pallet::constant] // Initial target registrations per interval. - type InitialTargetRegistrationsPerInterval: Get; - #[pallet::constant] // Rho constant. - type InitialRho: Get; - #[pallet::constant] // Kappa constant. - type InitialKappa: Get; - #[pallet::constant] // Max UID constant. - type InitialMaxAllowedUids: Get; - #[pallet::constant] // Initial validator context pruning length. - type InitialValidatorPruneLen: Get; - #[pallet::constant] // Initial scaling law power. - type InitialScalingLawPower: Get; - #[pallet::constant] // Immunity Period Constant. - type InitialImmunityPeriod: Get; - #[pallet::constant] // Activity constant. - type InitialActivityCutoff: Get; - #[pallet::constant] // Initial max registrations per block. - type InitialMaxRegistrationsPerBlock: Get; - #[pallet::constant] // Initial pruning score for each neuron. - type InitialPruningScore: Get; - #[pallet::constant] // Initial maximum allowed validators per network. - type InitialMaxAllowedValidators: Get; - #[pallet::constant] // Initial default delegation take. - type InitialDefaultTake: Get; - #[pallet::constant] // Initial weights version key. - type InitialWeightsVersionKey: Get; - #[pallet::constant] // Initial serving rate limit. - type InitialServingRateLimit: Get; - #[pallet::constant] // Initial transaction rate limit. - type InitialTxRateLimit: Get; - #[pallet::constant] // Initial percentage of total stake required to join senate. - type InitialSenateRequiredStakePercentage: Get; - #[pallet::constant] // Initial adjustment alpha on burn and pow. - type InitialAdjustmentAlpha: Get; - } - - pub type AccountIdOf = ::AccountId; - - // Senate requirements - #[pallet::type_value] - pub fn DefaultSenateRequiredStakePercentage() -> u64 { T::InitialSenateRequiredStakePercentage::get() } - - #[pallet::storage] // --- ITEM ( tx_rate_limit ) - pub(super) type SenateRequiredStakePercentage = StorageValue<_, u64, ValueQuery, DefaultSenateRequiredStakePercentage>; - - // ============================ - // ==== Staking + Accounts ==== - // ============================ - #[pallet::type_value] - pub fn DefaultDefaultTake() -> u16 { T::InitialDefaultTake::get() } - #[pallet::type_value] - pub fn DefaultAccountTake() -> u64 { 0 } - #[pallet::type_value] - pub fn DefaultBlockEmission() -> u64 {1_000_000_000} - #[pallet::type_value] - pub fn DefaultAllowsDelegation() -> bool { false } - #[pallet::type_value] - pub fn DefaultTotalIssuance() -> u64 { T::InitialIssuance::get() } - #[pallet::type_value] - pub fn DefaultAccount() -> T::AccountId { T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).unwrap()} - - #[pallet::storage] // --- ITEM ( total_stake ) - pub type TotalStake = StorageValue<_, u64, ValueQuery>; - #[pallet::storage] // --- ITEM ( default_take ) - pub type DefaultTake = StorageValue<_, u16, ValueQuery, DefaultDefaultTake>; - #[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] // --- 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 | 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>; - - // ===================================== - // ==== Difficulty / Registrations ===== - // ===================================== - #[pallet::type_value] - pub fn DefaultLastAdjustmentBlock() -> u64 { 0 } - #[pallet::type_value] - pub fn DefaultRegistrationsThisBlock() -> u16 { 0} - #[pallet::type_value] - pub fn DefaultBurn() -> u64 { T::InitialBurn::get() } - #[pallet::type_value] - pub fn DefaultMinBurn() -> u64 { T::InitialMinBurn::get() } - #[pallet::type_value] - pub fn DefaultMaxBurn() -> u64 { T::InitialMaxBurn::get() } - #[pallet::type_value] - pub fn DefaultDifficulty() -> u64 { T::InitialDifficulty::get() } - #[pallet::type_value] - pub fn DefaultMinDifficulty() -> u64 { T::InitialMinDifficulty::get() } - #[pallet::type_value] - pub fn DefaultMaxDifficulty() -> u64 { T::InitialMaxDifficulty::get() } - #[pallet::type_value] - pub fn DefaultMaxRegistrationsPerBlock() -> u16 { T::InitialMaxRegistrationsPerBlock::get() } - #[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 ===== - // ============================== - #[pallet::type_value] - pub fn DefaultN() -> u16 { 0 } - #[pallet::type_value] - pub fn DefaultModality() -> u16 { 0 } - #[pallet::type_value] - pub fn DefaultHotkeys() -> Vec { vec![ ] } - #[pallet::type_value] - pub fn DefaultNeworksAdded() -> bool { false } - #[pallet::type_value] - pub fn DefaultIsNetworkMember() -> bool { false } - #[pallet::type_value] - pub fn DefaultRegistrationAllowed() -> bool { false } - - - #[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 ( netuid, netuid ) -> registration_requirement - pub type NetworkConnect = StorageDoubleMap<_, Identity, u16, Identity, u16, u16, OptionQuery>; - #[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>; - - // ============================== - // ==== Subnetwork Features ===== - // ============================== - #[pallet::type_value] - pub fn DefaultEmissionValues() -> u64 { 0 } - #[pallet::type_value] - pub fn DefaultPendingEmission() -> u64 { 0 } - #[pallet::type_value] - pub fn DefaultBlocksSinceLastStep() -> u64 { 0 } - #[pallet::type_value] - pub fn DefaultLastMechansimStepBlock() -> u64 { 0 } - #[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, DefaultLastMechansimStepBlock >; - - // ================================= - // ==== Axon / Promo Endpoints ===== - // ================================= - - // --- Struct for Axon. - pub type AxonInfoOf = AxonInfo; - - #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)] + use frame_support::inherent::Vec; + use frame_support::sp_std::vec; + use frame_support::traits::{Currency, UnfilteredDispatchable}; + use frame_support::{ + dispatch::GetDispatchInfo, + pallet_prelude::{DispatchResult, StorageMap, *}, + }; + use frame_system::pallet_prelude::*; + + #[cfg(not(feature = "std"))] + use alloc::boxed::Box; + #[cfg(feature = "std")] + use sp_std::prelude::Box; + + // Tracks version for migrations. Should be monotonic with respect to the + // order of migrations. (i.e. always increasing) + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] + #[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: Currency + Send + Sync; + + type SenateMembers: crate::MemberManagement; + + type TriumvirateInterface: crate::CollectiveInterface; + + // ================================= + // ==== Initial Value Constants ==== + // ================================= + #[pallet::constant] // Initial currency issuance. + type InitialIssuance: Get; + #[pallet::constant] // Initial min allowed weights setting. + type InitialMinAllowedWeights: Get; + #[pallet::constant] // Initial Emission Ratio. + type InitialEmissionValue: Get; + #[pallet::constant] // Initial max weight limit. + type InitialMaxWeightsLimit: Get; + #[pallet::constant] // Tempo for each network. + type InitialTempo: Get; + #[pallet::constant] // Initial Difficulty. + type InitialDifficulty: Get; + #[pallet::constant] // Initial Max Difficulty. + type InitialMaxDifficulty: Get; + #[pallet::constant] // Initial Min Difficulty. + type InitialMinDifficulty: Get; + #[pallet::constant] // Initial RAO Recycled. + type InitialRAORecycledForRegistration: Get; + #[pallet::constant] // Initial Burn. + type InitialBurn: Get; + #[pallet::constant] // Initial Max Burn. + type InitialMaxBurn: Get; + #[pallet::constant] // Initial Min Burn. + type InitialMinBurn: Get; + #[pallet::constant] // Initial adjustment interval. + type InitialAdjustmentInterval: Get; + #[pallet::constant] // Initial bonds moving average. + type InitialBondsMovingAverage: Get; + #[pallet::constant] // Initial target registrations per interval. + type InitialTargetRegistrationsPerInterval: Get; + #[pallet::constant] // Rho constant. + type InitialRho: Get; + #[pallet::constant] // Kappa constant. + type InitialKappa: Get; + #[pallet::constant] // Max UID constant. + type InitialMaxAllowedUids: Get; + #[pallet::constant] // Initial validator context pruning length. + type InitialValidatorPruneLen: Get; + #[pallet::constant] // Initial scaling law power. + type InitialScalingLawPower: Get; + #[pallet::constant] // Immunity Period Constant. + type InitialImmunityPeriod: Get; + #[pallet::constant] // Activity constant. + type InitialActivityCutoff: Get; + #[pallet::constant] // Initial max registrations per block. + type InitialMaxRegistrationsPerBlock: Get; + #[pallet::constant] // Initial pruning score for each neuron. + type InitialPruningScore: Get; + #[pallet::constant] // Initial maximum allowed validators per network. + type InitialMaxAllowedValidators: Get; + #[pallet::constant] // Initial default delegation take. + type InitialDefaultTake: Get; + #[pallet::constant] // Initial weights version key. + type InitialWeightsVersionKey: Get; + #[pallet::constant] // Initial serving rate limit. + type InitialServingRateLimit: Get; + #[pallet::constant] // Initial transaction rate limit. + type InitialTxRateLimit: Get; + #[pallet::constant] // Initial percentage of total stake required to join senate. + type InitialSenateRequiredStakePercentage: Get; + #[pallet::constant] // Initial adjustment alpha on burn and pow. + type InitialAdjustmentAlpha: Get; + } + + pub type AccountIdOf = ::AccountId; + + // Senate requirements + #[pallet::type_value] + pub fn DefaultSenateRequiredStakePercentage() -> u64 { + T::InitialSenateRequiredStakePercentage::get() + } + + #[pallet::storage] // --- ITEM ( tx_rate_limit ) + pub(super) type SenateRequiredStakePercentage = + StorageValue<_, u64, ValueQuery, DefaultSenateRequiredStakePercentage>; + + // ============================ + // ==== Staking + Accounts ==== + // ============================ + #[pallet::type_value] + pub fn DefaultDefaultTake() -> u16 { + T::InitialDefaultTake::get() + } + #[pallet::type_value] + pub fn DefaultAccountTake() -> u64 { + 0 + } + #[pallet::type_value] + pub fn DefaultBlockEmission() -> u64 { + 1_000_000_000 + } + #[pallet::type_value] + pub fn DefaultAllowsDelegation() -> bool { + false + } + #[pallet::type_value] + pub fn DefaultTotalIssuance() -> u64 { + T::InitialIssuance::get() + } + #[pallet::type_value] + pub fn DefaultAccount() -> T::AccountId { + T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).unwrap() + } + + #[pallet::storage] // --- ITEM ( total_stake ) + pub type TotalStake = StorageValue<_, u64, ValueQuery>; + #[pallet::storage] // --- ITEM ( default_take ) + pub type DefaultTake = StorageValue<_, u16, ValueQuery, DefaultDefaultTake>; + #[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] // --- 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 | 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, + >; + + // ===================================== + // ==== Difficulty / Registrations ===== + // ===================================== + #[pallet::type_value] + pub fn DefaultLastAdjustmentBlock() -> u64 { + 0 + } + #[pallet::type_value] + pub fn DefaultRegistrationsThisBlock() -> u16 { + 0 + } + #[pallet::type_value] + pub fn DefaultBurn() -> u64 { + T::InitialBurn::get() + } + #[pallet::type_value] + pub fn DefaultMinBurn() -> u64 { + T::InitialMinBurn::get() + } + #[pallet::type_value] + pub fn DefaultMaxBurn() -> u64 { + T::InitialMaxBurn::get() + } + #[pallet::type_value] + pub fn DefaultDifficulty() -> u64 { + T::InitialDifficulty::get() + } + #[pallet::type_value] + pub fn DefaultMinDifficulty() -> u64 { + T::InitialMinDifficulty::get() + } + #[pallet::type_value] + pub fn DefaultMaxDifficulty() -> u64 { + T::InitialMaxDifficulty::get() + } + #[pallet::type_value] + pub fn DefaultMaxRegistrationsPerBlock() -> u16 { + T::InitialMaxRegistrationsPerBlock::get() + } + #[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 ===== + // ============================== + #[pallet::type_value] + pub fn DefaultN() -> u16 { + 0 + } + #[pallet::type_value] + pub fn DefaultModality() -> u16 { + 0 + } + #[pallet::type_value] + pub fn DefaultHotkeys() -> Vec { + vec![] + } + #[pallet::type_value] + pub fn DefaultNeworksAdded() -> bool { + false + } + #[pallet::type_value] + pub fn DefaultIsNetworkMember() -> bool { + false + } + #[pallet::type_value] + pub fn DefaultRegistrationAllowed() -> bool { + false + } + + #[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 ( netuid, netuid ) -> registration_requirement + pub type NetworkConnect = + StorageDoubleMap<_, Identity, u16, Identity, u16, u16, OptionQuery>; + #[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>; + + // ============================== + // ==== Subnetwork Features ===== + // ============================== + #[pallet::type_value] + pub fn DefaultEmissionValues() -> u64 { + 0 + } + #[pallet::type_value] + pub fn DefaultPendingEmission() -> u64 { + 0 + } + #[pallet::type_value] + pub fn DefaultBlocksSinceLastStep() -> u64 { + 0 + } + #[pallet::type_value] + pub fn DefaultLastMechansimStepBlock() -> u64 { + 0 + } + #[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, DefaultLastMechansimStepBlock>; + + // ================================= + // ==== Axon / Promo Endpoints ===== + // ================================= + + // --- Struct for Axon. + pub type AxonInfoOf = AxonInfo; + + #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)] pub struct AxonInfo { - pub block: u64, // --- Axon serving block. - pub version: u32, // --- Axon version - pub ip: u128, // --- Axon u128 encoded ip address of type v6 or v4. - pub port: u16, // --- Axon u16 encoded port. - pub ip_type: u8, // --- Axon ip type, 4 for ipv4 and 6 for ipv6. - pub protocol: u8, // --- Axon protocol. TCP, UDP, other. - pub placeholder1: u8, // --- Axon proto placeholder 1. - pub placeholder2: u8, // --- Axon proto placeholder 1. - } - - // --- Struct for Prometheus. - pub type PrometheusInfoOf = PrometheusInfo; - #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)] - pub struct PrometheusInfo { - pub block: u64, // --- Prometheus serving block. + pub block: u64, // --- Axon serving block. + pub version: u32, // --- Axon version + pub ip: u128, // --- Axon u128 encoded ip address of type v6 or v4. + pub port: u16, // --- Axon u16 encoded port. + pub ip_type: u8, // --- Axon ip type, 4 for ipv4 and 6 for ipv6. + pub protocol: u8, // --- Axon protocol. TCP, UDP, other. + pub placeholder1: u8, // --- Axon proto placeholder 1. + pub placeholder2: u8, // --- Axon proto placeholder 1. + } + + // --- Struct for Prometheus. + pub type PrometheusInfoOf = PrometheusInfo; + #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)] + pub struct PrometheusInfo { + pub block: u64, // --- Prometheus serving block. pub version: u32, // --- Prometheus version. - pub ip: u128, // --- Prometheus u128 encoded ip address of type v6 or v4. - pub port: u16, // --- Prometheus u16 encoded port. - pub ip_type: u8, // --- Prometheus ip type, 4 for ipv4 and 6 for ipv6. - } - - // Rate limiting - #[pallet::type_value] - pub fn DefaultTxRateLimit() -> u64 { T::InitialTxRateLimit::get() } - #[pallet::type_value] - pub fn DefaultLastTxBlock() -> u64 { 0 } - - #[pallet::storage] // --- ITEM ( tx_rate_limit ) - pub(super) type TxRateLimit = StorageValue<_, u64, ValueQuery, DefaultTxRateLimit>; - #[pallet::storage] // --- MAP ( key ) --> last_block - pub(super) type LastTxBlock = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; - - - #[pallet::type_value] - pub fn DefaultServingRateLimit() -> u64 { T::InitialServingRateLimit::get() } - - #[pallet::storage] // --- MAP ( netuid ) --> serving_rate_limit - pub type ServingRateLimit = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultServingRateLimit> ; - #[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>; - - // ======================================= - // ==== Subnetwork Hyperparam storage ==== - // ======================================= - #[pallet::type_value] - pub fn DefaultWeightsSetRateLimit() -> u64 { 100 } - #[pallet::type_value] - pub fn DefaultBlockAtRegistration() -> u64 { 0 } - #[pallet::type_value] - pub fn DefaultRho() -> u16 { T::InitialRho::get() } - #[pallet::type_value] - pub fn DefaultKappa() -> u16 { T::InitialKappa::get() } - #[pallet::type_value] - pub fn DefaultMaxAllowedUids() -> u16 { T::InitialMaxAllowedUids::get() } - #[pallet::type_value] - pub fn DefaultImmunityPeriod() -> u16 { T::InitialImmunityPeriod::get() } - #[pallet::type_value] - pub fn DefaultActivityCutoff() -> u16 { T::InitialActivityCutoff::get() } - #[pallet::type_value] - pub fn DefaultMaxWeightsLimit() -> u16 { T::InitialMaxWeightsLimit::get() } - #[pallet::type_value] - pub fn DefaultWeightsVersionKey() -> u64 { T::InitialWeightsVersionKey::get() } - #[pallet::type_value] - pub fn DefaultMinAllowedWeights() -> u16 { T::InitialMinAllowedWeights::get() } - #[pallet::type_value] - pub fn DefaultMaxAllowedValidators() -> u16 { T::InitialMaxAllowedValidators::get() } - #[pallet::type_value] - pub fn DefaultAdjustmentInterval() -> u16 { T::InitialAdjustmentInterval::get() } - #[pallet::type_value] - pub fn DefaultBondsMovingAverage() -> u64 { T::InitialBondsMovingAverage::get() } - #[pallet::type_value] - pub fn DefaultValidatorPruneLen() -> u64 { T::InitialValidatorPruneLen::get() } - #[pallet::type_value] - pub fn DefaultScalingLawPower() -> u16 { T::InitialScalingLawPower::get() } - #[pallet::type_value] - pub fn DefaultTargetRegistrationsPerInterval() -> u16 { T::InitialTargetRegistrationsPerInterval::get() } - #[pallet::type_value] - pub fn DefaultAdjustmentAlpha() -> u64 { T::InitialAdjustmentAlpha::get() } - - - #[pallet::storage] // --- MAP ( netuid ) --> Rho - pub type Rho = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultRho >; - #[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. - pub type NeuronsToPruneAtNextEpoch = StorageMap<_, Identity, u16, u16, ValueQuery>; - #[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 >; - - // ======================================= - // ==== Subnetwork Consensus Storage ==== - // ======================================= - #[pallet::type_value] - pub fn EmptyU16Vec() -> Vec { vec![] } - #[pallet::type_value] - pub fn EmptyU64Vec() -> Vec { vec![] } - #[pallet::type_value] - pub fn EmptyBoolVec() -> Vec { vec![] } - #[pallet::type_value] - pub fn DefaultBonds() -> Vec<(u16, u16)> { vec![] } - #[pallet::type_value] - pub fn DefaultWeights() -> Vec<(u16, u16)> { vec![] } - #[pallet::type_value] - pub fn DefaultKey() -> T::AccountId { T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).unwrap() } - - #[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 >; - - // Pallets use events to inform users when important changes are made. - // https://docs.substrate.io/main-docs/build/events-errors/ - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - // Event documentation should end with an array that provides descriptive names for event - // parameters. [something, who] - NetworkAdded( u16, u16 ), // --- Event created when a new network is added. - NetworkRemoved( u16 ), // --- Event created when a network is removed. - StakeAdded( T::AccountId, u64 ), // --- Event created when stake has been transfered from the a coldkey account onto the hotkey staking account. - StakeRemoved( T::AccountId, u64 ), // --- Event created when stake has been removed from the hotkey staking account onto the coldkey account. - WeightsSet( u16, u16 ), // ---- Event created when a caller successfully sets their weights on a subnetwork. - NeuronRegistered( u16, u16, T::AccountId ), // --- Event created when a new neuron account has been registered to the chain. - BulkNeuronsRegistered( u16, u16 ), // --- Event created when multiple uids have been concurrently registered. - BulkBalancesSet(u16, u16), // --- FIXME: Not used yet - MaxAllowedUidsSet( u16, u16 ), // --- Event created when max allowed uids has been set for a subnetwork. - MaxWeightLimitSet( u16, u16 ), // --- Event created when the max weight limit has been set for a subnetwork. - DifficultySet( u16, u64 ), // --- Event created when the difficulty has been set for a subnet. - AdjustmentIntervalSet( u16, u16 ), // --- Event created when the adjustment interval is set for a subnet. - RegistrationPerIntervalSet( u16, u16 ), // --- Event created when registeration per interval is set for a subnet. - MaxRegistrationsPerBlockSet( u16, u16), // --- Event created when we set max registrations per block. - ActivityCutoffSet( u16, u16 ), // --- Event created when an activity cutoff is set for a subnet. - RhoSet( u16, u16 ), // --- Event created when Rho value is set. - KappaSet( u16, u16 ), // --- Event created when Kappa is set for a subnet. - MinAllowedWeightSet( u16, u16 ), // --- Event created when minimun allowed weight is set for a subnet. - ValidatorPruneLenSet( u16, u64 ), // --- Event created when the validator pruning length has been set. - ScalingLawPowerSet( u16, u16 ), // --- Event created when the scaling law power has been set for a subnet. - WeightsSetRateLimitSet( u16, u64 ), // --- Event created when weights set rate limit has been set for a subnet. - ImmunityPeriodSet( u16, u16), // --- Event created when immunity period is set for a subnet. - BondsMovingAverageSet( u16, u64), // --- Event created when bonds moving average is set for a subnet. - MaxAllowedValidatorsSet( u16, u16), // --- Event created when setting the max number of allowed validators on a subnet. - AxonServed( u16, T::AccountId ), // --- Event created when the axon server information is added to the network. - PrometheusServed( u16, T::AccountId ), // --- Event created when the prometheus server information is added to the network. - EmissionValuesSet(), // --- Event created when emission ratios for all networks is set. - NetworkConnectionAdded( u16, u16, u16 ), // --- Event created when a network connection requirement is added. - NetworkConnectionRemoved( u16, u16 ), // --- Event created when a network connection requirement is removed. - DelegateAdded( T::AccountId, T::AccountId, u16 ), // --- Event created to signal that a hotkey has become a delegate. - DefaultTakeSet( u16 ), // --- Event created when the default take is set. - WeightsVersionKeySet( u16, u64 ), // --- Event created when weights version key is set for a network. - MinDifficultySet( u16, u64 ), // --- Event created when setting min difficutly on a network. - MaxDifficultySet( u16, u64 ), // --- Event created when setting max difficutly on a network. - ServingRateLimitSet( u16, u64 ), // --- Event created when setting the prometheus serving rate limit. - BurnSet( u16, u64 ), // --- Event created when setting burn on a network. - MaxBurnSet( u16, u64 ), // --- Event created when setting max burn on a network. - MinBurnSet( u16, u64 ), // --- Event created when setting min burn on a network. - TxRateLimitSet( u64 ), // --- Event created when setting the transaction rate limit. - Sudid ( DispatchResult ), // --- Event created when a sudo call is done. - RegistrationAllowed( u16, bool ), // --- Event created when registration is allowed/disallowed for a subnet. - TempoSet(u16, u16), // --- Event created when setting tempo on a network - RAORecycledForRegistrationSet( u16, u64 ), // Event created when setting the RAO recycled for registration. - SenateRequiredStakePercentSet( u64 ), // Event created when setting the minimum required stake amount for senate registration. - AdjustmentAlphaSet( u16, u64 ), // Event created when setting the adjustment alpha on a subnet. - } - - // Errors inform users that something went wrong. - #[pallet::error] - pub enum Error { - InvalidConnectionRequirement, // --- Thrown if we are attempting to create an invalid connection requirement. - NetworkDoesNotExist, // --- Thrown when the network does not exist. - NetworkExist, // --- Thrown when the network already exists. - InvalidModality, // --- Thrown when an invalid modality attempted on serve. - InvalidIpType, // ---- Thrown when the user tries to serve an axon which is not of type 4 (IPv4) or 6 (IPv6). - InvalidIpAddress, // --- Thrown when an invalid IP address is passed to the serve function. - InvalidPort, // --- Thrown when an invalid port is passed to the serve function. - NotRegistered, // ---- Thrown when the caller requests setting or removing data from a neuron which does not exist in the active set. - NonAssociatedColdKey, // ---- Thrown when a stake, unstake or subscribe request is made by a coldkey which is not associated with the hotkey account. - NotEnoughStaketoWithdraw, // ---- Thrown when the caller requests removing more stake than there exists in the staking account. See: fn remove_stake. - NotEnoughBalanceToStake, // ---- Thrown when the caller requests adding more stake than there exists in the cold key account. See: fn add_stake - BalanceWithdrawalError, // ---- Thrown when the caller tries to add stake, but for some reason the requested amount could not be withdrawn from the coldkey account. - NoValidatorPermit, // ---- Thrown when the caller attempts to set non-self weights without being a permitted validator. - WeightVecNotEqualSize, // ---- Thrown when the caller attempts to set the weight keys and values but these vectors have different size. - DuplicateUids, // ---- Thrown when the caller attempts to set weights with duplicate uids in the weight matrix. - InvalidUid, // ---- Thrown when a caller attempts to set weight to at least one uid that does not exist in the metagraph. - NotSettingEnoughWeights, // ---- Thrown when the dispatch attempts to set weights on chain with fewer elements than are allowed. - TooManyRegistrationsThisBlock, // ---- Thrown when registrations this block exceeds allowed number. - AlreadyRegistered, // ---- Thrown when the caller requests registering a neuron which already exists in the active set. - InvalidWorkBlock, // ---- Thrown if the supplied pow hash block is in the future or negative. - InvalidDifficulty, // ---- Thrown if the supplied pow hash block does not meet the network difficulty. - InvalidSeal, // ---- Thrown if the supplied pow hash seal does not match the supplied work. - MaxAllowedUIdsNotAllowed, // --- Thrown if the vaule is invalid for MaxAllowedUids. - CouldNotConvertToBalance, // ---- Thrown when the dispatch attempts to convert between a u64 and T::balance but the call fails. - StakeAlreadyAdded, // --- Thrown when the caller requests adding stake for a hotkey to the total stake which already added. - MaxWeightExceeded, // --- Thrown when the dispatch attempts to set weights on chain with where any normalized weight is more than MaxWeightLimit. - StorageValueOutOfRange, // --- Thrown when the caller attempts to set a storage value outside of its allowed range. - TempoHasNotSet, // --- Thrown when tempo has not set. - InvalidTempo, // --- Thrown when tempo is not valid. - EmissionValuesDoesNotMatchNetworks, // --- Thrown when number or recieved emission rates does not match number of networks. - InvalidEmissionValues, // --- Thrown when emission ratios are not valid (did not sum up to 10^9). - DidNotPassConnectedNetworkRequirement, // --- Thrown when a hotkey attempts to register into a network without passing the registration requirment from another network. - AlreadyDelegate, // --- Thrown if the hotkey attempts to become delegate when they are already. - SettingWeightsTooFast, // --- Thrown if the hotkey attempts to set weights twice within net_tempo/2 blocks. - IncorrectNetworkVersionKey, // --- Thrown when a validator attempts to set weights from a validator with incorrect code base key. - ServingRateLimitExceeded, // --- Thrown when an axon or prometheus serving exceeds the rate limit for a registered neuron. - BalanceSetError, // --- Thrown when an error occurs while setting a balance. - MaxAllowedUidsExceeded, // --- Thrown when number of accounts going to be registered exceeds MaxAllowedUids for the network. - TooManyUids, // ---- Thrown when the caller attempts to set weights with more uids than allowed. - TxRateLimitExceeded, // --- Thrown when a transactor exceeds the rate limit for transactions. - RegistrationDisabled, // --- Thrown when registration is disabled - TooManyRegistrationsThisInterval, // --- Thrown when registration attempt exceeds allowed in interval - BenchmarkingOnly, // --- Thrown when a function is only available for benchmarking - HotkeyOriginMismatch, // --- Thrown when the hotkey passed is not the origin, but it should be - // Senate errors - SenateMember, // --- Thrown when attempting to do something to a senate member that is limited - NotSenateMember, // --- Thrown when a hotkey attempts to do something only senate members can do - AlreadySenateMember, // --- Thrown when a hotkey attempts to join the senate while already being a member - BelowStakeThreshold, // --- Thrown when a hotkey attempts to join the senate without enough stake - NotDelegate, // --- Thrown when a hotkey attempts to join the senate without being a delegate first - IncorrectNetuidsLength, // --- Thrown when an incorrect amount of Netuids are passed as input - } - - // ================== - // ==== Genesis ===== - // ================== - - #[pallet::genesis_config] - #[cfg(feature = "std")] - pub struct GenesisConfig { - pub stakes: Vec<(T::AccountId, Vec<(T::AccountId, (u64, u16))>)>, - pub balances_issuance: u64 - } - - #[cfg(feature = "std")] - impl Default for GenesisConfig { - fn default() -> Self { - Self { - stakes: Default::default(), - balances_issuance: 0 - } - } - } - - #[pallet::genesis_build] - impl GenesisBuild 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); - } - } - - // ================ - // ==== 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': (T::BlockNumber): - // - The number of the block we are initializing. - fn on_initialize( _block_number: BlockNumberFor ) -> Weight { - Self::block_step(); - - return Weight::from_ref_time(110_634_229_000 as u64) - .saturating_add(T::DbWeight::get().reads(8304 as u64)) - .saturating_add(T::DbWeight::get().writes(110 as u64)); - } - - fn on_runtime_upgrade() -> frame_support::weights::Weight { - // --- Migrate to v2 - use crate::migration; - - migration::migrate_to_v2_separate_emission::() - } - } - - // 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: - // * 'NetworkDoesNotExist': - // - 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. - // - // * 'TooManyUids': - // - Attempting to set weights above the max allowed uids. - // - // * 'InvalidUid': - // - Attempting to set weights with invalid uids. - // - // * 'NotSettingEnoughWeights': - // - Attempting to set weights with fewer weights than min. - // - // * 'MaxWeightExceeded': - // - Attempting to set weights with max value exceeding limit. - #[pallet::call_index(0)] + pub ip: u128, // --- Prometheus u128 encoded ip address of type v6 or v4. + pub port: u16, // --- Prometheus u16 encoded port. + pub ip_type: u8, // --- Prometheus ip type, 4 for ipv4 and 6 for ipv6. + } + + // Rate limiting + #[pallet::type_value] + pub fn DefaultTxRateLimit() -> u64 { + T::InitialTxRateLimit::get() + } + #[pallet::type_value] + pub fn DefaultLastTxBlock() -> u64 { + 0 + } + + #[pallet::storage] // --- ITEM ( tx_rate_limit ) + pub(super) type TxRateLimit = StorageValue<_, u64, ValueQuery, DefaultTxRateLimit>; + #[pallet::storage] // --- MAP ( key ) --> last_block + pub(super) type LastTxBlock = + StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; + + #[pallet::type_value] + pub fn DefaultServingRateLimit() -> u64 { + T::InitialServingRateLimit::get() + } + + #[pallet::storage] // --- MAP ( netuid ) --> serving_rate_limit + pub type ServingRateLimit = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultServingRateLimit>; + #[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, + >; + + // ======================================= + // ==== Subnetwork Hyperparam storage ==== + // ======================================= + #[pallet::type_value] + pub fn DefaultWeightsSetRateLimit() -> u64 { + 100 + } + #[pallet::type_value] + pub fn DefaultBlockAtRegistration() -> u64 { + 0 + } + #[pallet::type_value] + pub fn DefaultRho() -> u16 { + T::InitialRho::get() + } + #[pallet::type_value] + pub fn DefaultKappa() -> u16 { + T::InitialKappa::get() + } + #[pallet::type_value] + pub fn DefaultMaxAllowedUids() -> u16 { + T::InitialMaxAllowedUids::get() + } + #[pallet::type_value] + pub fn DefaultImmunityPeriod() -> u16 { + T::InitialImmunityPeriod::get() + } + #[pallet::type_value] + pub fn DefaultActivityCutoff() -> u16 { + T::InitialActivityCutoff::get() + } + #[pallet::type_value] + pub fn DefaultMaxWeightsLimit() -> u16 { + T::InitialMaxWeightsLimit::get() + } + #[pallet::type_value] + pub fn DefaultWeightsVersionKey() -> u64 { + T::InitialWeightsVersionKey::get() + } + #[pallet::type_value] + pub fn DefaultMinAllowedWeights() -> u16 { + T::InitialMinAllowedWeights::get() + } + #[pallet::type_value] + pub fn DefaultMaxAllowedValidators() -> u16 { + T::InitialMaxAllowedValidators::get() + } + #[pallet::type_value] + pub fn DefaultAdjustmentInterval() -> u16 { + T::InitialAdjustmentInterval::get() + } + #[pallet::type_value] + pub fn DefaultBondsMovingAverage() -> u64 { + T::InitialBondsMovingAverage::get() + } + #[pallet::type_value] + pub fn DefaultValidatorPruneLen() -> u64 { + T::InitialValidatorPruneLen::get() + } + #[pallet::type_value] + pub fn DefaultScalingLawPower() -> u16 { + T::InitialScalingLawPower::get() + } + #[pallet::type_value] + pub fn DefaultTargetRegistrationsPerInterval() -> u16 { + T::InitialTargetRegistrationsPerInterval::get() + } + #[pallet::type_value] + pub fn DefaultAdjustmentAlpha() -> u64 { + T::InitialAdjustmentAlpha::get() + } + + #[pallet::storage] // --- MAP ( netuid ) --> Rho + pub type Rho = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultRho>; + #[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. + pub type NeuronsToPruneAtNextEpoch = StorageMap<_, Identity, u16, u16, ValueQuery>; + #[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>; + + // ======================================= + // ==== Subnetwork Consensus Storage ==== + // ======================================= + #[pallet::type_value] + pub fn EmptyU16Vec() -> Vec { + vec![] + } + #[pallet::type_value] + pub fn EmptyU64Vec() -> Vec { + vec![] + } + #[pallet::type_value] + pub fn EmptyBoolVec() -> Vec { + vec![] + } + #[pallet::type_value] + pub fn DefaultBonds() -> Vec<(u16, u16)> { + vec![] + } + #[pallet::type_value] + pub fn DefaultWeights() -> Vec<(u16, u16)> { + vec![] + } + #[pallet::type_value] + pub fn DefaultKey() -> T::AccountId { + T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).unwrap() + } + + #[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, + >; + + // Pallets use events to inform users when important changes are made. + // https://docs.substrate.io/main-docs/build/events-errors/ + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + // Event documentation should end with an array that provides descriptive names for event + // parameters. [something, who] + NetworkAdded(u16, u16), // --- Event created when a new network is added. + NetworkRemoved(u16), // --- Event created when a network is removed. + StakeAdded(T::AccountId, u64), // --- Event created when stake has been transfered from the a coldkey account onto the hotkey staking account. + StakeRemoved(T::AccountId, u64), // --- Event created when stake has been removed from the hotkey staking account onto the coldkey account. + WeightsSet(u16, u16), // ---- Event created when a caller successfully sets their weights on a subnetwork. + NeuronRegistered(u16, u16, T::AccountId), // --- Event created when a new neuron account has been registered to the chain. + BulkNeuronsRegistered(u16, u16), // --- Event created when multiple uids have been concurrently registered. + BulkBalancesSet(u16, u16), // --- FIXME: Not used yet + MaxAllowedUidsSet(u16, u16), // --- Event created when max allowed uids has been set for a subnetwork. + MaxWeightLimitSet(u16, u16), // --- Event created when the max weight limit has been set for a subnetwork. + DifficultySet(u16, u64), // --- Event created when the difficulty has been set for a subnet. + AdjustmentIntervalSet(u16, u16), // --- Event created when the adjustment interval is set for a subnet. + RegistrationPerIntervalSet(u16, u16), // --- Event created when registeration per interval is set for a subnet. + MaxRegistrationsPerBlockSet(u16, u16), // --- Event created when we set max registrations per block. + ActivityCutoffSet(u16, u16), // --- Event created when an activity cutoff is set for a subnet. + RhoSet(u16, u16), // --- Event created when Rho value is set. + KappaSet(u16, u16), // --- Event created when Kappa is set for a subnet. + MinAllowedWeightSet(u16, u16), // --- Event created when minimun allowed weight is set for a subnet. + ValidatorPruneLenSet(u16, u64), // --- Event created when the validator pruning length has been set. + ScalingLawPowerSet(u16, u16), // --- Event created when the scaling law power has been set for a subnet. + WeightsSetRateLimitSet(u16, u64), // --- Event created when weights set rate limit has been set for a subnet. + ImmunityPeriodSet(u16, u16), // --- Event created when immunity period is set for a subnet. + BondsMovingAverageSet(u16, u64), // --- Event created when bonds moving average is set for a subnet. + MaxAllowedValidatorsSet(u16, u16), // --- Event created when setting the max number of allowed validators on a subnet. + AxonServed(u16, T::AccountId), // --- Event created when the axon server information is added to the network. + PrometheusServed(u16, T::AccountId), // --- Event created when the prometheus server information is added to the network. + EmissionValuesSet(), // --- Event created when emission ratios for all networks is set. + NetworkConnectionAdded(u16, u16, u16), // --- Event created when a network connection requirement is added. + NetworkConnectionRemoved(u16, u16), // --- Event created when a network connection requirement is removed. + DelegateAdded(T::AccountId, T::AccountId, u16), // --- Event created to signal that a hotkey has become a delegate. + DefaultTakeSet(u16), // --- Event created when the default take is set. + WeightsVersionKeySet(u16, u64), // --- Event created when weights version key is set for a network. + MinDifficultySet(u16, u64), // --- Event created when setting min difficutly on a network. + MaxDifficultySet(u16, u64), // --- Event created when setting max difficutly on a network. + ServingRateLimitSet(u16, u64), // --- Event created when setting the prometheus serving rate limit. + BurnSet(u16, u64), // --- Event created when setting burn on a network. + MaxBurnSet(u16, u64), // --- Event created when setting max burn on a network. + MinBurnSet(u16, u64), // --- Event created when setting min burn on a network. + TxRateLimitSet(u64), // --- Event created when setting the transaction rate limit. + Sudid(DispatchResult), // --- Event created when a sudo call is done. + RegistrationAllowed(u16, bool), // --- Event created when registration is allowed/disallowed for a subnet. + TempoSet(u16, u16), // --- Event created when setting tempo on a network + RAORecycledForRegistrationSet(u16, u64), // Event created when setting the RAO recycled for registration. + SenateRequiredStakePercentSet(u64), // Event created when setting the minimum required stake amount for senate registration. + AdjustmentAlphaSet(u16, u64), // Event created when setting the adjustment alpha on a subnet. + } + + // Errors inform users that something went wrong. + #[pallet::error] + pub enum Error { + InvalidConnectionRequirement, // --- Thrown if we are attempting to create an invalid connection requirement. + NetworkDoesNotExist, // --- Thrown when the network does not exist. + NetworkExist, // --- Thrown when the network already exists. + InvalidModality, // --- Thrown when an invalid modality attempted on serve. + InvalidIpType, // ---- Thrown when the user tries to serve an axon which is not of type 4 (IPv4) or 6 (IPv6). + InvalidIpAddress, // --- Thrown when an invalid IP address is passed to the serve function. + InvalidPort, // --- Thrown when an invalid port is passed to the serve function. + NotRegistered, // ---- Thrown when the caller requests setting or removing data from a neuron which does not exist in the active set. + NonAssociatedColdKey, // ---- Thrown when a stake, unstake or subscribe request is made by a coldkey which is not associated with the hotkey account. + NotEnoughStaketoWithdraw, // ---- Thrown when the caller requests removing more stake than there exists in the staking account. See: fn remove_stake. + NotEnoughBalanceToStake, // ---- Thrown when the caller requests adding more stake than there exists in the cold key account. See: fn add_stake + BalanceWithdrawalError, // ---- Thrown when the caller tries to add stake, but for some reason the requested amount could not be withdrawn from the coldkey account. + NoValidatorPermit, // ---- Thrown when the caller attempts to set non-self weights without being a permitted validator. + WeightVecNotEqualSize, // ---- Thrown when the caller attempts to set the weight keys and values but these vectors have different size. + DuplicateUids, // ---- Thrown when the caller attempts to set weights with duplicate uids in the weight matrix. + InvalidUid, // ---- Thrown when a caller attempts to set weight to at least one uid that does not exist in the metagraph. + NotSettingEnoughWeights, // ---- Thrown when the dispatch attempts to set weights on chain with fewer elements than are allowed. + TooManyRegistrationsThisBlock, // ---- Thrown when registrations this block exceeds allowed number. + AlreadyRegistered, // ---- Thrown when the caller requests registering a neuron which already exists in the active set. + InvalidWorkBlock, // ---- Thrown if the supplied pow hash block is in the future or negative. + InvalidDifficulty, // ---- Thrown if the supplied pow hash block does not meet the network difficulty. + InvalidSeal, // ---- Thrown if the supplied pow hash seal does not match the supplied work. + MaxAllowedUIdsNotAllowed, // --- Thrown if the vaule is invalid for MaxAllowedUids. + CouldNotConvertToBalance, // ---- Thrown when the dispatch attempts to convert between a u64 and T::balance but the call fails. + StakeAlreadyAdded, // --- Thrown when the caller requests adding stake for a hotkey to the total stake which already added. + MaxWeightExceeded, // --- Thrown when the dispatch attempts to set weights on chain with where any normalized weight is more than MaxWeightLimit. + StorageValueOutOfRange, // --- Thrown when the caller attempts to set a storage value outside of its allowed range. + TempoHasNotSet, // --- Thrown when tempo has not set. + InvalidTempo, // --- Thrown when tempo is not valid. + EmissionValuesDoesNotMatchNetworks, // --- Thrown when number or recieved emission rates does not match number of networks. + InvalidEmissionValues, // --- Thrown when emission ratios are not valid (did not sum up to 10^9). + DidNotPassConnectedNetworkRequirement, // --- Thrown when a hotkey attempts to register into a network without passing the registration requirment from another network. + AlreadyDelegate, // --- Thrown if the hotkey attempts to become delegate when they are already. + SettingWeightsTooFast, // --- Thrown if the hotkey attempts to set weights twice within net_tempo/2 blocks. + IncorrectNetworkVersionKey, // --- Thrown when a validator attempts to set weights from a validator with incorrect code base key. + ServingRateLimitExceeded, // --- Thrown when an axon or prometheus serving exceeds the rate limit for a registered neuron. + BalanceSetError, // --- Thrown when an error occurs while setting a balance. + MaxAllowedUidsExceeded, // --- Thrown when number of accounts going to be registered exceeds MaxAllowedUids for the network. + TooManyUids, // ---- Thrown when the caller attempts to set weights with more uids than allowed. + TxRateLimitExceeded, // --- Thrown when a transactor exceeds the rate limit for transactions. + RegistrationDisabled, // --- Thrown when registration is disabled + TooManyRegistrationsThisInterval, // --- Thrown when registration attempt exceeds allowed in interval + BenchmarkingOnly, // --- Thrown when a function is only available for benchmarking + HotkeyOriginMismatch, // --- Thrown when the hotkey passed is not the origin, but it should be + // Senate errors + SenateMember, // --- Thrown when attempting to do something to a senate member that is limited + NotSenateMember, // --- Thrown when a hotkey attempts to do something only senate members can do + AlreadySenateMember, // --- Thrown when a hotkey attempts to join the senate while already being a member + BelowStakeThreshold, // --- Thrown when a hotkey attempts to join the senate without enough stake + NotDelegate, // --- Thrown when a hotkey attempts to join the senate without being a delegate first + IncorrectNetuidsLength, // --- Thrown when an incorrect amount of Netuids are passed as input + } + + // ================== + // ==== Genesis ===== + // ================== + + #[pallet::genesis_config] + #[cfg(feature = "std")] + pub struct GenesisConfig { + pub stakes: Vec<(T::AccountId, Vec<(T::AccountId, (u64, u16))>)>, + pub balances_issuance: u64, + } + + #[cfg(feature = "std")] + impl Default for GenesisConfig { + fn default() -> Self { + Self { + stakes: Default::default(), + balances_issuance: 0, + } + } + } + + #[pallet::genesis_build] + impl GenesisBuild 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); + } + } + + // ================ + // ==== 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': (T::BlockNumber): + // - The number of the block we are initializing. + fn on_initialize(_block_number: BlockNumberFor) -> Weight { + Self::block_step(); + + return Weight::from_ref_time(110_634_229_000 as u64) + .saturating_add(T::DbWeight::get().reads(8304 as u64)) + .saturating_add(T::DbWeight::get().writes(110 as u64)); + } + + fn on_runtime_upgrade() -> frame_support::weights::Weight { + // --- Migrate to v2 + use crate::migration; + + migration::migrate_to_v2_separate_emission::() + } + } + + // 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: + // * 'NetworkDoesNotExist': + // - 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. + // + // * 'TooManyUids': + // - Attempting to set weights above the max allowed uids. + // + // * 'InvalidUid': + // - Attempting to set weights with invalid uids. + // + // * 'NotSettingEnoughWeights': + // - 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_ref_time(10_151_000_000) .saturating_add(T::DbWeight::get().reads(4104)) .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 { - Self::do_set_weights( origin, netuid, 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((0, DispatchClass::Normal, Pays::No))] - pub fn become_delegate( - origin: OriginFor, - hotkey: T::AccountId - ) -> DispatchResult { - Self::do_become_delegate(origin, hotkey, Self::get_default_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: - // * 'CouldNotConvertToBalance': - // - Unable to convert the passed stake value to a balance. - // - // * '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_ref_time(65_000_000) + pub fn set_weights( + origin: OriginFor, + netuid: u16, + dests: Vec, + weights: Vec, + version_key: u64, + ) -> DispatchResult { + Self::do_set_weights(origin, netuid, 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((0, DispatchClass::Normal, Pays::No))] + pub fn become_delegate(origin: OriginFor, hotkey: T::AccountId) -> DispatchResult { + Self::do_become_delegate(origin, hotkey, Self::get_default_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: + // * 'CouldNotConvertToBalance': + // - Unable to convert the passed stake value to a balance. + // + // * '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_ref_time(65_000_000) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(6)), 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. - // - // * 'CouldNotConvertToBalance': - // - Thrown if we could not convert this amount to a balance. - // - // - #[pallet::call_index(3)] - #[pallet::weight((Weight::from_ref_time(63_000_000) + 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. + // + // * 'CouldNotConvertToBalance': + // - Thrown if we could not convert this amount to a balance. + // + // + #[pallet::call_index(3)] + #[pallet::weight((Weight::from_ref_time(63_000_000) .saturating_add(Weight::from_proof_size(43991)) .saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().writes(9)), 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: - // * 'NetworkDoesNotExist': - // - 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_ref_time(19_000_000) + 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: + // * 'NetworkDoesNotExist': + // - 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_ref_time(19_000_000) .saturating_add(T::DbWeight::get().reads(2)) .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 ) - } - - #[pallet::call_index(5)] - #[pallet::weight((Weight::from_ref_time(17_000_000) + 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, + ) + } + + #[pallet::call_index(5)] + #[pallet::weight((Weight::from_ref_time(17_000_000) .saturating_add(T::DbWeight::get().reads(2)) .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 registereing a uid to a neuron slot on a subnetwork. - // - // # Raises: - // * 'NetworkDoesNotExist': - // - Attempting to registed to a non existent network. - // - // * 'TooManyRegistrationsThisBlock': - // - This registration exceeds the total allowed on this network this block. - // - // * 'AlreadyRegistered': - // - 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 difficutly. - // - // * 'InvalidSeal': - // - The seal is incorrect. - // - #[pallet::call_index(6)] - #[pallet::weight((Weight::from_ref_time(91_000_000) + 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 registereing a uid to a neuron slot on a subnetwork. + // + // # Raises: + // * 'NetworkDoesNotExist': + // - Attempting to registed to a non existent network. + // + // * 'TooManyRegistrationsThisBlock': + // - This registration exceeds the total allowed on this network this block. + // + // * 'AlreadyRegistered': + // - 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 difficutly. + // + // * 'InvalidSeal': + // - The seal is incorrect. + // + #[pallet::call_index(6)] + #[pallet::weight((Weight::from_ref_time(91_000_000) .saturating_add(T::DbWeight::get().reads(27)) .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) - } - - #[pallet::call_index(7)] - #[pallet::weight((Weight::from_ref_time(89_000_000) + 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) + } + + #[pallet::call_index(7)] + #[pallet::weight((Weight::from_ref_time(89_000_000) .saturating_add(T::DbWeight::get().reads(27)) .saturating_add(T::DbWeight::get().writes(22)), DispatchClass::Normal, Pays::No))] - pub fn burned_register( - origin:OriginFor, - netuid: u16, - hotkey: T::AccountId, - ) -> DispatchResult { - Self::do_burned_registration(origin, netuid, hotkey) - } - - #[pallet::call_index(8)] - #[pallet::weight((Weight::from_ref_time(81_000_000) + pub fn burned_register( + origin: OriginFor, + netuid: u16, + hotkey: T::AccountId, + ) -> DispatchResult { + Self::do_burned_registration(origin, netuid, hotkey) + } + + #[pallet::call_index(8)] + #[pallet::weight((Weight::from_ref_time(81_000_000) .saturating_add(T::DbWeight::get().reads(21)) .saturating_add(T::DbWeight::get().writes(23)), DispatchClass::Operational, Pays::No))] - pub fn sudo_register( - origin:OriginFor, - netuid: u16, - hotkey: T::AccountId, - coldkey: T::AccountId, - stake: u64, - balance: u64, - ) -> DispatchResult { - Self::do_sudo_registration(origin, netuid, hotkey, coldkey, stake, balance) - } - - // ---- SUDO ONLY FUNCTIONS ------------------------------------------------------------ - - // ---- Sudo add a network to the network set. - // # Args: - // * 'origin': (Origin): - // - Must be sudo. - // - // * 'netuid' (u16): - // - The u16 network identifier. - // - // * 'tempo' ( u16 ): - // - Number of blocks between epoch step. - // - // * 'modality' ( u16 ): - // - Network modality specifier. - // - // # Event: - // * NetworkAdded; - // - On successfully creation of a network. - // - // # Raises: - // * 'NetworkExist': - // - Attempting to register an already existing. - // - // * 'InvalidModality': - // - Attempting to register a network with an invalid modality. - // - // * 'InvalidTempo': - // - Attempting to register a network with an invalid tempo. - // - #[pallet::call_index(9)] - #[pallet::weight((Weight::from_ref_time(50_000_000) + pub fn sudo_register( + origin: OriginFor, + netuid: u16, + hotkey: T::AccountId, + coldkey: T::AccountId, + stake: u64, + balance: u64, + ) -> DispatchResult { + Self::do_sudo_registration(origin, netuid, hotkey, coldkey, stake, balance) + } + + // ---- SUDO ONLY FUNCTIONS ------------------------------------------------------------ + + // ---- Sudo add a network to the network set. + // # Args: + // * 'origin': (Origin): + // - Must be sudo. + // + // * 'netuid' (u16): + // - The u16 network identifier. + // + // * 'tempo' ( u16 ): + // - Number of blocks between epoch step. + // + // * 'modality' ( u16 ): + // - Network modality specifier. + // + // # Event: + // * NetworkAdded; + // - On successfully creation of a network. + // + // # Raises: + // * 'NetworkExist': + // - Attempting to register an already existing. + // + // * 'InvalidModality': + // - Attempting to register a network with an invalid modality. + // + // * 'InvalidTempo': + // - Attempting to register a network with an invalid tempo. + // + #[pallet::call_index(9)] + #[pallet::weight((Weight::from_ref_time(50_000_000) .saturating_add(T::DbWeight::get().reads(17)) .saturating_add(T::DbWeight::get().writes(20)), DispatchClass::Operational, Pays::No))] - pub fn sudo_add_network( - origin: OriginFor, - netuid: u16, - tempo: u16, - modality: u16 - ) -> DispatchResultWithPostInfo { - Self::do_add_network(origin, netuid, tempo, modality) - } - - // ---- Sudo remove a network from the network set. - // # Args: - // * 'origin': (Origin): - // - Must be sudo. - // - // * 'netuid' (u16): - // - The u16 network identifier. - // - // # Event: - // * NetworkRemoved; - // - On the successfull removing of this network. - // - // # Raises: - // * 'NetworkDoesNotExist': - // - Attempting to remove a non existent network. - // - #[pallet::call_index(10)] - #[pallet::weight((Weight::from_ref_time(42_000_000) + pub fn sudo_add_network( + origin: OriginFor, + netuid: u16, + tempo: u16, + modality: u16, + ) -> DispatchResultWithPostInfo { + Self::do_add_network(origin, netuid, tempo, modality) + } + + // ---- Sudo remove a network from the network set. + // # Args: + // * 'origin': (Origin): + // - Must be sudo. + // + // * 'netuid' (u16): + // - The u16 network identifier. + // + // # Event: + // * NetworkRemoved; + // - On the successfull removing of this network. + // + // # Raises: + // * 'NetworkDoesNotExist': + // - Attempting to remove a non existent network. + // + #[pallet::call_index(10)] + #[pallet::weight((Weight::from_ref_time(42_000_000) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(31)), DispatchClass::Operational, Pays::No))] - pub fn sudo_remove_network( - origin: OriginFor, - netuid: u16 - ) -> DispatchResult { - Self::do_remove_network(origin, netuid) - } - - // ---- Sudo set emission values for all networks. - // Args: - // * 'origin': (Origin): - // - The caller, must be sudo. - // - // * `netuids` (Vec): - // - A vector of network uids values. This must include all netuids. - // - // * `emission` (Vec): - // - The emission values associated with passed netuids in order. - // - #[pallet::call_index(11)] - #[pallet::weight((Weight::from_ref_time(28_000_000) + pub fn sudo_remove_network(origin: OriginFor, netuid: u16) -> DispatchResult { + Self::do_remove_network(origin, netuid) + } + + // ---- Sudo set emission values for all networks. + // Args: + // * 'origin': (Origin): + // - The caller, must be sudo. + // + // * `netuids` (Vec): + // - A vector of network uids values. This must include all netuids. + // + // * `emission` (Vec): + // - The emission values associated with passed netuids in order. + // + #[pallet::call_index(11)] + #[pallet::weight((Weight::from_ref_time(28_000_000) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(10)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_emission_values( - origin: OriginFor, - netuids: Vec, - emission: Vec, - ) -> DispatchResult { - Self::do_set_emission_values( - origin, - netuids, - emission - ) - } - - // ---- Sudo add a network connect requirement. - // Args: - // * 'origin': (Origin): - // - The caller, must be sudo. - // - // * `netuid_a` (u16): - // - The network we are adding the requirment to (parent network) - // - // * `netuid_b` (u16): - // - The network we the requirement refers to (child network) - // - // * `requirement` (u16): - // - The topk percentile prunning score requirement (u16:MAX normalized.) - // - #[pallet::call_index(12)] - #[pallet::weight((Weight::from_ref_time(17_000_000) + pub fn sudo_set_emission_values( + origin: OriginFor, + netuids: Vec, + emission: Vec, + ) -> DispatchResult { + Self::do_set_emission_values(origin, netuids, emission) + } + + // ---- Sudo add a network connect requirement. + // Args: + // * 'origin': (Origin): + // - The caller, must be sudo. + // + // * `netuid_a` (u16): + // - The network we are adding the requirment to (parent network) + // + // * `netuid_b` (u16): + // - The network we the requirement refers to (child network) + // + // * `requirement` (u16): + // - The topk percentile prunning score requirement (u16:MAX normalized.) + // + #[pallet::call_index(12)] + #[pallet::weight((Weight::from_ref_time(17_000_000) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_add_network_connection_requirement( origin:OriginFor, netuid_a: u16, netuid_b: u16, requirement: u16 ) -> DispatchResult { - Self::do_sudo_add_network_connection_requirement( origin, netuid_a, netuid_b, requirement ) - } - - // ---- Sudo remove a network connection requirement. - // Args: - // * 'origin': (Origin): - // - The caller, must be sudo. - // - // * `netuid_a` (u16): - // - The network we are removing the requirment from. - // - // * `netuid_b` (u16): - // - The required network connection to remove. - // - #[pallet::call_index(13)] - #[pallet::weight((Weight::from_ref_time(15_000_000) + pub fn sudo_add_network_connection_requirement( + origin: OriginFor, + netuid_a: u16, + netuid_b: u16, + requirement: u16, + ) -> DispatchResult { + Self::do_sudo_add_network_connection_requirement( + origin, + netuid_a, + netuid_b, + requirement, + ) + } + + // ---- Sudo remove a network connection requirement. + // Args: + // * 'origin': (Origin): + // - The caller, must be sudo. + // + // * `netuid_a` (u16): + // - The network we are removing the requirment from. + // + // * `netuid_b` (u16): + // - The required network connection to remove. + // + #[pallet::call_index(13)] + #[pallet::weight((Weight::from_ref_time(15_000_000) .saturating_add(T::DbWeight::get().reads(3)), DispatchClass::Operational, Pays::No))] - pub fn sudo_remove_network_connection_requirement( origin:OriginFor, netuid_a: u16, netuid_b: u16 ) -> DispatchResult { - Self::do_sudo_remove_network_connection_requirement( origin, netuid_a, netuid_b ) - } - - // ================================== - // ==== 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. - // - #[pallet::call_index(14)] - #[pallet::weight((Weight::from_ref_time(11_000_000) + pub fn sudo_remove_network_connection_requirement( + origin: OriginFor, + netuid_a: u16, + netuid_b: u16, + ) -> DispatchResult { + Self::do_sudo_remove_network_connection_requirement(origin, netuid_a, netuid_b) + } + + // ================================== + // ==== 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. + // + #[pallet::call_index(14)] + #[pallet::weight((Weight::from_ref_time(11_000_000) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_default_take( origin:OriginFor, default_take: u16 ) -> DispatchResult { - Self::do_sudo_set_default_take( origin, default_take ) - } + pub fn sudo_set_default_take(origin: OriginFor, default_take: u16) -> DispatchResult { + Self::do_sudo_set_default_take(origin, default_take) + } - #[pallet::call_index(15)] - #[pallet::weight((Weight::from_ref_time(10_000_000) + #[pallet::call_index(15)] + #[pallet::weight((Weight::from_ref_time(10_000_000) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_serving_rate_limit( origin:OriginFor, netuid: u16, serving_rate_limit: u64 ) -> DispatchResult { - Self::do_sudo_set_serving_rate_limit( origin, netuid, serving_rate_limit ) - } - - // Sudo call for setting tx rate limit - #[pallet::call_index(16)] - #[pallet::weight((0, DispatchClass::Operational, Pays::No))] - pub fn sudo_set_tx_rate_limit( origin:OriginFor, tx_rate_limit: u64 ) -> DispatchResult { - Self::do_sudo_set_tx_rate_limit( origin, tx_rate_limit ) - } - - #[pallet::call_index(17)] - #[pallet::weight((0, DispatchClass::Operational, Pays::No))] - pub fn sudo_set_max_burn( origin:OriginFor, netuid: u16, max_burn: u64 ) -> DispatchResult { - Self::do_sudo_set_max_burn( origin, netuid, max_burn ) - } - - #[pallet::call_index(18)] - #[pallet::weight((Weight::from_ref_time(13_000_000) + pub fn sudo_set_serving_rate_limit( + origin: OriginFor, + netuid: u16, + serving_rate_limit: u64, + ) -> DispatchResult { + Self::do_sudo_set_serving_rate_limit(origin, netuid, serving_rate_limit) + } + + // Sudo call for setting tx rate limit + #[pallet::call_index(16)] + #[pallet::weight((0, DispatchClass::Operational, Pays::No))] + pub fn sudo_set_tx_rate_limit(origin: OriginFor, tx_rate_limit: u64) -> DispatchResult { + Self::do_sudo_set_tx_rate_limit(origin, tx_rate_limit) + } + + #[pallet::call_index(17)] + #[pallet::weight((0, DispatchClass::Operational, Pays::No))] + pub fn sudo_set_max_burn( + origin: OriginFor, + netuid: u16, + max_burn: u64, + ) -> DispatchResult { + Self::do_sudo_set_max_burn(origin, netuid, max_burn) + } + + #[pallet::call_index(18)] + #[pallet::weight((Weight::from_ref_time(13_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_min_burn( origin:OriginFor, netuid: u16, min_burn: u64 ) -> DispatchResult { - Self::do_sudo_set_min_burn( origin, netuid, min_burn ) - } + pub fn sudo_set_min_burn( + origin: OriginFor, + netuid: u16, + min_burn: u64, + ) -> DispatchResult { + Self::do_sudo_set_min_burn(origin, netuid, min_burn) + } - #[pallet::call_index(19)] - #[pallet::weight((Weight::from_ref_time(14_000_000) + #[pallet::call_index(19)] + #[pallet::weight((Weight::from_ref_time(14_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_burn( origin:OriginFor, netuid: u16, burn: u64 ) -> DispatchResult { - Self::do_sudo_set_burn( origin, netuid, burn ) - } + pub fn sudo_set_burn(origin: OriginFor, netuid: u16, burn: u64) -> DispatchResult { + Self::do_sudo_set_burn(origin, netuid, burn) + } - #[pallet::call_index(20)] - #[pallet::weight((Weight::from_ref_time(14_000_000) + #[pallet::call_index(20)] + #[pallet::weight((Weight::from_ref_time(14_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_max_difficulty( origin:OriginFor, netuid: u16, max_difficulty: u64 ) -> DispatchResult { - Self::do_sudo_set_max_difficulty( origin, netuid, max_difficulty ) - } + pub fn sudo_set_max_difficulty( + origin: OriginFor, + netuid: u16, + max_difficulty: u64, + ) -> DispatchResult { + Self::do_sudo_set_max_difficulty(origin, netuid, max_difficulty) + } - #[pallet::call_index(21)] - #[pallet::weight((Weight::from_ref_time(14_000_000) + #[pallet::call_index(21)] + #[pallet::weight((Weight::from_ref_time(14_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_min_difficulty( origin:OriginFor, netuid: u16, min_difficulty: u64 ) -> DispatchResult { - Self::do_sudo_set_min_difficulty( origin, netuid, min_difficulty ) - } + pub fn sudo_set_min_difficulty( + origin: OriginFor, + netuid: u16, + min_difficulty: u64, + ) -> DispatchResult { + Self::do_sudo_set_min_difficulty(origin, netuid, min_difficulty) + } - #[pallet::call_index(22)] - #[pallet::weight((Weight::from_ref_time(15_000_000) + #[pallet::call_index(22)] + #[pallet::weight((Weight::from_ref_time(15_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_weights_set_rate_limit( origin:OriginFor, netuid: u16, weights_set_rate_limit: u64 ) -> DispatchResult { - Self::do_sudo_set_weights_set_rate_limit( origin, netuid, weights_set_rate_limit ) - } + pub fn sudo_set_weights_set_rate_limit( + origin: OriginFor, + netuid: u16, + weights_set_rate_limit: u64, + ) -> DispatchResult { + Self::do_sudo_set_weights_set_rate_limit(origin, netuid, weights_set_rate_limit) + } - #[pallet::call_index(23)] - #[pallet::weight((Weight::from_ref_time(14_000_000) + #[pallet::call_index(23)] + #[pallet::weight((Weight::from_ref_time(14_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_weights_version_key( origin:OriginFor, netuid: u16, weights_version_key: u64 ) -> DispatchResult { - Self::do_sudo_set_weights_version_key( origin, netuid, weights_version_key ) - } + pub fn sudo_set_weights_version_key( + origin: OriginFor, + netuid: u16, + weights_version_key: u64, + ) -> DispatchResult { + Self::do_sudo_set_weights_version_key(origin, netuid, weights_version_key) + } - #[pallet::call_index(24)] - #[pallet::weight((Weight::from_ref_time(14_000_000) + #[pallet::call_index(24)] + #[pallet::weight((Weight::from_ref_time(14_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_bonds_moving_average( origin:OriginFor, netuid: u16, bonds_moving_average: u64 ) -> DispatchResult { - Self::do_sudo_set_bonds_moving_average( origin, netuid, bonds_moving_average ) - } + pub fn sudo_set_bonds_moving_average( + origin: OriginFor, + netuid: u16, + bonds_moving_average: u64, + ) -> DispatchResult { + Self::do_sudo_set_bonds_moving_average(origin, netuid, bonds_moving_average) + } - #[pallet::call_index(25)] - #[pallet::weight((Weight::from_ref_time(14_000_000) + #[pallet::call_index(25)] + #[pallet::weight((Weight::from_ref_time(14_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_max_allowed_validators( origin:OriginFor, netuid: u16, max_allowed_validators: u16 ) -> DispatchResult { - Self::do_sudo_set_max_allowed_validators( origin, netuid, max_allowed_validators ) - } + pub fn sudo_set_max_allowed_validators( + origin: OriginFor, + netuid: u16, + max_allowed_validators: u16, + ) -> DispatchResult { + Self::do_sudo_set_max_allowed_validators(origin, netuid, max_allowed_validators) + } - #[pallet::call_index(26)] - #[pallet::weight((Weight::from_ref_time(13_000_000) + #[pallet::call_index(26)] + #[pallet::weight((Weight::from_ref_time(13_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_difficulty( origin:OriginFor, netuid: u16, difficulty: u64 ) -> DispatchResult { - Self::do_sudo_set_difficulty( origin, netuid, difficulty ) - } + pub fn sudo_set_difficulty( + origin: OriginFor, + netuid: u16, + difficulty: u64, + ) -> DispatchResult { + Self::do_sudo_set_difficulty(origin, netuid, difficulty) + } - #[pallet::call_index(27)] - #[pallet::weight((Weight::from_ref_time(14_000_000) + #[pallet::call_index(27)] + #[pallet::weight((Weight::from_ref_time(14_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_adjustment_interval( origin:OriginFor, netuid: u16, adjustment_interval: u16 ) -> DispatchResult { - Self::do_sudo_set_adjustment_interval( origin, netuid, adjustment_interval ) - } + pub fn sudo_set_adjustment_interval( + origin: OriginFor, + netuid: u16, + adjustment_interval: u16, + ) -> DispatchResult { + Self::do_sudo_set_adjustment_interval(origin, netuid, adjustment_interval) + } - #[pallet::call_index(28)] - #[pallet::weight((Weight::from_ref_time(14_000_000) + #[pallet::call_index(28)] + #[pallet::weight((Weight::from_ref_time(14_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_target_registrations_per_interval( origin:OriginFor, netuid: u16, target_registrations_per_interval: u16 ) -> DispatchResult { - Self::do_sudo_set_target_registrations_per_interval( origin, netuid, target_registrations_per_interval ) - } + pub fn sudo_set_target_registrations_per_interval( + origin: OriginFor, + netuid: u16, + target_registrations_per_interval: u16, + ) -> DispatchResult { + Self::do_sudo_set_target_registrations_per_interval( + origin, + netuid, + target_registrations_per_interval, + ) + } - #[pallet::call_index(29)] - #[pallet::weight((Weight::from_ref_time(13_000_000) + #[pallet::call_index(29)] + #[pallet::weight((Weight::from_ref_time(13_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_activity_cutoff( origin:OriginFor, netuid: u16, activity_cutoff: u16 ) -> DispatchResult { - Self::do_sudo_set_activity_cutoff( origin, netuid, activity_cutoff ) - } + pub fn sudo_set_activity_cutoff( + origin: OriginFor, + netuid: u16, + activity_cutoff: u16, + ) -> DispatchResult { + Self::do_sudo_set_activity_cutoff(origin, netuid, activity_cutoff) + } - #[pallet::call_index(30)] - #[pallet::weight((Weight::from_ref_time(14_000_000) + #[pallet::call_index(30)] + #[pallet::weight((Weight::from_ref_time(14_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_rho( origin:OriginFor, netuid: u16, rho: u16 ) -> DispatchResult { - Self::do_sudo_set_rho( origin, netuid, rho ) - } + pub fn sudo_set_rho(origin: OriginFor, netuid: u16, rho: u16) -> DispatchResult { + Self::do_sudo_set_rho(origin, netuid, rho) + } - #[pallet::call_index(31)] - #[pallet::weight(( Weight::from_ref_time(14_000_000) + #[pallet::call_index(31)] + #[pallet::weight(( Weight::from_ref_time(14_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_kappa( origin:OriginFor, netuid: u16, kappa: u16 ) -> DispatchResult { - Self::do_sudo_set_kappa( origin, netuid, kappa ) - } + pub fn sudo_set_kappa(origin: OriginFor, netuid: u16, kappa: u16) -> DispatchResult { + Self::do_sudo_set_kappa(origin, netuid, kappa) + } - #[pallet::call_index(32)] - #[pallet::weight((Weight::from_ref_time(18_000_000) + #[pallet::call_index(32)] + #[pallet::weight((Weight::from_ref_time(18_000_000) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_max_allowed_uids( origin:OriginFor, netuid: u16, max_allowed_uids: u16 ) -> DispatchResult { - Self::do_sudo_set_max_allowed_uids(origin, netuid, max_allowed_uids ) - } + pub fn sudo_set_max_allowed_uids( + origin: OriginFor, + netuid: u16, + max_allowed_uids: u16, + ) -> DispatchResult { + Self::do_sudo_set_max_allowed_uids(origin, netuid, max_allowed_uids) + } - #[pallet::call_index(33)] - #[pallet::weight((Weight::from_ref_time(13_000_000) + #[pallet::call_index(33)] + #[pallet::weight((Weight::from_ref_time(13_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_min_allowed_weights( origin:OriginFor, netuid: u16, min_allowed_weights: u16 ) -> DispatchResult { - Self::do_sudo_set_min_allowed_weights( origin, netuid, min_allowed_weights ) - } + pub fn sudo_set_min_allowed_weights( + origin: OriginFor, + netuid: u16, + min_allowed_weights: u16, + ) -> DispatchResult { + Self::do_sudo_set_min_allowed_weights(origin, netuid, min_allowed_weights) + } - #[pallet::call_index(38)] - #[pallet::weight((Weight::from_ref_time(14_000_000) + #[pallet::call_index(38)] + #[pallet::weight((Weight::from_ref_time(14_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_validator_prune_len( origin:OriginFor, netuid: u16, validator_prune_len: u64 ) -> DispatchResult { - Self::do_sudo_set_validator_prune_len( origin, netuid, validator_prune_len ) - } + pub fn sudo_set_validator_prune_len( + origin: OriginFor, + netuid: u16, + validator_prune_len: u64, + ) -> DispatchResult { + Self::do_sudo_set_validator_prune_len(origin, netuid, validator_prune_len) + } - #[pallet::call_index(41)] - #[pallet::weight((Weight::from_ref_time(13_000_000) + #[pallet::call_index(41)] + #[pallet::weight((Weight::from_ref_time(13_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_scaling_law_power( origin:OriginFor, netuid: u16, scaling_law_power: u16 ) -> DispatchResult { - Self::do_sudo_set_scaling_law_power( origin, netuid, scaling_law_power ) - } + pub fn sudo_set_scaling_law_power( + origin: OriginFor, + netuid: u16, + scaling_law_power: u16, + ) -> DispatchResult { + Self::do_sudo_set_scaling_law_power(origin, netuid, scaling_law_power) + } - #[pallet::call_index(43)] - #[pallet::weight((Weight::from_ref_time(13_000_000) + #[pallet::call_index(43)] + #[pallet::weight((Weight::from_ref_time(13_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_immunity_period( origin:OriginFor, netuid: u16, immunity_period: u16 ) -> DispatchResult { - Self::do_sudo_set_immunity_period( origin, netuid, immunity_period ) - } + pub fn sudo_set_immunity_period( + origin: OriginFor, + netuid: u16, + immunity_period: u16, + ) -> DispatchResult { + Self::do_sudo_set_immunity_period(origin, netuid, immunity_period) + } - #[pallet::call_index(44)] - #[pallet::weight((Weight::from_ref_time(13_000_000) + #[pallet::call_index(44)] + #[pallet::weight((Weight::from_ref_time(13_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_max_weight_limit( origin:OriginFor, netuid: u16, max_weight_limit: u16 ) -> DispatchResult { - Self::do_sudo_set_max_weight_limit( origin, netuid, max_weight_limit ) - } + pub fn sudo_set_max_weight_limit( + origin: OriginFor, + netuid: u16, + max_weight_limit: u16, + ) -> DispatchResult { + Self::do_sudo_set_max_weight_limit(origin, netuid, max_weight_limit) + } - #[pallet::call_index(45)] - #[pallet::weight((Weight::from_ref_time(15_000_000) + #[pallet::call_index(45)] + #[pallet::weight((Weight::from_ref_time(15_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_max_registrations_per_block(origin: OriginFor, netuid: u16, max_registrations_per_block: u16 ) -> DispatchResult { - Self::do_sudo_set_max_registrations_per_block(origin, netuid, max_registrations_per_block ) - } - - #[pallet::call_index(46)] - #[pallet::weight((0, DispatchClass::Operational, Pays::No))] - pub fn sudo_set_total_issuance(origin: OriginFor, total_issuance: u64 ) -> DispatchResult { - Self::do_set_total_issuance(origin, total_issuance) - } - - #[pallet::call_index(47)] - #[pallet::weight((Weight::from_ref_time(15_000_000) + pub fn sudo_set_max_registrations_per_block( + origin: OriginFor, + netuid: u16, + max_registrations_per_block: u16, + ) -> DispatchResult { + Self::do_sudo_set_max_registrations_per_block( + origin, + netuid, + max_registrations_per_block, + ) + } + + #[pallet::call_index(46)] + #[pallet::weight((0, DispatchClass::Operational, Pays::No))] + pub fn sudo_set_total_issuance( + origin: OriginFor, + total_issuance: u64, + ) -> DispatchResult { + Self::do_set_total_issuance(origin, total_issuance) + } + + #[pallet::call_index(47)] + #[pallet::weight((Weight::from_ref_time(15_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_tempo(origin:OriginFor, netuid: u16, tempo: u16) -> DispatchResult { - Self::do_sudo_set_tempo(origin, netuid, tempo) - } - - #[pallet::call_index(48)] - #[pallet::weight((0, DispatchClass::Operational, Pays::No))] - pub fn sudo_set_rao_recycled(origin: OriginFor, netuid: u16, rao_recycled: u64 ) -> DispatchResult { - Self::do_set_rao_recycled(origin, netuid, rao_recycled) - } - - /// 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_ref_time(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). - #[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 { - // 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 - } - - #[pallet::call_index(53)] - #[pallet::weight((Weight::from_ref_time(67_000_000) + pub fn sudo_set_tempo(origin: OriginFor, netuid: u16, tempo: u16) -> DispatchResult { + Self::do_sudo_set_tempo(origin, netuid, tempo) + } + + #[pallet::call_index(48)] + #[pallet::weight((0, DispatchClass::Operational, Pays::No))] + pub fn sudo_set_rao_recycled( + origin: OriginFor, + netuid: u16, + rao_recycled: u64, + ) -> DispatchResult { + Self::do_set_rao_recycled(origin, netuid, rao_recycled) + } + + /// 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_ref_time(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). + #[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 { + // 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; + } + + #[pallet::call_index(53)] + #[pallet::weight((Weight::from_ref_time(67_000_000) .saturating_add(Weight::from_proof_size(61173)) .saturating_add(T::DbWeight::get().reads(20)) .saturating_add(T::DbWeight::get().writes(3)), DispatchClass::Normal, Pays::No))] - pub fn join_senate( - origin: OriginFor, - hotkey: T::AccountId - ) -> DispatchResult { - Self::do_join_senate(origin, &hotkey) - } - - #[pallet::call_index(54)] - #[pallet::weight((Weight::from_ref_time(20_000_000) + pub fn join_senate(origin: OriginFor, hotkey: T::AccountId) -> DispatchResult { + Self::do_join_senate(origin, &hotkey) + } + + #[pallet::call_index(54)] + #[pallet::weight((Weight::from_ref_time(20_000_000) .saturating_add(Weight::from_proof_size(4748)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)), DispatchClass::Normal, Pays::No))] - pub fn leave_senate( - origin: OriginFor, - hotkey: T::AccountId - ) -> DispatchResult { - Self::do_leave_senate(origin, &hotkey) - } - - #[pallet::call_index(55)] - #[pallet::weight((Weight::from_ref_time(0) + pub fn leave_senate(origin: OriginFor, hotkey: T::AccountId) -> DispatchResult { + Self::do_leave_senate(origin, &hotkey) + } + + #[pallet::call_index(55)] + #[pallet::weight((Weight::from_ref_time(0) .saturating_add(Weight::from_proof_size(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_senate(origin, &hotkey, proposal, index, approve) - } - - // Sudo call for setting registration allowed - #[pallet::call_index(49)] - #[pallet::weight((Weight::from_ref_time(4_000_000) + pub fn vote( + origin: OriginFor, + hotkey: T::AccountId, + proposal: T::Hash, + #[pallet::compact] index: u32, + approve: bool, + ) -> DispatchResultWithPostInfo { + Self::do_vote_senate(origin, &hotkey, proposal, index, approve) + } + + // Sudo call for setting registration allowed + #[pallet::call_index(49)] + #[pallet::weight((Weight::from_ref_time(4_000_000) .saturating_add(Weight::from_proof_size(0)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_registration_allowed( origin:OriginFor, netuid: u16, registration_allowed: bool ) -> DispatchResult { - Self::do_sudo_set_network_registration_allowed( origin, netuid, registration_allowed ) - } - - #[pallet::call_index(56)] - #[pallet::weight((0, DispatchClass::Operational, Pays::No))] - pub fn sudo_set_senate_required_stake_perc(origin: OriginFor, required_percent: u64 ) -> DispatchResult { - Self::do_set_senate_required_stake_perc(origin, required_percent) - } - - #[pallet::call_index(57)] - #[pallet::weight((0, DispatchClass::Operational, Pays::No))] - pub fn sudo_remove_votes(origin: OriginFor, who: T::AccountId ) -> DispatchResult { - Self::do_remove_votes(origin, &who) - } - - #[pallet::call_index(58)] - #[pallet::weight((Weight::from_ref_time(14_000_000) + pub fn sudo_set_registration_allowed( + origin: OriginFor, + netuid: u16, + registration_allowed: bool, + ) -> DispatchResult { + Self::do_sudo_set_network_registration_allowed(origin, netuid, registration_allowed) + } + + #[pallet::call_index(56)] + #[pallet::weight((0, DispatchClass::Operational, Pays::No))] + pub fn sudo_set_senate_required_stake_perc( + origin: OriginFor, + required_percent: u64, + ) -> DispatchResult { + Self::do_set_senate_required_stake_perc(origin, required_percent) + } + + #[pallet::call_index(57)] + #[pallet::weight((0, DispatchClass::Operational, Pays::No))] + pub fn sudo_remove_votes(origin: OriginFor, who: T::AccountId) -> DispatchResult { + Self::do_remove_votes(origin, &who) + } + + #[pallet::call_index(58)] + #[pallet::weight((Weight::from_ref_time(14_000_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No))] - pub fn sudo_set_adjustment_alpha( origin:OriginFor, netuid: u16, adjustment_alpha: u64 ) -> DispatchResult { - Self::do_sudo_set_adjustment_alpha( origin, netuid, adjustment_alpha ) - } - - } - - // ---- Subtensor helper functions. - impl Pallet { - // --- Returns the transaction priority for setting weights. - pub fn get_priority_set_weights( hotkey: &T::AccountId, netuid: u16 ) -> u64 { - if Uids::::contains_key( netuid, &hotkey ) { - let uid = Self::get_uid_for_net_and_hotkey(netuid, &hotkey.clone()).unwrap(); - let current_block_number: u64 = Self::get_current_block_as_u64(); - let default_priority: u64 = current_block_number - Self::get_last_update_for_uid(netuid, uid as u16); - return default_priority + u32::max_value() as u64; - } - return 0; - } - - // Benchmarking functions. - #[cfg(feature = "runtime-benchmarks")] - pub fn create_network( _: OriginFor, netuid: u16, n: u16, tempo: u16 ) -> DispatchResult { - Self::init_new_network( netuid, tempo, 1 ); - Self::set_max_allowed_uids( netuid, n ); - let mut seed : u32 = 1; - for _ in 0..n { - let block_number: u64 = Self::get_current_block_as_u64(); - let hotkey: T::AccountId = T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).unwrap(); - Self::append_neuron( netuid, &hotkey, block_number ); - seed = seed + 1; - } - Ok(()) - } - - #[cfg(feature = "runtime-benchmarks")] - pub fn create_network_with_weights( _: OriginFor, netuid: u16, n: u16, tempo: u16, n_vals: u16, n_weights: u16 ) -> DispatchResult { - Self::init_new_network( netuid, tempo, 1 ); - Self::set_max_allowed_uids( netuid, n ); - Self::set_max_allowed_validators( netuid, n_vals ); - Self::set_min_allowed_weights( netuid, n_weights ); - Self::set_emission_for_network( netuid, 1_000_000_000 ); - let mut seed : u32 = 1; - for _ in 0..n { - let block_number: u64 = Self::get_current_block_as_u64(); - let hotkey: T::AccountId = T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).unwrap(); - Self::increase_stake_on_coldkey_hotkey_account( &hotkey, &hotkey, 1_000_000_000 ); - Self::append_neuron( netuid, &hotkey, block_number ); - seed = seed + 1; - } - for uid in 0..n { - let uids: Vec = (0..n_weights).collect(); - let values: Vec = vec![1; n_weights as usize]; - let normalized_values = Self::normalize_weights( values ); - let mut zipped_weights: Vec<( u16, u16 )> = vec![]; - for ( uid, val ) in uids.iter().zip(normalized_values.iter()) { zipped_weights.push((*uid, *val)) } - if uid < n_vals { - Weights::::insert( netuid, uid, zipped_weights ); - } else { - break; - } - } - Ok(()) - } - } -} + pub fn sudo_set_adjustment_alpha( + origin: OriginFor, + netuid: u16, + adjustment_alpha: u64, + ) -> DispatchResult { + Self::do_sudo_set_adjustment_alpha(origin, netuid, adjustment_alpha) + } + } + // ---- Subtensor helper functions. + impl Pallet { + // --- Returns the transaction priority for setting weights. + pub fn get_priority_set_weights(hotkey: &T::AccountId, netuid: u16) -> u64 { + if Uids::::contains_key(netuid, &hotkey) { + let uid = Self::get_uid_for_net_and_hotkey(netuid, &hotkey.clone()).unwrap(); + let current_block_number: u64 = Self::get_current_block_as_u64(); + let default_priority: u64 = + current_block_number - Self::get_last_update_for_uid(netuid, uid as u16); + return default_priority + u32::max_value() as u64; + } + return 0; + } + + // Benchmarking functions. + #[cfg(feature = "runtime-benchmarks")] + pub fn create_network(_: OriginFor, netuid: u16, n: u16, tempo: u16) -> DispatchResult { + Self::init_new_network(netuid, tempo, 1); + Self::set_max_allowed_uids(netuid, n); + let mut seed: u32 = 1; + for _ in 0..n { + let block_number: u64 = Self::get_current_block_as_u64(); + let hotkey: T::AccountId = + T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) + .unwrap(); + Self::append_neuron(netuid, &hotkey, block_number); + seed = seed + 1; + } + Ok(()) + } + + #[cfg(feature = "runtime-benchmarks")] + pub fn create_network_with_weights( + _: OriginFor, + netuid: u16, + n: u16, + tempo: u16, + n_vals: u16, + n_weights: u16, + ) -> DispatchResult { + Self::init_new_network(netuid, tempo, 1); + Self::set_max_allowed_uids(netuid, n); + Self::set_max_allowed_validators(netuid, n_vals); + Self::set_min_allowed_weights(netuid, n_weights); + Self::set_emission_for_network(netuid, 1_000_000_000); + let mut seed: u32 = 1; + for _ in 0..n { + let block_number: u64 = Self::get_current_block_as_u64(); + let hotkey: T::AccountId = + T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) + .unwrap(); + Self::increase_stake_on_coldkey_hotkey_account(&hotkey, &hotkey, 1_000_000_000); + Self::append_neuron(netuid, &hotkey, block_number); + seed = seed + 1; + } + for uid in 0..n { + let uids: Vec = (0..n_weights).collect(); + let values: Vec = vec![1; n_weights as usize]; + let normalized_values = Self::normalize_weights(values); + let mut zipped_weights: Vec<(u16, u16)> = vec![]; + for (uid, val) in uids.iter().zip(normalized_values.iter()) { + zipped_weights.push((*uid, *val)) + } + if uid < n_vals { + Weights::::insert(netuid, uid, zipped_weights); + } else { + break; + } + } + Ok(()) + } + } +} /************************************************************ - CallType definition + CallType definition ************************************************************/ #[derive(Debug, PartialEq)] pub enum CallType { SetWeights, AddStake, RemoveStake, - AddDelegate, + AddDelegate, Register, Serve, - Other, + Other, } impl Default for CallType { fn default() -> Self { @@ -1708,97 +2057,94 @@ impl Default for CallType { #[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] pub struct SubtensorSignedExtension(pub PhantomData); -impl SubtensorSignedExtension where - T::RuntimeCall: Dispatchable, - ::RuntimeCall: IsSubType>, +impl SubtensorSignedExtension +where + T::RuntimeCall: Dispatchable, + ::RuntimeCall: IsSubType>, { - pub fn new() -> Self { - Self(Default::default()) - } - - pub fn get_priority_vanilla() -> u64 { - // Return high priority so that every extrinsic except set_weights function will - // have a higher priority than the set_weights call - return u64::max_value(); - } + pub fn new() -> Self { + Self(Default::default()) + } - pub fn get_priority_set_weights( who: &T::AccountId, netuid: u16 ) -> u64 { - // Return the non vanilla priority for a set weights call. + pub fn get_priority_vanilla() -> u64 { + // Return high priority so that every extrinsic except set_weights function will + // have a higher priority than the set_weights call + return u64::max_value(); + } - return Pallet::::get_priority_set_weights( who, netuid ); - } + pub fn get_priority_set_weights(who: &T::AccountId, netuid: u16) -> u64 { + // Return the non vanilla priority for a set weights call. - pub fn u64_to_balance( input: u64 ) -> Option<<::Currency as Currency<::AccountId>>::Balance> { input.try_into().ok() } + return Pallet::::get_priority_set_weights(who, netuid); + } + pub fn u64_to_balance( + input: u64, + ) -> Option< + <::Currency as Currency<::AccountId>>::Balance, + > { + input.try_into().ok() + } } -impl sp_std::fmt::Debug for SubtensorSignedExtension { - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - write!(f, "SubtensorSignedExtension") - } +impl sp_std::fmt::Debug for SubtensorSignedExtension { + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + write!(f, "SubtensorSignedExtension") + } } impl SignedExtension for SubtensorSignedExtension - where - T::RuntimeCall: Dispatchable, - ::RuntimeCall: IsSubType>, +where + T::RuntimeCall: Dispatchable, + ::RuntimeCall: IsSubType>, { - const IDENTIFIER: &'static str = "SubtensorSignedExtension"; - - type AccountId = T::AccountId; - type Call = T::RuntimeCall; - type AdditionalSigned = (); - type Pre = (CallType, u64, Self::AccountId); - - fn additional_signed( &self ) -> Result { - Ok(()) - } - - - fn validate( - &self, - who: &Self::AccountId, - call: &Self::Call, - _info: &DispatchInfoOf, - _len: usize, - ) -> TransactionValidity { - match call.is_sub_type() { - Some(Call::set_weights{netuid, ..}) => { - let priority: u64 = Self::get_priority_set_weights(who, *netuid); + const IDENTIFIER: &'static str = "SubtensorSignedExtension"; + + type AccountId = T::AccountId; + type Call = T::RuntimeCall; + type AdditionalSigned = (); + type Pre = (CallType, u64, Self::AccountId); + + fn additional_signed(&self) -> Result { + Ok(()) + } + + fn validate( + &self, + who: &Self::AccountId, + call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> TransactionValidity { + match call.is_sub_type() { + Some(Call::set_weights { netuid, .. }) => { + let priority: u64 = Self::get_priority_set_weights(who, *netuid); Ok(ValidTransaction { priority: priority, longevity: 1, ..Default::default() }) } - Some(Call::add_stake{..}) => { - Ok(ValidTransaction { - priority: Self::get_priority_vanilla(), - ..Default::default() - }) - } - Some(Call::remove_stake{..}) => { - Ok(ValidTransaction { - priority: Self::get_priority_vanilla(), - ..Default::default() - }) - } - Some(Call::register{..}) => { - Ok(ValidTransaction { - priority: Self::get_priority_vanilla(), - ..Default::default() - }) - } - _ => { - Ok(ValidTransaction { - priority: Self::get_priority_vanilla(), - ..Default::default() - }) - } - } - } + Some(Call::add_stake { .. }) => Ok(ValidTransaction { + priority: Self::get_priority_vanilla(), + ..Default::default() + }), + Some(Call::remove_stake { .. }) => Ok(ValidTransaction { + priority: Self::get_priority_vanilla(), + ..Default::default() + }), + Some(Call::register { .. }) => Ok(ValidTransaction { + priority: Self::get_priority_vanilla(), + ..Default::default() + }), + _ => Ok(ValidTransaction { + priority: Self::get_priority_vanilla(), + ..Default::default() + }), + } + } - // NOTE: Add later when we put in a pre and post dispatch step. + // NOTE: Add later when we put in a pre and post dispatch step. fn pre_dispatch( self, who: &Self::AccountId, @@ -1806,119 +2152,137 @@ impl SignedExtension for SubtensorSignedExte _info: &DispatchInfoOf, _len: usize, ) -> Result { - match call.is_sub_type() { - Some(Call::add_stake{..}) => { - let transaction_fee = 100000; + Some(Call::add_stake { .. }) => { + let transaction_fee = 100000; Ok((CallType::AddStake, transaction_fee, who.clone())) } - Some(Call::remove_stake{..}) => { - let transaction_fee = 0; + Some(Call::remove_stake { .. }) => { + let transaction_fee = 0; Ok((CallType::RemoveStake, transaction_fee, who.clone())) } - Some(Call::set_weights{..}) => { - let transaction_fee = 0; - Ok((CallType::SetWeights, transaction_fee, who.clone())) + Some(Call::set_weights { .. }) => { + let transaction_fee = 0; + Ok((CallType::SetWeights, transaction_fee, who.clone())) } - Some(Call::register{..}) => { + Some(Call::register { .. }) => { let transaction_fee = 0; Ok((CallType::Register, transaction_fee, who.clone())) } - Some(Call::serve_axon{..}) => { + Some(Call::serve_axon { .. }) => { let transaction_fee = 0; Ok((CallType::Serve, transaction_fee, who.clone())) } _ => { - let transaction_fee = 0; + let transaction_fee = 0; Ok((CallType::Other, transaction_fee, who.clone())) } } } - fn post_dispatch( + fn post_dispatch( maybe_pre: Option, _info: &DispatchInfoOf, _post_info: &PostDispatchInfoOf, _len: usize, _result: &dispatch::DispatchResult, ) -> Result<(), TransactionValidityError> { - - if let Some((call_type, _transaction_fee, _who)) = maybe_pre { - match call_type { - CallType::SetWeights => { - log::debug!("Not Implemented!"); - } - CallType::AddStake => { - log::debug!("Not Implemented! Need to add potential transaction fees here."); - } - CallType::RemoveStake => { - log::debug!("Not Implemented! Need to add potential transaction fees here."); - } - CallType::Register => { - log::debug!("Not Implemented!"); - } - _ => { - log::debug!("Not Implemented!"); - } - } - } - Ok(()) + if let Some((call_type, _transaction_fee, _who)) = maybe_pre { + match call_type { + CallType::SetWeights => { + log::debug!("Not Implemented!"); + } + CallType::AddStake => { + log::debug!("Not Implemented! Need to add potential transaction fees here."); + } + CallType::RemoveStake => { + log::debug!("Not Implemented! Need to add potential transaction fees here."); + } + CallType::Register => { + log::debug!("Not Implemented!"); + } + _ => { + log::debug!("Not Implemented!"); + } + } + } + Ok(()) } - } use frame_support::{inherent::Vec, sp_std::vec}; /// Trait for managing a membership pallet instance in the runtime pub trait MemberManagement { - /// Add member - fn add_member(account: &AccountId) -> DispatchResult; + /// Add member + fn add_member(account: &AccountId) -> DispatchResult; - /// Remove a member - fn remove_member(account: &AccountId) -> DispatchResult; + /// Remove a member + fn remove_member(account: &AccountId) -> DispatchResult; - /// Swap member - fn swap_member(remove: &AccountId, add: &AccountId) -> DispatchResult; + /// Swap member + fn swap_member(remove: &AccountId, add: &AccountId) -> DispatchResult; - /// Get all members - fn members() -> Vec; + /// Get all members + fn members() -> Vec; - /// Check if an account is apart of the set - fn is_member(account: &AccountId) -> bool; + /// Check if an account is apart of the set + fn is_member(account: &AccountId) -> bool; - /// Get our maximum member count - fn max_members() -> u32; + /// Get our maximum member count + fn max_members() -> u32; } impl MemberManagement for () { - /// Add member - fn add_member(_: &T) -> DispatchResult {Ok(())} + /// Add member + fn add_member(_: &T) -> DispatchResult { + Ok(()) + } - // Remove a member - fn remove_member(_: &T) -> DispatchResult {Ok(())} + // Remove a member + fn remove_member(_: &T) -> DispatchResult { + Ok(()) + } - // Swap member - fn swap_member(_: &T, _: &T) -> DispatchResult {Ok(())} + // Swap member + fn swap_member(_: &T, _: &T) -> DispatchResult { + Ok(()) + } - // Get all members - fn members() -> Vec {vec![]} + // Get all members + fn members() -> Vec { + vec![] + } - // Check if an account is apart of the set - fn is_member(_: &T) -> bool {false} + // Check if an account is apart of the set + fn is_member(_: &T) -> bool { + false + } - fn max_members() -> u32 {0} + fn max_members() -> u32 { + 0 + } } /// Trait for interacting with collective pallets pub trait CollectiveInterface { - /// Remove vote - fn remove_votes(hotkey: &AccountId) -> Result; - - fn add_vote(hotkey: &AccountId, proposal: Hash, index: ProposalIndex, approve: bool) -> Result; + /// Remove vote + fn remove_votes(hotkey: &AccountId) -> Result; + + fn add_vote( + hotkey: &AccountId, + proposal: Hash, + index: ProposalIndex, + approve: bool, + ) -> Result; } impl CollectiveInterface for () { - fn remove_votes(_: &T) -> Result {Ok(true)} + fn remove_votes(_: &T) -> Result { + Ok(true) + } - fn add_vote(_: &T, _: H, _: P, _: bool) -> Result {Ok(true)} -} \ No newline at end of file + fn add_vote(_: &T, _: H, _: P, _: bool) -> Result { + Ok(true) + } +} diff --git a/pallets/subtensor/tests/batch_tx.rs b/pallets/subtensor/tests/batch_tx.rs index f856c93425..0aaa2d1dd6 100644 --- a/pallets/subtensor/tests/batch_tx.rs +++ b/pallets/subtensor/tests/batch_tx.rs @@ -16,20 +16,16 @@ fn test_batch_txs() { ]; test_ext_with_balances(initial_balances).execute_with(|| { assert_ok!(Utility::batch( - <::RuntimeOrigin>::signed(alice), + <::RuntimeOrigin>::signed(alice), vec![ - RuntimeCall::Balances( - BalanceCall::transfer{ - dest: bob, - value: 1_000_000_000 - } - ), - RuntimeCall::Balances( - BalanceCall::transfer{ - dest: charlie, - value: 1_000_000_000 - } - ) + RuntimeCall::Balances(BalanceCall::transfer { + dest: bob, + value: 1_000_000_000 + }), + RuntimeCall::Balances(BalanceCall::transfer { + dest: charlie, + value: 1_000_000_000 + }) ] )); assert_eq!(Balances::total_balance(&alice), 6_000_000_000); diff --git a/pallets/subtensor/tests/block_step.rs b/pallets/subtensor/tests/block_step.rs index a0c9739280..d87cbf286a 100644 --- a/pallets/subtensor/tests/block_step.rs +++ b/pallets/subtensor/tests/block_step.rs @@ -6,79 +6,119 @@ use sp_core::U256; #[test] fn test_loaded_emission() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let n: u16 = 100; let netuid: u16 = 0; let tempo: u16 = 10; let netuids: Vec = vec![0]; - let emission: Vec = vec![1000000000]; - add_network( netuid, tempo, 0 ); - SubtensorModule::set_max_allowed_uids( netuid, n ); - assert_ok!(SubtensorModule::do_set_emission_values(<::RuntimeOrigin>::root(), netuids, emission)); - for i in 0..n {SubtensorModule::append_neuron( netuid, &U256::from(i), 0 );} - assert!( !SubtensorModule::has_loaded_emission_tuples( netuid ) ); + let emission: Vec = vec![1000000000]; + add_network(netuid, tempo, 0); + SubtensorModule::set_max_allowed_uids(netuid, n); + assert_ok!(SubtensorModule::do_set_emission_values( + <::RuntimeOrigin>::root(), + netuids, + emission + )); + for i in 0..n { + SubtensorModule::append_neuron(netuid, &U256::from(i), 0); + } + assert!(!SubtensorModule::has_loaded_emission_tuples(netuid)); // Try loading at block 0 let block: u64 = 0; - assert_eq!( SubtensorModule::blocks_until_next_epoch( netuid, tempo, block ), 9 ); - SubtensorModule::generate_emission( block ); - assert!( !SubtensorModule::has_loaded_emission_tuples( netuid ) ); + assert_eq!( + SubtensorModule::blocks_until_next_epoch(netuid, tempo, block), + 9 + ); + SubtensorModule::generate_emission(block); + assert!(!SubtensorModule::has_loaded_emission_tuples(netuid)); // Try loading at block = 9; let block: u64 = 9; - assert_eq!( SubtensorModule::blocks_until_next_epoch( netuid, tempo, block ), 0 ); - SubtensorModule::generate_emission( block ); - assert!( SubtensorModule::has_loaded_emission_tuples( netuid ) ); - assert_eq!( SubtensorModule::get_loaded_emission_tuples( netuid ).len(), n as usize ); + assert_eq!( + SubtensorModule::blocks_until_next_epoch(netuid, tempo, block), + 0 + ); + SubtensorModule::generate_emission(block); + assert!(SubtensorModule::has_loaded_emission_tuples(netuid)); + assert_eq!( + SubtensorModule::get_loaded_emission_tuples(netuid).len(), + n as usize + ); // Try draining the emission tuples // None remaining because we are at epoch. let block: u64 = 9; - SubtensorModule::drain_emission( block ); - assert!( !SubtensorModule::has_loaded_emission_tuples( netuid ) ); + SubtensorModule::drain_emission(block); + assert!(!SubtensorModule::has_loaded_emission_tuples(netuid)); // Generate more emission. - SubtensorModule::generate_emission( 9 ); - assert_eq!( SubtensorModule::get_loaded_emission_tuples( netuid ).len(), n as usize ); - + SubtensorModule::generate_emission(9); + assert_eq!( + SubtensorModule::get_loaded_emission_tuples(netuid).len(), + n as usize + ); + for block in 10..20 { let mut n_remaining: usize = 0; let mut n_to_drain: usize = 0; - if SubtensorModule::has_loaded_emission_tuples( netuid ) { - n_remaining = SubtensorModule::get_loaded_emission_tuples( netuid ).len(); - n_to_drain = SubtensorModule::tuples_to_drain_this_block( netuid, tempo, block, SubtensorModule::get_loaded_emission_tuples( netuid ).len() ); + if SubtensorModule::has_loaded_emission_tuples(netuid) { + n_remaining = SubtensorModule::get_loaded_emission_tuples(netuid).len(); + n_to_drain = SubtensorModule::tuples_to_drain_this_block( + netuid, + tempo, + block, + SubtensorModule::get_loaded_emission_tuples(netuid).len(), + ); } - SubtensorModule::drain_emission( block ); // drain it with 9 more blocks to go - if SubtensorModule::has_loaded_emission_tuples( netuid ) { - assert_eq!( SubtensorModule::get_loaded_emission_tuples( netuid ).len(), n_remaining - n_to_drain ); + SubtensorModule::drain_emission(block); // drain it with 9 more blocks to go + if SubtensorModule::has_loaded_emission_tuples(netuid) { + assert_eq!( + SubtensorModule::get_loaded_emission_tuples(netuid).len(), + n_remaining - n_to_drain + ); } - log::info!( "n_to_drain:{:?}", n_to_drain.clone() ); - log::info!( "SubtensorModule::get_loaded_emission_tuples( netuid ).len():{:?}", n_remaining - n_to_drain ); + log::info!("n_to_drain:{:?}", n_to_drain.clone()); + 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().execute_with(|| { +fn test_tuples_to_drain_this_block() { + new_test_ext().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 + 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 ); + for l in 0..10 { + assert!(SubtensorModule::tuples_to_drain_this_block(i, j, k, l) <= 10); } } } @@ -86,549 +126,672 @@ fn test_tuples_to_drain_this_block(){ }) } - #[test] -fn test_blocks_until_epoch(){ - new_test_ext().execute_with(|| { - +fn test_blocks_until_epoch() { + new_test_ext().execute_with(|| { // Check tempo = 0 block = * netuid = * - assert_eq!( SubtensorModule::blocks_until_next_epoch( 0, 0, 0 ), 1000 ); + 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 { + 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 ); + 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 ); + 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 as u16 { + for netuid in 0..30 as u16 { for block in 0..30 as u64 { for tempo in 1..30 as u16 { - assert_eq!( SubtensorModule::blocks_until_next_epoch( netuid, tempo, block ), tempo as u64 - ( block + netuid as u64 + 1 ) % ( tempo as u64 + 1 ) ); + 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 + block_step::adjust_registration_terms_for_networks tests *********************************************/ #[test] fn test_burn_adjustment() { - new_test_ext().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; - SubtensorModule::set_burn( netuid, burn_cost); - SubtensorModule::set_adjustment_interval( netuid, adjustment_interval ); - SubtensorModule::set_target_registrations_per_interval( netuid, target_registrations_per_interval); - add_network(netuid, tempo, 0); - - // 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); - }); + new_test_ext().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; + SubtensorModule::set_burn(netuid, burn_cost); + SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); + SubtensorModule::set_target_registrations_per_interval( + netuid, + target_registrations_per_interval, + ); + add_network(netuid, tempo, 0); + + // 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().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; - SubtensorModule::set_burn( netuid, burn_cost); - SubtensorModule::set_adjustment_interval( netuid, adjustment_interval ); - SubtensorModule::set_target_registrations_per_interval( netuid, target_registrations_per_interval); - // Set alpha here. - add_network(netuid, tempo, 0); - 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); - }); + new_test_ext().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; + SubtensorModule::set_burn(netuid, burn_cost); + SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); + SubtensorModule::set_target_registrations_per_interval( + netuid, + target_registrations_per_interval, + ); + // Set alpha here. + add_network(netuid, tempo, 0); + 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 + // 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().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; - SubtensorModule::set_burn( netuid, burn_cost); - SubtensorModule::set_difficulty(netuid, start_diff); - SubtensorModule::set_adjustment_interval( netuid, adjustment_interval ); - SubtensorModule::set_target_registrations_per_interval( netuid, target_registrations_per_interval); - add_network(netuid, tempo, 0); - - // 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); - }); + new_test_ext().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; + SubtensorModule::set_burn(netuid, burn_cost); + SubtensorModule::set_difficulty(netuid, start_diff); + SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); + SubtensorModule::set_target_registrations_per_interval( + netuid, + target_registrations_per_interval, + ); + add_network(netuid, tempo, 0); + + // 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 + // 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().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; - SubtensorModule::set_burn( netuid, burn_cost); - SubtensorModule::set_difficulty(netuid, start_diff); - SubtensorModule::set_adjustment_interval( netuid, adjustment_interval ); - SubtensorModule::set_target_registrations_per_interval( netuid, target_registrations_per_interval); - add_network(netuid, tempo, 0); - - // 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); - }); + new_test_ext().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; + SubtensorModule::set_burn(netuid, burn_cost); + SubtensorModule::set_difficulty(netuid, start_diff); + SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); + SubtensorModule::set_target_registrations_per_interval( + netuid, + target_registrations_per_interval, + ); + add_network(netuid, tempo, 0); + + // 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 + // 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().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; - SubtensorModule::set_burn( netuid, burn_cost); - SubtensorModule::set_difficulty(netuid, start_diff); - SubtensorModule::set_adjustment_interval( netuid, adjustment_interval ); - SubtensorModule::set_target_registrations_per_interval( netuid, target_registrations_per_interval); - add_network(netuid, tempo, 0); - - // 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); - }); + new_test_ext().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; + SubtensorModule::set_burn(netuid, burn_cost); + SubtensorModule::set_difficulty(netuid, start_diff); + SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); + SubtensorModule::set_target_registrations_per_interval( + netuid, + target_registrations_per_interval, + ); + add_network(netuid, tempo, 0); + + // 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 + // 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().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; - SubtensorModule::set_burn( netuid, burn_cost); - SubtensorModule::set_difficulty(netuid, start_diff); - SubtensorModule::set_adjustment_interval( netuid, adjustment_interval ); - SubtensorModule::set_target_registrations_per_interval( netuid, target_registrations_per_interval); - add_network(netuid, tempo, 0); - - // 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); - }); + new_test_ext().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; + SubtensorModule::set_burn(netuid, burn_cost); + SubtensorModule::set_difficulty(netuid, start_diff); + SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); + SubtensorModule::set_target_registrations_per_interval( + netuid, + target_registrations_per_interval, + ); + add_network(netuid, tempo, 0); + + // 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 + // 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().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; - SubtensorModule::set_max_registrations_per_block( netuid, 10 ); - SubtensorModule::set_burn( netuid, burn_cost); - SubtensorModule::set_difficulty(netuid, start_diff); - SubtensorModule::set_adjustment_interval( netuid, adjustment_interval ); - SubtensorModule::set_target_registrations_per_interval( netuid, target_registrations_per_interval); - add_network(netuid, tempo, 0); - - // 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); - }); + new_test_ext().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; + SubtensorModule::set_max_registrations_per_block(netuid, 10); + SubtensorModule::set_burn(netuid, burn_cost); + SubtensorModule::set_difficulty(netuid, start_diff); + SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); + SubtensorModule::set_target_registrations_per_interval( + netuid, + target_registrations_per_interval, + ); + add_network(netuid, tempo, 0); + + // 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 + // 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().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; - SubtensorModule::set_max_registrations_per_block( netuid, 10 ); - SubtensorModule::set_burn( netuid, burn_cost); - SubtensorModule::set_difficulty(netuid, start_diff); - SubtensorModule::set_adjustment_interval( netuid, adjustment_interval ); - SubtensorModule::set_target_registrations_per_interval( netuid, target_registrations_per_interval); - add_network(netuid, tempo, 0); - - // 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); - }); + new_test_ext().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; + SubtensorModule::set_max_registrations_per_block(netuid, 10); + SubtensorModule::set_burn(netuid, burn_cost); + SubtensorModule::set_difficulty(netuid, start_diff); + SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); + SubtensorModule::set_target_registrations_per_interval( + netuid, + target_registrations_per_interval, + ); + add_network(netuid, tempo, 0); + + // 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 + // 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().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; - SubtensorModule::set_max_registrations_per_block( netuid, 10 ); - SubtensorModule::set_burn( netuid, burn_cost); - SubtensorModule::set_difficulty(netuid, start_diff); - SubtensorModule::set_adjustment_interval( netuid, adjustment_interval ); - SubtensorModule::set_target_registrations_per_interval( netuid, target_registrations_per_interval); - add_network(netuid, tempo, 0); - - // 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); - }); + // BUT there are zero registrations this interval. + new_test_ext().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; + SubtensorModule::set_max_registrations_per_block(netuid, 10); + SubtensorModule::set_burn(netuid, burn_cost); + SubtensorModule::set_difficulty(netuid, start_diff); + SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); + SubtensorModule::set_target_registrations_per_interval( + netuid, + target_registrations_per_interval, + ); + add_network(netuid, tempo, 0); + + // 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); + }); } - - // add_network( netuid1, tempo1, 0 ); // add_network( netuid2, tempo2, 0 ); @@ -681,10 +844,9 @@ fn test_burn_adjustment_case_e_zero_registrations() { // assert_eq!( SubtensorModule::get_pending_emission( netuid1 ), 1_333_333_332 ); // assert_eq!( SubtensorModule::get_pending_emission( netuid2 ), 1_333_333_336 ); - // #[test] // fn test_nakamoto(){ -// new_test_ext().execute_with(|| { +// new_test_ext().execute_with(|| { // // Create nakamoto. // let n: u16 = 10; @@ -714,4 +876,4 @@ fn test_burn_adjustment_case_e_zero_registrations() { // } // }); -// } \ No newline at end of file +// } diff --git a/pallets/subtensor/tests/difficulty.rs b/pallets/subtensor/tests/difficulty.rs index 39d84d8733..ec26a1d434 100644 --- a/pallets/subtensor/tests/difficulty.rs +++ b/pallets/subtensor/tests/difficulty.rs @@ -1,37 +1,48 @@ -use crate::{mock::*}; +use crate::mock::*; mod mock; use sp_core::U256; #[test] #[cfg(not(tarpaulin))] fn test_registration_difficulty_adjustment() { - new_test_ext().execute_with(|| { - + new_test_ext().execute_with(|| { // Create Net 1 - let netuid: u16 = 1; + let netuid: u16 = 1; let tempo: u16 = 1; let modality: u16 = 1; - add_network( netuid, tempo, modality ); - assert_eq!( SubtensorModule::get_difficulty_as_u64( netuid ), 10000 ); // Check initial difficulty. - assert_eq!( SubtensorModule::get_last_adjustment_block( netuid ), 0 ); // Last adjustment block starts at 0. - assert_eq!( SubtensorModule::get_registrations_this_block( netuid ), 0 ); // No registrations this block. - assert_eq!( SubtensorModule::get_target_registrations_per_interval( netuid ), 2 ); // Target is default. - assert_eq!( SubtensorModule::get_adjustment_interval( netuid ), 100 ); // Default adustment intrerval. - assert_eq!( SubtensorModule::get_network_registration_allowed( netuid ), true ); // Default registration allowed. - + add_network(netuid, tempo, modality); + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 10000); // Check initial difficulty. + assert_eq!(SubtensorModule::get_last_adjustment_block(netuid), 0); // Last adjustment block starts at 0. + assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 0); // No registrations this block. + assert_eq!( + SubtensorModule::get_target_registrations_per_interval(netuid), + 2 + ); // Target is default. + assert_eq!(SubtensorModule::get_adjustment_interval(netuid), 100); // Default adustment intrerval. + assert_eq!( + SubtensorModule::get_network_registration_allowed(netuid), + true + ); // Default registration allowed. + // Set values and check. - SubtensorModule::set_difficulty( netuid, 20000 ); - SubtensorModule::set_adjustment_interval( netuid, 1 ); - SubtensorModule::set_target_registrations_per_interval( netuid, 1 ); - SubtensorModule::set_max_registrations_per_block( netuid, 3 ); - SubtensorModule::set_max_allowed_uids( netuid, 3 ); - SubtensorModule::set_network_registration_allowed( netuid, true ); - assert_eq!( SubtensorModule::get_difficulty_as_u64( netuid ), 20000 ); // Check set difficutly. - assert_eq!( SubtensorModule::get_adjustment_interval( netuid ), 1 ); // Check set adjustment interval. - assert_eq!( SubtensorModule::get_target_registrations_per_interval( netuid ), 1 ); // Check set adjustment interval. - assert_eq!( SubtensorModule::get_max_registrations_per_block( netuid ), 3 ); // Check set registrations per block. - assert_eq!( SubtensorModule::get_max_allowed_uids( netuid ), 3 ); // Check set registrations per block. - assert_eq!( SubtensorModule::get_network_registration_allowed( netuid ), true ); // Check set registration allowed + SubtensorModule::set_difficulty(netuid, 20000); + SubtensorModule::set_adjustment_interval(netuid, 1); + SubtensorModule::set_target_registrations_per_interval(netuid, 1); + SubtensorModule::set_max_registrations_per_block(netuid, 3); + SubtensorModule::set_max_allowed_uids(netuid, 3); + SubtensorModule::set_network_registration_allowed(netuid, true); + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 20000); // Check set difficutly. + assert_eq!(SubtensorModule::get_adjustment_interval(netuid), 1); // Check set adjustment interval. + assert_eq!( + SubtensorModule::get_target_registrations_per_interval(netuid), + 1 + ); // Check set adjustment interval. + assert_eq!(SubtensorModule::get_max_registrations_per_block(netuid), 3); // Check set registrations per block. + assert_eq!(SubtensorModule::get_max_allowed_uids(netuid), 3); // Check set registrations per block. + assert_eq!( + SubtensorModule::get_network_registration_allowed(netuid), + true + ); // Check set registration allowed // Lets register 3 neurons... let hotkey0 = U256::from(0); @@ -40,94 +51,117 @@ fn test_registration_difficulty_adjustment() { let coldkey0 = U256::from(0); let coldkey1 = U256::from(1000); let coldkey2 = U256::from(20000); - register_ok_neuron( netuid, hotkey0, coldkey0, 39420842 ); - register_ok_neuron( netuid, hotkey1, coldkey1, 12412392 ); - register_ok_neuron( netuid, hotkey2, coldkey2, 21813123 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid, 0 ).unwrap(), hotkey0 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid, 1 ).unwrap(), hotkey1 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid, 2 ).unwrap(), hotkey2 ); + register_ok_neuron(netuid, hotkey0, coldkey0, 39420842); + register_ok_neuron(netuid, hotkey1, coldkey1, 12412392); + register_ok_neuron(netuid, hotkey2, coldkey2, 21813123); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid, 0).unwrap(), + hotkey0 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid, 1).unwrap(), + hotkey1 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid, 2).unwrap(), + hotkey2 + ); - assert_eq!( SubtensorModule::get_subnetwork_n(netuid), 3); // All 3 are registered. - assert_eq!( SubtensorModule::get_registrations_this_block( netuid ), 3 ); // 3 Registrations. - assert_eq!( SubtensorModule::get_registrations_this_interval( netuid ), 3 ); // 3 Registrations this interval. + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 3); // All 3 are registered. + assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 3); // 3 Registrations. + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 3); // 3 Registrations this interval. // Fast forward 1 block. - assert_eq!( SubtensorModule::get_difficulty_as_u64( netuid ), 20000 ); // Difficulty is unchanged. - step_block( 1 ); - assert_eq!( SubtensorModule::get_registrations_this_block( netuid ), 0 ); // Registrations have been erased. - assert_eq!( SubtensorModule::get_last_adjustment_block( netuid ), 1 ); // We just adjusted on the first block. - assert_eq!( SubtensorModule::get_difficulty_as_u64( netuid ), 40000 ); // Difficulty is increased ( 20000 * ( 3 + 1 ) / ( 1 + 1 ) ) = 80_000 - assert_eq!( SubtensorModule::get_registrations_this_interval( netuid ), 0 ); // Registrations this interval has been wiped. + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 20000); // Difficulty is unchanged. + step_block(1); + assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 0); // Registrations have been erased. + assert_eq!(SubtensorModule::get_last_adjustment_block(netuid), 1); // We just adjusted on the first block. + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 40000); // Difficulty is increased ( 20000 * ( 3 + 1 ) / ( 1 + 1 ) ) = 80_000 + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 0); // Registrations this interval has been wiped. // Lets change the adjustment interval - SubtensorModule::set_adjustment_interval( netuid, 3 ); - assert_eq!( SubtensorModule::get_adjustment_interval( netuid ), 3 ); // Check set adjustment interval. + SubtensorModule::set_adjustment_interval(netuid, 3); + assert_eq!(SubtensorModule::get_adjustment_interval(netuid), 3); // Check set adjustment interval. - SubtensorModule::set_target_registrations_per_interval( netuid, 3 ); - assert_eq!( SubtensorModule::get_target_registrations_per_interval( netuid ), 3 ); // Target is default. + SubtensorModule::set_target_registrations_per_interval(netuid, 3); + assert_eq!( + SubtensorModule::get_target_registrations_per_interval(netuid), + 3 + ); // Target is default. - // Register 3 more - register_ok_neuron( netuid, hotkey0 + 1, coldkey0 + 1, 3942084 ); - register_ok_neuron( netuid, hotkey1 + 1, coldkey1 + 1, 1241239 ); - register_ok_neuron( netuid, hotkey2 + 1, coldkey2 + 1, 2181312 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid, 0 ).unwrap(), hotkey0 + 1); // replace 0 - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid, 1 ).unwrap(), hotkey1 + 1); // replace 1 - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid, 2 ).unwrap(), hotkey2 + 1); // replace 2 - assert_eq!( SubtensorModule::get_registrations_this_block( netuid ), 3 ); // Registrations have been erased. - assert_eq!( SubtensorModule::get_registrations_this_interval( netuid ), 3 ); // Registrations this interval = 3 + // Register 3 more + register_ok_neuron(netuid, hotkey0 + 1, coldkey0 + 1, 3942084); + register_ok_neuron(netuid, hotkey1 + 1, coldkey1 + 1, 1241239); + register_ok_neuron(netuid, hotkey2 + 1, coldkey2 + 1, 2181312); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid, 0).unwrap(), + hotkey0 + 1 + ); // replace 0 + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid, 1).unwrap(), + hotkey1 + 1 + ); // replace 1 + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid, 2).unwrap(), + hotkey2 + 1 + ); // replace 2 + assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 3); // Registrations have been erased. + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 3); // Registrations this interval = 3 - step_block( 1 ); // Step - assert_eq!( SubtensorModule::get_last_adjustment_block( netuid ), 1 ); // Still previous adjustment block. - assert_eq!( SubtensorModule::get_registrations_this_block( netuid ), 0 ); // Registrations have been erased. - assert_eq!( SubtensorModule::get_registrations_this_interval( netuid ), 3 ); // Registrations this interval = 3 + step_block(1); // Step + assert_eq!(SubtensorModule::get_last_adjustment_block(netuid), 1); // Still previous adjustment block. + assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 0); // Registrations have been erased. + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 3); // Registrations this interval = 3 // Register 3 more. - register_ok_neuron( netuid, hotkey0 + 2, coldkey0 + 2, 394208420 ); - register_ok_neuron( netuid, hotkey1 + 2, coldkey1 + 2, 124123920 ); - register_ok_neuron( netuid, hotkey2 + 2, coldkey2 + 2, 218131230 ); - assert_eq!( SubtensorModule::get_registrations_this_block( netuid ), 3 ); // Registrations have been erased. + register_ok_neuron(netuid, hotkey0 + 2, coldkey0 + 2, 394208420); + register_ok_neuron(netuid, hotkey1 + 2, coldkey1 + 2, 124123920); + register_ok_neuron(netuid, hotkey2 + 2, coldkey2 + 2, 218131230); + assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 3); // Registrations have been erased. // We have 6 registrations this adjustment interval. - step_block( 1 ); // Step - assert_eq!( SubtensorModule::get_registrations_this_interval( netuid ), 6 ); // Registrations this interval = 6 - assert_eq!( SubtensorModule::get_difficulty_as_u64( netuid ), 40000 ); // Difficulty unchanged. - step_block( 1 ); // Step - assert_eq!( SubtensorModule::get_difficulty_as_u64( netuid ), 60_000 ); // Difficulty changed ( 40000 ) * ( 6 + 3 / 3 + 3 ) = 40000 * 1.5 = 60_000 - assert_eq!( SubtensorModule::get_registrations_this_interval( netuid ), 0 ); // Registrations this interval drops to 0. + step_block(1); // Step + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 6); // Registrations this interval = 6 + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 40000); // Difficulty unchanged. + step_block(1); // Step + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 60_000); // Difficulty changed ( 40000 ) * ( 6 + 3 / 3 + 3 ) = 40000 * 1.5 = 60_000 + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 0); // Registrations this interval drops to 0. // Test min value. - SubtensorModule::set_min_difficulty( netuid, 1 ); - SubtensorModule::set_difficulty( netuid, 4 ); - assert_eq!( SubtensorModule::get_min_difficulty( netuid ), 1 ); - assert_eq!( SubtensorModule::get_difficulty_as_u64( netuid ), 4 ); - SubtensorModule::set_adjustment_interval( netuid, 1 ); - step_block( 1 ); // Step - assert_eq!( SubtensorModule::get_difficulty_as_u64( netuid ), 2 ); // Difficulty dropped 4 * ( 0 + 1 ) / (1 + 1) = 1/2 = 2 - step_block( 1 ); // Step - assert_eq!( SubtensorModule::get_difficulty_as_u64( netuid ), 1 ); // Difficulty dropped 2 * ( 0 + 1 ) / (1 + 1) = 1/2 = 1 - step_block( 1 ); // Step - assert_eq!( SubtensorModule::get_difficulty_as_u64( netuid ), 1 ); // Difficulty dropped 2 * ( 0 + 1 ) / (1 + 1) = 1/2 = max(0.5, 1) + SubtensorModule::set_min_difficulty(netuid, 1); + SubtensorModule::set_difficulty(netuid, 4); + assert_eq!(SubtensorModule::get_min_difficulty(netuid), 1); + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 4); + SubtensorModule::set_adjustment_interval(netuid, 1); + step_block(1); // Step + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 2); // Difficulty dropped 4 * ( 0 + 1 ) / (1 + 1) = 1/2 = 2 + step_block(1); // Step + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 1); // Difficulty dropped 2 * ( 0 + 1 ) / (1 + 1) = 1/2 = 1 + step_block(1); // Step + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 1); // Difficulty dropped 2 * ( 0 + 1 ) / (1 + 1) = 1/2 = max(0.5, 1) // Test max value. - SubtensorModule::set_max_difficulty( netuid, 10000 ); - SubtensorModule::set_difficulty( netuid, 5000 ); - assert_eq!( SubtensorModule::get_max_difficulty( netuid ), 10000); - assert_eq!( SubtensorModule::get_difficulty_as_u64( netuid ), 5000); - SubtensorModule::set_max_registrations_per_block( netuid, 4 ); - register_ok_neuron( netuid, hotkey0 + 3, coldkey0 + 3, 294208420 ); - register_ok_neuron( netuid, hotkey1 + 3, coldkey1 + 3, 824123920 ); - register_ok_neuron( netuid, hotkey2 + 3, coldkey2 + 3, 324123920 ); - register_ok_neuron( netuid, hotkey2 + 4, coldkey2 + 4, 524123920 ); - assert_eq!( SubtensorModule::get_registrations_this_interval( netuid ), 4 ); - assert_eq!( SubtensorModule::get_target_registrations_per_interval( netuid ), 3 ); - step_block( 1 ); // Step - assert_eq!( SubtensorModule::get_difficulty_as_u64( netuid ), 5833 ); // Difficulty increased 5000 * ( 4 + 3 ) / (3 + 3) = 1.16 * 5000 = 5833 - - register_ok_neuron( netuid, hotkey0 + 4, coldkey0 + 4, 124208420 ); - register_ok_neuron( netuid, hotkey1 + 4, coldkey1 + 4, 314123920 ); - register_ok_neuron( netuid, hotkey2 + 4, coldkey2 + 4, 834123920 ); - step_block( 1 ); // Step - assert_eq!( SubtensorModule::get_difficulty_as_u64( netuid ), 5833 ); // Difficulty unchanged + SubtensorModule::set_max_difficulty(netuid, 10000); + SubtensorModule::set_difficulty(netuid, 5000); + assert_eq!(SubtensorModule::get_max_difficulty(netuid), 10000); + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 5000); + SubtensorModule::set_max_registrations_per_block(netuid, 4); + register_ok_neuron(netuid, hotkey0 + 3, coldkey0 + 3, 294208420); + register_ok_neuron(netuid, hotkey1 + 3, coldkey1 + 3, 824123920); + register_ok_neuron(netuid, hotkey2 + 3, coldkey2 + 3, 324123920); + register_ok_neuron(netuid, hotkey2 + 4, coldkey2 + 4, 524123920); + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 4); + assert_eq!( + SubtensorModule::get_target_registrations_per_interval(netuid), + 3 + ); + step_block(1); // Step + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 5833); // Difficulty increased 5000 * ( 4 + 3 ) / (3 + 3) = 1.16 * 5000 = 5833 - }); + register_ok_neuron(netuid, hotkey0 + 4, coldkey0 + 4, 124208420); + register_ok_neuron(netuid, hotkey1 + 4, coldkey1 + 4, 314123920); + register_ok_neuron(netuid, hotkey2 + 4, coldkey2 + 4, 834123920); + step_block(1); // Step + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 5833); // Difficulty unchanged + }); } diff --git a/pallets/subtensor/tests/epoch.rs b/pallets/subtensor/tests/epoch.rs index b00d719593..8e5122d2fe 100644 --- a/pallets/subtensor/tests/epoch.rs +++ b/pallets/subtensor/tests/epoch.rs @@ -1,592 +1,975 @@ use crate::mock::*; -use rand::{Rng, thread_rng, SeedableRng, rngs::StdRng, seq::SliceRandom, distributions::Uniform}; -use sp_core::U256; -use substrate_fixed::types::{I32F32, I64F64}; -use substrate_fixed::transcendental::{PI, cos, ln, sqrt}; -use frame_system::Config; use frame_support::assert_ok; +use frame_system::Config; +use rand::{distributions::Uniform, rngs::StdRng, seq::SliceRandom, thread_rng, Rng, SeedableRng}; +use sp_core::U256; use std::time::Instant; +use substrate_fixed::transcendental::{cos, ln, sqrt, PI}; +use substrate_fixed::types::{I32F32, I64F64}; mod mock; -pub fn fixed(val: f32) -> I32F32 { I32F32::from_num(val) } +pub fn fixed(val: f32) -> I32F32 { + I32F32::from_num(val) +} -pub fn fixed_to_u16( x: I32F32 ) -> u16 { x.to_num::() } +pub fn fixed_to_u16(x: I32F32) -> u16 { + x.to_num::() +} -pub fn fixed_proportion_to_u16( x: I32F32 ) -> u16 { fixed_to_u16( x * I32F32::from_num( u16::MAX )) } +pub fn fixed_proportion_to_u16(x: I32F32) -> u16 { + fixed_to_u16(x * I32F32::from_num(u16::MAX)) +} // Normalizes (sum to 1 except 0) the input vector directly in-place. #[allow(dead_code)] -pub fn inplace_normalize( x: &mut Vec ) { +pub fn inplace_normalize(x: &mut Vec) { let x_sum: I32F32 = x.iter().sum(); - if x_sum == I32F32::from_num( 0.0 as f32 ){ return } + if x_sum == I32F32::from_num(0.0 as f32) { + return; + } for i in 0..x.len() { - x[i] = x[i]/x_sum; + x[i] = x[i] / x_sum; } } // Inplace normalize the passed positive integer weights so that they sum to u16 max value. fn normalize_weights(mut weights: Vec) -> Vec { - let sum: u64 = weights.iter().map(|x| *x as u64).sum(); - if sum == 0 { return weights; } - weights.iter_mut().for_each(|x| { *x = (*x as u64 * u16::max_value() as u64 / sum) as u16; }); - return weights; + let sum: u64 = weights.iter().map(|x| *x as u64).sum(); + if sum == 0 { + return weights; + } + weights.iter_mut().for_each(|x| { + *x = (*x as u64 * u16::max_value() as u64 / sum) as u16; + }); + return weights; } // Return as usize an I32F32 ratio of a usize input, avoiding the 0% and 100% extremes. fn non_extreme_fixed_ratio(ratio: I32F32, total: usize) -> usize { - if total == 0 { return total } - let mut subset: usize = (ratio * I32F32::from_num(total)).to_num::(); - if subset == 0 { - subset = 1; - } - else if subset == total { - subset = total - 1; - } - return subset + if total == 0 { + return total; + } + let mut subset: usize = (ratio * I32F32::from_num(total)).to_num::(); + if subset == 0 { + subset = 1; + } else if subset == total { + subset = total - 1; + } + return subset; } // Box-Muller Transform converting two uniform random samples to a normal random sample. fn normal(size: usize, rng: &mut StdRng, dist: &Uniform) -> Vec { - let max: I32F32 = I32F32::from_num(u16::MAX); - let two: I32F32 = I32F32::from_num(2); - let eps: I32F32 = I32F32::from_num(0.000001); - let pi: I32F32 = I32F32::from_num(PI); - - let uniform_u16: Vec = (0..(2*size)).map(|_| rng.sample(&dist)).collect(); - let uniform: Vec = uniform_u16.iter().map(|&x| I32F32::from_num(x) / max).collect(); - let mut normal: Vec = vec![ I32F32::from_num(0); size as usize]; - - for i in 0..size { - let u1: I32F32 = uniform[i] + eps; - let u2: I32F32 = uniform[i + size] + eps; - normal[i] = sqrt::(-two * ln::(u1).expect("")).expect("") * cos(two * pi * u2); - } - normal + let max: I32F32 = I32F32::from_num(u16::MAX); + let two: I32F32 = I32F32::from_num(2); + let eps: I32F32 = I32F32::from_num(0.000001); + let pi: I32F32 = I32F32::from_num(PI); + + let uniform_u16: Vec = (0..(2 * size)).map(|_| rng.sample(&dist)).collect(); + let uniform: Vec = uniform_u16 + .iter() + .map(|&x| I32F32::from_num(x) / max) + .collect(); + let mut normal: Vec = vec![I32F32::from_num(0); size as usize]; + + for i in 0..size { + let u1: I32F32 = uniform[i] + eps; + let u2: I32F32 = uniform[i + size] + eps; + normal[i] = sqrt::(-two * ln::(u1).expect("")).expect("") + * cos(two * pi * u2); + } + normal } // Returns validators and servers uids with either blockwise, regular, or random interleaving. -fn distribute_nodes(validators_n: usize, network_n: usize, interleave: usize) -> (Vec, Vec) { - let mut validators: Vec = vec![]; - let mut servers: Vec = vec![]; - - if interleave == 0 { // blockwise [validator_block, server_block] - validators = (0..validators_n as u16).collect(); - servers = (validators_n as u16..network_n as u16 ).collect(); - } - else if interleave == 1 { // regular interleaving [val, srv, srv, ..., srv, val, srv, srv, ..., srv, val, srv, ..., srv] - (validators, servers) = (0..network_n as u16).collect::>().iter().partition( | &i | *i as usize % (network_n / validators_n) == 0); - } - else if interleave == 2 { // random interleaving - let mut permuted_uids: Vec = (0..network_n as u16).collect(); - permuted_uids.shuffle(&mut thread_rng()); - validators = permuted_uids[0..validators_n as usize].into(); - servers = permuted_uids[validators_n as usize..network_n as usize].into(); - } - - return (validators, servers); +fn distribute_nodes( + validators_n: usize, + network_n: usize, + interleave: usize, +) -> (Vec, Vec) { + let mut validators: Vec = vec![]; + let mut servers: Vec = vec![]; + + if interleave == 0 { + // blockwise [validator_block, server_block] + validators = (0..validators_n as u16).collect(); + servers = (validators_n as u16..network_n as u16).collect(); + } else if interleave == 1 { + // regular interleaving [val, srv, srv, ..., srv, val, srv, srv, ..., srv, val, srv, ..., srv] + (validators, servers) = (0..network_n as u16) + .collect::>() + .iter() + .partition(|&i| *i as usize % (network_n / validators_n) == 0); + } else if interleave == 2 { + // random interleaving + let mut permuted_uids: Vec = (0..network_n as u16).collect(); + permuted_uids.shuffle(&mut thread_rng()); + validators = permuted_uids[0..validators_n as usize].into(); + servers = permuted_uids[validators_n as usize..network_n as usize].into(); + } + + return (validators, servers); } #[allow(dead_code)] fn uid_stats(netuid: u16, uid: u16) { - log::info!( "stake: {:?}", SubtensorModule::get_total_stake_for_hotkey( &(U256::from(uid)) ) ); - log::info!( "rank: {:?}", SubtensorModule::get_rank_for_uid( netuid, uid ) ); - log::info!( "trust: {:?}", SubtensorModule::get_trust_for_uid( netuid, uid ) ); - log::info!( "consensus: {:?}", SubtensorModule::get_consensus_for_uid( netuid, uid ) ); - log::info!( "incentive: {:?}", SubtensorModule::get_incentive_for_uid( netuid, uid ) ); - log::info!( "dividend: {:?}", SubtensorModule::get_dividends_for_uid( netuid, uid ) ); - log::info!( "emission: {:?}", SubtensorModule::get_emission_for_uid( netuid, uid ) ); + log::info!( + "stake: {:?}", + SubtensorModule::get_total_stake_for_hotkey(&(U256::from(uid))) + ); + log::info!("rank: {:?}", SubtensorModule::get_rank_for_uid(netuid, uid)); + log::info!( + "trust: {:?}", + SubtensorModule::get_trust_for_uid(netuid, uid) + ); + log::info!( + "consensus: {:?}", + SubtensorModule::get_consensus_for_uid(netuid, uid) + ); + log::info!( + "incentive: {:?}", + SubtensorModule::get_incentive_for_uid(netuid, uid) + ); + log::info!( + "dividend: {:?}", + SubtensorModule::get_dividends_for_uid(netuid, uid) + ); + log::info!( + "emission: {:?}", + SubtensorModule::get_emission_for_uid(netuid, uid) + ); } -fn init_run_epochs(netuid: u16, n: u16, validators: &Vec, servers: &Vec, epochs: u16, stake_per_validator: u64, server_self: bool, input_stake: &Vec, use_input_stake: bool, input_weights: &Vec>, use_input_weights: bool, random_weights: bool, random_seed: u64, sparse: bool) { - // === Create the network - add_network(netuid, u16::MAX - 1, 0); // set higher tempo to avoid built-in epoch, then manual epoch instead - - // === Register uids - SubtensorModule::set_max_allowed_uids( netuid, n ); - for key in 0..n { - let stake: u64; - if use_input_stake { - stake = input_stake[key as usize]; - } - else { - stake = if validators.contains(&key) { stake_per_validator } else { 0 }; // only validators receive stake - } - // let stake: u64 = 1; // alternative test: all nodes receive stake, should be same outcome, except stake - SubtensorModule::add_balance_to_coldkey_account( &(U256::from(key)), stake ); - SubtensorModule::append_neuron( netuid, &(U256::from(key)), 0 ); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( &U256::from(key), &U256::from(key), stake as u64 ); - } - assert_eq!( SubtensorModule::get_subnetwork_n(netuid), n ); - - // === Issue validator permits - assert_ok!( SubtensorModule::sudo_set_max_allowed_validators(<::RuntimeOrigin>::root(), netuid, validators.len() as u16) ); - assert_eq!( SubtensorModule::get_max_allowed_validators(netuid), validators.len() as u16); - SubtensorModule::epoch( netuid, 1_000_000_000 ); // run first epoch to set allowed validators - run_to_block( 1 ); // run to next block to ensure weights are set on nodes after their registration block - - // === Set weights - let mut rng = StdRng::seed_from_u64(random_seed); // constant seed so weights over multiple runs are equal +fn init_run_epochs( + netuid: u16, + n: u16, + validators: &Vec, + servers: &Vec, + epochs: u16, + stake_per_validator: u64, + server_self: bool, + input_stake: &Vec, + use_input_stake: bool, + input_weights: &Vec>, + use_input_weights: bool, + random_weights: bool, + random_seed: u64, + sparse: bool, +) { + // === Create the network + add_network(netuid, u16::MAX - 1, 0); // set higher tempo to avoid built-in epoch, then manual epoch instead + + // === Register uids + SubtensorModule::set_max_allowed_uids(netuid, n); + for key in 0..n { + let stake: u64; + if use_input_stake { + stake = input_stake[key as usize]; + } else { + stake = if validators.contains(&key) { + stake_per_validator + } else { + 0 + }; // only validators receive stake + } + // let stake: u64 = 1; // alternative test: all nodes receive stake, should be same outcome, except stake + SubtensorModule::add_balance_to_coldkey_account(&(U256::from(key)), stake); + SubtensorModule::append_neuron(netuid, &(U256::from(key)), 0); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &U256::from(key), + &U256::from(key), + stake as u64, + ); + } + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), n); + + // === Issue validator permits + assert_ok!(SubtensorModule::sudo_set_max_allowed_validators( + <::RuntimeOrigin>::root(), + netuid, + validators.len() as u16 + )); + assert_eq!( + SubtensorModule::get_max_allowed_validators(netuid), + validators.len() as u16 + ); + SubtensorModule::epoch(netuid, 1_000_000_000); // run first epoch to set allowed validators + run_to_block(1); // run to next block to ensure weights are set on nodes after their registration block + + // === Set weights + let mut rng = StdRng::seed_from_u64(random_seed); // constant seed so weights over multiple runs are equal let range = Uniform::new(0, u16::MAX); - let mut weights: Vec = vec![ u16::MAX / n; servers.len() as usize ]; - for uid in validators { - if random_weights { - weights = (0..servers.len()).map(|_| rng.sample(&range)).collect(); - weights = normalize_weights(weights); - // assert_eq!(weights.iter().map(|x| *x as u64).sum::(), u16::MAX as u64); // normalized weight sum not always u16::MAX - } - if use_input_weights { - let sparse_weights = input_weights[*uid as usize].clone(); - weights = sparse_weights.iter().map(|(_, w)| *w).collect(); - let srvs: Vec = sparse_weights.iter().map(|(s, _)| *s).collect(); - assert_ok!(SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(*uid as u64)), netuid, srvs, weights.clone(), 0)); - } - else { - assert_ok!(SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(*uid as u64)), netuid, servers.clone(), weights.clone(), 0)); - } - } - if server_self { - for uid in servers { - assert_ok!(SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(*uid as u64)), netuid, vec![ *uid as u16 ], vec![ u16::MAX ], 0)); // server self-weight - } - } - - // === Run the epochs. - log::info!( "Start {epochs} epoch(s)" ); - let start = Instant::now(); - for _ in 0..epochs { - if sparse { - SubtensorModule::epoch( netuid, 1_000_000_000 ); - } - else { - SubtensorModule::epoch_dense( netuid, 1_000_000_000 ); - } - } - let duration = start.elapsed(); - log::info!( "Time elapsed in (sparse={sparse}) epoch() is: {:?}", duration ); - - // let bonds = SubtensorModule::get_bonds( netuid ); - // for (uid, node) in vec![ (validators[0], "validator"), (servers[0], "server") ] { - // log::info!("\n{node}" ); - // uid_stats(netuid, uid); - // log::info!("bonds: {:?} (on validator), {:?} (on server)", bonds[uid as usize][0], bonds[uid as usize][servers[0] as usize]); - // } + let mut weights: Vec = vec![u16::MAX / n; servers.len() as usize]; + for uid in validators { + if random_weights { + weights = (0..servers.len()).map(|_| rng.sample(&range)).collect(); + weights = normalize_weights(weights); + // assert_eq!(weights.iter().map(|x| *x as u64).sum::(), u16::MAX as u64); // normalized weight sum not always u16::MAX + } + if use_input_weights { + let sparse_weights = input_weights[*uid as usize].clone(); + weights = sparse_weights.iter().map(|(_, w)| *w).collect(); + let srvs: Vec = sparse_weights.iter().map(|(s, _)| *s).collect(); + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(*uid as u64)), + netuid, + srvs, + weights.clone(), + 0 + )); + } else { + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(*uid as u64)), + netuid, + servers.clone(), + weights.clone(), + 0 + )); + } + } + if server_self { + for uid in servers { + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(*uid as u64)), + netuid, + vec![*uid as u16], + vec![u16::MAX], + 0 + )); // server self-weight + } + } + + // === Run the epochs. + log::info!("Start {epochs} epoch(s)"); + let start = Instant::now(); + for _ in 0..epochs { + if sparse { + SubtensorModule::epoch(netuid, 1_000_000_000); + } else { + SubtensorModule::epoch_dense(netuid, 1_000_000_000); + } + } + let duration = start.elapsed(); + log::info!( + "Time elapsed in (sparse={sparse}) epoch() is: {:?}", + duration + ); + + // let bonds = SubtensorModule::get_bonds( netuid ); + // for (uid, node) in vec![ (validators[0], "validator"), (servers[0], "server") ] { + // log::info!("\n{node}" ); + // uid_stats(netuid, uid); + // log::info!("bonds: {:?} (on validator), {:?} (on server)", bonds[uid as usize][0], bonds[uid as usize][servers[0] as usize]); + // } } // Generate a random graph that is split into a major and minor set, each setting specific weight on itself and the complement on the other. -fn split_graph(major_stake: I32F32, major_weight: I32F32, minor_weight: I32F32, weight_stddev: I32F32, validators_n: usize, network_n: usize, interleave: usize) -> (Vec, Vec, Vec, Vec, Vec, Vec, Vec, Vec>, I32F32) { - let servers_n: usize = network_n - validators_n; - let major_servers_n: usize = non_extreme_fixed_ratio(major_stake, servers_n); - let major_validators_n: usize = non_extreme_fixed_ratio(major_stake, validators_n); - - let (validators, servers) = distribute_nodes(validators_n, network_n, interleave as usize); - let major_validators: Vec = (0..major_validators_n).map(|i| validators[i]).collect(); - let minor_validators: Vec = (major_validators_n..validators_n).map(|i| validators[i]).collect(); - let major_servers: Vec = (0..major_servers_n).map(|i| servers[i]).collect(); - let minor_servers: Vec = (major_servers_n..servers_n).map(|i| servers[i]).collect(); - - let zero: I32F32 = I32F32::from_num(0); - let one: I32F32 = I32F32::from_num(1); - let stddev: I32F32 = I32F32::from_num(0.3); - let total_stake: I64F64 = I64F64::from_num(21_000_000_000_000_000 as u64); - let mut rng = StdRng::seed_from_u64(0); // constant seed so weights over multiple runs are equal +fn split_graph( + major_stake: I32F32, + major_weight: I32F32, + minor_weight: I32F32, + weight_stddev: I32F32, + validators_n: usize, + network_n: usize, + interleave: usize, +) -> ( + Vec, + Vec, + Vec, + Vec, + Vec, + Vec, + Vec, + Vec>, + I32F32, +) { + let servers_n: usize = network_n - validators_n; + let major_servers_n: usize = non_extreme_fixed_ratio(major_stake, servers_n); + let major_validators_n: usize = non_extreme_fixed_ratio(major_stake, validators_n); + + let (validators, servers) = distribute_nodes(validators_n, network_n, interleave as usize); + let major_validators: Vec = (0..major_validators_n).map(|i| validators[i]).collect(); + let minor_validators: Vec = (major_validators_n..validators_n) + .map(|i| validators[i]) + .collect(); + let major_servers: Vec = (0..major_servers_n).map(|i| servers[i]).collect(); + let minor_servers: Vec = (major_servers_n..servers_n).map(|i| servers[i]).collect(); + + let zero: I32F32 = I32F32::from_num(0); + let one: I32F32 = I32F32::from_num(1); + let stddev: I32F32 = I32F32::from_num(0.3); + let total_stake: I64F64 = I64F64::from_num(21_000_000_000_000_000 as u64); + let mut rng = StdRng::seed_from_u64(0); // constant seed so weights over multiple runs are equal let dist = Uniform::new(0, u16::MAX); - let mut stake: Vec = vec![0; network_n]; - let mut stake_fixed: Vec = vec![zero; network_n]; - for (ratio, vals) in vec![(major_stake, &major_validators), (one - major_stake, &minor_validators)] { - let mut sample = normal(vals.len(), &mut rng, &dist).iter().map(|x: &I32F32| { let v: I32F32 = (stddev * x) + one; if v < zero {zero} else {v} }).collect(); - inplace_normalize(&mut sample); - for (i, &val) in vals.iter().enumerate() { - stake[val as usize] = ( I64F64::from_num(ratio) * I64F64::from_num(sample[i]) * total_stake ).to_num::(); - stake_fixed[val as usize] = I32F32::from_num(I64F64::from_num(ratio) * I64F64::from_num(sample[i])); - } - } - - let mut weights: Vec> = vec![ vec![]; network_n as usize ]; - let mut weights_fixed: Vec> = vec![ vec![zero; network_n]; network_n ]; - for (first, second, vals) in vec![(major_weight, one - major_weight, &major_validators), (one - minor_weight, minor_weight, &minor_validators)] { - for &val in vals { - for (weight, srvs) in vec![(first, &major_servers), (second, &minor_servers)] { - let mut sample: Vec = normal(srvs.len(), &mut rng, &dist).iter().map(|x: &I32F32| { let v: I32F32 = (weight_stddev * x) + one; if v < zero {zero} else {v} }).collect(); - inplace_normalize(&mut sample); - - for (i, &srv) in srvs.iter().enumerate() { - weights[val as usize].push( (srv, fixed_proportion_to_u16(weight * sample[i])) ); - weights_fixed[val as usize][srv as usize] = weight * sample[i]; - } - } - inplace_normalize(&mut weights_fixed[val as usize]); - } - } + let mut stake: Vec = vec![0; network_n]; + let mut stake_fixed: Vec = vec![zero; network_n]; + for (ratio, vals) in vec![ + (major_stake, &major_validators), + (one - major_stake, &minor_validators), + ] { + let mut sample = normal(vals.len(), &mut rng, &dist) + .iter() + .map(|x: &I32F32| { + let v: I32F32 = (stddev * x) + one; + if v < zero { + zero + } else { + v + } + }) + .collect(); + inplace_normalize(&mut sample); + for (i, &val) in vals.iter().enumerate() { + stake[val as usize] = + (I64F64::from_num(ratio) * I64F64::from_num(sample[i]) * total_stake) + .to_num::(); + stake_fixed[val as usize] = + I32F32::from_num(I64F64::from_num(ratio) * I64F64::from_num(sample[i])); + } + } - inplace_normalize(&mut stake_fixed); + let mut weights: Vec> = vec![vec![]; network_n as usize]; + let mut weights_fixed: Vec> = vec![vec![zero; network_n]; network_n]; + for (first, second, vals) in vec![ + (major_weight, one - major_weight, &major_validators), + (one - minor_weight, minor_weight, &minor_validators), + ] { + for &val in vals { + for (weight, srvs) in vec![(first, &major_servers), (second, &minor_servers)] { + let mut sample: Vec = normal(srvs.len(), &mut rng, &dist) + .iter() + .map(|x: &I32F32| { + let v: I32F32 = (weight_stddev * x) + one; + if v < zero { + zero + } else { + v + } + }) + .collect(); + inplace_normalize(&mut sample); + + for (i, &srv) in srvs.iter().enumerate() { + weights[val as usize].push((srv, fixed_proportion_to_u16(weight * sample[i]))); + weights_fixed[val as usize][srv as usize] = weight * sample[i]; + } + } + inplace_normalize(&mut weights_fixed[val as usize]); + } + } - // Calculate stake-weighted mean per server - let mut weight_mean: Vec = vec![ zero; network_n ]; - for val in 0..network_n { - if stake_fixed[val] > zero { - for srv in 0..network_n { - weight_mean[srv] += stake_fixed[val] * weights_fixed[val][srv]; - } - } - } - - // Calculate stake-weighted absolute standard deviation - let mut weight_dev: Vec = vec![ zero; network_n ]; - for val in 0..network_n { - if stake_fixed[val] > zero { - for srv in 0..network_n { - weight_dev[srv] += stake_fixed[val] * (weight_mean[srv] - weights_fixed[val][srv]).abs(); - } - } - } + inplace_normalize(&mut stake_fixed); - // Calculate rank-weighted mean of weight_dev - let avg_weight_dev: I32F32 = weight_dev.iter().sum::() / weight_mean.iter().sum::(); - - (validators, servers, major_validators, minor_validators, major_servers, minor_servers, stake, weights, avg_weight_dev) + // Calculate stake-weighted mean per server + let mut weight_mean: Vec = vec![zero; network_n]; + for val in 0..network_n { + if stake_fixed[val] > zero { + for srv in 0..network_n { + weight_mean[srv] += stake_fixed[val] * weights_fixed[val][srv]; + } + } + } + + // Calculate stake-weighted absolute standard deviation + let mut weight_dev: Vec = vec![zero; network_n]; + for val in 0..network_n { + if stake_fixed[val] > zero { + for srv in 0..network_n { + weight_dev[srv] += + stake_fixed[val] * (weight_mean[srv] - weights_fixed[val][srv]).abs(); + } + } + } + + // Calculate rank-weighted mean of weight_dev + let avg_weight_dev: I32F32 = + weight_dev.iter().sum::() / weight_mean.iter().sum::(); + + ( + validators, + servers, + major_validators, + minor_validators, + major_servers, + minor_servers, + stake, + weights, + avg_weight_dev, + ) } // Test consensus guarantees with an epoch on a graph with 4096 nodes, of which the first 128 are validators, the graph is split into a major and minor set, each setting specific weight on itself and the complement on the other. Asserts that the major emission ratio >= major stake ratio. #[test] fn test_consensus_guarantees() { - let netuid: u16 = 0; - let network_n: u16 = 512; - let validators_n: u16 = 64; - let epochs: u16 = 1; - let interleave = 2; - log::info!( "test_consensus_guarantees ({network_n:?}, {validators_n:?} validators)" ); - for (major_stake, major_weight, minor_weight, weight_stddev) in vec![(0.51, 1., 1., 0.001), (0.51, 0.03, 0., 0.001), (0.51, 0.51, 0.49, 0.001), (0.51, 0.51, 1., 0.001), (0.51, 0.61, 0.8, 0.1), (0.6, 0.67, 0.65, 0.2), (0.6, 0.74, 0.77, 0.4), (0.6, 0.76, 0.8, 0.4), (0.6, 0.76, 1., 0.4), (0.6, 0.92, 1., 0.4), (0.6, 0.94, 1., 0.4), (0.65, 0.78, 0.85, 0.6), (0.7, 0.81, 0.85, 0.8), (0.7, 0.83, 0.85, 1.)] { - let (validators, servers, major_validators, minor_validators, major_servers, minor_servers, stake, weights, _avg_weight_dev) = split_graph(fixed(major_stake), fixed(major_weight), fixed(minor_weight), fixed(weight_stddev), validators_n as usize, network_n as usize, interleave as usize); - - new_test_ext().execute_with(|| { - init_run_epochs(netuid, network_n, &validators, &servers, epochs, 1, true, &stake, true, &weights, true, false, 0, false); - - let mut major_emission: I64F64 = I64F64::from_num(0); - let mut minor_emission: I64F64 = I64F64::from_num(0); - for set in vec![major_validators, major_servers] { - for uid in set { - major_emission += I64F64::from_num(SubtensorModule::get_emission_for_uid( netuid, uid )); - } - } - for set in vec![minor_validators, minor_servers] { - for uid in set { - minor_emission += I64F64::from_num(SubtensorModule::get_emission_for_uid( netuid, uid )); - } - } - let major_ratio: I32F32 = I32F32::from_num(major_emission / (major_emission + minor_emission)); - assert!(major_stake <= major_ratio); - }); - } + let netuid: u16 = 0; + let network_n: u16 = 512; + let validators_n: u16 = 64; + let epochs: u16 = 1; + let interleave = 2; + log::info!("test_consensus_guarantees ({network_n:?}, {validators_n:?} validators)"); + for (major_stake, major_weight, minor_weight, weight_stddev) in vec![ + (0.51, 1., 1., 0.001), + (0.51, 0.03, 0., 0.001), + (0.51, 0.51, 0.49, 0.001), + (0.51, 0.51, 1., 0.001), + (0.51, 0.61, 0.8, 0.1), + (0.6, 0.67, 0.65, 0.2), + (0.6, 0.74, 0.77, 0.4), + (0.6, 0.76, 0.8, 0.4), + (0.6, 0.76, 1., 0.4), + (0.6, 0.92, 1., 0.4), + (0.6, 0.94, 1., 0.4), + (0.65, 0.78, 0.85, 0.6), + (0.7, 0.81, 0.85, 0.8), + (0.7, 0.83, 0.85, 1.), + ] { + let ( + validators, + servers, + major_validators, + minor_validators, + major_servers, + minor_servers, + stake, + weights, + _avg_weight_dev, + ) = split_graph( + fixed(major_stake), + fixed(major_weight), + fixed(minor_weight), + fixed(weight_stddev), + validators_n as usize, + network_n as usize, + interleave as usize, + ); + + new_test_ext().execute_with(|| { + init_run_epochs( + netuid, + network_n, + &validators, + &servers, + epochs, + 1, + true, + &stake, + true, + &weights, + true, + false, + 0, + false, + ); + + let mut major_emission: I64F64 = I64F64::from_num(0); + let mut minor_emission: I64F64 = I64F64::from_num(0); + for set in vec![major_validators, major_servers] { + for uid in set { + major_emission += + I64F64::from_num(SubtensorModule::get_emission_for_uid(netuid, uid)); + } + } + for set in vec![minor_validators, minor_servers] { + for uid in set { + minor_emission += + I64F64::from_num(SubtensorModule::get_emission_for_uid(netuid, uid)); + } + } + let major_ratio: I32F32 = + I32F32::from_num(major_emission / (major_emission + minor_emission)); + assert!(major_stake <= major_ratio); + }); + } } // Test an epoch on an empty graph. #[test] fn test_overflow() { - new_test_ext().execute_with(|| { - log::info!( "test_overflow:" ); - let netuid: u16 = 0; - add_network(netuid, 0, 0); - SubtensorModule::set_max_allowed_uids( netuid, 3 ); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( &U256::from(0), &U256::from(0), 10 ); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( &U256::from(1), &U256::from(1), 10 ); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( &U256::from(2), &U256::from(2), 10 ); - SubtensorModule::append_neuron( netuid, &U256::from(0), 0 ); - SubtensorModule::append_neuron( netuid, &U256::from(1), 0 ); - SubtensorModule::append_neuron( netuid, &U256::from(2), 0 ); - SubtensorModule::set_validator_permit_for_uid(0, 0, true); - SubtensorModule::set_validator_permit_for_uid(0, 1, true); - SubtensorModule::set_validator_permit_for_uid(0, 2, true); - assert_ok!(SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(0)), netuid, vec![ 0, 1, 2 ], vec![ u16::MAX/3, u16::MAX/3, u16::MAX ], 0)); - assert_ok!(SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(1)), netuid, vec![ 1, 2 ], vec![ u16::MAX/2, u16::MAX/2 ], 0)); - assert_ok!(SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(2)), netuid, vec![ 2 ], vec![ u16::MAX ], 0)); - SubtensorModule::epoch( 0, u64::MAX ); - }); + new_test_ext().execute_with(|| { + log::info!("test_overflow:"); + let netuid: u16 = 0; + add_network(netuid, 0, 0); + SubtensorModule::set_max_allowed_uids(netuid, 3); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &U256::from(0), + &U256::from(0), + 10, + ); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &U256::from(1), + &U256::from(1), + 10, + ); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &U256::from(2), + &U256::from(2), + 10, + ); + SubtensorModule::append_neuron(netuid, &U256::from(0), 0); + SubtensorModule::append_neuron(netuid, &U256::from(1), 0); + SubtensorModule::append_neuron(netuid, &U256::from(2), 0); + SubtensorModule::set_validator_permit_for_uid(0, 0, true); + SubtensorModule::set_validator_permit_for_uid(0, 1, true); + SubtensorModule::set_validator_permit_for_uid(0, 2, true); + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(0)), + netuid, + vec![0, 1, 2], + vec![u16::MAX / 3, u16::MAX / 3, u16::MAX], + 0 + )); + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(1)), + netuid, + vec![1, 2], + vec![u16::MAX / 2, u16::MAX / 2], + 0 + )); + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(2)), + netuid, + vec![2], + vec![u16::MAX], + 0 + )); + SubtensorModule::epoch(0, u64::MAX); + }); } // Test an epoch on an empty graph. #[test] fn test_nill_epoch_subtensor() { - new_test_ext().execute_with(|| { - log::info!( "test_nill_epoch:" ); - SubtensorModule::epoch( 0, 0 ); - }); + new_test_ext().execute_with(|| { + log::info!("test_nill_epoch:"); + SubtensorModule::epoch(0, 0); + }); } // Test an epoch on a graph with a single item. #[test] fn test_1_graph() { - new_test_ext().execute_with(|| { - log::info!( "test_1_graph:" ); - let netuid: u16 = 0; - let coldkey = U256::from(0); - let hotkey = U256::from(0); - let uid: u16 = 0; - let stake_amount: u64 = 1; - add_network(netuid, u16::MAX - 1, 0); // set higher tempo to avoid built-in epoch, then manual epoch instead - SubtensorModule::set_max_allowed_uids( netuid, 1 ); - SubtensorModule::add_balance_to_coldkey_account( &coldkey, stake_amount ); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( &coldkey, &hotkey, stake_amount ); - SubtensorModule::append_neuron( netuid, &hotkey, 0 ); - assert_eq!( SubtensorModule::get_subnetwork_n(netuid), 1 ); - run_to_block( 1 ); // run to next block to ensure weights are set on nodes after their registration block - assert_ok!(SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(uid)), netuid, vec![ uid as u16 ], vec![ u16::MAX ], 0)); - // SubtensorModule::set_weights_for_testing( netuid, i as u16, vec![ ( 0, u16::MAX )]); // doesn't set update status - // SubtensorModule::set_bonds_for_testing( netuid, uid, vec![ ( 0, u16::MAX )]); // rather, bonds are calculated in epoch - SubtensorModule::epoch( 0, 1_000_000_000 ); - assert_eq!( SubtensorModule::get_total_stake_for_hotkey( &hotkey ), stake_amount ); - assert_eq!( SubtensorModule::get_rank_for_uid( netuid, uid ), 0 ); - assert_eq!( SubtensorModule::get_trust_for_uid( netuid, uid ), 0 ); - assert_eq!( SubtensorModule::get_consensus_for_uid( netuid, uid ), 0 ); - assert_eq!( SubtensorModule::get_incentive_for_uid( netuid, uid ), 0 ); - assert_eq!( SubtensorModule::get_dividends_for_uid( netuid, uid ), 0 ); - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, uid ), 1_000_000_000 ); - }); + new_test_ext().execute_with(|| { + log::info!("test_1_graph:"); + let netuid: u16 = 0; + let coldkey = U256::from(0); + let hotkey = U256::from(0); + let uid: u16 = 0; + let stake_amount: u64 = 1; + add_network(netuid, u16::MAX - 1, 0); // set higher tempo to avoid built-in epoch, then manual epoch instead + SubtensorModule::set_max_allowed_uids(netuid, 1); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, stake_amount); + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey, &hotkey, stake_amount); + SubtensorModule::append_neuron(netuid, &hotkey, 0); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 1); + run_to_block(1); // run to next block to ensure weights are set on nodes after their registration block + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(uid)), + netuid, + vec![uid as u16], + vec![u16::MAX], + 0 + )); + // SubtensorModule::set_weights_for_testing( netuid, i as u16, vec![ ( 0, u16::MAX )]); // doesn't set update status + // SubtensorModule::set_bonds_for_testing( netuid, uid, vec![ ( 0, u16::MAX )]); // rather, bonds are calculated in epoch + SubtensorModule::epoch(0, 1_000_000_000); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey), + stake_amount + ); + assert_eq!(SubtensorModule::get_rank_for_uid(netuid, uid), 0); + assert_eq!(SubtensorModule::get_trust_for_uid(netuid, uid), 0); + assert_eq!(SubtensorModule::get_consensus_for_uid(netuid, uid), 0); + assert_eq!(SubtensorModule::get_incentive_for_uid(netuid, uid), 0); + assert_eq!(SubtensorModule::get_dividends_for_uid(netuid, uid), 0); + assert_eq!( + SubtensorModule::get_emission_for_uid(netuid, uid), + 1_000_000_000 + ); + }); } // Test an epoch on a graph with two items. #[test] fn test_10_graph() { - new_test_ext().execute_with(|| { - log::info!("test_10_graph" ); - // Function for adding a nodes to the graph. - pub fn add_node( - netuid: u16, - coldkey: U256, - hotkey: U256, - uid: u16, - stake_amount: u64 - ){ - log::info!( - "+Add net:{:?} coldkey:{:?} hotkey:{:?} uid:{:?} stake_amount: {:?} subn: {:?}", - netuid, - coldkey, - hotkey, - uid, - stake_amount, - SubtensorModule::get_subnetwork_n(netuid), - ); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( &coldkey, &hotkey, stake_amount ); - SubtensorModule::append_neuron( netuid, &hotkey, 0 ); - assert_eq!( SubtensorModule::get_subnetwork_n(netuid) - 1 , uid ); - } - // Build the graph with 10 items - // each with 1 stake and self weights. - let n: usize = 10; - let netuid: u16 = 0; - add_network(netuid, u16::MAX - 1, 0); // set higher tempo to avoid built-in epoch, then manual epoch instead - SubtensorModule::set_max_allowed_uids( netuid, n as u16 ); - for i in 0..10 { - add_node( - netuid, - U256::from(i), - U256::from(i), - i as u16, - 1 - ) - } - assert_eq!( SubtensorModule::get_subnetwork_n(netuid), 10 ); - run_to_block( 1 ); // run to next block to ensure weights are set on nodes after their registration block - for i in 0..10 { - assert_ok!(SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(i)), netuid, vec![ i as u16 ], vec![ u16::MAX ], 0)); - } - // Run the epoch. - SubtensorModule::epoch( 0, 1_000_000_000 ); - // Check return values. - for i in 0..n { - assert_eq!( SubtensorModule::get_total_stake_for_hotkey( &(U256::from(i)) ), 1 ); - assert_eq!( SubtensorModule::get_rank_for_uid( netuid, i as u16 ), 0 ); - assert_eq!( SubtensorModule::get_trust_for_uid( netuid, i as u16 ), 0 ); - assert_eq!( SubtensorModule::get_consensus_for_uid( netuid, i as u16 ), 0 ); - assert_eq!( SubtensorModule::get_incentive_for_uid( netuid, i as u16 ), 0 ); - assert_eq!( SubtensorModule::get_dividends_for_uid( netuid, i as u16 ), 0 ); - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, i as u16 ), 99999999 ); - } - }); + new_test_ext().execute_with(|| { + log::info!("test_10_graph"); + // Function for adding a nodes to the graph. + pub fn add_node(netuid: u16, coldkey: U256, hotkey: U256, uid: u16, stake_amount: u64) { + log::info!( + "+Add net:{:?} coldkey:{:?} hotkey:{:?} uid:{:?} stake_amount: {:?} subn: {:?}", + netuid, + coldkey, + hotkey, + uid, + stake_amount, + SubtensorModule::get_subnetwork_n(netuid), + ); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &coldkey, + &hotkey, + stake_amount, + ); + SubtensorModule::append_neuron(netuid, &hotkey, 0); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid) - 1, uid); + } + // Build the graph with 10 items + // each with 1 stake and self weights. + let n: usize = 10; + let netuid: u16 = 0; + add_network(netuid, u16::MAX - 1, 0); // set higher tempo to avoid built-in epoch, then manual epoch instead + SubtensorModule::set_max_allowed_uids(netuid, n as u16); + for i in 0..10 { + add_node(netuid, U256::from(i), U256::from(i), i as u16, 1) + } + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 10); + run_to_block(1); // run to next block to ensure weights are set on nodes after their registration block + for i in 0..10 { + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(i)), + netuid, + vec![i as u16], + vec![u16::MAX], + 0 + )); + } + // Run the epoch. + SubtensorModule::epoch(0, 1_000_000_000); + // Check return values. + for i in 0..n { + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&(U256::from(i))), + 1 + ); + assert_eq!(SubtensorModule::get_rank_for_uid(netuid, i as u16), 0); + assert_eq!(SubtensorModule::get_trust_for_uid(netuid, i as u16), 0); + assert_eq!(SubtensorModule::get_consensus_for_uid(netuid, i as u16), 0); + assert_eq!(SubtensorModule::get_incentive_for_uid(netuid, i as u16), 0); + assert_eq!(SubtensorModule::get_dividends_for_uid(netuid, i as u16), 0); + assert_eq!( + SubtensorModule::get_emission_for_uid(netuid, i as u16), + 99999999 + ); + } + }); } // Test an epoch on a graph with 512 nodes, of which the first 64 are validators setting non-self weights, and the rest servers setting only self-weights. #[test] fn test_512_graph() { - let netuid: u16 = 0; - let network_n: u16 = 512; - let validators_n: u16 = 64; - let max_stake_per_validator: u64 = 328_125_000_000_000; // 21_000_000_000_000_000 / 64 - let epochs: u16 = 3; - log::info!( "test_{network_n:?}_graph ({validators_n:?} validators)" ); - for interleave in 0..3 { - for server_self in vec![false, true] { // server-self weight off/on - let (validators, servers) = distribute_nodes(validators_n as usize, network_n as usize, interleave as usize); - let server: usize = servers[0] as usize; - let validator: usize = validators[0] as usize; - new_test_ext().execute_with(|| { - init_run_epochs(netuid, network_n, &validators, &servers, epochs, max_stake_per_validator, server_self, &vec![], false, &vec![], false, false, 0, false); - let bonds = SubtensorModule::get_bonds( netuid ); - for uid in validators { - assert_eq!( SubtensorModule::get_total_stake_for_hotkey( &(U256::from(uid)) ), max_stake_per_validator ); - assert_eq!( SubtensorModule::get_rank_for_uid( netuid, uid ), 0 ); - assert_eq!( SubtensorModule::get_trust_for_uid( netuid, uid ), 0 ); - assert_eq!( SubtensorModule::get_consensus_for_uid( netuid, uid ), 0 ); - assert_eq!( SubtensorModule::get_incentive_for_uid( netuid, uid ), 0 ); - assert_eq!( SubtensorModule::get_dividends_for_uid( netuid, uid ), 1023 ); // Note D = floor(1 / 64 * 65_535) = 1023 - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, uid ), 7812500 ); // Note E = 0.5 / 200 * 1_000_000_000 = 7_812_500 - assert_eq!( bonds[uid as usize][validator], 0.0 ); - assert_eq!( bonds[uid as usize][server], I32F32::from_num(65_535) ); // Note B_ij = floor(1 / 64 * 65_535) / 65_535 = 1023 / 65_535, then max-upscaled to 65_535 - } - for uid in servers { - assert_eq!( SubtensorModule::get_total_stake_for_hotkey( &(U256::from(uid)) ), 0 ); - assert_eq!( SubtensorModule::get_rank_for_uid( netuid, uid ), 146 ); // Note R = floor(1 / (512 - 64) * 65_535) = 146 - assert_eq!( SubtensorModule::get_trust_for_uid( netuid, uid ), 65535 ); - assert_eq!( SubtensorModule::get_consensus_for_uid( netuid, uid ), 146 ); // Note C = floor(1 / (512 - 64) * 65_535) = 146 - assert_eq!( SubtensorModule::get_incentive_for_uid( netuid, uid ), 146 ); // Note I = floor(1 / (512 - 64) * 65_535) = 146 - assert_eq!( SubtensorModule::get_dividends_for_uid( netuid, uid ), 0 ); - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, uid ), 1116071 ); // Note E = floor(0.5 / (512 - 64) * 1_000_000_000) = 1_116_071 - assert_eq!( bonds[uid as usize][validator], 0.0 ); - assert_eq!( bonds[uid as usize][server], 0.0 ); - } - }); - } - } + let netuid: u16 = 0; + let network_n: u16 = 512; + let validators_n: u16 = 64; + let max_stake_per_validator: u64 = 328_125_000_000_000; // 21_000_000_000_000_000 / 64 + let epochs: u16 = 3; + log::info!("test_{network_n:?}_graph ({validators_n:?} validators)"); + for interleave in 0..3 { + for server_self in vec![false, true] { + // server-self weight off/on + let (validators, servers) = distribute_nodes( + validators_n as usize, + network_n as usize, + interleave as usize, + ); + let server: usize = servers[0] as usize; + let validator: usize = validators[0] as usize; + new_test_ext().execute_with(|| { + init_run_epochs( + netuid, + network_n, + &validators, + &servers, + epochs, + max_stake_per_validator, + server_self, + &vec![], + false, + &vec![], + false, + false, + 0, + false, + ); + let bonds = SubtensorModule::get_bonds(netuid); + for uid in validators { + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&(U256::from(uid))), + max_stake_per_validator + ); + assert_eq!(SubtensorModule::get_rank_for_uid(netuid, uid), 0); + assert_eq!(SubtensorModule::get_trust_for_uid(netuid, uid), 0); + assert_eq!(SubtensorModule::get_consensus_for_uid(netuid, uid), 0); + assert_eq!(SubtensorModule::get_incentive_for_uid(netuid, uid), 0); + assert_eq!(SubtensorModule::get_dividends_for_uid(netuid, uid), 1023); // Note D = floor(1 / 64 * 65_535) = 1023 + assert_eq!(SubtensorModule::get_emission_for_uid(netuid, uid), 7812500); // Note E = 0.5 / 200 * 1_000_000_000 = 7_812_500 + assert_eq!(bonds[uid as usize][validator], 0.0); + assert_eq!(bonds[uid as usize][server], I32F32::from_num(65_535)); + // Note B_ij = floor(1 / 64 * 65_535) / 65_535 = 1023 / 65_535, then max-upscaled to 65_535 + } + for uid in servers { + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&(U256::from(uid))), + 0 + ); + assert_eq!(SubtensorModule::get_rank_for_uid(netuid, uid), 146); // Note R = floor(1 / (512 - 64) * 65_535) = 146 + assert_eq!(SubtensorModule::get_trust_for_uid(netuid, uid), 65535); + assert_eq!(SubtensorModule::get_consensus_for_uid(netuid, uid), 146); // Note C = floor(1 / (512 - 64) * 65_535) = 146 + assert_eq!(SubtensorModule::get_incentive_for_uid(netuid, uid), 146); // Note I = floor(1 / (512 - 64) * 65_535) = 146 + assert_eq!(SubtensorModule::get_dividends_for_uid(netuid, uid), 0); + assert_eq!(SubtensorModule::get_emission_for_uid(netuid, uid), 1116071); // Note E = floor(0.5 / (512 - 64) * 1_000_000_000) = 1_116_071 + assert_eq!(bonds[uid as usize][validator], 0.0); + assert_eq!(bonds[uid as usize][server], 0.0); + } + }); + } + } } // Test an epoch on a graph with 4096 nodes, of which the first 256 are validators setting random non-self weights, and the rest servers setting only self-weights. #[test] fn test_512_graph_random_weights() { - let netuid: u16 = 0; - let network_n: u16 = 512; - let validators_n: u16 = 64; - let epochs: u16 = 1; - log::info!( "test_{network_n:?}_graph_random_weights ({validators_n:?} validators)" ); - for interleave in 0..3 { - for server_self in vec![false, true] { // server-self weight off/on - let (validators, servers) = distribute_nodes(validators_n as usize, network_n as usize, interleave as usize); - let server: usize = servers[0] as usize; - let validator: usize = validators[0] as usize; - let (mut rank, mut incentive, mut dividend, mut emission, mut bondv, mut bonds): (Vec, Vec, Vec, Vec, Vec, Vec) = (vec![], vec![], vec![], vec![], vec![], vec![]); - - // Dense epoch - new_test_ext().execute_with(|| { - init_run_epochs(netuid, network_n, &validators, &servers, epochs, 1, server_self, &vec![], false, &vec![], false, true, interleave as u64, false); - - let bond = SubtensorModule::get_bonds( netuid ); - for uid in 0..network_n { - rank.push( SubtensorModule::get_rank_for_uid( netuid, uid ) ); - incentive.push( SubtensorModule::get_incentive_for_uid( netuid, uid ) ); - dividend.push( SubtensorModule::get_dividends_for_uid( netuid, uid ) ); - emission.push( SubtensorModule::get_emission_for_uid( netuid, uid ) ); - bondv.push( bond[uid as usize][validator] ); - bonds.push( bond[uid as usize][server] ); - } - }); - - // Sparse epoch (same random seed as dense) - new_test_ext().execute_with(|| { - init_run_epochs(netuid, network_n, &validators, &servers, epochs, 1, server_self, &vec![], false, &vec![], false, true, interleave as u64, true); - // Assert that dense and sparse epoch results are equal - let bond = SubtensorModule::get_bonds( netuid ); - for uid in 0..network_n { - assert_eq!( SubtensorModule::get_rank_for_uid( netuid, uid ), rank[uid as usize] ); - assert_eq!( SubtensorModule::get_incentive_for_uid( netuid, uid ), incentive[uid as usize] ); - assert_eq!( SubtensorModule::get_dividends_for_uid( netuid, uid ), dividend[uid as usize] ); - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, uid ), emission[uid as usize] ); - assert_eq!( bond[uid as usize][validator], bondv[uid as usize] ); - assert_eq!( bond[uid as usize][server], bonds[uid as usize] ); - } - }); - } - } + let netuid: u16 = 0; + let network_n: u16 = 512; + let validators_n: u16 = 64; + let epochs: u16 = 1; + log::info!("test_{network_n:?}_graph_random_weights ({validators_n:?} validators)"); + for interleave in 0..3 { + for server_self in vec![false, true] { + // server-self weight off/on + let (validators, servers) = distribute_nodes( + validators_n as usize, + network_n as usize, + interleave as usize, + ); + let server: usize = servers[0] as usize; + let validator: usize = validators[0] as usize; + let (mut rank, mut incentive, mut dividend, mut emission, mut bondv, mut bonds): ( + Vec, + Vec, + Vec, + Vec, + Vec, + Vec, + ) = (vec![], vec![], vec![], vec![], vec![], vec![]); + + // Dense epoch + new_test_ext().execute_with(|| { + init_run_epochs( + netuid, + network_n, + &validators, + &servers, + epochs, + 1, + server_self, + &vec![], + false, + &vec![], + false, + true, + interleave as u64, + false, + ); + + let bond = SubtensorModule::get_bonds(netuid); + for uid in 0..network_n { + rank.push(SubtensorModule::get_rank_for_uid(netuid, uid)); + incentive.push(SubtensorModule::get_incentive_for_uid(netuid, uid)); + dividend.push(SubtensorModule::get_dividends_for_uid(netuid, uid)); + emission.push(SubtensorModule::get_emission_for_uid(netuid, uid)); + bondv.push(bond[uid as usize][validator]); + bonds.push(bond[uid as usize][server]); + } + }); + + // Sparse epoch (same random seed as dense) + new_test_ext().execute_with(|| { + init_run_epochs( + netuid, + network_n, + &validators, + &servers, + epochs, + 1, + server_self, + &vec![], + false, + &vec![], + false, + true, + interleave as u64, + true, + ); + // Assert that dense and sparse epoch results are equal + let bond = SubtensorModule::get_bonds(netuid); + for uid in 0..network_n { + assert_eq!( + SubtensorModule::get_rank_for_uid(netuid, uid), + rank[uid as usize] + ); + assert_eq!( + SubtensorModule::get_incentive_for_uid(netuid, uid), + incentive[uid as usize] + ); + assert_eq!( + SubtensorModule::get_dividends_for_uid(netuid, uid), + dividend[uid as usize] + ); + assert_eq!( + SubtensorModule::get_emission_for_uid(netuid, uid), + emission[uid as usize] + ); + assert_eq!(bond[uid as usize][validator], bondv[uid as usize]); + assert_eq!(bond[uid as usize][server], bonds[uid as usize]); + } + }); + } + } } // Test an epoch on a graph with 4096 nodes, of which the first 256 are validators setting non-self weights, and the rest servers setting only self-weights. // #[test] #[allow(dead_code)] fn test_4096_graph() { - let netuid: u16 = 0; - let network_n: u16 = 4096; - let validators_n: u16 = 256; - let epochs: u16 = 1; - let max_stake_per_validator: u64 = 82_031_250_000_000; // 21_000_000_000_000_000 / 256 - log::info!( "test_{network_n:?}_graph ({validators_n:?} validators)" ); - for interleave in 0..3 { - let (validators, servers) = distribute_nodes(validators_n as usize, network_n as usize, interleave as usize); - let server: usize = servers[0] as usize; - let validator: usize = validators[0] as usize; - for server_self in vec![false, true] { // server-self weight off/on - new_test_ext().execute_with(|| { - init_run_epochs(netuid, network_n, &validators, &servers, epochs, max_stake_per_validator, server_self, &vec![], false, &vec![], false, false, 0, true); - assert_eq!(SubtensorModule::get_total_stake(), 21_000_000_000_000_000); - let bonds = SubtensorModule::get_bonds( netuid ); - for uid in &validators { - assert_eq!( SubtensorModule::get_total_stake_for_hotkey( &(U256::from(*uid as u64)) ), max_stake_per_validator ); - assert_eq!( SubtensorModule::get_rank_for_uid( netuid, *uid ), 0 ); - assert_eq!( SubtensorModule::get_trust_for_uid( netuid, *uid ), 0 ); - assert_eq!( SubtensorModule::get_consensus_for_uid( netuid, *uid ), 0 ); - assert_eq!( SubtensorModule::get_incentive_for_uid( netuid, *uid ), 0 ); - assert_eq!( SubtensorModule::get_dividends_for_uid( netuid, *uid ), 255 ); // Note D = floor(1 / 256 * 65_535) - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, *uid ), 1953125 ); // Note E = 0.5 / 256 * 1_000_000_000 = 1953125 - assert_eq!( bonds[*uid as usize][validator], 0.0 ); - assert_eq!( bonds[*uid as usize][server], I32F32::from_num(255) / I32F32::from_num(65_535) ); // Note B_ij = floor(1 / 256 * 65_535) / 65_535 - } - for uid in &servers { - assert_eq!( SubtensorModule::get_total_stake_for_hotkey( &(U256::from(*uid as u64)) ), 0 ); - assert_eq!( SubtensorModule::get_rank_for_uid( netuid, *uid ), 17 ); // Note R = floor(1 / (4096 - 256) * 65_535) = 17 - assert_eq!( SubtensorModule::get_trust_for_uid( netuid, *uid ), 65535 ); - assert_eq!( SubtensorModule::get_consensus_for_uid( netuid, *uid ), 17 ); // Note C = floor(1 / (4096 - 256) * 65_535) = 17 - assert_eq!( SubtensorModule::get_incentive_for_uid( netuid, *uid ), 17 ); // Note I = floor(1 / (4096 - 256) * 65_535) = 17 - assert_eq!( SubtensorModule::get_dividends_for_uid( netuid, *uid ), 0 ); - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, *uid ), 130208 ); // Note E = floor(0.5 / (4096 - 256) * 1_000_000_000) = 130208 - assert_eq!( bonds[*uid as usize][validator], 0.0 ); - assert_eq!( bonds[*uid as usize][server], 0.0 ); - } - }); - } - } + let netuid: u16 = 0; + let network_n: u16 = 4096; + let validators_n: u16 = 256; + let epochs: u16 = 1; + let max_stake_per_validator: u64 = 82_031_250_000_000; // 21_000_000_000_000_000 / 256 + log::info!("test_{network_n:?}_graph ({validators_n:?} validators)"); + for interleave in 0..3 { + let (validators, servers) = distribute_nodes( + validators_n as usize, + network_n as usize, + interleave as usize, + ); + let server: usize = servers[0] as usize; + let validator: usize = validators[0] as usize; + for server_self in vec![false, true] { + // server-self weight off/on + new_test_ext().execute_with(|| { + init_run_epochs( + netuid, + network_n, + &validators, + &servers, + epochs, + max_stake_per_validator, + server_self, + &vec![], + false, + &vec![], + false, + false, + 0, + true, + ); + assert_eq!(SubtensorModule::get_total_stake(), 21_000_000_000_000_000); + let bonds = SubtensorModule::get_bonds(netuid); + for uid in &validators { + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&(U256::from(*uid as u64))), + max_stake_per_validator + ); + assert_eq!(SubtensorModule::get_rank_for_uid(netuid, *uid), 0); + assert_eq!(SubtensorModule::get_trust_for_uid(netuid, *uid), 0); + assert_eq!(SubtensorModule::get_consensus_for_uid(netuid, *uid), 0); + assert_eq!(SubtensorModule::get_incentive_for_uid(netuid, *uid), 0); + assert_eq!(SubtensorModule::get_dividends_for_uid(netuid, *uid), 255); // Note D = floor(1 / 256 * 65_535) + assert_eq!(SubtensorModule::get_emission_for_uid(netuid, *uid), 1953125); // Note E = 0.5 / 256 * 1_000_000_000 = 1953125 + assert_eq!(bonds[*uid as usize][validator], 0.0); + assert_eq!( + bonds[*uid as usize][server], + I32F32::from_num(255) / I32F32::from_num(65_535) + ); // Note B_ij = floor(1 / 256 * 65_535) / 65_535 + } + for uid in &servers { + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&(U256::from(*uid as u64))), + 0 + ); + assert_eq!(SubtensorModule::get_rank_for_uid(netuid, *uid), 17); // Note R = floor(1 / (4096 - 256) * 65_535) = 17 + assert_eq!(SubtensorModule::get_trust_for_uid(netuid, *uid), 65535); + assert_eq!(SubtensorModule::get_consensus_for_uid(netuid, *uid), 17); // Note C = floor(1 / (4096 - 256) * 65_535) = 17 + assert_eq!(SubtensorModule::get_incentive_for_uid(netuid, *uid), 17); // Note I = floor(1 / (4096 - 256) * 65_535) = 17 + assert_eq!(SubtensorModule::get_dividends_for_uid(netuid, *uid), 0); + assert_eq!(SubtensorModule::get_emission_for_uid(netuid, *uid), 130208); // Note E = floor(0.5 / (4096 - 256) * 1_000_000_000) = 130208 + assert_eq!(bonds[*uid as usize][validator], 0.0); + assert_eq!(bonds[*uid as usize][server], 0.0); + } + }); + } + } } // Test an epoch_sparse on a graph with 16384 nodes, of which the first 512 are validators setting non-self weights, and the rest servers setting only self-weights. // #[test] #[allow(dead_code)] fn test_16384_graph_sparse() { - new_test_ext().execute_with(|| { - let netuid: u16 = 0; - let n: u16 = 16384; - let validators_n: u16 = 512; - let validators: Vec = (0..validators_n).collect(); - let servers: Vec = (validators_n..n).collect(); - let server: u16 = servers[0]; - let epochs: u16 = 1; - log::info!( "test_{n:?}_graph ({validators_n:?} validators)" ); - init_run_epochs(netuid, n, &validators, &servers, epochs, 1, false, &vec![], false, &vec![], false, false, 0, true); - let bonds = SubtensorModule::get_bonds( netuid ); - for uid in validators { - assert_eq!( SubtensorModule::get_total_stake_for_hotkey( &(U256::from(uid)) ), 1 ); - assert_eq!( SubtensorModule::get_rank_for_uid( netuid, uid ), 0 ); - assert_eq!( SubtensorModule::get_trust_for_uid( netuid, uid ), 0 ); - assert_eq!( SubtensorModule::get_consensus_for_uid( netuid, uid ), 438 ); // Note C = 0.0066928507 = (0.0066928507*65_535) = floor( 438.6159706245 ) - assert_eq!( SubtensorModule::get_incentive_for_uid( netuid, uid ), 0 ); - assert_eq!( SubtensorModule::get_dividends_for_uid( netuid, uid ), 127 ); // Note D = floor(1 / 512 * 65_535) = 127 - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, uid ), 976085 ); // Note E = 0.5 / 512 * 1_000_000_000 = 976_562 (discrepancy) - assert_eq!( bonds[uid as usize][0], 0.0 ); - assert_eq!( bonds[uid as usize][server as usize], I32F32::from_num(127) / I32F32::from_num(65_535) ); // Note B_ij = floor(1 / 512 * 65_535) / 65_535 = 127 / 65_535 - } - for uid in servers { - assert_eq!( SubtensorModule::get_total_stake_for_hotkey( &(U256::from(uid)) ), 0 ); - assert_eq!( SubtensorModule::get_rank_for_uid( netuid, uid ), 4 ); // Note R = floor(1 / (16384 - 512) * 65_535) = 4 - assert_eq!( SubtensorModule::get_trust_for_uid( netuid, uid ), 65535 ); - assert_eq!( SubtensorModule::get_consensus_for_uid( netuid, uid ), 4 ); // Note C = floor(1 / (16384 - 512) * 65_535) = 4 - assert_eq!( SubtensorModule::get_incentive_for_uid( netuid, uid ), 4 ); // Note I = floor(1 / (16384 - 512) * 65_535) = 4 - assert_eq!( SubtensorModule::get_dividends_for_uid( netuid, uid ), 0 ); - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, uid ), 31517 ); // Note E = floor(0.5 / (16384 - 512) * 1_000_000_000) = 31502 (discrepancy) - assert_eq!( bonds[uid as usize][0], 0.0 ); - assert_eq!( bonds[uid as usize][server as usize], 0.0 ); - } - }); + new_test_ext().execute_with(|| { + let netuid: u16 = 0; + let n: u16 = 16384; + let validators_n: u16 = 512; + let validators: Vec = (0..validators_n).collect(); + let servers: Vec = (validators_n..n).collect(); + let server: u16 = servers[0]; + let epochs: u16 = 1; + log::info!("test_{n:?}_graph ({validators_n:?} validators)"); + init_run_epochs( + netuid, + n, + &validators, + &servers, + epochs, + 1, + false, + &vec![], + false, + &vec![], + false, + false, + 0, + true, + ); + let bonds = SubtensorModule::get_bonds(netuid); + for uid in validators { + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&(U256::from(uid))), + 1 + ); + assert_eq!(SubtensorModule::get_rank_for_uid(netuid, uid), 0); + assert_eq!(SubtensorModule::get_trust_for_uid(netuid, uid), 0); + assert_eq!(SubtensorModule::get_consensus_for_uid(netuid, uid), 438); // Note C = 0.0066928507 = (0.0066928507*65_535) = floor( 438.6159706245 ) + assert_eq!(SubtensorModule::get_incentive_for_uid(netuid, uid), 0); + assert_eq!(SubtensorModule::get_dividends_for_uid(netuid, uid), 127); // Note D = floor(1 / 512 * 65_535) = 127 + assert_eq!(SubtensorModule::get_emission_for_uid(netuid, uid), 976085); // Note E = 0.5 / 512 * 1_000_000_000 = 976_562 (discrepancy) + assert_eq!(bonds[uid as usize][0], 0.0); + assert_eq!( + bonds[uid as usize][server as usize], + I32F32::from_num(127) / I32F32::from_num(65_535) + ); // Note B_ij = floor(1 / 512 * 65_535) / 65_535 = 127 / 65_535 + } + for uid in servers { + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&(U256::from(uid))), + 0 + ); + assert_eq!(SubtensorModule::get_rank_for_uid(netuid, uid), 4); // Note R = floor(1 / (16384 - 512) * 65_535) = 4 + assert_eq!(SubtensorModule::get_trust_for_uid(netuid, uid), 65535); + assert_eq!(SubtensorModule::get_consensus_for_uid(netuid, uid), 4); // Note C = floor(1 / (16384 - 512) * 65_535) = 4 + assert_eq!(SubtensorModule::get_incentive_for_uid(netuid, uid), 4); // Note I = floor(1 / (16384 - 512) * 65_535) = 4 + assert_eq!(SubtensorModule::get_dividends_for_uid(netuid, uid), 0); + assert_eq!(SubtensorModule::get_emission_for_uid(netuid, uid), 31517); // Note E = floor(0.5 / (16384 - 512) * 1_000_000_000) = 31502 (discrepancy) + assert_eq!(bonds[uid as usize][0], 0.0); + assert_eq!(bonds[uid as usize][server as usize], 0.0); + } + }); } // Test bonds exponential moving average over a sequence of epochs. #[test] fn test_bonds() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let sparse: bool = true; let n: u16 = 8; let netuid: u16 = 0; @@ -815,7 +1198,7 @@ fn test_bonds() { assert_eq!(bonds[1][7], 24609); assert_eq!(bonds[2][7], 49150); assert_eq!(bonds[3][7], 65535); - + run_to_block(6); if sparse { SubtensorModule::epoch( netuid, 1_000_000_000 ); } else { SubtensorModule::epoch_dense( netuid, 1_000_000_000 ); } @@ -879,456 +1262,713 @@ fn test_bonds() { // Test that epoch masks out inactive stake of validators with outdated weights beyond activity cutoff. #[test] fn test_active_stake() { - new_test_ext().execute_with(|| { - let sparse: bool = true; - let n: u16 = 4; - let netuid: u16 = 0; - let tempo: u16 = u16::MAX - 1; // high tempo to skip automatic epochs in on_initialize, use manual epochs instead - let block_number: u64 = 0; - let stake: u64 = 1; - add_network(netuid, tempo, 0); - SubtensorModule::set_max_allowed_uids( netuid, n ); - assert_eq!(SubtensorModule::get_max_allowed_uids(netuid), n); - SubtensorModule::set_max_registrations_per_block( netuid, n ); - - // === Register [validator1, validator2, server1, server2] - for key in 0..n as u64 { - SubtensorModule::add_balance_to_coldkey_account( &U256::from(key), stake ); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, key * 1_000_000, &U256::from(key)); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(key)), netuid, block_number, nonce, work, U256::from(key), U256::from(key))); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( &U256::from(key), &U256::from(key), stake ); - } - assert_eq!(SubtensorModule::get_max_allowed_uids(netuid), n); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), n); - - // === Issue validator permits - assert_ok!( SubtensorModule::sudo_set_max_allowed_validators(<::RuntimeOrigin>::root(), netuid, n) ); - assert_eq!( SubtensorModule::get_max_allowed_validators(netuid), n); - SubtensorModule::epoch( netuid, 1_000_000_000 ); // run first epoch to set allowed validators - run_to_block( 1 ); // run to next block to ensure weights are set on nodes after their registration block - - // === Set weights [val1->srv1: 0.5, val1->srv2: 0.5, val2->srv1: 0.5, val2->srv2: 0.5] - for uid in 0..(n/2) as u64 { - assert_ok!(SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(uid)), netuid, ((n/2)..n).collect(), vec![ u16::MAX / (n/2); (n/2) as usize ], 0)); - } - if sparse { SubtensorModule::epoch( netuid, 1_000_000_000 ); } - else { SubtensorModule::epoch_dense( netuid, 1_000_000_000 ); } - let bonds = SubtensorModule::get_bonds( netuid ); - for uid in 0..n as u16 { - // log::info!("\n{uid}" ); - // uid_stats(netuid, uid); - // log::info!("bonds: {:?}", bonds[uid as usize]); - if uid < n/2 { - assert_eq!( SubtensorModule::get_dividends_for_uid( netuid, uid ), 32767 ); // Note D = floor(0.5 * 65_535) - } - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, uid ), 250000000 ); // Note E = 0.5 / (n/2) * 1_000_000_000 = 250_000_000 - } - for validator in 0..(n/2) as usize { - for on_validator in 0..(n/2) as usize { - assert_eq!( bonds[validator][on_validator], 0 ); - } - for server in ((n/2) as usize)..n as usize { - assert_eq!( bonds[validator][server], I32F32::from_num(65_535) ); // floor(0.5*(2^16-1))/(2^16-1), then max-upscale to 65_535 - } - } - let activity_cutoff: u64 = SubtensorModule::get_activity_cutoff( netuid ) as u64; - run_to_block( activity_cutoff + 2 ); // run to block where validator (uid 0, 1) weights become outdated - - // === Update uid 0 weights - assert_ok!(SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(0)), netuid, ((n/2)..n).collect(), vec![ u16::MAX / (n/2); (n/2) as usize ], 0)); - if sparse { SubtensorModule::epoch( netuid, 1_000_000_000 ); } - else { SubtensorModule::epoch_dense( netuid, 1_000_000_000 ); } - /* current_block: 5002; activity_cutoff: 5000 - Last update: [5002, 1, 0, 0]; Inactive: [false, true, true, true]; Block at registration: [0, 0, 0, 0] - S: [0.25, 0.25, 0.25, 0.25]; S (mask): [0.25, 0, 0, 0]; S (mask+norm): [1, 0, 0, 0] - validator_permits: [true, true, true, true]; max_allowed_validators: 4; new_validator_permits: [true, true, true, true] - W: [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] - W (permit): [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] - W (permit+diag): [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] - W (permit+diag+outdate): [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] - W (mask+norm): [[(2, 0.5), (3, 0.5)], [(2, 0.5), (3, 0.5)], [], []] - R: [0, 0, 0.5, 0.5] - W (threshold): [[(2, 1), (3, 1)], [(2, 1), (3, 1)], [], []] - T: [0, 0, 1, 1] - C: [0.006693358, 0.006693358, 0.9933076561, 0.9933076561] - I: [0, 0, 0.5, 0.5] - B: [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] - B (outdatedmask): [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] - B (mask+norm): [[(2, 0.5), (3, 0.5)], [(2, 0.5), (3, 0.5)], [], []] - ΔB: [[(2, 0.5), (3, 0.5)], [(2, 0), (3, 0)], [], []] - ΔB (norm): [[(2, 1), (3, 1)], [(2, 0), (3, 0)], [], []] - emaB: [[(2, 0.55), (3, 0.55)], [(2, 0.45), (3, 0.45)], [], []] - emaB (max-upscale): [[(2, 1), (3, 1)], [(2, 1), (3, 1)], [], []] - D: [0.55, 0.4499999997, 0, 0] - nE: [0.275, 0.2249999999, 0.25, 0.25] - E: [274999999, 224999999, 250000000, 250000000] - P: [0.275, 0.2249999999, 0.25, 0.25] - P (u16): [65535, 53619, 59577, 59577] */ - let bonds = SubtensorModule::get_bonds( netuid ); - assert_eq!( SubtensorModule::get_dividends_for_uid( netuid, 0 ), 36044 ); // Note D = floor((0.5 * 0.9 + 0.1) * 65_535) - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, 0 ), 274999999 ); // Note E = 0.5 * 0.55 * 1_000_000_000 = 275_000_000 (discrepancy) - for server in ((n/2) as usize)..n as usize { - assert_eq!( bonds[0][server], I32F32::from_num(65_535) ); // floor(0.55*(2^16-1))/(2^16-1), then max-upscale - } - for validator in 1..(n/2) as u16 { - assert_eq!( SubtensorModule::get_dividends_for_uid( netuid, validator ), 29490 ); // Note D = floor((0.5 * 0.9) * 65_535) - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, validator ), 224999999 ); // Note E = 0.5 * 0.45 * 1_000_000_000 = 225_000_000 (discrepancy) - for server in ((n/2) as usize)..n as usize { - assert_eq!( bonds[validator as usize][server], I32F32::from_num(53619) ); // floor(0.45*(2^16-1))/(2^16-1), then max-upscale - } - } - - // === Update uid 1 weights as well - assert_ok!(SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(1)), netuid, ((n/2)..n).collect(), vec![ u16::MAX / (n/2); (n/2) as usize ], 0)); - run_to_block( activity_cutoff + 3 ); // run to block where validator (uid 0, 1) weights become outdated - if sparse { SubtensorModule::epoch( netuid, 1_000_000_000 ); } - else { SubtensorModule::epoch_dense( netuid, 1_000_000_000 ); } - /* current_block: 5003; activity_cutoff: 5000 - Last update: [5002, 5002, 0, 0]; Inactive: [false, false, true, true]; Block at registration: [0, 0, 0, 0] - S: [0.25, 0.25, 0.25, 0.25]; S (mask): [0.25, 0.25, 0, 0]; S (mask+norm): [0.5, 0.5, 0, 0] - validator_permits: [true, true, true, true]; max_allowed_validators: 4; new_validator_permits: [true, true, true, true] - W: [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] - W (permit): [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] - W (permit+diag): [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] - W (permit+diag+outdate): [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] - W (mask+norm): [[(2, 0.5), (3, 0.5)], [(2, 0.5), (3, 0.5)], [], []] - R: [0, 0, 0.5, 0.5] - W (threshold): [[(2, 1), (3, 1)], [(2, 1), (3, 1)], [], []] - T: [0, 0, 1, 1] - C: [0.006693358, 0.006693358, 0.9933076561, 0.9933076561] - I: [0, 0, 0.5, 0.5] - B: [[(2, 65535), (3, 65535)], [(2, 53619), (3, 53619)], [], []] - B (outdatedmask): [[(2, 65535), (3, 65535)], [(2, 53619), (3, 53619)], [], []] - B (mask+norm): [[(2, 0.5500025176), (3, 0.5500025176)], [(2, 0.4499974821), (3, 0.4499974821)], [], []] - ΔB: [[(2, 0.25), (3, 0.25)], [(2, 0.25), (3, 0.25)], [], []] - ΔB (norm): [[(2, 0.5), (3, 0.5)], [(2, 0.5), (3, 0.5)], [], []] - emaB: [[(2, 0.545002266), (3, 0.545002266)], [(2, 0.4549977337), (3, 0.4549977337)], [], []] - emaB (max-upscale): [[(2, 1), (3, 1)], [(2, 0.8348547556), (3, 0.8348547556)], [], []] - D: [0.545002266, 0.4549977337, 0, 0] - nE: [0.272501133, 0.2274988669, 0.25, 0.25] - E: [272501132, 227498866, 250000000, 250000000] - P: [0.272501133, 0.2274988669, 0.25, 0.25] - P (u16): [65535, 54711, 60123, 60123] */ - let bonds = SubtensorModule::get_bonds( netuid ); - assert_eq!( SubtensorModule::get_dividends_for_uid( netuid, 0 ), 35716 ); // Note D = floor((0.55 * 0.9 + 0.5 * 0.1) * 65_535) - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, 0 ), 272501132 ); // Note E = 0.5 * (0.55 * 0.9 + 0.5 * 0.1) * 1_000_000_000 = 272_500_000 (discrepancy) - for server in ((n/2) as usize)..n as usize { - assert_eq!( bonds[0][server], I32F32::from_num(65_535) ); // floor((0.55 * 0.9 + 0.5 * 0.1)*(2^16-1))/(2^16-1), then max-upscale - } - assert_eq!( SubtensorModule::get_dividends_for_uid( netuid, 1 ), 29818 ); // Note D = floor((0.45 * 0.9 + 0.5 * 0.1) * 65_535) - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, 1 ), 227498866 ); // Note E = 0.5 * (0.45 * 0.9 + 0.5 * 0.1) * 1_000_000_000 = 227_500_000 (discrepancy) - for server in ((n/2) as usize)..n as usize { - assert_eq!( bonds[1][server], I32F32::from_num(54712) ); // floor((0.45 * 0.9 + 0.5 * 0.1)/(0.55 * 0.9 + 0.5 * 0.1)*(2^16-1)) - } - }); + new_test_ext().execute_with(|| { + let sparse: bool = true; + let n: u16 = 4; + let netuid: u16 = 0; + let tempo: u16 = u16::MAX - 1; // high tempo to skip automatic epochs in on_initialize, use manual epochs instead + let block_number: u64 = 0; + let stake: u64 = 1; + add_network(netuid, tempo, 0); + SubtensorModule::set_max_allowed_uids(netuid, n); + assert_eq!(SubtensorModule::get_max_allowed_uids(netuid), n); + SubtensorModule::set_max_registrations_per_block(netuid, n); + + // === Register [validator1, validator2, server1, server2] + for key in 0..n as u64 { + SubtensorModule::add_balance_to_coldkey_account(&U256::from(key), stake); + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + key * 1_000_000, + &U256::from(key), + ); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(key)), + netuid, + block_number, + nonce, + work, + U256::from(key), + U256::from(key) + )); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &U256::from(key), + &U256::from(key), + stake, + ); + } + assert_eq!(SubtensorModule::get_max_allowed_uids(netuid), n); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), n); + + // === Issue validator permits + assert_ok!(SubtensorModule::sudo_set_max_allowed_validators( + <::RuntimeOrigin>::root(), + netuid, + n + )); + assert_eq!(SubtensorModule::get_max_allowed_validators(netuid), n); + SubtensorModule::epoch(netuid, 1_000_000_000); // run first epoch to set allowed validators + run_to_block(1); // run to next block to ensure weights are set on nodes after their registration block + + // === Set weights [val1->srv1: 0.5, val1->srv2: 0.5, val2->srv1: 0.5, val2->srv2: 0.5] + for uid in 0..(n / 2) as u64 { + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(uid)), + netuid, + ((n / 2)..n).collect(), + vec![u16::MAX / (n / 2); (n / 2) as usize], + 0 + )); + } + if sparse { + SubtensorModule::epoch(netuid, 1_000_000_000); + } else { + SubtensorModule::epoch_dense(netuid, 1_000_000_000); + } + let bonds = SubtensorModule::get_bonds(netuid); + for uid in 0..n as u16 { + // log::info!("\n{uid}" ); + // uid_stats(netuid, uid); + // log::info!("bonds: {:?}", bonds[uid as usize]); + if uid < n / 2 { + assert_eq!(SubtensorModule::get_dividends_for_uid(netuid, uid), 32767); + // Note D = floor(0.5 * 65_535) + } + assert_eq!( + SubtensorModule::get_emission_for_uid(netuid, uid), + 250000000 + ); // Note E = 0.5 / (n/2) * 1_000_000_000 = 250_000_000 + } + for validator in 0..(n / 2) as usize { + for on_validator in 0..(n / 2) as usize { + assert_eq!(bonds[validator][on_validator], 0); + } + for server in ((n / 2) as usize)..n as usize { + assert_eq!(bonds[validator][server], I32F32::from_num(65_535)); // floor(0.5*(2^16-1))/(2^16-1), then max-upscale to 65_535 + } + } + let activity_cutoff: u64 = SubtensorModule::get_activity_cutoff(netuid) as u64; + run_to_block(activity_cutoff + 2); // run to block where validator (uid 0, 1) weights become outdated + + // === Update uid 0 weights + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(0)), + netuid, + ((n / 2)..n).collect(), + vec![u16::MAX / (n / 2); (n / 2) as usize], + 0 + )); + if sparse { + SubtensorModule::epoch(netuid, 1_000_000_000); + } else { + SubtensorModule::epoch_dense(netuid, 1_000_000_000); + } + /* current_block: 5002; activity_cutoff: 5000 + Last update: [5002, 1, 0, 0]; Inactive: [false, true, true, true]; Block at registration: [0, 0, 0, 0] + S: [0.25, 0.25, 0.25, 0.25]; S (mask): [0.25, 0, 0, 0]; S (mask+norm): [1, 0, 0, 0] + validator_permits: [true, true, true, true]; max_allowed_validators: 4; new_validator_permits: [true, true, true, true] + W: [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] + W (permit): [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] + W (permit+diag): [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] + W (permit+diag+outdate): [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] + W (mask+norm): [[(2, 0.5), (3, 0.5)], [(2, 0.5), (3, 0.5)], [], []] + R: [0, 0, 0.5, 0.5] + W (threshold): [[(2, 1), (3, 1)], [(2, 1), (3, 1)], [], []] + T: [0, 0, 1, 1] + C: [0.006693358, 0.006693358, 0.9933076561, 0.9933076561] + I: [0, 0, 0.5, 0.5] + B: [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] + B (outdatedmask): [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] + B (mask+norm): [[(2, 0.5), (3, 0.5)], [(2, 0.5), (3, 0.5)], [], []] + ΔB: [[(2, 0.5), (3, 0.5)], [(2, 0), (3, 0)], [], []] + ΔB (norm): [[(2, 1), (3, 1)], [(2, 0), (3, 0)], [], []] + emaB: [[(2, 0.55), (3, 0.55)], [(2, 0.45), (3, 0.45)], [], []] + emaB (max-upscale): [[(2, 1), (3, 1)], [(2, 1), (3, 1)], [], []] + D: [0.55, 0.4499999997, 0, 0] + nE: [0.275, 0.2249999999, 0.25, 0.25] + E: [274999999, 224999999, 250000000, 250000000] + P: [0.275, 0.2249999999, 0.25, 0.25] + P (u16): [65535, 53619, 59577, 59577] */ + let bonds = SubtensorModule::get_bonds(netuid); + assert_eq!(SubtensorModule::get_dividends_for_uid(netuid, 0), 36044); // Note D = floor((0.5 * 0.9 + 0.1) * 65_535) + assert_eq!(SubtensorModule::get_emission_for_uid(netuid, 0), 274999999); // Note E = 0.5 * 0.55 * 1_000_000_000 = 275_000_000 (discrepancy) + for server in ((n / 2) as usize)..n as usize { + assert_eq!(bonds[0][server], I32F32::from_num(65_535)); // floor(0.55*(2^16-1))/(2^16-1), then max-upscale + } + for validator in 1..(n / 2) as u16 { + assert_eq!( + SubtensorModule::get_dividends_for_uid(netuid, validator), + 29490 + ); // Note D = floor((0.5 * 0.9) * 65_535) + assert_eq!( + SubtensorModule::get_emission_for_uid(netuid, validator), + 224999999 + ); // Note E = 0.5 * 0.45 * 1_000_000_000 = 225_000_000 (discrepancy) + for server in ((n / 2) as usize)..n as usize { + assert_eq!(bonds[validator as usize][server], I32F32::from_num(53619)); + // floor(0.45*(2^16-1))/(2^16-1), then max-upscale + } + } + + // === Update uid 1 weights as well + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(1)), + netuid, + ((n / 2)..n).collect(), + vec![u16::MAX / (n / 2); (n / 2) as usize], + 0 + )); + run_to_block(activity_cutoff + 3); // run to block where validator (uid 0, 1) weights become outdated + if sparse { + SubtensorModule::epoch(netuid, 1_000_000_000); + } else { + SubtensorModule::epoch_dense(netuid, 1_000_000_000); + } + /* current_block: 5003; activity_cutoff: 5000 + Last update: [5002, 5002, 0, 0]; Inactive: [false, false, true, true]; Block at registration: [0, 0, 0, 0] + S: [0.25, 0.25, 0.25, 0.25]; S (mask): [0.25, 0.25, 0, 0]; S (mask+norm): [0.5, 0.5, 0, 0] + validator_permits: [true, true, true, true]; max_allowed_validators: 4; new_validator_permits: [true, true, true, true] + W: [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] + W (permit): [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] + W (permit+diag): [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] + W (permit+diag+outdate): [[(2, 0.4999923704), (3, 0.4999923704)], [(2, 0.4999923704), (3, 0.4999923704)], [], []] + W (mask+norm): [[(2, 0.5), (3, 0.5)], [(2, 0.5), (3, 0.5)], [], []] + R: [0, 0, 0.5, 0.5] + W (threshold): [[(2, 1), (3, 1)], [(2, 1), (3, 1)], [], []] + T: [0, 0, 1, 1] + C: [0.006693358, 0.006693358, 0.9933076561, 0.9933076561] + I: [0, 0, 0.5, 0.5] + B: [[(2, 65535), (3, 65535)], [(2, 53619), (3, 53619)], [], []] + B (outdatedmask): [[(2, 65535), (3, 65535)], [(2, 53619), (3, 53619)], [], []] + B (mask+norm): [[(2, 0.5500025176), (3, 0.5500025176)], [(2, 0.4499974821), (3, 0.4499974821)], [], []] + ΔB: [[(2, 0.25), (3, 0.25)], [(2, 0.25), (3, 0.25)], [], []] + ΔB (norm): [[(2, 0.5), (3, 0.5)], [(2, 0.5), (3, 0.5)], [], []] + emaB: [[(2, 0.545002266), (3, 0.545002266)], [(2, 0.4549977337), (3, 0.4549977337)], [], []] + emaB (max-upscale): [[(2, 1), (3, 1)], [(2, 0.8348547556), (3, 0.8348547556)], [], []] + D: [0.545002266, 0.4549977337, 0, 0] + nE: [0.272501133, 0.2274988669, 0.25, 0.25] + E: [272501132, 227498866, 250000000, 250000000] + P: [0.272501133, 0.2274988669, 0.25, 0.25] + P (u16): [65535, 54711, 60123, 60123] */ + let bonds = SubtensorModule::get_bonds(netuid); + assert_eq!(SubtensorModule::get_dividends_for_uid(netuid, 0), 35716); // Note D = floor((0.55 * 0.9 + 0.5 * 0.1) * 65_535) + assert_eq!(SubtensorModule::get_emission_for_uid(netuid, 0), 272501132); // Note E = 0.5 * (0.55 * 0.9 + 0.5 * 0.1) * 1_000_000_000 = 272_500_000 (discrepancy) + for server in ((n / 2) as usize)..n as usize { + assert_eq!(bonds[0][server], I32F32::from_num(65_535)); // floor((0.55 * 0.9 + 0.5 * 0.1)*(2^16-1))/(2^16-1), then max-upscale + } + assert_eq!(SubtensorModule::get_dividends_for_uid(netuid, 1), 29818); // Note D = floor((0.45 * 0.9 + 0.5 * 0.1) * 65_535) + assert_eq!(SubtensorModule::get_emission_for_uid(netuid, 1), 227498866); // Note E = 0.5 * (0.45 * 0.9 + 0.5 * 0.1) * 1_000_000_000 = 227_500_000 (discrepancy) + for server in ((n / 2) as usize)..n as usize { + assert_eq!(bonds[1][server], I32F32::from_num(54712)); // floor((0.45 * 0.9 + 0.5 * 0.1)/(0.55 * 0.9 + 0.5 * 0.1)*(2^16-1)) + } + }); } // Test that epoch masks out outdated weights and bonds of validators on deregistered servers. #[test] fn test_outdated_weights() { - new_test_ext().execute_with(|| { - let sparse: bool = true; - let n: u16 = 4; - let netuid: u16 = 0; - let tempo: u16 = u16::MAX - 1; // high tempo to skip automatic epochs in on_initialize, use manual epochs instead - let mut block_number: u64 = 0; - let stake: u64 = 1; - add_network(netuid, tempo, 0); - SubtensorModule::set_max_allowed_uids( netuid, n ); - SubtensorModule::set_weights_set_rate_limit( netuid, 0 ); - SubtensorModule::set_max_registrations_per_block( netuid, n+1 ); // should be n, but RegistrationsThisBlock is not reset (TODO: Saeideh) - - // === Register [validator1, validator2, server1, server2] - for key in 0..n as u64 { - SubtensorModule::add_balance_to_coldkey_account( &U256::from(key), stake ); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, key * 1_000_000, &U256::from(key)); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(key)), netuid, block_number, nonce, work, U256::from(key), U256::from(key))); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( &U256::from(key), &U256::from(key), stake ); - } - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), n); - - // === Issue validator permits - assert_ok!( SubtensorModule::sudo_set_max_allowed_validators(<::RuntimeOrigin>::root(), netuid, n) ); - assert_eq!( SubtensorModule::get_max_allowed_validators(netuid), n); - SubtensorModule::epoch( netuid, 1_000_000_000 ); // run first epoch to set allowed validators - run_to_block( 1 ); block_number += 1; // run to next block to ensure weights are set on nodes after their registration block - - // === Set weights [val1->srv1: 2/3, val1->srv2: 1/3, val2->srv1: 2/3, val2->srv2: 1/3, srv1->srv1: 1, srv2->srv2: 1] - for uid in 0..(n/2) as u64 { - assert_ok!(SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(uid)), netuid, ((n/2)..n).collect(), vec![ 2 * (u16::MAX / 3), u16::MAX / 3 ], 0)); - } - for uid in ((n/2) as u64)..n as u64 { - assert_ok!(SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(uid)), netuid, vec![ uid as u16 ], vec![ u16::MAX ], 0)); // server self-weight - } - if sparse { SubtensorModule::epoch( netuid, 1_000_000_000 ); } - else { SubtensorModule::epoch_dense( netuid, 1_000_000_000 ); } - /* current_block: 1; activity_cutoff: 5000 - Last update: [1, 1, 1, 1]; Inactive: [false, false, false, false]; Block at registration: [0, 0, 0, 0] - S: [0.25, 0.25, 0.25, 0.25]; S (mask): [0.25, 0.25, 0.25, 0.25]; S (mask+norm): [0.25, 0.25, 0.25, 0.25] - validator_permits: [true, true, true, true]; max_allowed_validators: 4; new_validator_permits: [true, true, true, true] - W: [[(2, 65535), (3, 32768)], [(2, 65535), (3, 32768)], [(2, 65535)], [(3, 65535)]] - W (permit): [[(2, 65535), (3, 32768)], [(2, 65535), (3, 32768)], [(2, 65535)], [(3, 65535)]] - W (permit+diag): [[(2, 65535), (3, 32768)], [(2, 65535), (3, 32768)], [], []] - W (permit+diag+outdate): [[(2, 65535), (3, 32768)], [(2, 65535), (3, 32768)], [], []] - W (mask+norm): [[(2, 0.6666632756), (3, 0.3333367242)], [(2, 0.6666632756), (3, 0.3333367242)], [], []] - R (before): [0, 0, 0.3333316376, 0.166668362] - C: [0, 0, 0.6666632756, 0.3333367242] - W: [[(2, 0.6666632756), (3, 0.3333367242)], [(2, 0.6666632756), (3, 0.3333367242)], [], []] - Tv: [0.9999999998, 0.9999999998, 0, 0] - R (after): [0, 0, 0.3333316376, 0.166668362] - T: [0, 0, 1, 1] - I (=R): [0, 0, 0.6666632756, 0.3333367242] - B: [[], [], [], []] - B (outdatedmask): [[], [], [], []] - B (mask+norm): [[], [], [], []] - ΔB: [[(2, 0.1666658188), (3, 0.083334181)], [(2, 0.1666658188), (3, 0.083334181)], [], []] - ΔB (norm): [[(2, 0.5), (3, 0.5)], [(2, 0.5), (3, 0.5)], [], []] - emaB: [[(2, 0.5), (3, 0.5)], [(2, 0.5), (3, 0.5)], [], []] - D: [0.5, 0.5, 0, 0] - nE: [0.25, 0.25, 0.3333316378, 0.166668362] - E: [250000000, 250000000, 333331637, 166668361] - P: [0.25, 0.25, 0.3333316378, 0.166668362] - P (u16): [49151, 49151, 65535, 32767] */ - - // === Dereg server2 at uid3 (least emission) + register new key over uid3 - let new_key: u64 = n as u64; // register a new key while at max capacity, which means the least incentive uid will be deregistered - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 0, &U256::from(new_key)); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(new_key)), netuid, block_number, nonce, work, U256::from(new_key), U256::from(new_key))); - let deregistered_uid: u16 = n-1; // since uid=n-1 only recieved 1/3 of weight, it will get pruned first - assert_eq!(U256::from(new_key), SubtensorModule::get_hotkey_for_net_and_uid(netuid, deregistered_uid).expect("Not registered")); - run_to_block( 2 ); // run to next block to outdate weights and bonds set on deregistered uid - - // === Update weights from only uid=0 - assert_ok!(SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(0)), netuid, ((n/2)..n).collect(), vec![ 2 * (u16::MAX / 3), u16::MAX / 3 ], 0)); - if sparse { SubtensorModule::epoch( netuid, 1_000_000_000 ); } - else { SubtensorModule::epoch_dense( netuid, 1_000_000_000 ); } - /* current_block: 2; activity_cutoff: 5000 - Last update: [2, 1, 1, 1]; Inactive: [false, false, false, false]; Block at registration: [0, 0, 0, 1] - S: [0.3333333333, 0.3333333333, 0.3333333333, 0] - S (mask): [0.3333333333, 0.3333333333, 0.3333333333, 0] - S (mask+norm): [0.3333333333, 0.3333333333, 0.3333333333, 0] - validator_permits: [true, true, true, false]; max_allowed_validators: 4; new_validator_permits: [true, true, true, true] - W: [[(2, 65535), (3, 32768)], [(2, 65535), (3, 32768)], [(2, 65535)], [(3, 65535)]] - W (permit): [[(2, 65535), (3, 32768)], [(2, 65535), (3, 32768)], [(2, 65535)], [(3, 65535)]] - W (permit+diag): [[(2, 65535), (3, 32768)], [(2, 65535), (3, 32768)], [], []] - W (permit+diag+outdate): [[(2, 65535), (3, 32768)], [(2, 65535)], [], []] - W (mask+norm): [[(2, 0.6666632756), (3, 0.3333367242)], [(2, 1)], [], []] - R (before): [0, 0, 0.5555544249, 0.1111122412] - C: [0, 0, 0.6666632756, 0] - W: [[(2, 0.6666632756)], [(2, 0.6666632756)], [], []] - Tv: [0.6666632756, 0.6666632756, 0, 0] - R (after): [0, 0, 0.4444421832, 0] - T: [0, 0, 0.799997558, 0] - I (=R): [0, 0, 1, 0] - B: [[(2, 65535), (3, 65535)], [(2, 65535), (3, 65535)], [], []] - B (outdatedmask): [[(2, 65535), (3, 65535)], [(2, 65535)], [], []] - B (mask+norm): [[(2, 0.5), (3, 1)], [(2, 0.5)], [], []] - ΔB: [[(2, 0.2222210916)], [(2, 0.2222210916)], [], []] - ΔB (norm): [[(2, 0.5)], [(2, 0.5)], [], []] - emaB: [[(2, 0.5), (3, 1)], [(2, 0.5)], [], []] - emaB (max-upscale): [[(2, 1), (3, 1)], [(2, 1)], [], []] - D: [0.5, 0.5, 0, 0] - nE: [0.25, 0.25, 0.5, 0] - E: [250000000, 250000000, 500000000, 0] - P: [0.25, 0.25, 0.5, 0] - P (u16): [32767, 32767, 65535, 0] */ - let bonds = SubtensorModule::get_bonds( netuid ); - assert_eq!( SubtensorModule::get_dividends_for_uid( netuid, 0 ), 32767 ); // Note D = floor(0.5 * 65_535) - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, 0 ), 250000000 ); // Note E = 0.5 * 0.5 * 1_000_000_000 = 249311245 - assert_eq!( bonds[0][2], I32F32::from_num(65_535) ); // floor(0.5*(2^16-1))/(2^16-1), then max-upscale - assert_eq!( bonds[0][3], I32F32::from_num(65_535) ); // only uid0 has updated weights for new reg - }); + new_test_ext().execute_with(|| { + let sparse: bool = true; + let n: u16 = 4; + let netuid: u16 = 0; + let tempo: u16 = u16::MAX - 1; // high tempo to skip automatic epochs in on_initialize, use manual epochs instead + let mut block_number: u64 = 0; + let stake: u64 = 1; + add_network(netuid, tempo, 0); + SubtensorModule::set_max_allowed_uids(netuid, n); + SubtensorModule::set_weights_set_rate_limit(netuid, 0); + SubtensorModule::set_max_registrations_per_block(netuid, n + 1); // should be n, but RegistrationsThisBlock is not reset (TODO: Saeideh) + + // === Register [validator1, validator2, server1, server2] + for key in 0..n as u64 { + SubtensorModule::add_balance_to_coldkey_account(&U256::from(key), stake); + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + key * 1_000_000, + &U256::from(key), + ); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(key)), + netuid, + block_number, + nonce, + work, + U256::from(key), + U256::from(key) + )); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &U256::from(key), + &U256::from(key), + stake, + ); + } + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), n); + + // === Issue validator permits + assert_ok!(SubtensorModule::sudo_set_max_allowed_validators( + <::RuntimeOrigin>::root(), + netuid, + n + )); + assert_eq!(SubtensorModule::get_max_allowed_validators(netuid), n); + SubtensorModule::epoch(netuid, 1_000_000_000); // run first epoch to set allowed validators + run_to_block(1); + block_number += 1; // run to next block to ensure weights are set on nodes after their registration block + + // === Set weights [val1->srv1: 2/3, val1->srv2: 1/3, val2->srv1: 2/3, val2->srv2: 1/3, srv1->srv1: 1, srv2->srv2: 1] + for uid in 0..(n / 2) as u64 { + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(uid)), + netuid, + ((n / 2)..n).collect(), + vec![2 * (u16::MAX / 3), u16::MAX / 3], + 0 + )); + } + for uid in ((n / 2) as u64)..n as u64 { + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(uid)), + netuid, + vec![uid as u16], + vec![u16::MAX], + 0 + )); // server self-weight + } + if sparse { + SubtensorModule::epoch(netuid, 1_000_000_000); + } else { + SubtensorModule::epoch_dense(netuid, 1_000_000_000); + } + /* current_block: 1; activity_cutoff: 5000 + Last update: [1, 1, 1, 1]; Inactive: [false, false, false, false]; Block at registration: [0, 0, 0, 0] + S: [0.25, 0.25, 0.25, 0.25]; S (mask): [0.25, 0.25, 0.25, 0.25]; S (mask+norm): [0.25, 0.25, 0.25, 0.25] + validator_permits: [true, true, true, true]; max_allowed_validators: 4; new_validator_permits: [true, true, true, true] + W: [[(2, 65535), (3, 32768)], [(2, 65535), (3, 32768)], [(2, 65535)], [(3, 65535)]] + W (permit): [[(2, 65535), (3, 32768)], [(2, 65535), (3, 32768)], [(2, 65535)], [(3, 65535)]] + W (permit+diag): [[(2, 65535), (3, 32768)], [(2, 65535), (3, 32768)], [], []] + W (permit+diag+outdate): [[(2, 65535), (3, 32768)], [(2, 65535), (3, 32768)], [], []] + W (mask+norm): [[(2, 0.6666632756), (3, 0.3333367242)], [(2, 0.6666632756), (3, 0.3333367242)], [], []] + R (before): [0, 0, 0.3333316376, 0.166668362] + C: [0, 0, 0.6666632756, 0.3333367242] + W: [[(2, 0.6666632756), (3, 0.3333367242)], [(2, 0.6666632756), (3, 0.3333367242)], [], []] + Tv: [0.9999999998, 0.9999999998, 0, 0] + R (after): [0, 0, 0.3333316376, 0.166668362] + T: [0, 0, 1, 1] + I (=R): [0, 0, 0.6666632756, 0.3333367242] + B: [[], [], [], []] + B (outdatedmask): [[], [], [], []] + B (mask+norm): [[], [], [], []] + ΔB: [[(2, 0.1666658188), (3, 0.083334181)], [(2, 0.1666658188), (3, 0.083334181)], [], []] + ΔB (norm): [[(2, 0.5), (3, 0.5)], [(2, 0.5), (3, 0.5)], [], []] + emaB: [[(2, 0.5), (3, 0.5)], [(2, 0.5), (3, 0.5)], [], []] + D: [0.5, 0.5, 0, 0] + nE: [0.25, 0.25, 0.3333316378, 0.166668362] + E: [250000000, 250000000, 333331637, 166668361] + P: [0.25, 0.25, 0.3333316378, 0.166668362] + P (u16): [49151, 49151, 65535, 32767] */ + + // === Dereg server2 at uid3 (least emission) + register new key over uid3 + let new_key: u64 = n as u64; // register a new key while at max capacity, which means the least incentive uid will be deregistered + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 0, + &U256::from(new_key), + ); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(new_key)), + netuid, + block_number, + nonce, + work, + U256::from(new_key), + U256::from(new_key) + )); + let deregistered_uid: u16 = n - 1; // since uid=n-1 only recieved 1/3 of weight, it will get pruned first + assert_eq!( + U256::from(new_key), + SubtensorModule::get_hotkey_for_net_and_uid(netuid, deregistered_uid) + .expect("Not registered") + ); + run_to_block(2); // run to next block to outdate weights and bonds set on deregistered uid + + // === Update weights from only uid=0 + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(0)), + netuid, + ((n / 2)..n).collect(), + vec![2 * (u16::MAX / 3), u16::MAX / 3], + 0 + )); + if sparse { + SubtensorModule::epoch(netuid, 1_000_000_000); + } else { + SubtensorModule::epoch_dense(netuid, 1_000_000_000); + } + /* current_block: 2; activity_cutoff: 5000 + Last update: [2, 1, 1, 1]; Inactive: [false, false, false, false]; Block at registration: [0, 0, 0, 1] + S: [0.3333333333, 0.3333333333, 0.3333333333, 0] + S (mask): [0.3333333333, 0.3333333333, 0.3333333333, 0] + S (mask+norm): [0.3333333333, 0.3333333333, 0.3333333333, 0] + validator_permits: [true, true, true, false]; max_allowed_validators: 4; new_validator_permits: [true, true, true, true] + W: [[(2, 65535), (3, 32768)], [(2, 65535), (3, 32768)], [(2, 65535)], [(3, 65535)]] + W (permit): [[(2, 65535), (3, 32768)], [(2, 65535), (3, 32768)], [(2, 65535)], [(3, 65535)]] + W (permit+diag): [[(2, 65535), (3, 32768)], [(2, 65535), (3, 32768)], [], []] + W (permit+diag+outdate): [[(2, 65535), (3, 32768)], [(2, 65535)], [], []] + W (mask+norm): [[(2, 0.6666632756), (3, 0.3333367242)], [(2, 1)], [], []] + R (before): [0, 0, 0.5555544249, 0.1111122412] + C: [0, 0, 0.6666632756, 0] + W: [[(2, 0.6666632756)], [(2, 0.6666632756)], [], []] + Tv: [0.6666632756, 0.6666632756, 0, 0] + R (after): [0, 0, 0.4444421832, 0] + T: [0, 0, 0.799997558, 0] + I (=R): [0, 0, 1, 0] + B: [[(2, 65535), (3, 65535)], [(2, 65535), (3, 65535)], [], []] + B (outdatedmask): [[(2, 65535), (3, 65535)], [(2, 65535)], [], []] + B (mask+norm): [[(2, 0.5), (3, 1)], [(2, 0.5)], [], []] + ΔB: [[(2, 0.2222210916)], [(2, 0.2222210916)], [], []] + ΔB (norm): [[(2, 0.5)], [(2, 0.5)], [], []] + emaB: [[(2, 0.5), (3, 1)], [(2, 0.5)], [], []] + emaB (max-upscale): [[(2, 1), (3, 1)], [(2, 1)], [], []] + D: [0.5, 0.5, 0, 0] + nE: [0.25, 0.25, 0.5, 0] + E: [250000000, 250000000, 500000000, 0] + P: [0.25, 0.25, 0.5, 0] + P (u16): [32767, 32767, 65535, 0] */ + let bonds = SubtensorModule::get_bonds(netuid); + assert_eq!(SubtensorModule::get_dividends_for_uid(netuid, 0), 32767); // Note D = floor(0.5 * 65_535) + assert_eq!(SubtensorModule::get_emission_for_uid(netuid, 0), 250000000); // Note E = 0.5 * 0.5 * 1_000_000_000 = 249311245 + assert_eq!(bonds[0][2], I32F32::from_num(65_535)); // floor(0.5*(2^16-1))/(2^16-1), then max-upscale + assert_eq!(bonds[0][3], I32F32::from_num(65_535)); // only uid0 has updated weights for new reg + }); } // Test the zero emission handling and fallback under zero effective weight conditions, to ensure non-zero effective emission. #[test] fn test_zero_weights() { - new_test_ext().execute_with(|| { - let sparse: bool = true; - let n: u16 = 2; - let netuid: u16 = 0; - let tempo: u16 = u16::MAX - 1; // high tempo to skip automatic epochs in on_initialize, use manual epochs instead - let mut block_number: u64 = 0; - let stake: u64 = 1; - add_network(netuid, tempo, 0); - SubtensorModule::set_max_allowed_uids( netuid, n ); - SubtensorModule::set_weights_set_rate_limit( netuid, 0 ); - SubtensorModule::set_max_registrations_per_block( netuid, n+1 ); // should be n, but RegistrationsThisBlock is not reset (TODO: Saeideh) - - // === Register [validator, server] - for key in 0..n as u64 { - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, key * 1_000_000, &U256::from(key)); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(key)), netuid, block_number, nonce, work, U256::from(key), U256::from(key))); - } - for validator in 0..(n/2) as u64 { - SubtensorModule::add_balance_to_coldkey_account( &U256::from(validator), stake ); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( &U256::from(validator), &U256::from(validator), stake ); - } - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), n); - - // === No weights - if sparse { SubtensorModule::epoch( netuid, 1_000_000_000 ); } - else { SubtensorModule::epoch_dense( netuid, 1_000_000_000 ); } - /* current_block: 0; activity_cutoff: 5000; Last update: [0, 0]; Inactive: [false, false] - S: [1, 0]; S (mask): [1, 0]; S (mask+norm): [1, 0]; Block at registration: [0, 0] - W: [[], []]; W (diagmask): [[], []]; W (diag+outdatemask): [[], []]; W (mask+norm): [[], []] - R: [0, 0]; W (threshold): [[], []]; T: [0, 0]; C: [0.006693358, 0.006693358]; I: [0, 0] - B: [[], []]; B (outdatedmask): [[], []]; B (mask+norm): [[], []]; - ΔB: [[], []]; ΔB (norm): [[], []]; emaB: [[], []]; D: [0, 0] - E: [1000000000, 0]; P: [1, 0] */ - for validator in 0..(n/2) as u16 { - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, validator ), 1000000000 ); // Note E = 1 * 1_000_000_000 - } - for server in (n/2)..n as u16 { - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, server ), 0 ); // no stake - } - run_to_block( 1 ); block_number += 1; // run to next block to ensure weights are set on nodes after their registration block - - // === Self-weights only: set weights [srv->srv: 1] - for uid in ((n/2) as u64)..n as u64 { - assert_ok!(SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(uid)), netuid, vec![ uid as u16 ], vec![ u16::MAX ], 0)); // server self-weight - } - if sparse { SubtensorModule::epoch( netuid, 1_000_000_000 ); } - else { SubtensorModule::epoch_dense( netuid, 1_000_000_000 ); } - /* current_block: 1; activity_cutoff: 5000; Last update: [0, 1]; Inactive: [false, false] - S: [1, 0]; S (mask): [1, 0]; S (mask+norm): [1, 0]; Block at registration: [0, 0] - W: [[], [(1, 1)]] - W (diagmask): [[], []]; W (diag+outdatemask): [[], []]; W (mask+norm): [[], []] - R: [0, 0]; W (threshold): [[], []]; T: [0, 0]; C: [0.006693358, 0.006693358]; I: [0, 0] - B: [[], []]: B (outdatedmask): [[], []]; B (mask+norm): [[], []] - ΔB: [[], []]; ΔB (norm): [[], []]; emaB: [[], []]; D: [0, 0] - E: [1000000000, 0]; P: [1, 0] */ - for validator in 0..(n/2) as u16 { - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, validator ), 1000000000 ); // Note E = 1 * 1_000_000_000 - } - for server in (n/2)..n as u16 { - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, server ), 0 ); // no stake - } - run_to_block( 2 ); block_number += 1; - - // === Set weights [val->srv: 1/(n/2)] - for uid in 0..(n/2) as u64 { - assert_ok!(SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(uid)), netuid, ((n/2)..n).collect(), vec![ u16::MAX / (n/2); (n/2) as usize ], 0)); - } - - // === Outdate weights by reregistering servers - for new_key in n..n+(n/2) {// register a new key while at max capacity, which means the least emission uid will be deregistered - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, new_key as u64 * 1_000_000, &(U256::from(new_key))); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(new_key)), netuid, block_number, nonce, work, U256::from(new_key), U256::from(new_key))); - } - if sparse { SubtensorModule::epoch( netuid, 1_000_000_000 ); } - else { SubtensorModule::epoch_dense( netuid, 1_000_000_000 ); } - /* current_block: 2; activity_cutoff: 5000; Last update: [2, 1]; Inactive: [false, false]; - S: [1, 0]; S (mask): [1, 0]; S (mask+norm): [1, 0]; Block at registration: [0, 2]; - W: [[(1, 1)], []]; W (diagmask): [[(1, 1)], []]; W (diag+outdatemask): [[], []]; W (mask+norm): [[], []]; - R: [0, 0]; W (threshold): [[], []]; T: [0, 0]; C: [0.006693358, 0.006693358]; I: [0, 0]; - B: [[], []]; B (outdatedmask): [[], []]; B (mask+norm): [[], []]; - ΔB: [[], []]; ΔB (norm): [[], []]; emaB: [[], []]; D: [0, 0]; - E: [1000000000, 0]; P: [1, 0] */ - for validator in 0..(n/2) as u16 { - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, validator ), 1000000000 ); // Note E = 1 * 1_000_000_000 - } - for server in (n/2)..n as u16 { - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, server ), 0 ); // no stake - } - run_to_block( 3 ); - - // === Set new weights [val->srv: 1/(n/2)] to check that updated weights would produce non-zero incentive - for uid in 0..(n/2) as u64 { - assert_ok!(SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(uid)), netuid, ((n/2)..n).collect(), vec![ u16::MAX / (n/2); (n/2) as usize], 0)); - } - if sparse { SubtensorModule::epoch( netuid, 1_000_000_000 ); } - else { SubtensorModule::epoch_dense( netuid, 1_000_000_000 ); } - /* current_block: 3; activity_cutoff: 5000; Last update: [3, 1]; Inactive: [false, false]; - S: [1, 0]; S (mask): [1, 0]; S (mask+norm): [1, 0]; Block at registration: [0, 2]; - W: [[(1, 1)], []]; W (diagmask): [[(1, 1)], []]; W (diag+outdatemask): [[(1, 1)], []]; W (mask+norm): [[(1, 1)], []]; - R: [0, 1]; W (threshold): [[(1, 1)], []]; T: [0, 1]; C: [0.006693358, 0.9933076561]; I: [0, 1]; - B: [[], []]; B (outdatedmask): [[], []]; B (mask+norm): [[], []]; - ΔB: [[(1, 1)], []]; ΔB (norm): [[(1, 1)], []]; emaB: [[(1, 1)], []]; D: [1, 0]; emaB (max-upscale): [[(1, 1)], []] - E: [500000000, 500000000]; P: [0.5, 0.5] */ - for validator in 0..n as u16 { - assert_eq!( SubtensorModule::get_emission_for_uid( netuid, validator ), 1000000000 / (n as u64) ); // Note E = 1/2 * 1_000_000_000 - } - }); + new_test_ext().execute_with(|| { + let sparse: bool = true; + let n: u16 = 2; + let netuid: u16 = 0; + let tempo: u16 = u16::MAX - 1; // high tempo to skip automatic epochs in on_initialize, use manual epochs instead + let mut block_number: u64 = 0; + let stake: u64 = 1; + add_network(netuid, tempo, 0); + SubtensorModule::set_max_allowed_uids(netuid, n); + SubtensorModule::set_weights_set_rate_limit(netuid, 0); + SubtensorModule::set_max_registrations_per_block(netuid, n + 1); // should be n, but RegistrationsThisBlock is not reset (TODO: Saeideh) + + // === Register [validator, server] + for key in 0..n as u64 { + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + key * 1_000_000, + &U256::from(key), + ); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(key)), + netuid, + block_number, + nonce, + work, + U256::from(key), + U256::from(key) + )); + } + for validator in 0..(n / 2) as u64 { + SubtensorModule::add_balance_to_coldkey_account(&U256::from(validator), stake); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &U256::from(validator), + &U256::from(validator), + stake, + ); + } + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), n); + + // === No weights + if sparse { + SubtensorModule::epoch(netuid, 1_000_000_000); + } else { + SubtensorModule::epoch_dense(netuid, 1_000_000_000); + } + /* current_block: 0; activity_cutoff: 5000; Last update: [0, 0]; Inactive: [false, false] + S: [1, 0]; S (mask): [1, 0]; S (mask+norm): [1, 0]; Block at registration: [0, 0] + W: [[], []]; W (diagmask): [[], []]; W (diag+outdatemask): [[], []]; W (mask+norm): [[], []] + R: [0, 0]; W (threshold): [[], []]; T: [0, 0]; C: [0.006693358, 0.006693358]; I: [0, 0] + B: [[], []]; B (outdatedmask): [[], []]; B (mask+norm): [[], []]; + ΔB: [[], []]; ΔB (norm): [[], []]; emaB: [[], []]; D: [0, 0] + E: [1000000000, 0]; P: [1, 0] */ + for validator in 0..(n / 2) as u16 { + assert_eq!( + SubtensorModule::get_emission_for_uid(netuid, validator), + 1000000000 + ); // Note E = 1 * 1_000_000_000 + } + for server in (n / 2)..n as u16 { + assert_eq!(SubtensorModule::get_emission_for_uid(netuid, server), 0); + // no stake + } + run_to_block(1); + block_number += 1; // run to next block to ensure weights are set on nodes after their registration block + + // === Self-weights only: set weights [srv->srv: 1] + for uid in ((n / 2) as u64)..n as u64 { + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(uid)), + netuid, + vec![uid as u16], + vec![u16::MAX], + 0 + )); // server self-weight + } + if sparse { + SubtensorModule::epoch(netuid, 1_000_000_000); + } else { + SubtensorModule::epoch_dense(netuid, 1_000_000_000); + } + /* current_block: 1; activity_cutoff: 5000; Last update: [0, 1]; Inactive: [false, false] + S: [1, 0]; S (mask): [1, 0]; S (mask+norm): [1, 0]; Block at registration: [0, 0] + W: [[], [(1, 1)]] + W (diagmask): [[], []]; W (diag+outdatemask): [[], []]; W (mask+norm): [[], []] + R: [0, 0]; W (threshold): [[], []]; T: [0, 0]; C: [0.006693358, 0.006693358]; I: [0, 0] + B: [[], []]: B (outdatedmask): [[], []]; B (mask+norm): [[], []] + ΔB: [[], []]; ΔB (norm): [[], []]; emaB: [[], []]; D: [0, 0] + E: [1000000000, 0]; P: [1, 0] */ + for validator in 0..(n / 2) as u16 { + assert_eq!( + SubtensorModule::get_emission_for_uid(netuid, validator), + 1000000000 + ); // Note E = 1 * 1_000_000_000 + } + for server in (n / 2)..n as u16 { + assert_eq!(SubtensorModule::get_emission_for_uid(netuid, server), 0); + // no stake + } + run_to_block(2); + block_number += 1; + + // === Set weights [val->srv: 1/(n/2)] + for uid in 0..(n / 2) as u64 { + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(uid)), + netuid, + ((n / 2)..n).collect(), + vec![u16::MAX / (n / 2); (n / 2) as usize], + 0 + )); + } + + // === Outdate weights by reregistering servers + for new_key in n..n + (n / 2) { + // register a new key while at max capacity, which means the least emission uid will be deregistered + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + new_key as u64 * 1_000_000, + &(U256::from(new_key)), + ); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(new_key)), + netuid, + block_number, + nonce, + work, + U256::from(new_key), + U256::from(new_key) + )); + } + if sparse { + SubtensorModule::epoch(netuid, 1_000_000_000); + } else { + SubtensorModule::epoch_dense(netuid, 1_000_000_000); + } + /* current_block: 2; activity_cutoff: 5000; Last update: [2, 1]; Inactive: [false, false]; + S: [1, 0]; S (mask): [1, 0]; S (mask+norm): [1, 0]; Block at registration: [0, 2]; + W: [[(1, 1)], []]; W (diagmask): [[(1, 1)], []]; W (diag+outdatemask): [[], []]; W (mask+norm): [[], []]; + R: [0, 0]; W (threshold): [[], []]; T: [0, 0]; C: [0.006693358, 0.006693358]; I: [0, 0]; + B: [[], []]; B (outdatedmask): [[], []]; B (mask+norm): [[], []]; + ΔB: [[], []]; ΔB (norm): [[], []]; emaB: [[], []]; D: [0, 0]; + E: [1000000000, 0]; P: [1, 0] */ + for validator in 0..(n / 2) as u16 { + assert_eq!( + SubtensorModule::get_emission_for_uid(netuid, validator), + 1000000000 + ); // Note E = 1 * 1_000_000_000 + } + for server in (n / 2)..n as u16 { + assert_eq!(SubtensorModule::get_emission_for_uid(netuid, server), 0); + // no stake + } + run_to_block(3); + + // === Set new weights [val->srv: 1/(n/2)] to check that updated weights would produce non-zero incentive + for uid in 0..(n / 2) as u64 { + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(uid)), + netuid, + ((n / 2)..n).collect(), + vec![u16::MAX / (n / 2); (n / 2) as usize], + 0 + )); + } + if sparse { + SubtensorModule::epoch(netuid, 1_000_000_000); + } else { + SubtensorModule::epoch_dense(netuid, 1_000_000_000); + } + /* current_block: 3; activity_cutoff: 5000; Last update: [3, 1]; Inactive: [false, false]; + S: [1, 0]; S (mask): [1, 0]; S (mask+norm): [1, 0]; Block at registration: [0, 2]; + W: [[(1, 1)], []]; W (diagmask): [[(1, 1)], []]; W (diag+outdatemask): [[(1, 1)], []]; W (mask+norm): [[(1, 1)], []]; + R: [0, 1]; W (threshold): [[(1, 1)], []]; T: [0, 1]; C: [0.006693358, 0.9933076561]; I: [0, 1]; + B: [[], []]; B (outdatedmask): [[], []]; B (mask+norm): [[], []]; + ΔB: [[(1, 1)], []]; ΔB (norm): [[(1, 1)], []]; emaB: [[(1, 1)], []]; D: [1, 0]; emaB (max-upscale): [[(1, 1)], []] + E: [500000000, 500000000]; P: [0.5, 0.5] */ + for validator in 0..n as u16 { + assert_eq!( + SubtensorModule::get_emission_for_uid(netuid, validator), + 1000000000 / (n as u64) + ); // Note E = 1/2 * 1_000_000_000 + } + }); } // Test that epoch assigns validator permits to highest stake uids, varies uid interleaving and stake values. #[test] #[cfg(not(tarpaulin))] fn test_validator_permits() { - let netuid: u16 = 0; - let tempo: u16 = u16::MAX - 1; // high tempo to skip automatic epochs in on_initialize, use manual epochs instead - for interleave in 0..3 { - for (network_n, validators_n) in vec![(2, 1), (4, 2), (8, 4)] { - for assignment in 0..=1 { - let (validators, servers) = distribute_nodes(validators_n as usize, network_n as usize, interleave as usize); - let correct: bool = true; - let mut stake: Vec = vec![0; network_n]; - for validator in &validators { - stake[*validator as usize] = match assignment { - 1 => *validator as u64 + network_n as u64, - _ => 1 - }; - } - for server in &servers { - stake[*server as usize] = match assignment { - 1 => *server as u64, - _ => 0 - }; - } - new_test_ext().execute_with(|| { - let block_number: u64 = 0; - add_network(netuid, tempo, 0); - SubtensorModule::set_max_allowed_uids( netuid, network_n as u16 ); - assert_eq!(SubtensorModule::get_max_allowed_uids(netuid), network_n as u16 ); - SubtensorModule::set_max_registrations_per_block( netuid, network_n as u16 ); - SubtensorModule::set_target_registrations_per_interval(netuid, network_n as u16); - - // === Register [validator1, validator2, server1, server2] - for key in 0..network_n as u64 { - SubtensorModule::add_balance_to_coldkey_account( &U256::from(key), stake[key as usize] ); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, key * 1_000_000, &U256::from(key)); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(key)), netuid, block_number, nonce, work, U256::from(key), U256::from(key))); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( &U256::from(key), &U256::from(key), stake[key as usize] ); - } - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), network_n as u16); - - // === Issue validator permits - assert_ok!( SubtensorModule::sudo_set_max_allowed_validators(<::RuntimeOrigin>::root(), netuid, validators_n as u16) ); - assert_eq!( SubtensorModule::get_max_allowed_validators(netuid), validators_n as u16); - SubtensorModule::epoch( netuid, 1_000_000_000 ); // run first epoch to set allowed validators - for validator in &validators { - assert_eq!(correct, SubtensorModule::get_validator_permit_for_uid(netuid, *validator)); - } - for server in &servers { - assert_eq!(!correct, SubtensorModule::get_validator_permit_for_uid(netuid, *server)); - } - - // === Increase server stake above validators - for server in &servers { - SubtensorModule::add_balance_to_coldkey_account( &(U256::from(*server as u64)), 2 * network_n as u64 ); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( &(U256::from(*server as u64)), &(U256::from(*server as u64)), 2*network_n as u64 ); - } - - // === Update validator permits - run_to_block( 1 ); - SubtensorModule::epoch( netuid, 1_000_000_000 ); - - // === Check that servers now own permits instead of the validator uids - for validator in &validators { - assert_eq!(!correct, SubtensorModule::get_validator_permit_for_uid(netuid, *validator)); - } - for server in &servers { - assert_eq!(correct, SubtensorModule::get_validator_permit_for_uid(netuid, *server)); - } - }); - } - } - } + let netuid: u16 = 0; + let tempo: u16 = u16::MAX - 1; // high tempo to skip automatic epochs in on_initialize, use manual epochs instead + for interleave in 0..3 { + for (network_n, validators_n) in vec![(2, 1), (4, 2), (8, 4)] { + for assignment in 0..=1 { + let (validators, servers) = distribute_nodes( + validators_n as usize, + network_n as usize, + interleave as usize, + ); + let correct: bool = true; + let mut stake: Vec = vec![0; network_n]; + for validator in &validators { + stake[*validator as usize] = match assignment { + 1 => *validator as u64 + network_n as u64, + _ => 1, + }; + } + for server in &servers { + stake[*server as usize] = match assignment { + 1 => *server as u64, + _ => 0, + }; + } + new_test_ext().execute_with(|| { + let block_number: u64 = 0; + add_network(netuid, tempo, 0); + SubtensorModule::set_max_allowed_uids(netuid, network_n as u16); + assert_eq!( + SubtensorModule::get_max_allowed_uids(netuid), + network_n as u16 + ); + SubtensorModule::set_max_registrations_per_block(netuid, network_n as u16); + SubtensorModule::set_target_registrations_per_interval( + netuid, + network_n as u16, + ); + + // === Register [validator1, validator2, server1, server2] + for key in 0..network_n as u64 { + SubtensorModule::add_balance_to_coldkey_account( + &U256::from(key), + stake[key as usize], + ); + let (nonce, work): (u64, Vec) = + SubtensorModule::create_work_for_block_number( + netuid, + block_number, + key * 1_000_000, + &U256::from(key), + ); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(key)), + netuid, + block_number, + nonce, + work, + U256::from(key), + U256::from(key) + )); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &U256::from(key), + &U256::from(key), + stake[key as usize], + ); + } + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), network_n as u16); + + // === Issue validator permits + assert_ok!(SubtensorModule::sudo_set_max_allowed_validators( + <::RuntimeOrigin>::root(), + netuid, + validators_n as u16 + )); + assert_eq!( + SubtensorModule::get_max_allowed_validators(netuid), + validators_n as u16 + ); + SubtensorModule::epoch(netuid, 1_000_000_000); // run first epoch to set allowed validators + for validator in &validators { + assert_eq!( + correct, + SubtensorModule::get_validator_permit_for_uid(netuid, *validator) + ); + } + for server in &servers { + assert_eq!( + !correct, + SubtensorModule::get_validator_permit_for_uid(netuid, *server) + ); + } + + // === Increase server stake above validators + for server in &servers { + SubtensorModule::add_balance_to_coldkey_account( + &(U256::from(*server as u64)), + 2 * network_n as u64, + ); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &(U256::from(*server as u64)), + &(U256::from(*server as u64)), + 2 * network_n as u64, + ); + } + + // === Update validator permits + run_to_block(1); + SubtensorModule::epoch(netuid, 1_000_000_000); + + // === Check that servers now own permits instead of the validator uids + for validator in &validators { + assert_eq!( + !correct, + SubtensorModule::get_validator_permit_for_uid(netuid, *validator) + ); + } + for server in &servers { + assert_eq!( + correct, + SubtensorModule::get_validator_permit_for_uid(netuid, *server) + ); + } + }); + } + } + } } // Map the retention graph for consensus guarantees with an single epoch on a graph with 512 nodes, of which the first 64 are validators, the graph is split into a major and minor set, each setting specific weight on itself and the complement on the other. -// +// // ```import torch // import matplotlib.pyplot as plt // from matplotlib.pyplot import cm @@ -1368,22 +2008,41 @@ fn test_validator_permits() { // ``` // #[test] fn _map_consensus_guarantees() { - let netuid: u16 = 0; - let network_n: u16 = 512; - let validators_n: u16 = 64; - let epochs: u16 = 1; - let interleave = 0; - let weight_stddev: I32F32 = fixed(0.4); - println!("["); - for _major_stake in vec![0.51, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 0.99] { - let major_stake: I32F32 = I32F32::from_num(_major_stake); - for _major_weight in 0..51 { - let major_weight: I32F32 = I32F32::from_num(50 - _major_weight) / I32F32::from_num(50); - for _minor_weight in 0..51 { - let minor_weight: I32F32 = I32F32::from_num(50 - _minor_weight) / I32F32::from_num(50); - let (validators, servers, major_validators, minor_validators, major_servers, minor_servers, stake, weights, avg_weight_dev) = split_graph(major_stake, major_weight, minor_weight, weight_stddev, validators_n as usize, network_n as usize, interleave as usize); - - new_test_ext().execute_with(|| { + let netuid: u16 = 0; + let network_n: u16 = 512; + let validators_n: u16 = 64; + let epochs: u16 = 1; + let interleave = 0; + let weight_stddev: I32F32 = fixed(0.4); + println!("["); + for _major_stake in vec![0.51, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 0.99] { + let major_stake: I32F32 = I32F32::from_num(_major_stake); + for _major_weight in 0..51 { + let major_weight: I32F32 = I32F32::from_num(50 - _major_weight) / I32F32::from_num(50); + for _minor_weight in 0..51 { + let minor_weight: I32F32 = + I32F32::from_num(50 - _minor_weight) / I32F32::from_num(50); + let ( + validators, + servers, + major_validators, + minor_validators, + major_servers, + minor_servers, + stake, + weights, + avg_weight_dev, + ) = split_graph( + major_stake, + major_weight, + minor_weight, + weight_stddev, + validators_n as usize, + network_n as usize, + interleave as usize, + ); + + new_test_ext().execute_with(|| { init_run_epochs(netuid, network_n, &validators, &servers, epochs, 1, true, &stake, true, &weights, true, false, 0, true); let mut major_emission: I64F64 = I64F64::from_num(0); @@ -1401,8 +2060,8 @@ fn _map_consensus_guarantees() { let major_ratio: I32F32 = I32F32::from_num(major_emission / (major_emission + minor_emission)); println!("[{major_stake}, {major_weight:.2}, {minor_weight:.2}, {avg_weight_dev:.3}, {major_ratio:.3}], "); }); - } - } - } - println!("]"); -} \ No newline at end of file + } + } + } + println!("]"); +} diff --git a/pallets/subtensor/tests/mock.rs b/pallets/subtensor/tests/mock.rs index 6375e2740e..fdf84e220b 100644 --- a/pallets/subtensor/tests/mock.rs +++ b/pallets/subtensor/tests/mock.rs @@ -1,13 +1,17 @@ -use frame_support::{assert_ok, parameter_types, traits::{Everything, Hooks}, weights}; -use frame_system::{limits, EnsureNever, EnsureRoot, RawOrigin}; -use frame_support::traits::{StorageMapShim, Hash}; +use frame_support::traits::{Hash, StorageMapShim}; +use frame_support::{ + assert_ok, parameter_types, + traits::{Everything, Hooks}, + weights, +}; use frame_system as system; use frame_system::Config; -use sp_core::{H256, U256, Get}; +use frame_system::{limits, EnsureNever, EnsureRoot, RawOrigin}; +use sp_core::{Get, H256, U256}; use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - DispatchResult + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + DispatchResult, }; use pallet_collective::MemberCount; @@ -17,20 +21,20 @@ type Block = frame_system::mocking::MockBlock; // Configure a mock runtime to test the pallet. frame_support::construct_runtime!( - pub enum Test where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Config, Storage, Event}, - Triumvirate: pallet_collective::::{Pallet, Call, Storage, Origin, Event, Config}, - TriumvirateMembers: pallet_membership::::{Pallet, Call, Storage, Event, Config}, - Senate: pallet_collective::::{Pallet, Call, Storage, Origin, Event, Config}, - SenateMembers: pallet_membership::::{Pallet, Call, Storage, Event, Config}, - SubtensorModule: pallet_subtensor::{Pallet, Call, Storage, Event}, - Utility: pallet_utility::{Pallet, Call, Storage, Event}, - } + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Config, Storage, Event}, + Triumvirate: pallet_collective::::{Pallet, Call, Storage, Origin, Event, Config}, + TriumvirateMembers: pallet_membership::::{Pallet, Call, Storage, Event, Config}, + Senate: pallet_collective::::{Pallet, Call, Storage, Origin, Event, Config}, + SenateMembers: pallet_membership::::{Pallet, Call, Storage, Event, Config}, + SubtensorModule: pallet_subtensor::{Pallet, Call, Storage, Event}, + Utility: pallet_utility::{Pallet, Call, Storage, Event}, + } ); #[allow(dead_code)] @@ -43,12 +47,12 @@ pub type BalanceCall = pallet_balances::Call; pub type TestRuntimeCall = frame_system::Call; parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const SS58Prefix: u8 = 42; + pub const BlockHashCount: u64 = 250; + pub const SS58Prefix: u8 = 42; } #[allow(dead_code)] -pub type AccountId = U256; +pub type AccountId = U256; // The address format for describing accounts. #[allow(dead_code)] @@ -63,278 +67,287 @@ pub type Balance = u64; pub type BlockNumber = u64; impl pallet_balances::Config for Test { - type Balance = Balance; - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = (); - type AccountStore = StorageMapShim< - pallet_balances::Account, - frame_system::Provider, - AccountId, - pallet_balances::AccountData, - >; - type MaxLocks = (); - type WeightInfo = (); - type MaxReserves = (); - type ReserveIdentifier = (); + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = (); + type AccountStore = StorageMapShim< + pallet_balances::Account, + frame_system::Provider, + AccountId, + pallet_balances::AccountData, + >; + type MaxLocks = (); + type WeightInfo = (); + type MaxReserves = (); + type ReserveIdentifier = (); } impl system::Config for Test { - type BaseCallFilter = Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Index = u64; - type BlockNumber = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = U256; - type Lookup = IdentityLookup; - type Header = Header; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = SS58Prefix; - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = U256; + type Lookup = IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = SS58Prefix; + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } parameter_types! { - pub const InitialMinAllowedWeights: u16 = 0; - pub const InitialEmissionValue: u16 = 0; - pub const InitialMaxWeightsLimit: u16 = u16::MAX; - pub BlockWeights: limits::BlockWeights = limits::BlockWeights::simple_max(weights::Weight::from_ref_time(1024)); - pub const ExistentialDeposit: Balance = 1; - pub const TransactionByteFee: Balance = 100; - pub const SDebug:u64 = 1; - pub const InitialRho: u16 = 30; - pub const InitialKappa: u16 = 32_767; - pub const InitialTempo: u16 = 0; - pub const SelfOwnership: u64 = 2; - pub const InitialImmunityPeriod: u16 = 2; - pub const InitialMaxAllowedUids: u16 = 2; - pub const InitialBondsMovingAverage: u64 = 900_000; - pub const InitialStakePruningMin: u16 = 0; - pub const InitialFoundationDistribution: u64 = 0; - pub const InitialDefaultTake: u16 = 11_796; // 18% honest number. - pub const InitialWeightsVersionKey: u16 = 0; - pub const InitialServingRateLimit: u64 = 0; // No limit. - pub const InitialTxRateLimit: u64 = 2; // 2 blocks per stake/unstake/delegate - - pub const InitialBurn: u64 = 0; - pub const InitialMinBurn: u64 = 0; - pub const InitialMaxBurn: u64 = 1_000_000_000; - - pub const InitialValidatorPruneLen: u64 = 0; - pub const InitialScalingLawPower: u16 = 50; - pub const InitialMaxAllowedValidators: u16 = 100; - - pub const InitialIssuance: u64 = 548833985028256; - pub const InitialDifficulty: u64 = 10000; - pub const InitialActivityCutoff: u16 = 5000; - pub const InitialAdjustmentInterval: u16 = 100; - pub const InitialAdjustmentAlpha: u64 = 0; // no weight to previous value. - pub const InitialMaxRegistrationsPerBlock: u16 = 3; - pub const InitialTargetRegistrationsPerInterval: u16 = 2; - pub const InitialPruningScore : u16 = u16::MAX; - pub const InitialRegistrationRequirement: u16 = u16::MAX; // Top 100% - pub const InitialMinDifficulty: u64 = 1; - pub const InitialMaxDifficulty: u64 = u64::MAX; - pub const InitialRAORecycledForRegistration: u64 = 0; - - pub const InitialSenateRequiredStakePercentage: u64 = 2; // 2 percent of total stake + pub const InitialMinAllowedWeights: u16 = 0; + pub const InitialEmissionValue: u16 = 0; + pub const InitialMaxWeightsLimit: u16 = u16::MAX; + pub BlockWeights: limits::BlockWeights = limits::BlockWeights::simple_max(weights::Weight::from_ref_time(1024)); + pub const ExistentialDeposit: Balance = 1; + pub const TransactionByteFee: Balance = 100; + pub const SDebug:u64 = 1; + pub const InitialRho: u16 = 30; + pub const InitialKappa: u16 = 32_767; + pub const InitialTempo: u16 = 0; + pub const SelfOwnership: u64 = 2; + pub const InitialImmunityPeriod: u16 = 2; + pub const InitialMaxAllowedUids: u16 = 2; + pub const InitialBondsMovingAverage: u64 = 900_000; + pub const InitialStakePruningMin: u16 = 0; + pub const InitialFoundationDistribution: u64 = 0; + pub const InitialDefaultTake: u16 = 11_796; // 18% honest number. + pub const InitialWeightsVersionKey: u16 = 0; + pub const InitialServingRateLimit: u64 = 0; // No limit. + pub const InitialTxRateLimit: u64 = 2; // 2 blocks per stake/unstake/delegate + + pub const InitialBurn: u64 = 0; + pub const InitialMinBurn: u64 = 0; + pub const InitialMaxBurn: u64 = 1_000_000_000; + + pub const InitialValidatorPruneLen: u64 = 0; + pub const InitialScalingLawPower: u16 = 50; + pub const InitialMaxAllowedValidators: u16 = 100; + + pub const InitialIssuance: u64 = 548833985028256; + pub const InitialDifficulty: u64 = 10000; + pub const InitialActivityCutoff: u16 = 5000; + pub const InitialAdjustmentInterval: u16 = 100; + pub const InitialAdjustmentAlpha: u64 = 0; // no weight to previous value. + pub const InitialMaxRegistrationsPerBlock: u16 = 3; + pub const InitialTargetRegistrationsPerInterval: u16 = 2; + pub const InitialPruningScore : u16 = u16::MAX; + pub const InitialRegistrationRequirement: u16 = u16::MAX; // Top 100% + pub const InitialMinDifficulty: u64 = 1; + pub const InitialMaxDifficulty: u64 = u64::MAX; + pub const InitialRAORecycledForRegistration: u64 = 0; + + pub const InitialSenateRequiredStakePercentage: u64 = 2; // 2 percent of total stake } // Configure collective pallet for council parameter_types! { - pub const CouncilMotionDuration: BlockNumber = 100; - pub const CouncilMaxProposals: u32 = 10; - pub const CouncilMaxMembers: u32 = 3; + pub const CouncilMotionDuration: BlockNumber = 100; + pub const CouncilMaxProposals: u32 = 10; + pub const CouncilMaxMembers: u32 = 3; } // Configure collective pallet for Senate parameter_types! { - pub const SenateMaxMembers: u32 = 10; + pub const SenateMaxMembers: u32 = 10; } use pallet_collective::{CanPropose, CanVote, GetVotingMembers}; pub struct CanProposeToTriumvirate; impl CanPropose for CanProposeToTriumvirate { - fn can_propose(account: &AccountId) -> bool { - Triumvirate::is_member(account) - } + fn can_propose(account: &AccountId) -> bool { + Triumvirate::is_member(account) + } } pub struct CanVoteToTriumvirate; impl CanVote for CanVoteToTriumvirate { - fn can_vote(_: &AccountId) -> bool { - //Senate::is_member(account) - false // Disable voting from pallet_collective::vote - } + fn can_vote(_: &AccountId) -> bool { + //Senate::is_member(account) + false // Disable voting from pallet_collective::vote + } } -use pallet_subtensor::{MemberManagement, CollectiveInterface}; +use pallet_subtensor::{CollectiveInterface, MemberManagement}; pub struct ManageSenateMembers; impl MemberManagement for ManageSenateMembers { - fn add_member(account: &AccountId) -> DispatchResult { - SenateMembers::add_member(RawOrigin::Root.into(), *account) - } + fn add_member(account: &AccountId) -> DispatchResult { + SenateMembers::add_member(RawOrigin::Root.into(), *account) + } - fn remove_member(account: &AccountId) -> DispatchResult { - SenateMembers::remove_member(RawOrigin::Root.into(), *account) - } + fn remove_member(account: &AccountId) -> DispatchResult { + SenateMembers::remove_member(RawOrigin::Root.into(), *account) + } - fn swap_member(remove: &AccountId, add: &AccountId) -> DispatchResult { - SenateMembers::swap_member(RawOrigin::Root.into(), *remove, *add) - } + fn swap_member(remove: &AccountId, add: &AccountId) -> DispatchResult { + SenateMembers::swap_member(RawOrigin::Root.into(), *remove, *add) + } - fn is_member(account: &AccountId) -> bool { - Senate::is_member(account) - } + fn is_member(account: &AccountId) -> bool { + Senate::is_member(account) + } - fn members() -> Vec { - Senate::members() - } + fn members() -> Vec { + Senate::members() + } - fn max_members() -> u32 { - SenateMaxMembers::get() - } + fn max_members() -> u32 { + SenateMaxMembers::get() + } } pub struct GetSenateMemberCount; impl GetVotingMembers for GetSenateMemberCount { - fn get_count() -> MemberCount {Senate::members().len() as u32} + fn get_count() -> MemberCount { + Senate::members().len() as u32 + } } impl Get for GetSenateMemberCount { - fn get() -> MemberCount {SenateMaxMembers::get()} + fn get() -> MemberCount { + SenateMaxMembers::get() + } } pub struct TriumvirateVotes; impl CollectiveInterface for TriumvirateVotes { - fn remove_votes(hotkey: &AccountId) -> Result { - Triumvirate::remove_votes(hotkey) - } + fn remove_votes(hotkey: &AccountId) -> Result { + Triumvirate::remove_votes(hotkey) + } - fn add_vote(hotkey: &AccountId, proposal: Hash, index: u32, approve: bool) -> Result { - Triumvirate::do_vote(hotkey.clone(), proposal, index, approve) - } + fn add_vote( + hotkey: &AccountId, + proposal: Hash, + index: u32, + approve: bool, + ) -> Result { + Triumvirate::do_vote(hotkey.clone(), proposal, index, approve) + } } // We call pallet_collective TriumvirateCollective type TriumvirateCollective = pallet_collective::Instance1; impl pallet_collective::Config for Test { - type RuntimeOrigin = RuntimeOrigin; - type Proposal = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type MotionDuration = CouncilMotionDuration; - type MaxProposals = CouncilMaxProposals; - type MaxMembers = GetSenateMemberCount; - type DefaultVote = pallet_collective::PrimeDefaultVote; - type WeightInfo = pallet_collective::weights::SubstrateWeight; - type SetMembersOrigin = EnsureNever; - type CanPropose = CanProposeToTriumvirate; - type CanVote = CanVoteToTriumvirate; - type GetVotingMembers = GetSenateMemberCount; + type RuntimeOrigin = RuntimeOrigin; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type MotionDuration = CouncilMotionDuration; + type MaxProposals = CouncilMaxProposals; + type MaxMembers = GetSenateMemberCount; + type DefaultVote = pallet_collective::PrimeDefaultVote; + type WeightInfo = pallet_collective::weights::SubstrateWeight; + type SetMembersOrigin = EnsureNever; + type CanPropose = CanProposeToTriumvirate; + type CanVote = CanVoteToTriumvirate; + type GetVotingMembers = GetSenateMemberCount; } // We call council members Triumvirate type TriumvirateMembership = pallet_membership::Instance1; impl pallet_membership::Config for Test { - type RuntimeEvent = RuntimeEvent; - type AddOrigin = EnsureRoot; - type RemoveOrigin = EnsureRoot; - type SwapOrigin = EnsureRoot; - type ResetOrigin = EnsureRoot; - type PrimeOrigin = EnsureRoot; - type MembershipInitialized = Triumvirate; - type MembershipChanged = Triumvirate; - type MaxMembers = CouncilMaxMembers; - type WeightInfo = pallet_membership::weights::SubstrateWeight; + type RuntimeEvent = RuntimeEvent; + type AddOrigin = EnsureRoot; + type RemoveOrigin = EnsureRoot; + type SwapOrigin = EnsureRoot; + type ResetOrigin = EnsureRoot; + type PrimeOrigin = EnsureRoot; + type MembershipInitialized = Triumvirate; + type MembershipChanged = Triumvirate; + type MaxMembers = CouncilMaxMembers; + type WeightInfo = pallet_membership::weights::SubstrateWeight; } // This is a dummy collective instance for managing senate members // Probably not the best solution, but fastest implementation type SenateCollective = pallet_collective::Instance2; impl pallet_collective::Config for Test { - type RuntimeOrigin = RuntimeOrigin; - type Proposal = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type MotionDuration = CouncilMotionDuration; - type MaxProposals = CouncilMaxProposals; - type MaxMembers = SenateMaxMembers; - type DefaultVote = pallet_collective::PrimeDefaultVote; - type WeightInfo = pallet_collective::weights::SubstrateWeight; - type SetMembersOrigin = EnsureNever; - type CanPropose = (); - type CanVote = (); - type GetVotingMembers = (); + type RuntimeOrigin = RuntimeOrigin; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type MotionDuration = CouncilMotionDuration; + type MaxProposals = CouncilMaxProposals; + type MaxMembers = SenateMaxMembers; + type DefaultVote = pallet_collective::PrimeDefaultVote; + type WeightInfo = pallet_collective::weights::SubstrateWeight; + type SetMembersOrigin = EnsureNever; + type CanPropose = (); + type CanVote = (); + type GetVotingMembers = (); } // We call our top K delegates membership Senate type SenateMembership = pallet_membership::Instance2; impl pallet_membership::Config for Test { - type RuntimeEvent = RuntimeEvent; - type AddOrigin = EnsureRoot; - type RemoveOrigin = EnsureRoot; - type SwapOrigin = EnsureRoot; - type ResetOrigin = EnsureRoot; - type PrimeOrigin = EnsureRoot; - type MembershipInitialized = Senate; - type MembershipChanged = Senate; - type MaxMembers = SenateMaxMembers; - type WeightInfo = pallet_membership::weights::SubstrateWeight; + type RuntimeEvent = RuntimeEvent; + type AddOrigin = EnsureRoot; + type RemoveOrigin = EnsureRoot; + type SwapOrigin = EnsureRoot; + type ResetOrigin = EnsureRoot; + type PrimeOrigin = EnsureRoot; + type MembershipInitialized = Senate; + type MembershipChanged = Senate; + type MaxMembers = SenateMaxMembers; + type WeightInfo = pallet_membership::weights::SubstrateWeight; } impl pallet_subtensor::Config for Test { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type InitialIssuance = InitialIssuance; - type SudoRuntimeCall = TestRuntimeCall; - type CouncilOrigin = frame_system::EnsureSigned; - type SenateMembers = ManageSenateMembers; - type TriumvirateInterface = TriumvirateVotes; - - type InitialMinAllowedWeights = InitialMinAllowedWeights; - type InitialEmissionValue = InitialEmissionValue; - type InitialMaxWeightsLimit = InitialMaxWeightsLimit; - type InitialTempo = InitialTempo; - type InitialDifficulty = InitialDifficulty; - type InitialAdjustmentInterval = InitialAdjustmentInterval; - type InitialAdjustmentAlpha = InitialAdjustmentAlpha; - type InitialTargetRegistrationsPerInterval = InitialTargetRegistrationsPerInterval; - type InitialRho = InitialRho; - type InitialKappa = InitialKappa; - type InitialMaxAllowedUids = InitialMaxAllowedUids; - type InitialValidatorPruneLen = InitialValidatorPruneLen; - type InitialScalingLawPower = InitialScalingLawPower; - type InitialImmunityPeriod = InitialImmunityPeriod; - type InitialActivityCutoff = InitialActivityCutoff; - type InitialMaxRegistrationsPerBlock = InitialMaxRegistrationsPerBlock; - type InitialPruningScore = InitialPruningScore; - type InitialBondsMovingAverage = InitialBondsMovingAverage; - type InitialMaxAllowedValidators = InitialMaxAllowedValidators; - type InitialDefaultTake = InitialDefaultTake; - type InitialWeightsVersionKey = InitialWeightsVersionKey; - type InitialMaxDifficulty = InitialMaxDifficulty; - type InitialMinDifficulty = InitialMinDifficulty; - type InitialServingRateLimit = InitialServingRateLimit; - type InitialTxRateLimit = InitialTxRateLimit; - type InitialBurn = InitialBurn; - type InitialMaxBurn = InitialMaxBurn; - type InitialMinBurn = InitialMinBurn; - type InitialRAORecycledForRegistration = InitialRAORecycledForRegistration; - type InitialSenateRequiredStakePercentage = InitialSenateRequiredStakePercentage; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type InitialIssuance = InitialIssuance; + type SudoRuntimeCall = TestRuntimeCall; + type CouncilOrigin = frame_system::EnsureSigned; + type SenateMembers = ManageSenateMembers; + type TriumvirateInterface = TriumvirateVotes; + + type InitialMinAllowedWeights = InitialMinAllowedWeights; + type InitialEmissionValue = InitialEmissionValue; + type InitialMaxWeightsLimit = InitialMaxWeightsLimit; + type InitialTempo = InitialTempo; + type InitialDifficulty = InitialDifficulty; + type InitialAdjustmentInterval = InitialAdjustmentInterval; + type InitialAdjustmentAlpha = InitialAdjustmentAlpha; + type InitialTargetRegistrationsPerInterval = InitialTargetRegistrationsPerInterval; + type InitialRho = InitialRho; + type InitialKappa = InitialKappa; + type InitialMaxAllowedUids = InitialMaxAllowedUids; + type InitialValidatorPruneLen = InitialValidatorPruneLen; + type InitialScalingLawPower = InitialScalingLawPower; + type InitialImmunityPeriod = InitialImmunityPeriod; + type InitialActivityCutoff = InitialActivityCutoff; + type InitialMaxRegistrationsPerBlock = InitialMaxRegistrationsPerBlock; + type InitialPruningScore = InitialPruningScore; + type InitialBondsMovingAverage = InitialBondsMovingAverage; + type InitialMaxAllowedValidators = InitialMaxAllowedValidators; + type InitialDefaultTake = InitialDefaultTake; + type InitialWeightsVersionKey = InitialWeightsVersionKey; + type InitialMaxDifficulty = InitialMaxDifficulty; + type InitialMinDifficulty = InitialMinDifficulty; + type InitialServingRateLimit = InitialServingRateLimit; + type InitialTxRateLimit = InitialTxRateLimit; + type InitialBurn = InitialBurn; + type InitialMaxBurn = InitialMaxBurn; + type InitialMinBurn = InitialMinBurn; + type InitialRAORecycledForRegistration = InitialRAORecycledForRegistration; + type InitialSenateRequiredStakePercentage = InitialSenateRequiredStakePercentage; } impl pallet_utility::Config for Test { - type RuntimeEvent = RuntimeEvent; + type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; type WeightInfo = pallet_utility::weights::SubstrateWeight; @@ -348,59 +361,94 @@ impl pallet_utility::Config for Test { // Build genesis storage according to the mock runtime. #[allow(dead_code)] pub fn new_test_ext() -> sp_io::TestExternalities { - sp_tracing::try_init_simple(); - frame_system::GenesisConfig::default().build_storage::().unwrap().into() + sp_tracing::try_init_simple(); + frame_system::GenesisConfig::default() + .build_storage::() + .unwrap() + .into() } #[allow(dead_code)] -pub fn test_ext_with_balances(balances : Vec<(U256, u128)>) -> sp_io::TestExternalities { - sp_tracing::try_init_simple(); - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); - - pallet_balances::GenesisConfig:: { balances: balances.iter().map(|(a, b)| (*a, *b as u64)).collect::>() } - .assimilate_storage(&mut t) - .unwrap(); +pub fn test_ext_with_balances(balances: Vec<(U256, u128)>) -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); + let mut t = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: balances + .iter() + .map(|(a, b)| (*a, *b as u64)) + .collect::>(), + } + .assimilate_storage(&mut t) + .unwrap(); - t.into() + t.into() } #[allow(dead_code)] pub(crate) fn step_block(n: u16) { - for _ in 0..n { - SubtensorModule::on_finalize(System::block_number()); - System::on_finalize(System::block_number()); - System::set_block_number(System::block_number() + 1); - System::on_initialize(System::block_number()); - SubtensorModule::on_initialize(System::block_number()); - } + for _ in 0..n { + SubtensorModule::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + SubtensorModule::on_initialize(System::block_number()); + } } #[allow(dead_code)] pub(crate) fn run_to_block(n: u64) { while System::block_number() < n { - SubtensorModule::on_finalize(System::block_number()); + SubtensorModule::on_finalize(System::block_number()); System::on_finalize(System::block_number()); System::set_block_number(System::block_number() + 1); System::on_initialize(System::block_number()); - SubtensorModule::on_initialize(System::block_number()); + SubtensorModule::on_initialize(System::block_number()); } } #[allow(dead_code)] -pub fn register_ok_neuron( netuid: u16, hotkey_account_id: U256, coldkey_account_id: U256, start_nonce: u64) { - let block_number: u64 = SubtensorModule::get_current_block_as_u64(); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, start_nonce, &hotkey_account_id); - let result = SubtensorModule::register( <::RuntimeOrigin>::signed(hotkey_account_id), netuid, block_number, nonce, work, hotkey_account_id, coldkey_account_id ); - assert_ok!(result); - log::info!("Register ok neuron: netuid: {:?}, coldkey: {:?}, hotkey: {:?}", netuid, hotkey_account_id, coldkey_account_id ); +pub fn register_ok_neuron( + netuid: u16, + hotkey_account_id: U256, + coldkey_account_id: U256, + start_nonce: u64, +) { + let block_number: u64 = SubtensorModule::get_current_block_as_u64(); + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + start_nonce, + &hotkey_account_id, + ); + let result = SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + block_number, + nonce, + work, + hotkey_account_id, + coldkey_account_id, + ); + assert_ok!(result); + log::info!( + "Register ok neuron: netuid: {:?}, coldkey: {:?}, hotkey: {:?}", + netuid, + hotkey_account_id, + coldkey_account_id + ); } #[allow(dead_code)] -pub fn add_network(netuid: u16, tempo: u16, modality: u16){ - let result = SubtensorModule::do_add_network(<::RuntimeOrigin>::root(), netuid, tempo, modality); - SubtensorModule::set_network_registration_allowed( netuid, true ); - assert_ok!(result); +pub fn add_network(netuid: u16, tempo: u16, modality: u16) { + let result = SubtensorModule::do_add_network( + <::RuntimeOrigin>::root(), + netuid, + tempo, + modality, + ); + SubtensorModule::set_network_registration_allowed(netuid, true); + assert_ok!(result); } - diff --git a/pallets/subtensor/tests/networks.rs b/pallets/subtensor/tests/networks.rs index 32c8d3e8f2..440fac3e86 100644 --- a/pallets/subtensor/tests/networks.rs +++ b/pallets/subtensor/tests/networks.rs @@ -1,319 +1,411 @@ mod mock; -use mock::*; -use pallet_subtensor::Error; -use frame_system::Config; use frame_support::{ - dispatch::{ - GetDispatchInfo, - DispatchInfo, - DispatchClass, - Pays - }, - assert_ok, - sp_std::vec + assert_ok, + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}, + sp_std::vec, }; +use frame_system::Config; +use mock::*; +use pallet_subtensor::Error; use sp_core::U256; /*TO DO SAM: write test for LatuUpdate after it is set */ // --- add network tests ---- #[test] -fn test_add_network_dispatch_info_ok() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; - let modality = 0; - let tempo: u16 = 13; - let call = RuntimeCall::SubtensorModule(SubtensorCall::sudo_add_network{netuid, tempo, modality}); - assert_eq!(call.get_dispatch_info(), - DispatchInfo { - weight: frame_support::weights::Weight::from_ref_time(50000000), - class: DispatchClass::Operational, - pays_fee: Pays::No - }); -});} +fn test_add_network_dispatch_info_ok() { + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let modality = 0; + let tempo: u16 = 13; + let call = RuntimeCall::SubtensorModule(SubtensorCall::sudo_add_network { + netuid, + tempo, + modality, + }); + assert_eq!( + call.get_dispatch_info(), + DispatchInfo { + weight: frame_support::weights::Weight::from_ref_time(50000000), + class: DispatchClass::Operational, + pays_fee: Pays::No + } + ); + }); +} #[test] -fn test_add_network() { - new_test_ext().execute_with(|| { - let modality = 0; - let tempo: u16 = 13; - add_network(10, tempo, modality); - assert_eq!(SubtensorModule::get_number_of_subnets(), 1); - add_network( 20, tempo, modality); - assert_eq!(SubtensorModule::get_number_of_subnets(), 2); -});} +fn test_add_network() { + new_test_ext().execute_with(|| { + let modality = 0; + let tempo: u16 = 13; + add_network(10, tempo, modality); + assert_eq!(SubtensorModule::get_number_of_subnets(), 1); + add_network(20, tempo, modality); + assert_eq!(SubtensorModule::get_number_of_subnets(), 2); + }); +} #[test] -fn test_add_network_check_tempo() { - new_test_ext().execute_with(|| { - let modality = 0; - let tempo: u16 = 13; - assert_eq!(SubtensorModule::get_tempo(1), 0); - add_network(1, tempo, modality); - assert_eq!(SubtensorModule::get_tempo(1), 13); -});} +fn test_add_network_check_tempo() { + new_test_ext().execute_with(|| { + let modality = 0; + let tempo: u16 = 13; + assert_eq!(SubtensorModule::get_tempo(1), 0); + add_network(1, tempo, modality); + assert_eq!(SubtensorModule::get_tempo(1), 13); + }); +} #[test] -fn test_clear_min_allowed_weight_for_network() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; - let min_allowed_weight = 2; - let tempo: u16 = 13; - add_network(netuid, tempo, 0); - register_ok_neuron( 1, U256::from(55), U256::from(66), 0); - SubtensorModule::set_min_allowed_weights(netuid, min_allowed_weight); - assert_eq!(SubtensorModule::get_min_allowed_weights(netuid), 2); - assert_ok!(SubtensorModule::do_remove_network(<::RuntimeOrigin>::root(), netuid)); - assert_eq!(SubtensorModule::get_min_allowed_weights(netuid), 0); -});} +fn test_clear_min_allowed_weight_for_network() { + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let min_allowed_weight = 2; + let tempo: u16 = 13; + add_network(netuid, tempo, 0); + register_ok_neuron(1, U256::from(55), U256::from(66), 0); + SubtensorModule::set_min_allowed_weights(netuid, min_allowed_weight); + assert_eq!(SubtensorModule::get_min_allowed_weights(netuid), 2); + assert_ok!(SubtensorModule::do_remove_network( + <::RuntimeOrigin>::root(), + netuid + )); + assert_eq!(SubtensorModule::get_min_allowed_weights(netuid), 0); + }); +} #[test] fn test_remove_uid_for_network() { - new_test_ext().execute_with(|| { - - let netuid: u16 = 1; - let tempo: u16 = 13; - add_network(netuid, tempo, 0); - register_ok_neuron( 1, U256::from(55), U256::from(66), 0); - let neuron_id ; - match SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(55)) { - Ok(k) => neuron_id = k, - Err(e) => panic!("Error: {:?}", e), - } - assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(55)).is_ok()); - assert_eq!(neuron_id, 0); - register_ok_neuron( 1, U256::from(56), U256::from(67), 300000); - let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(56)).unwrap(); - assert_eq!(neuron_uid, 1); - assert_ok!(SubtensorModule::do_remove_network(<::RuntimeOrigin>::root(), netuid)); - assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(55)).is_err()); -});} + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + add_network(netuid, tempo, 0); + register_ok_neuron(1, U256::from(55), U256::from(66), 0); + let neuron_id; + match SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(55)) { + Ok(k) => neuron_id = k, + Err(e) => panic!("Error: {:?}", e), + } + assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(55)).is_ok()); + assert_eq!(neuron_id, 0); + register_ok_neuron(1, U256::from(56), U256::from(67), 300000); + let neuron_uid = + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(56)).unwrap(); + assert_eq!(neuron_uid, 1); + assert_ok!(SubtensorModule::do_remove_network( + <::RuntimeOrigin>::root(), + netuid + )); + assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(55)).is_err()); + }); +} #[test] fn test_remove_difficulty_for_network() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; - let difficulty: u64 = 10; - let tempo: u16 = 13; - add_network(netuid, tempo, 0); - register_ok_neuron( 1, U256::from(55), U256::from(66), 0); - assert_ok!(SubtensorModule::sudo_set_difficulty(<::RuntimeOrigin>::root(), netuid, difficulty)); - assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), difficulty); - assert_ok!(SubtensorModule::do_remove_network(<::RuntimeOrigin>::root(), netuid)); - assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 10000); -});} - + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let difficulty: u64 = 10; + let tempo: u16 = 13; + add_network(netuid, tempo, 0); + register_ok_neuron(1, U256::from(55), U256::from(66), 0); + assert_ok!(SubtensorModule::sudo_set_difficulty( + <::RuntimeOrigin>::root(), + netuid, + difficulty + )); + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), difficulty); + assert_ok!(SubtensorModule::do_remove_network( + <::RuntimeOrigin>::root(), + netuid + )); + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 10000); + }); +} #[test] fn test_remove_network_for_all_hotkeys() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; - let tempo: u16 = 13; - add_network(netuid, tempo, 0); - register_ok_neuron( 1, U256::from(55), U256::from(66), 0); - register_ok_neuron( 1, U256::from(77), U256::from(88), 65536); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 2); - assert_ok!(SubtensorModule::do_remove_network(<::RuntimeOrigin>::root(), netuid)); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 0); -});} + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + add_network(netuid, tempo, 0); + register_ok_neuron(1, U256::from(55), U256::from(66), 0); + register_ok_neuron(1, U256::from(77), U256::from(88), 65536); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 2); + assert_ok!(SubtensorModule::do_remove_network( + <::RuntimeOrigin>::root(), + netuid + )); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 0); + }); +} #[test] fn test_network_set_default_value_for_other_parameters() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; - let tempo: u16 = 13; - add_network(netuid, tempo, 0); - assert_eq!(SubtensorModule::get_min_allowed_weights(netuid), 0); - assert_eq!(SubtensorModule::get_emission_value(netuid), 0); - assert_eq!(SubtensorModule::get_max_weight_limit(netuid), u16::MAX); - assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 10000); - assert_eq!(SubtensorModule::get_immunity_period(netuid), 2); - -});} + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + add_network(netuid, tempo, 0); + assert_eq!(SubtensorModule::get_min_allowed_weights(netuid), 0); + assert_eq!(SubtensorModule::get_emission_value(netuid), 0); + assert_eq!(SubtensorModule::get_max_weight_limit(netuid), u16::MAX); + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 10000); + assert_eq!(SubtensorModule::get_immunity_period(netuid), 2); + }); +} // --- Set Emission Ratios Tests #[test] fn test_network_set_emission_ratios_dispatch_info_ok() { - new_test_ext().execute_with(|| { - let netuids: Vec = vec![ 1,2 ]; - let emission: Vec = vec![ 100000000, 900000000 ]; - let call = RuntimeCall::SubtensorModule(SubtensorCall::sudo_set_emission_values{ netuids, emission }); - assert_eq!(call.get_dispatch_info(), DispatchInfo { - weight: frame_support::weights::Weight::from_ref_time(28000000), - class: DispatchClass::Operational, - pays_fee: Pays::No - }); -});} + new_test_ext().execute_with(|| { + let netuids: Vec = vec![1, 2]; + let emission: Vec = vec![100000000, 900000000]; + let call = RuntimeCall::SubtensorModule(SubtensorCall::sudo_set_emission_values { + netuids, + emission, + }); + assert_eq!( + call.get_dispatch_info(), + DispatchInfo { + weight: frame_support::weights::Weight::from_ref_time(28000000), + class: DispatchClass::Operational, + pays_fee: Pays::No + } + ); + }); +} #[test] fn test_network_set_emission_ratios_ok() { - new_test_ext().execute_with(|| { - let netuids: Vec = vec![ 1,2 ]; - let emission: Vec = vec![ 100000000, 900000000 ]; - add_network(1, 0, 0); - add_network(2, 0, 0); - assert_ok!( SubtensorModule::sudo_set_emission_values(<::RuntimeOrigin>::root(), netuids, emission ) ); -});} + new_test_ext().execute_with(|| { + let netuids: Vec = vec![1, 2]; + let emission: Vec = vec![100000000, 900000000]; + add_network(1, 0, 0); + add_network(2, 0, 0); + assert_ok!(SubtensorModule::sudo_set_emission_values( + <::RuntimeOrigin>::root(), + netuids, + emission + )); + }); +} #[test] fn test_network_set_emission_ratios_fail_summation() { - new_test_ext().execute_with(|| { - let netuids: Vec = vec![ 1, 2 ]; - let emission: Vec = vec![ 100000000, 910000000 ]; - add_network(1, 0, 0); - add_network(2, 0, 0); - assert_eq!( SubtensorModule::sudo_set_emission_values(<::RuntimeOrigin>::root(), netuids, emission ), Err(Error::::InvalidEmissionValues.into()) ); -});} + new_test_ext().execute_with(|| { + let netuids: Vec = vec![1, 2]; + let emission: Vec = vec![100000000, 910000000]; + add_network(1, 0, 0); + add_network(2, 0, 0); + assert_eq!( + SubtensorModule::sudo_set_emission_values( + <::RuntimeOrigin>::root(), + netuids, + emission + ), + Err(Error::::InvalidEmissionValues.into()) + ); + }); +} #[test] fn test_network_set_emission_invalid_netuids() { - new_test_ext().execute_with(|| { - let netuids: Vec = vec![ 1, 2 ]; - let emission: Vec = vec![ 100000000, 900000000 ]; - add_network(1, 0, 0); - assert_eq!( SubtensorModule::sudo_set_emission_values(<::RuntimeOrigin>::root(), netuids, emission ), Err(Error::::IncorrectNetuidsLength.into()) ); -});} + new_test_ext().execute_with(|| { + let netuids: Vec = vec![1, 2]; + let emission: Vec = vec![100000000, 900000000]; + add_network(1, 0, 0); + assert_eq!( + SubtensorModule::sudo_set_emission_values( + <::RuntimeOrigin>::root(), + netuids, + emission + ), + Err(Error::::IncorrectNetuidsLength.into()) + ); + }); +} #[test] fn test_network_set_emission_ratios_fail_net() { - new_test_ext().execute_with(|| { - let netuids: Vec = vec![ 1, 2 ]; - let emission: Vec = vec![ 100000000, 900000000 ]; - add_network(1, 0, 0); - add_network(3, 0, 0); - assert_eq!( SubtensorModule::sudo_set_emission_values(<::RuntimeOrigin>::root(), netuids, emission ), Err(Error::::InvalidUid.into()) ); -});} + new_test_ext().execute_with(|| { + let netuids: Vec = vec![1, 2]; + let emission: Vec = vec![100000000, 900000000]; + add_network(1, 0, 0); + add_network(3, 0, 0); + assert_eq!( + SubtensorModule::sudo_set_emission_values( + <::RuntimeOrigin>::root(), + netuids, + emission + ), + Err(Error::::InvalidUid.into()) + ); + }); +} #[test] -fn test_add_difficulty_fail(){ - new_test_ext().execute_with(|| { - let netuid: u16 = 1; - assert_eq!(SubtensorModule::sudo_set_difficulty(<::RuntimeOrigin>::root(), netuid, 120000) , Err(Error::::NetworkDoesNotExist.into()) ); -});} - - +fn test_add_difficulty_fail() { + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + assert_eq!( + SubtensorModule::sudo_set_difficulty( + <::RuntimeOrigin>::root(), + netuid, + 120000 + ), + Err(Error::::NetworkDoesNotExist.into()) + ); + }); +} #[test] -fn test_multi_tempo_with_emission(){ - new_test_ext().execute_with(|| { - let netuid: u16 = 1; - assert_eq!(SubtensorModule::sudo_set_difficulty(<::RuntimeOrigin>::root(), netuid, 120000) , Err(Error::::NetworkDoesNotExist.into()) ); -});} - +fn test_multi_tempo_with_emission() { + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + assert_eq!( + SubtensorModule::sudo_set_difficulty( + <::RuntimeOrigin>::root(), + netuid, + 120000 + ), + Err(Error::::NetworkDoesNotExist.into()) + ); + }); +} #[test] // Required by the test otherwise it would panic if compiled in debug mode #[allow(arithmetic_overflow)] fn test_set_emission_values_errors_on_emission_sum_overflow() { - new_test_ext().execute_with(|| { - let netuids: Vec = vec![ 1,2 ]; - // u64(u64::MAX + 1..000..1) equals to 1_000_000_000 which is the same as - // the value of Self::get_block_emission() expected by the extrinsic - let emission: Vec = vec![ u64::MAX, 1_000_000_001 ]; - add_network(1, 0, 0); - add_network(2, 0, 0); - assert_eq!( - SubtensorModule::sudo_set_emission_values(<::RuntimeOrigin>::root(), netuids, emission ), - Err(Error::::InvalidEmissionValues.into()) - ); - }); + new_test_ext().execute_with(|| { + let netuids: Vec = vec![1, 2]; + // u64(u64::MAX + 1..000..1) equals to 1_000_000_000 which is the same as + // the value of Self::get_block_emission() expected by the extrinsic + let emission: Vec = vec![u64::MAX, 1_000_000_001]; + add_network(1, 0, 0); + add_network(2, 0, 0); + assert_eq!( + SubtensorModule::sudo_set_emission_values( + <::RuntimeOrigin>::root(), + netuids, + emission + ), + Err(Error::::InvalidEmissionValues.into()) + ); + }); } #[test] #[allow(arithmetic_overflow)] fn test_set_emission_values_no_errors() { - new_test_ext().execute_with(|| { - let netuids: Vec = vec![ 1,2 ]; - let emission: Vec = vec![ 600_000_000, 400_000_000 ]; - - add_network(1, 0, 0); - add_network(2, 0, 0); - assert_eq!( - SubtensorModule::sudo_set_emission_values(<::RuntimeOrigin>::root(), netuids, emission ), - Ok(()) - ); - }); + new_test_ext().execute_with(|| { + let netuids: Vec = vec![1, 2]; + let emission: Vec = vec![600_000_000, 400_000_000]; + + add_network(1, 0, 0); + add_network(2, 0, 0); + assert_eq!( + SubtensorModule::sudo_set_emission_values( + <::RuntimeOrigin>::root(), + netuids, + emission + ), + Ok(()) + ); + }); } #[test] // Required by the test otherwise it would panic if compiled in debug mode #[allow(arithmetic_overflow)] fn test_set_emission_values_sum_too_large() { - new_test_ext().execute_with(|| { - let netuids: Vec = vec![ 1,2 ]; - // u64(1_000_000_000 + 1) equals to 1_000_000_001 which is more than - // the value of Self::get_block_emission() expected by the extrinsic - let emission: Vec = vec![ 1_000_000_000, 1 ]; - add_network(1, 0, 0); - add_network(2, 0, 0); - assert_eq!( - SubtensorModule::sudo_set_emission_values(<::RuntimeOrigin>::root(), netuids, emission ), - Err(Error::::InvalidEmissionValues.into()) - ); - }); + new_test_ext().execute_with(|| { + let netuids: Vec = vec![1, 2]; + // u64(1_000_000_000 + 1) equals to 1_000_000_001 which is more than + // the value of Self::get_block_emission() expected by the extrinsic + let emission: Vec = vec![1_000_000_000, 1]; + add_network(1, 0, 0); + add_network(2, 0, 0); + assert_eq!( + SubtensorModule::sudo_set_emission_values( + <::RuntimeOrigin>::root(), + netuids, + emission + ), + Err(Error::::InvalidEmissionValues.into()) + ); + }); } #[test] // Required by the test otherwise it would panic if compiled in debug mode #[allow(arithmetic_overflow)] fn test_set_emission_values_sum_too_small() { - new_test_ext().execute_with(|| { - let netuids: Vec = vec![ 1,2 ]; - // u64(1 + 2_000) equals to 2_001 which is LESS than - // the value of Self::get_block_emission() expected by the extrinsic - let emission: Vec = vec![ 1, 2_000 ]; - add_network(1, 0, 0); - add_network(2, 0, 0); - assert_eq!( - SubtensorModule::sudo_set_emission_values(<::RuntimeOrigin>::root(), netuids, emission ), - Err(Error::::InvalidEmissionValues.into()) - ); - }); + new_test_ext().execute_with(|| { + let netuids: Vec = vec![1, 2]; + // u64(1 + 2_000) equals to 2_001 which is LESS than + // the value of Self::get_block_emission() expected by the extrinsic + let emission: Vec = vec![1, 2_000]; + add_network(1, 0, 0); + add_network(2, 0, 0); + assert_eq!( + SubtensorModule::sudo_set_emission_values( + <::RuntimeOrigin>::root(), + netuids, + emission + ), + Err(Error::::InvalidEmissionValues.into()) + ); + }); } - #[test] fn test_set_emission_values_too_many_netuids() { - new_test_ext().execute_with(|| { - let netuids: Vec = vec![ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; + new_test_ext().execute_with(|| { + let netuids: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - // Sums to 1_000_000_000 and has 10 elements - let emission: Vec = vec![ 1_000_000_000, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; - add_network(1, 0, 0); - add_network(2, 0, 0); - // We only add 2 networks, so this should fail - assert_eq!( - SubtensorModule::sudo_set_emission_values(<::RuntimeOrigin>::root(), netuids, emission ), - Err(Error::::IncorrectNetuidsLength.into()) - ); - }); + // Sums to 1_000_000_000 and has 10 elements + let emission: Vec = vec![1_000_000_000, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + add_network(1, 0, 0); + add_network(2, 0, 0); + // We only add 2 networks, so this should fail + assert_eq!( + SubtensorModule::sudo_set_emission_values( + <::RuntimeOrigin>::root(), + netuids, + emission + ), + Err(Error::::IncorrectNetuidsLength.into()) + ); + }); } #[test] fn test_set_emission_values_over_u16_max_values() { - new_test_ext().execute_with(|| { - // Make vec of u16 with length 2^16 + 2 - let netuids: Vec = vec![0; 0x10002]; - // This is greater than u16::MAX - assert!(netuids.len() > u16::MAX as usize); - // On cast to u16, this will be 2 - assert!(netuids.len() as u16 == 2); + new_test_ext().execute_with(|| { + // Make vec of u16 with length 2^16 + 2 + let netuids: Vec = vec![0; 0x10002]; + // This is greater than u16::MAX + assert!(netuids.len() > u16::MAX as usize); + // On cast to u16, this will be 2 + assert!(netuids.len() as u16 == 2); + + // Sums to 1_000_000_000 and the length is 65536 + let mut emission: Vec = vec![0; netuids.len()]; + emission[0] = 1_000_000_000; - // Sums to 1_000_000_000 and the length is 65536 - let mut emission: Vec = vec![ 0; netuids.len() ]; - emission[0] = 1_000_000_000; - - add_network(1, 0, 0); - add_network(2, 0, 0); - // We only add 2 networks, so this should fail - // but if we cast to u16 during length comparison, - // the length will be 2 and the check will pass - assert_eq!( - SubtensorModule::sudo_set_emission_values(<::RuntimeOrigin>::root(), netuids, emission ), - Err(Error::::IncorrectNetuidsLength.into()) - ); - }); -} \ No newline at end of file + add_network(1, 0, 0); + add_network(2, 0, 0); + // We only add 2 networks, so this should fail + // but if we cast to u16 during length comparison, + // the length will be 2 and the check will pass + assert_eq!( + SubtensorModule::sudo_set_emission_values( + <::RuntimeOrigin>::root(), + netuids, + emission + ), + Err(Error::::IncorrectNetuidsLength.into()) + ); + }); +} diff --git a/pallets/subtensor/tests/neuron_info.rs b/pallets/subtensor/tests/neuron_info.rs index 143355386d..3eef0ce6ba 100644 --- a/pallets/subtensor/tests/neuron_info.rs +++ b/pallets/subtensor/tests/neuron_info.rs @@ -1,10 +1,6 @@ mod mock; use mock::*; - - - - use sp_core::U256; #[test] @@ -31,8 +27,8 @@ fn test_get_neuron_some() { let hotkey0 = U256::from(0); let coldkey0 = U256::from(0); - add_network( netuid, tempo, modality ); - register_ok_neuron( netuid, hotkey0, coldkey0, 39420842 ); + add_network(netuid, tempo, modality); + register_ok_neuron(netuid, hotkey0, coldkey0, 39420842); let neuron = SubtensorModule::get_neuron(netuid, uid); assert_ne!(neuron, None); @@ -48,7 +44,7 @@ fn test_get_neurons_list() { let tempo: u16 = 2; let modality: u16 = 2; - add_network( netuid, tempo, modality ); + add_network(netuid, tempo, modality); let _uid: u16 = 42; @@ -57,7 +53,7 @@ fn test_get_neurons_list() { let hotkey = U256::from(0 + index); let coldkey = U256::from(0 + index); let nonce: u64 = 39420842 + index; - register_ok_neuron( netuid, hotkey, coldkey, nonce ); + register_ok_neuron(netuid, hotkey, coldkey, nonce); } let neurons = SubtensorModule::get_neurons(netuid); @@ -74,4 +70,4 @@ fn test_get_neurons_empty() { let neurons = SubtensorModule::get_neurons(netuid); assert_eq!(neurons.len(), neuron_count as usize); }); -} \ No newline at end of file +} diff --git a/pallets/subtensor/tests/registration.rs b/pallets/subtensor/tests/registration.rs index 3314901793..cf143bdfc6 100644 --- a/pallets/subtensor/tests/registration.rs +++ b/pallets/subtensor/tests/registration.rs @@ -1,864 +1,1606 @@ - use frame_support::traits::Currency; -use pallet_subtensor::{Error, AxonInfoOf}; +use crate::mock::*; use frame_support::assert_ok; +use frame_support::dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}; +use frame_support::sp_runtime::DispatchError; use frame_system::Config; +use pallet_subtensor::{AxonInfoOf, Error}; use sp_core::U256; -use crate::mock::*; -use frame_support::sp_runtime::DispatchError; -use frame_support::dispatch::{GetDispatchInfo, DispatchInfo, DispatchClass, Pays}; mod mock; /******************************************** - subscribing::subscribe() tests + subscribing::subscribe() tests *********************************************/ // Tests a basic registration dispatch passes. #[test] fn test_registration_subscribe_ok_dispatch_info_ok() { - new_test_ext().execute_with(|| { - let block_number: u64 = 0; - let nonce: u64 = 0; + new_test_ext().execute_with(|| { + let block_number: u64 = 0; + let nonce: u64 = 0; let netuid: u16 = 1; - let work: Vec = vec![0;32]; - let hotkey: U256 = U256::from(0); - let coldkey: U256 = U256::from(0); - let call = RuntimeCall::SubtensorModule(SubtensorCall::register{netuid, block_number, nonce, work, hotkey, coldkey }); - assert_eq!(call.get_dispatch_info(), DispatchInfo { - weight: frame_support::weights::Weight::from_ref_time(91000000), - class: DispatchClass::Normal, - pays_fee: Pays::No - }); - }); + let work: Vec = vec![0; 32]; + let hotkey: U256 = U256::from(0); + let coldkey: U256 = U256::from(0); + let call = RuntimeCall::SubtensorModule(SubtensorCall::register { + netuid, + block_number, + nonce, + work, + hotkey, + coldkey, + }); + assert_eq!( + call.get_dispatch_info(), + DispatchInfo { + weight: frame_support::weights::Weight::from_ref_time(91000000), + class: DispatchClass::Normal, + pays_fee: Pays::No + } + ); + }); } #[test] fn test_registration_difficulty() { - new_test_ext().execute_with(|| { - assert_eq!( SubtensorModule::get_difficulty(1).as_u64(), 10000 ); - }); - + new_test_ext().execute_with(|| { + assert_eq!(SubtensorModule::get_difficulty(1).as_u64(), 10000); + }); } #[test] fn test_registration_invalid_seal_hotkey() { - new_test_ext().execute_with(|| { - let block_number: u64 = 0; - let netuid: u16 = 1; - let tempo: u16 = 13; - let hotkey_account_id_1: U256 = U256::from(1); - let hotkey_account_id_2: U256 = U256::from(2); - let coldkey_account_id: U256 = U256::from(667); // Neighbour of the beast, har har - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 0, &hotkey_account_id_1); - let (nonce2, work2): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 0, &hotkey_account_id_1); - - //add network - add_network(netuid, tempo, 0); - - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id_1), netuid, block_number, nonce, work.clone(), hotkey_account_id_1, coldkey_account_id)); - let result = SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id_2), netuid, block_number, nonce2, work2.clone(), hotkey_account_id_2, coldkey_account_id); - assert_eq!( result, Err(Error::::InvalidSeal.into()) ); - }); -} + new_test_ext().execute_with(|| { + let block_number: u64 = 0; + let netuid: u16 = 1; + let tempo: u16 = 13; + let hotkey_account_id_1: U256 = U256::from(1); + let hotkey_account_id_2: U256 = U256::from(2); + let coldkey_account_id: U256 = U256::from(667); // Neighbour of the beast, har har + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 0, + &hotkey_account_id_1, + ); + let (nonce2, work2): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 0, + &hotkey_account_id_1, + ); + + //add network + add_network(netuid, tempo, 0); + + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id_1), + netuid, + block_number, + nonce, + work.clone(), + hotkey_account_id_1, + coldkey_account_id + )); + let result = SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id_2), + netuid, + block_number, + nonce2, + work2.clone(), + hotkey_account_id_2, + coldkey_account_id, + ); + assert_eq!(result, Err(Error::::InvalidSeal.into())); + }); +} #[test] fn test_registration_ok() { - new_test_ext().execute_with(|| { - let block_number: u64 = 0; - let netuid: u16 = 1; - let tempo: u16 = 13; - let hotkey_account_id: U256 = U256::from(1); - let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 129123813, &hotkey_account_id); - - //add network - add_network(netuid, tempo, 0); - - // Subscribe and check extrinsic output - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, block_number, nonce, work, hotkey_account_id, coldkey_account_id)); - - // Check if neuron has added to the specified network(netuid) - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 1); - - //check if hotkey is added to the Hotkeys - assert_eq!(SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey_account_id), coldkey_account_id); - - // Check if the neuron has added to the Keys - let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).unwrap(); - - assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).is_ok()); - // Check if neuron has added to Uids - let neuro_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).unwrap(); - assert_eq!(neuro_uid, neuron_uid); - - // Check if the balance of this hotkey account for this subnetwork == 0 - assert_eq!(SubtensorModule::get_stake_for_uid_and_subnetwork(netuid, neuron_uid), 0); - }); + new_test_ext().execute_with(|| { + let block_number: u64 = 0; + let netuid: u16 = 1; + let tempo: u16 = 13; + let hotkey_account_id: U256 = U256::from(1); + let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 129123813, + &hotkey_account_id, + ); + + //add network + add_network(netuid, tempo, 0); + + // Subscribe and check extrinsic output + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + block_number, + nonce, + work, + hotkey_account_id, + coldkey_account_id + )); + + // Check if neuron has added to the specified network(netuid) + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 1); + + //check if hotkey is added to the Hotkeys + assert_eq!( + SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey_account_id), + coldkey_account_id + ); + + // Check if the neuron has added to the Keys + let neuron_uid = + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).unwrap(); + + assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).is_ok()); + // Check if neuron has added to Uids + let neuro_uid = + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).unwrap(); + assert_eq!(neuro_uid, neuron_uid); + + // Check if the balance of this hotkey account for this subnetwork == 0 + assert_eq!( + SubtensorModule::get_stake_for_uid_and_subnetwork(netuid, neuron_uid), + 0 + ); + }); } - /******************************************** - registration::do_burned_registration tests + registration::do_burned_registration tests *********************************************/ #[test] fn test_burned_registration_ok() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let burn_cost = 1000; - let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har - //add network - SubtensorModule::set_burn( netuid, burn_cost); - add_network(netuid, tempo, 0); - // Give it some $$$ in his coldkey balance - SubtensorModule::add_balance_to_coldkey_account( &coldkey_account_id, 10000 ); - // Subscribe and check extrinsic output - assert_ok!(SubtensorModule::burned_register(<::RuntimeOrigin>::signed(coldkey_account_id), netuid, hotkey_account_id)); - // Check if balance has decreased to pay for the burn. - assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id) as u64, 10000 - burn_cost); // funds drained on reg. - // Check if neuron has added to the specified network(netuid) - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 1); - //check if hotkey is added to the Hotkeys - assert_eq!(SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey_account_id), coldkey_account_id); - // Check if the neuron has added to the Keys - let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).unwrap(); - assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).is_ok()); - // Check if neuron has added to Uids - let neuro_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).unwrap(); - assert_eq!(neuro_uid, neuron_uid); - // Check if the balance of this hotkey account for this subnetwork == 0 - assert_eq!(SubtensorModule::get_stake_for_uid_and_subnetwork(netuid, neuron_uid), 0); - }); + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + let hotkey_account_id = U256::from(1); + let burn_cost = 1000; + let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har + //add network + SubtensorModule::set_burn(netuid, burn_cost); + add_network(netuid, tempo, 0); + // Give it some $$$ in his coldkey balance + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); + // Subscribe and check extrinsic output + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid, + hotkey_account_id + )); + // Check if balance has decreased to pay for the burn. + assert_eq!( + SubtensorModule::get_coldkey_balance(&coldkey_account_id) as u64, + 10000 - burn_cost + ); // funds drained on reg. + // Check if neuron has added to the specified network(netuid) + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 1); + //check if hotkey is added to the Hotkeys + assert_eq!( + SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey_account_id), + coldkey_account_id + ); + // Check if the neuron has added to the Keys + let neuron_uid = + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).unwrap(); + assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).is_ok()); + // Check if neuron has added to Uids + let neuro_uid = + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).unwrap(); + assert_eq!(neuro_uid, neuron_uid); + // Check if the balance of this hotkey account for this subnetwork == 0 + assert_eq!( + SubtensorModule::get_stake_for_uid_and_subnetwork(netuid, neuron_uid), + 0 + ); + }); } #[test] fn test_burn_adjustment() { - new_test_ext().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; - SubtensorModule::set_burn( netuid, burn_cost); - SubtensorModule::set_adjustment_interval( netuid, adjustment_interval ); - SubtensorModule::set_target_registrations_per_interval( netuid, target_registrations_per_interval); - add_network(netuid, tempo, 0); - - // 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); - }); + new_test_ext().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; + SubtensorModule::set_burn(netuid, burn_cost); + SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); + SubtensorModule::set_target_registrations_per_interval( + netuid, + target_registrations_per_interval, + ); + add_network(netuid, tempo, 0); + + // 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] #[cfg(not(tarpaulin))] fn test_registration_too_many_registrations_per_block() { - new_test_ext().execute_with(|| { - - let netuid: u16 = 1; - let tempo: u16 = 13; - SubtensorModule::set_max_registrations_per_block( netuid, 10 ); - SubtensorModule::set_target_registrations_per_interval( netuid, 10 ); - assert_eq!( SubtensorModule::get_max_registrations_per_block(netuid), 10 ); - - let block_number: u64 = 0; - let (nonce0, work0): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 3942084, &U256::from(0)); - let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 11231312312, &U256::from(1)); - let (nonce2, work2): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 212312414, &U256::from(2)); - let (nonce3, work3): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 21813123, &U256::from(3)); - let (nonce4, work4): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 148141209, &U256::from(4)); - let (nonce5, work5): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 1245235534, &U256::from(5)); - let (nonce6, work6): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 256234, &U256::from(6)); - let (nonce7, work7): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 6923424, &U256::from(7)); - let (nonce8, work8): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 124242, &U256::from(8)); - let (nonce9, work9): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 153453, &U256::from(9)); - let (nonce10, work10): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 345923888, &U256::from(10)); - assert_eq!( SubtensorModule::get_difficulty_as_u64(netuid), 10000 ); - - //add network - add_network(netuid, tempo, 0); - - // Subscribe and check extrinsic output - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(0)), netuid, block_number, nonce0, work0, U256::from(0), U256::from(0))); - assert_eq!( SubtensorModule::get_registrations_this_block(netuid), 1 ); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(1)), netuid, block_number, nonce1, work1, U256::from(1), U256::from(1))); - assert_eq!( SubtensorModule::get_registrations_this_block(netuid), 2 ); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(2)), netuid, block_number, nonce2, work2, U256::from(2), U256::from(2))); - assert_eq!( SubtensorModule::get_registrations_this_block(netuid), 3 ); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(3)), netuid, block_number, nonce3, work3, U256::from(3), U256::from(3))); - assert_eq!( SubtensorModule::get_registrations_this_block(netuid), 4 ); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(4)), netuid, block_number, nonce4, work4, U256::from(4), U256::from(4))); - assert_eq!( SubtensorModule::get_registrations_this_block(netuid), 5 ); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(5)), netuid, block_number, nonce5, work5, U256::from(5), U256::from(5))); - assert_eq!( SubtensorModule::get_registrations_this_block(netuid), 6 ); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(6)), netuid, block_number, nonce6, work6, U256::from(6), U256::from(6))); - assert_eq!( SubtensorModule::get_registrations_this_block(netuid), 7 ); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(7)), netuid, block_number, nonce7, work7, U256::from(7), U256::from(7))); - assert_eq!( SubtensorModule::get_registrations_this_block(netuid), 8 ); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(8)), netuid, block_number, nonce8, work8, U256::from(8), U256::from(8))); - assert_eq!( SubtensorModule::get_registrations_this_block(netuid), 9 ); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(9)), netuid, block_number, nonce9, work9, U256::from(9), U256::from(9))); - assert_eq!( SubtensorModule::get_registrations_this_block(netuid), 10 ); - let result = SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(10)), netuid, block_number, nonce10, work10, U256::from(10), U256::from(10)); - assert_eq!( result, Err(Error::::TooManyRegistrationsThisBlock.into()) ); - }); + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + SubtensorModule::set_max_registrations_per_block(netuid, 10); + SubtensorModule::set_target_registrations_per_interval(netuid, 10); + assert_eq!(SubtensorModule::get_max_registrations_per_block(netuid), 10); + + let block_number: u64 = 0; + let (nonce0, work0): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 3942084, + &U256::from(0), + ); + let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 11231312312, + &U256::from(1), + ); + let (nonce2, work2): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 212312414, + &U256::from(2), + ); + let (nonce3, work3): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 21813123, + &U256::from(3), + ); + let (nonce4, work4): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 148141209, + &U256::from(4), + ); + let (nonce5, work5): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 1245235534, + &U256::from(5), + ); + let (nonce6, work6): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 256234, + &U256::from(6), + ); + let (nonce7, work7): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 6923424, + &U256::from(7), + ); + let (nonce8, work8): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 124242, + &U256::from(8), + ); + let (nonce9, work9): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 153453, + &U256::from(9), + ); + let (nonce10, work10): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 345923888, + &U256::from(10), + ); + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 10000); + + //add network + add_network(netuid, tempo, 0); + + // Subscribe and check extrinsic output + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(0)), + netuid, + block_number, + nonce0, + work0, + U256::from(0), + U256::from(0) + )); + assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 1); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(1)), + netuid, + block_number, + nonce1, + work1, + U256::from(1), + U256::from(1) + )); + assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 2); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(2)), + netuid, + block_number, + nonce2, + work2, + U256::from(2), + U256::from(2) + )); + assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 3); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(3)), + netuid, + block_number, + nonce3, + work3, + U256::from(3), + U256::from(3) + )); + assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 4); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(4)), + netuid, + block_number, + nonce4, + work4, + U256::from(4), + U256::from(4) + )); + assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 5); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(5)), + netuid, + block_number, + nonce5, + work5, + U256::from(5), + U256::from(5) + )); + assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 6); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(6)), + netuid, + block_number, + nonce6, + work6, + U256::from(6), + U256::from(6) + )); + assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 7); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(7)), + netuid, + block_number, + nonce7, + work7, + U256::from(7), + U256::from(7) + )); + assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 8); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(8)), + netuid, + block_number, + nonce8, + work8, + U256::from(8), + U256::from(8) + )); + assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 9); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(9)), + netuid, + block_number, + nonce9, + work9, + U256::from(9), + U256::from(9) + )); + assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 10); + let result = SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(10)), + netuid, + block_number, + nonce10, + work10, + U256::from(10), + U256::from(10), + ); + assert_eq!( + result, + Err(Error::::TooManyRegistrationsThisBlock.into()) + ); + }); } #[test] fn test_registration_too_many_registrations_per_interval() { - new_test_ext().execute_with(|| { - - let netuid: u16 = 1; - let tempo: u16 = 13; - SubtensorModule::set_max_registrations_per_block( netuid, 11 ); - assert_eq!( SubtensorModule::get_max_registrations_per_block(netuid), 11 ); - - SubtensorModule::set_target_registrations_per_interval( netuid, 3 ); - assert_eq!( SubtensorModule::get_target_registrations_per_interval(netuid), 3 ); - // Then the max is 3 * 3 = 9 - - let block_number: u64 = 0; - let (nonce0, work0): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 3942084, &U256::from(0)); - let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 11231312312, &U256::from(1)); - let (nonce2, work2): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 212312414, &U256::from(2)); - let (nonce3, work3): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 21813123, &U256::from(3)); - let (nonce4, work4): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 148141209, &U256::from(4)); - let (nonce5, work5): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 1245235534, &U256::from(5)); - let (nonce6, work6): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 256234, &U256::from(6)); - let (nonce7, work7): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 6923424, &U256::from(7)); - let (nonce8, work8): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 124242, &U256::from(8)); - let (nonce9, work9): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 153453, &U256::from(9)); - assert_eq!( SubtensorModule::get_difficulty_as_u64(netuid), 10000 ); - - //add network - add_network(netuid, tempo, 0); - - // Subscribe and check extrinsic output - // Try 10 registrations, this is less than the max per block, but more than the max per interval - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(0)), netuid, block_number, nonce0, work0, U256::from(0), U256::from(0))); - assert_eq!( SubtensorModule::get_registrations_this_interval(netuid), 1 ); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(1)), netuid, block_number, nonce1, work1, U256::from(1), U256::from(1))); - assert_eq!( SubtensorModule::get_registrations_this_interval(netuid), 2 ); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(2)), netuid, block_number, nonce2, work2, U256::from(2), U256::from(2))); - assert_eq!( SubtensorModule::get_registrations_this_interval(netuid), 3 ); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(3)), netuid, block_number, nonce3, work3, U256::from(3), U256::from(3))); - assert_eq!( SubtensorModule::get_registrations_this_interval(netuid), 4 ); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(4)), netuid, block_number, nonce4, work4, U256::from(4), U256::from(4))); - assert_eq!( SubtensorModule::get_registrations_this_interval(netuid), 5 ); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(5)), netuid, block_number, nonce5, work5, U256::from(5), U256::from(5))); - assert_eq!( SubtensorModule::get_registrations_this_interval(netuid), 6 ); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(6)), netuid, block_number, nonce6, work6, U256::from(6), U256::from(6))); - assert_eq!( SubtensorModule::get_registrations_this_interval(netuid), 7 ); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(7)), netuid, block_number, nonce7, work7, U256::from(7), U256::from(7))); - assert_eq!( SubtensorModule::get_registrations_this_interval(netuid), 8 ); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(8)), netuid, block_number, nonce8, work8, U256::from(8), U256::from(8))); - assert_eq!( SubtensorModule::get_registrations_this_interval(netuid), 9 ); - let result = SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(9)), netuid, block_number, nonce9, work9, U256::from(9), U256::from(9)); - assert_eq!( result, Err(Error::::TooManyRegistrationsThisInterval.into()) ); - }); + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + SubtensorModule::set_max_registrations_per_block(netuid, 11); + assert_eq!(SubtensorModule::get_max_registrations_per_block(netuid), 11); + + SubtensorModule::set_target_registrations_per_interval(netuid, 3); + assert_eq!( + SubtensorModule::get_target_registrations_per_interval(netuid), + 3 + ); + // Then the max is 3 * 3 = 9 + + let block_number: u64 = 0; + let (nonce0, work0): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 3942084, + &U256::from(0), + ); + let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 11231312312, + &U256::from(1), + ); + let (nonce2, work2): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 212312414, + &U256::from(2), + ); + let (nonce3, work3): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 21813123, + &U256::from(3), + ); + let (nonce4, work4): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 148141209, + &U256::from(4), + ); + let (nonce5, work5): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 1245235534, + &U256::from(5), + ); + let (nonce6, work6): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 256234, + &U256::from(6), + ); + let (nonce7, work7): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 6923424, + &U256::from(7), + ); + let (nonce8, work8): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 124242, + &U256::from(8), + ); + let (nonce9, work9): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 153453, + &U256::from(9), + ); + assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 10000); + + //add network + add_network(netuid, tempo, 0); + + // Subscribe and check extrinsic output + // Try 10 registrations, this is less than the max per block, but more than the max per interval + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(0)), + netuid, + block_number, + nonce0, + work0, + U256::from(0), + U256::from(0) + )); + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 1); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(1)), + netuid, + block_number, + nonce1, + work1, + U256::from(1), + U256::from(1) + )); + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 2); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(2)), + netuid, + block_number, + nonce2, + work2, + U256::from(2), + U256::from(2) + )); + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 3); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(3)), + netuid, + block_number, + nonce3, + work3, + U256::from(3), + U256::from(3) + )); + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 4); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(4)), + netuid, + block_number, + nonce4, + work4, + U256::from(4), + U256::from(4) + )); + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 5); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(5)), + netuid, + block_number, + nonce5, + work5, + U256::from(5), + U256::from(5) + )); + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 6); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(6)), + netuid, + block_number, + nonce6, + work6, + U256::from(6), + U256::from(6) + )); + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 7); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(7)), + netuid, + block_number, + nonce7, + work7, + U256::from(7), + U256::from(7) + )); + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 8); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(8)), + netuid, + block_number, + nonce8, + work8, + U256::from(8), + U256::from(8) + )); + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 9); + let result = SubtensorModule::register( + <::RuntimeOrigin>::signed(U256::from(9)), + netuid, + block_number, + nonce9, + work9, + U256::from(9), + U256::from(9), + ); + assert_eq!( + result, + Err(Error::::TooManyRegistrationsThisInterval.into()) + ); + }); } #[test] fn test_registration_immunity_period() { //impl this test when epoch impl and calculating pruning score is done - /* TO DO */ + /* TO DO */ } #[test] fn test_registration_already_active_hotkey() { - new_test_ext().execute_with(|| { - - let block_number: u64 = 0; - let netuid: u16 = 1; - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 0, &hotkey_account_id); - - //add network - add_network(netuid, tempo, 0); - - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, block_number, nonce, work, hotkey_account_id, coldkey_account_id)); - - let block_number: u64 = 0; - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 0, &hotkey_account_id); - let result = SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, block_number, nonce, work, hotkey_account_id, coldkey_account_id); - assert_eq!( result, Err(Error::::AlreadyRegistered.into()) ); - }); + new_test_ext().execute_with(|| { + let block_number: u64 = 0; + let netuid: u16 = 1; + let tempo: u16 = 13; + let hotkey_account_id = U256::from(1); + let coldkey_account_id = U256::from(667); + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 0, + &hotkey_account_id, + ); + + //add network + add_network(netuid, tempo, 0); + + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + block_number, + nonce, + work, + hotkey_account_id, + coldkey_account_id + )); + + let block_number: u64 = 0; + let hotkey_account_id = U256::from(1); + let coldkey_account_id = U256::from(667); + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 0, + &hotkey_account_id, + ); + let result = SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + block_number, + nonce, + work, + hotkey_account_id, + coldkey_account_id, + ); + assert_eq!(result, Err(Error::::AlreadyRegistered.into())); + }); } #[test] fn test_registration_invalid_seal() { - new_test_ext().execute_with(|| { - let block_number: u64 = 0; - let netuid:u16 =1; - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, 1, 0, &hotkey_account_id); - - - //add network - add_network(netuid, tempo, 0); - - let result = SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, block_number, nonce, work, hotkey_account_id, coldkey_account_id); - assert_eq!( result, Err(Error::::InvalidSeal.into()) ); - }); + new_test_ext().execute_with(|| { + let block_number: u64 = 0; + let netuid: u16 = 1; + let tempo: u16 = 13; + let hotkey_account_id = U256::from(1); + let coldkey_account_id = U256::from(667); + let (nonce, work): (u64, Vec) = + SubtensorModule::create_work_for_block_number(netuid, 1, 0, &hotkey_account_id); + + //add network + add_network(netuid, tempo, 0); + + let result = SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + block_number, + nonce, + work, + hotkey_account_id, + coldkey_account_id, + ); + assert_eq!(result, Err(Error::::InvalidSeal.into())); + }); } #[test] fn test_registration_invalid_block_number() { - new_test_ext().execute_with(|| { - let block_number: u64 = 1; - let netuid: u16 =1; - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number(netuid, block_number, 0, &hotkey_account_id); - - - //add network - add_network(netuid, tempo, 0); - - let result = SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, block_number, nonce, work, hotkey_account_id, coldkey_account_id); - assert_eq!( result, Err(Error::::InvalidWorkBlock.into()) ); - }); + new_test_ext().execute_with(|| { + let block_number: u64 = 1; + let netuid: u16 = 1; + let tempo: u16 = 13; + let hotkey_account_id = U256::from(1); + let coldkey_account_id = U256::from(667); + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 0, + &hotkey_account_id, + ); + + //add network + add_network(netuid, tempo, 0); + + let result = SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + block_number, + nonce, + work, + hotkey_account_id, + coldkey_account_id, + ); + assert_eq!(result, Err(Error::::InvalidWorkBlock.into())); + }); } #[test] fn test_registration_invalid_difficulty() { - new_test_ext().execute_with(|| { - let block_number: u64 = 0; - let netuid: u16 = 1; - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 0, &hotkey_account_id); - - //add network - add_network(netuid, tempo, 0); - - assert_ok!(SubtensorModule::sudo_set_difficulty( <::RuntimeOrigin>::root(), netuid, 18_446_744_073_709_551_615u64 )); - - let result = SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, block_number, nonce, work, hotkey_account_id, coldkey_account_id); - assert_eq!( result, Err(Error::::InvalidDifficulty.into()) ); - }); + new_test_ext().execute_with(|| { + let block_number: u64 = 0; + let netuid: u16 = 1; + let tempo: u16 = 13; + let hotkey_account_id = U256::from(1); + let coldkey_account_id = U256::from(667); + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 0, + &hotkey_account_id, + ); + + //add network + add_network(netuid, tempo, 0); + + assert_ok!(SubtensorModule::sudo_set_difficulty( + <::RuntimeOrigin>::root(), + netuid, + 18_446_744_073_709_551_615u64 + )); + + let result = SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + block_number, + nonce, + work, + hotkey_account_id, + coldkey_account_id, + ); + assert_eq!(result, Err(Error::::InvalidDifficulty.into())); + }); } #[test] fn test_registration_failed_no_signature() { - new_test_ext().execute_with(|| { - - let block_number: u64 = 1; - let netuid: u16 = 1; - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 0, &hotkey_account_id); - - - // Subscribe and check extrinsic output - let result = SubtensorModule::register(<::RuntimeOrigin>::none(), netuid, block_number, nonce, work, hotkey_account_id, coldkey_account_id); - assert_eq!(result, Err(DispatchError::BadOrigin.into())); - }); + new_test_ext().execute_with(|| { + let block_number: u64 = 1; + let netuid: u16 = 1; + let hotkey_account_id = U256::from(1); + let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 0, + &hotkey_account_id, + ); + + // Subscribe and check extrinsic output + let result = SubtensorModule::register( + <::RuntimeOrigin>::none(), + netuid, + block_number, + nonce, + work, + hotkey_account_id, + coldkey_account_id, + ); + assert_eq!(result, Err(DispatchError::BadOrigin.into())); + }); } #[test] fn test_registration_get_uid_to_prune_all_in_immunity_period() { - new_test_ext().execute_with(|| { - let netuid: u16 = 0; - add_network(netuid, 0, 0); - log::info!("add netweork"); - register_ok_neuron( netuid, U256::from(0), U256::from(0), 39420842 ); - register_ok_neuron( netuid, U256::from(1), U256::from(1), 12412392 ); - SubtensorModule::set_pruning_score_for_uid(netuid, 0, 100); - SubtensorModule::set_pruning_score_for_uid(netuid, 1, 110); - assert_eq!(SubtensorModule::get_pruning_score_for_uid( netuid, 0 ), 100 ); - assert_eq!(SubtensorModule::get_pruning_score_for_uid( netuid, 1 ), 110 ); - assert_eq!(SubtensorModule::get_immunity_period(netuid), 2); - assert_eq!(SubtensorModule::get_current_block_as_u64(), 0); - assert_eq!(SubtensorModule::get_neuron_block_at_registration(netuid, 0), 0); - assert_eq!(SubtensorModule::get_neuron_to_prune(0), 0); - }); + new_test_ext().execute_with(|| { + let netuid: u16 = 0; + add_network(netuid, 0, 0); + log::info!("add netweork"); + register_ok_neuron(netuid, U256::from(0), U256::from(0), 39420842); + register_ok_neuron(netuid, U256::from(1), U256::from(1), 12412392); + SubtensorModule::set_pruning_score_for_uid(netuid, 0, 100); + SubtensorModule::set_pruning_score_for_uid(netuid, 1, 110); + assert_eq!(SubtensorModule::get_pruning_score_for_uid(netuid, 0), 100); + assert_eq!(SubtensorModule::get_pruning_score_for_uid(netuid, 1), 110); + assert_eq!(SubtensorModule::get_immunity_period(netuid), 2); + assert_eq!(SubtensorModule::get_current_block_as_u64(), 0); + assert_eq!( + SubtensorModule::get_neuron_block_at_registration(netuid, 0), + 0 + ); + assert_eq!(SubtensorModule::get_neuron_to_prune(0), 0); + }); } #[test] fn test_registration_get_uid_to_prune_none_in_immunity_period() { - new_test_ext().execute_with(|| { - let netuid: u16 = 0; - add_network(netuid, 0, 0); - log::info!("add netweork"); - register_ok_neuron( netuid, U256::from(0), U256::from(0), 39420842 ); - register_ok_neuron( netuid, U256::from(1), U256::from(1), 12412392 ); - SubtensorModule::set_pruning_score_for_uid(netuid, 0, 100); - SubtensorModule::set_pruning_score_for_uid(netuid, 1, 110); - assert_eq!(SubtensorModule::get_pruning_score_for_uid( netuid, 0 ), 100 ); - assert_eq!(SubtensorModule::get_pruning_score_for_uid( netuid, 1 ), 110 ); - assert_eq!(SubtensorModule::get_immunity_period(netuid), 2); - assert_eq!(SubtensorModule::get_current_block_as_u64(), 0); - assert_eq!(SubtensorModule::get_neuron_block_at_registration(netuid, 0), 0); - step_block(3); - assert_eq!(SubtensorModule::get_current_block_as_u64(), 3); - assert_eq!(SubtensorModule::get_neuron_to_prune(0), 0); - }); + new_test_ext().execute_with(|| { + let netuid: u16 = 0; + add_network(netuid, 0, 0); + log::info!("add netweork"); + register_ok_neuron(netuid, U256::from(0), U256::from(0), 39420842); + register_ok_neuron(netuid, U256::from(1), U256::from(1), 12412392); + SubtensorModule::set_pruning_score_for_uid(netuid, 0, 100); + SubtensorModule::set_pruning_score_for_uid(netuid, 1, 110); + assert_eq!(SubtensorModule::get_pruning_score_for_uid(netuid, 0), 100); + assert_eq!(SubtensorModule::get_pruning_score_for_uid(netuid, 1), 110); + assert_eq!(SubtensorModule::get_immunity_period(netuid), 2); + assert_eq!(SubtensorModule::get_current_block_as_u64(), 0); + assert_eq!( + SubtensorModule::get_neuron_block_at_registration(netuid, 0), + 0 + ); + step_block(3); + assert_eq!(SubtensorModule::get_current_block_as_u64(), 3); + assert_eq!(SubtensorModule::get_neuron_to_prune(0), 0); + }); } #[test] fn test_registration_get_uid_to_prune_mix() { - new_test_ext().execute_with(|| { - let netuid: u16 = 0; - add_network(netuid, 0, 0); - log::info!("add netweork"); - register_ok_neuron( netuid, U256::from(0), U256::from(0), 39420842 ); - SubtensorModule::set_pruning_score_for_uid(netuid, 0, 120); - assert_eq!(SubtensorModule::get_pruning_score_for_uid( netuid, 0 ), 120 ); - step_block(1); - register_ok_neuron( netuid, U256::from(1), U256::from(1), 12412392 ); - SubtensorModule::set_pruning_score_for_uid(netuid, 1, 110); - assert_eq!(SubtensorModule::get_pruning_score_for_uid( netuid, 1 ), 110 ); - assert_eq!(SubtensorModule::get_immunity_period(netuid), 2); - assert_eq!(SubtensorModule::get_current_block_as_u64(), 1); - assert_eq!(SubtensorModule::get_neuron_block_at_registration(netuid, 0), 0); - assert_eq!(SubtensorModule::get_neuron_block_at_registration(netuid, 1), 1); - assert_eq!(SubtensorModule::get_neuron_to_prune(0), 1); - step_block(2); - assert_eq!(SubtensorModule::get_current_block_as_u64(), 3); - assert_eq!(SubtensorModule::get_neuron_to_prune(0), 0); - }); + new_test_ext().execute_with(|| { + let netuid: u16 = 0; + add_network(netuid, 0, 0); + log::info!("add netweork"); + register_ok_neuron(netuid, U256::from(0), U256::from(0), 39420842); + SubtensorModule::set_pruning_score_for_uid(netuid, 0, 120); + assert_eq!(SubtensorModule::get_pruning_score_for_uid(netuid, 0), 120); + step_block(1); + register_ok_neuron(netuid, U256::from(1), U256::from(1), 12412392); + SubtensorModule::set_pruning_score_for_uid(netuid, 1, 110); + assert_eq!(SubtensorModule::get_pruning_score_for_uid(netuid, 1), 110); + assert_eq!(SubtensorModule::get_immunity_period(netuid), 2); + assert_eq!(SubtensorModule::get_current_block_as_u64(), 1); + assert_eq!( + SubtensorModule::get_neuron_block_at_registration(netuid, 0), + 0 + ); + assert_eq!( + SubtensorModule::get_neuron_block_at_registration(netuid, 1), + 1 + ); + assert_eq!(SubtensorModule::get_neuron_to_prune(0), 1); + step_block(2); + assert_eq!(SubtensorModule::get_current_block_as_u64(), 3); + assert_eq!(SubtensorModule::get_neuron_to_prune(0), 0); + }); } #[test] fn test_registration_pruning() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; - let block_number: u64 = 0; - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); - let (nonce0, work0): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 3942084, &hotkey_account_id); - - - //add network - add_network(netuid, tempo, 0); - - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, block_number, nonce0, work0, hotkey_account_id, coldkey_account_id)); - // - let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).unwrap(); - SubtensorModule::set_pruning_score_for_uid(netuid, neuron_uid, 2); - // - let hotkey_account_id1 = U256::from(2); - let coldkey_account_id1 = U256::from(668); - let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 11231312312, &hotkey_account_id1); - - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id1), netuid, block_number, nonce1, work1, hotkey_account_id1, coldkey_account_id1)); - // - let neuron_uid1 = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id1).unwrap(); - SubtensorModule::set_pruning_score_for_uid(netuid, neuron_uid1, 3); - // - let hotkey_account_id2 = U256::from(3); - let coldkey_account_id2 = U256::from(669); - let (nonce2, work2): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 212312414, &hotkey_account_id2); - - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id2), netuid, block_number, nonce2, work2, hotkey_account_id2, coldkey_account_id2)); - }); + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let block_number: u64 = 0; + let tempo: u16 = 13; + let hotkey_account_id = U256::from(1); + let coldkey_account_id = U256::from(667); + let (nonce0, work0): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 3942084, + &hotkey_account_id, + ); + + //add network + add_network(netuid, tempo, 0); + + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + block_number, + nonce0, + work0, + hotkey_account_id, + coldkey_account_id + )); + // + let neuron_uid = + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).unwrap(); + SubtensorModule::set_pruning_score_for_uid(netuid, neuron_uid, 2); + // + let hotkey_account_id1 = U256::from(2); + let coldkey_account_id1 = U256::from(668); + let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 11231312312, + &hotkey_account_id1, + ); + + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id1), + netuid, + block_number, + nonce1, + work1, + hotkey_account_id1, + coldkey_account_id1 + )); + // + let neuron_uid1 = + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id1).unwrap(); + SubtensorModule::set_pruning_score_for_uid(netuid, neuron_uid1, 3); + // + let hotkey_account_id2 = U256::from(3); + let coldkey_account_id2 = U256::from(669); + let (nonce2, work2): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 212312414, + &hotkey_account_id2, + ); + + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id2), + netuid, + block_number, + nonce2, + work2, + hotkey_account_id2, + coldkey_account_id2 + )); + }); } #[test] fn test_registration_get_neuron_metadata() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; - let block_number: u64 = 0; - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); - let (nonce0, work0): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 3942084, &hotkey_account_id); - - - add_network(netuid, tempo, 0); - - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, block_number, nonce0, work0, hotkey_account_id, coldkey_account_id)); - // - //let neuron_id = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id); - // let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey( netuid, &hotkey_account_id ).unwrap(); - let neuron: AxonInfoOf = SubtensorModule::get_axon_info( netuid, &hotkey_account_id ); - assert_eq!(neuron.ip, 0); - assert_eq!(neuron.version, 0); - assert_eq!(neuron.port, 0); - }); + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let block_number: u64 = 0; + let tempo: u16 = 13; + let hotkey_account_id = U256::from(1); + let coldkey_account_id = U256::from(667); + let (nonce0, work0): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 3942084, + &hotkey_account_id, + ); + + add_network(netuid, tempo, 0); + + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + block_number, + nonce0, + work0, + hotkey_account_id, + coldkey_account_id + )); + // + //let neuron_id = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id); + // let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey( netuid, &hotkey_account_id ).unwrap(); + let neuron: AxonInfoOf = SubtensorModule::get_axon_info(netuid, &hotkey_account_id); + assert_eq!(neuron.ip, 0); + assert_eq!(neuron.version, 0); + assert_eq!(neuron.port, 0); + }); } #[test] fn test_registration_add_network_size() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let netuid: u16 = 1; - let netuid2: u16 = 2; - let block_number: u64 = 0; - let hotkey_account_id = U256::from(1); - let hotkey_account_id1 = U256::from(2); - let hotkey_account_id2 = U256::from(3); - let (nonce0, work0): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 3942084, &hotkey_account_id); - let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid2, block_number, 11231312312, &hotkey_account_id1); - let (nonce2, work2): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid2, block_number, 21813123, &hotkey_account_id2); - let coldkey_account_id = U256::from(667); - - add_network(netuid, 13, 0); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 0); - - add_network(netuid2, 13, 0); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 0); - - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, block_number, nonce0, work0, hotkey_account_id, coldkey_account_id)); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 1); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 1); - - - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id1), netuid2, block_number, nonce1, work1, hotkey_account_id1, coldkey_account_id)); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id2), netuid2, block_number, nonce2, work2, hotkey_account_id2, coldkey_account_id)); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 2); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid2), 2); - }); + let netuid2: u16 = 2; + let block_number: u64 = 0; + let hotkey_account_id = U256::from(1); + let hotkey_account_id1 = U256::from(2); + let hotkey_account_id2 = U256::from(3); + let (nonce0, work0): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 3942084, + &hotkey_account_id, + ); + let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid2, + block_number, + 11231312312, + &hotkey_account_id1, + ); + let (nonce2, work2): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid2, + block_number, + 21813123, + &hotkey_account_id2, + ); + let coldkey_account_id = U256::from(667); + + add_network(netuid, 13, 0); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 0); + + add_network(netuid2, 13, 0); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 0); + + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + block_number, + nonce0, + work0, + hotkey_account_id, + coldkey_account_id + )); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 1); + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 1); + + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id1), + netuid2, + block_number, + nonce1, + work1, + hotkey_account_id1, + coldkey_account_id + )); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id2), + netuid2, + block_number, + nonce2, + work2, + hotkey_account_id2, + coldkey_account_id + )); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 2); + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid2), 2); + }); } #[test] fn test_burn_registration_increase_recycled_rao() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let netuid: u16 = 1; - let netuid2: u16 = 2; - - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); - - // Give funds for burn. 1000 TAO - let _ = Balances::deposit_creating(&coldkey_account_id, Balance::from(1_000_000_000_000 as u64)); - - add_network(netuid, 13, 0); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 0); - - add_network(netuid2, 13, 0); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 0); - - run_to_block(1); - - let burn_amount = SubtensorModule::get_burn_as_u64(netuid); - assert_ok!(SubtensorModule::burned_register(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, hotkey_account_id)); - assert_eq!(SubtensorModule::get_rao_recycled(netuid), burn_amount); - - run_to_block(2); - - let burn_amount2 = SubtensorModule::get_burn_as_u64(netuid2); - assert_ok!(SubtensorModule::burned_register(<::RuntimeOrigin>::signed(hotkey_account_id), netuid2, hotkey_account_id)); - assert_ok!(SubtensorModule::burned_register(<::RuntimeOrigin>::signed(U256::from(2)), netuid2, U256::from(2))); - assert_eq!(SubtensorModule::get_rao_recycled(netuid2), burn_amount2 * 2); - // Validate netuid is not affected. - assert_eq!(SubtensorModule::get_rao_recycled(netuid), burn_amount); - }); + let netuid2: u16 = 2; + + let hotkey_account_id = U256::from(1); + let coldkey_account_id = U256::from(667); + + // Give funds for burn. 1000 TAO + let _ = Balances::deposit_creating( + &coldkey_account_id, + Balance::from(1_000_000_000_000 as u64), + ); + + add_network(netuid, 13, 0); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 0); + + add_network(netuid2, 13, 0); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 0); + + run_to_block(1); + + let burn_amount = SubtensorModule::get_burn_as_u64(netuid); + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + hotkey_account_id + )); + assert_eq!(SubtensorModule::get_rao_recycled(netuid), burn_amount); + + run_to_block(2); + + let burn_amount2 = SubtensorModule::get_burn_as_u64(netuid2); + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid2, + hotkey_account_id + )); + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(U256::from(2)), + netuid2, + U256::from(2) + )); + assert_eq!(SubtensorModule::get_rao_recycled(netuid2), burn_amount2 * 2); + // Validate netuid is not affected. + assert_eq!(SubtensorModule::get_rao_recycled(netuid), burn_amount); + }); } #[test] fn test_full_pass_through() { - new_test_ext().execute_with(|| { - - // Create 3 networks. + new_test_ext().execute_with(|| { + // Create 3 networks. let netuid0: u16 = 0; - let netuid1: u16 = 1; - let netuid2: u16 = 2; - - // With 3 tempos - let tempo0: u16 = 2; - let tempo1: u16 = 2; - let tempo2: u16 = 2; - - // Create 3 keys. - let hotkey0 = U256::from(0); - let hotkey1 = U256::from(1); - let hotkey2 = U256::from(2); - - // With 3 different coldkeys. - let coldkey0 = U256::from(0); - let coldkey1 = U256::from(1); - let coldkey2= U256::from(2); - - // Add the 3 networks. - add_network( netuid0, tempo0, 0 ); - add_network( netuid1, tempo1, 0 ); - add_network( netuid2, tempo2, 0 ); - - // Check their tempo. - assert_eq!(SubtensorModule::get_tempo(netuid0), tempo0); + let netuid1: u16 = 1; + let netuid2: u16 = 2; + + // With 3 tempos + let tempo0: u16 = 2; + let tempo1: u16 = 2; + let tempo2: u16 = 2; + + // Create 3 keys. + let hotkey0 = U256::from(0); + let hotkey1 = U256::from(1); + let hotkey2 = U256::from(2); + + // With 3 different coldkeys. + let coldkey0 = U256::from(0); + let coldkey1 = U256::from(1); + let coldkey2 = U256::from(2); + + // Add the 3 networks. + add_network(netuid0, tempo0, 0); + add_network(netuid1, tempo1, 0); + add_network(netuid2, tempo2, 0); + + // Check their tempo. + assert_eq!(SubtensorModule::get_tempo(netuid0), tempo0); assert_eq!(SubtensorModule::get_tempo(netuid1), tempo1); assert_eq!(SubtensorModule::get_tempo(netuid2), tempo2); - // Check their emission value. + // Check their emission value. assert_eq!(SubtensorModule::get_emission_value(netuid0), 0); assert_eq!(SubtensorModule::get_emission_value(netuid1), 0); assert_eq!(SubtensorModule::get_emission_value(netuid2), 0); - // Set their max allowed uids. - SubtensorModule::set_max_allowed_uids( netuid0, 2 ); - SubtensorModule::set_max_allowed_uids( netuid1, 2 ); - SubtensorModule::set_max_allowed_uids( netuid2, 2 ); - - // Check their max allowed. - assert_eq!( SubtensorModule::get_max_allowed_uids( netuid0 ), 2 ); - assert_eq!( SubtensorModule::get_max_allowed_uids( netuid0 ), 2 ); - assert_eq!( SubtensorModule::get_max_allowed_uids( netuid0 ), 2 ); - - // Set the max registration per block. - SubtensorModule::set_max_registrations_per_block( netuid0, 3 ); - SubtensorModule::set_max_registrations_per_block( netuid1, 3 ); - SubtensorModule::set_max_registrations_per_block( netuid2, 3 ); - assert_eq!( SubtensorModule::get_max_registrations_per_block(netuid0), 3 ); - assert_eq!( SubtensorModule::get_max_registrations_per_block(netuid1), 3 ); - assert_eq!( SubtensorModule::get_max_registrations_per_block(netuid2), 3 ); - - // Check that no one has registered yet. - assert_eq!(SubtensorModule::get_subnetwork_n(netuid0), 0); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid1), 0); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 0); - - // Registered the keys to all networks. - register_ok_neuron( netuid0, hotkey0, coldkey0, 39420842 ); - register_ok_neuron( netuid0, hotkey1, coldkey1, 12412392 ); - register_ok_neuron( netuid1, hotkey0, coldkey0, 21813123 ); - register_ok_neuron( netuid1, hotkey1, coldkey1, 25755207 ); - register_ok_neuron( netuid2, hotkey0, coldkey0, 251232207 ); - register_ok_neuron( netuid2, hotkey1, coldkey1, 159184122 ); - - // Check uids. - // n0 [ h0, h1 ] - // n1 [ h0, h1 ] - // n2 [ h0, h1 ] - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid0, 0 ).unwrap(), hotkey0 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid1, 0 ).unwrap(), hotkey0 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid2, 0 ).unwrap(), hotkey0 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid0, 1 ).unwrap(), hotkey1 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid1, 1 ).unwrap(), hotkey1 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid2, 1 ).unwrap(), hotkey1 ); - - // Check registered networks. - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid0 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid1 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid2 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid0 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid1 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid2 ) ); - // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid0 ) ); - // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid1 ) ); - // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid2 ) ); - - // Check the number of registrations. - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid0), 2); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid1), 2); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid2), 2); - - // Get the number of uids in each network. - assert_eq!(SubtensorModule::get_subnetwork_n(netuid0), 2); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid1), 2); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 2); - - // Check the uids exist. - assert!( SubtensorModule::is_uid_exist_on_network( netuid0, 0) ); - assert!( SubtensorModule::is_uid_exist_on_network( netuid1, 0) ); - assert!( SubtensorModule::is_uid_exist_on_network( netuid2, 0) ); - - // Check the other exists. - assert!( SubtensorModule::is_uid_exist_on_network( netuid0, 1) ); - assert!( SubtensorModule::is_uid_exist_on_network( netuid1, 1) ); - assert!( SubtensorModule::is_uid_exist_on_network( netuid2, 1) ); - - // Get the hotkey under each uid. - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid0, 0).unwrap(), hotkey0 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid1, 0).unwrap(), hotkey0 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid2, 0).unwrap(), hotkey0 ); - - // Get the hotkey under the other uid. - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid0, 1).unwrap(), hotkey1 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid1, 1).unwrap(), hotkey1 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid2, 1).unwrap(), hotkey1 ); - - // Check for replacement. - assert_eq!(SubtensorModule::get_subnetwork_n(netuid0), 2); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid1), 2); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 2); - - // Register the 3rd hotkey. - register_ok_neuron( netuid0, hotkey2, coldkey2, 59420842 ); - register_ok_neuron( netuid1, hotkey2, coldkey2, 31813123 ); - register_ok_neuron( netuid2, hotkey2, coldkey2, 451232207 ); - - // Check for replacement. - assert_eq!(SubtensorModule::get_subnetwork_n(netuid0), 2); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid1), 2); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 2); - - // Check uids. - // n0 [ h0, h1 ] - // n1 [ h0, h1 ] - // n2 [ h0, h1 ] - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid0, 0 ).unwrap(), hotkey2 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid1, 0 ).unwrap(), hotkey2 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid2, 0 ).unwrap(), hotkey2 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid0, 1 ).unwrap(), hotkey1 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid1, 1 ).unwrap(), hotkey1 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid2, 1 ).unwrap(), hotkey1 ); - - // Check registered networks. - // hotkey0 has been deregistered. - // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid0 ) ); - // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid1 ) ); - // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid2 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid0 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid1 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid2 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid0 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid1 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid2 ) ); - - // Check the registration counters. - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid0), 3); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid1), 3); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid2), 3); - - // Check the hotkeys are expected. - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid0, 0 ).unwrap(), hotkey2 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid1, 0 ).unwrap(), hotkey2 ); - assert_eq!( SubtensorModule::get_hotkey_for_net_and_uid( netuid2, 0 ).unwrap(), hotkey2 ); - }); + // Set their max allowed uids. + SubtensorModule::set_max_allowed_uids(netuid0, 2); + SubtensorModule::set_max_allowed_uids(netuid1, 2); + SubtensorModule::set_max_allowed_uids(netuid2, 2); + + // Check their max allowed. + assert_eq!(SubtensorModule::get_max_allowed_uids(netuid0), 2); + assert_eq!(SubtensorModule::get_max_allowed_uids(netuid0), 2); + assert_eq!(SubtensorModule::get_max_allowed_uids(netuid0), 2); + + // Set the max registration per block. + SubtensorModule::set_max_registrations_per_block(netuid0, 3); + SubtensorModule::set_max_registrations_per_block(netuid1, 3); + SubtensorModule::set_max_registrations_per_block(netuid2, 3); + assert_eq!(SubtensorModule::get_max_registrations_per_block(netuid0), 3); + assert_eq!(SubtensorModule::get_max_registrations_per_block(netuid1), 3); + assert_eq!(SubtensorModule::get_max_registrations_per_block(netuid2), 3); + + // Check that no one has registered yet. + assert_eq!(SubtensorModule::get_subnetwork_n(netuid0), 0); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid1), 0); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 0); + + // Registered the keys to all networks. + register_ok_neuron(netuid0, hotkey0, coldkey0, 39420842); + register_ok_neuron(netuid0, hotkey1, coldkey1, 12412392); + register_ok_neuron(netuid1, hotkey0, coldkey0, 21813123); + register_ok_neuron(netuid1, hotkey1, coldkey1, 25755207); + register_ok_neuron(netuid2, hotkey0, coldkey0, 251232207); + register_ok_neuron(netuid2, hotkey1, coldkey1, 159184122); + + // Check uids. + // n0 [ h0, h1 ] + // n1 [ h0, h1 ] + // n2 [ h0, h1 ] + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid0, 0).unwrap(), + hotkey0 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid1, 0).unwrap(), + hotkey0 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid2, 0).unwrap(), + hotkey0 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid0, 1).unwrap(), + hotkey1 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid1, 1).unwrap(), + hotkey1 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid2, 1).unwrap(), + hotkey1 + ); + + // Check registered networks. + // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid0 ) ); + // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid1 ) ); + // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid2 ) ); + // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid0 ) ); + // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid1 ) ); + // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid2 ) ); + // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid0 ) ); + // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid1 ) ); + // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid2 ) ); + + // Check the number of registrations. + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid0), 2); + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid1), 2); + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid2), 2); + + // Get the number of uids in each network. + assert_eq!(SubtensorModule::get_subnetwork_n(netuid0), 2); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid1), 2); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 2); + + // Check the uids exist. + assert!(SubtensorModule::is_uid_exist_on_network(netuid0, 0)); + assert!(SubtensorModule::is_uid_exist_on_network(netuid1, 0)); + assert!(SubtensorModule::is_uid_exist_on_network(netuid2, 0)); + + // Check the other exists. + assert!(SubtensorModule::is_uid_exist_on_network(netuid0, 1)); + assert!(SubtensorModule::is_uid_exist_on_network(netuid1, 1)); + assert!(SubtensorModule::is_uid_exist_on_network(netuid2, 1)); + + // Get the hotkey under each uid. + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid0, 0).unwrap(), + hotkey0 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid1, 0).unwrap(), + hotkey0 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid2, 0).unwrap(), + hotkey0 + ); + + // Get the hotkey under the other uid. + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid0, 1).unwrap(), + hotkey1 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid1, 1).unwrap(), + hotkey1 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid2, 1).unwrap(), + hotkey1 + ); + + // Check for replacement. + assert_eq!(SubtensorModule::get_subnetwork_n(netuid0), 2); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid1), 2); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 2); + + // Register the 3rd hotkey. + register_ok_neuron(netuid0, hotkey2, coldkey2, 59420842); + register_ok_neuron(netuid1, hotkey2, coldkey2, 31813123); + register_ok_neuron(netuid2, hotkey2, coldkey2, 451232207); + + // Check for replacement. + assert_eq!(SubtensorModule::get_subnetwork_n(netuid0), 2); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid1), 2); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 2); + + // Check uids. + // n0 [ h0, h1 ] + // n1 [ h0, h1 ] + // n2 [ h0, h1 ] + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid0, 0).unwrap(), + hotkey2 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid1, 0).unwrap(), + hotkey2 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid2, 0).unwrap(), + hotkey2 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid0, 1).unwrap(), + hotkey1 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid1, 1).unwrap(), + hotkey1 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid2, 1).unwrap(), + hotkey1 + ); + + // Check registered networks. + // hotkey0 has been deregistered. + // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid0 ) ); + // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid1 ) ); + // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid2 ) ); + // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid0 ) ); + // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid1 ) ); + // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid2 ) ); + // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid0 ) ); + // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid1 ) ); + // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid2 ) ); + + // Check the registration counters. + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid0), 3); + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid1), 3); + assert_eq!(SubtensorModule::get_registrations_this_interval(netuid2), 3); + + // Check the hotkeys are expected. + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid0, 0).unwrap(), + hotkey2 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid1, 0).unwrap(), + hotkey2 + ); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(netuid2, 0).unwrap(), + hotkey2 + ); + }); } - #[test] fn test_network_connection_requirement() { - new_test_ext().execute_with(|| { - // Add a networks and connection requirements. - let netuid_a: u16 = 0; - let netuid_b: u16 = 1; - add_network(netuid_a, 10, 0); - add_network(netuid_b, 10, 0); - - // Bulk values. - let hotkeys: Vec = (0..=10).map(|x| U256::from(x)).collect(); - let coldkeys: Vec = (0..=10).map(|x| U256::from(x)).collect(); - - // Add a connection requirement between the A and B. A requires B. - SubtensorModule::add_connection_requirement( netuid_a, netuid_b, u16::MAX ); - SubtensorModule::set_max_registrations_per_block( netuid_a, 10 ); // Enough for the below tests. - SubtensorModule::set_max_registrations_per_block( netuid_b, 10 ); // Enough for the below tests. - SubtensorModule::set_max_allowed_uids( netuid_a, 10 ); // Enough for the below tests. - SubtensorModule::set_max_allowed_uids( netuid_b, 10 ); // Enough for the below tests. - - // Attempt registration on A fails because the hotkey is not registered on network B. - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid_a, 0, 3942084, &U256::from(0)); - assert_eq!( SubtensorModule::register(<::RuntimeOrigin>::signed( hotkeys[0] ), netuid_a, 0, nonce, work, hotkeys[0], coldkeys[0]), Err(Error::::DidNotPassConnectedNetworkRequirement.into()) ); - - // Attempt registration on B passes because there is no exterior requirement. - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid_b, 0, 5942084, &U256::from(0)); - assert_ok!( SubtensorModule::register(<::RuntimeOrigin>::signed( hotkeys[0] ), netuid_b, 0, nonce, work, hotkeys[0], coldkeys[0]) ); - - // Attempt registration on A passes because this key is in the top 100 of keys on network B. - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid_a, 0, 6942084, &U256::from(0)); - assert_ok!( SubtensorModule::register(<::RuntimeOrigin>::signed( hotkeys[0] ), netuid_a, 0, nonce, work, hotkeys[0], coldkeys[0]) ); - - // Lets attempt the key registration on A. Fails because we are not in B. - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid_a, 0, 634242084, &U256::from(1)); - assert_eq!( SubtensorModule::register(<::RuntimeOrigin>::signed( hotkeys[1] ), netuid_a, 0, nonce, work, hotkeys[1], coldkeys[1]), Err(Error::::DidNotPassConnectedNetworkRequirement.into()) ); - - // Lets register the next key on B. Passes, np. - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid_b, 0, 7942084, &U256::from(1)); - assert_ok!( SubtensorModule::register(<::RuntimeOrigin>::signed( hotkeys[1] ), netuid_b, 0, nonce, work, hotkeys[1], coldkeys[1]) ); - - // Lets make the connection requirement harder. Top 0th percentile. - SubtensorModule::add_connection_requirement( netuid_a, netuid_b, 0 ); - - // Attempted registration passes because the prunning score for hotkey_1 is the top keys on network B. - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid_a, 0, 8942084, &U256::from(1)); - assert_ok!( SubtensorModule::register(<::RuntimeOrigin>::signed( hotkeys[1] ), netuid_a, 0, nonce, work, hotkeys[1], coldkeys[1]) ); - - // Lets register key 3 with lower prunning score. - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid_b, 0, 9942084, &U256::from(2)); - assert_ok!( SubtensorModule::register(<::RuntimeOrigin>::signed( hotkeys[2] ), netuid_b, 0, nonce, work, hotkeys[2], coldkeys[2]) ); - SubtensorModule::set_pruning_score_for_uid( netuid_b, SubtensorModule::get_uid_for_net_and_hotkey( netuid_b, &hotkeys[2] ).unwrap(), 0); // Set prunning score to 0. - SubtensorModule::set_pruning_score_for_uid( netuid_b, SubtensorModule::get_uid_for_net_and_hotkey( netuid_b, &hotkeys[1] ).unwrap(), 0); // Set prunning score to 0. - SubtensorModule::set_pruning_score_for_uid( netuid_b, SubtensorModule::get_uid_for_net_and_hotkey( netuid_b, &hotkeys[0] ).unwrap(), 0); // Set prunning score to 0. - - // Lets register key 4 with higher prunining score. - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid_b, 0, 10142084, &U256::from(3)); - assert_ok!( SubtensorModule::register(<::RuntimeOrigin>::signed( hotkeys[3] ), netuid_b, 0, nonce, work, hotkeys[3], coldkeys[3]) ); - SubtensorModule::set_pruning_score_for_uid( netuid_b, SubtensorModule::get_uid_for_net_and_hotkey( netuid_b, &hotkeys[3] ).unwrap(), 1); // Set prunning score to 1. - - // Attempted register of key 3 fails because of bad prunning score on B. - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid_a, 0, 11142084, &U256::from(2)); - assert_eq!( SubtensorModule::register(<::RuntimeOrigin>::signed( hotkeys[2] ), netuid_a, 0, nonce, work, hotkeys[2], coldkeys[2]), Err(Error::::DidNotPassConnectedNetworkRequirement.into()) ); - - // Attempt to register key 4 passes because of best prunning score on B. - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid_b, 0, 12142084, &U256::from(3)); - assert_ok!( SubtensorModule::register(<::RuntimeOrigin>::signed( hotkeys[3] ), netuid_a, 0, nonce, work, hotkeys[3], coldkeys[3]) ); - }); + new_test_ext().execute_with(|| { + // Add a networks and connection requirements. + let netuid_a: u16 = 0; + let netuid_b: u16 = 1; + add_network(netuid_a, 10, 0); + add_network(netuid_b, 10, 0); + + // Bulk values. + let hotkeys: Vec = (0..=10).map(|x| U256::from(x)).collect(); + let coldkeys: Vec = (0..=10).map(|x| U256::from(x)).collect(); + + // Add a connection requirement between the A and B. A requires B. + SubtensorModule::add_connection_requirement(netuid_a, netuid_b, u16::MAX); + SubtensorModule::set_max_registrations_per_block(netuid_a, 10); // Enough for the below tests. + SubtensorModule::set_max_registrations_per_block(netuid_b, 10); // Enough for the below tests. + SubtensorModule::set_max_allowed_uids(netuid_a, 10); // Enough for the below tests. + SubtensorModule::set_max_allowed_uids(netuid_b, 10); // Enough for the below tests. + + // Attempt registration on A fails because the hotkey is not registered on network B. + let (nonce, work): (u64, Vec) = + SubtensorModule::create_work_for_block_number(netuid_a, 0, 3942084, &U256::from(0)); + assert_eq!( + SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkeys[0]), + netuid_a, + 0, + nonce, + work, + hotkeys[0], + coldkeys[0] + ), + Err(Error::::DidNotPassConnectedNetworkRequirement.into()) + ); + + // Attempt registration on B passes because there is no exterior requirement. + let (nonce, work): (u64, Vec) = + SubtensorModule::create_work_for_block_number(netuid_b, 0, 5942084, &U256::from(0)); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkeys[0]), + netuid_b, + 0, + nonce, + work, + hotkeys[0], + coldkeys[0] + )); + + // Attempt registration on A passes because this key is in the top 100 of keys on network B. + let (nonce, work): (u64, Vec) = + SubtensorModule::create_work_for_block_number(netuid_a, 0, 6942084, &U256::from(0)); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkeys[0]), + netuid_a, + 0, + nonce, + work, + hotkeys[0], + coldkeys[0] + )); + + // Lets attempt the key registration on A. Fails because we are not in B. + let (nonce, work): (u64, Vec) = + SubtensorModule::create_work_for_block_number(netuid_a, 0, 634242084, &U256::from(1)); + assert_eq!( + SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkeys[1]), + netuid_a, + 0, + nonce, + work, + hotkeys[1], + coldkeys[1] + ), + Err(Error::::DidNotPassConnectedNetworkRequirement.into()) + ); + + // Lets register the next key on B. Passes, np. + let (nonce, work): (u64, Vec) = + SubtensorModule::create_work_for_block_number(netuid_b, 0, 7942084, &U256::from(1)); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkeys[1]), + netuid_b, + 0, + nonce, + work, + hotkeys[1], + coldkeys[1] + )); + + // Lets make the connection requirement harder. Top 0th percentile. + SubtensorModule::add_connection_requirement(netuid_a, netuid_b, 0); + + // Attempted registration passes because the prunning score for hotkey_1 is the top keys on network B. + let (nonce, work): (u64, Vec) = + SubtensorModule::create_work_for_block_number(netuid_a, 0, 8942084, &U256::from(1)); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkeys[1]), + netuid_a, + 0, + nonce, + work, + hotkeys[1], + coldkeys[1] + )); + + // Lets register key 3 with lower prunning score. + let (nonce, work): (u64, Vec) = + SubtensorModule::create_work_for_block_number(netuid_b, 0, 9942084, &U256::from(2)); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkeys[2]), + netuid_b, + 0, + nonce, + work, + hotkeys[2], + coldkeys[2] + )); + SubtensorModule::set_pruning_score_for_uid( + netuid_b, + SubtensorModule::get_uid_for_net_and_hotkey(netuid_b, &hotkeys[2]).unwrap(), + 0, + ); // Set prunning score to 0. + SubtensorModule::set_pruning_score_for_uid( + netuid_b, + SubtensorModule::get_uid_for_net_and_hotkey(netuid_b, &hotkeys[1]).unwrap(), + 0, + ); // Set prunning score to 0. + SubtensorModule::set_pruning_score_for_uid( + netuid_b, + SubtensorModule::get_uid_for_net_and_hotkey(netuid_b, &hotkeys[0]).unwrap(), + 0, + ); // Set prunning score to 0. + + // Lets register key 4 with higher prunining score. + let (nonce, work): (u64, Vec) = + SubtensorModule::create_work_for_block_number(netuid_b, 0, 10142084, &U256::from(3)); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkeys[3]), + netuid_b, + 0, + nonce, + work, + hotkeys[3], + coldkeys[3] + )); + SubtensorModule::set_pruning_score_for_uid( + netuid_b, + SubtensorModule::get_uid_for_net_and_hotkey(netuid_b, &hotkeys[3]).unwrap(), + 1, + ); // Set prunning score to 1. + + // Attempted register of key 3 fails because of bad prunning score on B. + let (nonce, work): (u64, Vec) = + SubtensorModule::create_work_for_block_number(netuid_a, 0, 11142084, &U256::from(2)); + assert_eq!( + SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkeys[2]), + netuid_a, + 0, + nonce, + work, + hotkeys[2], + coldkeys[2] + ), + Err(Error::::DidNotPassConnectedNetworkRequirement.into()) + ); + + // Attempt to register key 4 passes because of best prunning score on B. + let (nonce, work): (u64, Vec) = + SubtensorModule::create_work_for_block_number(netuid_b, 0, 12142084, &U256::from(3)); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkeys[3]), + netuid_a, + 0, + nonce, + work, + hotkeys[3], + coldkeys[3] + )); + }); } #[test] fn test_registration_origin_hotkey_mismatch() { - new_test_ext().execute_with(|| { - let block_number: u64 = 0; - let netuid: u16 = 1; - let tempo: u16 = 13; - let hotkey_account_id_1: U256 = U256::from(1); - let hotkey_account_id_2: U256 = U256::from(2); - let coldkey_account_id: U256 = U256::from(668); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 0, &hotkey_account_id_1); - - //add network - add_network(netuid, tempo, 0); - - let result = SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id_1), - netuid, block_number, nonce, work.clone(), - hotkey_account_id_2, // Not the same as the origin. - coldkey_account_id - ); - assert_eq!( result, Err(Error::::HotkeyOriginMismatch.into()) ); - }); + new_test_ext().execute_with(|| { + let block_number: u64 = 0; + let netuid: u16 = 1; + let tempo: u16 = 13; + let hotkey_account_id_1: U256 = U256::from(1); + let hotkey_account_id_2: U256 = U256::from(2); + let coldkey_account_id: U256 = U256::from(668); + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 0, + &hotkey_account_id_1, + ); + + //add network + add_network(netuid, tempo, 0); + + let result = SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id_1), + netuid, + block_number, + nonce, + work.clone(), + hotkey_account_id_2, // Not the same as the origin. + coldkey_account_id, + ); + assert_eq!(result, Err(Error::::HotkeyOriginMismatch.into())); + }); } #[test] fn test_registration_disabled() { - new_test_ext().execute_with(|| { - let block_number: u64 = 0; - let netuid: u16 = 1; - let tempo: u16 = 13; - let hotkey_account_id: U256 = U256::from(1); - let coldkey_account_id: U256 = U256::from(668); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 0, &hotkey_account_id); - - //add network - add_network(netuid, tempo, 0); - SubtensorModule::set_network_registration_allowed(netuid, false); - - let result = SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id), - netuid, block_number, nonce, work.clone(), - hotkey_account_id, - coldkey_account_id - ); - assert_eq!( result, Err(Error::::RegistrationDisabled.into()) ); - }); -} \ No newline at end of file + new_test_ext().execute_with(|| { + let block_number: u64 = 0; + let netuid: u16 = 1; + let tempo: u16 = 13; + let hotkey_account_id: U256 = U256::from(1); + let coldkey_account_id: U256 = U256::from(668); + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 0, + &hotkey_account_id, + ); + + //add network + add_network(netuid, tempo, 0); + SubtensorModule::set_network_registration_allowed(netuid, false); + + let result = SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + block_number, + nonce, + work.clone(), + hotkey_account_id, + coldkey_account_id, + ); + assert_eq!(result, Err(Error::::RegistrationDisabled.into())); + }); +} diff --git a/pallets/subtensor/tests/serving.rs b/pallets/subtensor/tests/serving.rs index ce19e7babe..50895fd1ac 100644 --- a/pallets/subtensor/tests/serving.rs +++ b/pallets/subtensor/tests/serving.rs @@ -2,19 +2,14 @@ use crate::mock::*; mod mock; use frame_support::{ assert_ok, - dispatch::{ - GetDispatchInfo, - DispatchInfo, - DispatchClass, - Pays - } + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}, }; -use pallet_subtensor::Error; use frame_system::Config; +use pallet_subtensor::Error; use sp_core::U256; mod test { -use std::net::{Ipv4Addr, Ipv6Addr}; + use std::net::{Ipv4Addr, Ipv6Addr}; // Generates an ipv6 address based on 8 ipv6 words and returns it as u128 pub fn ipv6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> u128 { @@ -32,315 +27,528 @@ use std::net::{Ipv4Addr, Ipv6Addr}; #[test] fn test_serving_subscribe_ok_dispatch_info_ok() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; - let version : u32 = 2; - let ip: u128 = 1676056785; - let port: u16 = 128; - let ip_type: u8 = 4; - let protocol: u8 = 0; - let placeholder1: u8 = 0; - let placeholder2: u8 = 0; - let call = RuntimeCall::SubtensorModule(SubtensorCall::serve_axon { netuid, version, ip, port, ip_type, protocol, placeholder1, placeholder2}); - assert_eq!(call.get_dispatch_info(), DispatchInfo { - weight: frame_support::weights::Weight::from_ref_time(19000000), - class: DispatchClass::Normal, - pays_fee: Pays::No - }); - }); + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let version: u32 = 2; + let ip: u128 = 1676056785; + let port: u16 = 128; + let ip_type: u8 = 4; + let protocol: u8 = 0; + let placeholder1: u8 = 0; + let placeholder2: u8 = 0; + let call = RuntimeCall::SubtensorModule(SubtensorCall::serve_axon { + netuid, + version, + ip, + port, + ip_type, + protocol, + placeholder1, + placeholder2, + }); + assert_eq!( + call.get_dispatch_info(), + DispatchInfo { + weight: frame_support::weights::Weight::from_ref_time(19000000), + class: DispatchClass::Normal, + pays_fee: Pays::No + } + ); + }); } #[test] fn test_serving_ok() { - new_test_ext().execute_with(|| { - let hotkey_account_id = U256::from(1); - let netuid: u16 = 1; - let tempo: u16 = 13; - let version : u32 = 2; - let ip: u128 = 1676056785; - let port: u16 = 128; - let ip_type: u8 = 4; - let modality: u16 = 0; - let protocol: u8 = 0; - let placeholder1: u8 = 0; - let placeholder2: u8 = 0; - add_network(netuid, tempo, modality); - register_ok_neuron( netuid, hotkey_account_id, U256::from(66), 0); - assert_ok!(SubtensorModule::serve_axon(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version, ip, port, ip_type, protocol, placeholder1, placeholder2)); - let neuron = SubtensorModule::get_axon_info( netuid, &hotkey_account_id ); - assert_eq!(neuron.ip, ip); - assert_eq!(neuron.version, version); - assert_eq!(neuron.port, port); - assert_eq!(neuron.ip_type, ip_type); - assert_eq!(neuron.protocol, protocol); - assert_eq!(neuron.placeholder1, placeholder1); - assert_eq!(neuron.placeholder2, placeholder2); - }); + new_test_ext().execute_with(|| { + let hotkey_account_id = U256::from(1); + let netuid: u16 = 1; + let tempo: u16 = 13; + let version: u32 = 2; + let ip: u128 = 1676056785; + let port: u16 = 128; + let ip_type: u8 = 4; + let modality: u16 = 0; + let protocol: u8 = 0; + let placeholder1: u8 = 0; + let placeholder2: u8 = 0; + add_network(netuid, tempo, modality); + register_ok_neuron(netuid, hotkey_account_id, U256::from(66), 0); + assert_ok!(SubtensorModule::serve_axon( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version, + ip, + port, + ip_type, + protocol, + placeholder1, + placeholder2 + )); + let neuron = SubtensorModule::get_axon_info(netuid, &hotkey_account_id); + assert_eq!(neuron.ip, ip); + assert_eq!(neuron.version, version); + assert_eq!(neuron.port, port); + assert_eq!(neuron.ip_type, ip_type); + assert_eq!(neuron.protocol, protocol); + assert_eq!(neuron.placeholder1, placeholder1); + assert_eq!(neuron.placeholder2, placeholder2); + }); } #[test] fn test_serving_set_metadata_update() { - new_test_ext().execute_with(|| { - let hotkey_account_id = U256::from(1); - let netuid: u16 = 1; - let tempo: u16 = 13; - let version: u32 = 2; - let ip: u128 = 1676056785; - let port: u16 = 128; - let ip_type: u8 = 4; - let modality: u16 = 0; - let protocol: u8 = 0; - let placeholder1: u8 = 0; - let placeholder2: u8 = 0; - add_network(netuid, tempo, modality); - register_ok_neuron( netuid, hotkey_account_id, U256::from(66), 0); - assert_ok!(SubtensorModule::serve_axon(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version, ip, port, ip_type, protocol, placeholder1, placeholder2)); - let neuron = SubtensorModule::get_axon_info( netuid, &hotkey_account_id ); - assert_eq!(neuron.ip, ip); - assert_eq!(neuron.version, version); - assert_eq!(neuron.port, port); - assert_eq!(neuron.ip_type, ip_type); - assert_eq!(neuron.protocol, protocol); - assert_eq!(neuron.placeholder1, placeholder1); - assert_eq!(neuron.placeholder2, placeholder2); - let version2: u32 = version + 1; - let ip2: u128 = ip + 1; - let port2: u16 = port + 1; - let ip_type2: u8 = 6; - let protocol2: u8 = protocol + 1; - let placeholder12: u8 = placeholder1 + 1; - let placeholder22: u8 = placeholder2 + 1; - assert_ok!(SubtensorModule::serve_axon(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version2, ip2, port2, ip_type2, protocol2, placeholder12, placeholder22)); - let neuron = SubtensorModule::get_axon_info( netuid, &hotkey_account_id ); - assert_eq!(neuron.ip, ip2); - assert_eq!(neuron.version, version2); - assert_eq!(neuron.port, port2); - assert_eq!(neuron.ip_type, ip_type2); - assert_eq!(neuron.protocol, protocol2); - assert_eq!(neuron.placeholder1, placeholder12); - assert_eq!(neuron.placeholder2, placeholder22); - - }); + new_test_ext().execute_with(|| { + let hotkey_account_id = U256::from(1); + let netuid: u16 = 1; + let tempo: u16 = 13; + let version: u32 = 2; + let ip: u128 = 1676056785; + let port: u16 = 128; + let ip_type: u8 = 4; + let modality: u16 = 0; + let protocol: u8 = 0; + let placeholder1: u8 = 0; + let placeholder2: u8 = 0; + add_network(netuid, tempo, modality); + register_ok_neuron(netuid, hotkey_account_id, U256::from(66), 0); + assert_ok!(SubtensorModule::serve_axon( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version, + ip, + port, + ip_type, + protocol, + placeholder1, + placeholder2 + )); + let neuron = SubtensorModule::get_axon_info(netuid, &hotkey_account_id); + assert_eq!(neuron.ip, ip); + assert_eq!(neuron.version, version); + assert_eq!(neuron.port, port); + assert_eq!(neuron.ip_type, ip_type); + assert_eq!(neuron.protocol, protocol); + assert_eq!(neuron.placeholder1, placeholder1); + assert_eq!(neuron.placeholder2, placeholder2); + let version2: u32 = version + 1; + let ip2: u128 = ip + 1; + let port2: u16 = port + 1; + let ip_type2: u8 = 6; + let protocol2: u8 = protocol + 1; + let placeholder12: u8 = placeholder1 + 1; + let placeholder22: u8 = placeholder2 + 1; + assert_ok!(SubtensorModule::serve_axon( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version2, + ip2, + port2, + ip_type2, + protocol2, + placeholder12, + placeholder22 + )); + let neuron = SubtensorModule::get_axon_info(netuid, &hotkey_account_id); + assert_eq!(neuron.ip, ip2); + assert_eq!(neuron.version, version2); + assert_eq!(neuron.port, port2); + assert_eq!(neuron.ip_type, ip_type2); + assert_eq!(neuron.protocol, protocol2); + assert_eq!(neuron.placeholder1, placeholder12); + assert_eq!(neuron.placeholder2, placeholder22); + }); } #[test] #[cfg(not(tarpaulin))] fn test_axon_serving_rate_limit_exceeded() { - new_test_ext().execute_with(|| { - let hotkey_account_id = U256::from(1); - let netuid: u16 = 1; - let tempo: u16 = 13; - let version: u32 = 2; - let ip: u128 = 1676056785; - let port: u16 = 128; - let ip_type: u8 = 4; - let modality: u16 = 0; - let protocol: u8 = 0; - let placeholder1: u8 = 0; - let placeholder2: u8 = 0; - add_network(netuid, tempo, modality); - register_ok_neuron( netuid, hotkey_account_id, U256::from(66), 0); - run_to_block(1); // Go to block 1 - // No issue on multiple - assert_ok!(SubtensorModule::serve_axon(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version, ip, port, ip_type, protocol, placeholder1, placeholder2)); - assert_ok!(SubtensorModule::serve_axon(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version, ip, port, ip_type, protocol, placeholder1, placeholder2)); - assert_ok!(SubtensorModule::serve_axon(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version, ip, port, ip_type, protocol, placeholder1, placeholder2)); - assert_ok!(SubtensorModule::serve_axon(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version, ip, port, ip_type, protocol, placeholder1, placeholder2)); - SubtensorModule::set_serving_rate_limit( netuid, 2 ); - run_to_block(2); // Go to block 2 - // Needs to be 2 blocks apart, we are only 1 block apart - assert_eq!(SubtensorModule::serve_axon(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version, ip, port, ip_type, protocol, placeholder1, placeholder2), Err(Error::::ServingRateLimitExceeded.into()) ); - }); + new_test_ext().execute_with(|| { + let hotkey_account_id = U256::from(1); + let netuid: u16 = 1; + let tempo: u16 = 13; + let version: u32 = 2; + let ip: u128 = 1676056785; + let port: u16 = 128; + let ip_type: u8 = 4; + let modality: u16 = 0; + let protocol: u8 = 0; + let placeholder1: u8 = 0; + let placeholder2: u8 = 0; + add_network(netuid, tempo, modality); + register_ok_neuron(netuid, hotkey_account_id, U256::from(66), 0); + run_to_block(1); // Go to block 1 + // No issue on multiple + assert_ok!(SubtensorModule::serve_axon( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version, + ip, + port, + ip_type, + protocol, + placeholder1, + placeholder2 + )); + assert_ok!(SubtensorModule::serve_axon( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version, + ip, + port, + ip_type, + protocol, + placeholder1, + placeholder2 + )); + assert_ok!(SubtensorModule::serve_axon( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version, + ip, + port, + ip_type, + protocol, + placeholder1, + placeholder2 + )); + assert_ok!(SubtensorModule::serve_axon( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version, + ip, + port, + ip_type, + protocol, + placeholder1, + placeholder2 + )); + SubtensorModule::set_serving_rate_limit(netuid, 2); + run_to_block(2); // Go to block 2 + // Needs to be 2 blocks apart, we are only 1 block apart + assert_eq!( + SubtensorModule::serve_axon( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version, + ip, + port, + ip_type, + protocol, + placeholder1, + placeholder2 + ), + Err(Error::::ServingRateLimitExceeded.into()) + ); + }); } #[test] fn test_axon_invalid_port() { - new_test_ext().execute_with(|| { - let hotkey_account_id = U256::from(1); - let netuid: u16 = 1; - let tempo: u16 = 13; - let version: u32 = 2; - let ip: u128 = 1676056785; - let port: u16 = 0; - let ip_type: u8 = 4; - let modality: u16 = 0; - let protocol: u8 = 0; - let placeholder1: u8 = 0; - let placeholder2: u8 = 0; - add_network(netuid, tempo, modality); - register_ok_neuron( netuid, hotkey_account_id, U256::from(66), 0); - run_to_block(1); // Go to block 1 - assert_eq!(SubtensorModule::serve_axon(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version, ip, port, ip_type, protocol, placeholder1, placeholder2), Err(Error::::InvalidPort.into()) ); - }); + new_test_ext().execute_with(|| { + let hotkey_account_id = U256::from(1); + let netuid: u16 = 1; + let tempo: u16 = 13; + let version: u32 = 2; + let ip: u128 = 1676056785; + let port: u16 = 0; + let ip_type: u8 = 4; + let modality: u16 = 0; + let protocol: u8 = 0; + let placeholder1: u8 = 0; + let placeholder2: u8 = 0; + add_network(netuid, tempo, modality); + register_ok_neuron(netuid, hotkey_account_id, U256::from(66), 0); + run_to_block(1); // Go to block 1 + assert_eq!( + SubtensorModule::serve_axon( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version, + ip, + port, + ip_type, + protocol, + placeholder1, + placeholder2 + ), + Err(Error::::InvalidPort.into()) + ); + }); } #[test] fn test_prometheus_serving_subscribe_ok_dispatch_info_ok() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; - let version : u32 = 2; - let ip: u128 = 1676056785; - let port: u16 = 128; - let ip_type: u8 = 4; - let call = RuntimeCall::SubtensorModule(SubtensorCall::serve_prometheus{ netuid, version, ip, port, ip_type}); - assert_eq!(call.get_dispatch_info(), DispatchInfo { - weight: frame_support::weights::Weight::from_ref_time(17000000), - class: DispatchClass::Normal, - pays_fee: Pays::No - }); - }); + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let version: u32 = 2; + let ip: u128 = 1676056785; + let port: u16 = 128; + let ip_type: u8 = 4; + let call = RuntimeCall::SubtensorModule(SubtensorCall::serve_prometheus { + netuid, + version, + ip, + port, + ip_type, + }); + assert_eq!( + call.get_dispatch_info(), + DispatchInfo { + weight: frame_support::weights::Weight::from_ref_time(17000000), + class: DispatchClass::Normal, + pays_fee: Pays::No + } + ); + }); } #[test] fn test_prometheus_serving_ok() { - new_test_ext().execute_with(|| { - let hotkey_account_id = U256::from(1); - let netuid: u16 = 1; - let tempo: u16 = 13; - let version : u32 = 2; - let ip: u128 = 1676056785; - let port: u16 = 128; - let ip_type: u8 = 4; - let modality: u16 = 0; - add_network(netuid, tempo, modality); - register_ok_neuron( netuid, hotkey_account_id, U256::from(66), 0); - assert_ok!(SubtensorModule::serve_prometheus(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version, ip, port, ip_type)); - let neuron = SubtensorModule::get_prometheus_info( netuid, &hotkey_account_id ); - assert_eq!(neuron.ip, ip); - assert_eq!(neuron.version, version); - assert_eq!(neuron.port, port); - assert_eq!(neuron.ip_type, ip_type); - }); + new_test_ext().execute_with(|| { + let hotkey_account_id = U256::from(1); + let netuid: u16 = 1; + let tempo: u16 = 13; + let version: u32 = 2; + let ip: u128 = 1676056785; + let port: u16 = 128; + let ip_type: u8 = 4; + let modality: u16 = 0; + add_network(netuid, tempo, modality); + register_ok_neuron(netuid, hotkey_account_id, U256::from(66), 0); + assert_ok!(SubtensorModule::serve_prometheus( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version, + ip, + port, + ip_type + )); + let neuron = SubtensorModule::get_prometheus_info(netuid, &hotkey_account_id); + assert_eq!(neuron.ip, ip); + assert_eq!(neuron.version, version); + assert_eq!(neuron.port, port); + assert_eq!(neuron.ip_type, ip_type); + }); } #[test] fn test_prometheus_serving_set_metadata_update() { - new_test_ext().execute_with(|| { - let hotkey_account_id = U256::from(1); - let netuid: u16 = 1; - let tempo: u16 = 13; - let version: u32 = 2; - let ip: u128 = 1676056785; - let port: u16 = 128; - let ip_type: u8 = 4; - let modality: u16 = 0; - add_network(netuid, tempo, modality); - register_ok_neuron( netuid, hotkey_account_id, U256::from(66), 0); - assert_ok!(SubtensorModule::serve_prometheus(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version, ip, port, ip_type)); - let neuron = SubtensorModule::get_prometheus_info( netuid, &hotkey_account_id ); - assert_eq!(neuron.ip, ip); - assert_eq!(neuron.version, version); - assert_eq!(neuron.port, port); - assert_eq!(neuron.ip_type, ip_type); - let version2: u32 = version + 1; - let ip2: u128 = ip + 1; - let port2: u16 = port + 1; - let ip_type2: u8 = 6; - assert_ok!(SubtensorModule::serve_prometheus(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version2, ip2, port2, ip_type2)); - let neuron = SubtensorModule::get_prometheus_info( netuid, &hotkey_account_id ); - assert_eq!(neuron.ip, ip2); - assert_eq!(neuron.version, version2); - assert_eq!(neuron.port, port2); - assert_eq!(neuron.ip_type, ip_type2); - - }); + new_test_ext().execute_with(|| { + let hotkey_account_id = U256::from(1); + let netuid: u16 = 1; + let tempo: u16 = 13; + let version: u32 = 2; + let ip: u128 = 1676056785; + let port: u16 = 128; + let ip_type: u8 = 4; + let modality: u16 = 0; + add_network(netuid, tempo, modality); + register_ok_neuron(netuid, hotkey_account_id, U256::from(66), 0); + assert_ok!(SubtensorModule::serve_prometheus( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version, + ip, + port, + ip_type + )); + let neuron = SubtensorModule::get_prometheus_info(netuid, &hotkey_account_id); + assert_eq!(neuron.ip, ip); + assert_eq!(neuron.version, version); + assert_eq!(neuron.port, port); + assert_eq!(neuron.ip_type, ip_type); + let version2: u32 = version + 1; + let ip2: u128 = ip + 1; + let port2: u16 = port + 1; + let ip_type2: u8 = 6; + assert_ok!(SubtensorModule::serve_prometheus( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version2, + ip2, + port2, + ip_type2 + )); + let neuron = SubtensorModule::get_prometheus_info(netuid, &hotkey_account_id); + assert_eq!(neuron.ip, ip2); + assert_eq!(neuron.version, version2); + assert_eq!(neuron.port, port2); + assert_eq!(neuron.ip_type, ip_type2); + }); } #[test] #[cfg(not(tarpaulin))] fn test_prometheus_serving_rate_limit_exceeded() { - new_test_ext().execute_with(|| { - let hotkey_account_id = U256::from(1); - let netuid: u16 = 1; - let tempo: u16 = 13; - let version: u32 = 2; - let ip: u128 = 1676056785; - let port: u16 = 128; - let ip_type: u8 = 4; - let modality: u16 = 0; - add_network(netuid, tempo, modality); - register_ok_neuron( netuid, hotkey_account_id, U256::from(66), 0); - run_to_block(1); // Go to block 1 - // No issue on multiple - assert_ok!(SubtensorModule::serve_prometheus(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version, ip, port, ip_type)); - assert_ok!(SubtensorModule::serve_prometheus(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version, ip, port, ip_type)); - assert_ok!(SubtensorModule::serve_prometheus(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version, ip, port, ip_type)); - assert_ok!(SubtensorModule::serve_prometheus(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version, ip, port, ip_type)); - SubtensorModule::set_serving_rate_limit( netuid, 1 ); - // Same block, need 1 block to pass - assert_eq!(SubtensorModule::serve_prometheus(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version, ip, port, ip_type), Err(Error::::ServingRateLimitExceeded.into()) ); - }); + new_test_ext().execute_with(|| { + let hotkey_account_id = U256::from(1); + let netuid: u16 = 1; + let tempo: u16 = 13; + let version: u32 = 2; + let ip: u128 = 1676056785; + let port: u16 = 128; + let ip_type: u8 = 4; + let modality: u16 = 0; + add_network(netuid, tempo, modality); + register_ok_neuron(netuid, hotkey_account_id, U256::from(66), 0); + run_to_block(1); // Go to block 1 + // No issue on multiple + assert_ok!(SubtensorModule::serve_prometheus( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version, + ip, + port, + ip_type + )); + assert_ok!(SubtensorModule::serve_prometheus( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version, + ip, + port, + ip_type + )); + assert_ok!(SubtensorModule::serve_prometheus( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version, + ip, + port, + ip_type + )); + assert_ok!(SubtensorModule::serve_prometheus( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version, + ip, + port, + ip_type + )); + SubtensorModule::set_serving_rate_limit(netuid, 1); + // Same block, need 1 block to pass + assert_eq!( + SubtensorModule::serve_prometheus( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version, + ip, + port, + ip_type + ), + Err(Error::::ServingRateLimitExceeded.into()) + ); + }); } #[test] fn test_prometheus_invalid_port() { - new_test_ext().execute_with(|| { - let hotkey_account_id = U256::from(1); - let netuid: u16 = 1; - let tempo: u16 = 13; - let version: u32 = 2; - let ip: u128 = 1676056785; - let port: u16 = 0; - let ip_type: u8 = 4; - let modality: u16 = 0; - add_network(netuid, tempo, modality); - register_ok_neuron( netuid, hotkey_account_id, U256::from(66), 0); - run_to_block(1); // Go to block 1 - assert_eq!(SubtensorModule::serve_prometheus(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, version, ip, port, ip_type), Err(Error::::InvalidPort.into()) ); - }); + new_test_ext().execute_with(|| { + let hotkey_account_id = U256::from(1); + let netuid: u16 = 1; + let tempo: u16 = 13; + let version: u32 = 2; + let ip: u128 = 1676056785; + let port: u16 = 0; + let ip_type: u8 = 4; + let modality: u16 = 0; + add_network(netuid, tempo, modality); + register_ok_neuron(netuid, hotkey_account_id, U256::from(66), 0); + run_to_block(1); // Go to block 1 + assert_eq!( + SubtensorModule::serve_prometheus( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + version, + ip, + port, + ip_type + ), + Err(Error::::InvalidPort.into()) + ); + }); } #[test] fn test_serving_is_valid_ip_type_ok_ipv4() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { assert_eq!(SubtensorModule::is_valid_ip_type(4), true); - }); + }); } #[test] fn test_serving_is_valid_ip_type_ok_ipv6() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { assert_eq!(SubtensorModule::is_valid_ip_type(6), true); - }); + }); } #[test] fn test_serving_is_valid_ip_type_nok() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { assert_eq!(SubtensorModule::is_valid_ip_type(10), false); - }); + }); } #[test] fn test_serving_is_valid_ip_address_ipv4() { - new_test_ext().execute_with(|| { - assert_eq!(SubtensorModule::is_valid_ip_address(4, test::ipv4(8, 8, 8, 8)), true); - }); + new_test_ext().execute_with(|| { + assert_eq!( + SubtensorModule::is_valid_ip_address(4, test::ipv4(8, 8, 8, 8)), + true + ); + }); } #[test] fn test_serving_is_valid_ip_address_ipv6() { - new_test_ext().execute_with(|| { - assert_eq!(SubtensorModule::is_valid_ip_address(6, test::ipv6(1, 2, 3, 4, 5, 6, 7, 8)), true); - assert_eq!(SubtensorModule::is_valid_ip_address(6, test::ipv6(1, 2, 3, 4, 5, 6, 7, 8)), true); - }); + new_test_ext().execute_with(|| { + assert_eq!( + SubtensorModule::is_valid_ip_address(6, test::ipv6(1, 2, 3, 4, 5, 6, 7, 8)), + true + ); + assert_eq!( + SubtensorModule::is_valid_ip_address(6, test::ipv6(1, 2, 3, 4, 5, 6, 7, 8)), + true + ); + }); } #[test] fn test_serving_is_invalid_ipv4_address() { - new_test_ext().execute_with(|| { - assert_eq!(SubtensorModule::is_valid_ip_address(4, test::ipv4(0, 0, 0, 0)), false); - assert_eq!(SubtensorModule::is_valid_ip_address(4, test::ipv4(255, 255, 255, 255)), false); - assert_eq!(SubtensorModule::is_valid_ip_address(4, test::ipv4(127, 0, 0, 1)), false); - assert_eq!(SubtensorModule::is_valid_ip_address(4, test::ipv6(0xffff, 2, 3, 4, 5, 6, 7, 8)), false); - }); + new_test_ext().execute_with(|| { + assert_eq!( + SubtensorModule::is_valid_ip_address(4, test::ipv4(0, 0, 0, 0)), + false + ); + assert_eq!( + SubtensorModule::is_valid_ip_address(4, test::ipv4(255, 255, 255, 255)), + false + ); + assert_eq!( + SubtensorModule::is_valid_ip_address(4, test::ipv4(127, 0, 0, 1)), + false + ); + assert_eq!( + SubtensorModule::is_valid_ip_address(4, test::ipv6(0xffff, 2, 3, 4, 5, 6, 7, 8)), + false + ); + }); } #[test] fn test_serving_is_invalid_ipv6_address() { - new_test_ext().execute_with(|| { - assert_eq!(SubtensorModule::is_valid_ip_address(6, test::ipv6(0, 0, 0, 0, 0, 0, 0, 0)), false); - assert_eq!(SubtensorModule::is_valid_ip_address(4, test::ipv6(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)), false); - }); + new_test_ext().execute_with(|| { + assert_eq!( + SubtensorModule::is_valid_ip_address(6, test::ipv6(0, 0, 0, 0, 0, 0, 0, 0)), + false + ); + assert_eq!( + SubtensorModule::is_valid_ip_address( + 4, + test::ipv6(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff) + ), + false + ); + }); } - diff --git a/pallets/subtensor/tests/staking.rs b/pallets/subtensor/tests/staking.rs index c6eace9c94..b8aaadd9aa 100644 --- a/pallets/subtensor/tests/staking.rs +++ b/pallets/subtensor/tests/staking.rs @@ -1,546 +1,659 @@ -use frame_support::{assert_ok, assert_noop, traits::Currency}; +use frame_support::{assert_noop, assert_ok, traits::Currency}; use frame_system::Config; mod mock; -use mock::*; +use frame_support::dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}; use frame_support::sp_runtime::DispatchError; +use mock::*; use pallet_subtensor::Error; -use frame_support::dispatch::{GetDispatchInfo, DispatchInfo, DispatchClass, Pays}; use sp_core::U256; /*********************************************************** - staking::add_stake() tests + staking::add_stake() tests ************************************************************/ #[test] #[cfg(not(tarpaulin))] fn test_add_stake_dispatch_info_ok() { - new_test_ext().execute_with(|| { - let hotkey = U256::from(0); - let amount_staked = 5000; - let call = RuntimeCall::SubtensorModule(SubtensorCall::add_stake{hotkey, amount_staked}); - assert_eq!(call.get_dispatch_info(), DispatchInfo { - weight: frame_support::weights::Weight::from_ref_time(65000000), - class: DispatchClass::Normal, - pays_fee: Pays::No - }); - }); + new_test_ext().execute_with(|| { + let hotkey = U256::from(0); + let amount_staked = 5000; + let call = RuntimeCall::SubtensorModule(SubtensorCall::add_stake { + hotkey, + amount_staked, + }); + assert_eq!( + call.get_dispatch_info(), + DispatchInfo { + weight: frame_support::weights::Weight::from_ref_time(65000000), + class: DispatchClass::Normal, + pays_fee: Pays::No + } + ); + }); } #[test] fn test_add_stake_ok_no_emission() { - new_test_ext().execute_with(|| { - let hotkey_account_id = U256::from(533453); - let coldkey_account_id = U256::from(55453); - let netuid : u16 = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; - - //add network - add_network(netuid, tempo, 0); - - // Register neuron - register_ok_neuron( netuid, hotkey_account_id, coldkey_account_id, start_nonce); + new_test_ext().execute_with(|| { + let hotkey_account_id = U256::from(533453); + let coldkey_account_id = U256::from(55453); + let netuid: u16 = 1; + let tempo: u16 = 13; + let start_nonce: u64 = 0; - // Give it some $$$ in his coldkey balance - SubtensorModule::add_balance_to_coldkey_account( &coldkey_account_id, 10000 ); + //add network + add_network(netuid, tempo, 0); - // Check we have zero staked before transfer - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id ), 0); + // Register neuron + register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); - // Also total stake should be zero - assert_eq!(SubtensorModule::get_total_stake(), 0); + // Give it some $$$ in his coldkey balance + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); - // Transfer to hotkey account, and check if the result is ok - assert_ok!(SubtensorModule::add_stake(<::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, 10000)); + // Check we have zero staked before transfer + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + 0 + ); - // Check if stake has increased - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), 10000); + // Also total stake should be zero + assert_eq!(SubtensorModule::get_total_stake(), 0); - // Check if balance has decreased - assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), 0); + // Transfer to hotkey account, and check if the result is ok + assert_ok!(SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(coldkey_account_id), + hotkey_account_id, + 10000 + )); + + // Check if stake has increased + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + 10000 + ); - // Check if total stake has increased accordingly. - assert_eq!(SubtensorModule::get_total_stake(), 10000); + // Check if balance has decreased + assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), 0); - }); + // Check if total stake has increased accordingly. + assert_eq!(SubtensorModule::get_total_stake(), 10000); + }); } #[test] fn test_dividends_with_run_to_block() { - new_test_ext().execute_with(|| { - let neuron_src_hotkey_id = U256::from(1); - let neuron_dest_hotkey_id = U256::from(2); - let coldkey_account_id = U256::from(667); - let netuid: u16 = 1; + new_test_ext().execute_with(|| { + let neuron_src_hotkey_id = U256::from(1); + let neuron_dest_hotkey_id = U256::from(2); + let coldkey_account_id = U256::from(667); + let netuid: u16 = 1; - let initial_stake:u64 = 5000; + let initial_stake: u64 = 5000; - //add network - add_network(netuid, 13, 0); + //add network + add_network(netuid, 13, 0); - // Register neuron, this will set a self weight - SubtensorModule::set_max_registrations_per_block( netuid, 3 ); - SubtensorModule::set_max_allowed_uids(1, 5); - - register_ok_neuron( netuid, U256::from(0), coldkey_account_id, 2112321); - register_ok_neuron(netuid, neuron_src_hotkey_id, coldkey_account_id, 192213123); - register_ok_neuron(netuid, neuron_dest_hotkey_id, coldkey_account_id, 12323); + // Register neuron, this will set a self weight + SubtensorModule::set_max_registrations_per_block(netuid, 3); + SubtensorModule::set_max_allowed_uids(1, 5); - // Add some stake to the hotkey account, so we can test for emission before the transfer takes place - SubtensorModule::increase_stake_on_hotkey_account(&neuron_src_hotkey_id, initial_stake); + register_ok_neuron(netuid, U256::from(0), coldkey_account_id, 2112321); + register_ok_neuron(netuid, neuron_src_hotkey_id, coldkey_account_id, 192213123); + register_ok_neuron(netuid, neuron_dest_hotkey_id, coldkey_account_id, 12323); - // Check if the initial stake has arrived - assert_eq!( SubtensorModule::get_total_stake_for_hotkey(&neuron_src_hotkey_id), initial_stake ); + // Add some stake to the hotkey account, so we can test for emission before the transfer takes place + SubtensorModule::increase_stake_on_hotkey_account(&neuron_src_hotkey_id, initial_stake); - // Check if all three neurons are registered - assert_eq!( SubtensorModule::get_subnetwork_n(netuid), 3 ); + // Check if the initial stake has arrived + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&neuron_src_hotkey_id), + initial_stake + ); - // Run a couple of blocks to check if emission works - run_to_block( 2 ); + // Check if all three neurons are registered + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 3); - // Check if the stake is equal to the inital stake + transfer - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&neuron_src_hotkey_id), initial_stake); + // Run a couple of blocks to check if emission works + run_to_block(2); + + // Check if the stake is equal to the inital stake + transfer + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&neuron_src_hotkey_id), + initial_stake + ); - // Check if the stake is equal to the inital stake + transfer - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&neuron_dest_hotkey_id), 0); + // Check if the stake is equal to the inital stake + transfer + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&neuron_dest_hotkey_id), + 0 + ); }); } #[test] fn test_add_stake_err_signature() { - new_test_ext().execute_with(|| { - let hotkey_account_id = U256::from(654); // bogus - let amount = 20000 ; // Not used - - let result = SubtensorModule::add_stake(<::RuntimeOrigin>::none(), hotkey_account_id, amount); - assert_eq!(result, DispatchError::BadOrigin.into()); - }); + new_test_ext().execute_with(|| { + let hotkey_account_id = U256::from(654); // bogus + let amount = 20000; // Not used + + let result = SubtensorModule::add_stake( + <::RuntimeOrigin>::none(), + hotkey_account_id, + amount, + ); + assert_eq!(result, DispatchError::BadOrigin.into()); + }); } #[test] fn test_add_stake_not_registered_key_pair() { - new_test_ext().execute_with(|| { - let coldkey_account_id = U256::from(435445); - let hotkey_account_id = U256::from(54544); - let amount = 1337; - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 1800); - assert_eq!(SubtensorModule::add_stake(<::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, amount), Err(Error::::NotRegistered.into())); - }); + new_test_ext().execute_with(|| { + let coldkey_account_id = U256::from(435445); + let hotkey_account_id = U256::from(54544); + let amount = 1337; + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 1800); + assert_eq!( + SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(coldkey_account_id), + hotkey_account_id, + amount + ), + Err(Error::::NotRegistered.into()) + ); + }); } #[test] fn test_add_stake_err_neuron_does_not_belong_to_coldkey() { - new_test_ext().execute_with(|| { - let coldkey_id = U256::from(544); - let hotkey_id = U256::from(54544); - let other_cold_key = U256::from(99498); + new_test_ext().execute_with(|| { + let coldkey_id = U256::from(544); + let hotkey_id = U256::from(54544); + let other_cold_key = U256::from(99498); let netuid: u16 = 1; - let tempo: u16 = 13; - let start_nonce : u64 = 0; - - //add network - add_network(netuid, tempo, 0); - - register_ok_neuron( netuid, hotkey_id, coldkey_id, start_nonce); - // Give it some $$$ in his coldkey balance - SubtensorModule::add_balance_to_coldkey_account( &other_cold_key, 100000 ); - - // Perform the request which is signed by a different cold key - let result = SubtensorModule::add_stake(<::RuntimeOrigin>::signed(other_cold_key), hotkey_id, 1000); - assert_eq!(result, Err(Error::::NonAssociatedColdKey.into())); - }); + let tempo: u16 = 13; + let start_nonce: u64 = 0; + + //add network + add_network(netuid, tempo, 0); + + register_ok_neuron(netuid, hotkey_id, coldkey_id, start_nonce); + // Give it some $$$ in his coldkey balance + SubtensorModule::add_balance_to_coldkey_account(&other_cold_key, 100000); + + // Perform the request which is signed by a different cold key + let result = SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(other_cold_key), + hotkey_id, + 1000, + ); + assert_eq!(result, Err(Error::::NonAssociatedColdKey.into())); + }); } #[test] fn test_add_stake_err_not_enough_belance() { - new_test_ext().execute_with(|| { - let coldkey_id = U256::from(544); - let hotkey_id = U256::from(54544); + new_test_ext().execute_with(|| { + let coldkey_id = U256::from(544); + let hotkey_id = U256::from(54544); let netuid: u16 = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; + let tempo: u16 = 13; + let start_nonce: u64 = 0; - //add network - add_network(netuid, tempo, 0); - - register_ok_neuron( netuid, hotkey_id, coldkey_id, start_nonce); + //add network + add_network(netuid, tempo, 0); - // Lets try to stake with 0 balance in cold key account - assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_id), 0); - let result = SubtensorModule::add_stake(<::RuntimeOrigin>::signed(coldkey_id), hotkey_id, 60000); + register_ok_neuron(netuid, hotkey_id, coldkey_id, start_nonce); + + // Lets try to stake with 0 balance in cold key account + assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_id), 0); + let result = SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(coldkey_id), + hotkey_id, + 60000, + ); - assert_eq!(result, Err(Error::::NotEnoughBalanceToStake.into())); - }); + assert_eq!(result, Err(Error::::NotEnoughBalanceToStake.into())); + }); } #[test] #[ignore] fn test_add_stake_total_balance_no_change() { - // When we add stake, the total balance of the coldkey account should not change - // this is because the stake should be part of the coldkey account balance (reserved/locked) - new_test_ext().execute_with(|| { - let hotkey_account_id = U256::from(551337); - let coldkey_account_id = U256::from(51337); - let netuid : u16 = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; - - //add network - add_network(netuid, tempo, 0); - - // Register neuron - register_ok_neuron( netuid, hotkey_account_id, coldkey_account_id, start_nonce); - - // Give it some $$$ in his coldkey balance - let initial_balance = 10000; - SubtensorModule::add_balance_to_coldkey_account( &coldkey_account_id, initial_balance ); - - // Check we have zero staked before transfer - let initial_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id); - assert_eq!(initial_stake, 0); - - // Check total balance is equal to initial balance - let initial_total_balance = Balances::total_balance(&coldkey_account_id); - assert_eq!(initial_total_balance, initial_balance); - - // Also total stake should be zero - assert_eq!(SubtensorModule::get_total_stake(), 0); - - // Stake to hotkey account, and check if the result is ok - assert_ok!(SubtensorModule::add_stake(<::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, 10000)); - - // Check if stake has increased - let new_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id); - assert_eq!(new_stake, 10000); - - // Check if free balance has decreased - let new_free_balance = SubtensorModule::get_coldkey_balance(&coldkey_account_id); - assert_eq!(new_free_balance, 0); - - // Check if total stake has increased accordingly. - assert_eq!(SubtensorModule::get_total_stake(), 10000); - - // Check if total balance has remained the same. (no fee, includes reserved/locked balance) - let total_balance = Balances::total_balance(&coldkey_account_id); - assert_eq!(total_balance, initial_total_balance); - }); + // When we add stake, the total balance of the coldkey account should not change + // this is because the stake should be part of the coldkey account balance (reserved/locked) + new_test_ext().execute_with(|| { + let hotkey_account_id = U256::from(551337); + let coldkey_account_id = U256::from(51337); + let netuid: u16 = 1; + let tempo: u16 = 13; + let start_nonce: u64 = 0; + + //add network + add_network(netuid, tempo, 0); + + // Register neuron + register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); + + // Give it some $$$ in his coldkey balance + let initial_balance = 10000; + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, initial_balance); + + // Check we have zero staked before transfer + let initial_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id); + assert_eq!(initial_stake, 0); + + // Check total balance is equal to initial balance + let initial_total_balance = Balances::total_balance(&coldkey_account_id); + assert_eq!(initial_total_balance, initial_balance); + + // Also total stake should be zero + assert_eq!(SubtensorModule::get_total_stake(), 0); + + // Stake to hotkey account, and check if the result is ok + assert_ok!(SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(coldkey_account_id), + hotkey_account_id, + 10000 + )); + + // Check if stake has increased + let new_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id); + assert_eq!(new_stake, 10000); + + // Check if free balance has decreased + let new_free_balance = SubtensorModule::get_coldkey_balance(&coldkey_account_id); + assert_eq!(new_free_balance, 0); + + // Check if total stake has increased accordingly. + assert_eq!(SubtensorModule::get_total_stake(), 10000); + + // Check if total balance has remained the same. (no fee, includes reserved/locked balance) + let total_balance = Balances::total_balance(&coldkey_account_id); + assert_eq!(total_balance, initial_total_balance); + }); } #[test] #[ignore] fn test_add_stake_total_issuance_no_change() { - // When we add stake, the total issuance of the balances pallet should not change - // this is because the stake should be part of the coldkey account balance (reserved/locked) - new_test_ext().execute_with(|| { - let hotkey_account_id = U256::from(561337); - let coldkey_account_id = U256::from(61337); - let netuid : u16 = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; - - //add network - add_network(netuid, tempo, 0); - - // Register neuron - register_ok_neuron( netuid, hotkey_account_id, coldkey_account_id, start_nonce); - - // Give it some $$$ in his coldkey balance - let initial_balance = 10000; - SubtensorModule::add_balance_to_coldkey_account( &coldkey_account_id, initial_balance ); - - // Check we have zero staked before transfer - let initial_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id); - assert_eq!(initial_stake, 0); - - // Check total balance is equal to initial balance - let initial_total_balance = Balances::total_balance(&coldkey_account_id); - assert_eq!(initial_total_balance, initial_balance); - - // Check total issuance is equal to initial balance - let initial_total_issuance = Balances::total_issuance(); - assert_eq!(initial_total_issuance, initial_balance); - - // Also total stake should be zero - assert_eq!(SubtensorModule::get_total_stake(), 0); - - // Stake to hotkey account, and check if the result is ok - assert_ok!(SubtensorModule::add_stake(<::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, 10000)); - - // Check if stake has increased - let new_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id); - assert_eq!(new_stake, 10000); - - // Check if free balance has decreased - let new_free_balance = SubtensorModule::get_coldkey_balance(&coldkey_account_id); - assert_eq!(new_free_balance, 0); - - // Check if total stake has increased accordingly. - assert_eq!(SubtensorModule::get_total_stake(), 10000); - - // Check if total issuance has remained the same. (no fee, includes reserved/locked balance) - let total_issuance = Balances::total_issuance(); - assert_eq!(total_issuance, initial_total_issuance); - }); + // When we add stake, the total issuance of the balances pallet should not change + // this is because the stake should be part of the coldkey account balance (reserved/locked) + new_test_ext().execute_with(|| { + let hotkey_account_id = U256::from(561337); + let coldkey_account_id = U256::from(61337); + let netuid: u16 = 1; + let tempo: u16 = 13; + let start_nonce: u64 = 0; + + //add network + add_network(netuid, tempo, 0); + + // Register neuron + register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); + + // Give it some $$$ in his coldkey balance + let initial_balance = 10000; + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, initial_balance); + + // Check we have zero staked before transfer + let initial_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id); + assert_eq!(initial_stake, 0); + + // Check total balance is equal to initial balance + let initial_total_balance = Balances::total_balance(&coldkey_account_id); + assert_eq!(initial_total_balance, initial_balance); + + // Check total issuance is equal to initial balance + let initial_total_issuance = Balances::total_issuance(); + assert_eq!(initial_total_issuance, initial_balance); + + // Also total stake should be zero + assert_eq!(SubtensorModule::get_total_stake(), 0); + + // Stake to hotkey account, and check if the result is ok + assert_ok!(SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(coldkey_account_id), + hotkey_account_id, + 10000 + )); + + // Check if stake has increased + let new_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id); + assert_eq!(new_stake, 10000); + + // Check if free balance has decreased + let new_free_balance = SubtensorModule::get_coldkey_balance(&coldkey_account_id); + assert_eq!(new_free_balance, 0); + + // Check if total stake has increased accordingly. + assert_eq!(SubtensorModule::get_total_stake(), 10000); + + // Check if total issuance has remained the same. (no fee, includes reserved/locked balance) + let total_issuance = Balances::total_issuance(); + assert_eq!(total_issuance, initial_total_issuance); + }); } // /*********************************************************** // staking::remove_stake() tests // ************************************************************/ - #[test] #[cfg(not(tarpaulin))] fn test_remove_stake_dispatch_info_ok() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let hotkey = U256::from(0); - let amount_unstaked = 5000; - let call = RuntimeCall::SubtensorModule(SubtensorCall::remove_stake{hotkey, amount_unstaked}); - assert_eq!(call.get_dispatch_info(), DispatchInfo { - weight: frame_support::weights::Weight::from_ref_time(63000000).add_proof_size(43991), - class: DispatchClass::Normal, - pays_fee: Pays::No - }); - }); + let amount_unstaked = 5000; + let call = RuntimeCall::SubtensorModule(SubtensorCall::remove_stake { + hotkey, + amount_unstaked, + }); + assert_eq!( + call.get_dispatch_info(), + DispatchInfo { + weight: frame_support::weights::Weight::from_ref_time(63000000) + .add_proof_size(43991), + class: DispatchClass::Normal, + pays_fee: Pays::No + } + ); + }); } #[test] fn test_remove_stake_ok_no_emission() { - new_test_ext().execute_with(|| { - let coldkey_account_id = U256::from(4343); - let hotkey_account_id = U256::from(4968585); - let amount = 10000; + new_test_ext().execute_with(|| { + let coldkey_account_id = U256::from(4343); + let hotkey_account_id = U256::from(4968585); + let amount = 10000; let netuid: u16 = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; - - //add network - add_network(netuid, tempo, 0); - - // Let's spin up a neuron - register_ok_neuron( netuid, hotkey_account_id, coldkey_account_id, start_nonce); - - // Some basic assertions - assert_eq!(SubtensorModule::get_total_stake(), 0); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), 0); - assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), 0); - - // Give the neuron some stake to remove - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_account_id, amount); - - // Do the magic - assert_ok!(SubtensorModule::remove_stake(<::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, amount)); - - assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), amount); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), 0); - assert_eq!(SubtensorModule::get_total_stake(), 0); - }); + let tempo: u16 = 13; + let start_nonce: u64 = 0; + + //add network + add_network(netuid, tempo, 0); + + // Let's spin up a neuron + register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); + + // Some basic assertions + assert_eq!(SubtensorModule::get_total_stake(), 0); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + 0 + ); + assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), 0); + + // Give the neuron some stake to remove + SubtensorModule::increase_stake_on_hotkey_account(&hotkey_account_id, amount); + + // Do the magic + assert_ok!(SubtensorModule::remove_stake( + <::RuntimeOrigin>::signed(coldkey_account_id), + hotkey_account_id, + amount + )); + + assert_eq!( + SubtensorModule::get_coldkey_balance(&coldkey_account_id), + amount + ); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + 0 + ); + assert_eq!(SubtensorModule::get_total_stake(), 0); + }); } #[test] fn test_remove_stake_amount_zero() { - new_test_ext().execute_with(|| { - let coldkey_account_id = U256::from(4343); - let hotkey_account_id = U256::from(4968585); - let amount = 10000; + new_test_ext().execute_with(|| { + let coldkey_account_id = U256::from(4343); + let hotkey_account_id = U256::from(4968585); + let amount = 10000; let netuid: u16 = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; - - //add network - add_network(netuid, tempo, 0); - - // Let's spin up a neuron - register_ok_neuron( netuid, hotkey_account_id, coldkey_account_id, start_nonce); - - // Some basic assertions - assert_eq!(SubtensorModule::get_total_stake(), 0); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), 0); - assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), 0); - - // Give the neuron some stake to remove - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_account_id, amount); - - // Do the magic - assert_noop!( - SubtensorModule::remove_stake(<::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, 0), + let tempo: u16 = 13; + let start_nonce: u64 = 0; + + //add network + add_network(netuid, tempo, 0); + + // Let's spin up a neuron + register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); + + // Some basic assertions + assert_eq!(SubtensorModule::get_total_stake(), 0); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + 0 + ); + assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), 0); + + // Give the neuron some stake to remove + SubtensorModule::increase_stake_on_hotkey_account(&hotkey_account_id, amount); + + // Do the magic + assert_noop!( + SubtensorModule::remove_stake( + <::RuntimeOrigin>::signed(coldkey_account_id), + hotkey_account_id, + 0 + ), Error::::NotEnoughStaketoWithdraw ); - }); + }); } #[test] fn test_remove_stake_err_signature() { - new_test_ext().execute_with(|| { - let hotkey_account_id = U256::from(4968585); - let amount = 10000; // Amount to be removed - - let result = SubtensorModule::remove_stake(<::RuntimeOrigin>::none(), hotkey_account_id, amount); - assert_eq!(result, DispatchError::BadOrigin.into()); - }); + new_test_ext().execute_with(|| { + let hotkey_account_id = U256::from(4968585); + let amount = 10000; // Amount to be removed + + let result = SubtensorModule::remove_stake( + <::RuntimeOrigin>::none(), + hotkey_account_id, + amount, + ); + assert_eq!(result, DispatchError::BadOrigin.into()); + }); } #[test] fn test_remove_stake_err_hotkey_does_not_belong_to_coldkey() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let coldkey_id = U256::from(544); - let hotkey_id = U256::from(54544); - let other_cold_key = U256::from(99498); + let hotkey_id = U256::from(54544); + let other_cold_key = U256::from(99498); let netuid: u16 = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; - - //add network - add_network(netuid, tempo, 0); - - register_ok_neuron( netuid, hotkey_id, coldkey_id, start_nonce); - - // Perform the request which is signed by a different cold key - let result = SubtensorModule::remove_stake(<::RuntimeOrigin>::signed(other_cold_key), hotkey_id, 1000); - assert_eq!(result, Err(Error::::NonAssociatedColdKey.into())); - }); + let tempo: u16 = 13; + let start_nonce: u64 = 0; + + //add network + add_network(netuid, tempo, 0); + + register_ok_neuron(netuid, hotkey_id, coldkey_id, start_nonce); + + // Perform the request which is signed by a different cold key + let result = SubtensorModule::remove_stake( + <::RuntimeOrigin>::signed(other_cold_key), + hotkey_id, + 1000, + ); + assert_eq!(result, Err(Error::::NonAssociatedColdKey.into())); + }); } #[test] fn test_remove_stake_no_enough_stake() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let coldkey_id = U256::from(544); - let hotkey_id = U256::from(54544); - let amount = 10000; + let hotkey_id = U256::from(54544); + let amount = 10000; let netuid: u16 = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; + let tempo: u16 = 13; + let start_nonce: u64 = 0; + + //add network + add_network(netuid, tempo, 0); - //add network - add_network(netuid, tempo, 0); - - register_ok_neuron( netuid, hotkey_id, coldkey_id, start_nonce); + register_ok_neuron(netuid, hotkey_id, coldkey_id, start_nonce); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), 0); + assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), 0); - let result = SubtensorModule::remove_stake(<::RuntimeOrigin>::signed(coldkey_id), hotkey_id, amount); - assert_eq!(result, Err(Error::::NotEnoughStaketoWithdraw.into())); - }); + let result = SubtensorModule::remove_stake( + <::RuntimeOrigin>::signed(coldkey_id), + hotkey_id, + amount, + ); + assert_eq!(result, Err(Error::::NotEnoughStaketoWithdraw.into())); + }); } #[test] fn test_remove_stake_total_balance_no_change() { - // When we remove stake, the total balance of the coldkey account should not change - // this is because the stake should be part of the coldkey account balance (reserved/locked) - // then the removed stake just becomes free balance - new_test_ext().execute_with(|| { - let hotkey_account_id = U256::from(571337); - let coldkey_account_id = U256::from(71337); - let netuid : u16 = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; - let amount = 10000; - - //add network - add_network(netuid, tempo, 0); - - // Register neuron - register_ok_neuron( netuid, hotkey_account_id, coldkey_account_id, start_nonce); - - // Some basic assertions - assert_eq!(SubtensorModule::get_total_stake(), 0); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), 0); - assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), 0); - let initial_total_balance = Balances::total_balance(&coldkey_account_id); - assert_eq!(initial_total_balance, 0); - - // Give the neuron some stake to remove - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_account_id, amount); - - // Do the magic - assert_ok!(SubtensorModule::remove_stake(<::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, amount)); - - assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), amount); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), 0); - assert_eq!(SubtensorModule::get_total_stake(), 0); - - // Check total balance is equal to the added stake. Even after remove stake (no fee, includes reserved/locked balance) - let total_balance = Balances::total_balance(&coldkey_account_id); - assert_eq!(total_balance, amount); - }); + // When we remove stake, the total balance of the coldkey account should not change + // this is because the stake should be part of the coldkey account balance (reserved/locked) + // then the removed stake just becomes free balance + new_test_ext().execute_with(|| { + let hotkey_account_id = U256::from(571337); + let coldkey_account_id = U256::from(71337); + let netuid: u16 = 1; + let tempo: u16 = 13; + let start_nonce: u64 = 0; + let amount = 10000; + + //add network + add_network(netuid, tempo, 0); + + // Register neuron + register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); + + // Some basic assertions + assert_eq!(SubtensorModule::get_total_stake(), 0); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + 0 + ); + assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), 0); + let initial_total_balance = Balances::total_balance(&coldkey_account_id); + assert_eq!(initial_total_balance, 0); + + // Give the neuron some stake to remove + SubtensorModule::increase_stake_on_hotkey_account(&hotkey_account_id, amount); + + // Do the magic + assert_ok!(SubtensorModule::remove_stake( + <::RuntimeOrigin>::signed(coldkey_account_id), + hotkey_account_id, + amount + )); + + assert_eq!( + SubtensorModule::get_coldkey_balance(&coldkey_account_id), + amount + ); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + 0 + ); + assert_eq!(SubtensorModule::get_total_stake(), 0); + + // Check total balance is equal to the added stake. Even after remove stake (no fee, includes reserved/locked balance) + let total_balance = Balances::total_balance(&coldkey_account_id); + assert_eq!(total_balance, amount); + }); } #[test] #[ignore] fn test_remove_stake_total_issuance_no_change() { - // When we remove stake, the total issuance of the balances pallet should not change - // this is because the stake should be part of the coldkey account balance (reserved/locked) - // then the removed stake just becomes free balance - new_test_ext().execute_with(|| { - let hotkey_account_id = U256::from(581337); - let coldkey_account_id = U256::from(81337); - let netuid : u16 = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; - let amount = 10000; - - //add network - add_network(netuid, tempo, 0); - - // Register neuron - register_ok_neuron( netuid, hotkey_account_id, coldkey_account_id, start_nonce); - - // Some basic assertions - assert_eq!(SubtensorModule::get_total_stake(), 0); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), 0); - assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), 0); - let initial_total_balance = Balances::total_balance(&coldkey_account_id); - assert_eq!(initial_total_balance, 0); - let inital_total_issuance = Balances::total_issuance(); - assert_eq!(inital_total_issuance, 0); - - // Give the neuron some stake to remove - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_account_id, amount); - - let total_issuance_after_stake = Balances::total_issuance(); - - // Do the magic - assert_ok!(SubtensorModule::remove_stake(<::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, amount)); - - assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), amount); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), 0); - assert_eq!(SubtensorModule::get_total_stake(), 0); - - // Check if total issuance is equal to the added stake, even after remove stake (no fee, includes reserved/locked balance) - // Should also be equal to the total issuance after adding stake - let total_issuance = Balances::total_issuance(); - assert_eq!(total_issuance, total_issuance_after_stake); - assert_eq!(total_issuance, amount); - }); + // When we remove stake, the total issuance of the balances pallet should not change + // this is because the stake should be part of the coldkey account balance (reserved/locked) + // then the removed stake just becomes free balance + new_test_ext().execute_with(|| { + let hotkey_account_id = U256::from(581337); + let coldkey_account_id = U256::from(81337); + let netuid: u16 = 1; + let tempo: u16 = 13; + let start_nonce: u64 = 0; + let amount = 10000; + + //add network + add_network(netuid, tempo, 0); + + // Register neuron + register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); + + // Some basic assertions + assert_eq!(SubtensorModule::get_total_stake(), 0); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + 0 + ); + assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), 0); + let initial_total_balance = Balances::total_balance(&coldkey_account_id); + assert_eq!(initial_total_balance, 0); + let inital_total_issuance = Balances::total_issuance(); + assert_eq!(inital_total_issuance, 0); + + // Give the neuron some stake to remove + SubtensorModule::increase_stake_on_hotkey_account(&hotkey_account_id, amount); + + let total_issuance_after_stake = Balances::total_issuance(); + + // Do the magic + assert_ok!(SubtensorModule::remove_stake( + <::RuntimeOrigin>::signed(coldkey_account_id), + hotkey_account_id, + amount + )); + + assert_eq!( + SubtensorModule::get_coldkey_balance(&coldkey_account_id), + amount + ); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + 0 + ); + assert_eq!(SubtensorModule::get_total_stake(), 0); + + // Check if total issuance is equal to the added stake, even after remove stake (no fee, includes reserved/locked balance) + // Should also be equal to the total issuance after adding stake + let total_issuance = Balances::total_issuance(); + assert_eq!(total_issuance, total_issuance_after_stake); + assert_eq!(total_issuance, amount); + }); } /*********************************************************** - staking::get_coldkey_balance() tests + staking::get_coldkey_balance() tests ************************************************************/ #[test] fn test_get_coldkey_balance_no_balance() { - new_test_ext().execute_with(|| { - let coldkey_account_id = U256::from(5454); // arbitrary - let result = SubtensorModule::get_coldkey_balance(&coldkey_account_id); - - // Arbitrary account should have 0 balance - assert_eq!(result, 0); + new_test_ext().execute_with(|| { + let coldkey_account_id = U256::from(5454); // arbitrary + let result = SubtensorModule::get_coldkey_balance(&coldkey_account_id); - }); + // Arbitrary account should have 0 balance + assert_eq!(result, 0); + }); } #[test] fn test_get_coldkey_balance_with_balance() { - new_test_ext().execute_with(|| { - let coldkey_account_id = U256::from(5454); // arbitrary - let amount = 1337; - - // Put the balance on the account - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, amount); + new_test_ext().execute_with(|| { + let coldkey_account_id = U256::from(5454); // arbitrary + let amount = 1337; - let result = SubtensorModule::get_coldkey_balance(&coldkey_account_id); + // Put the balance on the account + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, amount); - // Arbitrary account should have 0 balance - assert_eq!(result, amount); + let result = SubtensorModule::get_coldkey_balance(&coldkey_account_id); - }); + // Arbitrary account should have 0 balance + assert_eq!(result, amount); + }); } // /*********************************************************** @@ -548,123 +661,140 @@ fn test_get_coldkey_balance_with_balance() { // ************************************************************/ #[test] fn test_add_stake_to_hotkey_account_ok() { - new_test_ext().execute_with(|| { - let hotkey_id = U256::from(5445); - let coldkey_id = U256::from(5443433); - let amount: u64 = 10000; + new_test_ext().execute_with(|| { + let hotkey_id = U256::from(5445); + let coldkey_id = U256::from(5443433); + let amount: u64 = 10000; let netuid: u16 = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; + let tempo: u16 = 13; + let start_nonce: u64 = 0; - //add network - add_network(netuid, tempo, 0); - - register_ok_neuron( netuid, hotkey_id, coldkey_id, start_nonce); + //add network + add_network(netuid, tempo, 0); - // There is not stake in the system at first, so result should be 0; - assert_eq!(SubtensorModule::get_total_stake(), 0); + register_ok_neuron(netuid, hotkey_id, coldkey_id, start_nonce); - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_id, amount); + // There is not stake in the system at first, so result should be 0; + assert_eq!(SubtensorModule::get_total_stake(), 0); - // The stake that is now in the account, should equal the amount - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), amount); + SubtensorModule::increase_stake_on_hotkey_account(&hotkey_id, amount); + + // The stake that is now in the account, should equal the amount + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), + amount + ); - // The total stake should have been increased by the amount -> 0 + amount = amount - assert_eq!(SubtensorModule::get_total_stake(), amount); - }); + // The total stake should have been increased by the amount -> 0 + amount = amount + assert_eq!(SubtensorModule::get_total_stake(), amount); + }); } /************************************************************ - staking::remove_stake_from_hotkey_account() tests + staking::remove_stake_from_hotkey_account() tests ************************************************************/ #[test] fn test_remove_stake_from_hotkey_account() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let hotkey_id = U256::from(5445); - let coldkey_id = U256::from(5443433); - let amount: u64 = 10000; + let coldkey_id = U256::from(5443433); + let amount: u64 = 10000; let netuid: u16 = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; + let tempo: u16 = 13; + let start_nonce: u64 = 0; + + //add network + add_network(netuid, tempo, 0); - //add network - add_network(netuid, tempo, 0); - - register_ok_neuron( netuid, hotkey_id, coldkey_id, start_nonce); + register_ok_neuron(netuid, hotkey_id, coldkey_id, start_nonce); - // Add some stake that can be removed - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_id, amount); + // Add some stake that can be removed + SubtensorModule::increase_stake_on_hotkey_account(&hotkey_id, amount); - // Prelimiary checks - assert_eq!(SubtensorModule::get_total_stake(), amount); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), amount); + // Prelimiary checks + assert_eq!(SubtensorModule::get_total_stake(), amount); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), + amount + ); - // Remove stake - SubtensorModule::decrease_stake_on_hotkey_account(&hotkey_id, amount); + // Remove stake + SubtensorModule::decrease_stake_on_hotkey_account(&hotkey_id, amount); - // The stake on the hotkey account should be 0 - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), 0); + // The stake on the hotkey account should be 0 + assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), 0); - // The total amount of stake should be 0 - assert_eq!(SubtensorModule::get_total_stake(), 0); - }); + // The total amount of stake should be 0 + assert_eq!(SubtensorModule::get_total_stake(), 0); + }); } #[test] fn test_remove_stake_from_hotkey_account_registered_in_various_networks() { - new_test_ext().execute_with(|| { - let hotkey_id = U256::from(5445); - let coldkey_id = U256::from(5443433); - let amount: u64 = 10000; + new_test_ext().execute_with(|| { + let hotkey_id = U256::from(5445); + let coldkey_id = U256::from(5443433); + let amount: u64 = 10000; let netuid: u16 = 1; - let netuid_ex = 2; - let tempo: u16 = 13; - let start_nonce: u64 = 0; - // - add_network(netuid, tempo, 0); - add_network(netuid_ex, tempo, 0); - // - register_ok_neuron( netuid, hotkey_id, coldkey_id, start_nonce); - register_ok_neuron( netuid_ex, hotkey_id, coldkey_id, 48141209); - - //let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_id); - let neuron_uid ; + let netuid_ex = 2; + let tempo: u16 = 13; + let start_nonce: u64 = 0; + // + add_network(netuid, tempo, 0); + add_network(netuid_ex, tempo, 0); + // + register_ok_neuron(netuid, hotkey_id, coldkey_id, start_nonce); + register_ok_neuron(netuid_ex, hotkey_id, coldkey_id, 48141209); + + //let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_id); + let neuron_uid; match SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_id) { Ok(k) => neuron_uid = k, Err(e) => panic!("Error: {:?}", e), - } - //let neuron_uid_ex = SubtensorModule::get_uid_for_net_and_hotkey(netuid_ex, &hotkey_id); - let neuron_uid_ex ; + } + //let neuron_uid_ex = SubtensorModule::get_uid_for_net_and_hotkey(netuid_ex, &hotkey_id); + let neuron_uid_ex; match SubtensorModule::get_uid_for_net_and_hotkey(netuid_ex, &hotkey_id) { Ok(k) => neuron_uid_ex = k, Err(e) => panic!("Error: {:?}", e), - } - //Add some stake that can be removed - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_id, amount); - - assert_eq!(SubtensorModule::get_stake_for_uid_and_subnetwork(netuid, neuron_uid), amount); - assert_eq!(SubtensorModule::get_stake_for_uid_and_subnetwork(netuid_ex, neuron_uid_ex), amount); - - // Remove stake - SubtensorModule::decrease_stake_on_hotkey_account(&hotkey_id, amount); - // - assert_eq!(SubtensorModule::get_stake_for_uid_and_subnetwork(netuid, neuron_uid), 0); - assert_eq!(SubtensorModule::get_stake_for_uid_and_subnetwork(netuid_ex, neuron_uid_ex), 0); - }); -} + } + //Add some stake that can be removed + SubtensorModule::increase_stake_on_hotkey_account(&hotkey_id, amount); + + assert_eq!( + SubtensorModule::get_stake_for_uid_and_subnetwork(netuid, neuron_uid), + amount + ); + assert_eq!( + SubtensorModule::get_stake_for_uid_and_subnetwork(netuid_ex, neuron_uid_ex), + amount + ); + // Remove stake + SubtensorModule::decrease_stake_on_hotkey_account(&hotkey_id, amount); + // + assert_eq!( + SubtensorModule::get_stake_for_uid_and_subnetwork(netuid, neuron_uid), + 0 + ); + assert_eq!( + SubtensorModule::get_stake_for_uid_and_subnetwork(netuid_ex, neuron_uid_ex), + 0 + ); + }); +} // /************************************************************ // staking::increase_total_stake() tests // ************************************************************/ #[test] fn test_increase_total_stake_ok() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let increment = 10000; assert_eq!(SubtensorModule::get_total_stake(), 0); - SubtensorModule::increase_total_stake(increment); - assert_eq!(SubtensorModule::get_total_stake(), increment); - }); + SubtensorModule::increase_total_stake(increment); + assert_eq!(SubtensorModule::get_total_stake(), increment); + }); } // /************************************************************ @@ -672,16 +802,19 @@ fn test_increase_total_stake_ok() { // ************************************************************/ #[test] fn test_decrease_total_stake_ok() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let initial_total_stake = 10000; - let decrement = 5000; + let decrement = 5000; - SubtensorModule::increase_total_stake(initial_total_stake); - SubtensorModule::decrease_total_stake(decrement); + SubtensorModule::increase_total_stake(initial_total_stake); + SubtensorModule::decrease_total_stake(decrement); - // The total stake remaining should be the difference between the initial stake and the decrement - assert_eq!(SubtensorModule::get_total_stake(), initial_total_stake - decrement); - }); + // The total stake remaining should be the difference between the initial stake and the decrement + assert_eq!( + SubtensorModule::get_total_stake(), + initial_total_stake - decrement + ); + }); } // /************************************************************ @@ -689,12 +822,12 @@ fn test_decrease_total_stake_ok() { // ************************************************************/ #[test] fn test_add_balance_to_coldkey_account_ok() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let coldkey_id = U256::from(4444322); - let amount = 50000; - SubtensorModule::add_balance_to_coldkey_account(&coldkey_id, amount); - assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_id), amount); - }); + let amount = 50000; + SubtensorModule::add_balance_to_coldkey_account(&coldkey_id, amount); + assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_id), amount); + }); } // /*********************************************************** @@ -702,29 +835,34 @@ fn test_add_balance_to_coldkey_account_ok() { // ************************************************************/ #[test] fn test_remove_balance_from_coldkey_account_ok() { - new_test_ext().execute_with(|| { - let coldkey_account_id = U256::from(434324); // Random - let ammount = 10000; // Arbitrary - // Put some $$ on the bank - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, ammount); - assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), ammount); - // Should be able to withdraw without hassle - let result = SubtensorModule::remove_balance_from_coldkey_account(&coldkey_account_id, ammount); - assert_eq!(result, true); - }); + new_test_ext().execute_with(|| { + let coldkey_account_id = U256::from(434324); // Random + let ammount = 10000; // Arbitrary + // Put some $$ on the bank + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, ammount); + assert_eq!( + SubtensorModule::get_coldkey_balance(&coldkey_account_id), + ammount + ); + // Should be able to withdraw without hassle + let result = + SubtensorModule::remove_balance_from_coldkey_account(&coldkey_account_id, ammount); + assert_eq!(result, true); + }); } #[test] fn test_remove_balance_from_coldkey_account_failed() { - new_test_ext().execute_with(|| { - let coldkey_account_id = U256::from(434324); // Random - let ammount = 10000; // Arbitrary - - // Try to remove stake from the coldkey account. This should fail, - // as there is no balance, nor does the account exist - let result = SubtensorModule::remove_balance_from_coldkey_account(&coldkey_account_id, ammount); - assert_eq!(result, false); - }); + new_test_ext().execute_with(|| { + let coldkey_account_id = U256::from(434324); // Random + let ammount = 10000; // Arbitrary + + // Try to remove stake from the coldkey account. This should fail, + // as there is no balance, nor does the account exist + let result = + SubtensorModule::remove_balance_from_coldkey_account(&coldkey_account_id, ammount); + assert_eq!(result, false); + }); } //************************************************************ @@ -732,648 +870,1341 @@ fn test_remove_balance_from_coldkey_account_failed() { // ************************************************************/ #[test] fn test_hotkey_belongs_to_coldkey_ok() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let hotkey_id = U256::from(4434334); - let coldkey_id = U256::from(34333); + let coldkey_id = U256::from(34333); let netuid: u16 = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; - add_network(netuid, tempo, 0); - register_ok_neuron( netuid, hotkey_id, coldkey_id, start_nonce); - assert_eq!(SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey_id), coldkey_id); - }); + let tempo: u16 = 13; + let start_nonce: u64 = 0; + add_network(netuid, tempo, 0); + register_ok_neuron(netuid, hotkey_id, coldkey_id, start_nonce); + assert_eq!( + SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey_id), + coldkey_id + ); + }); } // /************************************************************ // staking::can_remove_balance_from_coldkey_account() tests // ************************************************************/ #[test] fn test_can_remove_balane_from_coldkey_account_ok() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let coldkey_id = U256::from(87987984); - let initial_amount = 10000; - let remove_amount = 5000; - SubtensorModule::add_balance_to_coldkey_account(&coldkey_id, initial_amount); - assert_eq!(SubtensorModule::can_remove_balance_from_coldkey_account(&coldkey_id, remove_amount), true); - }); + let initial_amount = 10000; + let remove_amount = 5000; + SubtensorModule::add_balance_to_coldkey_account(&coldkey_id, initial_amount); + assert_eq!( + SubtensorModule::can_remove_balance_from_coldkey_account(&coldkey_id, remove_amount), + true + ); + }); } #[test] fn test_can_remove_balance_from_coldkey_account_err_insufficient_balance() { - new_test_ext().execute_with(|| { - let coldkey_id = U256::from(87987984); - let initial_amount = 10000; - let remove_amount = 20000; - SubtensorModule::add_balance_to_coldkey_account(&coldkey_id, initial_amount); - assert_eq!(SubtensorModule::can_remove_balance_from_coldkey_account(&coldkey_id, remove_amount), false); - }); + new_test_ext().execute_with(|| { + let coldkey_id = U256::from(87987984); + let initial_amount = 10000; + let remove_amount = 20000; + SubtensorModule::add_balance_to_coldkey_account(&coldkey_id, initial_amount); + assert_eq!( + SubtensorModule::can_remove_balance_from_coldkey_account(&coldkey_id, remove_amount), + false + ); + }); } /************************************************************ - staking::has_enough_stake() tests + staking::has_enough_stake() tests ************************************************************/ #[test] fn test_has_enough_stake_yes() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let hotkey_id = U256::from(4334); - let coldkey_id = U256::from(87989); - let intial_amount = 10000; + let coldkey_id = U256::from(87989); + let intial_amount = 10000; let netuid = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; - add_network(netuid, tempo, 0); - register_ok_neuron( netuid, hotkey_id, coldkey_id, start_nonce); - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_id, intial_amount); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), 10000); - assert_eq!(SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey_id, &hotkey_id), 10000); - assert_eq!(SubtensorModule::has_enough_stake(&coldkey_id, &hotkey_id, 5000), true); - }); + let tempo: u16 = 13; + let start_nonce: u64 = 0; + add_network(netuid, tempo, 0); + register_ok_neuron(netuid, hotkey_id, coldkey_id, start_nonce); + SubtensorModule::increase_stake_on_hotkey_account(&hotkey_id, intial_amount); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), + 10000 + ); + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey_id, &hotkey_id), + 10000 + ); + assert_eq!( + SubtensorModule::has_enough_stake(&coldkey_id, &hotkey_id, 5000), + true + ); + }); } #[test] fn test_has_enough_stake_no() { - new_test_ext().execute_with(|| { - let hotkey_id = U256::from(4334); - let coldkey_id = U256::from(87989); - let intial_amount = 0; + new_test_ext().execute_with(|| { + let hotkey_id = U256::from(4334); + let coldkey_id = U256::from(87989); + let intial_amount = 0; let netuid = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; - add_network(netuid, tempo, 0); - register_ok_neuron( netuid, hotkey_id, coldkey_id, start_nonce); - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_id, intial_amount); - assert_eq!(SubtensorModule::has_enough_stake(&coldkey_id, &hotkey_id, 5000), false); - - }); + let tempo: u16 = 13; + let start_nonce: u64 = 0; + add_network(netuid, tempo, 0); + register_ok_neuron(netuid, hotkey_id, coldkey_id, start_nonce); + SubtensorModule::increase_stake_on_hotkey_account(&hotkey_id, intial_amount); + assert_eq!( + SubtensorModule::has_enough_stake(&coldkey_id, &hotkey_id, 5000), + false + ); + }); } #[test] fn test_non_existent_account() { - new_test_ext().execute_with(|| { - SubtensorModule::increase_stake_on_coldkey_hotkey_account( &U256::from(0), &(U256::from(0)), 10 ); - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &U256::from(0), &U256::from(0) ), 10 ); - assert_eq!(SubtensorModule::get_total_stake_for_coldkey(&(U256::from(0))), 10); - }); + new_test_ext().execute_with(|| { + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &U256::from(0), + &(U256::from(0)), + 10, + ); + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&U256::from(0), &U256::from(0)), + 10 + ); + assert_eq!( + SubtensorModule::get_total_stake_for_coldkey(&(U256::from(0))), + 10 + ); + }); } /************************************************************ - staking::delegating + staking::delegating ************************************************************/ #[test] -fn test_delegate_stake_division_by_zero_check(){ - new_test_ext().execute_with(|| { +fn test_delegate_stake_division_by_zero_check() { + new_test_ext().execute_with(|| { let netuid: u16 = 0; let tempo: u16 = 1; - let hotkey = U256::from(1); - let coldkey = U256::from(3); - add_network( netuid, tempo, 0 ); - register_ok_neuron( netuid, hotkey, coldkey, 2341312 ); - assert_ok!(SubtensorModule::become_delegate(<::RuntimeOrigin>::signed(coldkey), hotkey) ); - SubtensorModule::emit_inflation_through_hotkey_account( &hotkey, 0, 1000 ); + let hotkey = U256::from(1); + let coldkey = U256::from(3); + add_network(netuid, tempo, 0); + register_ok_neuron(netuid, hotkey, coldkey, 2341312); + assert_ok!(SubtensorModule::become_delegate( + <::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().execute_with(|| { - let netuid = 1; - // Make two accounts. + new_test_ext().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, 4); // Allow all 4 to be registered at once - - // 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::::NotRegistered.into())); - assert_eq!(SubtensorModule::add_stake(<::RuntimeOrigin>::signed(coldkey0), hotkey0, 100), Err(Error::::NotRegistered.into())); - - // Cant remove either. - assert_eq!(SubtensorModule::remove_stake(<::RuntimeOrigin>::signed(coldkey0), hotkey0, 10), Err(Error::::NotRegistered.into())); - assert_eq!(SubtensorModule::remove_stake(<::RuntimeOrigin>::signed(coldkey1), hotkey1, 10), Err(Error::::NotRegistered.into())); - assert_eq!(SubtensorModule::remove_stake(<::RuntimeOrigin>::signed(coldkey0), hotkey1, 10), Err(Error::::NotRegistered.into())); - assert_eq!(SubtensorModule::remove_stake(<::RuntimeOrigin>::signed(coldkey1), hotkey0, 10), Err(Error::::NotRegistered.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::::NotRegistered.into())); - assert_eq!(SubtensorModule::do_become_delegate(<::RuntimeOrigin>::signed(coldkey0), hotkey0, 100), Err(Error::::NotRegistered.into())); - - // 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 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::::NonAssociatedColdKey.into())); - assert_eq!(SubtensorModule::add_stake(<::RuntimeOrigin>::signed(coldkey1), hotkey0, 100), Err(Error::::NonAssociatedColdKey.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::::NonAssociatedColdKey.into())); - assert_eq!(SubtensorModule::remove_stake(<::RuntimeOrigin>::signed(coldkey1), hotkey0, 10), Err(Error::::NonAssociatedColdKey.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, 10) ); - assert_ok! (SubtensorModule::do_become_delegate(<::RuntimeOrigin>::signed(coldkey1), hotkey1, 10) ); - 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, 1000), Err(Error::::AlreadyDelegate.into())); - assert_eq!(SubtensorModule::do_become_delegate(<::RuntimeOrigin>::signed(coldkey1), hotkey1, 1000), Err(Error::::AlreadyDelegate.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 ); - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey0, &hotkey0 ), 601 ); // 200 + 1000 x ( 200 / 500 ) = 200 + 400 = 600 ~= 601 - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey0, &hotkey1 ), 700 ); // 200 + 1000 x ( 200 / 400 ) = 200 + 500 = 700 - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey1, &hotkey0 ), 899 ); // 300 + 1000 x ( 300 / 500 ) = 300 + 600 = 900 ~= 899 - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey1, &hotkey1 ), 700 ); // 200 + 1000 x ( 200 / 400 ) = 300 + 600 = 700 - assert_eq!( SubtensorModule::get_total_stake(), 2900 ); // 600 + 700 + 900 + 700 = 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 ), 501 ); - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey0, &hotkey1 ), 600 ); - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey1, &hotkey0 ), 799 ); - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey1, &hotkey1 ), 600 ); - - // 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::::NonAssociatedColdKey.into())); - assert_eq!(SubtensorModule::remove_stake(<::RuntimeOrigin>::signed(coldkey1), hotkey2, 10), Err(Error::::NonAssociatedColdKey.into())); - - // Lets make this new key a delegate with a 50% take. - assert_ok!( SubtensorModule::do_become_delegate(<::RuntimeOrigin>::signed(coldkey2), hotkey2, u16::MAX/2) ); - - // 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_668 ); // 1000 + 500 + 500 * (1000/3000) = 1500 + 166.6666666667 = 1,668 - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey1, &hotkey2 ), 1_166 ); // 1000 + 500 * (1000/3000) = 1000 + 166.6666666667 = 1166.6 - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey0, &hotkey2 ), 1_166 ); // 1000 + 500 * (1000/3000) = 1000 + 166.6666666667 = 1166.6 - 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, u16::MAX ) ); // 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 ), 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 ), 2000 ); - assert_eq!( SubtensorModule::get_total_stake(), 11_500 ); // before + 1_000 = 10_500 + 1_000 = 11_500 - - }); -} + let coldkey0 = U256::from(3); + let coldkey1 = U256::from(4); + SubtensorModule::set_max_registrations_per_block(netuid, 4); + SubtensorModule::set_max_allowed_uids(netuid, 4); // Allow all 4 to be registered at once + + // 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::::NotRegistered.into()) + ); + assert_eq!( + SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(coldkey0), + hotkey0, + 100 + ), + Err(Error::::NotRegistered.into()) + ); + + // Cant remove either. + assert_eq!( + SubtensorModule::remove_stake( + <::RuntimeOrigin>::signed(coldkey0), + hotkey0, + 10 + ), + Err(Error::::NotRegistered.into()) + ); + assert_eq!( + SubtensorModule::remove_stake( + <::RuntimeOrigin>::signed(coldkey1), + hotkey1, + 10 + ), + Err(Error::::NotRegistered.into()) + ); + assert_eq!( + SubtensorModule::remove_stake( + <::RuntimeOrigin>::signed(coldkey0), + hotkey1, + 10 + ), + Err(Error::::NotRegistered.into()) + ); + assert_eq!( + SubtensorModule::remove_stake( + <::RuntimeOrigin>::signed(coldkey1), + hotkey0, + 10 + ), + Err(Error::::NotRegistered.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::::NotRegistered.into()) + ); + assert_eq!( + SubtensorModule::do_become_delegate( + <::RuntimeOrigin>::signed(coldkey0), + hotkey0, + 100 + ), + Err(Error::::NotRegistered.into()) + ); + + // 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 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::::NonAssociatedColdKey.into()) + ); + assert_eq!( + SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(coldkey1), + hotkey0, + 100 + ), + Err(Error::::NonAssociatedColdKey.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::::NonAssociatedColdKey.into()) + ); + assert_eq!( + SubtensorModule::remove_stake( + <::RuntimeOrigin>::signed(coldkey1), + hotkey0, + 10 + ), + Err(Error::::NonAssociatedColdKey.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, + 10 + )); + assert_ok!(SubtensorModule::do_become_delegate( + <::RuntimeOrigin>::signed(coldkey1), + hotkey1, + 10 + )); + 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, + 1000 + ), + Err(Error::::AlreadyDelegate.into()) + ); + assert_eq!( + SubtensorModule::do_become_delegate( + <::RuntimeOrigin>::signed(coldkey1), + hotkey1, + 1000 + ), + Err(Error::::AlreadyDelegate.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); + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + 601 + ); // 200 + 1000 x ( 200 / 500 ) = 200 + 400 = 600 ~= 601 + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), + 700 + ); // 200 + 1000 x ( 200 / 400 ) = 200 + 500 = 700 + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), + 899 + ); // 300 + 1000 x ( 300 / 500 ) = 300 + 600 = 900 ~= 899 + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), + 700 + ); // 200 + 1000 x ( 200 / 400 ) = 300 + 600 = 700 + assert_eq!(SubtensorModule::get_total_stake(), 2900); // 600 + 700 + 900 + 700 = 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), + 501 + ); + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), + 600 + ); + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), + 799 + ); + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), + 600 + ); + + // 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::::NonAssociatedColdKey.into()) + ); + assert_eq!( + SubtensorModule::remove_stake( + <::RuntimeOrigin>::signed(coldkey1), + hotkey2, + 10 + ), + Err(Error::::NonAssociatedColdKey.into()) + ); + + // Lets make this new key a delegate with a 50% take. + assert_ok!(SubtensorModule::do_become_delegate( + <::RuntimeOrigin>::signed(coldkey2), + hotkey2, + u16::MAX / 2 + )); + + // 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_668 + ); // 1000 + 500 + 500 * (1000/3000) = 1500 + 166.6666666667 = 1,668 + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2), + 1_166 + ); // 1000 + 500 * (1000/3000) = 1000 + 166.6666666667 = 1166.6 + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2), + 1_166 + ); // 1000 + 500 * (1000/3000) = 1000 + 166.6666666667 = 1166.6 + 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, + u16::MAX + )); // 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), + 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), + 2000 + ); + 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().execute_with(|| { - let netuid = 1; - // Make two accounts. + new_test_ext().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 - - // 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, 10) ); - assert_ok! (SubtensorModule::do_become_delegate(<::RuntimeOrigin>::signed(coldkey1), hotkey1, 10) ); - 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 ), 801 ); // 200 + (200 + 1000 x ( 200 / 500 )) = 200 + (200 + 400) = 800 ~= 801 - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey1, &hotkey0 ), 899 ); // 300 + 1000 x ( 300 / 500 ) = 300 + 600 = 900 ~= 899 - 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_200 ); // 200 + (0 + 2000 x ( 200 / 400 )) = 200 + (1000) = 1_200 - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey1, &hotkey1 ), 1_323 ); // 200 + (123 + 2000 x ( 200 / 400 )) = 200 + (1_200) = 1_323 - assert_eq!( SubtensorModule::get_total_stake_for_hotkey( &hotkey1 ), 2_523 ); // 400 + 2_123 - assert_eq!( SubtensorModule::get_total_stake(), 4_223 ); // 1_700 + 2_523 = 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_151 ); // + 350 = 1_151 - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey0, &hotkey1 ), 1_200 ); // No change. - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey1, &hotkey0 ), 899 ); // No change. - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey1, &hotkey1 ), 1_473 ); // 1_323 + 150 = 1_473 - 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::::NonAssociatedColdKey.into())); - assert_eq!(SubtensorModule::remove_stake(<::RuntimeOrigin>::signed(coldkey1), hotkey2, 10), Err(Error::::NonAssociatedColdKey.into())); - - assert_eq!(SubtensorModule::get_total_stake(), 5_623 ); // 4_723 + 900 = 5_623 - - // Lets make this new key a delegate with a 50% take. - assert_ok!( SubtensorModule::do_become_delegate(<::RuntimeOrigin>::signed(coldkey2), hotkey2, u16::MAX/2) ); - - // 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_768 ); // 1000 + 100 + 500 + 500 * (1000/3000) = 100 + 1500 + 166.6666666667 ~= 1,768.6666666667 - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey1, &hotkey2 ), 1_166 ); // 1000 + 500 * (1000/3000) = 1000 + 166.6666666667 = 1166.6 - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey0, &hotkey2 ), 1_166 ); // 1000 + 500 * (1000/3000) = 1000 + 166.6666666667 = 1166.6 - 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_891 ); // 1_768 + 123 = 1_891 - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey1, &hotkey2 ), 1_166 ); // No change. - assert_eq!( SubtensorModule::get_stake_for_coldkey_and_hotkey( &coldkey0, &hotkey2 ), 1_166 ); // No change. - assert_eq!( SubtensorModule::get_total_stake(), 8_946 ); // 8_823 + 123 = 8_946 - }); -} + 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 + + // 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, + 10 + )); + assert_ok!(SubtensorModule::do_become_delegate( + <::RuntimeOrigin>::signed(coldkey1), + hotkey1, + 10 + )); + 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), + 801 + ); // 200 + (200 + 1000 x ( 200 / 500 )) = 200 + (200 + 400) = 800 ~= 801 + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), + 899 + ); // 300 + 1000 x ( 300 / 500 ) = 300 + 600 = 900 ~= 899 + 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_200 + ); // 200 + (0 + 2000 x ( 200 / 400 )) = 200 + (1000) = 1_200 + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), + 1_323 + ); // 200 + (123 + 2000 x ( 200 / 400 )) = 200 + (1_200) = 1_323 + assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 2_523); // 400 + 2_123 + assert_eq!(SubtensorModule::get_total_stake(), 4_223); // 1_700 + 2_523 = 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_151 + ); // + 350 = 1_151 + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), + 1_200 + ); // No change. + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), + 899 + ); // No change. + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), + 1_473 + ); // 1_323 + 150 = 1_473 + 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::::NonAssociatedColdKey.into()) + ); + assert_eq!( + SubtensorModule::remove_stake( + <::RuntimeOrigin>::signed(coldkey1), + hotkey2, + 10 + ), + Err(Error::::NonAssociatedColdKey.into()) + ); + + assert_eq!(SubtensorModule::get_total_stake(), 5_623); // 4_723 + 900 = 5_623 + + // Lets make this new key a delegate with a 50% take. + assert_ok!(SubtensorModule::do_become_delegate( + <::RuntimeOrigin>::signed(coldkey2), + hotkey2, + u16::MAX / 2 + )); + + // 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_768 + ); // 1000 + 100 + 500 + 500 * (1000/3000) = 100 + 1500 + 166.6666666667 ~= 1,768.6666666667 + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2), + 1_166 + ); // 1000 + 500 * (1000/3000) = 1000 + 166.6666666667 = 1166.6 + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2), + 1_166 + ); // 1000 + 500 * (1000/3000) = 1000 + 166.6666666667 = 1166.6 + 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_891 + ); // 1_768 + 123 = 1_891 + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2), + 1_166 + ); // No change. + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2), + 1_166 + ); // 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().execute_with(|| { - let netuid = 1; - // Make two accounts. + new_test_ext().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 - - // 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, 10) ); - assert_ok! (SubtensorModule::do_become_delegate(<::RuntimeOrigin>::signed(coldkey1), hotkey1, 10) ); - 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 - }); -} + 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 + + // 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, + 10 + )); + assert_ok!(SubtensorModule::do_become_delegate( + <::RuntimeOrigin>::signed(coldkey1), + hotkey1, + 10 + )); + 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 + }); +} /************************************************************ - staking::unstake_all_coldkeys_from_hotkey_account() tests + staking::unstake_all_coldkeys_from_hotkey_account() tests ************************************************************/ #[test] fn test_unstake_all_coldkeys_from_hotkey_account() { - new_test_ext().execute_with(|| { - let hotkey_id = U256::from(123570); - let coldkey0_id = U256::from(123560); - - let coldkey1_id = U256::from(123561); - let coldkey2_id = U256::from(123562); - let coldkey3_id = U256::from(123563); + new_test_ext().execute_with(|| { + let hotkey_id = U256::from(123570); + let coldkey0_id = U256::from(123560); + + let coldkey1_id = U256::from(123561); + let coldkey2_id = U256::from(123562); + let coldkey3_id = U256::from(123563); - let amount: u64 = 10000; + let amount: u64 = 10000; let netuid: u16 = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; - - // Make subnet - add_network(netuid, tempo, 0); - // Register delegate - register_ok_neuron( netuid, hotkey_id, coldkey0_id, start_nonce); - + let tempo: u16 = 13; + let start_nonce: u64 = 0; + + // Make subnet + add_network(netuid, tempo, 0); + // Register delegate + register_ok_neuron(netuid, hotkey_id, coldkey0_id, start_nonce); + match SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_id) { Ok(_k) => (), Err(e) => panic!("Error: {:?}", e), - } - - //Add some stake that can be removed - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey0_id, &hotkey_id, amount); - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey1_id, &hotkey_id, amount + 2); - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey2_id, &hotkey_id, amount + 3); - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey3_id, &hotkey_id, amount + 4); - - // Verify free balance is 0 for all coldkeys - assert_eq!(Balances::free_balance(coldkey0_id), 0); - assert_eq!(Balances::free_balance(coldkey1_id), 0); - assert_eq!(Balances::free_balance(coldkey2_id), 0); - assert_eq!(Balances::free_balance(coldkey3_id), 0); - - // Verify total stake is correct - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), amount * 4 + (2 + 3 + 4)); - - // Run unstake_all_coldkeys_from_hotkey_account - SubtensorModule::unstake_all_coldkeys_from_hotkey_account(&hotkey_id); - - // Verify total stake is 0 - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), 0); - - // Vefify stake for all coldkeys is 0 - assert_eq!(SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0_id, &hotkey_id), 0); - assert_eq!(SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1_id, &hotkey_id), 0); - assert_eq!(SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2_id, &hotkey_id), 0); - assert_eq!(SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey3_id, &hotkey_id), 0); - - // Verify free balance is correct for all coldkeys - assert_eq!(Balances::free_balance(coldkey0_id), amount); - assert_eq!(Balances::free_balance(coldkey1_id), amount + 2); - assert_eq!(Balances::free_balance(coldkey2_id), amount + 3); - assert_eq!(Balances::free_balance(coldkey3_id), amount + 4); - }); + } + + //Add some stake that can be removed + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey0_id, &hotkey_id, amount); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &coldkey1_id, + &hotkey_id, + amount + 2, + ); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &coldkey2_id, + &hotkey_id, + amount + 3, + ); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &coldkey3_id, + &hotkey_id, + amount + 4, + ); + + // Verify free balance is 0 for all coldkeys + assert_eq!(Balances::free_balance(coldkey0_id), 0); + assert_eq!(Balances::free_balance(coldkey1_id), 0); + assert_eq!(Balances::free_balance(coldkey2_id), 0); + assert_eq!(Balances::free_balance(coldkey3_id), 0); + + // Verify total stake is correct + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), + amount * 4 + (2 + 3 + 4) + ); + + // Run unstake_all_coldkeys_from_hotkey_account + SubtensorModule::unstake_all_coldkeys_from_hotkey_account(&hotkey_id); + + // Verify total stake is 0 + assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), 0); + + // Vefify stake for all coldkeys is 0 + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0_id, &hotkey_id), + 0 + ); + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1_id, &hotkey_id), + 0 + ); + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2_id, &hotkey_id), + 0 + ); + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey3_id, &hotkey_id), + 0 + ); + + // Verify free balance is correct for all coldkeys + assert_eq!(Balances::free_balance(coldkey0_id), amount); + assert_eq!(Balances::free_balance(coldkey1_id), amount + 2); + assert_eq!(Balances::free_balance(coldkey2_id), amount + 3); + assert_eq!(Balances::free_balance(coldkey3_id), amount + 4); + }); } #[test] fn test_unstake_all_coldkeys_from_hotkey_account_single_staker() { - new_test_ext().execute_with(|| { - let hotkey_id = U256::from(123570); - let coldkey0_id = U256::from(123560); - - let amount: u64 = 891011; + new_test_ext().execute_with(|| { + let hotkey_id = U256::from(123570); + let coldkey0_id = U256::from(123560); + + let amount: u64 = 891011; let netuid: u16 = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; - - // Make subnet - add_network(netuid, tempo, 0); - // Register delegate - register_ok_neuron( netuid, hotkey_id, coldkey0_id, start_nonce); - + let tempo: u16 = 13; + let start_nonce: u64 = 0; + + // Make subnet + add_network(netuid, tempo, 0); + // Register delegate + register_ok_neuron(netuid, hotkey_id, coldkey0_id, start_nonce); + match SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_id) { Ok(_) => (), Err(e) => panic!("Error: {:?}", e), - } - - //Add some stake that can be removed - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey0_id, &hotkey_id, amount); + } - // Verify free balance is 0 for coldkey - assert_eq!(Balances::free_balance(coldkey0_id), 0); + //Add some stake that can be removed + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey0_id, &hotkey_id, amount); - // Verify total stake is correct - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), amount); + // Verify free balance is 0 for coldkey + assert_eq!(Balances::free_balance(coldkey0_id), 0); - // Run unstake_all_coldkeys_from_hotkey_account - SubtensorModule::unstake_all_coldkeys_from_hotkey_account(&hotkey_id); + // Verify total stake is correct + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), + amount + ); + + // Run unstake_all_coldkeys_from_hotkey_account + SubtensorModule::unstake_all_coldkeys_from_hotkey_account(&hotkey_id); - // Verify total stake is 0 - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), 0); + // Verify total stake is 0 + assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), 0); - // Vefify stake for single coldkey is 0 - assert_eq!(SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0_id, &hotkey_id), 0); + // Vefify stake for single coldkey is 0 + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0_id, &hotkey_id), + 0 + ); - // Verify free balance is correct for single coldkey - assert_eq!(Balances::free_balance(coldkey0_id), amount); - }); + // Verify free balance is correct for single coldkey + assert_eq!(Balances::free_balance(coldkey0_id), amount); + }); } diff --git a/pallets/subtensor/tests/uids.rs b/pallets/subtensor/tests/uids.rs index 7bb8750706..772fcbc222 100644 --- a/pallets/subtensor/tests/uids.rs +++ b/pallets/subtensor/tests/uids.rs @@ -1,184 +1,371 @@ +use crate::mock::*; use frame_support::assert_ok; use frame_system::Config; use sp_core::U256; -use crate::{mock::*}; mod mock; /******************************************** - tests for uids.rs file + tests for uids.rs file *********************************************/ - /******************************************** - tests uids::replace_neuron() + tests uids::replace_neuron() *********************************************/ #[test] fn test_replace_neuron() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let block_number: u64 = 0; - let netuid: u16 = 1; - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 111111, &hotkey_account_id); - let coldkey_account_id = U256::from(1234); + let netuid: u16 = 1; + let tempo: u16 = 13; + let hotkey_account_id = U256::from(1); + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 111111, + &hotkey_account_id, + ); + let coldkey_account_id = U256::from(1234); let new_hotkey_account_id = U256::from(2); let _new_colkey_account_id = U256::from(12345); - //add network - add_network(netuid, tempo, 0); - - // Register a neuron. - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, block_number, nonce, work, hotkey_account_id, coldkey_account_id)); + //add network + add_network(netuid, tempo, 0); + + // Register a neuron. + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + block_number, + nonce, + work, + hotkey_account_id, + coldkey_account_id + )); // Get UID - let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id); + let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id); assert_ok!(neuron_uid); // Replace the neuron. - SubtensorModule::replace_neuron(netuid, neuron_uid.unwrap(), &new_hotkey_account_id, block_number); + SubtensorModule::replace_neuron( + netuid, + neuron_uid.unwrap(), + &new_hotkey_account_id, + block_number, + ); // Check old hotkey is not registered on any network. assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).is_err()); - assert!( ! SubtensorModule::is_hotkey_registered_on_any_network(&hotkey_account_id) ); - + assert!(!SubtensorModule::is_hotkey_registered_on_any_network( + &hotkey_account_id + )); + let curr_hotkey = SubtensorModule::get_hotkey_for_net_and_uid(netuid, neuron_uid.unwrap()); assert_ok!(curr_hotkey); assert_ne!(curr_hotkey.unwrap(), hotkey_account_id); // Check new hotkey is registered on the network. - assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &new_hotkey_account_id).is_ok()); - assert!(SubtensorModule::is_hotkey_registered_on_any_network(&new_hotkey_account_id) ); + assert!( + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &new_hotkey_account_id).is_ok() + ); + assert!(SubtensorModule::is_hotkey_registered_on_any_network( + &new_hotkey_account_id + )); assert_eq!(curr_hotkey.unwrap(), new_hotkey_account_id); - }); + }); } #[test] fn test_replace_neuron_multiple_subnets() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let block_number: u64 = 0; - let netuid: u16 = 1; + let netuid: u16 = 1; let netuid1: u16 = 2; - let tempo: u16 = 13; + let tempo: u16 = 13; let hotkey_account_id = U256::from(1); let new_hotkey_account_id = U256::from(2); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 111111, &hotkey_account_id); - let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid1, block_number, 111111 * 5, &hotkey_account_id); - - let coldkey_account_id = U256::from(1234); + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 111111, + &hotkey_account_id, + ); + let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid1, + block_number, + 111111 * 5, + &hotkey_account_id, + ); + + let coldkey_account_id = U256::from(1234); let _new_colkey_account_id = U256::from(12345); - //add network - add_network(netuid, tempo, 0); + //add network + add_network(netuid, tempo, 0); add_network(netuid1, tempo, 0); - - // Register a neuron on both networks. - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, block_number, nonce, work, hotkey_account_id, coldkey_account_id)); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id), netuid1, block_number, nonce1, work1, hotkey_account_id, coldkey_account_id)); + + // Register a neuron on both networks. + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + block_number, + nonce, + work, + hotkey_account_id, + coldkey_account_id + )); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid1, + block_number, + nonce1, + work1, + hotkey_account_id, + coldkey_account_id + )); // Get UID - let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id); + let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id); assert_ok!(neuron_uid); // Verify neuron is registered on both networks. - assert!(SubtensorModule::is_hotkey_registered_on_network(netuid, &hotkey_account_id) ); - assert!(SubtensorModule::is_hotkey_registered_on_network(netuid1, &hotkey_account_id) ); - assert!(SubtensorModule::is_hotkey_registered_on_any_network(&hotkey_account_id) ); + assert!(SubtensorModule::is_hotkey_registered_on_network( + netuid, + &hotkey_account_id + )); + assert!(SubtensorModule::is_hotkey_registered_on_network( + netuid1, + &hotkey_account_id + )); + assert!(SubtensorModule::is_hotkey_registered_on_any_network( + &hotkey_account_id + )); // Replace the neuron. // Only replace on ONE network. - SubtensorModule::replace_neuron(netuid, neuron_uid.unwrap(), &new_hotkey_account_id, block_number); + SubtensorModule::replace_neuron( + netuid, + neuron_uid.unwrap(), + &new_hotkey_account_id, + block_number, + ); // Check old hotkey is not registered on netuid network. assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).is_err()); // Verify still registered on netuid1 network. - assert!( SubtensorModule::is_hotkey_registered_on_any_network(&hotkey_account_id) ); - assert!( SubtensorModule::is_hotkey_registered_on_network(netuid1, &hotkey_account_id) ); - }); + assert!(SubtensorModule::is_hotkey_registered_on_any_network( + &hotkey_account_id + )); + assert!(SubtensorModule::is_hotkey_registered_on_network( + netuid1, + &hotkey_account_id + )); + }); } #[test] fn test_replace_neuron_multiple_subnets_unstake_all() { - new_test_ext().execute_with(|| { - let block_number: u64 = 0; - let netuid: u16 = 1; + new_test_ext().execute_with(|| { + let block_number: u64 = 0; + let netuid: u16 = 1; let netuid1: u16 = 2; - let tempo: u16 = 13; + let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); + let hotkey_account_id = U256::from(1); let new_hotkey_account_id = U256::from(2); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, 111111, &hotkey_account_id); - let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid1, block_number, 111111 * 5, &hotkey_account_id); - - let coldkey_account_id = U256::from(1234); - let coldkey_account1_id = U256::from(1235); - let coldkey_account2_id = U256::from(1236); - + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + 111111, + &hotkey_account_id, + ); + let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid1, + block_number, + 111111 * 5, + &hotkey_account_id, + ); + + let coldkey_account_id = U256::from(1234); + let coldkey_account1_id = U256::from(1235); + let coldkey_account2_id = U256::from(1236); let stake_amount = 1000; - //add network - add_network(netuid, tempo, 0); + //add network + add_network(netuid, tempo, 0); add_network(netuid1, tempo, 0); - - // Register a neuron on both networks. - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id), netuid, block_number, nonce, work, hotkey_account_id, coldkey_account_id)); - assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(hotkey_account_id), netuid1, block_number, nonce1, work1, hotkey_account_id, coldkey_account_id)); + + // Register a neuron on both networks. + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + block_number, + nonce, + work, + hotkey_account_id, + coldkey_account_id + )); + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid1, + block_number, + nonce1, + work1, + hotkey_account_id, + coldkey_account_id + )); // Get UID - let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id); + let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id); assert_ok!(neuron_uid); // Stake on neuron with multiple coldkeys. - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey_account_id, &hotkey_account_id, stake_amount); - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey_account1_id, &hotkey_account_id, stake_amount + 1); - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey_account2_id, &hotkey_account_id, stake_amount + 2); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &coldkey_account_id, + &hotkey_account_id, + stake_amount, + ); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &coldkey_account1_id, + &hotkey_account_id, + stake_amount + 1, + ); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &coldkey_account2_id, + &hotkey_account_id, + stake_amount + 2, + ); // Check stake on neuron - assert_eq!(SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey_account_id, &hotkey_account_id), stake_amount); - assert_eq!(SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey_account1_id, &hotkey_account_id), stake_amount + 1); - assert_eq!(SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey_account2_id, &hotkey_account_id), stake_amount + 2); + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey( + &coldkey_account_id, + &hotkey_account_id + ), + stake_amount + ); + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey( + &coldkey_account1_id, + &hotkey_account_id + ), + stake_amount + 1 + ); + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey( + &coldkey_account2_id, + &hotkey_account_id + ), + stake_amount + 2 + ); // Check total stake on neuron - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), (stake_amount * 3) + (1 + 2)); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + (stake_amount * 3) + (1 + 2) + ); // Replace the neuron. - SubtensorModule::replace_neuron(netuid, neuron_uid.unwrap(), &new_hotkey_account_id, block_number); + SubtensorModule::replace_neuron( + netuid, + neuron_uid.unwrap(), + &new_hotkey_account_id, + block_number, + ); // The stakes should still be on the neuron. It is still registered on one network. - assert!(SubtensorModule::is_hotkey_registered_on_any_network(&hotkey_account_id) ); + assert!(SubtensorModule::is_hotkey_registered_on_any_network( + &hotkey_account_id + )); // Check the stake is still on the coldkey accounts. - assert_eq!(SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey_account_id, &hotkey_account_id), stake_amount); - assert_eq!(SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey_account1_id, &hotkey_account_id), stake_amount + 1); - assert_eq!(SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey_account2_id, &hotkey_account_id), stake_amount + 2); + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey( + &coldkey_account_id, + &hotkey_account_id + ), + stake_amount + ); + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey( + &coldkey_account1_id, + &hotkey_account_id + ), + stake_amount + 1 + ); + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey( + &coldkey_account2_id, + &hotkey_account_id + ), + stake_amount + 2 + ); // Check total stake on neuron - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), (stake_amount * 3) + (1 + 2)); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + (stake_amount * 3) + (1 + 2) + ); // replace on second network - SubtensorModule::replace_neuron(netuid1, neuron_uid.unwrap(), &new_hotkey_account_id, block_number); + SubtensorModule::replace_neuron( + netuid1, + neuron_uid.unwrap(), + &new_hotkey_account_id, + block_number, + ); // The neuron should be unregistered now. - assert!( !SubtensorModule::is_hotkey_registered_on_any_network(&hotkey_account_id) ); + assert!(!SubtensorModule::is_hotkey_registered_on_any_network( + &hotkey_account_id + )); // Check the stake is now on the free balance of the coldkey accounts. - assert_eq!(SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey_account_id, &hotkey_account_id), 0); + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey( + &coldkey_account_id, + &hotkey_account_id + ), + 0 + ); assert_eq!(Balances::free_balance(&coldkey_account_id), stake_amount); - assert_eq!(SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey_account1_id, &hotkey_account_id), 0); - assert_eq!(Balances::free_balance(&coldkey_account1_id), stake_amount + 1); - - assert_eq!(SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey_account2_id, &hotkey_account_id), 0); - assert_eq!(Balances::free_balance(&coldkey_account2_id), stake_amount + 2); + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey( + &coldkey_account1_id, + &hotkey_account_id + ), + 0 + ); + assert_eq!( + Balances::free_balance(&coldkey_account1_id), + stake_amount + 1 + ); + + assert_eq!( + SubtensorModule::get_stake_for_coldkey_and_hotkey( + &coldkey_account2_id, + &hotkey_account_id + ), + 0 + ); + assert_eq!( + Balances::free_balance(&coldkey_account2_id), + stake_amount + 2 + ); // Check total stake on neuron - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), 0); - }); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + 0 + ); + }); } diff --git a/pallets/subtensor/tests/weights.rs b/pallets/subtensor/tests/weights.rs index d3d9b8ce61..206aceeb31 100644 --- a/pallets/subtensor/tests/weights.rs +++ b/pallets/subtensor/tests/weights.rs @@ -1,18 +1,14 @@ mod mock; -use mock::*; -use pallet_subtensor::Error; -use frame_system::Config; use frame_support::{ - assert_ok, - dispatch::{ - GetDispatchInfo, - DispatchClass, - Pays - } + assert_ok, + dispatch::{DispatchClass, GetDispatchInfo, Pays}, }; +use frame_system::Config; +use mock::*; +use pallet_subtensor::Error; +use sp_core::U256; use sp_runtime::DispatchError; use substrate_fixed::types::I32F32; -use sp_core::U256; /*************************** pub fn set_weights() tests @@ -22,716 +18,866 @@ use sp_core::U256; #[test] #[cfg(not(tarpaulin))] fn test_set_weights_dispatch_info_ok() { - new_test_ext().execute_with(|| { - let dests = vec![1, 1]; - let weights = vec![1, 1]; + new_test_ext().execute_with(|| { + let dests = vec![1, 1]; + let weights = vec![1, 1]; let netuid: u16 = 1; - let version_key: u64 = 0; - let call = RuntimeCall::SubtensorModule(SubtensorCall::set_weights{netuid, dests, weights, version_key}); - let dispatch_info = call.get_dispatch_info(); - - assert_eq!(dispatch_info.class, DispatchClass::Normal); - assert_eq!(dispatch_info.pays_fee, Pays::No); - }); + let version_key: u64 = 0; + let call = RuntimeCall::SubtensorModule(SubtensorCall::set_weights { + netuid, + dests, + weights, + version_key, + }); + let dispatch_info = call.get_dispatch_info(); + + assert_eq!(dispatch_info.class, DispatchClass::Normal); + assert_eq!(dispatch_info.pays_fee, Pays::No); + }); } // Test ensures that uid has validator permit to set non-self weights. #[test] fn test_weights_err_no_validator_permit() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let hotkey_account_id = U256::from(55); - let netuid: u16 = 1; - let tempo: u16 = 13; - add_network(netuid, tempo, 0); - SubtensorModule::set_max_allowed_uids(netuid, 3); - register_ok_neuron( netuid, hotkey_account_id, U256::from(66), 0); - register_ok_neuron( netuid, U256::from(1), U256::from(1), 65555 ); - register_ok_neuron( netuid, U256::from(2), U256::from(2), 75555 ); - - let weights_keys: Vec = vec![1, 2]; - let weight_values: Vec = vec![1, 2]; - let result = SubtensorModule::set_weights(RuntimeOrigin::signed(hotkey_account_id), netuid, weights_keys, weight_values, 0); - assert_eq!(result, Err(Error::::NoValidatorPermit.into())); - - let weights_keys: Vec = vec![1, 2]; - let weight_values: Vec = vec![1, 2]; - let neuron_uid: u16 = SubtensorModule::get_uid_for_net_and_hotkey( netuid, &hotkey_account_id ).expect("Not registered."); - SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); - let result = SubtensorModule::set_weights(RuntimeOrigin::signed(hotkey_account_id), netuid, weights_keys, weight_values, 0); - assert_ok!(result); - }); + let netuid: u16 = 1; + let tempo: u16 = 13; + add_network(netuid, tempo, 0); + SubtensorModule::set_max_allowed_uids(netuid, 3); + register_ok_neuron(netuid, hotkey_account_id, U256::from(66), 0); + register_ok_neuron(netuid, U256::from(1), U256::from(1), 65555); + register_ok_neuron(netuid, U256::from(2), U256::from(2), 75555); + + let weights_keys: Vec = vec![1, 2]; + let weight_values: Vec = vec![1, 2]; + let result = SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey_account_id), + netuid, + weights_keys, + weight_values, + 0, + ); + assert_eq!(result, Err(Error::::NoValidatorPermit.into())); + + let weights_keys: Vec = vec![1, 2]; + let weight_values: Vec = vec![1, 2]; + let neuron_uid: u16 = + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id) + .expect("Not registered."); + SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); + let result = SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey_account_id), + netuid, + weights_keys, + weight_values, + 0, + ); + assert_ok!(result); + }); } // Test ensures that a uid can only set weights if it has the valid weights set version key. #[test] fn test_weights_version_key() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let hotkey = U256::from(55); - let coldkey= U256::from(66); - let netuid0: u16 = 0; - let netuid1: u16 = 2; - add_network(netuid0, 0, 0); - add_network(netuid1, 0, 0); - register_ok_neuron( netuid0, hotkey, coldkey, 2143124 ); - register_ok_neuron( netuid1, hotkey, coldkey, 3124124 ); - - let weights_keys: Vec = vec![0]; - let weight_values: Vec = vec![1]; - assert_ok!( SubtensorModule::set_weights(RuntimeOrigin::signed(hotkey), netuid0, weights_keys.clone(), weight_values.clone(), 0) ); - assert_ok!( SubtensorModule::set_weights(RuntimeOrigin::signed(hotkey), netuid1, weights_keys.clone(), weight_values.clone(), 0) ); - - // Set version keys. - let key0: u64 = 12312; - let key1: u64 = 20313; - SubtensorModule::set_weights_version_key( netuid0, key0 ); - SubtensorModule::set_weights_version_key( netuid1, key1 ); - - // Setting works with version key. - assert_ok!( SubtensorModule::set_weights(RuntimeOrigin::signed(hotkey), netuid0, weights_keys.clone(), weight_values.clone(), key0) ); - assert_ok!( SubtensorModule::set_weights(RuntimeOrigin::signed(hotkey), netuid1, weights_keys.clone(), weight_values.clone(), key1) ); - - // validator:20313 >= network:12312 (accepted: validator newer) - assert_ok!( SubtensorModule::set_weights(RuntimeOrigin::signed(hotkey), netuid0, weights_keys.clone(), weight_values.clone(), key1) ); - - // Setting fails with incorrect keys. - // validator:12312 < network:20313 (rejected: validator not updated) - assert_eq!( SubtensorModule::set_weights(RuntimeOrigin::signed(hotkey), netuid1, weights_keys.clone(), weight_values.clone(), key0), Err(Error::::IncorrectNetworkVersionKey.into()) ); - }); + let coldkey = U256::from(66); + let netuid0: u16 = 0; + let netuid1: u16 = 2; + add_network(netuid0, 0, 0); + add_network(netuid1, 0, 0); + register_ok_neuron(netuid0, hotkey, coldkey, 2143124); + register_ok_neuron(netuid1, hotkey, coldkey, 3124124); + + let weights_keys: Vec = vec![0]; + let weight_values: Vec = vec![1]; + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey), + netuid0, + weights_keys.clone(), + weight_values.clone(), + 0 + )); + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey), + netuid1, + weights_keys.clone(), + weight_values.clone(), + 0 + )); + + // Set version keys. + let key0: u64 = 12312; + let key1: u64 = 20313; + SubtensorModule::set_weights_version_key(netuid0, key0); + SubtensorModule::set_weights_version_key(netuid1, key1); + + // Setting works with version key. + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey), + netuid0, + weights_keys.clone(), + weight_values.clone(), + key0 + )); + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey), + netuid1, + weights_keys.clone(), + weight_values.clone(), + key1 + )); + + // validator:20313 >= network:12312 (accepted: validator newer) + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey), + netuid0, + weights_keys.clone(), + weight_values.clone(), + key1 + )); + + // Setting fails with incorrect keys. + // validator:12312 < network:20313 (rejected: validator not updated) + assert_eq!( + SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey), + netuid1, + weights_keys.clone(), + weight_values.clone(), + key0 + ), + Err(Error::::IncorrectNetworkVersionKey.into()) + ); + }); } // Test ensures that uid has validator permit to set non-self weights. #[test] fn test_weights_err_setting_weights_too_fast() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let hotkey_account_id = U256::from(55); - let netuid: u16 = 1; - let tempo: u16 = 13; - add_network(netuid, tempo, 0); - SubtensorModule::set_max_allowed_uids(netuid, 3); - register_ok_neuron( netuid, hotkey_account_id, U256::from(66), 0); - register_ok_neuron( netuid, U256::from(1), U256::from(1), 65555 ); - register_ok_neuron( netuid, U256::from(2), U256::from(2), 75555 ); - - let neuron_uid: u16 = SubtensorModule::get_uid_for_net_and_hotkey( netuid, &hotkey_account_id ).expect("Not registered."); - SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); - assert_ok!( SubtensorModule::sudo_set_weights_set_rate_limit(<::RuntimeOrigin>::root(), netuid, 10) ); - assert_eq!( SubtensorModule::get_weights_set_rate_limit(netuid), 10); - - let weights_keys: Vec = vec![1, 2]; - let weight_values: Vec = vec![1, 2]; - - // Note that LastUpdate has default 0 for new uids, but if they have actually set weights on block 0 - // then they are allowed to set weights again once more without a wait restriction, to accommodate the default. - let result = SubtensorModule::set_weights(RuntimeOrigin::signed(hotkey_account_id), netuid, weights_keys.clone(), weight_values.clone(), 0); - assert_ok!(result); - run_to_block(1); - - for i in 1..100 { - let result = SubtensorModule::set_weights(RuntimeOrigin::signed(hotkey_account_id), netuid, weights_keys.clone(), weight_values.clone(), 0); - if i % 10 == 1 { - assert_ok!(result); - } - else { - assert_eq!(result, Err(Error::::SettingWeightsTooFast.into())); - } - run_to_block(i + 1); - } - }); + let netuid: u16 = 1; + let tempo: u16 = 13; + add_network(netuid, tempo, 0); + SubtensorModule::set_max_allowed_uids(netuid, 3); + register_ok_neuron(netuid, hotkey_account_id, U256::from(66), 0); + register_ok_neuron(netuid, U256::from(1), U256::from(1), 65555); + register_ok_neuron(netuid, U256::from(2), U256::from(2), 75555); + + let neuron_uid: u16 = + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id) + .expect("Not registered."); + SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); + assert_ok!(SubtensorModule::sudo_set_weights_set_rate_limit( + <::RuntimeOrigin>::root(), + netuid, + 10 + )); + assert_eq!(SubtensorModule::get_weights_set_rate_limit(netuid), 10); + + let weights_keys: Vec = vec![1, 2]; + let weight_values: Vec = vec![1, 2]; + + // Note that LastUpdate has default 0 for new uids, but if they have actually set weights on block 0 + // then they are allowed to set weights again once more without a wait restriction, to accommodate the default. + let result = SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey_account_id), + netuid, + weights_keys.clone(), + weight_values.clone(), + 0, + ); + assert_ok!(result); + run_to_block(1); + + for i in 1..100 { + let result = SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey_account_id), + netuid, + weights_keys.clone(), + weight_values.clone(), + 0, + ); + if i % 10 == 1 { + assert_ok!(result); + } else { + assert_eq!(result, Err(Error::::SettingWeightsTooFast.into())); + } + run_to_block(i + 1); + } + }); } // Test ensures that uids -- weights must have the same size. #[test] fn test_weights_err_weights_vec_not_equal_size() { - new_test_ext().execute_with(|| { + new_test_ext().execute_with(|| { let hotkey_account_id = U256::from(55); - let netuid: u16 = 1; - let tempo: u16 = 13; - add_network(netuid, tempo, 0); - register_ok_neuron(1, hotkey_account_id, U256::from(66), 0); - let neuron_uid: u16 = SubtensorModule::get_uid_for_net_and_hotkey( netuid, &hotkey_account_id ).expect("Not registered."); - SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); - let weights_keys: Vec = vec![1, 2, 3, 4, 5, 6]; - let weight_values: Vec = vec![1, 2, 3, 4, 5]; // Uneven sizes - let result = SubtensorModule::set_weights(RuntimeOrigin::signed(hotkey_account_id), 1, weights_keys, weight_values, 0); - assert_eq!(result, Err(Error::::WeightVecNotEqualSize.into())); - }); + let netuid: u16 = 1; + let tempo: u16 = 13; + add_network(netuid, tempo, 0); + register_ok_neuron(1, hotkey_account_id, U256::from(66), 0); + let neuron_uid: u16 = + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id) + .expect("Not registered."); + SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); + let weights_keys: Vec = vec![1, 2, 3, 4, 5, 6]; + let weight_values: Vec = vec![1, 2, 3, 4, 5]; // Uneven sizes + let result = SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey_account_id), + 1, + weights_keys, + weight_values, + 0, + ); + assert_eq!(result, Err(Error::::WeightVecNotEqualSize.into())); + }); } // Test ensures that uids can have not duplicates #[test] fn test_weights_err_has_duplicate_ids() { - new_test_ext().execute_with(|| { - let hotkey_account_id = U256::from(666); - let netuid: u16 = 1; - let tempo: u16 = 13; - add_network(netuid, tempo, 0); - - SubtensorModule::set_max_allowed_uids(netuid, 100); // Allow many registrations per block. - SubtensorModule::set_max_registrations_per_block(netuid, 100); // Allow many registrations per block. - - // uid 0 - register_ok_neuron( netuid, hotkey_account_id, U256::from(77), 0); - let neuron_uid: u16 = SubtensorModule::get_uid_for_net_and_hotkey( netuid, &hotkey_account_id ).expect("Not registered."); - SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); - - // uid 1 - register_ok_neuron( netuid, U256::from(1), U256::from(1), 100_000); - SubtensorModule::get_uid_for_net_and_hotkey( netuid, &U256::from(1) ).expect("Not registered."); - - // uid 2 - register_ok_neuron( netuid, U256::from(2), U256::from(1), 200_000); - SubtensorModule::get_uid_for_net_and_hotkey( netuid, &U256::from(2) ).expect("Not registered."); - - // uid 3 - register_ok_neuron( netuid, U256::from(3), U256::from(1), 300_000); - SubtensorModule::get_uid_for_net_and_hotkey( netuid, &U256::from(3) ).expect("Not registered."); - - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 4); - - let weights_keys: Vec = vec![1, 1, 1]; // Contains duplicates - let weight_values: Vec = vec![1, 2, 3]; - let result = SubtensorModule::set_weights(RuntimeOrigin::signed(hotkey_account_id), netuid, weights_keys, weight_values, 0); - assert_eq!(result, Err(Error::::DuplicateUids.into())); - }); + new_test_ext().execute_with(|| { + let hotkey_account_id = U256::from(666); + let netuid: u16 = 1; + let tempo: u16 = 13; + add_network(netuid, tempo, 0); + + SubtensorModule::set_max_allowed_uids(netuid, 100); // Allow many registrations per block. + SubtensorModule::set_max_registrations_per_block(netuid, 100); // Allow many registrations per block. + + // uid 0 + register_ok_neuron(netuid, hotkey_account_id, U256::from(77), 0); + let neuron_uid: u16 = + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id) + .expect("Not registered."); + SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); + + // uid 1 + register_ok_neuron(netuid, U256::from(1), U256::from(1), 100_000); + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(1)) + .expect("Not registered."); + + // uid 2 + register_ok_neuron(netuid, U256::from(2), U256::from(1), 200_000); + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(2)) + .expect("Not registered."); + + // uid 3 + register_ok_neuron(netuid, U256::from(3), U256::from(1), 300_000); + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(3)) + .expect("Not registered."); + + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 4); + + let weights_keys: Vec = vec![1, 1, 1]; // Contains duplicates + let weight_values: Vec = vec![1, 2, 3]; + let result = SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey_account_id), + netuid, + weights_keys, + weight_values, + 0, + ); + assert_eq!(result, Err(Error::::DuplicateUids.into())); + }); } // Test ensures weights cannot exceed max weight limit. #[test] -fn test_weights_err_max_weight_limit() { //TO DO SAM: uncomment when we implement run_to_block fn - new_test_ext().execute_with(|| { - // Add network. - let netuid: u16 = 1; - let tempo: u16 = 100; - add_network(netuid, tempo, 0); - - // Set params. - SubtensorModule::set_max_allowed_uids(netuid, 5); - SubtensorModule::set_max_weight_limit( netuid, u16::MAX/5 ); - - // Add 5 accounts. - println!( "+Registering: net:{:?}, cold:{:?}, hot:{:?}", netuid, 0, 0 ); - register_ok_neuron( netuid, U256::from(0), U256::from(0), 55555 ); - let neuron_uid: u16 = SubtensorModule::get_uid_for_net_and_hotkey( netuid, &U256::from(0) ).expect("Not registered."); - SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); - assert_eq!( SubtensorModule::get_subnetwork_n(netuid), 1 ); - assert!( SubtensorModule::is_hotkey_registered_on_network( netuid, &U256::from(0) ) ); - step_block(1); - - println!( "+Registering: net:{:?}, cold:{:?}, hot:{:?}", netuid, 1, 1 ); - register_ok_neuron( netuid, U256::from(1), U256::from(1), 65555 ); - assert!( SubtensorModule::is_hotkey_registered_on_network( netuid, &U256::from(1) ) ); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 2); - step_block(1); - - println!( "+Registering: net:{:?}, cold:{:?}, hot:{:?}", netuid, 2, 2 ); - register_ok_neuron( netuid, U256::from(2), U256::from(2), 75555 ); - assert!( SubtensorModule::is_hotkey_registered_on_network( netuid, &U256::from(2) ) ); - assert_eq!( SubtensorModule::get_subnetwork_n(netuid), 3 ); - step_block(1); - - println!( "+Registering: net:{:?}, cold:{:?}, hot:{:?}", netuid, 3, 3 ); - register_ok_neuron( netuid, U256::from(3), U256::from(3), 95555 ); - assert!( SubtensorModule::is_hotkey_registered_on_network( netuid, &U256::from(3) ) ); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 4); - step_block(1); - - println!( "+Registering: net:{:?}, cold:{:?}, hot:{:?}", netuid, 4, 4 ); - register_ok_neuron( netuid, U256::from(4), U256::from(4), 35555 ); - assert!( SubtensorModule::is_hotkey_registered_on_network( netuid, &U256::from(4) ) ); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 5); - step_block(1); - - // Non self-weight fails. - let uids: Vec = vec![ 1, 2, 3, 4 ]; - let values: Vec = vec![ u16::MAX/4, u16::MAX/4, u16::MAX/54, u16::MAX/4]; - let result = SubtensorModule::set_weights( RuntimeOrigin::signed(U256::from(0)), 1, uids, values, 0 ); - assert_eq!(result, Err(Error::::MaxWeightExceeded.into())); - - // Self-weight is a success. - let uids: Vec = vec![ 0 ]; // Self. - let values: Vec = vec![ u16::MAX ]; // normalizes to u32::MAX - assert_ok!(SubtensorModule::set_weights( RuntimeOrigin::signed(U256::from(0)), 1, uids, values, 0)); - }); +fn test_weights_err_max_weight_limit() { + //TO DO SAM: uncomment when we implement run_to_block fn + new_test_ext().execute_with(|| { + // Add network. + let netuid: u16 = 1; + let tempo: u16 = 100; + add_network(netuid, tempo, 0); + + // Set params. + SubtensorModule::set_max_allowed_uids(netuid, 5); + SubtensorModule::set_max_weight_limit(netuid, u16::MAX / 5); + + // Add 5 accounts. + println!("+Registering: net:{:?}, cold:{:?}, hot:{:?}", netuid, 0, 0); + register_ok_neuron(netuid, U256::from(0), U256::from(0), 55555); + let neuron_uid: u16 = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(0)) + .expect("Not registered."); + SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 1); + assert!(SubtensorModule::is_hotkey_registered_on_network( + netuid, + &U256::from(0) + )); + step_block(1); + + println!("+Registering: net:{:?}, cold:{:?}, hot:{:?}", netuid, 1, 1); + register_ok_neuron(netuid, U256::from(1), U256::from(1), 65555); + assert!(SubtensorModule::is_hotkey_registered_on_network( + netuid, + &U256::from(1) + )); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 2); + step_block(1); + + println!("+Registering: net:{:?}, cold:{:?}, hot:{:?}", netuid, 2, 2); + register_ok_neuron(netuid, U256::from(2), U256::from(2), 75555); + assert!(SubtensorModule::is_hotkey_registered_on_network( + netuid, + &U256::from(2) + )); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 3); + step_block(1); + + println!("+Registering: net:{:?}, cold:{:?}, hot:{:?}", netuid, 3, 3); + register_ok_neuron(netuid, U256::from(3), U256::from(3), 95555); + assert!(SubtensorModule::is_hotkey_registered_on_network( + netuid, + &U256::from(3) + )); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 4); + step_block(1); + + println!("+Registering: net:{:?}, cold:{:?}, hot:{:?}", netuid, 4, 4); + register_ok_neuron(netuid, U256::from(4), U256::from(4), 35555); + assert!(SubtensorModule::is_hotkey_registered_on_network( + netuid, + &U256::from(4) + )); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 5); + step_block(1); + + // Non self-weight fails. + let uids: Vec = vec![1, 2, 3, 4]; + let values: Vec = vec![u16::MAX / 4, u16::MAX / 4, u16::MAX / 54, u16::MAX / 4]; + let result = + SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(0)), 1, uids, values, 0); + assert_eq!(result, Err(Error::::MaxWeightExceeded.into())); + + // Self-weight is a success. + let uids: Vec = vec![0]; // Self. + let values: Vec = vec![u16::MAX]; // normalizes to u32::MAX + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(0)), + 1, + uids, + values, + 0 + )); + }); } // Tests the call requires a valid origin. #[test] fn test_no_signature() { - new_test_ext().execute_with(|| { - let uids: Vec = vec![]; - let values: Vec = vec![]; - let result = SubtensorModule::set_weights(RuntimeOrigin::none(), 1, uids, values, 0); - assert_eq!(result, Err(DispatchError::BadOrigin.into())); - }); + new_test_ext().execute_with(|| { + let uids: Vec = vec![]; + let values: Vec = vec![]; + let result = SubtensorModule::set_weights(RuntimeOrigin::none(), 1, uids, values, 0); + assert_eq!(result, Err(DispatchError::BadOrigin.into())); + }); } // Tests that weights cannot be set BY non-registered hotkeys. #[test] fn test_set_weights_err_not_active() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; - let tempo: u16 = 13; - add_network(netuid, tempo, 0); - - // Register one neuron. Should have uid 0 - register_ok_neuron(1, U256::from(666), U256::from(2), 100000); - SubtensorModule::get_uid_for_net_and_hotkey( netuid, &U256::from(666) ).expect("Not registered."); - - let weights_keys: Vec = vec![0]; // Uid 0 is valid. - let weight_values: Vec = vec![1]; - // This hotkey is NOT registered. - let result = SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(1)), 1, weights_keys, weight_values, 0); - assert_eq!(result, Err(Error::::NotRegistered.into())); - }); + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + add_network(netuid, tempo, 0); + + // Register one neuron. Should have uid 0 + register_ok_neuron(1, U256::from(666), U256::from(2), 100000); + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(666)) + .expect("Not registered."); + + let weights_keys: Vec = vec![0]; // Uid 0 is valid. + let weight_values: Vec = vec![1]; + // This hotkey is NOT registered. + let result = SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(1)), + 1, + weights_keys, + weight_values, + 0, + ); + assert_eq!(result, Err(Error::::NotRegistered.into())); + }); } // Tests that set weights fails if you pass invalid uids. #[test] fn test_set_weights_err_invalid_uid() { - new_test_ext().execute_with(|| { - let hotkey_account_id = U256::from(55); + new_test_ext().execute_with(|| { + let hotkey_account_id = U256::from(55); let netuid: u16 = 1; - let tempo: u16 = 13; - add_network(netuid, tempo, 0); - register_ok_neuron( 1, hotkey_account_id, U256::from(66), 0); - let neuron_uid: u16 = SubtensorModule::get_uid_for_net_and_hotkey( netuid, &hotkey_account_id ).expect("Not registered."); - SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); - let weight_keys : Vec = vec![9999]; // Does not exist - let weight_values : Vec = vec![88]; // random value - let result = SubtensorModule::set_weights(RuntimeOrigin::signed(hotkey_account_id), 1, weight_keys, weight_values, 0); - assert_eq!(result, Err(Error::::InvalidUid.into())); - }); + let tempo: u16 = 13; + add_network(netuid, tempo, 0); + register_ok_neuron(1, hotkey_account_id, U256::from(66), 0); + let neuron_uid: u16 = + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id) + .expect("Not registered."); + SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); + let weight_keys: Vec = vec![9999]; // Does not exist + let weight_values: Vec = vec![88]; // random value + let result = SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey_account_id), + 1, + weight_keys, + weight_values, + 0, + ); + assert_eq!(result, Err(Error::::InvalidUid.into())); + }); } // Tests that set weights fails if you dont pass enough values. #[test] fn test_set_weight_not_enough_values() { - new_test_ext().execute_with(|| { - - let netuid: u16 = 1; - let tempo: u16 = 13; - let account_id = U256::from(1); - add_network(netuid, tempo, 0); - - register_ok_neuron(1, account_id, U256::from(2), 100000); - let neuron_uid: u16 = SubtensorModule::get_uid_for_net_and_hotkey( netuid, &U256::from(1) ).expect("Not registered."); - SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); - - register_ok_neuron(1, U256::from(3), U256::from(4), 300000); - SubtensorModule::set_min_allowed_weights(1, 2); - - // Should fail because we are only setting a single value and its not the self weight. - let weight_keys : Vec = vec![1]; // not weight. - let weight_values : Vec = vec![88]; // random value. - let result = SubtensorModule::set_weights(RuntimeOrigin::signed(account_id), 1, weight_keys, weight_values, 0); - assert_eq!(result, Err(Error::::NotSettingEnoughWeights.into())); - - // Shouldnt fail because we setting a single value but it is the self weight. - let weight_keys : Vec = vec![0]; // self weight. - let weight_values : Vec = vec![88]; // random value. - assert_ok!( SubtensorModule::set_weights(RuntimeOrigin::signed(account_id), 1 , weight_keys, weight_values, 0)) ; - - // Should pass because we are setting enough values. - let weight_keys : Vec = vec![0, 1]; // self weight. - let weight_values : Vec = vec![10, 10]; // random value. - SubtensorModule::set_min_allowed_weights(1, 1); - assert_ok!( SubtensorModule::set_weights(RuntimeOrigin::signed(account_id), 1, weight_keys, weight_values, 0)) ; - }); + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + let account_id = U256::from(1); + add_network(netuid, tempo, 0); + + register_ok_neuron(1, account_id, U256::from(2), 100000); + let neuron_uid: u16 = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(1)) + .expect("Not registered."); + SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); + + register_ok_neuron(1, U256::from(3), U256::from(4), 300000); + SubtensorModule::set_min_allowed_weights(1, 2); + + // Should fail because we are only setting a single value and its not the self weight. + let weight_keys: Vec = vec![1]; // not weight. + let weight_values: Vec = vec![88]; // random value. + let result = SubtensorModule::set_weights( + RuntimeOrigin::signed(account_id), + 1, + weight_keys, + weight_values, + 0, + ); + assert_eq!(result, Err(Error::::NotSettingEnoughWeights.into())); + + // Shouldnt fail because we setting a single value but it is the self weight. + let weight_keys: Vec = vec![0]; // self weight. + let weight_values: Vec = vec![88]; // random value. + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(account_id), + 1, + weight_keys, + weight_values, + 0 + )); + + // Should pass because we are setting enough values. + let weight_keys: Vec = vec![0, 1]; // self weight. + let weight_values: Vec = vec![10, 10]; // random value. + SubtensorModule::set_min_allowed_weights(1, 1); + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(account_id), + 1, + weight_keys, + weight_values, + 0 + )); + }); } // Tests that the weights set fails if you pass too many uids for the subnet #[test] fn test_set_weight_too_many_uids() { - new_test_ext().execute_with(|| { - - let netuid: u16 = 1; - let tempo: u16 = 13; - add_network(netuid, tempo, 0); - - register_ok_neuron(1, U256::from(1), U256::from(2), 100_000); - let neuron_uid: u16 = SubtensorModule::get_uid_for_net_and_hotkey( netuid, &U256::from(1) ).expect("Not registered."); - SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); - - register_ok_neuron(1, U256::from(3), U256::from(4), 300_000); - SubtensorModule::set_min_allowed_weights(1, 2); - - // Should fail because we are setting more weights than there are neurons. - let weight_keys : Vec = vec![0, 1, 2, 3, 4]; // more uids than neurons in subnet. - let weight_values : Vec = vec![88, 102, 303, 1212, 11]; // random value. - let result = SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(1)), 1, weight_keys, weight_values, 0); - assert_eq!(result, Err(Error::::TooManyUids.into())); - - // Shouldnt fail because we are setting less weights than there are neurons. - let weight_keys : Vec = vec![0, 1]; // Only on neurons that exist. - let weight_values : Vec = vec![10, 10]; // random value. - assert_ok!( SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(1)), 1 , weight_keys, weight_values, 0)) ; - }); + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + add_network(netuid, tempo, 0); + + register_ok_neuron(1, U256::from(1), U256::from(2), 100_000); + let neuron_uid: u16 = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(1)) + .expect("Not registered."); + SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); + + register_ok_neuron(1, U256::from(3), U256::from(4), 300_000); + SubtensorModule::set_min_allowed_weights(1, 2); + + // Should fail because we are setting more weights than there are neurons. + let weight_keys: Vec = vec![0, 1, 2, 3, 4]; // more uids than neurons in subnet. + let weight_values: Vec = vec![88, 102, 303, 1212, 11]; // random value. + let result = SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(1)), + 1, + weight_keys, + weight_values, + 0, + ); + assert_eq!(result, Err(Error::::TooManyUids.into())); + + // Shouldnt fail because we are setting less weights than there are neurons. + let weight_keys: Vec = vec![0, 1]; // Only on neurons that exist. + let weight_values: Vec = vec![10, 10]; // random value. + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(1)), + 1, + weight_keys, + weight_values, + 0 + )); + }); } // Tests that the weights set doesn't panic if you pass weights that sum to larger than u16 max. #[test] fn test_set_weights_sum_larger_than_u16_max() { - new_test_ext().execute_with(|| { - - let netuid: u16 = 1; - let tempo: u16 = 13; - add_network(netuid, tempo, 0); - - register_ok_neuron(1, U256::from(1), U256::from(2), 100_000); - let neuron_uid: u16 = SubtensorModule::get_uid_for_net_and_hotkey( netuid, &U256::from(1) ).expect("Not registered."); - SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); - - register_ok_neuron(1, U256::from(3), U256::from(4), 300_000); - SubtensorModule::set_min_allowed_weights(1, 2); - - - // Shouldn't fail because we are setting the right number of weights. - let weight_keys : Vec = vec![0, 1]; - let weight_values : Vec = vec![u16::MAX, u16::MAX]; - // sum of weights is larger than u16 max. - assert!( weight_values.iter().map(|x| *x as u64).sum::() > (u16::MAX as u64) ); - - let result = SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(1)), 1, weight_keys, weight_values, 0); - assert_ok!(result); - - // Get max-upscaled unnormalized weights. - let all_weights: Vec> = SubtensorModule::get_weights(netuid); - let weights_set: &Vec = &all_weights[neuron_uid as usize]; - assert_eq!( weights_set[0], I32F32::from_num(u16::MAX) ); - assert_eq!( weights_set[1], I32F32::from_num(u16::MAX) ); - }); + new_test_ext().execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + add_network(netuid, tempo, 0); + + register_ok_neuron(1, U256::from(1), U256::from(2), 100_000); + let neuron_uid: u16 = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &U256::from(1)) + .expect("Not registered."); + SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); + + register_ok_neuron(1, U256::from(3), U256::from(4), 300_000); + SubtensorModule::set_min_allowed_weights(1, 2); + + // Shouldn't fail because we are setting the right number of weights. + let weight_keys: Vec = vec![0, 1]; + let weight_values: Vec = vec![u16::MAX, u16::MAX]; + // sum of weights is larger than u16 max. + assert!(weight_values.iter().map(|x| *x as u64).sum::() > (u16::MAX as u64)); + + let result = SubtensorModule::set_weights( + RuntimeOrigin::signed(U256::from(1)), + 1, + weight_keys, + weight_values, + 0, + ); + assert_ok!(result); + + // Get max-upscaled unnormalized weights. + let all_weights: Vec> = SubtensorModule::get_weights(netuid); + let weights_set: &Vec = &all_weights[neuron_uid as usize]; + assert_eq!(weights_set[0], I32F32::from_num(u16::MAX)); + assert_eq!(weights_set[1], I32F32::from_num(u16::MAX)); + }); } /// Check _truthy_ path for self weight #[test] fn test_check_length_allows_singleton() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; + new_test_ext().execute_with(|| { + let netuid: u16 = 1; - let max_allowed: u16 = 1; - let min_allowed_weights = max_allowed; + let max_allowed: u16 = 1; + let min_allowed_weights = max_allowed; - SubtensorModule::set_min_allowed_weights(netuid, min_allowed_weights); + SubtensorModule::set_min_allowed_weights(netuid, min_allowed_weights); - let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| { id + 1 })); - let uid: u16 = uids[0].clone(); - let weights: Vec = Vec::from_iter((0..max_allowed).map(|id| { id + 1 })); + let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| id + 1)); + let uid: u16 = uids[0].clone(); + let weights: Vec = Vec::from_iter((0..max_allowed).map(|id| id + 1)); - let expected = true; - let result = SubtensorModule::check_length(netuid, uid, &uids, &weights); + let expected = true; + let result = SubtensorModule::check_length(netuid, uid, &uids, &weights); - assert_eq!( - expected, - result, - "Failed get expected result" - ); - }); + assert_eq!(expected, result, "Failed get expected result"); + }); } /// Check _truthy_ path for weights within allowed range #[test] fn test_check_length_weights_length_exceeds_min_allowed() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; + new_test_ext().execute_with(|| { + let netuid: u16 = 1; - let max_allowed: u16 = 3; - let min_allowed_weights = max_allowed; + let max_allowed: u16 = 3; + let min_allowed_weights = max_allowed; - SubtensorModule::set_min_allowed_weights(netuid, min_allowed_weights); + SubtensorModule::set_min_allowed_weights(netuid, min_allowed_weights); - let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| { id + 1 })); - let uid: u16 = uids[0].clone(); - let weights: Vec = Vec::from_iter((0..max_allowed).map(|id| { id + 1 })); + let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| id + 1)); + let uid: u16 = uids[0].clone(); + let weights: Vec = Vec::from_iter((0..max_allowed).map(|id| id + 1)); - let expected = true; - let result = SubtensorModule::check_length(netuid, uid, &uids, &weights); + let expected = true; + let result = SubtensorModule::check_length(netuid, uid, &uids, &weights); - assert_eq!( - expected, - result, - "Failed get expected result" - ); - }); + assert_eq!(expected, result, "Failed get expected result"); + }); } /// Check _falsey_ path for weights outside allowed range #[test] fn test_check_length_to_few_weights() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; + new_test_ext().execute_with(|| { + let netuid: u16 = 1; - let max_allowed: u16 = 3; - let min_allowed_weights = max_allowed + 1; + let max_allowed: u16 = 3; + let min_allowed_weights = max_allowed + 1; - SubtensorModule::set_min_allowed_weights(netuid, min_allowed_weights); + SubtensorModule::set_min_allowed_weights(netuid, min_allowed_weights); - let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| { id + 1 })); - let uid: u16 = uids[0].clone(); - let weights: Vec = Vec::from_iter((0..max_allowed).map(|id| { id + 1 })); + let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| id + 1)); + let uid: u16 = uids[0].clone(); + let weights: Vec = Vec::from_iter((0..max_allowed).map(|id| id + 1)); - let expected = false; - let result = SubtensorModule::check_length(netuid, uid, &uids, &weights); + let expected = false; + let result = SubtensorModule::check_length(netuid, uid, &uids, &weights); - assert_eq!( - expected, - result, - "Failed get expected result" - ); - }); + assert_eq!(expected, result, "Failed get expected result"); + }); } /// Check do nothing path #[test] fn test_normalize_weights_does_not_mutate_when_sum_is_zero() { - new_test_ext().execute_with(|| { - let max_allowed: u16 = 3; + new_test_ext().execute_with(|| { + let max_allowed: u16 = 3; - let weights: Vec = Vec::from_iter((0..max_allowed).map(|_| { 0 })); + let weights: Vec = Vec::from_iter((0..max_allowed).map(|_| 0)); - let expected = weights.clone(); - let result = SubtensorModule::normalize_weights(weights); + let expected = weights.clone(); + let result = SubtensorModule::normalize_weights(weights); - assert_eq!( - expected, - result, - "Failed get expected result when everything _should_ be fine" - ); - }); + assert_eq!( + expected, result, + "Failed get expected result when everything _should_ be fine" + ); + }); } /// Check do something path #[test] fn test_normalize_weights_does_not_mutate_when_sum_not_zero() { - new_test_ext().execute_with(|| { - let max_allowed: u16 = 3; + new_test_ext().execute_with(|| { + let max_allowed: u16 = 3; - let weights: Vec = Vec::from_iter((0..max_allowed).map(|weight| { weight })); + let weights: Vec = Vec::from_iter((0..max_allowed).map(|weight| weight)); - let expected = weights.clone(); - let result = SubtensorModule::normalize_weights(weights); + let expected = weights.clone(); + let result = SubtensorModule::normalize_weights(weights); - assert_eq!( - expected.len(), - result.len(), - "Length of weights changed?!" - ); - }); + assert_eq!(expected.len(), result.len(), "Length of weights changed?!"); + }); } /// Check _truthy_ path for weights length #[test] fn test_max_weight_limited_allow_self_weights_to_exceed_max_weight_limit() { - new_test_ext().execute_with(|| { - let max_allowed: u16 = 1; - - let netuid: u16 = 1; - let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| { id + 1 })); - let uid: u16 = uids[0].clone(); - let weights: Vec = vec![0]; - - let expected = true; - let result = SubtensorModule::max_weight_limited(netuid, uid, &uids, &weights); - - assert_eq!( - expected, - result, - "Failed get expected result when everything _should_ be fine" - ); - }); + new_test_ext().execute_with(|| { + let max_allowed: u16 = 1; + + let netuid: u16 = 1; + let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| id + 1)); + let uid: u16 = uids[0].clone(); + let weights: Vec = vec![0]; + + let expected = true; + let result = SubtensorModule::max_weight_limited(netuid, uid, &uids, &weights); + + assert_eq!( + expected, result, + "Failed get expected result when everything _should_ be fine" + ); + }); } /// Check _truthy_ path for max weight limit #[test] fn test_max_weight_limited_when_weight_limit_is_u16_max() { - new_test_ext().execute_with(|| { - let max_allowed: u16 = 3; - - let netuid: u16 = 1; - let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| { id + 1 })); - let uid: u16 = uids[0].clone(); - let weights: Vec = Vec::from_iter((0..max_allowed).map(|_id| { u16::MAX })); - - let expected = true; - let result = SubtensorModule::max_weight_limited(netuid, uid, &uids, &weights); - - assert_eq!( - expected, - result, - "Failed get expected result when everything _should_ be fine" - ); - }); + new_test_ext().execute_with(|| { + let max_allowed: u16 = 3; + + let netuid: u16 = 1; + let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| id + 1)); + let uid: u16 = uids[0].clone(); + let weights: Vec = Vec::from_iter((0..max_allowed).map(|_id| u16::MAX)); + + let expected = true; + let result = SubtensorModule::max_weight_limited(netuid, uid, &uids, &weights); + + assert_eq!( + expected, result, + "Failed get expected result when everything _should_ be fine" + ); + }); } /// Check _truthy_ path for max weight limit #[test] fn test_max_weight_limited_when_max_weight_is_within_limit() { - new_test_ext().execute_with(|| { - let max_allowed: u16 = 1; - let max_weight_limit = u16::MAX / 5; - - let netuid: u16 = 1; - let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| { id + 1 })); - let uid: u16 = uids[0].clone(); - let weights: Vec = Vec::from_iter((0..max_allowed).map(|id| { max_weight_limit - id })); - - SubtensorModule::set_max_weight_limit(netuid, max_weight_limit); - - let expected = true; - let result = SubtensorModule::max_weight_limited(netuid, uid, &uids, &weights); - - assert_eq!( - expected, - result, - "Failed get expected result when everything _should_ be fine" - ); - }); + new_test_ext().execute_with(|| { + let max_allowed: u16 = 1; + let max_weight_limit = u16::MAX / 5; + + let netuid: u16 = 1; + let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| id + 1)); + let uid: u16 = uids[0].clone(); + let weights: Vec = Vec::from_iter((0..max_allowed).map(|id| max_weight_limit - id)); + + SubtensorModule::set_max_weight_limit(netuid, max_weight_limit); + + let expected = true; + let result = SubtensorModule::max_weight_limited(netuid, uid, &uids, &weights); + + assert_eq!( + expected, result, + "Failed get expected result when everything _should_ be fine" + ); + }); } /// Check _falsey_ path #[test] fn test_max_weight_limited_when_guard_checks_are_not_triggered() { - new_test_ext().execute_with(|| { - let max_allowed: u16 = 3; - let max_weight_limit = u16::MAX / 5; - - let netuid: u16 = 1; - let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| { id + 1 })); - let uid: u16 = uids[0].clone(); - let weights: Vec = Vec::from_iter((0..max_allowed).map(|id| { max_weight_limit + id })); - - SubtensorModule::set_max_weight_limit(netuid, max_weight_limit); - - let expected = false; - let result = SubtensorModule::max_weight_limited(netuid, uid, &uids, &weights); - - assert_eq!( - expected, - result, - "Failed get expected result when guard-checks were not triggered" - ); - }); + new_test_ext().execute_with(|| { + let max_allowed: u16 = 3; + let max_weight_limit = u16::MAX / 5; + + let netuid: u16 = 1; + let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| id + 1)); + let uid: u16 = uids[0].clone(); + let weights: Vec = Vec::from_iter((0..max_allowed).map(|id| max_weight_limit + id)); + + SubtensorModule::set_max_weight_limit(netuid, max_weight_limit); + + let expected = false; + let result = SubtensorModule::max_weight_limited(netuid, uid, &uids, &weights); + + assert_eq!( + expected, result, + "Failed get expected result when guard-checks were not triggered" + ); + }); } /// Check _falsey_ path for weights length #[test] fn test_is_self_weight_weights_length_not_one() { - new_test_ext().execute_with(|| { - let max_allowed: u16 = 3; - - let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| { id + 1 })); - let uid: u16 = uids[0].clone(); - let weights: Vec = Vec::from_iter((0..max_allowed).map(|id| { id + 1 })); - - let expected = false; - let result = SubtensorModule::is_self_weight(uid, &uids, &weights); - - assert_eq!( - expected, - result, - "Failed get expected result when `weights.len() != 1`" - ); - }); + new_test_ext().execute_with(|| { + let max_allowed: u16 = 3; + + let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| id + 1)); + let uid: u16 = uids[0].clone(); + let weights: Vec = Vec::from_iter((0..max_allowed).map(|id| id + 1)); + + let expected = false; + let result = SubtensorModule::is_self_weight(uid, &uids, &weights); + + assert_eq!( + expected, result, + "Failed get expected result when `weights.len() != 1`" + ); + }); } /// Check _falsey_ path for uid vs uids[0] #[test] fn test_is_self_weight_uid_not_in_uids() { - new_test_ext().execute_with(|| { - let max_allowed: u16 = 3; - - let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| { id + 1 })); - let uid: u16 = uids[1].clone(); - let weights: Vec = vec![0]; - - let expected = false; - let result = SubtensorModule::is_self_weight(uid, &uids, &weights); - - assert_eq!( - expected, - result, - "Failed get expected result when `uid != uids[0]`" - ); - }); + new_test_ext().execute_with(|| { + let max_allowed: u16 = 3; + + let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| id + 1)); + let uid: u16 = uids[1].clone(); + let weights: Vec = vec![0]; + + let expected = false; + let result = SubtensorModule::is_self_weight(uid, &uids, &weights); + + assert_eq!( + expected, result, + "Failed get expected result when `uid != uids[0]`" + ); + }); } /// Check _truthy_ path /// @TODO: double-check if this really be desired behavior #[test] fn test_is_self_weight_uid_in_uids() { - new_test_ext().execute_with(|| { - let max_allowed: u16 = 1; - - let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| { id + 1 })); - let uid: u16 = uids[0].clone(); - let weights: Vec = vec![0]; - - let expected = true; - let result = SubtensorModule::is_self_weight(uid, &uids, &weights); - - assert_eq!( - expected, - result, - "Failed get expected result when everything _should_ be fine" - ); - }); + new_test_ext().execute_with(|| { + let max_allowed: u16 = 1; + + let uids: Vec = Vec::from_iter((0..max_allowed).map(|id| id + 1)); + let uid: u16 = uids[0].clone(); + let weights: Vec = vec![0]; + + let expected = true; + let result = SubtensorModule::is_self_weight(uid, &uids, &weights); + + assert_eq!( + expected, result, + "Failed get expected result when everything _should_ be fine" + ); + }); } /// Check _truthy_ path #[test] fn test_check_len_uids_within_allowed_within_network_pool() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; + new_test_ext().execute_with(|| { + let netuid: u16 = 1; - let tempo: u16 = 13; - let modality: u16 = 0; + let tempo: u16 = 13; + let modality: u16 = 0; - let max_registrations_per_block: u16 = 100; + let max_registrations_per_block: u16 = 100; - add_network(netuid, tempo, modality); + add_network(netuid, tempo, modality); - /* @TODO: use a loop maybe */ - register_ok_neuron(netuid, U256::from(1), U256::from(1), 0); - register_ok_neuron(netuid, U256::from(3), U256::from(3), 65555); - register_ok_neuron(netuid, U256::from(5), U256::from(5), 75555); - let max_allowed: u16 = SubtensorModule::get_subnetwork_n(netuid); + /* @TODO: use a loop maybe */ + register_ok_neuron(netuid, U256::from(1), U256::from(1), 0); + register_ok_neuron(netuid, U256::from(3), U256::from(3), 65555); + register_ok_neuron(netuid, U256::from(5), U256::from(5), 75555); + let max_allowed: u16 = SubtensorModule::get_subnetwork_n(netuid); - SubtensorModule::set_max_allowed_uids(netuid, max_allowed); - SubtensorModule::set_max_registrations_per_block(netuid, max_registrations_per_block); + SubtensorModule::set_max_allowed_uids(netuid, max_allowed); + SubtensorModule::set_max_registrations_per_block(netuid, max_registrations_per_block); - let uids: Vec = Vec::from_iter((0..max_allowed).map(|uid| { uid })); + let uids: Vec = Vec::from_iter((0..max_allowed).map(|uid| uid)); - let expected = true; - let result = SubtensorModule::check_len_uids_within_allowed(netuid, &uids); - assert_eq!(expected, result, "netuid network length and uids length incompatible"); - }); + let expected = true; + let result = SubtensorModule::check_len_uids_within_allowed(netuid, &uids); + assert_eq!( + expected, result, + "netuid network length and uids length incompatible" + ); + }); } /// Check _falsey_ path #[test] fn test_check_len_uids_within_allowed_not_within_network_pool() { - new_test_ext().execute_with(|| { - let netuid: u16 = 1; + new_test_ext().execute_with(|| { + let netuid: u16 = 1; - let tempo: u16 = 13; - let modality: u16 = 0; + let tempo: u16 = 13; + let modality: u16 = 0; - let max_registrations_per_block: u16 = 100; + let max_registrations_per_block: u16 = 100; - add_network(netuid, tempo, modality); + add_network(netuid, tempo, modality); - /* @TODO: use a loop maybe */ - register_ok_neuron(netuid, U256::from(1), U256::from(1), 0); - register_ok_neuron(netuid, U256::from(3), U256::from(3), 65555); - register_ok_neuron(netuid, U256::from(5), U256::from(5), 75555); - let max_allowed: u16 = SubtensorModule::get_subnetwork_n(netuid); + /* @TODO: use a loop maybe */ + register_ok_neuron(netuid, U256::from(1), U256::from(1), 0); + register_ok_neuron(netuid, U256::from(3), U256::from(3), 65555); + register_ok_neuron(netuid, U256::from(5), U256::from(5), 75555); + let max_allowed: u16 = SubtensorModule::get_subnetwork_n(netuid); - SubtensorModule::set_max_allowed_uids(netuid, max_allowed); - SubtensorModule::set_max_registrations_per_block(netuid, max_registrations_per_block); + SubtensorModule::set_max_allowed_uids(netuid, max_allowed); + SubtensorModule::set_max_registrations_per_block(netuid, max_registrations_per_block); - let uids: Vec = Vec::from_iter((0..(max_allowed + 1)).map(|uid| { uid })); + let uids: Vec = Vec::from_iter((0..(max_allowed + 1)).map(|uid| uid)); - let expected = false; - let result = SubtensorModule::check_len_uids_within_allowed(netuid, &uids); - assert_eq!(expected, result, "Failed to detect incompatible uids for network"); - }); + let expected = false; + let result = SubtensorModule::check_len_uids_within_allowed(netuid, &uids); + assert_eq!( + expected, result, + "Failed to detect incompatible uids for network" + ); + }); } diff --git a/runtime/build.rs b/runtime/build.rs index c03d618535..8f021e8381 100644 --- a/runtime/build.rs +++ b/runtime/build.rs @@ -1,10 +1,10 @@ fn main() { - #[cfg(feature = "std")] - { - substrate_wasm_builder::WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build(); - } + #[cfg(feature = "std")] + { + substrate_wasm_builder::WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build(); + } } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index b06cf7823c..55cc1813a0 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -9,44 +9,46 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); use codec::Encode; use pallet_grandpa::{ - fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, + fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, }; -use frame_support::pallet_prelude::{Get, DispatchResult}; -use frame_system::{EnsureRoot, EnsureNever, RawOrigin}; +use frame_support::pallet_prelude::{DispatchResult, Get}; +use frame_system::{EnsureNever, EnsureRoot, RawOrigin}; use smallvec::smallvec; use sp_api::impl_runtime_apis; use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, - traits::{ - AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, One, Verify, - }, - transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, MultiSignature, + create_runtime_str, generic, impl_opaque_keys, + traits::{ + AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, One, Verify, + }, + transaction_validity::{TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, MultiSignature, }; -use sp_std::prelude::*; use sp_std::cmp::Ordering; +use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; // A few exports that help ease life for downstream crates. pub use frame_support::{ - construct_runtime, parameter_types, - traits::{ - ConstU128, ConstU32, ConstU64, ConstU8, KeyOwnerProofSystem, Randomness, StorageInfo, PrivilegeCmp - }, - weights::{ - constants::{ - BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND, - }, - IdentityFee, Weight, WeightToFeeCoefficients, WeightToFeeCoefficient, WeightToFeePolynomial - }, - StorageValue, + construct_runtime, parameter_types, + traits::{ + ConstU128, ConstU32, ConstU64, ConstU8, KeyOwnerProofSystem, PrivilegeCmp, Randomness, + StorageInfo, + }, + weights::{ + constants::{ + BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND, + }, + IdentityFee, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, + WeightToFeePolynomial, + }, + StorageValue, }; pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; @@ -86,42 +88,42 @@ type MemberCount = u32; // of data like extrinsics, allowing for them to continue syncing the network through upgrades // to even the core data structures. pub mod opaque { - use super::*; - - pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; - - // Opaque block header type. - pub type Header = generic::Header; - // Opaque block type. - pub type Block = generic::Block; - // Opaque block identifier type. - pub type BlockId = generic::BlockId; - - impl_opaque_keys! { - pub struct SessionKeys { - pub aura: Aura, - pub grandpa: Grandpa, - } - } + use super::*; + + pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; + + // Opaque block header type. + pub type Header = generic::Header; + // Opaque block type. + pub type Block = generic::Block; + // Opaque block identifier type. + pub type BlockId = generic::BlockId; + + impl_opaque_keys! { + pub struct SessionKeys { + pub aura: Aura, + pub grandpa: Grandpa, + } + } } // To learn more about runtime versioning, see: // https://docs.substrate.io/main-docs/build/upgrade#runtime-versioning #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("node-subtensor"), - impl_name: create_runtime_str!("node-subtensor"), - authoring_version: 1, - // The version of the runtime specification. A full node will not attempt to use its native - // runtime in substitute for the on-chain Wasm runtime unless all of `spec_name`, - // `spec_version`, and `authoring_version` are the same between Wasm and native. - // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use - // the compatible custom types. - spec_version: 127, - impl_version: 1, - apis: RUNTIME_API_VERSIONS, - transaction_version: 1, - state_version: 1, + spec_name: create_runtime_str!("node-subtensor"), + impl_name: create_runtime_str!("node-subtensor"), + authoring_version: 1, + // The version of the runtime specification. A full node will not attempt to use its native + // runtime in substitute for the on-chain Wasm runtime unless all of `spec_name`, + // `spec_version`, and `authoring_version` are the same between Wasm and native. + // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use + // the compatible custom types. + spec_version: 127, + impl_version: 1, + apis: RUNTIME_API_VERSIONS, + transaction_version: 1, + state_version: 1, }; /// This determines the average expected block time that we are targeting. @@ -144,113 +146,116 @@ pub const DAYS: BlockNumber = HOURS * 24; // The version information used to identify this runtime when compiled natively. #[cfg(feature = "std")] pub fn native_version() -> NativeVersion { - NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } + NativeVersion { + runtime_version: VERSION, + can_author_with: Default::default(), + } } const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); parameter_types! { - pub const BlockHashCount: BlockNumber = 2400; - pub const Version: RuntimeVersion = VERSION; - // We allow for 2 seconds of compute with a 6 second average block time. - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::with_sensible_defaults( - Weight::from_parts(4u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX), - NORMAL_DISPATCH_RATIO, - ); - pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength - ::max_with_normal_ratio(10 * 1024 * 1024, NORMAL_DISPATCH_RATIO); - pub const SS58Prefix: u8 = 42; + pub const BlockHashCount: BlockNumber = 2400; + pub const Version: RuntimeVersion = VERSION; + // We allow for 2 seconds of compute with a 6 second average block time. + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::with_sensible_defaults( + Weight::from_parts(4u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX), + NORMAL_DISPATCH_RATIO, + ); + pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength + ::max_with_normal_ratio(10 * 1024 * 1024, NORMAL_DISPATCH_RATIO); + pub const SS58Prefix: u8 = 42; } // Configure FRAME pallets to include in runtime. impl frame_system::Config for Runtime { - // The basic call filter to use in dispatchable. - type BaseCallFilter = frame_support::traits::Everything; - // Block & extrinsics weights: base values and limits. - type BlockWeights = BlockWeights; - // The maximum length of a block (in bytes). - type BlockLength = BlockLength; - // The identifier used to distinguish between accounts. - type AccountId = AccountId; - // The aggregated dispatch type that is available for extrinsics. - type RuntimeCall = RuntimeCall; - // The lookup mechanism to get account ID from whatever is passed in dispatchers. - type Lookup = AccountIdLookup; - // The index type for storing how many extrinsics an account has signed. - type Index = Index; - // The index type for blocks. - type BlockNumber = BlockNumber; - // The type for hashing blocks and tries. - type Hash = Hash; - // The hashing algorithm used. - type Hashing = BlakeTwo256; - // The header type. - type Header = generic::Header; - // The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; - // The ubiquitous origin type. - type RuntimeOrigin = RuntimeOrigin; - // Maximum number of block number to block hash mappings to keep (oldest pruned first). - type BlockHashCount = BlockHashCount; - // The weight of database operations that the runtime can invoke. - type DbWeight = RocksDbWeight; - // Version of the runtime. - type Version = Version; - // Converts a module to the index of the module in `construct_runtime!`. - // - // This type is being generated by `construct_runtime!`. - type PalletInfo = PalletInfo; - // What to do if a new account is created. - type OnNewAccount = (); - // What to do if an account is fully reaped from the system. - type OnKilledAccount = (); - // The data to be stored in an account. - type AccountData = pallet_balances::AccountData; - // Weight information for the extrinsics of this pallet. - type SystemWeightInfo = (); - // This is used as an identifier of the chain. 42 is the generic substrate prefix. - type SS58Prefix = SS58Prefix; - // The set code logic, just the default since we're not a parachain. - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + // The basic call filter to use in dispatchable. + type BaseCallFilter = frame_support::traits::Everything; + // Block & extrinsics weights: base values and limits. + type BlockWeights = BlockWeights; + // The maximum length of a block (in bytes). + type BlockLength = BlockLength; + // The identifier used to distinguish between accounts. + type AccountId = AccountId; + // The aggregated dispatch type that is available for extrinsics. + type RuntimeCall = RuntimeCall; + // The lookup mechanism to get account ID from whatever is passed in dispatchers. + type Lookup = AccountIdLookup; + // The index type for storing how many extrinsics an account has signed. + type Index = Index; + // The index type for blocks. + type BlockNumber = BlockNumber; + // The type for hashing blocks and tries. + type Hash = Hash; + // The hashing algorithm used. + type Hashing = BlakeTwo256; + // The header type. + type Header = generic::Header; + // The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + // The ubiquitous origin type. + type RuntimeOrigin = RuntimeOrigin; + // Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = BlockHashCount; + // The weight of database operations that the runtime can invoke. + type DbWeight = RocksDbWeight; + // Version of the runtime. + type Version = Version; + // Converts a module to the index of the module in `construct_runtime!`. + // + // This type is being generated by `construct_runtime!`. + type PalletInfo = PalletInfo; + // What to do if a new account is created. + type OnNewAccount = (); + // What to do if an account is fully reaped from the system. + type OnKilledAccount = (); + // The data to be stored in an account. + type AccountData = pallet_balances::AccountData; + // Weight information for the extrinsics of this pallet. + type SystemWeightInfo = (); + // This is used as an identifier of the chain. 42 is the generic substrate prefix. + type SS58Prefix = SS58Prefix; + // The set code logic, just the default since we're not a parachain. + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; } impl pallet_insecure_randomness_collective_flip::Config for Runtime {} impl pallet_aura::Config for Runtime { - type AuthorityId = AuraId; - type DisabledValidators = (); - type MaxAuthorities = ConstU32<32>; + type AuthorityId = AuraId; + type DisabledValidators = (); + type MaxAuthorities = ConstU32<32>; } impl pallet_grandpa::Config for Runtime { - type RuntimeEvent = RuntimeEvent; + type RuntimeEvent = RuntimeEvent; - type KeyOwnerProofSystem = (); + type KeyOwnerProofSystem = (); - type KeyOwnerProof = - >::Proof; + type KeyOwnerProof = + >::Proof; - type KeyOwnerIdentification = >::IdentificationTuple; + type KeyOwnerIdentification = >::IdentificationTuple; - type HandleEquivocation = (); + type HandleEquivocation = (); - type WeightInfo = (); - type MaxAuthorities = ConstU32<32>; - type MaxSetIdSessionEntries = ConstU64<0>; + type WeightInfo = (); + type MaxAuthorities = ConstU32<32>; + type MaxSetIdSessionEntries = ConstU64<0>; } impl pallet_timestamp::Config for Runtime { - // A timestamp: milliseconds since the unix epoch. - type Moment = u64; - type OnTimestampSet = Aura; - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; - type WeightInfo = (); + // A timestamp: milliseconds since the unix epoch. + type Moment = u64; + type OnTimestampSet = Aura; + type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; + type WeightInfo = (); } impl pallet_utility::Config for Runtime { @@ -264,278 +269,294 @@ impl pallet_utility::Config for Runtime { pub const EXISTENTIAL_DEPOSIT: u64 = 500; impl pallet_balances::Config for Runtime { - type MaxLocks = ConstU32<50>; - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - // The type for recording an account's balance. - type Balance = Balance; - // The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ConstU64; - type AccountStore = System; - type WeightInfo = pallet_balances::weights::SubstrateWeight; + type MaxLocks = ConstU32<50>; + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + // The type for recording an account's balance. + type Balance = Balance; + // The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ConstU64; + type AccountStore = System; + type WeightInfo = pallet_balances::weights::SubstrateWeight; } pub struct LinearWeightToFee(sp_std::marker::PhantomData); impl WeightToFeePolynomial for LinearWeightToFee where - C: Get, + C: Get, { - type Balance = Balance; - - fn polynomial() -> WeightToFeeCoefficients { - let coefficient = WeightToFeeCoefficient { - coeff_integer: 0, - coeff_frac: Perbill::from_parts(1), - negative: false, - degree: 1, - }; - - smallvec!(coefficient) - } + type Balance = Balance; + + fn polynomial() -> WeightToFeeCoefficients { + let coefficient = WeightToFeeCoefficient { + coeff_integer: 0, + coeff_frac: Perbill::from_parts(1), + negative: false, + degree: 1, + }; + + smallvec!(coefficient) + } } parameter_types! { - // Used with LinearWeightToFee conversion. - pub const FeeWeightRatio: u64 = 1; - pub const TransactionByteFee: u128 = 1; - pub FeeMultiplier: Multiplier = Multiplier::one(); + // Used with LinearWeightToFee conversion. + pub const FeeWeightRatio: u64 = 1; + pub const TransactionByteFee: u128 = 1; + pub FeeMultiplier: Multiplier = Multiplier::one(); } impl pallet_transaction_payment::Config for Runtime { - type RuntimeEvent = RuntimeEvent; + type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = CurrencyAdapter; - //type TransactionByteFee = TransactionByteFee; + type OnChargeTransaction = CurrencyAdapter; + //type TransactionByteFee = TransactionByteFee; - // Convert dispatch weight to a chargeable fee. - type WeightToFee = LinearWeightToFee; + // Convert dispatch weight to a chargeable fee. + type WeightToFee = LinearWeightToFee; - type FeeMultiplierUpdate = (); + type FeeMultiplierUpdate = (); - type OperationalFeeMultiplier = ConstU8<1>; + type OperationalFeeMultiplier = ConstU8<1>; - type LengthToFee = IdentityFee; - //type FeeMultiplierUpdate = ConstFeeMultiplier; + type LengthToFee = IdentityFee; + //type FeeMultiplierUpdate = ConstFeeMultiplier; } // Configure collective pallet for council parameter_types! { - pub const CouncilMotionDuration: BlockNumber = 12 * HOURS; - pub const CouncilMaxProposals: u32 = 10; - pub const CouncilMaxMembers: u32 = 3; + pub const CouncilMotionDuration: BlockNumber = 12 * HOURS; + pub const CouncilMaxProposals: u32 = 10; + pub const CouncilMaxMembers: u32 = 3; } // Configure collective pallet for Senate parameter_types! { - pub const SenateMaxMembers: u32 = 12; + pub const SenateMaxMembers: u32 = 12; } use pallet_collective::{CanPropose, CanVote, GetVotingMembers}; pub struct CanProposeToTriumvirate; impl CanPropose for CanProposeToTriumvirate { - fn can_propose(account: &AccountId) -> bool { - Triumvirate::is_member(account) - } + fn can_propose(account: &AccountId) -> bool { + Triumvirate::is_member(account) + } } pub struct CanVoteToTriumvirate; impl CanVote for CanVoteToTriumvirate { - fn can_vote(_: &AccountId) -> bool { - //Senate::is_member(account) - false // Disable voting from pallet_collective::vote - } + fn can_vote(_: &AccountId) -> bool { + //Senate::is_member(account) + false // Disable voting from pallet_collective::vote + } } -use pallet_subtensor::{MemberManagement, CollectiveInterface}; +use pallet_subtensor::{CollectiveInterface, MemberManagement}; pub struct ManageSenateMembers; impl MemberManagement for ManageSenateMembers { - fn add_member(account: &AccountId) -> DispatchResult { - let who = Address::Id( account.clone() ); - SenateMembers::add_member(RawOrigin::Root.into(), who) - } - - fn remove_member(account: &AccountId) -> DispatchResult { - let who = Address::Id( account.clone() ); - SenateMembers::remove_member(RawOrigin::Root.into(), who) - } - - fn swap_member(rm: &AccountId, add: &AccountId) -> DispatchResult { - let remove = Address::Id( rm.clone() ); - let add = Address::Id( add.clone() ); - - Triumvirate::remove_votes(rm)?; - SenateMembers::swap_member(RawOrigin::Root.into(), remove, add) - } - - fn is_member(account: &AccountId) -> bool { - SenateMembers::members().contains(account) - } - - fn members() -> Vec { - SenateMembers::members().into() - } - - fn max_members() -> u32 { - SenateMaxMembers::get() - } + fn add_member(account: &AccountId) -> DispatchResult { + let who = Address::Id(account.clone()); + SenateMembers::add_member(RawOrigin::Root.into(), who) + } + + fn remove_member(account: &AccountId) -> DispatchResult { + let who = Address::Id(account.clone()); + SenateMembers::remove_member(RawOrigin::Root.into(), who) + } + + fn swap_member(rm: &AccountId, add: &AccountId) -> DispatchResult { + let remove = Address::Id(rm.clone()); + let add = Address::Id(add.clone()); + + Triumvirate::remove_votes(rm)?; + SenateMembers::swap_member(RawOrigin::Root.into(), remove, add) + } + + fn is_member(account: &AccountId) -> bool { + SenateMembers::members().contains(account) + } + + fn members() -> Vec { + SenateMembers::members().into() + } + + fn max_members() -> u32 { + SenateMaxMembers::get() + } } pub struct GetSenateMemberCount; impl GetVotingMembers for GetSenateMemberCount { - fn get_count() -> MemberCount {SenateMembers::members().len() as u32} + fn get_count() -> MemberCount { + SenateMembers::members().len() as u32 + } } impl Get for GetSenateMemberCount { - fn get() -> MemberCount {SenateMaxMembers::get()} + fn get() -> MemberCount { + SenateMaxMembers::get() + } } pub struct TriumvirateVotes; impl CollectiveInterface for TriumvirateVotes { - fn remove_votes(hotkey: &AccountId) -> Result { - Triumvirate::remove_votes(hotkey) - } - - fn add_vote(hotkey: &AccountId, proposal: Hash, index: u32, approve: bool) -> Result { - Triumvirate::do_vote(hotkey.clone(), proposal, index, approve) - } + fn remove_votes(hotkey: &AccountId) -> Result { + Triumvirate::remove_votes(hotkey) + } + + fn add_vote( + hotkey: &AccountId, + proposal: Hash, + index: u32, + approve: bool, + ) -> Result { + Triumvirate::do_vote(hotkey.clone(), proposal, index, approve) + } } -type EnsureMajoritySenate = pallet_collective::EnsureProportionMoreThan; +type EnsureMajoritySenate = + pallet_collective::EnsureProportionMoreThan; // We call pallet_collective TriumvirateCollective type TriumvirateCollective = pallet_collective::Instance1; impl pallet_collective::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type Proposal = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type MotionDuration = CouncilMotionDuration; - type MaxProposals = CouncilMaxProposals; - type MaxMembers = GetSenateMemberCount; - type DefaultVote = pallet_collective::PrimeDefaultVote; - type WeightInfo = pallet_collective::weights::SubstrateWeight; - type SetMembersOrigin = EnsureNever; - type CanPropose = CanProposeToTriumvirate; - type CanVote = CanVoteToTriumvirate; - type GetVotingMembers = GetSenateMemberCount; + type RuntimeOrigin = RuntimeOrigin; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type MotionDuration = CouncilMotionDuration; + type MaxProposals = CouncilMaxProposals; + type MaxMembers = GetSenateMemberCount; + type DefaultVote = pallet_collective::PrimeDefaultVote; + type WeightInfo = pallet_collective::weights::SubstrateWeight; + type SetMembersOrigin = EnsureNever; + type CanPropose = CanProposeToTriumvirate; + type CanVote = CanVoteToTriumvirate; + type GetVotingMembers = GetSenateMemberCount; } // We call council members Triumvirate type TriumvirateMembership = pallet_membership::Instance1; impl pallet_membership::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type AddOrigin = EnsureRoot; - type RemoveOrigin = EnsureRoot; - type SwapOrigin = EnsureRoot; - type ResetOrigin = EnsureRoot; - type PrimeOrigin = EnsureRoot; - type MembershipInitialized = Triumvirate; - type MembershipChanged = Triumvirate; - type MaxMembers = CouncilMaxMembers; - type WeightInfo = pallet_membership::weights::SubstrateWeight; + type RuntimeEvent = RuntimeEvent; + type AddOrigin = EnsureRoot; + type RemoveOrigin = EnsureRoot; + type SwapOrigin = EnsureRoot; + type ResetOrigin = EnsureRoot; + type PrimeOrigin = EnsureRoot; + type MembershipInitialized = Triumvirate; + type MembershipChanged = Triumvirate; + type MaxMembers = CouncilMaxMembers; + type WeightInfo = pallet_membership::weights::SubstrateWeight; } // We call our top K delegates membership Senate type SenateMembership = pallet_membership::Instance2; impl pallet_membership::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type AddOrigin = EnsureRoot; - type RemoveOrigin = EnsureRoot; - type SwapOrigin = EnsureRoot; - type ResetOrigin = EnsureRoot; - type PrimeOrigin = EnsureRoot; - type MembershipInitialized = (); - type MembershipChanged = (); - type MaxMembers = SenateMaxMembers; - type WeightInfo = pallet_membership::weights::SubstrateWeight; + type RuntimeEvent = RuntimeEvent; + type AddOrigin = EnsureRoot; + type RemoveOrigin = EnsureRoot; + type SwapOrigin = EnsureRoot; + type ResetOrigin = EnsureRoot; + type PrimeOrigin = EnsureRoot; + type MembershipInitialized = (); + type MembershipChanged = (); + type MaxMembers = SenateMaxMembers; + type WeightInfo = pallet_membership::weights::SubstrateWeight; } impl pallet_sudo::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; } parameter_types! { - // One storage item; key size is 32; value is size 4+4+16+32 bytes = 56 bytes. - pub const DepositBase: Balance = (1) as Balance * 2_000 * 10_000_000 + (88 as Balance) * 100 * 1_000_000; - // Additional storage item size of 32 bytes. - pub const DepositFactor: Balance = (0) as Balance * 2_000 * 10_000_000 + (32 as Balance) * 100 * 1_000_000; - pub const MaxSignatories: u32 = 100; + // One storage item; key size is 32; value is size 4+4+16+32 bytes = 56 bytes. + pub const DepositBase: Balance = (1) as Balance * 2_000 * 10_000_000 + (88 as Balance) * 100 * 1_000_000; + // Additional storage item size of 32 bytes. + pub const DepositFactor: Balance = (0) as Balance * 2_000 * 10_000_000 + (32 as Balance) * 100 * 1_000_000; + pub const MaxSignatories: u32 = 100; } impl pallet_multisig::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type Currency = Balances; - type DepositBase = DepositBase; - type DepositFactor = DepositFactor; - type MaxSignatories = MaxSignatories; - type WeightInfo = pallet_multisig::weights::SubstrateWeight; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type DepositBase = DepositBase; + type DepositFactor = DepositFactor; + type MaxSignatories = MaxSignatories; + type WeightInfo = pallet_multisig::weights::SubstrateWeight; } parameter_types! { - pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * - BlockWeights::get().max_block; - pub const MaxScheduledPerBlock: u32 = 50; - pub const NoPreimagePostponement: Option = Some(10); + pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * + BlockWeights::get().max_block; + pub const MaxScheduledPerBlock: u32 = 50; + pub const NoPreimagePostponement: Option = Some(10); } /// Used the compare the privilege of an origin inside the scheduler. pub struct OriginPrivilegeCmp; impl PrivilegeCmp for OriginPrivilegeCmp { - fn cmp_privilege(left: &OriginCaller, right: &OriginCaller) -> Option { - if left == right { - return Some(Ordering::Equal) - } - - match (left, right) { - // Root is greater than anything. - (OriginCaller::system(frame_system::RawOrigin::Root), _) => Some(Ordering::Greater), - // Check which one has more yes votes. - ( - OriginCaller::Triumvirate(pallet_collective::RawOrigin::Members(l_yes_votes, l_count)), - OriginCaller::Triumvirate(pallet_collective::RawOrigin::Members(r_yes_votes, r_count)), // Equivalent to (l_yes_votes / l_count).cmp(&(r_yes_votes / r_count)) - ) => Some((l_yes_votes * r_count).cmp(&(r_yes_votes * l_count))), - // For every other origin we don't care, as they are not used for `ScheduleOrigin`. - _ => None, - } - } + fn cmp_privilege(left: &OriginCaller, right: &OriginCaller) -> Option { + if left == right { + return Some(Ordering::Equal); + } + + match (left, right) { + // Root is greater than anything. + (OriginCaller::system(frame_system::RawOrigin::Root), _) => Some(Ordering::Greater), + // Check which one has more yes votes. + ( + OriginCaller::Triumvirate(pallet_collective::RawOrigin::Members( + l_yes_votes, + l_count, + )), + OriginCaller::Triumvirate(pallet_collective::RawOrigin::Members( + r_yes_votes, + r_count, + )), // Equivalent to (l_yes_votes / l_count).cmp(&(r_yes_votes / r_count)) + ) => Some((l_yes_votes * r_count).cmp(&(r_yes_votes * l_count))), + // For every other origin we don't care, as they are not used for `ScheduleOrigin`. + _ => None, + } + } } impl pallet_scheduler::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeEvent = RuntimeEvent; - type PalletsOrigin = OriginCaller; - type RuntimeCall = RuntimeCall; - type MaximumWeight = MaximumSchedulerWeight; - type ScheduleOrigin = EnsureRoot; - type MaxScheduledPerBlock = MaxScheduledPerBlock; - type WeightInfo = pallet_scheduler::weights::SubstrateWeight; - type OriginPrivilegeCmp = OriginPrivilegeCmp; - type Preimages = Preimage; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type PalletsOrigin = OriginCaller; + type RuntimeCall = RuntimeCall; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureRoot; + type MaxScheduledPerBlock = MaxScheduledPerBlock; + type WeightInfo = pallet_scheduler::weights::SubstrateWeight; + type OriginPrivilegeCmp = OriginPrivilegeCmp; + type Preimages = Preimage; } parameter_types! { - pub const PreimageMaxSize: u32 = 4096 * 1024; - pub const PreimageBaseDeposit: Balance = (2) as Balance * 2_000 * 10_000_000 + (64 as Balance) * 100 * 1_000_000; - pub const PreimageByteDeposit: Balance = (0) as Balance * 2_000 * 10_000_000 + (1 as Balance) * 100 * 1_000_000; + pub const PreimageMaxSize: u32 = 4096 * 1024; + pub const PreimageBaseDeposit: Balance = (2) as Balance * 2_000 * 10_000_000 + (64 as Balance) * 100 * 1_000_000; + pub const PreimageByteDeposit: Balance = (0) as Balance * 2_000 * 10_000_000 + (1 as Balance) * 100 * 1_000_000; } impl pallet_preimage::Config for Runtime { - type WeightInfo = pallet_preimage::weights::SubstrateWeight; - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type ManagerOrigin = EnsureRoot; - type BaseDeposit = PreimageBaseDeposit; - type ByteDeposit = PreimageByteDeposit; + type WeightInfo = pallet_preimage::weights::SubstrateWeight; + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type BaseDeposit = PreimageBaseDeposit; + type ByteDeposit = PreimageByteDeposit; } // Configure the pallet subtensor. parameter_types! { - pub const SubtensorInitialRho: u16 = 10; - pub const SubtensorInitialKappa: u16 = 32_767; // 0.5 = 65535/2 + pub const SubtensorInitialRho: u16 = 10; + pub const SubtensorInitialKappa: u16 = 32_767; // 0.5 = 65535/2 pub const SubtensorInitialMaxAllowedUids: u16 = 4096; pub const SubtensorInitialIssuance: u64 = 0; pub const SubtensorInitialMinAllowedWeights: u16 = 1024; @@ -547,7 +568,7 @@ parameter_types! { pub const SubtensorInitialTempo: u16 = 99; pub const SubtensorInitialDifficulty: u64 = 10_000_000; pub const SubtensorInitialAdjustmentInterval: u16 = 100; - pub const SubtensorInitialAdjustmentAlpha: u64 = 0; // no weight to previous value. + pub const SubtensorInitialAdjustmentAlpha: u64 = 0; // no weight to previous value. pub const SubtensorInitialTargetRegistrationsPerInterval: u16 = 2; pub const SubtensorInitialImmunityPeriod: u16 = 4096; pub const SubtensorInitialActivityCutoff: u16 = 5000; @@ -558,81 +579,81 @@ parameter_types! { pub const SubtensorInitialWeightsVersionKey: u64 = 0; pub const SubtensorInitialMinDifficulty: u64 = 10_000_000; pub const SubtensorInitialMaxDifficulty: u64 = u64::MAX / 4; - pub const SubtensorInitialServingRateLimit: u64 = 50; - pub const SubtensorInitialBurn: u64 = 1_000_000_000; // 1 tao - pub const SubtensorInitialMinBurn: u64 = 1_000_000_000; // 1 tao - pub const SubtensorInitialMaxBurn: u64 = 100_000_000_000; // 100 tao - pub const SubtensorInitialTxRateLimit: u64 = 1000; - pub const SubtensorInitialRAORecycledForRegistration: u64 = 0; // 0 rao - pub const SubtensorInitialSenateRequiredStakePercentage: u64 = 1; // 1 percent of total stake + pub const SubtensorInitialServingRateLimit: u64 = 50; + pub const SubtensorInitialBurn: u64 = 1_000_000_000; // 1 tao + pub const SubtensorInitialMinBurn: u64 = 1_000_000_000; // 1 tao + pub const SubtensorInitialMaxBurn: u64 = 100_000_000_000; // 100 tao + pub const SubtensorInitialTxRateLimit: u64 = 1000; + pub const SubtensorInitialRAORecycledForRegistration: u64 = 0; // 0 rao + pub const SubtensorInitialSenateRequiredStakePercentage: u64 = 1; // 1 percent of total stake } impl pallet_subtensor::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type SudoRuntimeCall = RuntimeCall; - type Currency = Balances; - type CouncilOrigin = EnsureMajoritySenate; - type SenateMembers = ManageSenateMembers; - type TriumvirateInterface = TriumvirateVotes; - - type InitialRho = SubtensorInitialRho; - type InitialKappa = SubtensorInitialKappa; - type InitialMaxAllowedUids = SubtensorInitialMaxAllowedUids; - type InitialBondsMovingAverage = SubtensorInitialBondsMovingAverage; - type InitialIssuance = SubtensorInitialIssuance; - type InitialMinAllowedWeights = SubtensorInitialMinAllowedWeights; - type InitialEmissionValue = SubtensorInitialEmissionValue; - type InitialMaxWeightsLimit = SubtensorInitialMaxWeightsLimit; - type InitialValidatorPruneLen = SubtensorInitialValidatorPruneLen; - type InitialScalingLawPower = SubtensorInitialScalingLawPower; - type InitialTempo = SubtensorInitialTempo; - type InitialDifficulty = SubtensorInitialDifficulty; - type InitialAdjustmentInterval = SubtensorInitialAdjustmentInterval; - type InitialAdjustmentAlpha = SubtensorInitialAdjustmentAlpha; - type InitialTargetRegistrationsPerInterval = SubtensorInitialTargetRegistrationsPerInterval; - type InitialImmunityPeriod = SubtensorInitialImmunityPeriod; - type InitialActivityCutoff = SubtensorInitialActivityCutoff; - type InitialMaxRegistrationsPerBlock = SubtensorInitialMaxRegistrationsPerBlock; - type InitialPruningScore = SubtensorInitialPruningScore; - type InitialMaxAllowedValidators = SubtensorInitialMaxAllowedValidators; - type InitialDefaultTake = SubtensorInitialDefaultTake; - type InitialWeightsVersionKey = SubtensorInitialWeightsVersionKey; - type InitialMaxDifficulty = SubtensorInitialMaxDifficulty; - type InitialMinDifficulty = SubtensorInitialMinDifficulty; - type InitialServingRateLimit = SubtensorInitialServingRateLimit; - type InitialBurn = SubtensorInitialBurn; - type InitialMaxBurn = SubtensorInitialMaxBurn; - type InitialMinBurn = SubtensorInitialMinBurn; - type InitialTxRateLimit = SubtensorInitialTxRateLimit; - type InitialRAORecycledForRegistration = SubtensorInitialRAORecycledForRegistration; - type InitialSenateRequiredStakePercentage = SubtensorInitialSenateRequiredStakePercentage; + type RuntimeEvent = RuntimeEvent; + type SudoRuntimeCall = RuntimeCall; + type Currency = Balances; + type CouncilOrigin = EnsureMajoritySenate; + type SenateMembers = ManageSenateMembers; + type TriumvirateInterface = TriumvirateVotes; + + type InitialRho = SubtensorInitialRho; + type InitialKappa = SubtensorInitialKappa; + type InitialMaxAllowedUids = SubtensorInitialMaxAllowedUids; + type InitialBondsMovingAverage = SubtensorInitialBondsMovingAverage; + type InitialIssuance = SubtensorInitialIssuance; + type InitialMinAllowedWeights = SubtensorInitialMinAllowedWeights; + type InitialEmissionValue = SubtensorInitialEmissionValue; + type InitialMaxWeightsLimit = SubtensorInitialMaxWeightsLimit; + type InitialValidatorPruneLen = SubtensorInitialValidatorPruneLen; + type InitialScalingLawPower = SubtensorInitialScalingLawPower; + type InitialTempo = SubtensorInitialTempo; + type InitialDifficulty = SubtensorInitialDifficulty; + type InitialAdjustmentInterval = SubtensorInitialAdjustmentInterval; + type InitialAdjustmentAlpha = SubtensorInitialAdjustmentAlpha; + type InitialTargetRegistrationsPerInterval = SubtensorInitialTargetRegistrationsPerInterval; + type InitialImmunityPeriod = SubtensorInitialImmunityPeriod; + type InitialActivityCutoff = SubtensorInitialActivityCutoff; + type InitialMaxRegistrationsPerBlock = SubtensorInitialMaxRegistrationsPerBlock; + type InitialPruningScore = SubtensorInitialPruningScore; + type InitialMaxAllowedValidators = SubtensorInitialMaxAllowedValidators; + type InitialDefaultTake = SubtensorInitialDefaultTake; + type InitialWeightsVersionKey = SubtensorInitialWeightsVersionKey; + type InitialMaxDifficulty = SubtensorInitialMaxDifficulty; + type InitialMinDifficulty = SubtensorInitialMinDifficulty; + type InitialServingRateLimit = SubtensorInitialServingRateLimit; + type InitialBurn = SubtensorInitialBurn; + type InitialMaxBurn = SubtensorInitialMaxBurn; + type InitialMinBurn = SubtensorInitialMinBurn; + type InitialTxRateLimit = SubtensorInitialTxRateLimit; + type InitialRAORecycledForRegistration = SubtensorInitialRAORecycledForRegistration; + type InitialSenateRequiredStakePercentage = SubtensorInitialSenateRequiredStakePercentage; } // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( - pub struct Runtime - where - Block = Block, - NodeBlock = opaque::Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system, - RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip, - Timestamp: pallet_timestamp, - Aura: pallet_aura, - Grandpa: pallet_grandpa, - Balances: pallet_balances, - TransactionPayment: pallet_transaction_payment, - SubtensorModule: pallet_subtensor, - Triumvirate: pallet_collective::::{Pallet, Call, Storage, Origin, Event, Config}, - TriumvirateMembers: pallet_membership::::{Pallet, Call, Storage, Event, Config}, - SenateMembers: pallet_membership::::{Pallet, Call, Storage, Event, Config}, - Utility: pallet_utility, - Sudo: pallet_sudo, - Multisig: pallet_multisig, - Preimage: pallet_preimage, - Scheduler: pallet_scheduler - } + pub struct Runtime + where + Block = Block, + NodeBlock = opaque::Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system, + RandomnessCollectiveFlip: pallet_insecure_randomness_collective_flip, + Timestamp: pallet_timestamp, + Aura: pallet_aura, + Grandpa: pallet_grandpa, + Balances: pallet_balances, + TransactionPayment: pallet_transaction_payment, + SubtensorModule: pallet_subtensor, + Triumvirate: pallet_collective::::{Pallet, Call, Storage, Origin, Event, Config}, + TriumvirateMembers: pallet_membership::::{Pallet, Call, Storage, Event, Config}, + SenateMembers: pallet_membership::::{Pallet, Call, Storage, Event, Config}, + Utility: pallet_utility, + Sudo: pallet_sudo, + Multisig: pallet_multisig, + Preimage: pallet_preimage, + Scheduler: pallet_scheduler + } ); // The address format for describing accounts. @@ -643,29 +664,29 @@ pub type Header = generic::Header; pub type Block = generic::Block; // The SignedExtension to the basic transaction logic. pub type SignedExtra = ( - frame_system::CheckNonZeroSender, - frame_system::CheckSpecVersion, - frame_system::CheckTxVersion, - frame_system::CheckGenesis, - frame_system::CheckEra, - frame_system::CheckNonce, - frame_system::CheckWeight, - pallet_transaction_payment::ChargeTransactionPayment, - pallet_subtensor::SubtensorSignedExtension + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, + pallet_subtensor::SubtensorSignedExtension, ); // Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; // The payload being signed in transactions. pub type SignedPayload = generic::SignedPayload; // Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< - Runtime, - Block, - frame_system::ChainContext, - Runtime, - AllPalletsWithSystem, + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, >; #[cfg(feature = "runtime-benchmarks")] @@ -674,343 +695,343 @@ extern crate frame_benchmarking; #[cfg(feature = "runtime-benchmarks")] mod benches { - define_benchmarks!( - [frame_benchmarking, BaselineBench::] - [frame_system, SystemBench::] - [pallet_balances, Balances] - [pallet_subtensor, SubtensorModule] - [pallet_timestamp, Timestamp] - ); + define_benchmarks!( + [frame_benchmarking, BaselineBench::] + [frame_system, SystemBench::] + [pallet_balances, Balances] + [pallet_subtensor, SubtensorModule] + [pallet_timestamp, Timestamp] + ); } impl_runtime_apis! { - impl sp_api::Core for Runtime { - fn version() -> RuntimeVersion { - VERSION - } - - fn execute_block(block: Block) { - Executive::execute_block(block); - } - - fn initialize_block(header: &::Header) { - Executive::initialize_block(header) - } - } - - impl sp_api::Metadata for Runtime { - fn metadata() -> OpaqueMetadata { - OpaqueMetadata::new(Runtime::metadata().into()) - } - } - - impl sp_block_builder::BlockBuilder for Runtime { - fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { - Executive::apply_extrinsic(extrinsic) - } - - fn finalize_block() -> ::Header { - Executive::finalize_block() - } - - fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { - data.create_extrinsics() - } - - fn check_inherents( - block: Block, - data: sp_inherents::InherentData, - ) -> sp_inherents::CheckInherentsResult { - data.check_extrinsics(&block) - } - } - - impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { - fn validate_transaction( - source: TransactionSource, - tx: ::Extrinsic, - block_hash: ::Hash, - ) -> TransactionValidity { - Executive::validate_transaction(source, tx, block_hash) - } - } - - impl sp_offchain::OffchainWorkerApi for Runtime { - fn offchain_worker(header: &::Header) { - Executive::offchain_worker(header) - } - } - - impl sp_consensus_aura::AuraApi for Runtime { - fn slot_duration() -> sp_consensus_aura::SlotDuration { - sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration()) - } - - fn authorities() -> Vec { - Aura::authorities().into_inner() - } - } - - impl sp_session::SessionKeys for Runtime { - fn generate_session_keys(seed: Option>) -> Vec { - opaque::SessionKeys::generate(seed) - } - - fn decode_session_keys( - encoded: Vec, - ) -> Option, KeyTypeId)>> { - opaque::SessionKeys::decode_into_raw_public_keys(&encoded) - } - } - - impl fg_primitives::GrandpaApi for Runtime { - fn grandpa_authorities() -> GrandpaAuthorityList { - Grandpa::grandpa_authorities() - } - - fn current_set_id() -> fg_primitives::SetId { - Grandpa::current_set_id() - } - - fn submit_report_equivocation_unsigned_extrinsic( - _equivocation_proof: fg_primitives::EquivocationProof< - ::Hash, - NumberFor, - >, - _key_owner_proof: fg_primitives::OpaqueKeyOwnershipProof, - ) -> Option<()> { - None - } - - fn generate_key_ownership_proof( - _set_id: fg_primitives::SetId, - _authority_id: GrandpaId, - ) -> Option { - // NOTE: this is the only implementation possible since we've - // defined our key owner proof type as a bottom type (i.e. a type - // with no values). - None - } - } - - impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { - fn account_nonce(account: AccountId) -> Index { - System::account_nonce(account) - } - } - - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { - fn query_info( - uxt: ::Extrinsic, - len: u32, - ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { - TransactionPayment::query_info(uxt, len) - } - fn query_fee_details( - uxt: ::Extrinsic, - len: u32, - ) -> pallet_transaction_payment::FeeDetails { - TransactionPayment::query_fee_details(uxt, len) - } - fn query_weight_to_fee(weight: Weight) -> Balance { - TransactionPayment::weight_to_fee(weight) - } - fn query_length_to_fee(length: u32) -> Balance { - TransactionPayment::length_to_fee(length) - } - } - - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi - for Runtime - { - fn query_call_info( - call: RuntimeCall, - len: u32, - ) -> pallet_transaction_payment::RuntimeDispatchInfo { - TransactionPayment::query_call_info(call, len) - } - fn query_call_fee_details( - call: RuntimeCall, - len: u32, - ) -> pallet_transaction_payment::FeeDetails { - TransactionPayment::query_call_fee_details(call, len) - } - fn query_weight_to_fee(weight: Weight) -> Balance { - TransactionPayment::weight_to_fee(weight) - } - fn query_length_to_fee(length: u32) -> Balance { - TransactionPayment::length_to_fee(length) - } - } - - #[cfg(feature = "runtime-benchmarks")] - impl frame_benchmarking::Benchmark for Runtime { - fn benchmark_metadata(extra: bool) -> ( - Vec, - Vec, - ) { - use frame_benchmarking::{baseline, Benchmarking, BenchmarkList}; - use frame_support::traits::StorageInfoTrait; - use frame_system_benchmarking::Pallet as SystemBench; - use baseline::Pallet as BaselineBench; - - let mut list = Vec::::new(); - list_benchmarks!(list, extra); - - let storage_info = AllPalletsWithSystem::storage_info(); - - (list, storage_info) - } - - fn dispatch_benchmark( - config: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { - use frame_benchmarking::{baseline, Benchmarking, BenchmarkBatch, TrackedStorageKey}; - - use frame_system_benchmarking::Pallet as SystemBench; - use baseline::Pallet as BaselineBench; - - impl frame_system_benchmarking::Config for Runtime {} - impl baseline::Config for Runtime {} - - use frame_support::traits::WhitelistedStorageKeys; - let whitelist: Vec = AllPalletsWithSystem::whitelisted_storage_keys(); - - let mut batches = Vec::::new(); - let params = (&config, &whitelist); - add_benchmarks!(params, batches); - - Ok(batches) - } - } - - #[cfg(feature = "try-runtime")] - impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { - // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to - // have a backtrace here. If any of the pre/post migration checks fail, we shall stop - // right here and right now. - let weight = Executive::try_runtime_upgrade(checks).unwrap(); - (weight, BlockWeights::get().max_block) - } - - fn execute_block( - block: Block, - state_root_check: bool, - signature_check: bool, - select: frame_try_runtime::TryStateSelect - ) -> Weight { - // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to - // have a backtrace here. - Executive::try_execute_block(block, state_root_check, signature_check, select).expect("execute-block failed") - } - } - - impl subtensor_custom_rpc_runtime_api::DelegateInfoRuntimeApi for Runtime { - fn get_delegates() -> Vec { - let result = SubtensorModule::get_delegates(); - result.encode() - } - - fn get_delegate(delegate_account_vec: Vec) -> Vec { - let _result = SubtensorModule::get_delegate(delegate_account_vec); - if _result.is_some() { - let result = _result.expect("Could not get DelegateInfo"); - result.encode() - } else { - vec![] - } - } - - fn get_delegated(delegatee_account_vec: Vec) -> Vec { - let result = SubtensorModule::get_delegated(delegatee_account_vec); - result.encode() - } - } - - impl subtensor_custom_rpc_runtime_api::NeuronInfoRuntimeApi for Runtime { - fn get_neurons_lite(netuid: u16) -> Vec { - let result = SubtensorModule::get_neurons_lite(netuid); - result.encode() - } - - fn get_neuron_lite(netuid: u16, uid: u16) -> Vec { - let _result = SubtensorModule::get_neuron_lite(netuid, uid); - if _result.is_some() { - let result = _result.expect("Could not get NeuronInfoLite"); - result.encode() - } else { - vec![] - } - } - - fn get_neurons(netuid: u16) -> Vec { - let result = SubtensorModule::get_neurons(netuid); - result.encode() - } - - fn get_neuron(netuid: u16, uid: u16) -> Vec { - let _result = SubtensorModule::get_neuron(netuid, uid); - if _result.is_some() { - let result = _result.expect("Could not get NeuronInfo"); - result.encode() - } else { - vec![] - } - } - } - - impl subtensor_custom_rpc_runtime_api::SubnetInfoRuntimeApi for Runtime { - fn get_subnet_info(netuid: u16) -> Vec { - let _result = SubtensorModule::get_subnet_info(netuid); - if _result.is_some() { - let result = _result.expect("Could not get SubnetInfo"); - result.encode() - } else { - vec![] - } - } - - fn get_subnets_info() -> Vec { - let result = SubtensorModule::get_subnets_info(); - result.encode() - } - } + impl sp_api::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + Executive::execute_block(block); + } + + fn initialize_block(header: &::Header) { + Executive::initialize_block(header) + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + OpaqueMetadata::new(Runtime::metadata().into()) + } + } + + impl sp_block_builder::BlockBuilder for Runtime { + fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { + Executive::apply_extrinsic(extrinsic) + } + + fn finalize_block() -> ::Header { + Executive::finalize_block() + } + + fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { + data.create_extrinsics() + } + + fn check_inherents( + block: Block, + data: sp_inherents::InherentData, + ) -> sp_inherents::CheckInherentsResult { + data.check_extrinsics(&block) + } + } + + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + tx: ::Extrinsic, + block_hash: ::Hash, + ) -> TransactionValidity { + Executive::validate_transaction(source, tx, block_hash) + } + } + + impl sp_offchain::OffchainWorkerApi for Runtime { + fn offchain_worker(header: &::Header) { + Executive::offchain_worker(header) + } + } + + impl sp_consensus_aura::AuraApi for Runtime { + fn slot_duration() -> sp_consensus_aura::SlotDuration { + sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration()) + } + + fn authorities() -> Vec { + Aura::authorities().into_inner() + } + } + + impl sp_session::SessionKeys for Runtime { + fn generate_session_keys(seed: Option>) -> Vec { + opaque::SessionKeys::generate(seed) + } + + fn decode_session_keys( + encoded: Vec, + ) -> Option, KeyTypeId)>> { + opaque::SessionKeys::decode_into_raw_public_keys(&encoded) + } + } + + impl fg_primitives::GrandpaApi for Runtime { + fn grandpa_authorities() -> GrandpaAuthorityList { + Grandpa::grandpa_authorities() + } + + fn current_set_id() -> fg_primitives::SetId { + Grandpa::current_set_id() + } + + fn submit_report_equivocation_unsigned_extrinsic( + _equivocation_proof: fg_primitives::EquivocationProof< + ::Hash, + NumberFor, + >, + _key_owner_proof: fg_primitives::OpaqueKeyOwnershipProof, + ) -> Option<()> { + None + } + + fn generate_key_ownership_proof( + _set_id: fg_primitives::SetId, + _authority_id: GrandpaId, + ) -> Option { + // NOTE: this is the only implementation possible since we've + // defined our key owner proof type as a bottom type (i.e. a type + // with no values). + None + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Index { + System::account_nonce(account) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { + fn query_info( + uxt: ::Extrinsic, + len: u32, + ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + fn query_fee_details( + uxt: ::Extrinsic, + len: u32, + ) -> pallet_transaction_payment::FeeDetails { + TransactionPayment::query_fee_details(uxt, len) + } + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi + for Runtime + { + fn query_call_info( + call: RuntimeCall, + len: u32, + ) -> pallet_transaction_payment::RuntimeDispatchInfo { + TransactionPayment::query_call_info(call, len) + } + fn query_call_fee_details( + call: RuntimeCall, + len: u32, + ) -> pallet_transaction_payment::FeeDetails { + TransactionPayment::query_call_fee_details(call, len) + } + fn query_weight_to_fee(weight: Weight) -> Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> Balance { + TransactionPayment::length_to_fee(length) + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + fn benchmark_metadata(extra: bool) -> ( + Vec, + Vec, + ) { + use frame_benchmarking::{baseline, Benchmarking, BenchmarkList}; + use frame_support::traits::StorageInfoTrait; + use frame_system_benchmarking::Pallet as SystemBench; + use baseline::Pallet as BaselineBench; + + let mut list = Vec::::new(); + list_benchmarks!(list, extra); + + let storage_info = AllPalletsWithSystem::storage_info(); + + (list, storage_info) + } + + fn dispatch_benchmark( + config: frame_benchmarking::BenchmarkConfig + ) -> Result, sp_runtime::RuntimeString> { + use frame_benchmarking::{baseline, Benchmarking, BenchmarkBatch, TrackedStorageKey}; + + use frame_system_benchmarking::Pallet as SystemBench; + use baseline::Pallet as BaselineBench; + + impl frame_system_benchmarking::Config for Runtime {} + impl baseline::Config for Runtime {} + + use frame_support::traits::WhitelistedStorageKeys; + let whitelist: Vec = AllPalletsWithSystem::whitelisted_storage_keys(); + + let mut batches = Vec::::new(); + let params = (&config, &whitelist); + add_benchmarks!(params, batches); + + Ok(batches) + } + } + + #[cfg(feature = "try-runtime")] + impl frame_try_runtime::TryRuntime for Runtime { + fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { + // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to + // have a backtrace here. If any of the pre/post migration checks fail, we shall stop + // right here and right now. + let weight = Executive::try_runtime_upgrade(checks).unwrap(); + (weight, BlockWeights::get().max_block) + } + + fn execute_block( + block: Block, + state_root_check: bool, + signature_check: bool, + select: frame_try_runtime::TryStateSelect + ) -> Weight { + // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to + // have a backtrace here. + Executive::try_execute_block(block, state_root_check, signature_check, select).expect("execute-block failed") + } + } + + impl subtensor_custom_rpc_runtime_api::DelegateInfoRuntimeApi for Runtime { + fn get_delegates() -> Vec { + let result = SubtensorModule::get_delegates(); + result.encode() + } + + fn get_delegate(delegate_account_vec: Vec) -> Vec { + let _result = SubtensorModule::get_delegate(delegate_account_vec); + if _result.is_some() { + let result = _result.expect("Could not get DelegateInfo"); + result.encode() + } else { + vec![] + } + } + + fn get_delegated(delegatee_account_vec: Vec) -> Vec { + let result = SubtensorModule::get_delegated(delegatee_account_vec); + result.encode() + } + } + + impl subtensor_custom_rpc_runtime_api::NeuronInfoRuntimeApi for Runtime { + fn get_neurons_lite(netuid: u16) -> Vec { + let result = SubtensorModule::get_neurons_lite(netuid); + result.encode() + } + + fn get_neuron_lite(netuid: u16, uid: u16) -> Vec { + let _result = SubtensorModule::get_neuron_lite(netuid, uid); + if _result.is_some() { + let result = _result.expect("Could not get NeuronInfoLite"); + result.encode() + } else { + vec![] + } + } + + fn get_neurons(netuid: u16) -> Vec { + let result = SubtensorModule::get_neurons(netuid); + result.encode() + } + + fn get_neuron(netuid: u16, uid: u16) -> Vec { + let _result = SubtensorModule::get_neuron(netuid, uid); + if _result.is_some() { + let result = _result.expect("Could not get NeuronInfo"); + result.encode() + } else { + vec![] + } + } + } + + impl subtensor_custom_rpc_runtime_api::SubnetInfoRuntimeApi for Runtime { + fn get_subnet_info(netuid: u16) -> Vec { + let _result = SubtensorModule::get_subnet_info(netuid); + if _result.is_some() { + let result = _result.expect("Could not get SubnetInfo"); + result.encode() + } else { + vec![] + } + } + + fn get_subnets_info() -> Vec { + let result = SubtensorModule::get_subnets_info(); + result.encode() + } + } } #[cfg(test)] mod tests { - use super::*; - use frame_support::traits::WhitelistedStorageKeys; - use sp_core::hexdisplay::HexDisplay; - use std::collections::HashSet; - - #[test] - fn check_whitelist() { - let whitelist: HashSet = AllPalletsWithSystem::whitelisted_storage_keys() - .iter() - .map(|e| HexDisplay::from(&e.key).to_string()) - .collect(); - - // Block Number - assert!( - whitelist.contains("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac") - ); - // Total Issuance - assert!( - whitelist.contains("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80") - ); - // Execution Phase - assert!( - whitelist.contains("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a") - ); - // Event Count - assert!( - whitelist.contains("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850") - ); - // System Events - assert!( - whitelist.contains("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7") - ); - } -} \ No newline at end of file + use super::*; + use frame_support::traits::WhitelistedStorageKeys; + use sp_core::hexdisplay::HexDisplay; + use std::collections::HashSet; + + #[test] + fn check_whitelist() { + let whitelist: HashSet = AllPalletsWithSystem::whitelisted_storage_keys() + .iter() + .map(|e| HexDisplay::from(&e.key).to_string()) + .collect(); + + // Block Number + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac") + ); + // Total Issuance + assert!( + whitelist.contains("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80") + ); + // Execution Phase + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a") + ); + // Event Count + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850") + ); + // System Events + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7") + ); + } +}