From b5e9e81973a860f456c9514dcdd796fe661584fd Mon Sep 17 00:00:00 2001 From: JZ <115138297+Supremesource@users.noreply.github.com> Date: Mon, 18 Mar 2024 20:06:20 +0100 Subject: [PATCH] refac(pallets/subspace): making code more robust (#38) * improved test loggin * Refac: fixing commune * WIP: middle of major refactor, dangerous code * Refac: making code more readable, cleaning up * fmt * Refac: applied PR suggestions * applying requested changes * refac: deleting unused variables, improving debug prints * fix: clippy errors --- pallets/subspace/src/global.rs | 18 +- pallets/subspace/src/lib.rs | 171 +++---- pallets/subspace/src/math.rs | 2 +- pallets/subspace/src/module.rs | 53 +- pallets/subspace/src/profit_share.rs | 65 +-- pallets/subspace/src/registration.rs | 82 ++-- pallets/subspace/src/staking.rs | 237 ++++----- pallets/subspace/src/step.rs | 531 +++++++++++++-------- pallets/subspace/src/subnet.rs | 85 ++-- pallets/subspace/src/voting.rs | 8 +- pallets/subspace/src/weights.rs | 143 ++---- pallets/subspace/tests/delegate_staking.rs | 44 +- pallets/subspace/tests/mock.rs | 4 +- pallets/subspace/tests/profit_share.rs | 27 +- pallets/subspace/tests/registration.rs | 19 +- pallets/subspace/tests/staking.rs | 44 +- pallets/subspace/tests/step.rs | 109 ++--- pallets/subspace/tests/subnets.rs | 39 +- pallets/subspace/tests/voting.rs | 27 +- pallets/subspace/tests/weights.rs | 105 +--- 20 files changed, 850 insertions(+), 963 deletions(-) diff --git a/pallets/subspace/src/global.rs b/pallets/subspace/src/global.rs index cd269cb52..faf1b4bd5 100644 --- a/pallets/subspace/src/global.rs +++ b/pallets/subspace/src/global.rs @@ -31,8 +31,7 @@ impl Pallet { } } - // TODO: make sure there are checks for all values - pub fn check_global_params(params: GlobalParams) -> DispatchResult { + pub fn check_global_params(params: &GlobalParams) -> DispatchResult { // checks if params are valid let old_params = Self::global_params(); @@ -95,10 +94,23 @@ impl Pallet { Error::::InvalidMaxBurn ); + ensure!( + params.target_registrations_per_interval > 0, + Error::::InvalidTargetRegistrationsPerInterval + ); + + ensure!( + params.max_allowed_weights > 0, + Error::::InvalidMaxAllowedWeights + ); + Ok(()) } pub fn set_global_params(params: GlobalParams) { + // Check if the params are valid + Self::check_global_params(¶ms).expect("global params are invalid"); + Self::set_global_max_name_length(params.max_name_length); Self::set_global_max_allowed_subnets(params.max_allowed_subnets); Self::set_max_allowed_modules(params.max_allowed_modules); @@ -165,7 +177,7 @@ impl Pallet { VoteModeGlobal::::get() } pub fn get_burn_rate() -> u16 { - BurnRate::::get().min(100) + BurnRate::::get() } pub fn get_burn() -> u64 { diff --git a/pallets/subspace/src/lib.rs b/pallets/subspace/src/lib.rs index 29bdbc2a7..d32074aa6 100644 --- a/pallets/subspace/src/lib.rs +++ b/pallets/subspace/src/lib.rs @@ -24,12 +24,6 @@ use sp_runtime::{ }; use sp_std::marker::PhantomData; -// ============================ -// ==== Benchmark Imports ===== -// ============================ -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking; - pub mod autogen_weights; pub use autogen_weights::WeightInfo; @@ -50,6 +44,8 @@ mod subnet; mod voting; mod weights; +// TODO: better error handling in whole file + #[frame_support::pallet] pub mod pallet { #![allow( @@ -585,28 +581,6 @@ pub mod pallet { pub(super) type Uids = StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, u16, OptionQuery>; - #[pallet::storage] // --- DMAP ( netuid, module_key ) --> uid - pub(super) type Key2Controller = StorageDoubleMap< - _, - Identity, - T::AccountId, - Blake2_128Concat, - T::AccountId, - u16, - OptionQuery, - >; - - #[pallet::storage] // --- DMAP ( netuid, module_key ) --> uid - pub(super) type Controller2Keys = StorageDoubleMap< - _, - Identity, - T::AccountId, - Blake2_128Concat, - Vec, - u16, - OptionQuery, - >; - #[pallet::type_value] pub fn DefaultKey() -> T::AccountId { T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()).unwrap() @@ -712,16 +686,6 @@ pub mod pallet { #[pallet::storage] // --- MAP ( netuid ) --> subnet_total_stake pub type TotalStake = StorageMap<_, Identity, u16, u64, ValueQuery>; - // LOAN VARIABLES - - #[pallet::storage] // --- DMAP ( netuid, module_key ) --> Vec<(delegater, stake )> | Returns the list of delegates - pub type LoanTo = - StorageMap<_, Identity, T::AccountId, Vec<(T::AccountId, u64)>, ValueQuery>; - - #[pallet::storage] // --- DMAP ( netuid, module_key ) --> Vec<(delegater, stake )> | Returns the list of delegates - pub type LoanFrom = - StorageMap<_, Identity, T::AccountId, Vec<(T::AccountId, u64)>, ValueQuery>; - // PROFIT SHARE VARIABLES #[pallet::type_value] @@ -782,6 +746,50 @@ pub mod pallet { DefaultWeights, >; + // ======================================================== + // ==== Voting System to Update Global and Subnet ==== + // ======================================================== + #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug, TypeInfo)] + #[scale_info(skip_type_params(T))] + pub struct Proposal { + // --- parameters + pub subnet_params: SubnetParams, + pub global_params: GlobalParams, + pub netuid: u16, // FOR SUBNET PROPOSAL ONLY + pub votes: u64, + pub participants: Vec, + pub accepted: bool, + pub data: Vec, // for custom proposal + pub mode: Vec, // "global", "subnet", "custom" + } + + #[pallet::type_value] + pub fn DefaultProposal() -> Proposal { + Proposal { + global_params: DefaultGlobalParams::::get(), + subnet_params: DefaultSubnetParams::::get(), + votes: 0, + netuid: 0, + participants: vec![], + accepted: false, + mode: vec![], + data: vec![], + } + } + + #[pallet::storage] // --- MAP ( global_proposal_id ) --> global_update_proposal + pub(super) type Proposals = + StorageMap<_, Identity, u64, Proposal, ValueQuery, DefaultProposal>; + + #[pallet::type_value] + pub fn DefaultMaxProposals() -> u64 { + 128 + } + + #[pallet::storage] + pub(super) type MaxProposals = + StorageValue<_, u64, ValueQuery, DefaultMaxProposals>; + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -856,6 +864,8 @@ pub mod pallet { * 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. */ + InvalidUidsLength, /* ---- Thrown when the caller attempts to set weights with a + * different number of uids than allowed. */ NotSettingEnoughWeights, /* ---- Thrown when the dispatch attempts to set weights on * chain with fewer elements than are allowed. */ TooManyRegistrationsPerBlock, /* ---- Thrown when registrations this block exceeds @@ -891,14 +901,14 @@ pub mod pallet { KeyAlreadyRegistered, // ModuleNameDoesNotExist, /* --- Thrown when the user tries to remove a module name that * does not exist. */ - KeyNameMismatch, + EmptyKeys, + InvalidShares, + ProfitSharesNotAdded, NotFounder, NameAlreadyRegistered, - NotEnoughStaketoSetWeights, + NotEnoughStakeToSetWeights, NotEnoughStakeToStartNetwork, - NetworkRegistrationFailed, - NetworkAlreadyRegistered, - NotEnoughtStakePerWeight, + NotEnoughStakePerWeight, NoSelfWeight, DifferentLengths, NotEnoughBalanceToRegister, @@ -908,11 +918,6 @@ pub mod pallet { StillRegistered, MaxAllowedModules, /* --- Thrown when the user tries to set max allowed modules to a * value less than the current number of registered modules. */ - TooMuchUpdateProposals, - InvalidProposalId, - UpdateProposalAlreadyVoted, - UpdateProposalVoteNotAvailable, - NotEnoughVotesToAccept, NotEnoughBalanceToTransfer, NotAuthorityMode, InvalidTrustRatio, @@ -921,7 +926,6 @@ pub mod pallet { InvalidMinStake, InvalidMinDelegationFee, - InvalidGlobalParams, InvalidMaxNameLength, InvalidMaxAllowedSubnets, InvalidMaxAllowedModules, @@ -934,6 +938,7 @@ pub mod pallet { InvalidBurnRate, InvalidMinBurn, InvalidMaxBurn, + InvalidTargetRegistrationsPerInterval, // VOTING ProposalDoesNotExist, @@ -943,11 +948,14 @@ pub mod pallet { VoterIsNotRegistered, VoterIsRegistered, InvalidVoteMode, + InvalidImmunityPeriod, + InvalidFounderShare, + InvalidIncentiveRatio, InvalidMaxWeightAge, InvalidMaxStake, - AlreadyControlled, - AlreadyController, + // OTHER + ArithmeticError, } // ================== @@ -1023,65 +1031,12 @@ pub mod pallet { } } - // ======================================================== - // ==== Voting System to Update Global and Subnet ==== - // ======================================================== - #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug, TypeInfo)] - #[scale_info(skip_type_params(T))] - pub struct Proposal { - // --- parameters - pub subnet_params: SubnetParams, - pub global_params: GlobalParams, - pub netuid: u16, // FOR SUBNET PROPOSAL ONLY - pub votes: u64, - pub participants: Vec, - pub accepted: bool, - pub data: Vec, // for custom proposal - pub mode: Vec, // "global", "subnet", "custom" - } - - #[pallet::type_value] - pub fn DefaultProposal() -> Proposal { - Proposal { - global_params: DefaultGlobalParams::::get(), - subnet_params: DefaultSubnetParams::::get(), - votes: 0, - netuid: 0, - participants: vec![], - accepted: false, - mode: vec![], - data: vec![], - } - } - - #[pallet::storage] // --- MAP ( global_proposal_id ) --> global_update_proposal - pub(super) type Proposals = - StorageMap<_, Identity, u64, Proposal, ValueQuery, DefaultProposal>; - - #[pallet::type_value] - pub fn DefaultMaxProposals() -> u64 { - 128 - } - #[pallet::storage] - pub(super) type MaxProposals = - StorageValue<_, u64, ValueQuery, DefaultMaxProposals>; - // ================ // ==== 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_runtime_upgrade() -> frame_support::weights::Weight { - // migration::on_runtime_upgrade::() - // } - fn on_initialize(_block_number: BlockNumberFor) -> Weight { Self::block_step(); @@ -1258,7 +1213,7 @@ pub mod pallet { params.target_registrations_interval = target_registrations_interval; // Check if the parameters are valid - Self::check_global_params(params.clone())?; + Self::check_global_params(¶ms)?; // if so update them Self::do_update_global(origin, params) @@ -1340,7 +1295,7 @@ pub mod pallet { params.vote_threshold = vote_threshold; // Check if subnet parameters are valid - Self::check_subnet_params(params.clone())?; + Self::check_subnet_params(¶ms)?; // if so update them Self::do_update_subnet(origin, netuid, params) @@ -1408,7 +1363,7 @@ pub mod pallet { pub fn get_priority_set_weights(key: &T::AccountId, netuid: u16) -> u64 { if Uids::::contains_key(netuid, key) { let uid: u16 = Self::get_uid_for_key(netuid, &key.clone()); - let current_block_number: u64 = Self::get_current_block_as_u64(); + let current_block_number: u64 = Self::get_current_block_number(); return current_block_number - Self::get_last_update_for_uid(netuid, uid); } 0 @@ -1474,7 +1429,7 @@ where // Return high priority so that every extrinsic except set_weights function will // have a higher priority than the set_weights call // get the current block number - let current_block_number: u64 = Pallet::::get_current_block_as_u64(); + let current_block_number: u64 = Pallet::::get_current_block_number(); let balance = Pallet::::get_balance_u64(who); // this is the current block number minus the last update block number diff --git a/pallets/subspace/src/math.rs b/pallets/subspace/src/math.rs index 9eaa59056..ae5faa2fd 100644 --- a/pallets/subspace/src/math.rs +++ b/pallets/subspace/src/math.rs @@ -45,7 +45,7 @@ pub fn mask_diag_sparse(sparse_matrix: &[Vec<(u16, I32F32)>]) -> Vec]) { for sparse_row in sparse_matrix.iter_mut() { let row_sum: I32F32 = sparse_row.iter().map(|(_j, value)| *value).sum(); - if row_sum > I32F32::from_num(0.0) { + if row_sum != I32F32::from_num(0) { sparse_row.iter_mut().for_each(|(_j, value)| *value /= row_sum); } } diff --git a/pallets/subspace/src/module.rs b/pallets/subspace/src/module.rs index 746ff7472..4b65d485f 100644 --- a/pallets/subspace/src/module.rs +++ b/pallets/subspace/src/module.rs @@ -120,9 +120,9 @@ impl Pallet { ); // HANDLE THE KEY AND UID ASSOCIATIONS - Uids::::insert(netuid, replace_key.clone(), uid); // Remove old key - uid association. - Keys::::insert(netuid, uid, replace_key.clone()); // Make key - uid association. - Uids::::remove(netuid, uid_key.clone()); // Remove old key - uid association. + Uids::::insert(netuid, &replace_key, uid); // Remove old key - uid association. + Keys::::insert(netuid, uid, &replace_key); // Make key - uid association. + Uids::::remove(netuid, &uid_key); // Remove old key - uid association. Keys::::remove(netuid, replace_uid); // Remove key - uid association. // pop frm incentive vector and push to new key @@ -130,10 +130,8 @@ impl Pallet { let mut dividends: Vec = Dividends::::get(netuid); let mut last_update: Vec = LastUpdate::::get(netuid); let mut emission: Vec = Emission::::get(netuid); - let _delegation_fee: Percent = DelegationFee::::get(netuid, uid_key.clone()); // swap consensus vectors - incentive[uid as usize] = incentive[replace_uid as usize]; dividends[uid as usize] = dividends[replace_uid as usize]; emission[uid as usize] = emission[replace_uid as usize]; @@ -174,10 +172,10 @@ impl Pallet { // HANDLE THE DELEGATION FEE DelegationFee::::insert( netuid, - replace_key, - DelegationFee::::get(netuid, uid_key.clone()), + &replace_key, + DelegationFee::::get(netuid, &uid_key), ); // Make uid - key association. - DelegationFee::::remove(netuid, uid_key.clone()); // Make uid - key association. + DelegationFee::::remove(netuid, &uid_key); // Make uid - key association. // 3. Remove the network if it is empty. N::::mutate(netuid, |v| *v -= 1); // Decrease the number of modules in the network. @@ -195,34 +193,25 @@ impl Pallet { pub fn append_module(netuid: u16, key: &T::AccountId, name: Vec, address: Vec) -> u16 { // 1. Get the next uid. This is always equal to subnetwork_n. let uid: u16 = Self::get_subnet_n(netuid); - let block_number = Self::get_current_block_as_u64(); - log::debug!( - "append_module( netuid: {:?} | uid: {:?} | new_key: {:?} ) ", - netuid, - key, - uid - ); - - // 3. Expand Yuma with new position. - Emission::::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(block_number)); + let block_number = Self::get_current_block_number(); + log::debug!("append_module( netuid: {netuid:?} | uid: {key:?} | new_key: {uid:?})"); + // 3. Expand with new position. + Emission::::append(netuid, 0); + Incentive::::append(netuid, 0); + Dividends::::append(netuid, 0); + LastUpdate::::append(netuid, block_number); // 4. Insert new account information. - Keys::::insert(netuid, uid, key.clone()); // Make key - uid association. - Uids::::insert(netuid, key.clone(), uid); // Make uid - key association. + Keys::::insert(netuid, uid, key); // Make key - uid association. + Uids::::insert(netuid, key, uid); // Make uid - key association. RegistrationBlock::::insert(netuid, uid, block_number); // Fill block at registration. - Name::::insert(netuid, uid, name.clone()); // Fill module namespace. - Address::::insert(netuid, uid, address.clone()); // Fill module info. - DelegationFee::::insert( - netuid, - key.clone(), - DelegationFee::::get(netuid, key.clone()), - ); // Make uid - key association. + Name::::insert(netuid, uid, name); // Fill module namespace. + Address::::insert(netuid, uid, address); // Fill module info. + DelegationFee::::insert(netuid, key, DelegationFee::::get(netuid, key)); // Make uid - key association. + + N::::insert(netuid, N::::get(netuid) + 1); // Increase the number of modules in the network. - N::::insert(netuid, N::::get(netuid) + 1); // Decrease the number of modules in the network. - // increase the stake of the new key + // increase the stake of the new key Self::increase_stake(netuid, key, key, 0); uid diff --git a/pallets/subspace/src/profit_share.rs b/pallets/subspace/src/profit_share.rs index 9093899b6..b99b7749d 100644 --- a/pallets/subspace/src/profit_share.rs +++ b/pallets/subspace/src/profit_share.rs @@ -1,5 +1,4 @@ use frame_support::pallet_prelude::DispatchResult; -use substrate_fixed::types::{I64F64, I96F32}; use super::*; @@ -16,53 +15,38 @@ impl Pallet { Self::is_key_registered_on_any_network(&key), Error::::NotRegistered ); - assert!(!keys.is_empty()); - assert!(keys.len() == shares.len()); // make sure the keys and shares are the same length - // make sure the keys are unique and the shares are unique + ensure!(!keys.is_empty(), Error::::EmptyKeys); + ensure!(keys.len() == shares.len(), Error::::DifferentLengths); - let total_shares: u32 = shares.iter().map(|x| *x as u32).sum(); - assert!(total_shares > 0); - let mut normalized_shares_float: Vec = Vec::new(); - // normalize shares - for share in shares.iter() { - let normalized_share = - (I64F64::from(*share) / I64F64::from(total_shares as u16)) * I64F64::from(u16::MAX); - normalized_shares_float.push(normalized_share); - } - // make sure the normalized shares add up to the unit - // convert the normalized shares to u16 - let mut normalize_shares: Vec = - normalized_shares_float.iter().map(|x| x.to_num::()).collect(); + let total_shares: u32 = shares.iter().map(|&x| x as u32).sum(); + ensure!(total_shares > 0, Error::::InvalidShares); + + let normalized_shares: Vec = shares + .iter() + .map(|&share| (share as u64 * u16::MAX as u64 / total_shares as u64) as u16) + .collect(); - let mut total_normalized_shares: u16 = normalize_shares.iter().sum(); + let total_normalized_shares: u16 = normalized_shares.iter().sum(); - // ensure the profit shares add up to the unit + // Ensure the profit shares add up to the unit + let mut adjusted_shares = normalized_shares; if total_normalized_shares < u16::MAX { let diff = u16::MAX - total_normalized_shares; for i in 0..diff { - let idx = (i % normalize_shares.len() as u16) as usize; - normalize_shares[idx] += 1; + let idx = (i % adjusted_shares.len() as u16) as usize; + adjusted_shares[idx] += 1; } - total_normalized_shares = normalize_shares.iter().sum::(); } - assert!( - total_normalized_shares == u16::MAX, - "normalized shares {} vs {} do not add up to the unit", - total_normalized_shares, - u16::MAX - ); - - // now send the normalized shares to the profit share pallet let profit_share_tuples: Vec<(T::AccountId, u16)> = - keys.iter().zip(normalize_shares.iter()).map(|(x, y)| (x.clone(), *y)).collect(); + keys.into_iter().zip(adjusted_shares).collect(); ProfitShares::::insert(&key, profit_share_tuples.clone()); - assert!( + ensure!( ProfitShares::::get(&key).len() == profit_share_tuples.len(), - "profit shares not added" + Error::::ProfitSharesNotAdded ); Ok(()) @@ -73,15 +57,14 @@ impl Pallet { emission: u64, ) -> Vec<(T::AccountId, u64)> { let profit_shares = ProfitShares::::get(&key); - let mut emission_shares: Vec<(T::AccountId, u64)> = Vec::new(); - for (share_key, share_ratio) in profit_shares.iter() { - let share_emission_float: I96F32 = - I96F32::from(emission) * (I96F32::from(*share_ratio) / I96F32::from(u16::MAX)); - let share_emission: u64 = share_emission_float.to_num(); - emission_shares.push((share_key.clone(), share_emission)); - } - emission_shares + profit_shares + .into_iter() + .map(|(share_key, share_ratio)| { + let share_emission = emission * share_ratio as u64 / u16::MAX as u64; + (share_key, share_emission) + }) + .collect() } #[cfg(debug_assertions)] diff --git a/pallets/subspace/src/registration.rs b/pallets/subspace/src/registration.rs index b150c653e..b72e8fb04 100644 --- a/pallets/subspace/src/registration.rs +++ b/pallets/subspace/src/registration.rs @@ -6,13 +6,16 @@ use frame_system::ensure_signed; use sp_std::vec::Vec; impl Pallet { + // TODO: + //- check ip + // - add ability to set delegaiton fee, straight in registration pub fn do_register( origin: T::RuntimeOrigin, - network: Vec, // network name - name: Vec, // module name - address: Vec, // module address - stake_amount: u64, // stake amount - module_key: T::AccountId, // module key + network_name: Vec, + name: Vec, + address: Vec, + stake: u64, + module_key: T::AccountId, ) -> DispatchResult { // --- 1. Check that the caller has signed the transaction. let key = ensure_signed(origin.clone())?; @@ -27,26 +30,25 @@ impl Pallet { // ensure that the stake that the user wants to register with, // is already present as a balance. ensure!( - Self::has_enough_balance(&key, stake_amount), + Self::has_enough_balance(&key, stake), Error::::NotEnoughBalanceToRegister ); // --- 4. Resolve the network in case it doesn't exist - let netuid = if let Some(netuid) = Self::get_netuid_for_name(&network) { + let netuid = if let Some(netuid) = Self::get_netuid_for_name(&network_name) { netuid } else { // Create subnet if it does not exist. - Self::add_subnet_from_registration(network, stake_amount, &key)? + Self::add_subnet_from_registration(network_name, stake, &key)? }; // --- 5. Ensure the caller has enough stake to register. let min_stake: u64 = MinStake::::get(netuid); let current_burn: u64 = Self::get_burn(); - // also ensures that in the case current_burn is present, the stake is enough // as burn, will be decreased from the stake on the module ensure!( - Self::enough_stake_to_register(netuid, min_stake, current_burn, stake_amount), + Self::enough_stake_to_register(min_stake, current_burn, stake), Error::::NotEnoughStakeToRegister ); @@ -67,10 +69,10 @@ impl Pallet { Self::check_module_limits(netuid); // --- 8. Register the module. - let uid: u16 = Self::append_module(netuid, &module_key, name.clone(), address.clone()); + let uid: u16 = Self::append_module(netuid, &module_key, name, address); // --- 9. Add the stake to the module, now that it is registered on the network. - Self::do_add_stake(origin, netuid, module_key.clone(), stake_amount)?; + Self::do_add_stake(origin, netuid, module_key.clone(), stake)?; // constant -> current_burn logic if current_burn > 0 { @@ -97,14 +99,13 @@ impl Pallet { pub fn do_deregister(origin: T::RuntimeOrigin, netuid: u16) -> DispatchResult { // --- 1. Check that the caller has signed the transaction. - let key = ensure_signed(origin.clone())?; + let key = ensure_signed(origin)?; ensure!( Self::key_registered(netuid, &key), Error::::NotRegistered ); - // --- 2. Ensure we are not exceeding the max allowed registrations per block. let uid: u16 = Self::get_uid_for_key(netuid, &key); Self::remove_module(netuid, uid); @@ -120,12 +121,7 @@ impl Pallet { } /// Whether the netuid has enough stake to cover the minimal stake and min burn - pub fn enough_stake_to_register( - _netuid: u16, - min_stake: u64, - min_burn: u64, - stake_amount: u64, - ) -> bool { + pub fn enough_stake_to_register(min_stake: u64, min_burn: u64, stake_amount: u64) -> bool { stake_amount >= (min_stake + min_burn) } @@ -135,19 +131,16 @@ impl Pallet { pub fn get_pruning_score_for_uid(netuid: u16, uid: u16) -> u64 { let vec: Vec = Emission::::get(netuid); - if (uid as usize) < vec.len() { - vec[uid as usize] - } else { - 0u64 - } + *vec.get(uid as usize).unwrap_or(&0) } + pub fn get_lowest_uid(netuid: u16) -> u16 { let n: u16 = Self::get_subnet_n(netuid); let mut min_score: u64 = u64::MAX; let mut lowest_priority_uid: u16 = 0; let _prune_uids: Vec = Vec::new(); - let current_block = Self::get_current_block_as_u64(); + let current_block = Self::get_current_block_number(); let immunity_period: u64 = Self::get_immunity_period(netuid) as u64; for module_uid_i in 0..n { @@ -180,42 +173,39 @@ impl Pallet { ) -> Result { let num_subnets: u16 = Self::num_subnets(); let max_subnets: u16 = Self::get_global_max_allowed_subnets(); - let mut target_subnet = None; - // if we have not reached the max number of subnets, then we can start a new one - if num_subnets >= max_subnets { + + let target_subnet = if num_subnets >= max_subnets { let (min_stake_netuid, min_stake) = Self::least_staked_netuid(); - target_subnet = Some(min_stake_netuid); ensure!(stake > min_stake, Error::::NotEnoughStakeToStartNetwork); Self::remove_subnet(min_stake_netuid); - } - // if we have reached the max number of subnets, then we can start a new one if the stake is - // greater than the least staked network - let mut params: SubnetParams = Self::default_subnet_params(); - params.name = name; - params.founder = founder_key.clone(); + Some(min_stake_netuid) + } else { + None + }; + + let params = SubnetParams { + name, + founder: founder_key.clone(), + ..Self::default_subnet_params() + }; Ok(Self::add_subnet(params, target_subnet)) } pub fn check_module_limits(netuid: u16) { - // check if we have reached the max allowed modules, - // if so deregister the lowest priority node - - // replace a node if we reach the max allowed modules for the network + // Check if we have reached the max allowed modules for the network if Self::global_n() >= Self::get_max_allowed_modules() { - // get the least staked network (subnet) + // Get the least staked network (subnet) let (least_staked_netuid, _) = Self::least_staked_netuid(); - // deregister the lowest priority node + // Deregister the lowest priority node in the least staked network Self::remove_module( least_staked_netuid, Self::get_lowest_uid(least_staked_netuid), ); - - // if we reach the max allowed modules for this network, - // then we replace the lowest priority node } else if Self::get_subnet_n(netuid) >= Self::get_max_allowed_uids(netuid) { - // deregister the lowest priority node + // If we reach the max allowed modules for this network, + // then we replace the lowest priority node in the current network Self::remove_module(netuid, Self::get_lowest_uid(netuid)); } } diff --git a/pallets/subspace/src/staking.rs b/pallets/subspace/src/staking.rs index 4971f9261..d1e2bcddb 100644 --- a/pallets/subspace/src/staking.rs +++ b/pallets/subspace/src/staking.rs @@ -4,6 +4,7 @@ use sp_arithmetic::per_things::Percent; use sp_std::vec::Vec; impl Pallet { + /// Adds stake to multiple modules in a single transaction pub fn do_add_stake_multiple( origin: T::RuntimeOrigin, netuid: u16, @@ -11,19 +12,24 @@ impl Pallet { amounts: Vec, ) -> dispatch::DispatchResult { let key = ensure_signed(origin.clone())?; - let amounts_sum: u64 = amounts.iter().sum(); - ensure!( - Self::has_enough_balance(&key, amounts_sum), - Error::::NotEnoughStaketoWithdraw - ); + ensure!( amounts.len() == module_keys.len(), Error::::DifferentLengths ); - for (i, m_key) in module_keys.iter().enumerate() { - Self::do_add_stake(origin.clone(), netuid, m_key.clone(), amounts[i])?; + // Check if the caller has enough balance to stake + let total_amount: u64 = amounts.iter().sum(); + ensure!( + Self::has_enough_balance(&key, total_amount), + Error::::NotEnoughStaketoWithdraw + ); + + // Add stake to each module + for (m_key, amount) in module_keys.iter().zip(amounts.iter()) { + Self::do_add_stake(origin.clone(), netuid, m_key.clone(), *amount)?; } + Ok(()) } @@ -33,23 +39,28 @@ impl Pallet { amounts: Vec, ) -> dispatch::DispatchResult { let key = ensure_signed(origin.clone())?; - let amounts_sum: u64 = amounts.iter().sum(); - ensure!( - Self::has_enough_balance(&key, amounts_sum), - Error::::NotEnoughBalanceToTransfer - ); + ensure!( amounts.len() == destinations.len(), Error::::DifferentLengths ); - for (i, m_key) in destinations.iter().enumerate() { + // Check if the caller has enough balance to transfer + let total_amount: u64 = amounts.iter().sum(); + ensure!( + Self::has_enough_balance(&key, total_amount), + Error::::NotEnoughBalanceToTransfer + ); + + // Transfer balance to each destination + for (m_key, amount) in destinations.iter().zip(amounts.iter()) { ensure!( - Self::has_enough_balance(&key, amounts[i]), + Self::has_enough_balance(&key, *amount), Error::::NotEnoughBalanceToTransfer ); - Self::transfer_balance_to_account(&key, &m_key.clone(), amounts[i]); + Self::transfer_balance_to_account(&key, m_key, *amount); } + Ok(()) } @@ -60,21 +71,25 @@ impl Pallet { amounts: Vec, ) -> dispatch::DispatchResult { let key = ensure_signed(origin.clone())?; + ensure!( amounts.len() == module_keys.len(), Error::::DifferentLengths ); - for (i, m_key) in module_keys.iter().enumerate() { + // Remove stake from each module + for (m_key, amount) in module_keys.iter().zip(amounts.iter()) { ensure!( - Self::has_enough_stake(netuid, &key, &m_key.clone(), amounts[i]), + Self::has_enough_stake(netuid, &key, m_key, *amount), Error::::NotEnoughStaketoWithdraw ); - Self::do_remove_stake(origin.clone(), netuid, m_key.clone(), amounts[i])?; + Self::do_remove_stake(origin.clone(), netuid, m_key.clone(), *amount)?; } + Ok(()) } + /// Transfers stake from one module to another pub fn do_transfer_stake( origin: T::RuntimeOrigin, netuid: u16, @@ -83,21 +98,27 @@ impl Pallet { amount: u64, ) -> dispatch::DispatchResult { let key = ensure_signed(origin.clone())?; + + // Check if both modules are registered ensure!( - Self::is_registered(netuid, &module_key.clone()), + Self::is_registered(netuid, &module_key), Error::::NotRegistered ); ensure!( - Self::is_registered(netuid, &new_module_key.clone()), + Self::is_registered(netuid, &new_module_key), Error::::NotRegistered ); + + // Check if the caller has enough stake in the source module ensure!( Self::has_enough_stake(netuid, &key, &module_key, amount), Error::::NotEnoughStaketoWithdraw ); + // Remove stake from the source module and add it to the destination module Self::do_remove_stake(origin.clone(), netuid, module_key.clone(), amount)?; - Self::do_add_stake(origin.clone(), netuid, new_module_key.clone(), amount)?; + Self::do_add_stake(origin.clone(), netuid, new_module_key, amount)?; + Ok(()) } @@ -226,11 +247,7 @@ impl Pallet { // Returns the total amount of stake in the staking table. pub fn total_stake() -> u64 { - let mut total_stake: u64 = 0; - for (_netuid, subnet_total_stake) in TotalStake::::iter() { - total_stake += subnet_total_stake; - } - total_stake + TotalStake::::iter().map(|(_, stake)| stake).sum() } // Returns the stake under the cold - hot pairing in the staking table. @@ -241,14 +258,10 @@ impl Pallet { #[cfg(debug_assertions)] pub fn get_stakes(netuid: u16) -> Vec { - let _n = Self::get_subnet_n(netuid); - let mut stakes: Vec = Vec::new(); - let uid_key_tuples: Vec<(u16, T::AccountId)> = Self::get_uid_key_tuples(netuid); - for (_uid, key) in uid_key_tuples { - let stake: u64 = Self::get_stake(netuid, &key); - stakes.push(stake); - } - stakes + Self::get_uid_key_tuples(netuid) + .into_iter() + .map(|(_, key)| Self::get_stake(netuid, &key)) + .collect() } // Returns the delegation fee of a module @@ -277,22 +290,15 @@ impl Pallet { #[cfg(debug_assertions)] pub fn get_stake_to_total(netuid: u16, key: &T::AccountId) -> u64 { - let mut total_stake_to: u64 = 0; - for (_k, v) in Self::get_stake_to_vector(netuid, key) { - total_stake_to += v; - } - total_stake_to + Self::get_stake_to_vector(netuid, key).into_iter().map(|(_, v)| v).sum() } pub fn get_stake_to_module(netuid: u16, key: &T::AccountId, module_key: &T::AccountId) -> u64 { - let mut state_to: u64 = 0; - for (k, v) in Self::get_stake_to_vector(netuid, key) { - if k == module_key.clone() { - state_to = v; - } - } - - state_to + Self::get_stake_to_vector(netuid, key) + .into_iter() + .find(|(k, _)| k == module_key) + .map(|(_, v)| v) + .unwrap_or(0) } pub fn get_stake_to_vector(netuid: u16, key: &T::AccountId) -> Vec<(T::AccountId, u64)> { @@ -304,13 +310,11 @@ impl Pallet { key: &T::AccountId, stake_to_vector: Vec<(T::AccountId, u64)>, ) { - // we want to remove any keys that have a stake of 0, as these are from outside the subnet - // and can bloat the chain if stake_to_vector.is_empty() { StakeTo::::remove(netuid, key); - return; + } else { + StakeTo::::insert(netuid, key, stake_to_vector); } - StakeTo::::insert(netuid, key, stake_to_vector); } pub fn set_stake_from_vector( @@ -331,12 +335,7 @@ impl Pallet { } pub fn get_total_stake_to(netuid: u16, key: &T::AccountId) -> u64 { - let stake_to_vector: Vec<(T::AccountId, u64)> = Self::get_stake_to_vector(netuid, key); - let mut total_stake_to: u64 = 0; - for (_k, v) in stake_to_vector { - total_stake_to += v; - } - total_stake_to + Self::get_stake_to_vector(netuid, key).into_iter().map(|(_, v)| v).sum() } // INCREASE @@ -347,45 +346,34 @@ impl Pallet { module_key: &T::AccountId, amount: u64, ) -> bool { - let mut stake_from_vector: Vec<(T::AccountId, u64)> = - Self::get_stake_from_vector(netuid, module_key); - let mut found_key_in_vector: bool = false; - for (i, (k, v)) in stake_from_vector.clone().iter().enumerate() { - if *k == *key { - stake_from_vector[i] = (k.clone(), (*v).saturating_add(amount)); - found_key_in_vector = true; - } - } + let mut stake_from_vector = Self::get_stake_from_vector(netuid, module_key); + let found_key_in_vector = stake_from_vector.iter_mut().find(|(k, _)| k == key); - // if we didnt find the key in the vector, we need to add it - if !found_key_in_vector { + if let Some((_, v)) = found_key_in_vector { + *v = v.saturating_add(amount); + } else { stake_from_vector.push((key.clone(), amount)); } - // reset the stake to vector, as we have updated the stake_to_vector - let mut found_key_in_vector: bool = false; - let mut stake_to_vector: Vec<(T::AccountId, u64)> = Self::get_stake_to_vector(netuid, key); - - for (i, (k, v)) in stake_to_vector.clone().iter().enumerate() { - if *k == *module_key { - stake_to_vector[i] = (k.clone(), (*v).saturating_add(amount)); - found_key_in_vector = true; - } - } + let mut stake_to_vector = Self::get_stake_to_vector(netuid, key); + let found_key_in_vector = stake_to_vector.iter_mut().find(|(k, _)| k == module_key); - if !found_key_in_vector { + if let Some((_, v)) = found_key_in_vector { + *v = v.saturating_add(amount); + } else { stake_to_vector.push((module_key.clone(), amount)); } Self::set_stake_to_vector(netuid, key, stake_to_vector); Self::set_stake_from_vector(netuid, module_key, stake_from_vector); - Stake::::insert( - netuid, - module_key, - Stake::::get(netuid, module_key).saturating_add(amount), - ); - TotalStake::::insert(netuid, TotalStake::::get(netuid).saturating_add(amount)); + Stake::::mutate(netuid, module_key, |stake| { + *stake = stake.saturating_add(amount) + }); + TotalStake::::mutate(netuid, |total_stake| { + *total_stake = total_stake.saturating_add(amount) + }); + true } @@ -395,61 +383,42 @@ impl Pallet { module_key: &T::AccountId, amount: u64, ) -> bool { - // FROM DELEGATE STAKE - let mut stake_from_vector: Vec<(T::AccountId, u64)> = - Self::get_stake_from_vector(netuid, module_key).clone(); - - let mut idx_to_replace: usize = usize::MAX; - - let mut end_idx: usize = stake_from_vector.len() - 1; - for (i, (k, stake_amount)) in stake_from_vector.clone().iter().enumerate() { - if *k == *key { - let remaining_stake: u64 = (*stake_amount).saturating_sub(amount); - stake_from_vector[i] = (k.clone(), remaining_stake); - if remaining_stake == 0 { - // we need to remove this entry if its zero - idx_to_replace = i; - } - break; + let mut stake_from_vector = Self::get_stake_from_vector(netuid, module_key); + + if let Some((idx, (_, stake_amount))) = + stake_from_vector.iter_mut().enumerate().find(|(_, (k, _))| k == key) + { + let remaining_stake = stake_amount.saturating_sub(amount); + stake_from_vector[idx] = (key.clone(), remaining_stake); + + if remaining_stake == 0 { + stake_from_vector.swap_remove(idx); } } - if idx_to_replace != usize::MAX { - stake_from_vector.swap(idx_to_replace, end_idx); - stake_from_vector.remove(end_idx); - } Self::set_stake_from_vector(netuid, module_key, stake_from_vector); - let mut stake_to_vector: Vec<(T::AccountId, u64)> = Self::get_stake_to_vector(netuid, key); - // TO STAKE - idx_to_replace = usize::MAX; - end_idx = stake_to_vector.len() - 1; - - for (i, (k, v)) in stake_to_vector.clone().iter().enumerate() { - if *k == *module_key { - let remaining_stake: u64 = (*v).saturating_sub(amount); - stake_to_vector[i] = (k.clone(), remaining_stake); - if remaining_stake == 0 { - idx_to_replace = i; - } - break; - } - } + let mut stake_to_vector = Self::get_stake_to_vector(netuid, key); + + if let Some((idx, (_, v))) = + stake_to_vector.iter_mut().enumerate().find(|(_, (k, _))| k == module_key) + { + let remaining_stake = v.saturating_sub(amount); + stake_to_vector[idx] = (module_key.clone(), remaining_stake); - if idx_to_replace != usize::MAX { - stake_to_vector.swap(idx_to_replace, end_idx); - stake_to_vector.remove(end_idx); + if remaining_stake == 0 { + stake_to_vector.swap_remove(idx); + } } Self::set_stake_to_vector(netuid, key, stake_to_vector); - // --- 8. We add the balancer to the key. If the above fails we will not credit this key. - Stake::::insert( - netuid, - module_key, - Stake::::get(netuid, module_key).saturating_sub(amount), - ); - TotalStake::::insert(netuid, TotalStake::::get(netuid).saturating_sub(amount)); + Stake::::mutate(netuid, module_key, |stake| { + *stake = stake.saturating_sub(amount) + }); + TotalStake::::mutate(netuid, |total_stake| { + *total_stake = total_stake.saturating_sub(amount) + }); true } @@ -526,14 +495,12 @@ impl Pallet { key: &T::AccountId, amount: <::Currency as Currency<::AccountId>>::Balance, ) -> bool { - match T::Currency::withdraw( + T::Currency::withdraw( key, amount, WithdrawReasons::except(WithdrawReasons::TIP), ExistenceRequirement::KeepAlive, - ) { - Ok(_result) => true, - Err(_error) => false, - } + ) + .is_ok() } } diff --git a/pallets/subspace/src/step.rs b/pallets/subspace/src/step.rs index 6f6539e1e..d731e5459 100644 --- a/pallets/subspace/src/step.rs +++ b/pallets/subspace/src/step.rs @@ -6,7 +6,7 @@ use substrate_fixed::types::{I110F18, I32F32, I64F64}; impl Pallet { pub fn block_step() { - let block_number: u64 = Self::get_current_block_as_u64(); + let block_number: u64 = Self::get_current_block_number(); RegistrationsPerBlock::::mutate(|val| *val = 0); let registration_this_interval = Self::get_registrations_this_interval(); @@ -32,16 +32,22 @@ impl Pallet { } } - pub fn epoch(netuid: u16, mut token_emission: u64) { - // Get subnetwork size. + pub fn epoch(netuid: u16, token_emission: u64) { + /* + This function acts as the main function of the entire blockchain reward distribution. + It calculates the dividends, the incentive, the weights, the bonds, + the trust and the emission for the epoch. + */ + // get the network parameters let global_params = Self::global_params(); let subnet_params = Self::subnet_params(netuid); + // get the amount of modules let n: u16 = Self::get_subnet_n(netuid); - let current_block: u64 = Self::get_current_block_as_u64(); - let _block_at_registration: Vec = Self::get_block_at_registration(netuid); + let current_block: u64 = Self::get_current_block_number(); + // if there are no modules, then return if n == 0 { // return; @@ -49,30 +55,12 @@ impl Pallet { // FOUNDER DIVIDENDS let founder_key = Self::get_founder(netuid); - let is_founder_registered = Self::key_registered(netuid, &founder_key); - let _founder_uid = u16::MAX; - let mut founder_emission: u64 = 0; - if is_founder_registered { - let founder_share: u16 = Self::get_founder_share(netuid); - if founder_share > 0 { - let founder_emission_ratio: I64F64 = - I64F64::from_num(founder_share.min(100)) / I64F64::from_num(100); - founder_emission = - (founder_emission_ratio * I64F64::from_num(token_emission)).to_num::(); - token_emission = token_emission.saturating_sub(founder_emission); - } - } - - // =========== - // == Stake == - // =========== + let (token_emission, founder_emission) = + Self::calculate_founder_emission(netuid, token_emission, &founder_key); + // STAKE let uid_key_tuples: Vec<(u16, T::AccountId)> = Self::get_uid_key_tuples(netuid); - let _stake_64: Vec = vec![I64F64::from_num(0.0); n as usize]; - let mut total_stake_u64: u64 = Self::get_total_subnet_stake(netuid); - if total_stake_u64 == 0 { - total_stake_u64 = 1; - } + let total_stake_u64: u64 = Self::get_total_subnet_stake(netuid).max(1); let max_stake = subnet_params.max_stake; @@ -80,127 +68,48 @@ impl Pallet { .iter() .map(|(_, key)| Self::get_stake_for_key(netuid, key).min(max_stake)) .collect(); - // clip it to the max stake + + // Clip it to the max stake let stake_f64: Vec = stake_u64 .iter() .map(|x| I64F64::from_num(*x) / I64F64::from_num(total_stake_u64)) .collect(); - let mut stake: Vec = stake_f64.iter().map(|x| I32F32::from_num(*x)).collect(); - // Normalize active stake. - inplace_normalize(&mut stake); - - // ============= - // == Weights (N x N) Sparsified == - // ============= - // Access network weights row normalized. - let last_update_vector: Vec = Self::get_last_update(netuid); - - let mut weights: Vec> = vec![vec![]; n as usize]; - - let min_weight_stake_f64: I64F64 = I64F64::from_num(global_params.min_weight_stake); - - for (uid_i, weights_i) in - as IterableStorageDoubleMap>>::iter_prefix(netuid) - { - let mut weight_changed: bool = false; - // watchout for the overflow - - let weight_age: u64 = current_block.saturating_sub(last_update_vector[uid_i as usize]); - if weight_age > subnet_params.max_weight_age { - weight_changed = true; - weights[uid_i as usize] = vec![]; - } else { - if weights_i.len() < (subnet_params.min_allowed_weights as usize) { - weight_changed = true; - weights[uid_i as usize] = vec![]; - } - for (pos, (uid_j, weight_ij)) in weights_i.iter().enumerate() { - // ignore the weights that are not in the top max allowed weights - if (pos as u16) <= subnet_params.max_allowed_weights && *uid_j < n { - // okay , we passed the positioonal check, now check the weight - let weight_f64 = I64F64::from_num(*weight_ij) / I64F64::from_num(u16::MAX); - let weight_stake = (stake_f64[uid_i as usize] * weight_f64) - * I64F64::from_num(total_stake_u64); - if weight_stake > min_weight_stake_f64 { - weights[uid_i as usize].push((*uid_j, *weight_ij)); - } else { - weight_changed = true; - } - } else { - weight_changed = true; - } - } - } - - if weight_changed { - // update the weights if it was changed - >::insert(netuid, uid_i, weights[uid_i as usize].clone()); - } - } - - let mut weights: Vec> = weights - .iter() - .map(|x| { - x.iter().map(|(uid, weight)| (*uid, u16_proportion_to_fixed(*weight))).collect() - }) - .collect(); - - // Remove self-weight by masking diagonal. - weights = mask_diag_sparse(&weights); - - // Normalize remaining weights. - inplace_row_normalize_sparse(&mut weights); - - // ============================= - // == Incentive == - // ============================= - - // convert max u64 to I32F32 - - let mut incentive: Vec = vec![I32F32::from_num(0.0); n as usize]; - for (i, sparse_row) in weights.iter().enumerate() { - // clip based on the max stake - for (j, value) in sparse_row.iter() { - incentive[*j as usize] += stake[i] * value; - } - } - // If emission is zero, do an even split. - if is_zero(&incentive) { - // no weights set - for (uid_i, _key) in uid_key_tuples.iter() { - incentive[*uid_i as usize] = I32F32::from_num(1.0); - } - } - inplace_normalize(&mut incentive); // range: I32F32(0, 1) + let mut stake: Vec = stake_f64.iter().map(|x| I32F32::from_num(*x)).collect(); - // ================================= - // == TRUST == - // ================================= + // Normalize stake. + inplace_normalize(&mut stake); + // WEIGHTS + let weights: Vec> = Self::process_weights( + netuid, + n, + &global_params, + &subnet_params, + current_block, + &stake_f64, + total_stake_u64, + ); + + // INCENTIVE + // see if this shit needs to be mut + let mut incentive: Vec = + Self::compute_incentive(&weights, &stake, &uid_key_tuples, n); + + // TRUST // trust that acts as a multiplier for the incentive let trust_ratio: u16 = Self::get_trust_ratio(netuid); if trust_ratio > 0 { let trust_share: I32F32 = I32F32::from_num(trust_ratio) / I32F32::from_num(100); let incentive_share: I32F32 = I32F32::from_num(1.0).saturating_sub(trust_share); - let mut trust: Vec = vec![I32F32::from_num(0.0); n as usize]; - - for (i, weights_i) in weights.iter().enumerate() { - for (j, weight_ij) in weights_i.iter() { - // Compute trust scores: t_j = SUM(i) w_ij * s_i - // result_j = SUM(i) vector_i * matrix_ij - if *weight_ij > 0 && stake[i] > I32F32::from_num(subnet_params.min_stake) { - trust[*j as usize] += I32F32::from_num(1.0); - } - } - } + let trust = Self::compute_trust(&weights, &stake, &subnet_params, n); - inplace_normalize(&mut trust); incentive = incentive .iter() .zip(trust.iter()) .map(|(inc, tru)| (inc * incentive_share) + (tru * trust_share)) .collect(); + // save the trust into the trust vector Trust::::insert( netuid, @@ -213,98 +122,78 @@ impl Pallet { incentive.iter().map(|xi| fixed_proportion_to_u16(*xi)).collect::>(); Incentive::::insert(netuid, cloned_incentive); - // ================================= - // == Calculate Bonds== - // ================================= - - // Compute bonds delta column normalized. - let mut bonds: Vec> = weights.clone(); - let mut col_sum: Vec = vec![I32F32::from_num(0.0); n as usize]; // assume square matrix, rows=cols - - for (i, sparse_row) in bonds.iter_mut().enumerate() { - for (j, value) in sparse_row.iter_mut() { - *value *= stake[i]; // scale by stake - col_sum[*j as usize] += *value; // sum the column - } - } - // sum the votes per module - for sparse_row in bonds.iter_mut() { - for (j, value) in sparse_row.iter_mut() { - if col_sum[*j as usize] > I32F32::from_num(0.0f32) { - *value /= col_sum[*j as usize]; - } - } - } - // ================================= - // == Dividends== - // ================================= - - let mut dividends: Vec = vec![I32F32::from_num(0.0); incentive.len()]; - for (i, sparse_row) in bonds.iter().enumerate() { - for (j, value) in sparse_row.iter() { - dividends[i] += incentive[*j as usize] * value; - } - } - - // If emission is zero, do an even split. - if is_zero(÷nds) { - // no weights set - for (uid_i, _key) in uid_key_tuples.iter() { - dividends[*uid_i as usize] = I32F32::from_num(1.0); - } - } - inplace_normalize(&mut dividends); - - let cloned_dividends: Vec = - dividends.iter().map(|xi| fixed_proportion_to_u16(*xi)).collect::>(); - Dividends::::insert(netuid, cloned_dividends); + // BONDS + let bonds: Vec> = Self::compute_bonds_delta(&weights, &stake); + + // DIVIDENDS + let (fixed_dividends, dividends) = + Self::compute_dividends(&bonds, &incentive, &uid_key_tuples); + Dividends::::insert(netuid, fixed_dividends); + + // EMISSION + Self::process_emission( + &incentive, + ÷nds, + token_emission, + netuid, + founder_emission, + &founder_key, + &uid_key_tuples, + ); + } - // ================================= - // == Emission== - // ================================= + fn calculate_emission_ratios( + incentive: &[I32F32], + dividends: &[I32F32], + token_emission: u64, + netuid: u16, + ) -> (Vec, Vec) { let incentive_ratio: I64F64 = I64F64::from_num(Self::get_incentive_ratio(netuid) as u64) / I64F64::from_num(100); let dividend_ratio: I64F64 = I64F64::from_num(1.0) - incentive_ratio; let incentive_emission_float: Vec = incentive - .clone() .iter() - .map(|x| I64F64::from_num(*x) * I64F64::from_num(token_emission) * incentive_ratio) + .map(|&x| I64F64::from_num(x) * I64F64::from_num(token_emission) * incentive_ratio) .collect(); let dividends_emission_float: Vec = dividends - .clone() .iter() - .map(|x| I64F64::from_num(*x) * I64F64::from_num(token_emission) * dividend_ratio) + .map(|&x| I64F64::from_num(x) * I64F64::from_num(token_emission) * dividend_ratio) .collect(); + (incentive_emission_float, dividends_emission_float) + } + + fn calculate_emissions( + incentive_emission_float: &[I64F64], + dividends_emission_float: &[I64F64], + founder_emission: u64, + netuid: u16, + founder_key: &T::AccountId, + uid_key_tuples: &[(u16, T::AccountId)], + ) -> Vec { + let n = incentive_emission_float.len(); let mut incentive_emission: Vec = - incentive_emission_float.iter().map(|e: &I64F64| e.to_num::()).collect(); + incentive_emission_float.iter().map(|e| e.to_num::()).collect(); let dividends_emission: Vec = - dividends_emission_float.iter().map(|e: &I64F64| e.to_num::()).collect(); + dividends_emission_float.iter().map(|e| e.to_num::()).collect(); let burn_amount_per_epoch: u64 = Self::get_burn_per_epoch(netuid); - if is_founder_registered { - let founder_uid = Self::get_uid_for_key(netuid, &founder_key); - incentive_emission[founder_uid as usize] = - incentive_emission[founder_uid as usize].saturating_add(founder_emission); - } - // burn the amount + let founder_uid = Self::get_uid_for_key(netuid, founder_key); + incentive_emission[founder_uid as usize] = + incentive_emission[founder_uid as usize].saturating_add(founder_emission); - let mut emission: Vec = vec![0; n as usize]; + let mut emission: Vec = vec![0; n]; - // Emission tuples ( uid_key_tuples, u64 emission) - let _founder_share_added: bool = false; // avoid double counting the founder share for (module_uid, module_key) in uid_key_tuples.iter() { let mut owner_emission_incentive: u64 = incentive_emission[*module_uid as usize]; let mut owner_dividends_emission: u64 = dividends_emission[*module_uid as usize]; let owner_emission: u64 = owner_emission_incentive + owner_dividends_emission; - // if the owner emission is less than the burn amount if burn_amount_per_epoch > owner_emission { let burn_into_stake: u64 = burn_amount_per_epoch.saturating_sub(owner_emission); - // decrease the stake if there is remainder if burn_into_stake > 0 { Self::decrease_stake(netuid, module_key, module_key, burn_into_stake); } @@ -312,17 +201,13 @@ impl Pallet { continue; } - // eat into incentive first and then into the incentive if burn_amount_per_epoch > owner_emission_incentive { owner_emission_incentive = 0; - // correct the burn amount let left_burn_amount_per_epoch = burn_amount_per_epoch.saturating_sub(owner_emission_incentive); - // apply the burn to the incentive owner_dividends_emission = owner_dividends_emission.saturating_sub(left_burn_amount_per_epoch); } else { - // apply the burn to the emission only owner_emission_incentive = owner_emission_incentive.saturating_sub(burn_amount_per_epoch); } @@ -330,14 +215,11 @@ impl Pallet { emission[*module_uid as usize] = owner_emission_incentive + owner_dividends_emission; if owner_dividends_emission > 0 { - // get the ownership emission for this key - let ownership_vector: Vec<(T::AccountId, I64F64)> = Self::get_ownership_ratios(netuid, module_key); let delegation_fee = Self::get_delegation_fee(netuid, module_key); - // add the ownership let total_owner_dividends_emission: u64 = owner_dividends_emission; for (delegate_key, delegate_ratio) in ownership_vector.iter() { if delegate_key == module_key { @@ -345,7 +227,7 @@ impl Pallet { } let dividends_from_delegate: u64 = - (I64F64::from_num(total_owner_dividends_emission) * delegate_ratio) + (I64F64::from_num(total_owner_dividends_emission) * *delegate_ratio) .to_num::(); let to_module: u64 = delegation_fee.mul_floor(dividends_from_delegate); let to_delegate: u64 = dividends_from_delegate.saturating_sub(to_module); @@ -355,18 +237,12 @@ impl Pallet { } let owner_emission: u64 = owner_emission_incentive + owner_dividends_emission; - // add the emisssion and rm the burn amount if owner_emission > 0 { - // generate the profit shares let profit_share_emissions: Vec<(T::AccountId, u64)> = Self::get_profit_share_emissions(module_key.clone(), owner_emission); - // if there are profit shares, then increase the balance of the profit share key if !profit_share_emissions.is_empty() { - // if there are profit shares, then increase the balance of the profit share - // key for (profit_share_key, profit_share_emission) in profit_share_emissions.iter() { - // increase the balance of the profit share key Self::increase_stake( netuid, profit_share_key, @@ -375,13 +251,246 @@ impl Pallet { ); } } else { - // increase it to the module key Self::increase_stake(netuid, module_key, module_key, owner_emission); } } } - Emission::::insert(netuid, emission.clone()); + emission + } + + fn process_emission( + incentive: &[I32F32], + dividends: &[I32F32], + token_emission: u64, + netuid: u16, + founder_emission: u64, + founder_key: &T::AccountId, + uid_key_tuples: &[(u16, T::AccountId)], + ) { + let (incentive_emission_float, dividends_emission_float) = + Self::calculate_emission_ratios(incentive, dividends, token_emission, netuid); + + let emission = Self::calculate_emissions( + &incentive_emission_float, + ÷nds_emission_float, + founder_emission, + netuid, + founder_key, + uid_key_tuples, + ); + + Emission::::insert(netuid, emission); + } + + fn compute_dividends( + bonds: &[Vec<(u16, I32F32)>], + incentive: &[I32F32], + uid_key_tuples: &[(u16, T::AccountId)], + ) -> (Vec, Vec) { + let n = incentive.len(); + let mut dividends: Vec = vec![I32F32::from_num(0.0); n]; + + for (i, sparse_row) in bonds.iter().enumerate() { + for (j, value) in sparse_row.iter() { + dividends[i] += incentive[*j as usize] * *value; + } + } + + if dividends.iter().all(|&x| x == I32F32::from_num(0.0)) { + for (uid_i, _) in uid_key_tuples.iter() { + dividends[*uid_i as usize] = I32F32::from_num(1.0); + } + } + + inplace_normalize(&mut dividends); + + let fixed_dividends: Vec = + dividends.iter().map(|xi| fixed_proportion_to_u16(*xi)).collect(); + + (fixed_dividends, dividends) + } + + fn compute_bonds_delta( + weights: &[Vec<(u16, I32F32)>], + stake: &[I32F32], + ) -> Vec> { + let n = weights.len(); + let mut bonds: Vec> = weights.to_vec(); + let mut col_sum: Vec = vec![I32F32::from_num(0.0); n]; + + for (i, sparse_row) in bonds.iter_mut().enumerate() { + for (j, value) in sparse_row.iter_mut() { + *value *= stake[i]; + col_sum[*j as usize] += *value; + } + } + + for sparse_row in bonds.iter_mut() { + for (j, value) in sparse_row.iter_mut() { + if col_sum[*j as usize] > I32F32::from_num(0.0) { + *value /= col_sum[*j as usize]; + } + } + } + + bonds + } + + fn compute_trust( + weights: &[Vec<(u16, I32F32)>], + stake: &[I32F32], + subnet_params: &SubnetParams, + n: u16, + ) -> Vec { + let mut trust = vec![I32F32::from_num(0.0); n as usize]; + for (i, weights_i) in weights.iter().enumerate() { + for (j, weight_ij) in weights_i.iter() { + if *weight_ij > 0 && stake[i] > I32F32::from_num(subnet_params.min_stake) { + trust[*j as usize] += I32F32::from_num(1.0); + } + } + } + inplace_normalize(&mut trust); + trust + } + + fn compute_incentive( + weights: &[Vec<(u16, I32F32)>], + stake: &[I32F32], + uid_key_tuples: &[(u16, T::AccountId)], + n: u16, + ) -> Vec { + let mut incentive: Vec = vec![I32F32::from_num(0.0); n as usize]; + + for (i, sparse_row) in weights.iter().enumerate() { + for (j, value) in sparse_row.iter() { + incentive[*j as usize] += stake[i] * value; + } + } + + if is_zero(&incentive) { + for (uid_i, _key) in uid_key_tuples.iter() { + incentive[*uid_i as usize] = I32F32::from_num(1.0); + } + } + + inplace_normalize(&mut incentive); + incentive + } + + fn get_current_weight_age(last_update_vector: &[u64], current_block: u64, uid_i: u16) -> u64 { + current_block.saturating_sub(last_update_vector[uid_i as usize]) + } + + #[allow(clippy::too_many_arguments)] + fn check_weight_validity( + weight_age: u64, + subnet_params: &SubnetParams, + weights_i: &[(u16, u16)], + stake_f64: &[I64F64], + total_stake_u64: u64, + min_weight_stake_f64: I64F64, + n: u16, + uid_i: u16, + ) -> (bool, Vec<(u16, u16)>) { + let mut valid_weights = Vec::new(); + + if weight_age > subnet_params.max_weight_age + || weights_i.len() < subnet_params.min_allowed_weights as usize + { + return (true, valid_weights); + } + + for (pos, (uid_j, weight_ij)) in weights_i.iter().enumerate() { + if (pos as u16) > subnet_params.max_allowed_weights || *uid_j >= n { + return (true, valid_weights); + } + + let weight_f64 = I64F64::from_num(*weight_ij) / I64F64::from_num(u16::MAX); + let weight_stake = + (stake_f64[uid_i as usize] * weight_f64) * I64F64::from_num(total_stake_u64); + + if weight_stake > min_weight_stake_f64 { + valid_weights.push((*uid_j, *weight_ij)); + } else { + return (true, valid_weights); + } + } + + (false, valid_weights) + } + + fn process_weights( + netuid: u16, + n: u16, + global_params: &GlobalParams, + subnet_params: &SubnetParams, + current_block: u64, + stake_f64: &[I64F64], + total_stake_u64: u64, + ) -> Vec> { + let last_update_vector = Self::get_last_update(netuid); + let min_weight_stake_f64 = I64F64::from_num(global_params.min_weight_stake); + let mut weights: Vec> = vec![vec![]; n as usize]; + + for (uid_i, weights_i) in + as IterableStorageDoubleMap>>::iter_prefix(netuid) + { + let weight_age = + Self::get_current_weight_age(&last_update_vector, current_block, uid_i); + let (weight_changed, valid_weights) = Self::check_weight_validity( + weight_age, + subnet_params, + &weights_i, + stake_f64, + total_stake_u64, + min_weight_stake_f64, + n, + uid_i, + ); + + weights[uid_i as usize] = valid_weights; + if weight_changed { + >::insert(netuid, uid_i, weights[uid_i as usize].clone()); + } + } + + let mut weights: Vec> = weights + .iter() + .map(|x| { + x.iter().map(|(uid, weight)| (*uid, u16_proportion_to_fixed(*weight))).collect() + }) + .collect(); + + weights = mask_diag_sparse(&weights); + inplace_row_normalize_sparse(&mut weights); + + weights + } + + fn calculate_founder_emission( + netuid: u16, + mut token_emission: u64, + founder_key: &T::AccountId, + ) -> (u64, u64) { + let is_founder_registered = Self::key_registered(netuid, founder_key); + if !is_founder_registered { + return (token_emission, 0); + } + + let founder_share: u16 = Self::get_founder_share(netuid); + if founder_share == 0u16 { + return (token_emission, 0); + } + + let founder_emission_ratio: I64F64 = + I64F64::from_num(founder_share.min(100)) / I64F64::from_num(100); + let founder_emission = + (founder_emission_ratio * I64F64::from_num(token_emission)).to_num::(); + token_emission = token_emission.saturating_sub(founder_emission); + + (token_emission, founder_emission) } pub fn get_block_at_registration(netuid: u16) -> Vec { diff --git a/pallets/subspace/src/subnet.rs b/pallets/subspace/src/subnet.rs index 7d1044e73..e2201be80 100644 --- a/pallets/subspace/src/subnet.rs +++ b/pallets/subspace/src/subnet.rs @@ -67,7 +67,27 @@ impl Pallet { Ok(()) } - pub fn check_subnet_params(params: SubnetParams) -> DispatchResult { + pub fn subnet_params(netuid: u16) -> SubnetParams { + SubnetParams { + immunity_period: ImmunityPeriod::::get(netuid), + min_allowed_weights: MinAllowedWeights::::get(netuid), + max_allowed_weights: MaxAllowedWeights::::get(netuid), + max_allowed_uids: MaxAllowedUids::::get(netuid), + max_stake: MaxStake::::get(netuid), + max_weight_age: MaxWeightAge::::get(netuid), + min_stake: MinStake::::get(netuid), + tempo: Tempo::::get(netuid), + name: >::new(), + vote_threshold: VoteThresholdSubnet::::get(netuid), + vote_mode: VoteModeSubnet::::get(netuid), + trust_ratio: TrustRatio::::get(netuid), + founder_share: FounderShare::::get(netuid), + incentive_ratio: IncentiveRatio::::get(netuid), + founder: Founder::::get(netuid), + } + } + + pub fn check_subnet_params(params: &SubnetParams) -> DispatchResult { // checks if params are valid let global_params = Self::global_params(); @@ -114,32 +134,36 @@ impl Pallet { params.vote_mode.clone() == AUTHORITY_MODE || params.vote_mode.clone() == STAKE_MODE, Error::::InvalidVoteMode ); - Ok(()) - } - pub fn subnet_params(netuid: u16) -> SubnetParams { - SubnetParams { - immunity_period: ImmunityPeriod::::get(netuid), - min_allowed_weights: MinAllowedWeights::::get(netuid), - max_allowed_weights: MaxAllowedWeights::::get(netuid), - max_allowed_uids: MaxAllowedUids::::get(netuid), - max_stake: MaxStake::::get(netuid), - max_weight_age: MaxWeightAge::::get(netuid), - min_stake: MinStake::::get(netuid), - tempo: Tempo::::get(netuid), - name: >::new(), - vote_threshold: VoteThresholdSubnet::::get(netuid), - vote_mode: VoteModeSubnet::::get(netuid), - trust_ratio: TrustRatio::::get(netuid), - founder_share: FounderShare::::get(netuid), - incentive_ratio: IncentiveRatio::::get(netuid), - founder: Founder::::get(netuid), - } + ensure!( + params.immunity_period > 0, + Error::::InvalidImmunityPeriod + ); + + ensure!( + params.max_allowed_uids > 0, + Error::::InvalidMaxAllowedUids + ); + + ensure!( + params.vote_threshold <= 100, + Error::::InvalidVoteThreshold + ); + + ensure!(params.founder_share <= 100, Error::::InvalidFounderShare); + + ensure!( + params.incentive_ratio <= 100, + Error::::InvalidIncentiveRatio + ); + + Ok(()) } pub fn set_subnet_params(netuid: u16, params: SubnetParams) { - // TEMPO, IMMUNITY_PERIOD, MIN_ALLOWED_WEIGHTS, MAX_ALLOWED_WEIGHTS, MAX_ALLOWED_UIDS, - // MAX_IMMUNITY_RATIO + // Check if the params are valid + Self::check_subnet_params(¶ms).expect("subnet params are invalid"); + Self::set_founder(netuid, params.founder); Self::set_founder_share(netuid, params.founder_share); Self::set_tempo(netuid, params.tempo); @@ -344,7 +368,6 @@ impl Pallet { } // Initializes a new subnetwork under netuid with parameters. - // pub fn subnet_name_exists(name: Vec) -> bool { for (_netuid, _name) in as IterableStorageMap>>::iter() { if _name == name { @@ -572,7 +595,7 @@ impl Pallet { // ======================== // ==== Global Getters ==== // ======================== - pub fn get_current_block_as_u64() -> u64 { + pub fn get_current_block_number() -> u64 { TryInto::try_into(>::block_number()) .ok() .expect("blockchain will not exceed 2^64 blocks; QED.") @@ -630,7 +653,7 @@ impl Pallet { MaxAllowedSubnets::::get() } pub fn set_global_max_allowed_subnets(max_allowed_subnets: u16) { - MaxAllowedSubnets::::set(max_allowed_subnets) + MaxAllowedSubnets::::put(max_allowed_subnets) } // ============================ // ==== Subnetwork Getters ==== @@ -790,6 +813,11 @@ impl Pallet { true } + #[cfg(debug_assertions)] + pub fn get_trust(netuid: u16) -> Vec { + Trust::::get(netuid) + } + pub fn get_emissions(netuid: u16) -> Vec { Emission::::get(netuid) } @@ -797,11 +825,6 @@ impl Pallet { Incentive::::get(netuid) } - #[cfg(debug_assertions)] - pub fn get_trust(netuid: u16) -> Vec { - Trust::::get(netuid) - } - pub fn get_dividends(netuid: u16) -> Vec { Dividends::::get(netuid) } diff --git a/pallets/subspace/src/voting.rs b/pallets/subspace/src/voting.rs index aa62fe135..c27c7b1b6 100644 --- a/pallets/subspace/src/voting.rs +++ b/pallets/subspace/src/voting.rs @@ -13,6 +13,7 @@ impl Pallet { Self::is_voter_registered(&key), Error::::VoterIsNotRegistered ); + Self::unregister_voter(&key); ensure!( !Self::is_voter_registered(&key), @@ -51,7 +52,6 @@ impl Pallet { } // GLOBAL LAND - pub fn do_add_global_proposal( origin: T::RuntimeOrigin, // params @@ -65,7 +65,6 @@ impl Pallet { } // CUSTOM LAND - pub fn do_add_custom_proposal( origin: T::RuntimeOrigin, // params @@ -80,7 +79,6 @@ impl Pallet { } // SUBNET LAND - pub fn do_add_subnet_proposal( origin: T::RuntimeOrigin, // params @@ -195,9 +193,9 @@ impl Pallet { // check if proposal is valid match mode.as_slice() { - GLOBAL_MODE => Self::check_global_params(proposal.global_params)?, + GLOBAL_MODE => Self::check_global_params(&proposal.global_params)?, SUBNET_MODE => { - Self::check_subnet_params(proposal.subnet_params.clone())?; + Self::check_subnet_params(&proposal.subnet_params.clone())?; // check if vote mode is valid let subnet_params: SubnetParams = Self::subnet_params(proposal.netuid); // TODO: once decentralization is achieved, remove this check diff --git a/pallets/subspace/src/weights.rs b/pallets/subspace/src/weights.rs index 214dabbc9..c5dc77984 100644 --- a/pallets/subspace/src/weights.rs +++ b/pallets/subspace/src/weights.rs @@ -1,7 +1,12 @@ use super::*; -use sp_std::{vec, vec::Vec}; impl Pallet { + // Returns true if the items contain duplicates. + fn contains_duplicates(items: &[u16]) -> bool { + let mut seen = sp_std::collections::btree_set::BTreeSet::new(); + items.iter().any(|item| !seen.insert(item)) + } + pub fn do_set_weights( origin: T::RuntimeOrigin, netuid: u16, @@ -11,141 +16,93 @@ impl Pallet { // --- 1. Check the caller's signature. This is the key of a registered account. let key = ensure_signed(origin)?; - let stake: u64 = Self::get_stake_for_key(netuid, &key); - - // check if the stake per weight is greater than the stake - let min_stake_per_weight: u64 = Self::get_min_weight_stake(); - let min_stake_for_weights: u64 = min_stake_per_weight * uids.len() as u64; + // --- 2. Check that the length of uid list and value list are equal for this network. ensure!( - stake >= min_stake_for_weights, - Error::::NotEnoughtStakePerWeight + uids.len() == values.len(), + Error::::WeightVecNotEqualSize ); - ensure!(stake > 0, Error::::NotEnoughStaketoSetWeights); - - let stake: u64 = Self::get_stake_for_key(netuid, &key); - - ensure!(stake > 0, Error::::NotEnoughStaketoSetWeights); - // --- 2. Check to see if this is a valid network. + // --- 3. Check to see if this is a valid network. ensure!( Self::if_subnet_exist(netuid), Error::::NetworkDoesNotExist ); - // --- 5. Check to see if the key is registered to the passed network. + + // --- 4. Check to see if the key is registered to the passed network. ensure!( Self::is_key_registered_on_network(netuid, &key), Error::::NotRegistered ); - // --- 3. Check that the length of uid list and value list are equal for this network. - ensure!( - Self::uids_match_len(&uids, &values), - Error::::WeightVecNotEqualSize - ); - - // --- 4. Check to see if the number of uids is within the max allowed uids for this - // network. --- 7. Get the module uid of associated key on network netuid. - + // --- 5. Get the module uid of associated key on network netuid. let uid: u16 = Self::get_uid_for_key(netuid, &key); - // --- 10. Ensure the passed uids contain no duplicates. - ensure!(!Self::has_duplicate_uids(&uids), Error::::DuplicateUids); + // --- 6. Ensure the passed uids contain no duplicates. + ensure!(!Self::contains_duplicates(&uids), Error::::DuplicateUids); - // --- 11. Ensure that the passed uids are valid for the network. + // --- 7. Ensure that the passed uids are valid for the network. ensure!( - !Self::contains_invalid_uids(netuid, &uids), + uids.iter().all(|&uid| Self::is_uid_exist_on_network(netuid, uid)), Error::::InvalidUid ); + // --- 8. Check the allowed length of uids. let min_allowed_length: usize = Self::get_min_allowed_weights(netuid) as usize; let max_allowed_length: usize = Self::get_max_allowed_weights(netuid) as usize; + ensure!( + uids.len() >= min_allowed_length && uids.len() <= max_allowed_length, + Error::::InvalidUidsLength + ); - ensure!(!Self::is_self_weight(uid, &uids), Error::::NoSelfWeight); + // --- 9. Ensure the uid is not setting weights for itself. + ensure!(!uids.contains(&uid), Error::::NoSelfWeight); + + // --- 10. Get the stake for the key. + let stake: u64 = Self::get_stake_for_key(netuid, &key); + // --- 11. Check if the stake per weight is greater than the required minimum stake. + let min_stake_per_weight: u64 = Self::get_min_weight_stake(); + let min_stake_for_weights: u64 = min_stake_per_weight * uids.len() as u64; ensure!( - uids.len() >= min_allowed_length, - Error::::NotSettingEnoughWeights + stake >= min_stake_for_weights, + Error::::NotEnoughStakePerWeight ); - ensure!(uids.len() <= max_allowed_length, Error::::TooManyUids); + + // --- 12. Ensure the key has enough stake to set weights. + ensure!(stake > 0, Error::::NotEnoughStakeToSetWeights); // --- 13. Normalize the weights. let normalized_values = Self::normalize_weights(values); - // --- 15. Zip weights for sinking to storage map. - let mut zipped_weights: Vec<(u16, u16)> = vec![]; - for (uid, val) in uids.iter().zip(normalized_values.iter()) { - zipped_weights.push((*uid, *val)) - } + // --- 14. Zip weights for sinking to storage map. + let zipped_weights: Vec<(u16, u16)> = uids + .iter() + .zip(normalized_values.iter()) + .map(|(&uid, &val)| (uid, val)) + .collect(); - // --- 16. Set weights under netuid, uid double map entry. + // --- 15. Set weights under netuid, uid double map entry. Weights::::insert(netuid, uid, zipped_weights); - // --- 8. Ensure the uid is not setting weights faster than the weights_set_rate_limit. - let current_block: u64 = Self::get_current_block_as_u64(); - // --- 17. Set the activity for the weights on this network. + // --- 16. Set the activity for the weights on this network. + let current_block: u64 = Self::get_current_block_number(); Self::set_last_update_for_uid(netuid, uid, current_block); - // --- 18. Emit the tracking event. + // --- 17. Emit the tracking event. Self::deposit_event(Event::WeightsSet(netuid, uid)); - // --- 19. Return ok. Ok(()) } - // Checks for any invalid uids on this network. - pub fn contains_invalid_uids(netuid: u16, uids: &Vec) -> bool { - for uid in uids { - if !Self::is_uid_exist_on_network(netuid, *uid) { - return true; - } - } - false - } - - // Returns true if the passed uids have the same length of the passed values. - fn uids_match_len(uids: &[u16], values: &[u16]) -> bool { - uids.len() == values.len() - } - - // Returns true if the items contain duplicates. - fn has_duplicate_uids(items: &[u16]) -> bool { - let mut parsed = Vec::with_capacity(items.len()); - for item in items { - if parsed.contains(item) { - return true; - } - parsed.push(*item); - } - false - } - // Implace normalizes the passed positive integer weights so that they sum to u16 max value. - pub fn normalize_weights(mut weights: Vec) -> Vec { - let sum: u64 = weights.iter().map(|x| *x as u64).sum(); + pub fn normalize_weights(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; - }); weights - } - - // Returns true if the uids and weights correspond to a self weight on the uid. - pub fn is_self_weight(uid: u16, uids: &[u16]) -> bool { - uids.contains(&uid) - } - - #[cfg(debug_assertions)] - pub fn check_len_uids_within_allowed(netuid: u16, uids: &[u16]) -> bool { - let min_allowed_length: usize = Self::get_min_allowed_weights(netuid) as usize; - let max_allowed_length: usize = Self::get_max_allowed_weights(netuid) as usize; - if uids.len() > max_allowed_length { - return false; - } - if uids.len() < min_allowed_length { - return false; - } - true + .into_iter() + .map(|x| ((x as u64 * u16::max_value() as u64) / sum) as u16) + .collect() } } diff --git a/pallets/subspace/tests/delegate_staking.rs b/pallets/subspace/tests/delegate_staking.rs index 2fbb2b4ec..f0086f824 100644 --- a/pallets/subspace/tests/delegate_staking.rs +++ b/pallets/subspace/tests/delegate_staking.rs @@ -1,6 +1,7 @@ mod mock; use frame_support::assert_ok; +use log::info; use mock::*; use sp_core::U256; use substrate_fixed::types::I64F64; @@ -36,7 +37,7 @@ fn test_ownership_ratio() { assert_eq!(pre_delegate_stake_from_vector.len(), 1); // +1 for the module itself, +1 for the delegate key on for (i, d) in delegate_keys.iter().enumerate() { - println!("DELEGATE KEY: {}", d); + info!("DELEGATE KEY: {d}"); assert_ok!(SubspaceModule::add_stake( get_origin(*d), netuid, @@ -94,14 +95,11 @@ fn test_ownership_ratio() { .sum::(); let total_tokens_before = total_balance + total_stake + total_delegate_stake + total_delegate_balance; - println!("total_tokens_before: {:?}", total_tokens_before); + info!("total_tokens_before: {total_tokens_before:?}"); - println!("delegate_balances before: {:?}", delegate_balances_before); - println!("delegate_stakes before: {:?}", delegate_stakes_before); - println!( - "delegate_total_tokens before: {:?}", - delegate_total_tokens_before - ); + info!("delegate_balances before: {delegate_balances_before:?}"); + info!("delegate_stakes before: {delegate_stakes_before:?}"); + info!("delegate_total_tokens before: {delegate_total_tokens_before:?}"); let result = SubspaceModule::set_weights( get_origin(voter_key), @@ -118,12 +116,12 @@ fn test_ownership_ratio() { let incentives = SubspaceModule::get_incentives(netuid); let emissions = SubspaceModule::get_emissions(netuid); - println!("dividends: {:?}", dividends); - println!("incentives: {:?}", incentives); - println!("emissions: {:?}", emissions); + info!("dividends: {dividends:?}"); + info!("incentives: {incentives:?}"); + info!("emissions: {emissions:?}"); let total_emissions = emissions.iter().sum::(); - println!("total_emissions: {:?}", total_emissions); + info!("total_emissions: {total_emissions:?}"); let delegate_balances = delegate_keys.iter().map(SubspaceModule::get_balance).collect::>(); @@ -147,14 +145,14 @@ fn test_ownership_ratio() { let total_new_tokens = founder_new_tokens + delegate_new_tokens.iter().sum::(); - println!("owner_ratios: {:?}", ownership_ratios); - println!("total_new_tokens: {:?}", total_new_tokens); - println!("founder_tokens: {:?}", founder_tokens); - println!("delegate_balances: {:?}", delegate_balances); - println!("delegate_stakes: {:?}", delegate_stakes); - println!("delegate_total_tokens: {:?}", delegate_total_tokens); - println!("founder_new_tokens: {:?}", founder_new_tokens); - println!("delegate_new_tokens: {:?}", delegate_new_tokens); + info!("owner_ratios: {ownership_ratios:?}"); + info!("total_new_tokens: {total_new_tokens:?}"); + info!("founder_tokens: {founder_tokens:?}"); + info!("delegate_balances: {delegate_balances:?}"); + info!("delegate_stakes: {delegate_stakes:?}"); + info!("delegate_total_tokens: {delegate_total_tokens:?}"); + info!("founder_new_tokens: {founder_new_tokens:?}"); + info!("delegate_new_tokens: {delegate_new_tokens:?}"); let total_balance = keys .iter() @@ -183,14 +181,14 @@ fn test_ownership_ratio() { let total_tokens_after = total_balance + total_stake + total_delegate_stake + total_delegate_balance; let total_new_tokens = total_tokens_after - total_tokens_before; - println!("total_tokens_after: {:?}", total_tokens_before); - println!("total_new_tokens: {:?}", total_new_tokens); + info!("total_tokens_after: {total_tokens_before:?}"); + info!("total_new_tokens: {total_new_tokens:?}"); assert_eq!(total_new_tokens, total_emissions); let stake_from_vector = SubspaceModule::get_stake_from_vector(netuid, &voter_key); let _stake: u64 = SubspaceModule::get_stake(netuid, &voter_key); let _sumed_stake: u64 = stake_from_vector.iter().fold(0, |acc, (_a, x)| acc + x); let _total_stake: u64 = SubspaceModule::get_total_subnet_stake(netuid); - println!("stake_from_vector: {:?}", stake_from_vector); + info!("stake_from_vector: {stake_from_vector:?}"); }); } diff --git a/pallets/subspace/tests/mock.rs b/pallets/subspace/tests/mock.rs index 422fec9d2..a8d763681 100644 --- a/pallets/subspace/tests/mock.rs +++ b/pallets/subspace/tests/mock.rs @@ -11,6 +11,8 @@ use sp_runtime::{ BuildStorage, DispatchResult, }; +use log::info; + type Block = frame_system::mocking::MockBlock; const TOKEN_DECIMALS: u32 = 9; @@ -236,7 +238,7 @@ pub fn delegate_register_module( if stake >= balance { add_balance(key, stake + 1); } - println!("Registering module: network: {network:?}, key: {module_key:?} stake {balance:?}",); + info!("Registering module: network: {network:?}, key: {module_key:?} stake {balance:?}",); let result = SubspaceModule::register(origin, network, name.clone(), address, stake, module_key); diff --git a/pallets/subspace/tests/profit_share.rs b/pallets/subspace/tests/profit_share.rs index 2f0af3455..f6ede164a 100644 --- a/pallets/subspace/tests/profit_share.rs +++ b/pallets/subspace/tests/profit_share.rs @@ -1,6 +1,7 @@ mod mock; use frame_support::assert_ok; +use log::info; use mock::*; use sp_core::U256; use sp_std::vec; @@ -29,13 +30,13 @@ fn test_add_profit_share() { assert_ok!(result); let profit_shares = SubspaceModule::get_profit_shares(miner_key); assert_eq!(profit_shares.len(), shares.len(), "profit shares not added"); - println!("founder profit shares: {profit_shares:?}"); + info!("founder profit shares: {profit_shares:?}"); let result = SubspaceModule::set_weights(get_origin(voter_key), netuid, vec![miner_uid], vec![1]); assert_ok!(result); let params = SubspaceModule::subnet_params(netuid); - println!("params: {params:?}"); + info!("params: {params:?}"); let miner_emission = SubspaceModule::get_emission_for_key(netuid, &miner_key); let voter_emission = SubspaceModule::get_emission_for_key(netuid, &voter_key); assert_eq!(miner_emission, voter_emission, "emission not equal"); @@ -43,8 +44,8 @@ fn test_add_profit_share() { assert!(voter_emission == 0, "emission not equal"); let miner_stake = SubspaceModule::get_stake_for_key(netuid, &miner_key); let voter_stake = SubspaceModule::get_stake_for_key(netuid, &voter_key); - println!("miner stake before: {miner_stake:?}"); - println!("voter stake before: {voter_stake:?}"); + info!("miner stake before: {miner_stake:?}"); + info!("voter stake before: {voter_stake:?}"); step_epoch(netuid); let miner_emission = SubspaceModule::get_emission_for_key(netuid, &miner_key); let voter_emission = SubspaceModule::get_emission_for_key(netuid, &voter_key); @@ -52,20 +53,20 @@ fn test_add_profit_share() { assert!(voter_emission > 0, "emission not equal"); assert_eq!(miner_emission, voter_emission, "emission not equal"); - println!("miner emission: {miner_emission:?}"); - println!("voter emission: {voter_emission:?}"); + info!("miner emission: {miner_emission:?}"); + info!("voter emission: {voter_emission:?}"); let miner_balance = SubspaceModule::get_balance_u64(&miner_key); let voter_balance = SubspaceModule::get_balance_u64(&voter_key); - println!("miner balance: {miner_balance:?}"); - println!("voter balance: {voter_balance:?}"); + info!("miner balance: {miner_balance:?}"); + info!("voter balance: {voter_balance:?}"); let miner_stake = SubspaceModule::get_stake_for_key(netuid, &miner_key); let voter_stake = SubspaceModule::get_stake_for_key(netuid, &voter_key); - println!("miner stake after: {miner_stake:?}"); - println!("voter stake after: {voter_stake:?}"); + info!("miner stake after: {miner_stake:?}"); + info!("voter stake after: {voter_stake:?}"); let _emission_for_subnet = SubspaceModule::get_subnet_emission(netuid); let profit_share_emissions = SubspaceModule::get_profit_shares(miner_key); - println!("profit share emissions: {profit_share_emissions:?}"); + info!("profit share emissions: {profit_share_emissions:?}"); // check the profit sharers let mut profit_share_balances: Vec = Vec::new(); @@ -73,8 +74,8 @@ fn test_add_profit_share() { let profit_share_balance = SubspaceModule::get_stake_to_total(netuid, profit_sharer_key); let stake_to_vector = SubspaceModule::get_stake_to_vector(netuid, profit_sharer_key); - println!("profit share balance: {stake_to_vector:?}"); - println!("profit share balance: {profit_share_balance:?}"); + info!("profit share balance: {stake_to_vector:?}"); + info!("profit share balance: {profit_share_balance:?}"); profit_share_balances.push(profit_share_balance); assert!(profit_share_balances[0] > 0, "profit share balance is zero"); } diff --git a/pallets/subspace/tests/registration.rs b/pallets/subspace/tests/registration.rs index b31d11b1e..9189c7173 100644 --- a/pallets/subspace/tests/registration.rs +++ b/pallets/subspace/tests/registration.rs @@ -4,6 +4,7 @@ use frame_support::{assert_err, assert_ok}; use mock::*; use sp_core::U256; +use log::info; use pallet_subspace::Error; /******************************************** @@ -33,10 +34,10 @@ fn test_min_stake() { for key in keys_list { let _ = register_module(netuid, key, min_stake_to_register); - println!("registered module with key: {key:?} and min_stake_to_register: {min_stake_to_register:?}"); + info!("registered module with key: {key:?} and min_stake_to_register: {min_stake_to_register:?}"); } let registrations_this_block = SubspaceModule::get_registrations_this_block(); - println!("registrations_this_block: {registrations_this_block:?}"); + info!("registrations_this_block: {registrations_this_block:?}"); assert_eq!(registrations_this_block, max_registrations_per_block); step_block(1); @@ -61,7 +62,7 @@ fn test_max_registration() { let key = U256::from(i); let min_stake_to_register = SubspaceModule::get_min_stake(netuid); let factor: u64 = min_stake_to_register / min_stake; - println!("min_stake_to_register: {min_stake_to_register:?} min_stake: {min_stake:?} factor {factor:?}"); + info!("min_stake_to_register: {min_stake_to_register:?} min_stake: {min_stake:?} factor {factor:?}"); register_module(netuid, key, factor * min_stake).expect("register module failed"); let registrations_this_block = SubspaceModule::get_registrations_this_block(); @@ -87,9 +88,9 @@ fn test_delegate_register() { .expect("delegate register module failed"); let key_balance = SubspaceModule::get_balance_u64(&key); let stake_to_module = SubspaceModule::get_stake_to_module(netuid, &key, &module_key); - println!("key_balance: {key_balance:?}"); + info!("key_balance: {key_balance:?}"); let stake_to_vector = SubspaceModule::get_stake_to_vector(netuid, &key); - println!("stake_to_vector: {stake_to_vector:?}"); + info!("stake_to_vector: {stake_to_vector:?}"); assert_eq!(stake_to_module, stake_amount); } }); @@ -150,14 +151,14 @@ fn test_registration_with_stake() { let stake_value: u64 = *stake; let key = U256::from(uid); - println!("key: {key:?}"); - println!("stake: {stake_value:?}"); + info!("key: {key:?}"); + info!("stake: {stake_value:?}"); let stake_before: u64 = SubspaceModule::get_stake(netuid, &key); - println!("stake_before: {stake_before:?}"); + info!("stake_before: {stake_before:?}"); register_module(netuid, key, stake_value).unwrap_or_else(|_| { panic!("Failed to register module with key: {key:?} and stake: {stake_value:?}",) }); - println!("balance: {:?}", SubspaceModule::get_balance_u64(&key)); + info!("balance: {:?}", SubspaceModule::get_balance_u64(&key)); assert_eq!(SubspaceModule::get_stake_for_uid(netuid, uid), stake_value); } }); diff --git a/pallets/subspace/tests/staking.rs b/pallets/subspace/tests/staking.rs index d9683e85f..fca19618d 100644 --- a/pallets/subspace/tests/staking.rs +++ b/pallets/subspace/tests/staking.rs @@ -1,9 +1,11 @@ mod mock; use frame_support::assert_ok; +use log::info; use mock::*; use sp_core::U256; use substrate_fixed::types::I64F64; + // /*********************************************************** // staking::add_stake() tests // ************************************************************/ @@ -17,13 +19,13 @@ fn test_stake() { let mut subnet_stake: u64 = 0; for netuid in netuids { - println!("NETUID: {}", netuid); + info!("NETUID: {}", netuid); let amount_staked = amount_staked_vector[netuid as usize]; let key_vector: Vec = (0..max_uids).map(|i| U256::from(i + max_uids * netuid)).collect(); for key in key_vector.iter() { - println!( + info!( " KEY {} KEY STAKE {} STAKING AMOUNT {} ", key, SubspaceModule::get_stake(netuid, key), @@ -32,7 +34,7 @@ fn test_stake() { assert_ok!(register_module(netuid, *key, amount_staked)); // add_stake_and_balance(netuid, *key, amount_staked); - println!( + info!( " KEY STAKE {} STAKING AMOUNT {} ", SubspaceModule::get_stake(netuid, key), amount_staked @@ -69,8 +71,8 @@ fn test_stake() { total_stake += subnet_stake; assert_eq!(SubspaceModule::total_stake(), total_stake); subnet_stake = 0; - println!("TOTAL STAKE: {}", total_stake); - println!( + info!("TOTAL STAKE: {}", total_stake); + info!( "TOTAL SUBNET STAKE: {}", SubspaceModule::get_total_subnet_stake(netuid) ); @@ -101,13 +103,13 @@ fn test_multiple_stake() { let stake_amounts: Vec = vec![stake_amount; num_staked_modules as usize]; - println!("STAKE AMOUNTS: {:?}", stake_amounts); + info!("STAKE AMOUNTS: {stake_amounts:?}"); let total_actual_stake: u64 = keys.clone().into_iter().map(|k| SubspaceModule::get_stake(netuid, &k)).sum(); let staker_balance = SubspaceModule::get_balance(&controler_key); - println!("TOTAL ACTUAL STAKE: {}", total_actual_stake); - println!("TOTAL STAKE: {}", total_stake); - println!("STAKER BALANCE: {}", staker_balance); + info!("TOTAL ACTUAL STAKE: {total_actual_stake}"); + info!("TOTAL STAKE: {total_stake}"); + info!("STAKER BALANCE: {staker_balance}"); assert_ok!(SubspaceModule::add_stake_multiple( get_origin(controler_key), netuid, @@ -206,14 +208,14 @@ fn test_delegate_stake() { for i in netuids.iter() { let netuid = *i; - println!("NETUID: {}", netuid); + info!("NETUID: {}", netuid); let amount_staked = amount_staked_vector[netuid as usize]; let key_vector: Vec = (0..max_uids).map(|i| U256::from(i + max_uids * netuid)).collect(); let delegate_key_vector: Vec = key_vector.iter().map(|i| (*i + 1)).collect(); for (i, key) in key_vector.iter().enumerate() { - println!( + info!( " KEY {} KEY STAKE {} STAKING AMOUNT {} ", key, SubspaceModule::get_stake(netuid, key), @@ -225,7 +227,7 @@ fn test_delegate_stake() { assert_ok!(register_module(netuid, *key, 0)); // add_stake_and_balance(netuid, *key, amount_staked); - println!( + info!( " DELEGATE KEY STAKE {} STAKING AMOUNT {} ", SubspaceModule::get_stake(netuid, &delegate_key), amount_staked @@ -289,8 +291,8 @@ fn test_delegate_stake() { total_stake += subnet_stake; assert_eq!(SubspaceModule::total_stake(), total_stake); subnet_stake = 0; - println!("TOTAL STAKE: {}", total_stake); - println!( + info!("TOTAL STAKE: {}", total_stake); + info!( "TOTAL SUBNET STAKE: {}", SubspaceModule::get_total_subnet_stake(netuid) ); @@ -318,9 +320,9 @@ fn test_ownership_ratio() { let pre_delegate_stake_from_vector = SubspaceModule::get_stake_from_vector(netuid, k); assert_eq!(pre_delegate_stake_from_vector.len(), 1); // +1 for the module itself, +1 for the delegate key on - println!("KEY: {}", k); + info!("KEY: {}", k); for (i, d) in delegate_keys.iter().enumerate() { - println!("DELEGATE KEY: {}", d); + info!("DELEGATE KEY: {d}"); assert_ok!(SubspaceModule::add_stake( get_origin(*d), netuid, @@ -337,7 +339,7 @@ fn test_ownership_ratio() { SubspaceModule::get_ownership_ratios(netuid, k); assert_eq!(ownership_ratios.len(), delegate_keys.len() + 1); - println!("OWNERSHIP RATIOS: {:?}", ownership_ratios); + info!("OWNERSHIP RATIOS: {ownership_ratios:?}"); // step_block(); step_epoch(netuid); @@ -347,14 +349,14 @@ fn test_ownership_ratio() { let sumed_stake: u64 = stake_from_vector.iter().fold(0, |acc, (_a, x)| acc + x); let total_stake: u64 = SubspaceModule::get_total_subnet_stake(netuid); - println!("STAKE: {}", stake); - println!("SUMED STAKE: {}", sumed_stake); - println!("TOTAL STAKE: {}", total_stake); + info!("STAKE: {}", stake); + info!("SUMED STAKE: {sumed_stake}"); + info!("TOTAL STAKE: {total_stake}"); assert_eq!(stake, sumed_stake); // for (d_a, o) in ownership_ratios.iter() { - // println!("OWNERSHIP RATIO: {}", o); + // info!("OWNERSHIP RATIO: {}", o); // } } diff --git a/pallets/subspace/tests/step.rs b/pallets/subspace/tests/step.rs index 309ecfb37..d3d531267 100644 --- a/pallets/subspace/tests/step.rs +++ b/pallets/subspace/tests/step.rs @@ -1,6 +1,7 @@ mod mock; use frame_support::assert_ok; +use log::info; use mock::*; use sp_core::U256; @@ -15,14 +16,13 @@ fn check_network_stats(netuid: u16) { let total_dividends: u16 = dividends.iter().sum(); let total_emissions: u64 = emissions.iter().sum(); - println!("total_emissions: {}", total_emissions); - println!("total_incentives: {}", total_incentives); - println!("total_dividends: {}", total_dividends); + info!("total_emissions: {total_emissions}"); + info!("total_incentives: {total_incentives}"); + info!("total_dividends: {total_dividends}"); - println!("emission: {:?}", emissions); - println!("incentives: {:?}", incentives); - println!("incentives: {:?}", incentives); - println!("dividends: {:?}", dividends); + info!("emission: {emissions:?}"); + info!("incentives: {incentives:?}"); + info!("dividends: {dividends:?}"); assert!( total_emissions >= subnet_emission - emission_buffer @@ -75,12 +75,6 @@ fn test_dividends_same_stake() { SubspaceModule::set_max_allowed_weights(netuid, n); SubspaceModule::set_min_allowed_weights(netuid, 0); - // for i in 0..n { - - // let key: U256 = U256::from(i); - // register_module( netuid, key, stake_per_module ); - - // } let keys = SubspaceModule::get_keys(netuid); let _uids = SubspaceModule::get_uids(netuid); @@ -125,7 +119,7 @@ fn test_dividends_same_stake() { assert_eq!(incentives[0], incentives[1]); assert_eq!(dividends[2], dividends[3]); - println!("emissions: {:?}", emissions); + info!("emissions: {emissions:?}"); for (uid, emission) in emissions.iter().enumerate() { if emission == &0 { @@ -174,12 +168,6 @@ fn test_dividends_diff_stake() { SubspaceModule::set_max_allowed_weights(netuid, n); SubspaceModule::set_min_allowed_weights(netuid, 0); - // for i in 0..n { - - // let key: U256 = U256::from(i); - // register_module( netuid, key, stake_per_module ); - - // } let keys = SubspaceModule::get_keys(netuid); let _uids = SubspaceModule::get_uids(netuid); @@ -215,7 +203,7 @@ fn test_dividends_diff_stake() { assert_eq!(incentives[0], incentives[1]); assert_eq!(dividends[2], dividends[3]); - println!("emissions: {:?}", emissions); + info!("emissions: {emissions:?}"); for (uid, emission) in emissions.iter().enumerate() { if emission == &0 { @@ -235,7 +223,6 @@ fn test_dividends_diff_stake() { expected_stake_difference ); } - check_network_stats(netuid); }); } @@ -362,12 +349,12 @@ fn test_lowest_priority_mechanism() { assert!(dividends[prune_uid as usize] == 0); let lowest_priority_uid: u16 = SubspaceModule::get_lowest_uid(netuid); - println!("lowest_priority_uid: {}", lowest_priority_uid); - println!("prune_uid: {}", prune_uid); - println!("emissions: {:?}", emissions); - println!("lowest_priority_uid: {:?}", lowest_priority_uid); - println!("dividends: {:?}", dividends); - println!("incentives: {:?}", incentives); + info!("lowest_priority_uid: {lowest_priority_uid}"); + info!("prune_uid: {prune_uid}"); + info!("emissions: {emissions:?}"); + info!("lowest_priority_uid: {lowest_priority_uid:?}"); + info!("dividends: {dividends:?}"); + info!("incentives: {incentives:?}"); assert!(lowest_priority_uid == prune_uid); check_network_stats(netuid); }); @@ -426,22 +413,22 @@ fn test_lowest_priority_mechanism() { // let stake_per_module: u64 = 10_000; // for (netuid, n) in n_list.iter().enumerate() { -// println!("netuid: {}", netuid); +// info!("netuid: {}", netuid); // let netuid: u16 = netuid as u16; // let n: u16 = *n; // for i in 0..n { -// println!("i: {}", i); -// println!("keys: {:?}", SubspaceModule::get_keys(netuid)); -// println!("uids: {:?}", SubspaceModule::get_uids(netuid)); +// info!("i: {}", i); +// info!("keys: {:?}", SubspaceModule::get_keys(netuid)); +// info!("uids: {:?}", SubspaceModule::get_uids(netuid)); // let key: U256 = U256::from(i); -// println!( +// info!( // "Before Registered: {:?} -> {:?}", // key, // SubspaceModule::key_registered(netuid, &key) // ); // register_module(netuid, key, stake_per_module); -// println!( +// info!( // "After Registered: {:?} -> {:?}", // key, // SubspaceModule::key_registered(netuid, &key) @@ -571,7 +558,7 @@ fn test_trust() { register_n_modules(netuid, n, stake_per_module); let mut params = SubspaceModule::subnet_params(netuid); - params.min_allowed_weights = 0; + params.min_allowed_weights = 1; params.max_allowed_weights = n; params.tempo = 100; params.trust_ratio = 100; @@ -596,11 +583,11 @@ fn test_trust() { let emission: Vec = SubspaceModule::get_emissions(netuid); // evaluate votees - println!("trust: {:?}", trust); + info!("trust: {:?}", trust); assert!(trust[1] as u32 > 0); assert!(trust[2] as u32 > 2 * (trust[1] as u32) - 10); // evaluate votees - println!("trust: {:?}", emission); + info!("trust: {emission:?}"); assert!(emission[1] > 0); assert!(emission[2] > 2 * (emission[1]) - 1000); @@ -743,8 +730,8 @@ fn test_trust() { // let test_key_difference: u64 = // stake_amount - test_key_stake_from_vector_before[i].1; -// println!("test_key_difference: {}", test_key_difference); -// println!("test_key_difference: {}", expected_emission); +// info!("test_key_difference: {}", test_key_difference); +// info!("test_key_difference: {}", expected_emission); // assert!( // test_key_difference < expected_emission + errror_delta || @@ -772,30 +759,30 @@ fn test_trust() { // lowest_priority_balance // ); // assert!(SubspaceModule::key_registered(netuid, &lowest_priority_key)); -// println!("lowest_priority_key: {:?}", lowest_priority_key); -// println!("lowest_priority_stake: {:?}", lowest_priority_stake); -// println!("lowest_priority_balance: {:?}", lowest_priority_balance); +// info!("lowest_priority_key: {:?}", lowest_priority_key); +// info!("lowest_priority_stake: {:?}", lowest_priority_stake); +// info!("lowest_priority_balance: {:?}", lowest_priority_balance); // let lowest_prioirty_self_stake: u64 = // SubspaceModule::get_self_stake(netuid, &lowest_priority_key); // let new_key: U256 = U256::from(n + i as u16 + 1); // register_module(netuid, new_key, stake_per_module); -// println!("n: {:?}", n); -// println!("get_subnet_n: {:?}", SubspaceModule::get_subnet_n(netuid)); -// println!("max_allowed: {:?}", SubspaceModule::get_max_allowed_uids(netuid)); +// info!("n: {:?}", n); +// info!("get_subnet_n: {:?}", SubspaceModule::get_subnet_n(netuid)); +// info!("max_allowed: {:?}", SubspaceModule::get_max_allowed_uids(netuid)); // assert!(SubspaceModule::get_subnet_n(netuid) == n); // assert!(!SubspaceModule::key_registered(netuid, &lowest_priority_key)); -// println!("lowest_priority_key: {:?}", lowest_priority_key); -// println!("lowest_priority_stake: {:?}", lowest_priority_stake); -// println!("lowest_priority_balance: {:?}", lowest_priority_balance); +// info!("lowest_priority_key: {:?}", lowest_priority_key); +// info!("lowest_priority_stake: {:?}", lowest_priority_stake); +// info!("lowest_priority_balance: {:?}", lowest_priority_balance); // let emissions: Vec = SubspaceModule::get_emissions(netuid); // let total_emission: u64 = emissions.iter().sum(); -// println!("subnet total_emission: {:?}", total_emission); -// println!("expected_total_stake: {:?}", expected_total_stake); +// info!("subnet total_emission: {:?}", total_emission); +// info!("expected_total_stake: {:?}", expected_total_stake); // assert!(!SubspaceModule::key_registered(netuid, &lowest_priority_key)); @@ -850,7 +837,7 @@ fn test_founder_share() { for i in 0..n { assert_ok!(register_module(netuid, keys[i], stakes[i])); let stake_from_vector = SubspaceModule::get_stake_to_vector(netuid, &keys[i]); - println!("{:?}", stake_from_vector); + info!("{:?}", stake_from_vector); } SubspaceModule::set_founder_share(netuid, 50); let founder_share = SubspaceModule::get_founder_share(netuid); @@ -859,7 +846,7 @@ fn test_founder_share() { let subnet_params = SubspaceModule::subnet_params(netuid); let founder_stake_before = SubspaceModule::get_stake_for_key(netuid, &founder_key); - println!("founder_stake_before: {:?}", founder_stake_before); + info!("founder_stake_before: {founder_stake_before:?}"); // vote to avoid key[0] as we want to see the key[0] burn step_epoch(netuid); let total_emission = @@ -872,8 +859,8 @@ fn test_founder_share() { let total_dividends: u64 = dividends.iter().sum::() as u64; let total_incentives: u64 = incentives.iter().sum::() as u64; - println!("total_dividends: {:?}", total_dividends); - println!("total_incentives: {:?}", total_incentives); + info!("total_dividends: {total_dividends:?}"); + info!("total_incentives: {total_incentives:?}"); let expected_emission_after_founder_share = expected_emission - expected_founder_share; let founder_dividend_emission = ((dividends[0] as f64 / total_dividends as f64) * (expected_emission_after_founder_share / 2) as f64) @@ -883,10 +870,10 @@ fn test_founder_share() { as u64; let founder_emission = founder_incentive_emission + founder_dividend_emission; - println!("emissions: {:?}", emissions); - println!("dividends: {:?}", dividends); - println!("incentives: {:?}", incentives); - println!("founder_emission FAM: {:?}", founder_emission); + info!("emissions: {emissions:?}"); + info!("dividends: {dividends:?}"); + info!("incentives: {incentives:?}"); + info!("founder_emission FAM: {founder_emission:?}"); let calcualted_total_emission = emissions.iter().sum::(); let calculated_founder_share = SubspaceModule::get_stake_for_key(netuid, &founder_key) @@ -894,8 +881,8 @@ fn test_founder_share() { - founder_emission; let delta: u64 = 100000; - println!("expected_emission: {:?}", expected_emission); - println!("total_emission: {:?}", total_emission); + info!("expected_emission: {expected_emission:?}"); + info!("total_emission: {total_emission:?}"); assert!( expected_emission > calcualted_total_emission - delta, "expected_emission: {} != calcualted_total_emission: {}", @@ -909,7 +896,7 @@ fn test_founder_share() { calcualted_total_emission ); - println!("expected_founder_share: {:?}", expected_founder_share); + info!("expected_founder_share: {:?}", expected_founder_share); assert!( expected_founder_share > calculated_founder_share - delta, "expected_founder_share: {} != calculated_founder_share: {}", diff --git a/pallets/subspace/tests/subnets.rs b/pallets/subspace/tests/subnets.rs index 3489bedac..e5313c6a6 100644 --- a/pallets/subspace/tests/subnets.rs +++ b/pallets/subspace/tests/subnets.rs @@ -1,6 +1,7 @@ mod mock; use frame_support::assert_ok; +use log::info; use mock::*; use sp_core::U256; use sp_std::vec; @@ -22,7 +23,7 @@ fn test_add_subnets() { for j in 0..n { if j != i { let n = SubspaceModule::get_subnet_n(i); - println!("registering module i:{} j:{} n:{}", i, j, n); + info!("registering module i:{} j:{} n:{}", i, j, n); assert_ok!(register_module(i, U256::from(j), stake_per_module)); } } @@ -46,9 +47,9 @@ fn test_add_subnets() { let keys = SubspaceModule::get_keys(netuid); - println!("total stake {}", total_stake); - println!("total balance {}", total_balance); - println!("total tokens before {}", total_tokens_before); + info!("total stake {total_stake}"); + info!("total balance {total_balance}"); + info!("total tokens before {total_tokens_before}"); assert_eq!(keys.len() as u16, n); assert!(SubspaceModule::check_subnet_storage(netuid)); @@ -57,7 +58,7 @@ fn test_add_subnets() { assert!(SubspaceModule::check_subnet_storage(netuid)); let total_tokens_after: u64 = keys.iter().map(SubspaceModule::get_balance_u64).sum(); - println!("total tokens after {}", total_tokens_after); + info!("total tokens after {}", total_tokens_after); assert_eq!(total_tokens_after, total_tokens_before); expected_subnets = expected_subnets.saturating_sub(1); @@ -111,7 +112,7 @@ fn test_set_single_temple(tempo: u16) { let n_epochs = 3; let n_steps = n_epochs * tempo; for _i in 0..n_steps { - println!( + info!( "tempo {} block number: {} stake {} pending_emissiion {}", tempo, block_number(), @@ -124,16 +125,14 @@ fn test_set_single_temple(tempo: u16) { let dividends: Vec = SubspaceModule::get_dividends(netuid); let emissions: Vec = SubspaceModule::get_emissions(netuid); - println!("emission {:?}", emissions); - println!("incentives {:?}", incentives); - println!("dividends {:?}", dividends); - // println!("EMMISSIONS {:?}", SubspaceModule::get_ownership_ratios_emission(netuid, - // &U256::from(0),emissions[0] )); + info!("emission {emissions:?}"); + info!("incentives {incentives:?}"); + info!("dividends {dividends:?}"); let stake: u64 = SubspaceModule::get_stake_for_uid(netuid, 0); - println!("stake {:?}", stake); + info!("stake {:?}", stake); total_stake = SubspaceModule::get_total_subnet_stake(netuid); - println!("total stake {}", total_stake); + info!("total stake {}", total_stake); } assert_eq!( @@ -185,7 +184,7 @@ fn test_emission_ratio() { expected_emission ); assert!(block == 0, "block {} is not 0", block); - println!("block {} subnet_emission {} ", block, subnet_emission); + info!("block {} subnet_emission {} ", block, subnet_emission); } }); } @@ -247,7 +246,7 @@ fn test_set_max_allowed_uids_shrinking() { let extra_uids: u16 = 20; let mut n = SubspaceModule::get_subnet_n(netuid); - println!("registering module {}", n); + info!("registering module {}", n); assert_ok!(register_module(netuid, U256::from(0), stake)); SubspaceModule::set_max_allowed_uids(netuid, max_uids + extra_uids); SubspaceModule::set_max_registrations_per_block(max_uids + extra_uids); @@ -265,8 +264,8 @@ fn test_set_max_allowed_uids_shrinking() { let mut total_stake: u64 = SubspaceModule::get_total_subnet_stake(netuid); let mut expected_stake: u64 = n as u64 * stake; - println!("total stake {}", total_stake); - println!("expected stake {}", expected_stake); + info!("total stake {total_stake}"); + info!("expected stake {expected_stake}"); assert_eq!(total_stake, expected_stake); let _subnet = SubspaceModule::subnet_info(netuid); @@ -275,8 +274,8 @@ fn test_set_max_allowed_uids_shrinking() { params.max_allowed_uids = max_uids; let result = SubspaceModule::do_update_subnet(get_origin(keys[0]), netuid, params); let global_params = SubspaceModule::global_params(); - println!("global params {:?}", global_params); - println!("subnet params {:?}", SubspaceModule::subnet_params(netuid)); + info!("global params {:?}", global_params); + info!("subnet params {:?}", SubspaceModule::subnet_params(netuid)); assert_ok!(result); let params = SubspaceModule::subnet_params(netuid); let n = SubspaceModule::get_subnet_n(netuid); @@ -292,7 +291,7 @@ fn test_set_max_allowed_uids_shrinking() { let stake_vector: Vec = SubspaceModule::get_stakes(netuid); let calc_stake: u64 = stake_vector.iter().sum(); - println!("calculated stake {}", calc_stake); + info!("calculated stake {}", calc_stake); expected_stake = (max_uids) as u64 * stake; let _subnet_stake = SubspaceModule::get_total_subnet_stake(netuid); diff --git a/pallets/subspace/tests/voting.rs b/pallets/subspace/tests/voting.rs index 43278c24b..47b6069a0 100644 --- a/pallets/subspace/tests/voting.rs +++ b/pallets/subspace/tests/voting.rs @@ -3,10 +3,11 @@ use frame_support::assert_ok; use mock::*; +use log::info; use sp_core::U256; use sp_std::vec; -/* TO DO SAM: write test for LatuUpdate after it is set */ +/* TODO SAM: write test for LatuUpdate after it is set */ #[test] fn test_subnet_porposal() { @@ -25,7 +26,7 @@ fn test_subnet_porposal() { "vote mode not set" ); params.vote_mode = "stake".as_bytes().to_vec(); - println!("params: {:?}", params); + info!("params: {params:?}"); SubspaceModule::set_subnet_params(netuid, params.clone()); let mut params = SubspaceModule::subnet_params(netuid); let _initial_tempo = params.tempo; @@ -45,7 +46,7 @@ fn test_subnet_porposal() { // we have not passed the threshold yet let proposals = SubspaceModule::get_subnet_proposals(netuid); - println!("proposals: {:?}", proposals); + info!("proposals: {proposals:?}"); assert_eq!(proposals.len(), 1, "proposal not added"); assert_eq!(proposals[0].votes, stakes[0], "proposal not added"); @@ -60,7 +61,7 @@ fn test_subnet_porposal() { assert_eq!(proposal.votes, stakes[0] + stakes[1], "proposal not voted"); assert!(proposal.accepted, "proposal not voted"); - println!("proposal: {:?}", proposal); + info!("proposal: {proposal:?}"); let params = SubspaceModule::subnet_params(netuid); assert_eq!(params.tempo, final_tempo, "proposal not voted"); @@ -90,7 +91,7 @@ fn test_max_proposals() { ); params.vote_mode = "stake".as_bytes().to_vec(); params.max_proposals = (n / 2) as u64; - println!("params: {:?}", params); + info!("params: {params:?}"); SubspaceModule::set_global_params(params.clone()); assert_eq!( @@ -128,10 +129,10 @@ fn test_max_proposals() { let num_proposals = SubspaceModule::num_proposals(); let proposals = SubspaceModule::get_global_proposals(); let has_max_proposals = SubspaceModule::has_max_proposals(); - println!("max_proposals: {:?}", max_proposals); - println!("has_max_proposals: {:?}", has_max_proposals); - println!("num_proposals: {:?}", num_proposals); - println!("proposals: {:?}", proposals.len()); + info!("max_proposals: {max_proposals:?}"); + info!("has_max_proposals: {has_max_proposals:?}"); + info!("num_proposals: {num_proposals:?}"); + info!("proposals {:?}", proposals.len()); let num_subnet_proposals = SubspaceModule::num_subnet_proposals(netuid); let num_global_proposals = SubspaceModule::num_global_proposals(); @@ -174,7 +175,7 @@ fn test_global_porposal() { } let mut params = SubspaceModule::global_params(); - eprintln!("{}", params.min_burn); + info!("{}", params.min_burn); let _initial_max_registrations_per_block = params.max_registrations_per_block; let max_registrations_per_block = 1000; @@ -200,7 +201,7 @@ fn test_global_porposal() { assert_eq!(proposal.votes, stakes[0] + stakes[1], "proposal not voted"); assert!(proposal.accepted, "proposal not voted"); - println!("proposal: {:?}", proposal); + info!("proposal: {proposal:?}"); let params = SubspaceModule::global_params(); assert_eq!( @@ -227,7 +228,7 @@ fn test_unvote() { "vote mode not set" ); params.vote_mode = "stake".as_bytes().to_vec(); - println!("params: {:?}", params); + info!("params: {:?}", params); SubspaceModule::set_subnet_params(netuid, params.clone()); let mut params = SubspaceModule::subnet_params(netuid); let _initial_tempo = params.tempo; @@ -251,7 +252,7 @@ fn test_unvote() { // we have not passed the threshold yet let proposals = SubspaceModule::get_subnet_proposals(netuid); - println!("proposals: {:?}", proposals); + info!("proposals: {proposals:?}"); assert_eq!(proposals.len(), 0, "proposal not added"); }); diff --git a/pallets/subspace/tests/weights.rs b/pallets/subspace/tests/weights.rs index e6e12f4e7..e259b81f9 100644 --- a/pallets/subspace/tests/weights.rs +++ b/pallets/subspace/tests/weights.rs @@ -107,7 +107,9 @@ fn test_set_weight_not_enough_values() { let n = 100; SubspaceModule::set_max_registrations_per_block(n); let account_id = U256::from(0); + assert_ok!(register_module(netuid, account_id, 1_000_000_000)); + let _neuron_uid: u16 = SubspaceModule::get_uid_for_key(netuid, &account_id); for i in 1..n { assert_ok!(register_module(netuid, U256::from(i), 1_000_000_000)); @@ -115,7 +117,7 @@ fn test_set_weight_not_enough_values() { SubspaceModule::set_min_allowed_weights(netuid, 2); - // Should fail because we are only setting a single value and its not the self weight. + // setting weight below minimim let weight_keys: Vec = vec![1]; // not weight. let weight_values: Vec = vec![88]; // random value. let result = SubspaceModule::set_weights( @@ -124,9 +126,9 @@ fn test_set_weight_not_enough_values() { weight_keys, weight_values, ); - assert_eq!(result, Err(Error::::NotSettingEnoughWeights.into())); + assert_eq!(result, Err(Error::::InvalidUidsLength.into())); - // Shouldnt fail because we setting a single value but it is the self weight. + SubspaceModule::set_min_allowed_weights(netuid, 1); let weight_keys: Vec = vec![0]; // self weight. let weight_values: Vec = vec![88]; // random value. @@ -210,95 +212,6 @@ fn test_normalize_weights_does_not_mutate_when_sum_not_zero() { }); } -/// 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]; - - let expected = true; - let result = SubspaceModule::is_self_weight(uid, &uids); - - assert_eq!( - expected, result, - "Failed get expected result when `weights.len() != 1`" - ); - }); -} - -/// @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]; - - let expected = true; - let result = SubspaceModule::is_self_weight(uid, &uids); - - 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 = 0; - let _tempo: u16 = 13; - - SubspaceModule::set_max_registrations_per_block(100); - - /* @TODO: use a loop maybe */ - assert_ok!(register_module(netuid, U256::from(1), 1_000_000_000)); - assert_ok!(register_module(netuid, U256::from(3), 1_000_000_000)); - assert_ok!(register_module(netuid, U256::from(5), 1_000_000_000)); - let max_allowed: u16 = SubspaceModule::get_subnet_n(netuid); - - let uids: Vec = Vec::from_iter(0..max_allowed); - - let result = SubspaceModule::check_len_uids_within_allowed(netuid, &uids); - assert!(result, "netuid network length and uids length incompatible"); - }); -} - -#[test] -fn test_check_len_uids_within_allowed_not_within_network_pool() { - new_test_ext().execute_with(|| { - let netuid: u16 = 0; - - let _tempo: u16 = 13; - let _modality: u16 = 0; - - SubspaceModule::set_max_registrations_per_block(100); - - /* @TODO: use a loop maybe */ - assert_ok!(register_module(netuid, U256::from(1), 1_000_000_000)); - assert_ok!(register_module(netuid, U256::from(3), 1_000_000_000)); - assert_ok!(register_module(netuid, U256::from(5), 1_000_000_000)); - let max_allowed: u16 = SubspaceModule::get_subnet_n(netuid); - - SubspaceModule::set_max_allowed_uids(netuid, max_allowed); - - let uids: Vec = Vec::from_iter(0..(max_allowed + 1)); - - let expected = false; - let result = SubspaceModule::check_len_uids_within_allowed(netuid, &uids); - assert_eq!( - expected, result, - "Failed to detect incompatible uids for network" - ); - }); -} - #[test] fn test_min_weight_stake() { new_test_ext().execute_with(|| { @@ -325,7 +238,7 @@ fn test_min_weight_stake() { uids.clone(), weights.clone(), ), - Error::::NotEnoughtStakePerWeight + Error::::NotEnoughStakePerWeight ); increase_stake(netuid, U256::from(voter_idx), to_nano(400)); @@ -361,7 +274,7 @@ fn test_weight_age() { // Set subnet parameters let mut subnet_params = SubspaceModule::subnet_params(NETUID); subnet_params.tempo = TEMPO as u16; - subnet_params.max_weight_age = TEMPO; + subnet_params.max_weight_age = TEMPO * 2; SubspaceModule::set_subnet_params(NETUID, subnet_params); // Set weights for passive and active voters @@ -383,7 +296,7 @@ fn test_weight_age() { let active_stake_before = SubspaceModule::get_total_stake_to(NETUID, &U256::from(ACTIVE_VOTER)); - step_block(TEMPO as u16); + step_block((TEMPO as u16) * 2); let passive_stake_after = SubspaceModule::get_total_stake_to(NETUID, &U256::from(PASSIVE_VOTER)); @@ -403,7 +316,7 @@ fn test_weight_age() { weights, )); - step_block(TEMPO as u16); + step_block((TEMPO as u16) * 2); let passive_stake_after_v2 = SubspaceModule::get_total_stake_to(NETUID, &U256::from(PASSIVE_VOTER));