diff --git a/src/block_step.rs b/src/block_step.rs index e0b9d0a..3963444 100644 --- a/src/block_step.rs +++ b/src/block_step.rs @@ -1,8 +1,7 @@ use crate::epoch::epoch; use crate::root::{get_root_netuid, root_epoch}; use crate::staking::{ - add_balance_to_coldkey_account, hotkey_is_delegate, increase_stake_on_coldkey_hotkey_account, - increase_stake_on_hotkey_account, u64_to_balance, + hotkey_is_delegate, increase_stake_on_coldkey_hotkey_account, increase_stake_on_hotkey_account, }; use crate::state::{ ADJUSTMENTS_ALPHA, ADJUSTMENT_INTERVAL, BLOCKS_SINCE_LAST_STEP, BURN, @@ -15,35 +14,40 @@ use crate::state::{ }; use crate::utils::get_blocks_since_last_step; use crate::ContractError; -use cosmwasm_std::{Addr, Api, DepsMut, Env, Order, StdResult, Storage}; +use cosmwasm_std::{ + coins, Addr, Api, BankMsg, CosmosMsg, DepsMut, Env, Order, StdResult, Storage, Uint128, +}; use cyber_std::Response; -use std::ops::Add; use substrate_fixed::types::I110F18; use substrate_fixed::types::I64F64; use substrate_fixed::types::I96F32; /// Executes the necessary operations for each block. -/// TODO make it msg and then do call from native layer as sudo pub fn block_step(deps: DepsMut, env: Env) -> Result { let block_number: u64 = env.block.height; deps.api - .debug(&format!("block_step for block: {:?} ", block_number)); + .debug(&format!("🕛 block_step for block: {:?} ", block_number)); // --- 1. Adjust difficulties. adjust_registration_terms_for_networks(deps.storage, deps.api, env.block.height)?; // --- 2. Calculate per-subnet emissions match root_epoch(deps.storage, deps.api, block_number) { - Ok(_) => (), + Ok(_) => { + deps.api + .debug(&format!("🟩 Successfully executed root epoch")); + } Err(e) => { - // return Err(ContractError::Std(GenericErr {msg: format!("Error while running root epoch: {:?}", e)})) deps.api - .debug(&format!("Error while running root epoch: {:?}", e)); + .debug(&format!("🟥 Error while running root epoch: {:?}", e)); } } // --- 3. Drains emission tuples ( hotkey, amount ). drain_emission(deps.storage, deps.api, block_number)?; // --- 4. Generates emission tuples from epoch functions. - generate_emission(deps.storage, deps.api, block_number)?; - // Return ok. + let _msgs = generate_emission(deps.storage, deps.api, block_number)?; + // Ok(Response::new() + // .add_messages(msgs) + // .add_attribute("action", "block_step") + // ) Ok(Response::default().add_attribute("action", "block_step")) } @@ -76,6 +80,7 @@ pub fn blocks_until_next_epoch(netuid: u16, tempo: u16, block_number: u64) -> u6 // Helper function returns the number of tuples to drain on a particular step based on // the remaining tuples to sink and the block number // +#[cfg(test)] pub fn tuples_to_drain_this_block( netuid: u16, tempo: u16, @@ -110,8 +115,9 @@ pub fn generate_emission( store: &mut dyn Storage, api: &dyn Api, block_number: u64, -) -> Result<(), ContractError> { +) -> Result, ContractError> { // --- 1. Iterate across each network and add pending emission into stash. + let msgs: Vec = Vec::new(); let netuid_tempo: Vec<(u16, u16)> = TEMPO .range(store, None, None, Order::Ascending) .map(|item| { @@ -130,7 +136,7 @@ pub fn generate_emission( // --- 2. Queue the emission due to this network. let new_queued_emission = EMISSION_VALUES.load(store, netuid)?; api.debug(&format!( - "generate_emission for netuid: {:?} with tempo: {:?} and emission: {:?}", + "💎 generate_emission for netuid: {:?} with tempo: {:?} and emission: {:?}", netuid, tempo, new_queued_emission, )); @@ -144,17 +150,14 @@ pub fn generate_emission( remaining = remaining.saturating_sub(cut); - let subnet_owner = SUBNET_OWNER.load(store, netuid)?; - // TODO create messages here - // add_balance_to_coldkey_account( - // &subnet_owner, - // u64_to_balance(cut.to_num::()).unwrap(), - // ); - // let denom = DENOM.load(deps.storage)?; - // let msg = CosmosMsg::Bank(BankMsg::Send { - // to_address: &subnet_owner.to_string(), + // TODO back to this, by default subnet owner cut is zero + // let subnet_owner = SUBNET_OWNER.load(store, netuid)?; + // + // let denom = DENOM.load(store)?; + // msgs.push(CosmosMsg::Bank(BankMsg::Send { + // to_address: subnet_owner.to_string(), // amount: coins(Uint128::from(cut.to_num::()).u128(), denom), - // }); + // })); TOTAL_ISSUANCE.update(store, |a| -> StdResult<_> { Ok(a.saturating_add(cut.to_num::())) @@ -167,7 +170,7 @@ pub fn generate_emission( Ok(q) })?; api.debug(&format!( - "netuid_i: {:?} queued_emission: +{:?} ", + "💎 netuid_i: {:?} queued_emission: +{:?} ", netuid, new_queued_emission )); @@ -189,7 +192,7 @@ pub fn generate_emission( let emission_tuples_this_block: Vec<(Addr, u64, u64)> = epoch(store, api, netuid, emission_to_drain, block_number)?; api.debug(&format!( - "netuid_i: {:?} emission_to_drain: {:?} ", + "💎 netuid_i: {:?} emission_to_drain: {:?} ", netuid, emission_to_drain )); @@ -216,12 +219,15 @@ pub fn generate_emission( BLOCKS_SINCE_LAST_STEP.save(store, netuid, &0)?; LAST_MECHANISM_STEP_BLOCK.save(store, netuid, &block_number)?; } - Ok(()) + Ok(msgs) } +#[cfg(test)] pub fn has_loaded_emission_tuples(store: &dyn Storage, netuid: u16) -> bool { LOADED_EMISSION.has(store, netuid) } + +#[cfg(test)] pub fn get_loaded_emission_tuples(store: &dyn Storage, netuid: u16) -> Vec<(Addr, u64, u64)> { LOADED_EMISSION.load(store, netuid).unwrap() } @@ -315,7 +321,7 @@ pub fn emit_inflation_through_hotkey_account( stake_proportion, ); api.debug(&format!( - "owning_coldkey_i: {:?} hotkey: {:?} emission: +{:?} ", + "🤗 owning_coldkey_i: {:?} hotkey: {:?} emission: +{:?} ", owning_coldkey_i, hotkey.clone(), stake_proportion @@ -327,7 +333,7 @@ pub fn emit_inflation_through_hotkey_account( // the delegate and effect calculation in 4. increase_stake_on_hotkey_account(store, &hotkey, delegate_take + remaining_validator_emission); api.debug(&format!( - "delkey: {:?} delegate_take: +{:?} ", + "🤗 delkey: {:?} delegate_take: +{:?} ", hotkey, delegate_take )); // Also emit the server_emission to the hotkey @@ -342,6 +348,7 @@ pub fn emit_inflation_through_hotkey_account( // This function should be called rather than set_stake under account. // // TODO revisit +#[cfg(test)] pub fn block_step_increase_stake_on_coldkey_hotkey_account( store: &mut dyn Storage, coldkey: &Addr, @@ -369,6 +376,7 @@ pub fn block_step_increase_stake_on_coldkey_hotkey_account( // Decreases the stake on the cold - hot pairing by the decrement while decreasing other counters. // // TODO revisit +#[cfg(test)] pub fn block_step_decrease_stake_on_coldkey_hotkey_account( store: &mut dyn Storage, coldkey: &Addr, @@ -429,7 +437,7 @@ pub fn adjust_registration_terms_for_networks( api: &dyn Api, current_block: u64, ) -> Result<(), ContractError> { - api.debug(&format!("adjust_registration_terms_for_networks")); + api.debug(&format!("⚙️ adjust_registration_terms_for_networks")); let networks_added: Vec<(u16, bool)> = NETWORKS_ADDED .range(store, None, None, Order::Ascending) @@ -444,7 +452,7 @@ pub fn adjust_registration_terms_for_networks( // --- 2. Pull counters for network difficulty. let last_adjustment_block: u64 = LAST_ADJUSTMENT_BLOCK.load(store, netuid)?; let adjustment_interval: u16 = ADJUSTMENT_INTERVAL.load(store, netuid)?; - api.debug(&format!("netuid: {:?} last_adjustment_block: {:?} adjustment_interval: {:?} current_block: {:?}", + api.debug(&format!("⚙️ netuid: {:?}, last_adjustment_block: {:?}, adjustment_interval: {:?}, current_block: {:?}", netuid, last_adjustment_block, adjustment_interval, @@ -454,7 +462,7 @@ pub fn adjust_registration_terms_for_networks( // --- 3. Check if we are at the adjustment interval for this network. // If so, we need to adjust the registration difficulty based on target and actual registrations. if (current_block - last_adjustment_block) >= adjustment_interval as u64 { - api.debug(&format!("interval reached.")); + api.debug(&format!("ℹ️ interval reached")); // --- 4. Get the current counters for this network w.r.t burn and difficulty values. let current_burn: u64 = BURN.load(store, netuid)?; @@ -573,7 +581,7 @@ pub fn adjust_registration_terms_for_networks( POW_REGISTRATIONS_THIS_INTERVAL.save(store, netuid, &0)?; BURN_REGISTRATIONS_THIS_INTERVAL.save(store, netuid, &0)?; } else { - api.debug(&format!("interval not reached.")); + api.debug(&format!("ℹ️ interval not reached.")); } // --- 7. Drain block registrations for each network. Needed for registration rate limits. diff --git a/src/contract.rs b/src/contract.rs index a04c6dc..b7b41a6 100644 --- a/src/contract.rs +++ b/src/contract.rs @@ -1,10 +1,8 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; -use cosmwasm_std::{ - to_json_binary, Addr, Binary, Coin, Deps, DepsMut, Env, MessageInfo, Order, StdResult, Storage, - Uint128, -}; +use cosmwasm_std::{to_json_binary, Addr, Binary, Coin, Deps, DepsMut, Env, MessageInfo, Order, StdResult, Storage, Uint128, CosmosMsg, BankMsg, coins}; use cw2::{get_contract_version, set_contract_version, ContractVersion}; +use cyber_std::Response; use cyber_std::{create_creat_thought_msg, Load, Trigger}; use crate::block_step::block_step; @@ -16,29 +14,27 @@ use crate::registration::{do_burned_registration, do_registration, do_sudo_regis use crate::root::{do_root_register, get_network_lock_cost, user_add_network, user_remove_network}; use crate::serving::{do_serve_axon, do_serve_prometheus}; use crate::stake_info::{get_stake_info_for_coldkey, get_stake_info_for_coldkeys}; -use crate::staking::{ - do_add_stake, do_become_delegate, do_remove_stake, increase_stake_on_coldkey_hotkey_account, -}; +use crate::staking::{do_add_stake, do_become_delegate, do_remove_stake}; use crate::state::{ AxonInfo, PrometheusInfo, ACTIVE, ACTIVITY_CUTOFF, ADJUSTMENTS_ALPHA, ADJUSTMENT_INTERVAL, - ALLOW_FAUCET, AXONS, BLOCKS_SINCE_LAST_STEP, BLOCK_AT_REGISTRATION, BLOCK_EMISSION, - BONDS_MOVING_AVERAGE, BURN, BURN_REGISTRATIONS_THIS_INTERVAL, CONSENSUS, DEFAULT_TAKE, - DELEGATES, DENOM, DIFFICULTY, DIVIDENDS, EMISSION, EMISSION_VALUES, IMMUNITY_PERIOD, INCENTIVE, - IS_NETWORK_MEMBER, KAPPA, KEYS, LAST_ADJUSTMENT_BLOCK, LAST_UPDATE, MAX_ALLOWED_UIDS, - MAX_ALLOWED_VALIDATORS, MAX_BURN, MAX_DIFFICULTY, MAX_REGISTRATION_PER_BLOCK, - MAX_WEIGHTS_LIMIT, MIN_ALLOWED_WEIGHTS, MIN_BURN, MIN_DIFFICULTY, NETWORKS_ADDED, - NETWORK_IMMUNITY_PERIOD, NETWORK_LAST_LOCK_COST, NETWORK_LAST_REGISTERED, - NETWORK_LOCK_REDUCTION_INTERVAL, NETWORK_MIN_ALLOWED_UIDS, NETWORK_MIN_LOCK_COST, + ALLOW_FAUCET, AXONS, BLOCKS_SINCE_LAST_STEP, BLOCK_EMISSION, BONDS_MOVING_AVERAGE, BURN, + BURN_REGISTRATIONS_THIS_INTERVAL, CONSENSUS, DEFAULT_TAKE, DELEGATES, DENOM, DIFFICULTY, + DIVIDENDS, EMISSION, EMISSION_VALUES, IMMUNITY_PERIOD, INCENTIVE, KAPPA, LAST_ADJUSTMENT_BLOCK, + LAST_UPDATE, MAX_ALLOWED_UIDS, MAX_ALLOWED_VALIDATORS, MAX_BURN, MAX_DIFFICULTY, + MAX_REGISTRATION_PER_BLOCK, MAX_WEIGHTS_LIMIT, METADATA, MIN_ALLOWED_WEIGHTS, MIN_BURN, + MIN_DIFFICULTY, NETWORKS_ADDED, NETWORK_IMMUNITY_PERIOD, NETWORK_LAST_LOCK_COST, + NETWORK_LAST_REGISTERED, NETWORK_LOCK_REDUCTION_INTERVAL, NETWORK_MIN_LOCK_COST, NETWORK_MODALITY, NETWORK_RATE_LIMIT, NETWORK_REGISTERED_AT, NETWORK_REGISTRATION_ALLOWED, OWNER, PENDING_EMISSION, POW_REGISTRATIONS_THIS_INTERVAL, PROMETHEUS, PRUNING_SCORES, RANK, RAO_RECYCLED_FOR_REGISTRATION, REGISTRATIONS_THIS_BLOCK, REGISTRATIONS_THIS_INTERVAL, RHO, - ROOT, SCALING_LAW_POWER, SERVING_RATE_LIMIT, STAKE, SUBNETWORK_N, SUBNET_LIMIT, SUBNET_LOCKED, - SUBNET_OWNER, SUBNET_OWNER_CUT, TARGET_REGISTRATIONS_PER_INTERVAL, TEMPO, TOTAL_COLDKEY_STAKE, + ROOT, SERVING_RATE_LIMIT, STAKE, SUBNETWORK_N, SUBNET_LIMIT, SUBNET_LOCKED, SUBNET_OWNER, + SUBNET_OWNER_CUT, TARGET_REGISTRATIONS_PER_INTERVAL, TEMPO, TOTAL_COLDKEY_STAKE, TOTAL_HOTKEY_STAKE, TOTAL_ISSUANCE, TOTAL_NETWORKS, TOTAL_STAKE, TRUST, TX_RATE_LIMIT, UIDS, VALIDATOR_PERMIT, VALIDATOR_TRUST, WEIGHTS_SET_RATE_LIMIT, WEIGHTS_VERSION_KEY, }; use crate::state_info::get_state_info; use crate::subnet_info::{get_subnet_hyperparams, get_subnet_info, get_subnets_info}; +use crate::uids::get_registered_networks_for_hotkey; use crate::utils::{ do_sudo_set_activity_cutoff, do_sudo_set_adjustment_alpha, do_sudo_set_adjustment_interval, do_sudo_set_block_emission, do_sudo_set_bonds_moving_average, do_sudo_set_default_take, @@ -49,8 +45,8 @@ use crate::utils::{ do_sudo_set_min_allowed_weights, do_sudo_set_min_burn, do_sudo_set_min_difficulty, do_sudo_set_network_immunity_period, do_sudo_set_network_min_lock_cost, do_sudo_set_network_rate_limit, do_sudo_set_network_registration_allowed, - do_sudo_set_rao_recycled, do_sudo_set_rho, do_sudo_set_scaling_law_power, - do_sudo_set_serving_rate_limit, do_sudo_set_subnet_limit, do_sudo_set_subnet_owner_cut, + do_sudo_set_rao_recycled, do_sudo_set_rho, do_sudo_set_serving_rate_limit, + do_sudo_set_subnet_limit, do_sudo_set_subnet_metadata, do_sudo_set_subnet_owner_cut, do_sudo_set_target_registrations_per_interval, do_sudo_set_tempo, do_sudo_set_total_issuance, do_sudo_set_tx_rate_limit, do_sudo_set_validator_permit_for_uid, do_sudo_set_validator_prune_len, do_sudo_set_weights_set_rate_limit, @@ -58,30 +54,27 @@ use crate::utils::{ }; use crate::weights::{do_set_weights, get_network_weights, get_network_weights_sparse}; -// use cw2::set_contract_version; - -// version info for migration info const CONTRACT_NAME: &str = "cybernet"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); -use crate::uids::get_registered_networks_for_hotkey; -use cyber_std::Response; - #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( deps: DepsMut, env: Env, info: MessageInfo, - msg: InstantiateMsg, + _msg: InstantiateMsg, ) -> Result { set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; ROOT.save(deps.storage, &info.sender)?; ALLOW_FAUCET.save(deps.storage, &false)?; - DENOM.save(deps.storage, &"boot".to_string())?; - // TODO remove from InstantiateMsg - // // Set initial total issuance from balances + if info.funds.len() > 0 { + DENOM.save(deps.storage, &info.funds[0].denom)?; + } else { + DENOM.save(deps.storage, &"boot".to_string())?; + } + TOTAL_ISSUANCE.save(deps.storage, &0)?; TOTAL_STAKE.save(deps.storage, &0)?; @@ -89,29 +82,26 @@ pub fn instantiate( SUBNET_LIMIT.save(deps.storage, &16)?; NETWORK_IMMUNITY_PERIOD.save(deps.storage, &7200)?; - BLOCK_EMISSION.save(deps.storage, &1_000_000_000)?; + BLOCK_EMISSION.save(deps.storage, &4_200_000)?; - NETWORK_MIN_ALLOWED_UIDS.save(deps.storage, &0)?; SUBNET_OWNER_CUT.save(deps.storage, &0)?; NETWORK_RATE_LIMIT.save(deps.storage, &0)?; - DEFAULT_TAKE.save(deps.storage, &11_796)?; - TX_RATE_LIMIT.save(deps.storage, &1000)?; + // 6.25% (2^12/2^16) + DEFAULT_TAKE.save(deps.storage, &4096)?; + TX_RATE_LIMIT.save(deps.storage, &0)?; - NETWORK_LAST_LOCK_COST.save(deps.storage, &100_000_000_000)?; - NETWORK_MIN_LOCK_COST.save(deps.storage, &100_000_000_000)?; - NETWORK_LOCK_REDUCTION_INTERVAL.save(deps.storage, &2)?; // test value, change to 14 * 7200; + NETWORK_LAST_LOCK_COST.save(deps.storage, &10_000_000_000)?; + NETWORK_MIN_LOCK_COST.save(deps.storage, &10_000_000_000)?; + NETWORK_LOCK_REDUCTION_INTERVAL.save(deps.storage, &(7 * 7200))?; // -- Root network initialization -- - - // Get the root network uid. let root_netuid: u16 = 0; SUBNET_OWNER.save(deps.storage, root_netuid, &info.sender)?; - // TODO revisit set of 1 SUBNETWORK_N.save(deps.storage, root_netuid, &0)?; NETWORKS_ADDED.save(deps.storage, root_netuid, &true)?; - NETWORK_MODALITY.save(deps.storage, root_netuid, &u16::MAX)?; + NETWORK_MODALITY.save(deps.storage, root_netuid, &u16::MAX)?; // revisit MAX_ALLOWED_UIDS.save(deps.storage, root_netuid, &64)?; MAX_ALLOWED_VALIDATORS.save(deps.storage, root_netuid, &64)?; MIN_ALLOWED_WEIGHTS.save(deps.storage, root_netuid, &1)?; @@ -120,7 +110,6 @@ pub fn instantiate( NETWORK_REGISTRATION_ALLOWED.save(deps.storage, root_netuid, &true)?; TARGET_REGISTRATIONS_PER_INTERVAL.save(deps.storage, root_netuid, &1)?; WEIGHTS_VERSION_KEY.save(deps.storage, root_netuid, &0)?; - SUBNET_OWNER.save(deps.storage, root_netuid, &info.sender)?; NETWORK_REGISTERED_AT.save(deps.storage, root_netuid, &env.block.height)?; WEIGHTS_SET_RATE_LIMIT.save(deps.storage, root_netuid, &100)?; @@ -150,20 +139,20 @@ pub fn instantiate( EMISSION_VALUES.save(deps.storage, root_netuid, &0)?; NETWORK_LAST_REGISTERED.save(deps.storage, &0)?; TOTAL_NETWORKS.save(deps.storage, &1)?; - SCALING_LAW_POWER.save(deps.storage, root_netuid, &50)?; + METADATA.save( + deps.storage, + root_netuid, + &"Qmd2anGbDQj7pYWMZwv9SEw11QFLQu3nzoGXfi1KwLy3Zr".to_string(), + )?; // -- Subnetwork 1 initialization -- - - // Subnet config values let netuid: u16 = 1; - let tempo = 10; - let max_uids = 4096; SUBNET_OWNER.save(deps.storage, netuid, &info.sender)?; NETWORKS_ADDED.save(deps.storage, netuid, &true)?; - TEMPO.save(deps.storage, netuid, &tempo)?; + TEMPO.save(deps.storage, netuid, &10)?; NETWORK_MODALITY.save(deps.storage, netuid, &0)?; - // TEMPO.save(deps.storage, netuid, &0)?; + TEMPO.save(deps.storage, netuid, &10)?; KAPPA.save(deps.storage, netuid, &0)?; DIFFICULTY.save(deps.storage, netuid, &10_000_000)?; IMMUNITY_PERIOD.save(deps.storage, netuid, &7200)?; @@ -175,7 +164,7 @@ pub fn instantiate( POW_REGISTRATIONS_THIS_INTERVAL.save(deps.storage, netuid, &0)?; BURN_REGISTRATIONS_THIS_INTERVAL.save(deps.storage, netuid, &0)?; MAX_ALLOWED_VALIDATORS.save(deps.storage, netuid, &64)?; - MAX_ALLOWED_UIDS.save(deps.storage, netuid, &max_uids)?; + MAX_ALLOWED_UIDS.save(deps.storage, netuid, &1024)?; WEIGHTS_VERSION_KEY.save(deps.storage, netuid, &0)?; WEIGHTS_SET_RATE_LIMIT.save(deps.storage, netuid, &100)?; @@ -201,8 +190,12 @@ pub fn instantiate( SUBNETWORK_N.save(deps.storage, netuid, &0)?; SUBNET_LOCKED.save(deps.storage, netuid, &0)?; TARGET_REGISTRATIONS_PER_INTERVAL.save(deps.storage, netuid, &1)?; - SCALING_LAW_POWER.save(deps.storage, netuid, &50)?; NETWORK_REGISTRATION_ALLOWED.save(deps.storage, netuid, &true)?; + METADATA.save( + deps.storage, + root_netuid, + &"Qmd2anGbDQj7pYWMZwv9SEw11QFLQu3nzoGXfi1KwLy3Zr".to_string(), + )?; RANK.save(deps.storage, netuid, &vec![])?; TRUST.save(deps.storage, netuid, &vec![])?; @@ -224,7 +217,7 @@ pub fn instantiate( Ok(Response::default().add_attribute("action", "instantiate")) } -pub fn activate(deps: DepsMut, env: Env) -> Result { +pub fn activate(_deps: DepsMut, env: Env) -> Result { let res = Response::new() .add_message(create_creat_thought_msg( env.contract.address.to_string(), @@ -243,7 +236,25 @@ pub fn activate(deps: DepsMut, env: Env) -> Result { env.contract.address.as_str()[0..32].to_string(), "Qmd2anGbDQj7pYWMZwv9SEw11QFLQu3nzoGXfi1KwLy3Zr".to_string(), )) - .add_attribute("action", "dmn"); + .add_attribute("action", "activate"); + + Ok(res) +} + +pub fn deactivate(deps: DepsMut, env: Env) -> Result { + let denom = DENOM.load(deps.storage)?; + let root = ROOT.load(deps.storage)?; + + let coin = deps.querier.query_balance(env.contract.address, denom).unwrap(); + + let msg = CosmosMsg::Bank(BankMsg::Send { + to_address: root.to_string(), + amount: vec![coin], + }); + + let res = Response::new() + .add_message(msg) + .add_attribute("action", "deactivate"); Ok(res) } @@ -257,6 +268,7 @@ pub fn execute( ) -> Result { match msg { ExecuteMsg::Activate {} => activate(deps, env), + ExecuteMsg::Deactivate {} => deactivate(deps, env), ExecuteMsg::BlockStep {} => block_step(deps, env), ExecuteMsg::SetWeights { @@ -329,9 +341,7 @@ pub fn execute( netuid, hotkey, coldkey, - stake, - balance, - } => do_sudo_registration(deps, env, info, netuid, hotkey, coldkey, stake, balance), + } => do_sudo_registration(deps, env, info, netuid, hotkey, coldkey), ExecuteMsg::SudoSetDefaultTake { default_take } => { do_sudo_set_default_take(deps, env, info, default_take) } @@ -409,10 +419,6 @@ pub fn execute( netuid, validator_prune_len, } => do_sudo_set_validator_prune_len(deps, env, info, netuid, validator_prune_len), - ExecuteMsg::SudoSetScalingLawPower { - netuid, - scaling_law_power, - } => do_sudo_set_scaling_law_power(deps, env, info, netuid, scaling_law_power), ExecuteMsg::SudoSetImmunityPeriod { netuid, immunity_period, @@ -478,6 +484,9 @@ pub fn execute( ExecuteMsg::SudoSetBlockEmission { emission } => { do_sudo_set_block_emission(deps, env, info, emission) } + ExecuteMsg::SudoSetSubnetMetadata { netuid, particle } => { + do_sudo_set_subnet_metadata(deps, env, info, netuid, particle) + } } } diff --git a/src/delegate_info.rs b/src/delegate_info.rs index 3ad8518..8e63dff 100644 --- a/src/delegate_info.rs +++ b/src/delegate_info.rs @@ -112,10 +112,11 @@ pub fn get_delegates(deps: Deps) -> StdResult> { return Ok(delegates); } +// TODO add pagination and limit pub fn get_delegated(deps: Deps, delegatee: String) -> StdResult> { let delegatee = deps.api.addr_validate(&delegatee)?; let mut delegates: Vec<(DelegateInfo, u64)> = Vec::new(); - // TODO iterator over all delegates? rewrite + // TODO iterator over all delegates? for item in DELEGATES .range(deps.storage, None, None, Order::Ascending) .into_iter() diff --git a/src/epoch.rs b/src/epoch.rs index f078afe..828c6de 100644 --- a/src/epoch.rs +++ b/src/epoch.rs @@ -3,371 +3,26 @@ use cosmwasm_std::{Addr, Api, Order, Storage}; use substrate_fixed::types::{I32F32, I64F64, I96F32}; use crate::math::{ - col_clip_sparse, fixed_proportion_to_u16, inplace_col_clip, inplace_col_max_upscale, - inplace_col_max_upscale_sparse, inplace_col_normalize, inplace_col_normalize_sparse, - inplace_mask_diag, inplace_mask_matrix, inplace_mask_rows, inplace_mask_vector, - inplace_normalize, inplace_normalize_64, inplace_normalize_using_sum, inplace_row_normalize, - inplace_row_normalize_sparse, is_topk, is_zero, mask_diag_sparse, mask_rows_sparse, mat_ema, - mat_ema_sparse, matmul, matmul_sparse, matmul_transpose, matmul_transpose_sparse, row_hadamard, - row_hadamard_sparse, row_sum, row_sum_sparse, vec_fixed64_to_fixed32, - vec_fixed_proportions_to_u16, vec_mask_sparse_matrix, vec_max_upscale_to_u16, vecdiv, - weighted_median_col, weighted_median_col_sparse, + col_clip_sparse, fixed_proportion_to_u16, inplace_col_max_upscale_sparse, + inplace_col_normalize_sparse, inplace_mask_vector, inplace_normalize, inplace_normalize_64, + inplace_normalize_using_sum, inplace_row_normalize_sparse, is_topk, is_zero, mask_diag_sparse, + mask_rows_sparse, mat_ema_sparse, matmul_sparse, matmul_transpose_sparse, row_hadamard_sparse, + row_sum_sparse, vec_fixed64_to_fixed32, vec_mask_sparse_matrix, vec_max_upscale_to_u16, vecdiv, + weighted_median_col_sparse, }; use crate::staking::get_total_stake_for_hotkey; use crate::state::{ ACTIVE, BONDS, CONSENSUS, DIVIDENDS, EMISSION, INCENTIVE, KEYS, PRUNING_SCORES, RANK, TRUST, VALIDATOR_PERMIT, VALIDATOR_TRUST, WEIGHTS, }; -use crate::uids::{get_stake_for_uid_and_subnetwork, get_subnetwork_n}; +use crate::uids::get_subnetwork_n; use crate::utils::{ get_activity_cutoff, get_bonds_moving_average, get_kappa, get_last_update, get_max_allowed_validators, get_neuron_block_at_registration, get_rho, get_validator_permit, }; -// Calculates reward consensus and returns the emissions for uids/hotkeys in a given `netuid`. -// (Dense version used only for testing purposes.) -pub fn epoch_dense( - store: &mut dyn Storage, - netuid: u16, - rao_emission: u64, - current_block: u64, -) -> Vec<(Addr, u64, u64)> { - // Get subnetwork size. - let n: u16 = get_subnetwork_n(store, netuid); - println!("n:\n{:?}\n", n); - - // ====================== - // == Active & updated == - // ====================== - - // Get current block. - // let current_block: u64 = env.block.height; - println!("current_block:\n{:?}\n", current_block); - - // Get activity cutoff. - let activity_cutoff: u64 = get_activity_cutoff(store, netuid) as u64; - println!("activity_cutoff:\n{:?}\n", activity_cutoff); - - // Last update vector. - let last_update: Vec = get_last_update(store, netuid); - println!("Last update:\n{:?}\n", &last_update); - - // Inactive mask. - let inactive: Vec = last_update - .iter() - .map(|updated| *updated + activity_cutoff < current_block) - .collect(); - println!("Inactive:\n{:?}\n", inactive.clone()); - - // Logical negation of inactive. - let active: Vec = inactive.iter().map(|&b| !b).collect(); - - // Block at registration vector (block when each neuron was most recently registered). - let block_at_registration: Vec = get_block_at_registration(store, netuid); - println!("Block at registration:\n{:?}\n", &block_at_registration); - - // Outdated matrix, updated_ij=True if i has last updated (weights) after j has last registered. - let outdated: Vec> = last_update - .iter() - .map(|updated| { - block_at_registration - .iter() - .map(|registered| updated <= registered) - .collect() - }) - .collect(); - println!("Outdated:\n{:?}\n", &outdated); - - // =========== - // == Stake == - // =========== - - let mut hotkeys: Vec<(u16, Addr)> = vec![]; - for item in KEYS - .prefix(netuid) - .range(store, None, None, Order::Ascending) - { - let (uid_i, hotkey) = item.unwrap(); - hotkeys.push((uid_i, hotkey)); - } - println!("hotkeys: {:?}", &hotkeys); - - // Access network stake as normalized vector. - let mut stake_64: Vec = vec![I64F64::from_num(0.0); n as usize]; - for (uid_i, hotkey) in hotkeys.iter() { - stake_64[*uid_i as usize] = I64F64::from_num(get_total_stake_for_hotkey(store, hotkey)); - } - inplace_normalize_64(&mut stake_64); - let stake: Vec = vec_fixed64_to_fixed32(stake_64); - println!("S:\n{:?}\n", &stake); - - // ======================= - // == Validator permits == - // ======================= - - // Get validator permits. - let validator_permits: Vec = get_validator_permit(store, netuid); - println!("validator_permits: {:?}", validator_permits); - - // Logical negation of validator_permits. - let validator_forbids: Vec = validator_permits.iter().map(|&b| !b).collect(); - - // Get max allowed validators. - let max_allowed_validators: u16 = get_max_allowed_validators(store, netuid); - println!("max_allowed_validators: {:?}", max_allowed_validators); - - // Get new validator permits. - let new_validator_permits: Vec = is_topk(&stake, max_allowed_validators as usize); - println!("new_validator_permits: {:?}", new_validator_permits); - - // ================== - // == Active Stake == - // ================== - - let mut active_stake: Vec = stake.clone(); - - // Remove inactive stake. - inplace_mask_vector(&inactive, &mut active_stake); - - // Remove non-validator stake. - inplace_mask_vector(&validator_forbids, &mut active_stake); - - // Normalize active stake. - inplace_normalize(&mut active_stake); - println!("S:\n{:?}\n", &active_stake); - - // ============= - // == Weights == - // ============= - - // Access network weights row unnormalized. - let mut weights: Vec> = get_weights(store, netuid); - println!("W:\n{:?}\n", &weights); - - // Mask weights that are not from permitted validators. - inplace_mask_rows(&validator_forbids, &mut weights); - println!("W (permit): {:?}", &weights); - - // Remove self-weight by masking diagonal. - inplace_mask_diag(&mut weights); - println!("W (permit+diag):\n{:?}\n", &weights); - - // Mask outdated weights: remove weights referring to deregistered neurons. - inplace_mask_matrix(&outdated, &mut weights); - println!("W (permit+diag+outdate):\n{:?}\n", &weights); - - // Normalize remaining weights. - inplace_row_normalize(&mut weights); - println!("W (mask+norm):\n{:?}\n", &weights); - - // ================================ - // == Consensus, Validator Trust == - // ================================ - - // Compute preranks: r_j = SUM(i) w_ij * s_i - let preranks: Vec = matmul(&weights, &active_stake); - - // Clip weights at majority consensus - let kappa: I32F32 = get_float_kappa(store, netuid); // consensus majority ratio, e.g. 51%. - let consensus: Vec = weighted_median_col(&active_stake, &weights, kappa); - inplace_col_clip(&mut weights, &consensus); - let validator_trust: Vec = row_sum(&weights); - - // ==================================== - // == Ranks, Server Trust, Incentive == - // ==================================== - - // Compute ranks: r_j = SUM(i) w_ij * s_i - let mut ranks: Vec = matmul(&weights, &active_stake); - - // Compute server trust: ratio of rank after vs. rank before. - let trust: Vec = vecdiv(&ranks, &preranks); - - inplace_normalize(&mut ranks); - let incentive: Vec = ranks.clone(); - println!("I:\n{:?}\n", &incentive); - - // ========================= - // == Bonds and Dividends == - // ========================= - - // Access network bonds. - let mut bonds: Vec> = get_bonds(store, netuid); - inplace_mask_matrix(&outdated, &mut bonds); // mask outdated bonds - inplace_col_normalize(&mut bonds); // sum_i b_ij = 1 - println!("B:\n{:?}\n", &bonds); - - // Compute bonds delta column normalized. - let mut bonds_delta: Vec> = row_hadamard(&weights, &active_stake); // ΔB = W◦S - inplace_col_normalize(&mut bonds_delta); // sum_i b_ij = 1 - println!("ΔB:\n{:?}\n", &bonds_delta); - - // Compute bonds moving average. - let bonds_moving_average: I64F64 = - I64F64::from_num(get_bonds_moving_average(store, netuid)) / I64F64::from_num(1_000_000); - let alpha: I32F32 = I32F32::from_num(1) - I32F32::from_num(bonds_moving_average); - let mut ema_bonds: Vec> = mat_ema(&bonds_delta, &bonds, alpha); - inplace_col_normalize(&mut ema_bonds); // sum_i b_ij = 1 - println!("emaB:\n{:?}\n", &ema_bonds); - - // Compute dividends: d_i = SUM(j) b_ij * inc_j - let mut dividends: Vec = matmul_transpose(&ema_bonds, &incentive); - inplace_normalize(&mut dividends); - println!("D:\n{:?}\n", ÷nds); - - // ================================= - // == Emission and Pruning scores == - // ================================= - - // Compute emission scores. - - // Compute normalized emission scores. range: I32F32(0, 1) - // Compute normalized emission scores. range: I32F32(0, 1) - let combined_emission: Vec = incentive - .iter() - .zip(dividends.clone()) - .map(|(ii, di)| ii + di) - .collect(); - let emission_sum: I32F32 = combined_emission.iter().sum(); - - let mut normalized_server_emission: Vec = incentive.clone(); // Servers get incentive. - let mut normalized_validator_emission: Vec = dividends.clone(); // Validators get dividends. - let mut normalized_combined_emission: Vec = combined_emission.clone(); - // Normalize on the sum of incentive + dividends. - inplace_normalize_using_sum(&mut normalized_server_emission, emission_sum); - inplace_normalize_using_sum(&mut normalized_validator_emission, emission_sum); - inplace_normalize(&mut normalized_combined_emission); - - // If emission is zero, replace emission with normalized stake. - if emission_sum == I32F32::from(0) { - // no weights set | outdated weights | self_weights - if is_zero(&active_stake) { - // no active stake - normalized_validator_emission = stake.clone(); // do not mask inactive, assumes stake is normalized - normalized_combined_emission = stake.clone(); - } else { - normalized_validator_emission = active_stake.clone(); // emission proportional to inactive-masked normalized stake - normalized_combined_emission = active_stake.clone(); - } - } - - // Compute rao based emission scores. range: I96F32(0, rao_emission) - let float_rao_emission: I96F32 = I96F32::from_num(rao_emission); - - let server_emission: Vec = normalized_server_emission - .iter() - .map(|se: &I32F32| I96F32::from_num(*se) * float_rao_emission) - .collect(); - let server_emission: Vec = server_emission - .iter() - .map(|e: &I96F32| e.to_num::()) - .collect(); - - let validator_emission: Vec = normalized_validator_emission - .iter() - .map(|ve: &I32F32| I96F32::from_num(*ve) * float_rao_emission) - .collect(); - let validator_emission: Vec = validator_emission - .iter() - .map(|e: &I96F32| e.to_num::()) - .collect(); - - // Used only to track combined emission in the storage. - let combined_emission: Vec = normalized_combined_emission - .iter() - .map(|ce: &I32F32| I96F32::from_num(*ce) * float_rao_emission) - .collect(); - let combined_emission: Vec = combined_emission - .iter() - .map(|e: &I96F32| e.to_num::()) - .collect(); - - // api.debug(&format!( "nSE: {:?}", &normalized_server_emission )); - println!("SE: {:?}", &server_emission); - // api.debug(&format!( "nVE: {:?}", &normalized_validator_emission )); - println!("VE: {:?}", &validator_emission); - // api.debug(&format!( "nCE: {:?}", &normalized_combined_emission )); - println!("CE: {:?}", &combined_emission); - - // Set pruning scores using combined emission scores. - let pruning_scores: Vec = normalized_combined_emission.clone(); - println!("P: {:?}", &pruning_scores); - - // =================== - // == Value storage == - // =================== - let cloned_emission: Vec = combined_emission.clone(); - let cloned_ranks: Vec = ranks - .iter() - .map(|xi| fixed_proportion_to_u16(*xi)) - .collect::>(); - let cloned_trust: Vec = trust - .iter() - .map(|xi| fixed_proportion_to_u16(*xi)) - .collect::>(); - let cloned_consensus: Vec = consensus - .iter() - .map(|xi| fixed_proportion_to_u16(*xi)) - .collect::>(); - let cloned_incentive: Vec = incentive - .iter() - .map(|xi| fixed_proportion_to_u16(*xi)) - .collect::>(); - let cloned_dividends: Vec = dividends - .iter() - .map(|xi| fixed_proportion_to_u16(*xi)) - .collect::>(); - let cloned_pruning_scores: Vec = vec_max_upscale_to_u16(&pruning_scores); - let cloned_validator_trust: Vec = validator_trust - .iter() - .map(|xi| fixed_proportion_to_u16(*xi)) - .collect::>(); - - ACTIVE.save(store, netuid, &active).unwrap(); - EMISSION.save(store, netuid, &cloned_emission).unwrap(); - RANK.save(store, netuid, &cloned_ranks).unwrap(); - TRUST.save(store, netuid, &cloned_trust).unwrap(); - CONSENSUS.save(store, netuid, &cloned_consensus).unwrap(); - INCENTIVE.save(store, netuid, &cloned_incentive).unwrap(); - DIVIDENDS.save(store, netuid, &cloned_dividends).unwrap(); - PRUNING_SCORES - .save(store, netuid, &cloned_pruning_scores) - .unwrap(); - VALIDATOR_TRUST - .save(store, netuid, &cloned_validator_trust) - .unwrap(); - VALIDATOR_PERMIT - .save(store, netuid, &new_validator_permits) - .unwrap(); - - // Column max-upscale EMA bonds for storage: max_i w_ij = 1. - inplace_col_max_upscale(&mut ema_bonds); - for i in 0..n { - // Set bonds only if uid retains validator permit, otherwise clear bonds. - if new_validator_permits[i as usize] { - let new_bonds_row: Vec<(u16, u16)> = (0..n) - .zip(vec_fixed_proportions_to_u16(ema_bonds[i as usize].clone())) - .collect(); - BONDS.save(store, (netuid, i), &new_bonds_row).unwrap(); - } else if validator_permits[i as usize] { - // Only overwrite the intersection. - let new_empty_bonds_row: Vec<(u16, u16)> = vec![]; - BONDS - .save(store, (netuid, i), &new_empty_bonds_row) - .unwrap(); - } - } - - let mut result: Vec<(Addr, u64, u64)> = vec![]; - for (uid_i, hotkey) in hotkeys.iter() { - result.push(( - hotkey.clone(), - server_emission[*uid_i as usize], - validator_emission[*uid_i as usize], - )); - } - result -} +#[cfg(test)] +use crate::uids::get_stake_for_uid_and_subnetwork; // Calculates reward consensus values, then updates rank, trust, consensus, incentive, dividend, pruning_score, emission and bonds, and // returns the emissions for uids/hotkeys in a given `netuid`. @@ -386,12 +41,12 @@ pub fn epoch( store: &mut dyn Storage, api: &dyn Api, netuid: u16, - rao_emission: u64, + token_emission: u64, current_block: u64, ) -> Result, ContractError> { // Get subnetwork size. let n: u16 = get_subnetwork_n(store, netuid); - api.debug(&format!("n: {:?}", n)); + api.debug(&format!("⚪️ subnet_n: {:?}", n)); // ====================== // == Active & updated == @@ -399,22 +54,22 @@ pub fn epoch( // Get current block. // let current_block: u64 = get_current_block_as_u64(); - api.debug(&format!("current_block: {:?}", current_block)); + api.debug(&format!("⚪️ current_block: {:?}", current_block)); // Get activity cutoff. let activity_cutoff: u64 = get_activity_cutoff(store, netuid) as u64; - api.debug(&format!("activity_cutoff: {:?}", activity_cutoff)); + api.debug(&format!("⚪️ activity_cutoff: {:?}", activity_cutoff)); // Last update vector. let last_update: Vec = get_last_update(store, netuid); - api.debug(&format!("Last update: {:?}", &last_update)); + api.debug(&format!("⚪️ last_update: {:?}", &last_update)); // Inactive mask. let inactive: Vec = last_update .iter() .map(|updated| *updated + activity_cutoff < current_block) .collect(); - api.debug(&format!("Inactive: {:?}", inactive.clone())); + api.debug(&format!("⚪️ inactive: {:?}", inactive.clone())); // Logical negation of inactive. let active: Vec = inactive.iter().map(|&b| !b).collect(); @@ -422,7 +77,7 @@ pub fn epoch( // Block at registration vector (block when each neuron was most recently registered). let block_at_registration: Vec = get_block_at_registration(store, netuid); api.debug(&format!( - "Block at registration: {:?}", + "⚪️ block_at_registration: {:?}", &block_at_registration )); @@ -438,7 +93,7 @@ pub fn epoch( let (uid_i, hotkey) = item.unwrap(); hotkeys.push((uid_i, hotkey)); } - api.debug(&format!("hotkeys: {:?}", &hotkeys)); + api.debug(&format!("⚪️ hotkeys: {:?}", &hotkeys)); // Access network stake as normalized vector. let mut stake_64: Vec = vec![I64F64::from_num(0.0); n as usize]; @@ -448,7 +103,7 @@ pub fn epoch( inplace_normalize_64(&mut stake_64); let stake: Vec = vec_fixed64_to_fixed32(stake_64); // range: I32F32(0, 1) - api.debug(&format!("S: {:?}", &stake)); + api.debug(&format!("⚪️ stake: {:?}", &stake)); // ======================= // == Validator permits == @@ -456,7 +111,7 @@ pub fn epoch( // Get current validator permits. let validator_permits: Vec = get_validator_permit(store, netuid); - api.debug(&format!("validator_permits: {:?}", validator_permits)); + api.debug(&format!("⚪️ validator_permits: {:?}", validator_permits)); // Logical negation of validator_permits. let validator_forbids: Vec = validator_permits.iter().map(|&b| !b).collect(); @@ -464,14 +119,14 @@ pub fn epoch( // Get max allowed validators. let max_allowed_validators: u16 = get_max_allowed_validators(store, netuid); api.debug(&format!( - "max_allowed_validators: {:?}", + "⚪️ max_allowed_validators: {:?}", max_allowed_validators )); // Get new validator permits. let new_validator_permits: Vec = is_topk(&stake, max_allowed_validators as usize); api.debug(&format!( - "new_validator_permits: {:?}", + "⚪️ new_validator_permits: {:?}", new_validator_permits )); @@ -489,7 +144,7 @@ pub fn epoch( // Normalize active stake. inplace_normalize(&mut active_stake); - api.debug(&format!("S:\n{:?}\n", &active_stake)); + api.debug(&format!("⚪️ stake: {:?}", &active_stake)); // ============= // == Weights == @@ -526,18 +181,18 @@ pub fn epoch( // Compute preranks: r_j = SUM(i) w_ij * s_i let preranks: Vec = matmul_sparse(&weights, &active_stake, n); - api.debug(&format!("R (before): {:?}", &preranks)); + // api.debug(&format!("R (before): {:?}", &preranks)); // Clip weights at majority consensus let kappa: I32F32 = get_float_kappa(store, netuid); // consensus majority ratio, e.g. 51%. let consensus: Vec = weighted_median_col_sparse(&active_stake, &weights, n, kappa); - api.debug(&format!("C: {:?}", &consensus)); + api.debug(&format!("⚪️ consensus: {:?}", &consensus)); weights = col_clip_sparse(&weights, &consensus); - api.debug(&format!("W: {:?}", &weights)); + // api.debug(&format!("W: {:?}", &weights)); let validator_trust: Vec = row_sum_sparse(&weights); - api.debug(&format!("Tv: {:?}", &validator_trust)); + api.debug(&format!("⚪️ validator_trust: {:?}", &validator_trust)); // ============================= // == Ranks, Trust, Incentive == @@ -545,16 +200,16 @@ pub fn epoch( // Compute ranks: r_j = SUM(i) w_ij * s_i. let mut ranks: Vec = matmul_sparse(&weights, &active_stake, n); - api.debug(&format!("R (after): {:?}", &ranks)); + // api.debug(&format!("R (after): {:?}", &ranks)); // Compute server trust: ratio of rank after vs. rank before. let trust: Vec = vecdiv(&ranks, &preranks); // range: I32F32(0, 1) - api.debug(&format!("T: {:?}", &trust)); + api.debug(&format!("⚪️ trust: {:?}", &trust)); inplace_normalize(&mut ranks); // range: I32F32(0, 1) let incentive: Vec = ranks.clone(); - api.debug(&format!("I (=R): {:?}", &incentive)); + api.debug(&format!("⚪️ incentive: {:?}", &incentive)); // ========================= // == Bonds and Dividends == @@ -562,7 +217,7 @@ pub fn epoch( // Access network bonds. let mut bonds: Vec> = get_bonds_sparse(store, netuid); - api.debug(&format!("B: {:?}", &bonds)); + // api.debug(&format!("B: {:?}", &bonds)); // Remove bonds referring to deregistered neurons. bonds = vec_mask_sparse_matrix( @@ -571,19 +226,21 @@ pub fn epoch( &block_at_registration, &|updated, registered| updated <= registered, ); - api.debug(&format!("B (outdatedmask): {:?}", &bonds)); + // api.debug(&format!("B (outdatedmask): {:?}", &bonds)); // Normalize remaining bonds: sum_i b_ij = 1. inplace_col_normalize_sparse(&mut bonds, n); - api.debug(&format!("B (mask+norm): {:?}", &bonds)); + // api.debug(&format!("B (mask+norm): {:?}", &bonds)); // Compute bonds delta column normalized. - let mut bonds_delta: Vec> = row_hadamard_sparse(&weights, &active_stake); // ΔB = W◦S (outdated W masked) - api.debug(&format!("ΔB: {:?}", &bonds_delta)); + // ΔB = W◦S (outdated W masked) + let mut bonds_delta: Vec> = row_hadamard_sparse(&weights, &active_stake); + // api.debug(&format!("ΔB: {:?}", &bonds_delta)); // Normalize bonds delta. - inplace_col_normalize_sparse(&mut bonds_delta, n); // sum_i b_ij = 1 - api.debug(&format!("ΔB (norm): {:?}", &bonds_delta)); + // sum_i b_ij = 1 + inplace_col_normalize_sparse(&mut bonds_delta, n); + // api.debug(&format!("ΔB (norm): {:?}", &bonds_delta)); // Compute bonds moving average. let bonds_moving_average: I64F64 = @@ -592,14 +249,15 @@ pub fn epoch( let mut ema_bonds: Vec> = mat_ema_sparse(&bonds_delta, &bonds, alpha); // Normalize EMA bonds. - inplace_col_normalize_sparse(&mut ema_bonds, n); // sum_i b_ij = 1 - api.debug(&format!("emaB: {:?}", &ema_bonds)); + // sum_i b_ij = 1 + inplace_col_normalize_sparse(&mut ema_bonds, n); + // api.debug(&format!("emaB: {:?}", &ema_bonds)); // Compute dividends: d_i = SUM(j) b_ij * inc_j. // range: I32F32(0, 1) let mut dividends: Vec = matmul_transpose_sparse(&ema_bonds, &incentive); inplace_normalize(&mut dividends); - api.debug(&format!("D: {:?}", ÷nds)); + api.debug(&format!("⚪️ dividends: {:?}", ÷nds)); // ================================= // == Emission and Pruning scores == @@ -635,11 +293,11 @@ pub fn epoch( } // Compute rao based emission scores. range: I96F32(0, rao_emission) - let float_rao_emission: I96F32 = I96F32::from_num(rao_emission); + let float_token_emission: I96F32 = I96F32::from_num(token_emission); let server_emission: Vec = normalized_server_emission .iter() - .map(|se: &I32F32| I96F32::from_num(*se) * float_rao_emission) + .map(|se: &I32F32| I96F32::from_num(*se) * float_token_emission) .collect(); let server_emission: Vec = server_emission .iter() @@ -648,7 +306,7 @@ pub fn epoch( let validator_emission: Vec = normalized_validator_emission .iter() - .map(|ve: &I32F32| I96F32::from_num(*ve) * float_rao_emission) + .map(|ve: &I32F32| I96F32::from_num(*ve) * float_token_emission) .collect(); let validator_emission: Vec = validator_emission .iter() @@ -658,23 +316,23 @@ pub fn epoch( // Only used to track emission in storage. let combined_emission: Vec = normalized_combined_emission .iter() - .map(|ce: &I32F32| I96F32::from_num(*ce) * float_rao_emission) + .map(|ce: &I32F32| I96F32::from_num(*ce) * float_token_emission) .collect(); let combined_emission: Vec = combined_emission .iter() .map(|e: &I96F32| e.to_num::()) .collect(); - api.debug(&format!("nSE: {:?}", &normalized_server_emission)); - api.debug(&format!("SE: {:?}", &server_emission)); - api.debug(&format!("nVE: {:?}", &normalized_validator_emission)); - api.debug(&format!("VE: {:?}", &validator_emission)); - api.debug(&format!("nCE: {:?}", &normalized_combined_emission)); - api.debug(&format!("CE: {:?}", &combined_emission)); + api.debug(&format!("⚪️ nSE: {:?}", &normalized_server_emission)); + api.debug(&format!("⚪️ SE: {:?}", &server_emission)); + api.debug(&format!("⚪️ nVE: {:?}", &normalized_validator_emission)); + api.debug(&format!("⚪️ VE: {:?}", &validator_emission)); + api.debug(&format!("⚪️ nCE: {:?}", &normalized_combined_emission)); + api.debug(&format!("⚪️ CE: {:?}", &combined_emission)); // Set pruning scores using combined emission scores. let pruning_scores: Vec = normalized_combined_emission.clone(); - api.debug(&format!("P: {:?}", &pruning_scores)); + api.debug(&format!("⚪️ Psc: {:?}", &pruning_scores)); // =================== // == Value storage == @@ -754,6 +412,7 @@ pub fn epoch( Ok(result) } +#[cfg(test)] pub fn get_float_rho(store: &dyn Storage, netuid: u16) -> I32F32 { I32F32::from_num(get_rho(store, netuid)) } @@ -762,6 +421,7 @@ pub fn get_float_kappa(store: &dyn Storage, netuid: u16) -> I32F32 { I32F32::from_num(get_kappa(store, netuid)) / I32F32::from_num(u16::MAX) } +#[cfg(test)] pub fn get_normalized_stake(store: &dyn Storage, netuid: u16) -> Vec { let n: usize = get_subnetwork_n(store, netuid) as usize; let mut stake_64: Vec = vec![I64F64::from_num(0.0); n]; @@ -806,6 +466,7 @@ pub fn get_weights_sparse(store: &dyn Storage, netuid: u16) -> Vec Vec> { let n: usize = get_subnetwork_n(store, netuid) as usize; let mut weights: Vec> = vec![vec![I32F32::from_num(0.0); n]; n]; @@ -838,6 +499,7 @@ pub fn get_bonds_sparse(store: &dyn Storage, netuid: u16) -> Vec Vec> { let n: usize = get_subnetwork_n(store, netuid) as usize; let mut bonds: Vec> = vec![vec![I32F32::from_num(0.0); n]; n]; diff --git a/src/error.rs b/src/error.rs index 06db01e..ade961d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -19,7 +19,7 @@ pub enum ContractError { InvalidModality {}, #[error( - "Thrown when the user tries to serve an axon which is not of type 4 (IPv4) or 6 (IPv6)." + "Thrown when the user tries to serve an axon which is not of type 4 (IPv4) or 6 (IPv6)." )] InvalidIpType {}, @@ -79,7 +79,7 @@ pub enum ContractError { #[error("Thrown if the vaule is invalid for MaxAllowedUids.")] MaxAllowedUIdsNotAllowed {}, - #[error("Thrown when the dispatch attempts to convert between a u64 and T::balance but the call fails.")] + #[error("Thrown when wrong denom passed to the contract as payment")] CouldNotConvertToBalance {}, #[error("Thrown when the caller requests adding stake for a hotkey to the total stake which already added.")] @@ -143,21 +143,6 @@ pub enum ContractError { #[error("Thrown when the hotkey passed is not the origin, but it should be")] HotkeyOriginMismatch {}, - // {} Senate errors - // #[error("Thrown when attempting to do something to a senate member that is limited")] - // SenateMember {}, - // - // #[error("Thrown when a hotkey attempts to do something only senate members can do")] - // NotSenateMember {}, - // - // #[error("Thrown when a hotkey attempts to join the senate while already being a member")] - // AlreadySenateMember {}, - // - // #[error("Thrown when a hotkey attempts to join the senate without enough stake")] - // BelowStakeThreshold {}, - // - // #[error("Thrown when a hotkey attempts to join the senate without being a delegate first")] - // NotDelegate {}, #[error("Thrown when an incorrect amount of Netuids are passed as input")] IncorrectNetuidsLength {}, @@ -175,4 +160,7 @@ pub enum ContractError { #[error("Thrown when all subnets are in the immunity period")] AllNetworksInImmunity {}, + + #[error("Thrown when particle metadata size is invalid")] + MetadataSizeError {}, } diff --git a/src/math.rs b/src/math.rs index 4c92553..7392a40 100644 --- a/src/math.rs +++ b/src/math.rs @@ -1,87 +1,81 @@ -use substrate_fixed::transcendental::exp; use substrate_fixed::types::{I32F32, I64F64}; -// use num_traits::CheckedAdd; -#[allow(dead_code)] +#[cfg(test)] +use substrate_fixed::transcendental::exp; + +#[cfg(test)] pub fn fixed(val: f32) -> I32F32 { I32F32::from_num(val) } -#[allow(dead_code)] pub fn fixed_to_u16(x: I32F32) -> u16 { x.to_num::() } -#[allow(dead_code)] +#[cfg(test)] pub fn fixed_to_u64(x: I32F32) -> u64 { x.to_num::() } -#[allow(dead_code)] pub fn fixed64_to_u64(x: I64F64) -> u64 { x.to_num::() } -#[allow(dead_code)] pub fn fixed64_to_fixed32(x: I64F64) -> I32F32 { I32F32::from_num(x) } -#[allow(dead_code)] +#[cfg(test)] pub fn fixed32_to_fixed64(x: I32F32) -> I64F64 { I64F64::from_num(x) } -#[allow(dead_code)] +#[cfg(test)] pub fn u16_to_fixed(x: u16) -> I32F32 { I32F32::from_num(x) } -#[allow(dead_code)] +#[cfg(test)] pub fn u16_proportion_to_fixed(x: u16) -> I32F32 { I32F32::from_num(x) / I32F32::from_num(u16::MAX) } -#[allow(dead_code)] pub fn fixed_proportion_to_u16(x: I32F32) -> u16 { fixed_to_u16(x * I32F32::from_num(u16::MAX)) } -#[allow(dead_code)] +#[cfg(test)] pub fn vec_fixed32_to_u64(vec: Vec) -> Vec { vec.into_iter().map(|e| fixed_to_u64(e)).collect() } -#[allow(dead_code)] pub fn vec_fixed64_to_fixed32(vec: Vec) -> Vec { vec.into_iter().map(|e| fixed64_to_fixed32(e)).collect() } -#[allow(dead_code)] +#[cfg(test)] pub fn vec_fixed32_to_fixed64(vec: Vec) -> Vec { vec.into_iter().map(|e| fixed32_to_fixed64(e)).collect() } -#[allow(dead_code)] pub fn vec_fixed64_to_u64(vec: Vec) -> Vec { vec.into_iter().map(|e| fixed64_to_u64(e)).collect() } -#[allow(dead_code)] +#[cfg(test)] pub fn vec_u16_proportions_to_fixed(vec: Vec) -> Vec { vec.into_iter() .map(|e| u16_proportion_to_fixed(e)) .collect() } -#[allow(dead_code)] +#[cfg(test)] pub fn vec_fixed_proportions_to_u16(vec: Vec) -> Vec { vec.into_iter() .map(|e| fixed_proportion_to_u16(e)) .collect() } -#[allow(dead_code)] // Max-upscale vector and convert to u16 so max_value = u16::MAX. Assumes non-negative normalized input. pub fn vec_max_upscale_to_u16(vec: &Vec) -> Vec { let u16_max: I32F32 = I32F32::from_num(u16::MAX); @@ -116,14 +110,12 @@ pub fn vec_max_upscale_to_u16(vec: &Vec) -> Vec { } } -#[allow(dead_code)] // Max-upscale u16 vector and convert to u16 so max_value = u16::MAX. Assumes u16 vector input. pub fn vec_u16_max_upscale_to_u16(vec: &Vec) -> Vec { let vec_fixed: Vec = vec.iter().map(|e: &u16| I32F32::from_num(*e)).collect(); vec_max_upscale_to_u16(&vec_fixed) } -#[allow(dead_code)] // Checks if u16 vector, when normalized, has a max value not greater than a u16 ratio max_limit. pub fn check_vec_max_limited(vec: &Vec, max_limit: u16) -> bool { let max_limit_fixed: I32F32 = I32F32::from_num(max_limit) / I32F32::from_num(u16::MAX); @@ -140,42 +132,18 @@ pub fn check_vec_max_limited(vec: &Vec, max_limit: u16) -> bool { } } -#[allow(dead_code)] pub fn sum(x: &Vec) -> I32F32 { x.iter().sum() } -#[allow(dead_code)] -// Sums a Vector of type that has CheckedAdd trait. -// Returns None if overflow occurs during sum using T::checked_add. -// Returns Some(T::default()) if input vector is empty. -// pub fn checked_sum(x: &Vec) -> Option -// where -// T: Copy + Default + CheckedAdd, -// { -// if x.len() == 0 { -// return Some(T::default()); -// } -// -// let mut sum: T = x[0]; -// for i in x[1..].iter() { -// match sum.checked_add(i) { -// Some(val) => sum = val, -// None => return None, -// } -// } -// Some(sum) -// } - // Return true when vector sum is zero. -#[allow(dead_code)] pub fn is_zero(vector: &Vec) -> bool { let vector_sum: I32F32 = sum(&vector); vector_sum == I32F32::from_num(0) } // Exp safe function with I32F32 output of I32F32 input. -#[allow(dead_code)] +#[cfg(test)] pub fn exp_safe(input: I32F32) -> I32F32 { let min_input: I32F32 = I32F32::from_num(-20); // <= 1/exp(-20) = 485 165 195,4097903 let max_input: I32F32 = I32F32::from_num(20); // <= exp(20) = 485 165 195,4097903 @@ -202,7 +170,7 @@ pub fn exp_safe(input: I32F32) -> I32F32 { } // Sigmoid safe function with I32F32 output of I32F32 input with offset kappa and (recommended) scaling 0 < rho <= 40. -#[allow(dead_code)] +#[cfg(test)] pub fn sigmoid_safe(input: I32F32, rho: I32F32, kappa: I32F32) -> I32F32 { let one: I32F32 = I32F32::from_num(1); let offset: I32F32 = input.saturating_sub(kappa); // (input - kappa) @@ -215,7 +183,6 @@ pub fn sigmoid_safe(input: I32F32, rho: I32F32, kappa: I32F32) -> I32F32 { } // Returns a bool vector where an item is true if the vector item is in topk values. -#[allow(dead_code)] pub fn is_topk(vector: &Vec, k: usize) -> Vec { let n: usize = vector.len(); let mut result: Vec = vec![true; n]; @@ -231,7 +198,7 @@ pub fn is_topk(vector: &Vec, k: usize) -> Vec { } // Returns a normalized (sum to 1 except 0) copy of the input vector. -#[allow(dead_code)] +#[cfg(test)] pub fn normalize(x: &Vec) -> Vec { let x_sum: I32F32 = sum(x); if x_sum != I32F32::from_num(0.0 as f32) { @@ -242,7 +209,6 @@ pub fn normalize(x: &Vec) -> Vec { } // Normalizes (sum to 1 except 0) the input vector directly in-place. -#[allow(dead_code)] pub fn inplace_normalize(x: &mut Vec) { let x_sum: I32F32 = x.iter().sum(); if x_sum == I32F32::from_num(0.0 as f32) { @@ -254,7 +220,6 @@ pub fn inplace_normalize(x: &mut Vec) { } // Normalizes (sum to 1 except 0) the input vector directly in-place, using the sum arg. -#[allow(dead_code)] pub fn inplace_normalize_using_sum(x: &mut Vec, x_sum: I32F32) { if x_sum == I32F32::from_num(0.0 as f32) { return; @@ -265,7 +230,6 @@ pub fn inplace_normalize_using_sum(x: &mut Vec, x_sum: I32F32) { } // Normalizes (sum to 1 except 0) the I64F64 input vector directly in-place. -#[allow(dead_code)] pub fn inplace_normalize_64(x: &mut Vec) { let x_sum: I64F64 = x.iter().sum(); if x_sum == I64F64::from_num(0) { @@ -277,7 +241,6 @@ pub fn inplace_normalize_64(x: &mut Vec) { } /// Returns x / y for input vectors x and y, if y == 0 return 0. -#[allow(dead_code)] pub fn vecdiv(x: &Vec, y: &Vec) -> Vec { assert_eq!(x.len(), y.len()); let n = x.len(); @@ -291,7 +254,7 @@ pub fn vecdiv(x: &Vec, y: &Vec) -> Vec { } // Normalizes (sum to 1 except 0) each row (dim=0) of a matrix in-place. -#[allow(dead_code)] +#[cfg(test)] pub fn inplace_row_normalize(x: &mut Vec>) { for i in 0..x.len() { let row_sum: I32F32 = x[i].iter().sum(); @@ -303,7 +266,6 @@ pub fn inplace_row_normalize(x: &mut Vec>) { } // Normalizes (sum to 1 except 0) each row (dim=0) of a sparse matrix in-place. -#[allow(dead_code)] pub fn inplace_row_normalize_sparse(sparse_matrix: &mut Vec>) { for sparse_row in sparse_matrix.iter_mut() { let row_sum: I32F32 = sparse_row.iter().map(|(_j, value)| *value).sum(); @@ -316,7 +278,7 @@ pub fn inplace_row_normalize_sparse(sparse_matrix: &mut Vec>) } // Sum across each row (dim=0) of a matrix. -#[allow(dead_code)] +#[cfg(test)] pub fn row_sum(x: &Vec>) -> Vec { if x.len() == 0 { return vec![]; @@ -335,7 +297,6 @@ pub fn row_sum(x: &Vec>) -> Vec { } // Sum across each row (dim=0) of a sparse matrix. -#[allow(dead_code)] pub fn row_sum_sparse(sparse_matrix: &Vec>) -> Vec { let rows = sparse_matrix.len(); let mut result: Vec = vec![I32F32::from_num(0); rows]; @@ -348,7 +309,7 @@ pub fn row_sum_sparse(sparse_matrix: &Vec>) -> Vec { } // Sum across each column (dim=1) of a matrix. -#[allow(dead_code)] +#[cfg(test)] pub fn col_sum(x: &Vec>) -> Vec { if x.len() == 0 { return vec![]; @@ -368,7 +329,7 @@ pub fn col_sum(x: &Vec>) -> Vec { } // Sum across each column (dim=1) of a sparse matrix. -#[allow(dead_code)] +#[cfg(test)] pub fn col_sum_sparse(sparse_matrix: &Vec>, columns: u16) -> Vec { let mut result: Vec = vec![I32F32::from_num(0); columns as usize]; for sparse_row in sparse_matrix.iter() { @@ -380,7 +341,6 @@ pub fn col_sum_sparse(sparse_matrix: &Vec>, columns: u16) -> } // Normalizes (sum to 1 except 0) each column (dim=1) of a sparse matrix in-place. -#[allow(dead_code)] pub fn inplace_col_normalize_sparse(sparse_matrix: &mut Vec>, columns: u16) { let mut col_sum: Vec = vec![I32F32::from_num(0.0); columns as usize]; // assume square matrix, rows=cols for sparse_row in sparse_matrix.iter() { @@ -399,7 +359,7 @@ pub fn inplace_col_normalize_sparse(sparse_matrix: &mut Vec>, } // Normalizes (sum to 1 except 0) each column (dim=1) of a matrix in-place. -#[allow(dead_code)] +#[cfg(test)] pub fn inplace_col_normalize(x: &mut Vec>) { if x.len() == 0 { return; @@ -426,7 +386,6 @@ pub fn inplace_col_normalize(x: &mut Vec>) { } // Max-upscale each column (dim=1) of a sparse matrix in-place. -#[allow(dead_code)] pub fn inplace_col_max_upscale_sparse(sparse_matrix: &mut Vec>, columns: u16) { let mut col_max: Vec = vec![I32F32::from_num(0.0); columns as usize]; // assume square matrix, rows=cols for sparse_row in sparse_matrix.iter() { @@ -447,7 +406,7 @@ pub fn inplace_col_max_upscale_sparse(sparse_matrix: &mut Vec } // Max-upscale each column (dim=1) of a matrix in-place. -#[allow(dead_code)] +#[cfg(test)] pub fn inplace_col_max_upscale(x: &mut Vec>) { if x.len() == 0 { return; @@ -476,7 +435,6 @@ pub fn inplace_col_max_upscale(x: &mut Vec>) { } // Apply mask to vector, mask=true will mask out, i.e. set to 0. -#[allow(dead_code)] pub fn inplace_mask_vector(mask: &Vec, vector: &mut Vec) { if mask.len() == 0 { return; @@ -491,7 +449,7 @@ pub fn inplace_mask_vector(mask: &Vec, vector: &mut Vec) { } // Apply mask to matrix, mask=true will mask out, i.e. set to 0. -#[allow(dead_code)] +#[cfg(test)] pub fn inplace_mask_matrix(mask: &Vec>, matrix: &mut Vec>) { if mask.len() == 0 { return; @@ -511,7 +469,7 @@ pub fn inplace_mask_matrix(mask: &Vec>, matrix: &mut Vec>) } // Apply row mask to matrix, mask=true will mask out, i.e. set to 0. -#[allow(dead_code)] +#[cfg(test)] pub fn inplace_mask_rows(mask: &Vec, matrix: &mut Vec>) { let rows = matrix.len(); if rows == 0 { @@ -528,7 +486,7 @@ pub fn inplace_mask_rows(mask: &Vec, matrix: &mut Vec>) { } // Mask out the diagonal of the input matrix in-place. -#[allow(dead_code)] +#[cfg(test)] pub fn inplace_mask_diag(matrix: &mut Vec>) { if matrix.len() == 0 { return; @@ -544,7 +502,6 @@ pub fn inplace_mask_diag(matrix: &mut Vec>) { } // Return a new sparse matrix that replaces masked rows with an empty vector placeholder. -#[allow(dead_code)] pub fn mask_rows_sparse( mask: &Vec, sparse_matrix: &Vec>, @@ -561,7 +518,6 @@ pub fn mask_rows_sparse( } // Return a new sparse matrix with a masked out diagonal of input sparse matrix. -#[allow(dead_code)] pub fn mask_diag_sparse(sparse_matrix: &Vec>) -> Vec> { let n: usize = sparse_matrix.len(); let mut result: Vec> = vec![vec![]; n]; @@ -576,7 +532,6 @@ pub fn mask_diag_sparse(sparse_matrix: &Vec>) -> Vec>, first_vector: &Vec, @@ -596,7 +551,7 @@ pub fn vec_mask_sparse_matrix( } // Row-wise matrix-vector hadamard product. -#[allow(dead_code)] +#[cfg(test)] pub fn row_hadamard(matrix: &Vec>, vector: &Vec) -> Vec> { if matrix.len() == 0 { return vec![vec![]]; @@ -615,7 +570,6 @@ pub fn row_hadamard(matrix: &Vec>, vector: &Vec) -> Vec>, vector: &Vec, @@ -630,7 +584,7 @@ pub fn row_hadamard_sparse( } // Row-wise matrix-vector product, column-wise sum: result_j = SUM(i) vector_i * matrix_ij. -#[allow(dead_code)] +#[cfg(test)] pub fn matmul(matrix: &Vec>, vector: &Vec) -> Vec { if matrix.len() == 0 { return vec![]; @@ -651,52 +605,50 @@ pub fn matmul(matrix: &Vec>, vector: &Vec) -> Vec { result } -// Row-wise matrix-vector product, column-wise sum: result_j = SUM(i) vector_i * matrix_ij. -#[allow(dead_code)] -pub fn matmul_64(matrix: &Vec>, vector: &Vec) -> Vec { +// Column-wise matrix-vector product, row-wise sum: result_i = SUM(j) vector_j * matrix_ij. +#[cfg(test)] +pub fn matmul_transpose(matrix: &Vec>, vector: &Vec) -> Vec { if matrix.len() == 0 { return vec![]; } if matrix[0].len() == 0 { return vec![]; } - assert!(matrix.len() == vector.len()); - let mut result: Vec = vec![I64F64::from_num(0.0); matrix[0].len()]; + assert!(matrix[0].len() == vector.len()); + let mut result: Vec = vec![I32F32::from_num(0.0); matrix.len()]; for i in 0..matrix.len() { for j in 0..matrix[i].len() { - // Compute ranks: r_j = SUM(i) w_ij * s_i - // Compute trust scores: t_j = SUM(i) w_ij * s_i - // result_j = SUM(i) vector_i * matrix_ij - result[j] += vector[i] * matrix[i][j]; + // Compute dividends: d_j = SUM(i) b_ji * inc_i + // result_j = SUM(i) vector_i * matrix_ji + // result_i = SUM(j) vector_j * matrix_ij + result[i] += vector[j] * matrix[i][j]; } } result } -// Column-wise matrix-vector product, row-wise sum: result_i = SUM(j) vector_j * matrix_ij. -#[allow(dead_code)] -pub fn matmul_transpose(matrix: &Vec>, vector: &Vec) -> Vec { +// Row-wise matrix-vector product, column-wise sum: result_j = SUM(i) vector_i * matrix_ij. +pub fn matmul_64(matrix: &Vec>, vector: &Vec) -> Vec { if matrix.len() == 0 { return vec![]; } if matrix[0].len() == 0 { return vec![]; } - assert!(matrix[0].len() == vector.len()); - let mut result: Vec = vec![I32F32::from_num(0.0); matrix.len()]; + assert!(matrix.len() == vector.len()); + let mut result: Vec = vec![I64F64::from_num(0.0); matrix[0].len()]; for i in 0..matrix.len() { for j in 0..matrix[i].len() { - // Compute dividends: d_j = SUM(i) b_ji * inc_i - // result_j = SUM(i) vector_i * matrix_ji - // result_i = SUM(j) vector_j * matrix_ij - result[i] += vector[j] * matrix[i][j]; + // Compute ranks: r_j = SUM(i) w_ij * s_i + // Compute trust scores: t_j = SUM(i) w_ij * s_i + // result_j = SUM(i) vector_i * matrix_ij + result[j] += vector[i] * matrix[i][j]; } } result } // Row-wise sparse_matrix-vector product, column-wise sum: result_j = SUM(i) vector_i * matrix_ij. -#[allow(dead_code)] pub fn matmul_sparse( sparse_matrix: &Vec>, vector: &Vec, @@ -709,13 +661,13 @@ pub fn matmul_sparse( // Compute trust scores: t_j = SUM(i) w_ij * s_i // result_j = SUM(i) vector_i * matrix_ij result[*j as usize] += vector[i] * value; + // println!("{} {} {}", j, vector[i], value) } } result } // Column-wise sparse_matrix-vector product, row-wise sum: result_i = SUM(j) vector_j * matrix_ij. -#[allow(dead_code)] pub fn matmul_transpose_sparse( sparse_matrix: &Vec>, vector: &Vec, @@ -733,7 +685,7 @@ pub fn matmul_transpose_sparse( } // Set inplace matrix values above column threshold to threshold value. -#[allow(dead_code)] +#[cfg(test)] pub fn inplace_col_clip(x: &mut Vec>, col_threshold: &Vec) { for i in 0..x.len() { for j in 0..x[i].len() { @@ -745,7 +697,6 @@ pub fn inplace_col_clip(x: &mut Vec>, col_threshold: &Vec) { } // Return sparse matrix with values above column threshold set to threshold value. -#[allow(dead_code)] pub fn col_clip_sparse( sparse_matrix: &Vec>, col_threshold: &Vec, @@ -766,7 +717,7 @@ pub fn col_clip_sparse( } // Set matrix values below threshold to lower, and equal-above to upper. -#[allow(dead_code)] +#[cfg(test)] pub fn clip( x: &Vec>, threshold: I32F32, @@ -789,7 +740,7 @@ pub fn clip( } // Set inplace matrix values below threshold to lower, and equal-above to upper. -#[allow(dead_code)] +#[cfg(test)] pub fn inplace_clip(x: &mut Vec>, threshold: I32F32, upper: I32F32, lower: I32F32) { for i in 0..x.len() { for j in 0..x[i].len() { @@ -804,7 +755,7 @@ pub fn inplace_clip(x: &mut Vec>, threshold: I32F32, upper: I32F32, // Set sparse matrix values below threshold to lower, and equal-above to upper. // Does not add missing elements (0 value assumed) when lower!=0. -#[allow(dead_code)] +#[cfg(test)] pub fn clip_sparse( sparse_matrix: &Vec>, threshold: I32F32, @@ -851,7 +802,6 @@ pub fn clip_sparse( // * 'median': ( I32F32 ): // - median via random pivot binary search. // -#[allow(dead_code)] pub fn weighted_median( stake: &Vec, score: &Vec, @@ -911,7 +861,7 @@ pub fn weighted_median( } /// Column-wise weighted median, e.g. stake-weighted median scores per server (column) over all validators (rows). -#[allow(dead_code)] +#[cfg(test)] pub fn weighted_median_col( stake: &Vec, score: &Vec>, @@ -949,7 +899,6 @@ pub fn weighted_median_col( } /// Column-wise weighted median, e.g. stake-weighted median scores per server (column) over all validators (rows). -#[allow(dead_code)] pub fn weighted_median_col_sparse( stake: &Vec, score: &Vec>, @@ -989,7 +938,7 @@ pub fn weighted_median_col_sparse( } // Element-wise product of two matrices. -#[allow(dead_code)] +#[cfg(test)] pub fn hadamard(mat1: &Vec>, mat2: &Vec>) -> Vec> { assert!(mat1.len() == mat2.len()); if mat1.len() == 0 { @@ -1009,7 +958,7 @@ pub fn hadamard(mat1: &Vec>, mat2: &Vec>) -> Vec>, mat2: &Vec>, @@ -1041,7 +990,7 @@ pub fn hadamard_sparse( // Return matrix exponential moving average: `alpha * a_ij + one_minus_alpha * b_ij`. // `alpha` is the EMA coefficient, how much to add of the new observation, typically small, // higher alpha discounts older observations faster. -#[allow(dead_code)] +#[cfg(test)] pub fn mat_ema(new: &Vec>, old: &Vec>, alpha: I32F32) -> Vec> { if new.len() == 0 { return vec![vec![]; 1]; @@ -1064,7 +1013,6 @@ pub fn mat_ema(new: &Vec>, old: &Vec>, alpha: I32F32) -> // Return sparse matrix exponential moving average: `alpha * a_ij + one_minus_alpha * b_ij`. // `alpha` is the EMA coefficient, how much to add of the new observation, typically small, // higher alpha discounts older observations faster. -#[allow(dead_code)] pub fn mat_ema_sparse( new: &Vec>, old: &Vec>, @@ -1093,7 +1041,7 @@ pub fn mat_ema_sparse( } // Return sparse matrix only with elements >= threshold of an input sparse matrix. -#[allow(dead_code)] +#[cfg(test)] pub fn sparse_threshold(w: &Vec>, threshold: I32F32) -> Vec> { let mut sparse_threshold_result: Vec> = vec![vec![]; w.len()]; for (uid_i, weights_i) in w.iter().enumerate() { diff --git a/src/msg.rs b/src/msg.rs index 5612a40..e705afa 100644 --- a/src/msg.rs +++ b/src/msg.rs @@ -6,6 +6,7 @@ pub struct InstantiateMsg {} #[cw_serde] pub enum ExecuteMsg { Activate {}, + Deactivate {}, // TODO remove later, use for manual block_step BlockStep {}, @@ -68,8 +69,6 @@ pub enum ExecuteMsg { netuid: u16, hotkey: String, coldkey: String, - stake: u64, - balance: u64, }, SudoSetDefaultTake { default_take: u16, @@ -149,10 +148,6 @@ pub enum ExecuteMsg { netuid: u16, validator_prune_len: u64, }, - SudoSetScalingLawPower { - netuid: u16, - scaling_law_power: u16, - }, SudoSetImmunityPeriod { netuid: u16, immunity_period: u16, @@ -212,6 +207,10 @@ pub enum ExecuteMsg { SudoSetBlockEmission { emission: u64, }, + SudoSetSubnetMetadata { + netuid: u16, + particle: String, + }, } #[cw_serde] @@ -250,86 +249,63 @@ pub enum QueryMsg { #[returns(Vec)] GetStakeInfoForColdkeys { coldkeys: Vec }, - #[returns(u64)] - GetNetworkRegistrationCost {}, - - // TODO added for cybertensor CLI - #[returns(Option)] - GetSubnetOwner { netuid: u16 }, - - #[returns(Option)] - GetHotkeyOwner { hotkey: String }, - + #[returns(Option)] + GetTotalStakeForHotkey { address: String }, + #[returns(Option)] + GetTotalStakeForColdkey { address: String }, #[returns(Option)] GetStakeForColdkeyAndHotkey { coldkey: String, hotkey: String }, + #[returns(Option)] + GetHotkeyOwner { hotkey: String }, #[returns(Option)] GetUidForHotkeyOnSubnet { hotkey: String, netuid: u16 }, - #[returns(Option>)] GetNetuidsForHotkey { hotkey: String }, + #[returns(bool)] + GetHotkeyExist { hotkey: String }, + #[returns(Vec<(String, u64)>)] + GetStake { hotkey: String }, + #[returns(Option)] + GetDelegateTake { hotkey: String }, #[returns(bool)] GetSubnetExist { netuid: u16 }, - + #[returns(Option)] + GetSubnetOwner { netuid: u16 }, #[returns(Option)] GetMaxWeightLimit { netuid: u16 }, - #[returns(Option)] GetMinAllowedWeights { netuid: u16 }, - - #[returns(Option)] - GetDelegateTake { hotkey: String }, - #[returns(Option)] GetBurn { netuid: u16 }, - #[returns(Option)] GetDifficulty { netuid: u16 }, - #[returns(Option)] GetTempo { netuid: u16 }, + #[returns(u64)] + GetEmissionValueBySubnet { netuid: u16 }, + #[returns(u64)] + GetNetworkRegistrationCost {}, #[returns(u16)] GetTotalNetworks {}, - #[returns(Vec)] GetNetworksAdded {}, - - #[returns(u64)] - GetEmissionValueBySubnet { netuid: u16 }, - #[returns(Vec)] GetAllSubnetNetuids {}, - #[returns(u64)] GetTotalIssuance {}, - #[returns(u64)] GetTotalStake {}, - #[returns(u64)] GetTxRateLimit {}, #[returns(Option)] GetAxonInfo { netuid: u16, hotkey: String }, - #[returns(Option)] GetPrometheusInfo { netuid: u16, hotkey: String }, - #[returns(Option)] - GetTotalStakeForHotkey { address: String }, - - #[returns(Option)] - GetTotalStakeForColdkey { address: String }, - - #[returns(bool)] - GetHotkeyExist { hotkey: String }, - - #[returns(Vec<(String, u64)>)] - GetStake { hotkey: String }, - - // TODO added for debugging, remove later #[returns(Vec>)] GetWeights { netuid: u16 }, #[returns(Vec>)] diff --git a/src/registration.rs b/src/registration.rs index 14c74e6..dd3474c 100644 --- a/src/registration.rs +++ b/src/registration.rs @@ -1,15 +1,9 @@ use crate::root::{get_root_netuid, if_subnet_allows_registration, if_subnet_exist}; -use crate::staking::{ - add_balance_to_coldkey_account, create_account_if_non_existent, - increase_stake_on_coldkey_hotkey_account, u64_to_balance, -}; -use crate::staking::{ - can_remove_balance_from_coldkey_account, coldkey_owns_hotkey, - remove_balance_from_coldkey_account, -}; +use crate::staking::coldkey_owns_hotkey; +use crate::staking::{create_account_if_non_existent, increase_stake_on_coldkey_hotkey_account}; use crate::state::{ - ALLOW_FAUCET, BURN_REGISTRATIONS_THIS_INTERVAL, DENOM, POW_REGISTRATIONS_THIS_INTERVAL, - REGISTRATIONS_THIS_BLOCK, REGISTRATIONS_THIS_INTERVAL, TOTAL_ISSUANCE, UIDS, USED_WORK, + BURN_REGISTRATIONS_THIS_INTERVAL, DENOM, POW_REGISTRATIONS_THIS_INTERVAL, + REGISTRATIONS_THIS_BLOCK, REGISTRATIONS_THIS_INTERVAL, UIDS, USED_WORK, }; use crate::uids::{append_neuron, get_subnetwork_n, replace_neuron}; use crate::utils::{ @@ -19,7 +13,7 @@ use crate::utils::{ get_target_registrations_per_interval, increase_rao_recycled, set_pruning_score_for_uid, }; use crate::ContractError; -use cosmwasm_std::{ensure, Addr, Api, DepsMut, Env, MessageInfo, StdResult, Storage}; +use cosmwasm_std::{ensure, Api, DepsMut, Env, MessageInfo, StdResult, Storage}; use cw_utils::must_pay; use primitive_types::{H256, U256}; @@ -34,16 +28,18 @@ pub fn do_sudo_registration( netuid: u16, hotkey_address: String, coldkey_address: String, - stake: u64, - balance: u64, ) -> Result { - // TODO update stake and balance to incoming tokens - // let denom = DENOM.load(deps.storage)?; - // let amount = must_pay(&info, &denom).map_err(|_| ContractError::CouldNotConvertToBalance {})?; + let denom = DENOM.load(deps.storage)?; + let stake = must_pay(&info, &denom).map_err(|_| ContractError::CouldNotConvertToBalance {})?; let hotkey = deps.api.addr_validate(&hotkey_address)?; let coldkey = deps.api.addr_validate(&coldkey_address)?; + deps.api.debug(&format!( + "👾 do_sudo_registration ( netuid:{:?} hotkey:{:?}, coldkey:{:?} )", + netuid, hotkey, coldkey + )); + ensure_root(deps.storage, &info.sender)?; ensure!( @@ -66,14 +62,7 @@ pub fn do_sudo_registration( coldkey_owns_hotkey(deps.storage, &coldkey, &hotkey), ContractError::NonAssociatedColdKey {} ); - increase_stake_on_coldkey_hotkey_account(deps.storage, &coldkey, &hotkey, stake); - - // let balance_to_be_added_as_balance = u64_to_balance(balance); - // ensure!( - // balance_to_be_added_as_balance.is_some(), - // ContractError::CouldNotConvertToBalance {} - // ); - // add_balance_to_coldkey_account(&coldkey, balance_to_be_added_as_balance.unwrap()); + increase_stake_on_coldkey_hotkey_account(deps.storage, &coldkey, &hotkey, stake.u128() as u64); let subnetwork_uid: u16; let current_block_number: u64 = env.block.height; @@ -91,14 +80,14 @@ pub fn do_sudo_registration( &hotkey, current_block_number, )?; - deps.api.debug(&format!("add new neuron account")); + deps.api.debug(&format!("👾 add new neuron account")); } else { // --- 12.1.1 Replacement required. // We take the neuron with the lowest pruning score here. subnetwork_uid = get_neuron_to_prune(deps.storage, deps.api, netuid, env.block.height); // --- 12.1.1 Replace the neuron account with the new info. - replace_neuron( + let _msgs = replace_neuron( deps.storage, deps.api, netuid, @@ -106,11 +95,11 @@ pub fn do_sudo_registration( &hotkey, current_block_number, )?; - deps.api.debug(&format!("prune neuron")); + deps.api.debug(&format!("👾 prune neuron")); } deps.api.debug(&format!( - "NeuronRegistered( netuid:{:?} uid:{:?} hotkey:{:?} ) ", + "👾 Neuron Registration Sudo ( netuid:{:?} uid:{:?} hotkey:{:?} ) ", netuid, subnetwork_uid, hotkey )); @@ -120,7 +109,6 @@ pub fn do_sudo_registration( .add_attribute("hotkey", hotkey)) } -// ---- The implementation for the extrinsic do_burned_registration: registering by burning TAO. // // # Args: // * 'origin': (RuntimeOrigin): @@ -154,7 +142,7 @@ pub fn do_burned_registration( netuid: u16, hotkey_address: String, ) -> Result { - // TODO cannot burn so just receive tokens for registration and account as burned increase_rao_recycled + // TODO update burn when token factory bindings will be available let denom = DENOM.load(deps.storage)?; let amount = must_pay(&info, &denom).map_err(|_| ContractError::CouldNotConvertToBalance {})?; @@ -163,8 +151,8 @@ pub fn do_burned_registration( let hotkey = deps.api.addr_validate(&hotkey_address)?; deps.api.debug(&format!( - "do_registration( coldkey:{:?} netuid:{:?} hotkey:{:?} )", - coldkey, netuid, hotkey + "👾 do_burned_registration ( netuid:{:?} hotkey:{:?}, coldkey:{:?} )", + netuid, hotkey, coldkey )); // --- 2. Ensure the passed network is valid. @@ -206,23 +194,12 @@ pub fn do_burned_registration( // --- 7. Ensure the callers coldkey has enough stake to perform the transaction. let current_block_number: u64 = env.block.height; let registration_cost_as_u64 = get_burn_as_u64(deps.storage, netuid); - let registration_cost_as_balance = u64_to_balance(registration_cost_as_u64).unwrap(); - // ensure!( - // can_remove_balance_from_coldkey_account(&coldkey, registration_cost_as_balance), - // ContractError::NotEnoughBalanceToStake {} - // ); ensure!( - amount.u128() as u64 >= registration_cost_as_balance, + amount.u128() as u64 >= registration_cost_as_u64, ContractError::NotEnoughTokens {} ); - // --- 8. Ensure the remove operation from the coldkey is a success. - // ensure!( - // remove_balance_from_coldkey_account(&coldkey, registration_cost_as_balance) == true, - // ContractError::BalanceWithdrawalError {} - // ); - // The burn occurs here. // same as below let burn_amount = get_burn_as_u64(deps.storage, netuid); @@ -260,14 +237,14 @@ pub fn do_burned_registration( &hotkey, current_block_number, )?; - deps.api.debug(&format!("add new neuron account")); + deps.api.debug(&format!("👾 add new neuron account")); } else { // --- 13.1.1 Replacement required. // We take the neuron with the lowest pruning score here. subnetwork_uid = get_neuron_to_prune(deps.storage, deps.api, netuid, env.block.height); // --- 13.1.1 Replace the neuron account with the new info. - replace_neuron( + let _msgs = replace_neuron( deps.storage, deps.api, netuid, @@ -275,7 +252,7 @@ pub fn do_burned_registration( &hotkey, current_block_number, )?; - deps.api.debug(&format!("prune neuron")); + deps.api.debug(&format!("👾 prune neuron")); } // --- 14. Record the registration and increment block and interval counters. @@ -302,7 +279,7 @@ pub fn do_burned_registration( // --- 15. Deposit successful event. deps.api.debug(&format!( - "NeuronRegistered( netuid:{:?} uid:{:?} hotkey:{:?} ) ", + "👾 Neuron Registration Burned ( netuid:{:?} uid:{:?} hotkey:{:?} ) ", netuid, subnetwork_uid, hotkey.clone() @@ -381,7 +358,7 @@ pub fn do_registration( let coldkey = deps.api.addr_validate(&coldkey_address)?; deps.api.debug(&format!( - "do_registration( origin:{:?} netuid:{:?} hotkey:{:?}, coldkey:{:?} )", + "👾 do_registration ( origin:{:?} netuid:{:?} hotkey:{:?}, coldkey:{:?} )", signing_origin, netuid, hotkey, coldkey )); @@ -484,14 +461,14 @@ pub fn do_registration( &hotkey.clone(), current_block_number, )?; - deps.api.debug(&format!("add new neuron account")); + deps.api.debug(&format!("👾 add new neuron account")); } else { // --- 11.1.1 Replacement required. // We take the neuron with the lowest pruning score here. subnetwork_uid = get_neuron_to_prune(deps.storage, deps.api, netuid, current_block_number); // --- 11.1.1 Replace the neuron account with the new info. - replace_neuron( + let _msgs = replace_neuron( deps.storage, deps.api, netuid, @@ -499,7 +476,7 @@ pub fn do_registration( &hotkey.clone(), current_block_number, )?; - deps.api.debug(&format!("prune neuron")); + deps.api.debug(&format!("👾 prune neuron")); } // --- 12. Record the registration and increment block and interval counters. @@ -524,7 +501,7 @@ pub fn do_registration( // --- 13. Deposit successful event. deps.api.debug(&format!( - "NeuronRegistered( netuid:{:?} uid:{:?} hotkey:{:?} ) ", + "👾 Neuron Registration PoW( netuid:{:?} uid:{:?} hotkey:{:?} ) ", netuid, subnetwork_uid, hotkey )); @@ -721,6 +698,7 @@ pub fn get_block_hash_from_u64(_: u64) -> H256 { return real_hash; } +#[cfg(test)] pub fn hash_to_vec(hash: H256) -> Vec { let hash_as_bytes: &[u8] = hash.as_bytes(); let hash_as_vec: Vec = hash_as_bytes.iter().cloned().collect(); @@ -882,6 +860,7 @@ pub fn get_difficulty(store: &dyn Storage, netuid: u16) -> U256 { // Helper function for creating nonce and work. // TODO rewrite to use only address and nonce +#[cfg(test)] pub fn create_work_for_block_number( store: &dyn Storage, netuid: u16, diff --git a/src/root.rs b/src/root.rs index 112a6c5..2452260 100644 --- a/src/root.rs +++ b/src/root.rs @@ -15,22 +15,21 @@ use crate::state::{ BONDS_MOVING_AVERAGE, BURN, BURN_REGISTRATIONS_THIS_INTERVAL, CONSENSUS, DENOM, DIFFICULTY, DIVIDENDS, EMISSION, EMISSION_VALUES, IMMUNITY_PERIOD, INCENTIVE, KAPPA, KEYS, LAST_ADJUSTMENT_BLOCK, LAST_UPDATE, MAX_ALLOWED_UIDS, MAX_ALLOWED_VALIDATORS, MAX_BURN, - MAX_DIFFICULTY, MAX_REGISTRATION_PER_BLOCK, MAX_WEIGHTS_LIMIT, MIN_ALLOWED_WEIGHTS, MIN_BURN, - MIN_DIFFICULTY, NETWORKS_ADDED, NETWORK_IMMUNITY_PERIOD, NETWORK_LAST_LOCK_COST, + MAX_DIFFICULTY, MAX_REGISTRATION_PER_BLOCK, MAX_WEIGHTS_LIMIT, METADATA, MIN_ALLOWED_WEIGHTS, + MIN_BURN, MIN_DIFFICULTY, NETWORKS_ADDED, NETWORK_IMMUNITY_PERIOD, NETWORK_LAST_LOCK_COST, NETWORK_LAST_REGISTERED, NETWORK_LOCK_REDUCTION_INTERVAL, NETWORK_MIN_LOCK_COST, NETWORK_MODALITY, NETWORK_RATE_LIMIT, NETWORK_REGISTERED_AT, NETWORK_REGISTRATION_ALLOWED, PENDING_EMISSION, POW_REGISTRATIONS_THIS_INTERVAL, PRUNING_SCORES, RANK, RAO_RECYCLED_FOR_REGISTRATION, REGISTRATIONS_THIS_BLOCK, REGISTRATIONS_THIS_INTERVAL, RHO, - SCALING_LAW_POWER, SERVING_RATE_LIMIT, SUBNETWORK_N, SUBNET_LIMIT, SUBNET_OWNER, + SERVING_RATE_LIMIT, SUBNETWORK_N, SUBNET_LIMIT, SUBNET_OWNER, TARGET_REGISTRATIONS_PER_INTERVAL, TEMPO, TOTAL_NETWORKS, TRUST, UIDS, VALIDATOR_PERMIT, VALIDATOR_TRUST, WEIGHTS, WEIGHTS_SET_RATE_LIMIT, WEIGHTS_VERSION_KEY, }; use crate::uids::{append_neuron, get_hotkey_for_net_and_uid, get_subnetwork_n, replace_neuron}; use crate::utils::{ get_block_emission, get_emission_value, get_max_allowed_uids, get_max_registrations_per_block, - get_registrations_this_block, get_registrations_this_interval, get_rho, - get_subnet_locked_balance, get_subnet_owner, get_target_registrations_per_interval, get_tempo, - set_subnet_locked_balance, + get_registrations_this_block, get_registrations_this_interval, get_rho, get_subnet_owner, + get_target_registrations_per_interval, get_tempo, set_subnet_locked_balance, }; use crate::ContractError; @@ -96,7 +95,7 @@ pub fn get_max_root_validators(store: &dyn Storage) -> u16 { // // # Returns: // * 'u64': The emission value for the given subnet. -// +#[cfg(test)] pub fn get_subnet_emission_value(store: &dyn Storage, netuid: u16) -> u64 { EMISSION_VALUES.load(store, netuid).unwrap() } @@ -158,7 +157,7 @@ pub fn contains_invalid_root_uids(store: &dyn Storage, api: &dyn Api, netuids: & for netuid in netuids { if !if_subnet_exist(store, *netuid) { api.debug(&format!( - "contains_invalid_root_uids: netuid {:?} does not exist", + "🔵 contains_invalid_root_uids: netuid {:?} does not exist", netuid )); return true; @@ -177,28 +176,28 @@ pub fn set_emission_values( emission: Vec, ) -> Result<(), ContractError> { api.debug(&format!( - "set_emission_values: netuids: {:?} emission:{:?}", + "🔵 set_emission_values: netuids: {:?}, emission:{:?}", netuids, emission )); // Be careful this function can fail. if contains_invalid_root_uids(store, api, netuids) { api.debug(&format!( - "error set_emission_values: contains_invalid_root_uids" + "🔵 error set_emission_values: contains_invalid_root_uids" )); return Err(ContractError::InvalidUid {}); } if netuids.len() != emission.len() { api.debug(&format!( - "error set_emission_values: netuids.len() != emission.len()" + "🔵 error set_emission_values: netuids.len() != emission.len()" )); return Err(ContractError::Std(GenericErr { - msg: "netuids and emission must have the same length".to_string(), + msg: "🔵 netuids and emission must have the same length".to_string(), })); } for (i, netuid_i) in netuids.iter().enumerate() { api.debug(&format!( - "set netuid:{:?} emission:{:?}", + "🔵 set netuid:{:?}, emission:{:?}", netuid_i, emission[i] )); EMISSION_VALUES.save(store, *netuid_i, &emission[i])?; @@ -218,12 +217,12 @@ pub fn get_root_weights(store: &dyn Storage, api: &dyn Api) -> Vec> let n: usize = get_num_root_validators(store) as usize; // --- 1 The number of subnets to validate. - api.debug(&format!( - "subnet size before cast: {:?}", - get_num_subnets(store) - )); + // api.debug(&format!( + // "🔵 subnet size before cast: {:?}", + // get_num_subnets(store) + // )); let k: usize = get_num_subnets(store) as usize; - api.debug(&format!("n: {:?} k: {:?}", n, k)); + api.debug(&format!("🔵 root_validators: {:?}, subnets: {:?}", n, k)); // --- 2. Initialize a 2D vector with zeros to store the weights. The dimensions are determined // by `n` (number of validators) and `k` (total number of subnets). @@ -280,38 +279,38 @@ pub fn root_epoch( if blocks_until_next_epoch != 0 { // Not the block to update emission values. api.debug(&format!( - "blocks_until_next_epoch: {:?}", + "🔵 blocks_until_next_epoch: {:?}", blocks_until_next_epoch )); return Err(ContractError::Std(GenericErr { - msg: "Not the block to update emission values.".to_string(), + msg: "🔵 Not the block to update emission values.".to_string(), })); } // --- 1. Retrieves the number of root validators on subnets. let n: u16 = get_num_root_validators(store); - api.debug(&format!("n:\n{:?}\n", n)); + api.debug(&format!("root_validators: {:?}", n)); if n == 0 { // No validators. return Err(ContractError::Std(GenericErr { - msg: "No validators to validate emission values.".to_string(), + msg: "🔵 No validators to validate emission values.".to_string(), })); } // --- 2. Obtains the number of registered subnets. let k: u16 = get_all_subnet_netuids(store).len() as u16; - api.debug(&format!("k:\n{:?}\n", k)); + api.debug(&format!("subnets 🔵: {:?}", k)); if k == 0 { // No networks to validate. return Err(ContractError::Std(GenericErr { - msg: "No networks to validate emission values.".to_string(), + msg: "🔵 No networks to validate emission values.".to_string(), })); } // --- 4. Determines the total block emission across all the subnetworks. This is the // value which will be distributed based on the computation below. let block_emission: I64F64 = I64F64::from_num(get_block_emission(store)); - api.debug(&format!("block_emission:\n{:?}\n", block_emission)); + api.debug(&format!("🔵 block_emission: {:?}", block_emission)); // --- 5. A collection of all registered hotkeys on the root network. Hotkeys // pairs with network UIDs and stake values. @@ -324,7 +323,7 @@ pub fn root_epoch( let (uid_i, hotkey) = item?; hotkeys.push((uid_i, hotkey)); } - api.debug(&format!("hotkeys:\n{:?}\n", hotkeys)); + api.debug(&format!("🔵 hotkeys: {:?}\n", hotkeys)); // --- 6. Retrieves and stores the stake value associated with each hotkey on the root network. // Stakes are stored in a 64-bit fixed point representation for precise calculations. @@ -333,17 +332,17 @@ pub fn root_epoch( stake_i64[*uid_i as usize] = I64F64::from_num(get_total_stake_for_hotkey(store, &hotkey)); } inplace_normalize_64(&mut stake_i64); - api.debug(&format!("S:\n{:?}\n", &stake_i64)); + api.debug(&format!("🔵 stake: {:?}\n", &stake_i64)); // --- 8. Retrieves the network weights in a 2D Vector format. Weights have shape // n x k where is n is the number of registered peers and k is the number of subnets. let weights: Vec> = get_root_weights(store, api); - api.debug(&format!("W:\n{:?}\n", &weights)); + api.debug(&format!("🔵 weights: {:?}\n", &weights)); // --- 9. Calculates the rank of networks. Rank is a product of weights and stakes. // Ranks will have shape k, a score for each subnet. let ranks: Vec = matmul_64(&weights, &stake_i64); - api.debug(&format!("R:\n{:?}\n", &ranks)); + api.debug(&format!("🔵 ranks: {:?}\n", &ranks)); // --- 10. Calculates the trust of networks. Trust is a sum of all stake with weights > 0. // Trust will have shape k, a score for each subnet. @@ -360,12 +359,12 @@ pub fn root_epoch( } } - api.debug(&format!("T_before normalization:\n{:?}\n", &trust)); - api.debug(&format!("Total_stake:\n{:?}\n", &total_stake)); + api.debug(&format!("🔵 trust_nn: {:?}\n", &trust)); + api.debug(&format!("🔵 total_stake: {:?}\n", &total_stake)); if total_stake == 0 { return Err(ContractError::Std(GenericErr { - msg: "No stake on network".to_string(), + msg: "🔵 No stake on network".to_string(), })); } @@ -380,7 +379,7 @@ pub fn root_epoch( // --- 11. Calculates the consensus of networks. Consensus is a sigmoid normalization of the trust scores. // Consensus will have shape k, a score for each subnet. - api.debug(&format!("T:\n{:?}\n", &trust)); + api.debug(&format!("🔵 trust_n: {:?}\n", &trust)); let one = I64F64::from_num(1); let mut consensus = vec![I64F64::from_num(0); total_networks as usize]; for (idx, trust_score) in trust.iter_mut().enumerate() { @@ -392,28 +391,28 @@ pub fn root_epoch( consensus[idx] = one / (one + exponentiated_trust); } - api.debug(&format!("C:\n{:?}\n", &consensus)); + api.debug(&format!("🔵 consensus: {:?}\n", &consensus)); let mut weighted_emission = vec![I64F64::from_num(0); total_networks as usize]; for (idx, emission) in weighted_emission.iter_mut().enumerate() { *emission = consensus[idx] * ranks[idx]; } inplace_normalize_64(&mut weighted_emission); - api.debug(&format!("Ei64:\n{:?}\n", &weighted_emission)); + api.debug(&format!("🔵 emission_w: {:?}\n", &weighted_emission)); // -- 11. Converts the normalized 64-bit fixed point rank values to u64 for the final emission calculation. - let emission_as_tao: Vec = weighted_emission + let emission_as_boot: Vec = weighted_emission .iter() .map(|v: &I64F64| *v * block_emission) .collect(); // --- 12. Converts the normalized 64-bit fixed point rank values to u64 for the final emission calculation. - let emission_u64: Vec = vec_fixed64_to_u64(emission_as_tao); - api.debug(&format!("Eu64:\n{:?}\n", &emission_u64)); + let emission_u64: Vec = vec_fixed64_to_u64(emission_as_boot); + api.debug(&format!("🔵 emission_f: {:?}\n", &emission_u64)); // --- 13. Set the emission values for each subnet directly. let netuids: Vec = get_all_subnet_netuids(store); api.debug(&format!( - "netuids: {:?} values: {:?}", + "🔵 netuids: {:?}, values: {:?}", netuids, emission_u64 )); @@ -453,7 +452,7 @@ pub fn do_root_register( // --- 1. Ensure that the call originates from a signed source and retrieve the caller's account ID (coldkey). let coldkey = info.sender; deps.api.debug(&format!( - "do_root_register( coldkey: {:?}, hotkey: {:?} )", + "🔵 do_root_register ( coldkey: {:?}, hotkey: {:?} )", coldkey, hotkey.clone() )); @@ -502,7 +501,7 @@ pub fn do_root_register( current_block_number, )?; deps.api.debug(&format!( - "add new neuron: {:?} on uid {:?}", + "🔵 add new neuron: {:?} on uid {:?}", hotkey, subnetwork_uid )); } else { @@ -535,7 +534,7 @@ pub fn do_root_register( // --- 13.1.3 The new account has a higher stake than the one being replaced. // Replace the neuron account with new information. - replace_neuron( + let _msgs = replace_neuron( deps.storage, deps.api, root_netuid, @@ -545,7 +544,7 @@ pub fn do_root_register( )?; deps.api.debug(&format!( - "replace neuron: {:?} with {:?} on uid {:?}", + "🔵 replace neuron: {:?} with {:?} on uid {:?}", replaced_hotkey, hotkey, subnetwork_uid )); } @@ -594,7 +593,7 @@ pub fn do_root_register( // --- 15. Log and announce the successful registration. deps.api.debug(&format!( - "RootRegistered(netuid:{:?} uid:{:?} hotkey:{:?})", + "🔵 RootRegistered (netuid:{:?} uid:{:?} hotkey:{:?})", root_netuid, subnetwork_uid, hotkey )); @@ -640,30 +639,18 @@ pub fn user_add_network( // --- 2. Calculate and lock the required tokens. let lock_amount: u64 = get_network_lock_cost(deps.storage, deps.api, env.block.height)?; - // TODO revisit this - // let lock_as_balance = u64_to_balance(lock_amount); - // let lock_as_balance = 0; deps.api - .debug(&format!("network lock_amount: {:?}", lock_amount)); + .debug(&format!("🔵 network lock_amount: {:?}", lock_amount)); ensure!( amount.u128() as u64 >= lock_amount, ContractError::NotEnoughTokens {} ); - // ensure!( - // lock_as_balance.is_some(), - // Error::::CouldNotConvertToBalance - // ); - // ensure!( - // can_remove_balance_from_coldkey_account(&coldkey, lock_as_balance), - // ContractError::NotEnoughBalanceToStake {} - // ); - // --- 4. Determine the netuid to register. let netuid_to_register: u16 = { deps.api.debug(&format!( - "subnet count: {:?}\nmax subnets: {:?}", + "🔵 subnet count: {:?}\nmax subnets: {:?}", get_num_subnets(deps.storage), get_max_subnets(deps.storage) )); @@ -680,7 +667,7 @@ pub fn user_add_network( } } else { let netuid_to_prune = get_subnet_to_prune(deps.storage, env.block.height)?; - // ensure!(netuid_to_prune > 0, Error::::AllNetworksInImmunity); + ensure!(netuid_to_prune > 0, ContractError::AllNetworksInImmunity {}); remove_network(deps.storage, netuid_to_prune)?; deps.api @@ -690,10 +677,6 @@ pub fn user_add_network( }; // --- 5. Perform the lock operation. - // ensure!( - // remove_balance_from_coldkey_account(&coldkey, lock_as_balance) == true, - // ContractError::BalanceWithdrawalError {} - // ); set_subnet_locked_balance(deps.storage, netuid_to_register, lock_amount); set_network_last_lock(deps.storage, lock_amount); @@ -710,7 +693,7 @@ pub fn user_add_network( // --- 8. Emit the NetworkAdded event. deps.api.debug(&format!( - "NetworkAdded( netuid:{:?}, modality:{:?} )", + "🔵 NetworkAdded ( netuid:{:?}, modality:{:?} )", netuid_to_register, 0 )); @@ -735,7 +718,7 @@ pub fn user_add_network( // pub fn user_remove_network( deps: DepsMut, - env: Env, + _env: Env, info: MessageInfo, netuid: u16, ) -> Result { @@ -759,7 +742,7 @@ pub fn user_remove_network( // --- 5. Emit the NetworkRemoved event. deps.api - .debug(&format!("NetworkRemoved( netuid:{:?} )", netuid)); + .debug(&format!("🔵 NetworkRemoved ( netuid:{:?} )", netuid)); // --- 6. Return success. Ok(Response::default() @@ -801,7 +784,6 @@ pub fn init_new_network( TARGET_REGISTRATIONS_PER_INTERVAL.save(store, netuid, &1)?; ADJUSTMENTS_ALPHA.save(store, netuid, &58000)?; IMMUNITY_PERIOD.save(store, netuid, &7200)?; - MIN_BURN.save(store, netuid, &1)?; DIFFICULTY.save(store, netuid, &10_000_000)?; MIN_DIFFICULTY.save(store, netuid, &10_000_000)?; @@ -826,9 +808,11 @@ pub fn init_new_network( BONDS_MOVING_AVERAGE.save(store, netuid, &900_000)?; LAST_ADJUSTMENT_BLOCK.save(store, netuid, &0)?; ADJUSTMENT_INTERVAL.save(store, netuid, &100)?; - BURN.save(store, netuid, &0)?; - // MIN_BURN.save(store, netuid,&0)?; - MAX_BURN.save(store, netuid, &1_000_000_000)?; + + BURN.save(store, netuid, &1_000_000_000)?; + MIN_BURN.save(store, netuid, &100_000_000)?; + MAX_BURN.save(store, netuid, &100_000_000_000)?; + REGISTRATIONS_THIS_BLOCK.save(store, netuid, &0)?; // MAX_REGISTRATION_PER_BLOCK.save(store, netuid, &3)?; KAPPA.save(store, netuid, &32_767)?; @@ -837,7 +821,11 @@ pub fn init_new_network( SERVING_RATE_LIMIT.save(store, netuid, &50)?; ADJUSTMENTS_ALPHA.save(store, netuid, &0)?; LAST_UPDATE.save(store, netuid, &vec![])?; - SCALING_LAW_POWER.save(store, netuid, &50)?; + METADATA.save( + store, + netuid, + &"Qmd2anGbDQj7pYWMZwv9SEw11QFLQu3nzoGXfi1KwLy3Zr".to_string(), + )?; Ok(()) } @@ -857,16 +845,8 @@ pub fn init_new_network( // pub fn remove_network(store: &mut dyn Storage, netuid: u16) -> Result<(), ContractError> { // --- 1. Return balance to subnet owner. - let owner_coldkey = get_subnet_owner(store, netuid); - let reserved_amount = get_subnet_locked_balance(store, netuid); - - // Ensure that we can convert this u64 to a balance. - // TODO revisit this - // let reserved_amount_as_bal = u64_to_balance(reserved_amount); - // if !reserved_amount_as_bal.is_some() { - // return; - // } - let reserved_amount_as_bal = 0; + // let _owner_coldkey = get_subnet_owner(store, netuid); + // let _reserved_amount = get_subnet_locked_balance(store, netuid); // --- 2. Remove network count. SUBNETWORK_N.remove(store, netuid); @@ -921,8 +901,7 @@ pub fn remove_network(store: &mut dyn Storage, netuid: u16) -> Result<(), Contra BURN_REGISTRATIONS_THIS_INTERVAL.remove(store, netuid); // --- 11. Add the balance back to the owner. - // TODO create messages send here - // add_balance_to_coldkey_account(&owner_coldkey, reserved_amount_as_bal); + // TODO create messages to send token here or burn them during creation, decide later set_subnet_locked_balance(store, netuid, 0); SUBNET_OWNER.remove(store, netuid); @@ -948,9 +927,9 @@ pub fn remove_network(store: &mut dyn Storage, netuid: u16) -> Result<(), Contra MIN_DIFFICULTY.remove(store, netuid); MAX_DIFFICULTY.remove(store, netuid); ADJUSTMENTS_ALPHA.remove(store, netuid); - SCALING_LAW_POWER.remove(store, netuid); NETWORK_REGISTRATION_ALLOWED.remove(store, netuid); TARGET_REGISTRATIONS_PER_INTERVAL.remove(store, netuid); + METADATA.remove(store, netuid); Ok(()) } @@ -994,7 +973,7 @@ pub fn get_network_lock_cost( lock_cost = min_lock; } - api.debug(&format!("last_lock: {:?}, min_lock: {:?}, last_lock_block: {:?}, lock_reduction_interval: {:?}, current_block: {:?}, mult: {:?} lock_cost: {:?}", + api.debug(&format!("🔵 last_lock: {:?}, min_lock: {:?}, last_lock_block: {:?}, lock_reduction_interval: {:?}, current_block: {:?}, mult: {:?} lock_cost: {:?}", last_lock, min_lock, last_lock_block, lock_reduction_interval, current_block, mult, lock_cost)); Ok(lock_cost) @@ -1012,7 +991,7 @@ pub fn get_subnet_to_prune(store: &dyn Storage, current_block: u64) -> Result Result emission_value { min_score_in_immunity_period = emission_value; - uid_with_min_score_in_immunity_period = netuid; + // uid_with_min_score_in_immunity_period = netuid; } } else { min_score = emission_value; @@ -1039,7 +1018,7 @@ pub fn get_subnet_to_prune(store: &dyn Storage, current_block: u64) -> Result emission_value { min_score_in_immunity_period = emission_value; - uid_with_min_score_in_immunity_period = netuid; + // uid_with_min_score_in_immunity_period = netuid; } } else { min_score = emission_value; @@ -1064,12 +1043,14 @@ pub fn get_network_immunity_period(store: &dyn Storage) -> u64 { NETWORK_IMMUNITY_PERIOD.load(store).unwrap() } +#[cfg(test)] pub fn set_network_immunity_period(store: &mut dyn Storage, net_immunity_period: u64) { NETWORK_IMMUNITY_PERIOD .save(store, &net_immunity_period) .unwrap(); } +#[cfg(test)] pub fn set_network_min_lock(store: &mut dyn Storage, net_min_lock: u64) { NETWORK_MIN_LOCK_COST.save(store, &net_min_lock).unwrap(); } @@ -1090,6 +1071,7 @@ pub fn get_network_last_lock_block(store: &dyn Storage) -> u64 { NETWORK_LAST_REGISTERED.load(store).unwrap() } +#[cfg(test)] pub fn set_lock_reduction_interval(store: &mut dyn Storage, interval: u64) { NETWORK_LOCK_REDUCTION_INTERVAL .save(store, &interval) diff --git a/src/serving.rs b/src/serving.rs index 1af04f5..668731a 100644 --- a/src/serving.rs +++ b/src/serving.rs @@ -114,8 +114,10 @@ pub fn do_serve_axon( AXONS.save(deps.storage, (netuid, &hotkey_id), &prev_axon)?; // --- 8. We deposit axon served event. - deps.api - .debug(&format!("AxonServed( hotkey:{:?} ) ", hotkey_id.clone())); + deps.api.debug(&format!( + "📡 AxonServed ( hotkey:{:?} ) ", + hotkey_id.clone() + )); // --- 9. Return is successful dispatch. Ok(Response::default() @@ -218,7 +220,7 @@ pub fn do_serve_prometheus( // --- 9. We deposit prometheus served event. deps.api.debug(&format!( - "PrometheusServed( hotkey:{:?} ) ", + "📡 PrometheusServed ( hotkey:{:?} ) ", hotkey_id.clone() )); diff --git a/src/staking.rs b/src/staking.rs index caa1e3a..77d567a 100644 --- a/src/staking.rs +++ b/src/staking.rs @@ -10,7 +10,7 @@ use crate::state::{ DELEGATES, DENOM, OWNER, STAKE, TOTAL_COLDKEY_STAKE, TOTAL_HOTKEY_STAKE, TOTAL_ISSUANCE, TOTAL_STAKE, }; -use crate::utils::{exceeds_tx_rate_limit, get_last_tx_block, set_last_tx_block}; +use crate::utils::{exceeds_tx_rate_limit, get_default_take, get_last_tx_block, set_last_tx_block}; use crate::ContractError; use cyber_std::Response; @@ -47,15 +47,14 @@ pub fn do_become_delegate( hotkey_address: String, // take: u16, ) -> Result { - // TODO set get_default_take() of custom take - let take = 11_796; + let take = get_default_take(deps.storage); // --- 1. We check the coldkey signuture. let coldkey = info.sender; let hotkey = deps.api.addr_validate(&hotkey_address)?; deps.api.debug(&format!( - "do_become_delegate( origin:{:?} hotkey:{:?}, take:{:?} )", + "🌐 do_become_delegate ( coldkey:{:?} hotkey:{:?}, take:{:?} )", coldkey, hotkey, take )); @@ -95,7 +94,7 @@ pub fn do_become_delegate( // --- 7. Emit the staking event. deps.api.debug(&format!( - "DelegateAdded( coldkey:{:?}, hotkey:{:?}, take:{:?} )", + "🌐 DelegateAdded( coldkey:{:?}, hotkey:{:?}, take:{:?} )", coldkey, hotkey.clone(), take @@ -155,23 +154,10 @@ pub fn do_add_stake( must_pay(&info, &denom).map_err(|_| ContractError::CouldNotConvertToBalance {})?; deps.api.debug(&format!( - "do_add_stake( origin:{:?} hotkey:{:?}, stake_to_be_added:{:?} )", + "🌐 do_add_stake ( coldkey:{:?}, hotkey:{:?}, stake_to_be_added:{:?} )", coldkey, hotkey, stake_to_be_added )); - // --- 2. We convert the stake u64 into a balancer. - // let stake_as_balance = u64_to_balance(stake_to_be_added); - // ensure!( - // stake_as_balance.is_some(), - // ContractError::CouldNotConvertToBalance {} - // ); - - // --- 3. Ensure the callers coldkey has enough stake to perform the transaction. - // ensure!( - // can_remove_balance_from_coldkey_account(&coldkey, stake_as_balance.unwrap()), - // ContractError::NotEnoughBalanceToStake {} - // ); - // --- 4. Ensure that the hotkey account exists this is only possible through registration. ensure!( hotkey_account_exists(deps.storage, &hotkey), @@ -194,12 +180,6 @@ pub fn do_add_stake( ContractError::TxRateLimitExceeded {} ); - // --- 7. Ensure the remove operation from the coldkey is a success. - // ensure!( - // remove_balance_from_coldkey_account(&coldkey, stake_as_balance.unwrap()) == true, - // ContractError::BalanceWithdrawalError {} - // ); - // --- 8. If we reach here, add the balance to the hotkey. increase_stake_on_coldkey_hotkey_account( deps.storage, @@ -210,7 +190,7 @@ pub fn do_add_stake( // --- 9. Emit the staking event. deps.api.debug(&format!( - "StakeAdded( hotkey:{:?}, stake_to_be_added:{:?} )", + "🌐 StakeAdded ( hotkey:{:?}, stake_to_be_added:{:?} )", hotkey.clone(), stake_to_be_added )); @@ -267,7 +247,7 @@ pub fn do_remove_stake( let hotkey = deps.api.addr_validate(&hotkey_address)?; deps.api.debug(&format!( - "do_remove_stake( origin:{:?} hotkey:{:?}, stake_to_be_removed:{:?} )", + "🌐 do_remove_stake ( coldkey:{:?}, hotkey:{:?}, stake_to_be_removed:{:?} )", coldkey, hotkey, stake_to_be_removed )); @@ -296,13 +276,6 @@ pub fn do_remove_stake( ContractError::NotEnoughStaketoWithdraw {} ); - // --- 5. Ensure that we can convert this u64 to a balance. - // let stake_to_be_added_as_currency = u64_to_balance(stake_to_be_removed); - // ensure!( - // stake_to_be_added_as_currency.is_some(), - // ContractError::CouldNotConvertToBalance {} - // ); - // --- 6. Ensure we don't exceed tx rate limit ensure!( !exceeds_tx_rate_limit( @@ -314,11 +287,9 @@ pub fn do_remove_stake( ); // --- 7. We remove the balance from the hotkey. - decrease_stake_on_coldkey_hotkey_account(deps.storage, &coldkey, &hotkey, stake_to_be_removed); - - // --- 8. We add the balancer to the coldkey. If the above fails we will not credit this coldkey. - // add_balance_to_coldkey_account(&coldkey, stake_to_be_added_as_currency.unwrap()); + decrease_stake_on_coldkey_hotkey_account(deps.storage, &coldkey, &hotkey, stake_to_be_removed)?; + // --- 8. We add the balance to the coldkey let denom = DENOM.load(deps.storage)?; let msg = CosmosMsg::Bank(BankMsg::Send { to_address: info.sender.to_string(), @@ -327,7 +298,7 @@ pub fn do_remove_stake( // --- 9. Emit the unstaking event. deps.api.debug(&format!( - "StakeRemoved( hotkey:{:?}, stake_to_be_removed:{:?} )", + "🌐 StakeRemoved ( hotkey:{:?}, stake_to_be_removed:{:?} )", hotkey, stake_to_be_removed )); @@ -352,13 +323,13 @@ pub fn delegate_hotkey(store: &mut dyn Storage, hotkey: &Addr, take: u16) { } // Returns the total amount of stake in the staking table. -// +#[cfg(test)] pub fn get_total_stake(store: &dyn Storage) -> u64 { return TOTAL_STAKE.load(store).unwrap(); } // Increases the total amount of stake by the passed amount. -// +#[cfg(test)] pub fn increase_total_stake(store: &mut dyn Storage, increment: u64) { TOTAL_STAKE .update(store, |s| -> StdResult<_> { @@ -368,7 +339,7 @@ pub fn increase_total_stake(store: &mut dyn Storage, increment: u64) { } // Decreases the total amount of stake by the passed amount. -// +#[cfg(test)] pub fn decrease_total_stake(store: &mut dyn Storage, decrement: u64) { TOTAL_STAKE .update(store, |s| -> StdResult<_> { @@ -385,7 +356,7 @@ pub fn get_total_stake_for_hotkey(store: &dyn Storage, hotkey: &Addr) -> u64 { } // Returns the total amount of stake held by the coldkey (delegative or otherwise) -// +#[cfg(test)] pub fn get_total_stake_for_coldkey(store: &dyn Storage, coldkey: &Addr) -> u64 { return TOTAL_COLDKEY_STAKE.load(store, coldkey).unwrap(); } @@ -447,10 +418,16 @@ pub fn increase_stake_on_hotkey_account(store: &mut dyn Storage, hotkey: &Addr, } // Decreases the stake on the hotkey account under its owning coldkey. -// -pub fn decrease_stake_on_hotkey_account(store: &mut dyn Storage, hotkey: &Addr, decrement: u64) { +#[cfg(test)] +pub fn decrease_stake_on_hotkey_account( + store: &mut dyn Storage, + hotkey: &Addr, + decrement: u64, +) -> Result<(), ContractError> { let coldkey = get_owning_coldkey_for_hotkey(store, hotkey); - decrease_stake_on_coldkey_hotkey_account(store, &coldkey, &hotkey, decrement); + decrease_stake_on_coldkey_hotkey_account(store, &coldkey, &hotkey, decrement)?; + + Ok(()) } // Increases the stake on the cold - hot pairing by increment while also incrementing other counters. @@ -499,93 +476,51 @@ pub fn decrease_stake_on_coldkey_hotkey_account( coldkey: &Addr, hotkey: &Addr, decrement: u64, -) { - TOTAL_COLDKEY_STAKE - .update(store, coldkey, |s| -> StdResult<_> { - let stake = s.unwrap(); - Ok(stake.saturating_sub(decrement)) - }) - .unwrap(); - TOTAL_HOTKEY_STAKE - .update(store, hotkey, |s| -> StdResult<_> { - let stake = s.unwrap(); - Ok(stake.saturating_sub(decrement)) - }) - .unwrap(); - STAKE - .update(store, (hotkey, coldkey), |s| -> StdResult<_> { - let stake = s.unwrap(); - Ok(stake.saturating_sub(decrement)) - }) - .unwrap(); - TOTAL_STAKE - .update(store, |s| -> StdResult<_> { - Ok(s.saturating_sub(decrement)) - }) - .unwrap(); - TOTAL_ISSUANCE - .update(store, |s| -> StdResult<_> { - Ok(s.saturating_sub(decrement)) - }) - .unwrap(); -} - -pub fn u64_to_balance(input: u64) -> Option { - // TODO revisit this - // input.try_into().ok() - Some(input) -} - -// TODO replace this logic -pub fn add_balance_to_coldkey_account(coldkey: &Addr, amount: u64) { - // TODO return message and then return in response - // T::Currency::deposit_creating(&coldkey, amount); // Infallibe -} - -pub fn can_remove_balance_from_coldkey_account(coldkey: &Addr, amount: u64) -> bool { - // let current_balance = get_coldkey_balance(coldkey); - // if amount > current_balance { - // return false; - // } - // - // // This bit is currently untested. @todo - // let new_potential_balance = current_balance - amount; - // let can_withdraw = T::Currency::ensure_can_withdraw( - // &coldkey, - // amount, - // WithdrawReasons::except(WithdrawReasons::TIP), - // new_potential_balance, - // ) - // .is_ok(); - // can_withdraw - true +) -> Result<(), ContractError> { + TOTAL_COLDKEY_STAKE.update(store, coldkey, |s| -> StdResult<_> { + let stake = s.unwrap(); + Ok(stake.saturating_sub(decrement)) + })?; + TOTAL_HOTKEY_STAKE.update(store, hotkey, |s| -> StdResult<_> { + let stake = s.unwrap(); + Ok(stake.saturating_sub(decrement)) + })?; + STAKE.update(store, (hotkey, coldkey), |s| -> StdResult<_> { + let stake = s.unwrap(); + Ok(stake.saturating_sub(decrement)) + })?; + TOTAL_STAKE.update(store, |s| -> StdResult<_> { + Ok(s.saturating_sub(decrement)) + })?; + TOTAL_ISSUANCE.update(store, |s| -> StdResult<_> { + Ok(s.saturating_sub(decrement)) + })?; + + Ok(()) } -pub fn get_coldkey_balance(coldkey: &Addr) -> u64 { - // return T::Currency::free_balance(&coldkey); - return 0; -} +// #[cfg(test)] +// pub fn can_remove_balance_from_coldkey_account(_coldkey: &Addr, _amount: u64) -> bool { +// true +// } -pub fn remove_balance_from_coldkey_account(coldkey: &Addr, amount: u64) -> bool { - // TODO rewrite whole logic -> account should send tokens upfront with transaction - // return match T::Currency::withdraw( - // &coldkey, - // amount, - // WithdrawReasons::except(WithdrawReasons::TIP), - // ExistenceRequirement::KeepAlive, - // ) { - // Ok(_result) => true, - // Err(_error) => false, - // }; - true -} +// #[cfg(test)] +// pub fn get_coldkey_balance(_coldkey: &Addr) -> u64 { +// return 0; +// } -pub fn unstake_all_coldkeys_from_hotkey_account(store: &mut dyn Storage, hotkey: &Addr) { - // TODO we use messages to send tokens from contract balance to coldkey - // can be issue when there are a lot of stakers on account on replacement +// #[cfg(test)] +// pub fn remove_balance_from_coldkey_account(_coldkey: &Addr, _amount: u64) -> bool { +// true +// } - // TODO return messages from here as we send token from contarct balance to coldkey +pub fn unstake_all_coldkeys_from_hotkey_account( + store: &mut dyn Storage, + hotkey: &Addr, +) -> Result, ContractError> { + // TODO can be issue when there are a lot of stakers (and messages) on account on replacement // Iterate through all coldkeys that have a stake on this hotkey account. + let mut msgs: Vec = Vec::new(); let stakes = STAKE .prefix(hotkey) @@ -597,19 +532,21 @@ pub fn unstake_all_coldkeys_from_hotkey_account(store: &mut dyn Storage, hotkey: .collect::>(); for (delegate_coldkey_i, stake_i) in stakes { - // Convert to balance and add to the coldkey account. - let stake_i_as_balance = u64_to_balance(stake_i); - if stake_i_as_balance.is_none() { - continue; // Don't unstake if we can't convert to balance. + if stake_i == 0 { + continue; } else { // Stake is successfully converted to balance. // Remove the stake from the coldkey - hotkey pairing. - decrease_stake_on_coldkey_hotkey_account(store, &delegate_coldkey_i, &hotkey, stake_i); + decrease_stake_on_coldkey_hotkey_account(store, &delegate_coldkey_i, &hotkey, stake_i)?; - // Add the balance to the coldkey account. - // TODO create messages here - // add_balance_to_coldkey_account(&delegate_coldkey_i, stake_i_as_balance.unwrap()); + let denom = DENOM.load(store)?; + msgs.push(CosmosMsg::Bank(BankMsg::Send { + to_address: delegate_coldkey_i.to_string(), + amount: coins(Uint128::from(stake_i).u128(), denom), + })); } } + + Ok(msgs) } diff --git a/src/state.rs b/src/state.rs index 923bcd2..e0d966a 100644 --- a/src/state.rs +++ b/src/state.rs @@ -115,6 +115,8 @@ pub const LAST_MECHANISM_STEP_BLOCK: Map = Map::new("last_mechanism_st pub const SUBNET_OWNER: Map = Map::new("subnet_owner"); // --- MAP (netuid ) --> subnet_locked pub const SUBNET_LOCKED: Map = Map::new("subnet_locked"); +// --- MAP (netuid ) --> metadata +pub const METADATA: Map = Map::new("metadata"); // ================================= // ==== Axon / Promo Endpoints ===== @@ -198,8 +200,6 @@ pub const BONDS_MOVING_AVERAGE: Map = Map::new("bonds_moving_average") pub const WEIGHTS_SET_RATE_LIMIT: Map = Map::new("weights_set_rate_limit"); // --- MAP ( netuid ) --> validator_prune_len pub const VALIDATOR_PRUNE_LEN: Map = Map::new("validator_prune_len"); -// --- MAP ( netuid ) --> scaling_law_power -pub const SCALING_LAW_POWER: Map = Map::new("scaling_law_power"); // --- MAP ( netuid ) --> target_registrations_this_interval // TODO update to target_regs_per_interval, check later pub const TARGET_REGISTRATIONS_PER_INTERVAL: Map = Map::new("target_regs_per_interval"); diff --git a/src/state_info.rs b/src/state_info.rs index 04a3d07..aefd261 100644 --- a/src/state_info.rs +++ b/src/state_info.rs @@ -10,16 +10,15 @@ use crate::state::{ LAST_TX_BLOCK, LAST_UPDATE, LOADED_EMISSION, MAX_ALLOWED_UIDS, MAX_ALLOWED_VALIDATORS, MAX_BURN, MAX_DIFFICULTY, MAX_REGISTRATION_PER_BLOCK, MAX_WEIGHTS_LIMIT, MIN_ALLOWED_WEIGHTS, MIN_BURN, MIN_DIFFICULTY, NETWORKS_ADDED, NETWORK_IMMUNITY_PERIOD, NETWORK_LAST_LOCK_COST, - NETWORK_LAST_REGISTERED, NETWORK_LOCK_REDUCTION_INTERVAL, NETWORK_MIN_ALLOWED_UIDS, - NETWORK_MIN_LOCK_COST, NETWORK_MODALITY, NETWORK_RATE_LIMIT, NETWORK_REGISTERED_AT, - NETWORK_REGISTRATION_ALLOWED, NEURONS_TO_PRUNE_AT_NEXT_EPOCH, OWNER, PENDING_EMISSION, - POW_REGISTRATIONS_THIS_INTERVAL, PROMETHEUS, PRUNING_SCORES, RANK, - RAO_RECYCLED_FOR_REGISTRATION, REGISTRATIONS_THIS_BLOCK, REGISTRATIONS_THIS_INTERVAL, RHO, - ROOT, SCALING_LAW_POWER, SERVING_RATE_LIMIT, STAKE, SUBNETWORK_N, SUBNET_LIMIT, SUBNET_LOCKED, - SUBNET_OWNER, SUBNET_OWNER_CUT, TARGET_REGISTRATIONS_PER_INTERVAL, TEMPO, TOTAL_COLDKEY_STAKE, - TOTAL_HOTKEY_STAKE, TOTAL_ISSUANCE, TOTAL_NETWORKS, TOTAL_STAKE, TRUST, TX_RATE_LIMIT, UIDS, - USED_WORK, VALIDATOR_PERMIT, VALIDATOR_PRUNE_LEN, VALIDATOR_TRUST, WEIGHTS, - WEIGHTS_SET_RATE_LIMIT, WEIGHTS_VERSION_KEY, + NETWORK_LAST_REGISTERED, NETWORK_LOCK_REDUCTION_INTERVAL, NETWORK_MIN_LOCK_COST, + NETWORK_MODALITY, NETWORK_RATE_LIMIT, NETWORK_REGISTERED_AT, NETWORK_REGISTRATION_ALLOWED, + NEURONS_TO_PRUNE_AT_NEXT_EPOCH, OWNER, PENDING_EMISSION, POW_REGISTRATIONS_THIS_INTERVAL, + PROMETHEUS, PRUNING_SCORES, RANK, RAO_RECYCLED_FOR_REGISTRATION, REGISTRATIONS_THIS_BLOCK, + REGISTRATIONS_THIS_INTERVAL, RHO, ROOT, SERVING_RATE_LIMIT, STAKE, SUBNETWORK_N, SUBNET_LIMIT, + SUBNET_LOCKED, SUBNET_OWNER, SUBNET_OWNER_CUT, TARGET_REGISTRATIONS_PER_INTERVAL, TEMPO, + TOTAL_COLDKEY_STAKE, TOTAL_HOTKEY_STAKE, TOTAL_ISSUANCE, TOTAL_NETWORKS, TOTAL_STAKE, TRUST, + TX_RATE_LIMIT, UIDS, USED_WORK, VALIDATOR_PERMIT, VALIDATOR_PRUNE_LEN, VALIDATOR_TRUST, + WEIGHTS, WEIGHTS_SET_RATE_LIMIT, WEIGHTS_VERSION_KEY, }; #[cw_serde] @@ -55,7 +54,6 @@ pub struct StateInfo { network_registered_at: Vec<(u16, u64)>, network_immunity_period: u64, network_last_registered: u64, - network_min_allowed_uids: u16, network_min_lock_cost: u64, network_last_lock_cost: u64, network_lock_reduction_interval: u64, @@ -91,7 +89,6 @@ pub struct StateInfo { bonds_moving_average: Vec<(u16, u64)>, weights_set_rate_limit: Vec<(u16, u64)>, validator_prune_len: Vec<(u16, u64)>, - scaling_law_power: Vec<(u16, u16)>, target_registrations_per_interval: Vec<(u16, u16)>, block_at_registration: Vec<((u16, u16), u64)>, adjustments_alpha: Vec<(u16, u64)>, @@ -212,7 +209,6 @@ pub fn get_state_info(store: &dyn Storage) -> StdResult { .unwrap(); let network_immunity_period: u64 = NETWORK_IMMUNITY_PERIOD.load(store)?; let network_last_registered: u64 = NETWORK_LAST_REGISTERED.load(store)?; - let network_min_allowed_uids: u16 = NETWORK_MIN_ALLOWED_UIDS.load(store)?; let network_min_lock_cost: u64 = NETWORK_MIN_LOCK_COST.load(store)?; let network_last_lock_cost: u64 = NETWORK_LAST_LOCK_COST.load(store)?; let network_lock_reduction_interval: u64 = NETWORK_LOCK_REDUCTION_INTERVAL.load(store)?; @@ -331,10 +327,6 @@ pub fn get_state_info(store: &dyn Storage) -> StdResult { .range(store, None, None, Order::Ascending) .collect::>>() .unwrap(); - let scaling_law_power: Vec<(u16, u16)> = SCALING_LAW_POWER - .range(store, None, None, Order::Ascending) - .collect::>>() - .unwrap(); let target_registrations_per_interval: Vec<(u16, u16)> = TARGET_REGISTRATIONS_PER_INTERVAL .range(store, None, None, Order::Ascending) .collect::>>() @@ -445,7 +437,6 @@ pub fn get_state_info(store: &dyn Storage) -> StdResult { network_registered_at, network_immunity_period, network_last_registered, - network_min_allowed_uids, network_min_lock_cost, network_last_lock_cost, network_lock_reduction_interval, @@ -480,7 +471,6 @@ pub fn get_state_info(store: &dyn Storage) -> StdResult { bonds_moving_average, weights_set_rate_limit, validator_prune_len, - scaling_law_power, target_registrations_per_interval, block_at_registration, adjustments_alpha, diff --git a/src/subnet_info.rs b/src/subnet_info.rs index 28e0b92..aa319a3 100644 --- a/src/subnet_info.rs +++ b/src/subnet_info.rs @@ -5,9 +5,9 @@ use crate::root::if_subnet_exist; use crate::state::{ ACTIVITY_CUTOFF, ADJUSTMENT_INTERVAL, BLOCKS_SINCE_LAST_STEP, BONDS_MOVING_AVERAGE, BURN, DIFFICULTY, EMISSION_VALUES, IMMUNITY_PERIOD, KAPPA, MAX_ALLOWED_UIDS, MAX_ALLOWED_VALIDATORS, - MAX_BURN, MAX_DIFFICULTY, MAX_REGISTRATION_PER_BLOCK, MAX_WEIGHTS_LIMIT, MIN_ALLOWED_WEIGHTS, - MIN_BURN, MIN_DIFFICULTY, NETWORKS_ADDED, NETWORK_MODALITY, NETWORK_REGISTRATION_ALLOWED, RHO, - SCALING_LAW_POWER, SUBNET_OWNER, TARGET_REGISTRATIONS_PER_INTERVAL, TEMPO, + MAX_BURN, MAX_DIFFICULTY, MAX_REGISTRATION_PER_BLOCK, MAX_WEIGHTS_LIMIT, METADATA, + MIN_ALLOWED_WEIGHTS, MIN_BURN, MIN_DIFFICULTY, NETWORKS_ADDED, NETWORK_MODALITY, + NETWORK_REGISTRATION_ALLOWED, RHO, SUBNET_OWNER, TARGET_REGISTRATIONS_PER_INTERVAL, TEMPO, WEIGHTS_SET_RATE_LIMIT, WEIGHTS_VERSION_KEY, }; use crate::uids::get_subnetwork_n; @@ -22,16 +22,15 @@ pub struct SubnetInfo { pub max_allowed_validators: u16, pub min_allowed_weights: u16, pub max_weights_limit: u16, - pub scaling_law_power: u16, pub subnetwork_n: u16, pub max_allowed_uids: u16, pub blocks_since_last_step: u64, pub tempo: u16, pub network_modality: u16, - pub network_connect: Vec<[u16; 2]>, pub emission_values: u64, pub burn: u64, pub owner: Addr, + pub metadata: String, } #[cw_serde] @@ -68,7 +67,6 @@ pub fn get_subnet_info(deps: Deps, netuid: u16) -> StdResult> let max_allowed_validators = MAX_ALLOWED_VALIDATORS.load(deps.storage, netuid)?; let min_allowed_weights = MIN_ALLOWED_WEIGHTS.load(deps.storage, netuid)?; let max_weights_limit = MAX_WEIGHTS_LIMIT.load(deps.storage, netuid)?; - let scaling_law_power = SCALING_LAW_POWER.load(deps.storage, netuid)?; let subnetwork_n = get_subnetwork_n(deps.storage, netuid); let max_allowed_uids = MAX_ALLOWED_UIDS.load(deps.storage, netuid)?; let blocks_since_last_step = BLOCKS_SINCE_LAST_STEP.load(deps.storage, netuid)?; @@ -77,14 +75,7 @@ pub fn get_subnet_info(deps: Deps, netuid: u16) -> StdResult> let emission_values = EMISSION_VALUES.load(deps.storage, netuid)?; let burn = BURN.load(deps.storage, netuid)?; let owner = SUBNET_OWNER.load(deps.storage, netuid)?; - // TODO update - // let owner = SUBNET_OWNER.load(deps.storage, netuid).map_err(|_| return Ok(None))?; - - // DEPRECATED - let network_connect: Vec<[u16; 2]> = Vec::<[u16; 2]>::new(); - // DEPRECATED for ( _netuid_, con_req) in < NetworkConnect as IterableStorageDoubleMap >::iter_prefix(netuid) { - // network_connect.push([_netuid_, con_req]); - // } + let metadata = METADATA.load(deps.storage, netuid)?; return Ok(Some(SubnetInfo { rho: rho.into(), @@ -95,16 +86,15 @@ pub fn get_subnet_info(deps: Deps, netuid: u16) -> StdResult> max_allowed_validators: max_allowed_validators.into(), min_allowed_weights: min_allowed_weights.into(), max_weights_limit: max_weights_limit.into(), - scaling_law_power: scaling_law_power.into(), subnetwork_n: subnetwork_n.into(), max_allowed_uids: max_allowed_uids.into(), blocks_since_last_step: blocks_since_last_step.into(), tempo: tempo.into(), network_modality: network_modality.into(), - network_connect, emission_values: emission_values.into(), burn, owner: owner.into(), + metadata: metadata.into(), })); } diff --git a/src/test_helpers.rs b/src/test_helpers.rs index eb77632..3bf9677 100644 --- a/src/test_helpers.rs +++ b/src/test_helpers.rs @@ -3,20 +3,20 @@ use std::fs::File; use std::io::Write; use cosmwasm_std::testing::{mock_env, mock_info, MockApi, MockQuerier}; -use cosmwasm_std::{Addr, Coin, DepsMut, Empty, Env, MemoryStorage, OwnedDeps, Storage}; -use cw_multi_test::{App, AppBuilder, BasicAppBuilder, Contract, ContractWrapper, Executor}; +use cosmwasm_std::{coin, Addr, Coin, DepsMut, Empty, Env, OwnedDeps, Storage}; +use cw_multi_test::{Contract, ContractWrapper, Executor}; use cw_storage_gas_meter::MemoryStorageWithGas; use cyber_std::CyberMsgWrapper; use cyber_std::Response; -use cyber_std_test::{CyberApp, CyberAppWrapped, CyberModule}; +use cyber_std_test::CyberApp; use crate::contract::{execute, instantiate, query}; use crate::msg::ExecuteMsg; use crate::registration::create_work_for_block_number; -use crate::root::init_new_network; +use crate::root::{get_network_lock_cost, init_new_network}; use crate::utils::{ - get_difficulty_as_u64, set_difficulty, set_network_registration_allowed, + get_burn_as_u64, get_difficulty_as_u64, set_difficulty, set_network_registration_allowed, set_weights_set_rate_limit, }; use crate::ContractError; @@ -108,47 +108,47 @@ pub fn instantiate_contract() -> (TestDeps, Env) { (deps, env) } -pub fn instantiate_contract_app(app: &mut CyberApp) -> Addr { - // TODO fix this - let cn_id = app.store_code(cn_contract()); - let msg = crate::msg::InstantiateMsg {}; - - app.instantiate_contract( - cn_id, - Addr::unchecked(ROOT.to_string()), - &msg, - &[], - "cybernet", - None, - ) - .unwrap() -} - -pub fn register_ok_neuron_app( - app: &mut CyberApp, - netuid: u16, - hotkey: &str, - coldkey: String, - nonce: u64, -) { - let msg = ExecuteMsg::Register { - netuid, - block_number: app.block_info().height, - nonce, - work: vec![], - hotkey: hotkey.to_string(), - coldkey, - }; - - let res = app.execute_contract( - Addr::unchecked(hotkey), - Addr::unchecked(CT_ADDR.to_string()), - &msg, - &[], - ); - // app.update_block(|block| block.height += 100); - assert_eq!(res.is_ok(), true); -} +// pub fn instantiate_contract_app(app: &mut CyberApp) -> Addr { +// // TODO fix this +// let cn_id = app.store_code(cn_contract()); +// let msg = crate::msg::InstantiateMsg {}; +// +// app.instantiate_contract( +// cn_id, +// Addr::unchecked(ROOT.to_string()), +// &msg, +// &[], +// "cybernet", +// None, +// ) +// .unwrap() +// } + +// pub fn register_ok_neuron_app( +// app: &mut CyberApp, +// netuid: u16, +// hotkey: &str, +// coldkey: String, +// nonce: u64, +// ) { +// let msg = ExecuteMsg::Register { +// netuid, +// block_number: app.block_info().height, +// nonce, +// work: vec![], +// hotkey: hotkey.to_string(), +// coldkey, +// }; +// +// let res = app.execute_contract( +// Addr::unchecked(hotkey), +// Addr::unchecked(CT_ADDR.to_string()), +// &msg, +// &[], +// ); +// // app.update_block(|block| block.height += 100); +// assert_eq!(res.is_ok(), true); +// } pub fn register_ok_neuron( deps: DepsMut, @@ -205,17 +205,16 @@ pub fn pow_register_ok_neuron( result } -pub fn sudo_register_ok_neuron(deps: DepsMut, env: Env, netuid: u16, hotkey: &str, coldkey: &str) { +pub fn sudo_register_ok_neuron(deps: DepsMut, _env: Env, netuid: u16, hotkey: &str, coldkey: &str) { let msg = ExecuteMsg::SudoRegister { netuid, hotkey: hotkey.to_string(), coldkey: coldkey.to_string(), - stake: 300, - balance: 300, }; + // TODO stake as funds let env = mock_env(); - let info = mock_info(&ROOT, &[]); + let info = mock_info(&ROOT, &[coin(1, "boot".to_string())]); let res = execute(deps, env, info, msg); assert_eq!(res.is_ok(), true); } @@ -248,7 +247,12 @@ pub fn burned_register_ok_neuron( hotkey: hotkey.to_string(), }; - let info = mock_info(coldkey, &[]); + let mut amount = get_burn_as_u64(deps.storage, netuid); + // need to send at least 1 boot + if amount == 0 { + amount = 1; + } + let info = mock_info(coldkey, &[coin(amount as u128, "boot".to_string())]); let result = execute(deps, env, info, msg); result @@ -263,39 +267,40 @@ pub fn add_stake( ) -> Result { let msg = ExecuteMsg::AddStake { hotkey: hotkey.to_string(), - amount_staked: amount, + // amount_staked: amount, }; // TODO Add funds here - let info = mock_info(coldkey, &[]); + let info = mock_info(coldkey, &[coin(amount as u128, "boot".to_string())]); let result = execute(deps, env, info, msg); result } pub fn register_network(deps: DepsMut, env: Env, key: &str) -> Result { + let amount = get_network_lock_cost(deps.storage, deps.api, env.block.height).unwrap(); let msg = ExecuteMsg::RegisterNetwork {}; - let info = mock_info(key, &[]); + let info = mock_info(key, &[coin(amount as u128, "boot".to_string())]); let result = execute(deps, env, info, msg); result } -pub fn add_network_app(app: &mut CyberApp) -> u16 { - let msg = ExecuteMsg::RegisterNetwork {}; - - let res = app - .execute_contract( - Addr::unchecked(ROOT.to_string()), - Addr::unchecked(CT_ADDR.to_string()), - &msg, - &[], - ) - .unwrap(); - // let attrs = res.custom_attrs(res.events.len() - 1); - return res.custom_attrs(1)[1].value.parse().unwrap(); -} +// pub fn add_network_app(app: &mut CyberApp) -> u16 { +// let msg = ExecuteMsg::RegisterNetwork {}; +// +// let res = app +// .execute_contract( +// Addr::unchecked(ROOT.to_string()), +// Addr::unchecked(CT_ADDR.to_string()), +// &msg, +// &[], +// ) +// .unwrap(); +// // let attrs = res.custom_attrs(res.events.len() - 1); +// return res.custom_attrs(1)[1].value.parse().unwrap(); +// } pub fn add_network(store: &mut dyn Storage, netuid: u16, tempo: u16, _modality: u16) { init_new_network(store, netuid, tempo).unwrap(); @@ -306,7 +311,7 @@ pub fn add_network(store: &mut dyn Storage, netuid: u16, tempo: u16, _modality: } // TODO revisit block increasing logic before or after step -pub fn step_block(mut deps: DepsMut, mut env: &mut Env) -> Result { +pub fn step_block(mut deps: DepsMut, env: &mut Env) -> Result { env.block.height += 1; let result = execute( deps.branch(), @@ -331,7 +336,7 @@ pub fn step_block(mut deps: DepsMut, mut env: &mut Env) -> Result Result { while env.block.height < block_number { @@ -447,13 +452,13 @@ pub fn print_state(app: &mut CyberApp, cn_addr: &Addr) { file.write(data.as_bytes()).unwrap(); } -#[test] -fn test_instantiate() { - let mut app = mock_app(&[]); - - let cn_addr = instantiate_contract_app(&mut app); - assert_eq!(cn_addr, Addr::unchecked("contract0")); -} +// #[test] +// fn test_instantiate() { +// let mut app = mock_app(&[]); +// +// let cn_addr = instantiate_contract_app(&mut app); +// assert_eq!(cn_addr, Addr::unchecked("contract0")); +// } #[test] fn test_deps() { @@ -467,3 +472,6 @@ fn test_deps() { let after = get_difficulty_as_u64(&deps.storage, 1); assert_eq!(after, 1); } + +#[cfg(test)] +pub fn add_balance_to_coldkey_account(_coldkey: &Addr, _amount: u64) {} diff --git a/src/tests/block_step.rs b/src/tests/block_step.rs index 124e942..4f9e8fd 100644 --- a/src/tests/block_step.rs +++ b/src/tests/block_step.rs @@ -1,22 +1,382 @@ -use cosmwasm_std::Addr; +use cosmwasm_std::{Addr, Order, Storage}; +use substrate_fixed::types::{I32F32, I64F64, I96F32}; use crate::block_step::{ blocks_until_next_epoch, drain_emission, generate_emission, get_loaded_emission_tuples, has_loaded_emission_tuples, tuples_to_drain_this_block, }; +use crate::epoch::{get_block_at_registration, get_bonds, get_float_kappa, get_weights}; +use crate::math::{ + fixed_proportion_to_u16, inplace_col_clip, inplace_col_max_upscale, inplace_col_normalize, + inplace_mask_diag, inplace_mask_matrix, inplace_mask_rows, inplace_mask_vector, + inplace_normalize, inplace_normalize_64, inplace_normalize_using_sum, inplace_row_normalize, + is_topk, is_zero, mat_ema, matmul, matmul_transpose, row_hadamard, row_sum, + vec_fixed64_to_fixed32, vec_fixed_proportions_to_u16, vec_max_upscale_to_u16, vecdiv, + weighted_median_col, +}; use crate::registration::create_work_for_block_number; use crate::root::set_emission_values; -use crate::staking::add_balance_to_coldkey_account; +use crate::staking::get_total_stake_for_hotkey; +use crate::state::{ + ACTIVE, BONDS, CONSENSUS, DIVIDENDS, EMISSION, INCENTIVE, KEYS, PRUNING_SCORES, RANK, TRUST, + VALIDATOR_PERMIT, VALIDATOR_TRUST, +}; use crate::test_helpers::{ - add_network, burned_register_ok_neuron, instantiate_contract, pow_register_ok_neuron, - step_block, sudo_register_ok_neuron, + add_balance_to_coldkey_account, add_network, burned_register_ok_neuron, instantiate_contract, + pow_register_ok_neuron, step_block, sudo_register_ok_neuron, }; +use crate::uids::get_subnetwork_n; use crate::utils::{ - get_adjustment_interval, get_burn_as_u64, get_difficulty_as_u64, set_adjustment_alpha, - set_adjustment_interval, set_burn, set_difficulty, set_max_allowed_uids, + get_activity_cutoff, get_adjustment_interval, get_bonds_moving_average, get_burn_as_u64, + get_difficulty_as_u64, get_last_update, get_max_allowed_validators, get_validator_permit, + set_adjustment_alpha, set_adjustment_interval, set_burn, set_difficulty, set_max_allowed_uids, set_max_registrations_per_block, set_min_difficulty, set_target_registrations_per_interval, }; +// Calculates reward consensus and returns the emissions for uids/hotkeys in a given `netuid`. +// (Dense version used only for testing purposes.) +pub fn epoch_dense( + store: &mut dyn Storage, + netuid: u16, + token_emission: u64, + current_block: u64, +) -> Vec<(Addr, u64, u64)> { + // Get subnetwork size. + let n: u16 = get_subnetwork_n(store, netuid); + println!("n:\n{:?}\n", n); + + // ====================== + // == Active & updated == + // ====================== + + // Get current block. + // let current_block: u64 = env.block.height; + println!("current_block:\n{:?}\n", current_block); + + // Get activity cutoff. + let activity_cutoff: u64 = get_activity_cutoff(store, netuid) as u64; + println!("activity_cutoff:\n{:?}\n", activity_cutoff); + + // Last update vector. + let last_update: Vec = get_last_update(store, netuid); + println!("Last update:\n{:?}\n", &last_update); + + // Inactive mask. + let inactive: Vec = last_update + .iter() + .map(|updated| *updated + activity_cutoff < current_block) + .collect(); + println!("Inactive:\n{:?}\n", inactive.clone()); + + // Logical negation of inactive. + let active: Vec = inactive.iter().map(|&b| !b).collect(); + + // Block at registration vector (block when each neuron was most recently registered). + let block_at_registration: Vec = get_block_at_registration(store, netuid); + println!("Block at registration:\n{:?}\n", &block_at_registration); + + // Outdated matrix, updated_ij=True if i has last updated (weights) after j has last registered. + let outdated: Vec> = last_update + .iter() + .map(|updated| { + block_at_registration + .iter() + .map(|registered| updated <= registered) + .collect() + }) + .collect(); + println!("Outdated:\n{:?}\n", &outdated); + + // =========== + // == Stake == + // =========== + + let mut hotkeys: Vec<(u16, Addr)> = vec![]; + for item in KEYS + .prefix(netuid) + .range(store, None, None, Order::Ascending) + { + let (uid_i, hotkey) = item.unwrap(); + hotkeys.push((uid_i, hotkey)); + } + println!("hotkeys: {:?}", &hotkeys); + + // Access network stake as normalized vector. + let mut stake_64: Vec = vec![I64F64::from_num(0.0); n as usize]; + for (uid_i, hotkey) in hotkeys.iter() { + stake_64[*uid_i as usize] = I64F64::from_num(get_total_stake_for_hotkey(store, hotkey)); + } + inplace_normalize_64(&mut stake_64); + let stake: Vec = vec_fixed64_to_fixed32(stake_64); + println!("S:\n{:?}\n", &stake); + + // ======================= + // == Validator permits == + // ======================= + + // Get validator permits. + let validator_permits: Vec = get_validator_permit(store, netuid); + println!("validator_permits: {:?}", validator_permits); + + // Logical negation of validator_permits. + let validator_forbids: Vec = validator_permits.iter().map(|&b| !b).collect(); + + // Get max allowed validators. + let max_allowed_validators: u16 = get_max_allowed_validators(store, netuid); + println!("max_allowed_validators: {:?}", max_allowed_validators); + + // Get new validator permits. + let new_validator_permits: Vec = is_topk(&stake, max_allowed_validators as usize); + println!("new_validator_permits: {:?}", new_validator_permits); + + // ================== + // == Active Stake == + // ================== + + let mut active_stake: Vec = stake.clone(); + + // Remove inactive stake. + inplace_mask_vector(&inactive, &mut active_stake); + + // Remove non-validator stake. + inplace_mask_vector(&validator_forbids, &mut active_stake); + + // Normalize active stake. + inplace_normalize(&mut active_stake); + println!("S:\n{:?}\n", &active_stake); + + // ============= + // == Weights == + // ============= + + // Access network weights row unnormalized. + let mut weights: Vec> = get_weights(store, netuid); + println!("W:\n{:?}\n", &weights); + + // Mask weights that are not from permitted validators. + inplace_mask_rows(&validator_forbids, &mut weights); + println!("W (permit): {:?}", &weights); + + // Remove self-weight by masking diagonal. + inplace_mask_diag(&mut weights); + println!("W (permit+diag):\n{:?}\n", &weights); + + // Mask outdated weights: remove weights referring to deregistered neurons. + inplace_mask_matrix(&outdated, &mut weights); + println!("W (permit+diag+outdate):\n{:?}\n", &weights); + + // Normalize remaining weights. + inplace_row_normalize(&mut weights); + println!("W (mask+norm):\n{:?}\n", &weights); + + // ================================ + // == Consensus, Validator Trust == + // ================================ + + // Compute preranks: r_j = SUM(i) w_ij * s_i + let preranks: Vec = matmul(&weights, &active_stake); + + // Clip weights at majority consensus + let kappa: I32F32 = get_float_kappa(store, netuid); // consensus majority ratio, e.g. 51%. + let consensus: Vec = weighted_median_col(&active_stake, &weights, kappa); + inplace_col_clip(&mut weights, &consensus); + let validator_trust: Vec = row_sum(&weights); + + // ==================================== + // == Ranks, Server Trust, Incentive == + // ==================================== + + // Compute ranks: r_j = SUM(i) w_ij * s_i + let mut ranks: Vec = matmul(&weights, &active_stake); + + // Compute server trust: ratio of rank after vs. rank before. + let trust: Vec = vecdiv(&ranks, &preranks); + + inplace_normalize(&mut ranks); + let incentive: Vec = ranks.clone(); + println!("I:\n{:?}\n", &incentive); + + // ========================= + // == Bonds and Dividends == + // ========================= + + // Access network bonds. + let mut bonds: Vec> = get_bonds(store, netuid); + inplace_mask_matrix(&outdated, &mut bonds); // mask outdated bonds + inplace_col_normalize(&mut bonds); // sum_i b_ij = 1 + println!("B:\n{:?}\n", &bonds); + + // Compute bonds delta column normalized. + let mut bonds_delta: Vec> = row_hadamard(&weights, &active_stake); // ΔB = W◦S + inplace_col_normalize(&mut bonds_delta); // sum_i b_ij = 1 + println!("ΔB:\n{:?}\n", &bonds_delta); + + // Compute bonds moving average. + let bonds_moving_average: I64F64 = + I64F64::from_num(get_bonds_moving_average(store, netuid)) / I64F64::from_num(1_000_000); + let alpha: I32F32 = I32F32::from_num(1) - I32F32::from_num(bonds_moving_average); + let mut ema_bonds: Vec> = mat_ema(&bonds_delta, &bonds, alpha); + inplace_col_normalize(&mut ema_bonds); // sum_i b_ij = 1 + println!("emaB:\n{:?}\n", &ema_bonds); + + // Compute dividends: d_i = SUM(j) b_ij * inc_j + let mut dividends: Vec = matmul_transpose(&ema_bonds, &incentive); + inplace_normalize(&mut dividends); + println!("D:\n{:?}\n", ÷nds); + + // ================================= + // == Emission and Pruning scores == + // ================================= + + // Compute emission scores. + + // Compute normalized emission scores. range: I32F32(0, 1) + // Compute normalized emission scores. range: I32F32(0, 1) + let combined_emission: Vec = incentive + .iter() + .zip(dividends.clone()) + .map(|(ii, di)| ii + di) + .collect(); + let emission_sum: I32F32 = combined_emission.iter().sum(); + + let mut normalized_server_emission: Vec = incentive.clone(); // Servers get incentive. + let mut normalized_validator_emission: Vec = dividends.clone(); // Validators get dividends. + let mut normalized_combined_emission: Vec = combined_emission.clone(); + // Normalize on the sum of incentive + dividends. + inplace_normalize_using_sum(&mut normalized_server_emission, emission_sum); + inplace_normalize_using_sum(&mut normalized_validator_emission, emission_sum); + inplace_normalize(&mut normalized_combined_emission); + + // If emission is zero, replace emission with normalized stake. + if emission_sum == I32F32::from(0) { + // no weights set | outdated weights | self_weights + if is_zero(&active_stake) { + // no active stake + normalized_validator_emission = stake.clone(); // do not mask inactive, assumes stake is normalized + normalized_combined_emission = stake.clone(); + } else { + normalized_validator_emission = active_stake.clone(); // emission proportional to inactive-masked normalized stake + normalized_combined_emission = active_stake.clone(); + } + } + + // Compute rao based emission scores. range: I96F32(0, rao_emission) + let float_token_emission: I96F32 = I96F32::from_num(token_emission); + + let server_emission: Vec = normalized_server_emission + .iter() + .map(|se: &I32F32| I96F32::from_num(*se) * float_token_emission) + .collect(); + let server_emission: Vec = server_emission + .iter() + .map(|e: &I96F32| e.to_num::()) + .collect(); + + let validator_emission: Vec = normalized_validator_emission + .iter() + .map(|ve: &I32F32| I96F32::from_num(*ve) * float_token_emission) + .collect(); + let validator_emission: Vec = validator_emission + .iter() + .map(|e: &I96F32| e.to_num::()) + .collect(); + + // Used only to track combined emission in the storage. + let combined_emission: Vec = normalized_combined_emission + .iter() + .map(|ce: &I32F32| I96F32::from_num(*ce) * float_token_emission) + .collect(); + let combined_emission: Vec = combined_emission + .iter() + .map(|e: &I96F32| e.to_num::()) + .collect(); + + // api.debug(&format!( "nSE: {:?}", &normalized_server_emission )); + println!("SE: {:?}", &server_emission); + // api.debug(&format!( "nVE: {:?}", &normalized_validator_emission )); + println!("VE: {:?}", &validator_emission); + // api.debug(&format!( "nCE: {:?}", &normalized_combined_emission )); + println!("CE: {:?}", &combined_emission); + + // Set pruning scores using combined emission scores. + let pruning_scores: Vec = normalized_combined_emission.clone(); + println!("P: {:?}", &pruning_scores); + + // =================== + // == Value storage == + // =================== + let cloned_emission: Vec = combined_emission.clone(); + let cloned_ranks: Vec = ranks + .iter() + .map(|xi| fixed_proportion_to_u16(*xi)) + .collect::>(); + let cloned_trust: Vec = trust + .iter() + .map(|xi| fixed_proportion_to_u16(*xi)) + .collect::>(); + let cloned_consensus: Vec = consensus + .iter() + .map(|xi| fixed_proportion_to_u16(*xi)) + .collect::>(); + let cloned_incentive: Vec = incentive + .iter() + .map(|xi| fixed_proportion_to_u16(*xi)) + .collect::>(); + let cloned_dividends: Vec = dividends + .iter() + .map(|xi| fixed_proportion_to_u16(*xi)) + .collect::>(); + let cloned_pruning_scores: Vec = vec_max_upscale_to_u16(&pruning_scores); + let cloned_validator_trust: Vec = validator_trust + .iter() + .map(|xi| fixed_proportion_to_u16(*xi)) + .collect::>(); + + ACTIVE.save(store, netuid, &active).unwrap(); + EMISSION.save(store, netuid, &cloned_emission).unwrap(); + RANK.save(store, netuid, &cloned_ranks).unwrap(); + TRUST.save(store, netuid, &cloned_trust).unwrap(); + CONSENSUS.save(store, netuid, &cloned_consensus).unwrap(); + INCENTIVE.save(store, netuid, &cloned_incentive).unwrap(); + DIVIDENDS.save(store, netuid, &cloned_dividends).unwrap(); + PRUNING_SCORES + .save(store, netuid, &cloned_pruning_scores) + .unwrap(); + VALIDATOR_TRUST + .save(store, netuid, &cloned_validator_trust) + .unwrap(); + VALIDATOR_PERMIT + .save(store, netuid, &new_validator_permits) + .unwrap(); + + // Column max-upscale EMA bonds for storage: max_i w_ij = 1. + inplace_col_max_upscale(&mut ema_bonds); + for i in 0..n { + // Set bonds only if uid retains validator permit, otherwise clear bonds. + if new_validator_permits[i as usize] { + let new_bonds_row: Vec<(u16, u16)> = (0..n) + .zip(vec_fixed_proportions_to_u16(ema_bonds[i as usize].clone())) + .collect(); + BONDS.save(store, (netuid, i), &new_bonds_row).unwrap(); + } else if validator_permits[i as usize] { + // Only overwrite the intersection. + let new_empty_bonds_row: Vec<(u16, u16)> = vec![]; + BONDS + .save(store, (netuid, i), &new_empty_bonds_row) + .unwrap(); + } + } + + let mut result: Vec<(Addr, u64, u64)> = vec![]; + for (uid_i, hotkey) in hotkeys.iter() { + result.push(( + hotkey.clone(), + server_emission[*uid_i as usize], + validator_emission[*uid_i as usize], + )); + } + result +} #[test] fn test_loaded_emission() { let (mut deps, mut env) = instantiate_contract(); @@ -177,7 +537,7 @@ fn test_burn_adjustment() { let netuid: u16 = 2; let tempo: u16 = 13; - let burn_cost: u64 = 1000; + let burn_cost: u64 = 1000000000; let adjustment_interval = 1; let target_registrations_per_interval = 1; add_network(&mut deps.storage, netuid, tempo, 0); @@ -230,7 +590,7 @@ fn test_burn_adjustment() { step_block(deps.as_mut(), &mut env).unwrap(); // Check the adjusted burn. - assert_eq!(get_burn_as_u64(&deps.storage, netuid), 1500); + assert_eq!(get_burn_as_u64(&deps.storage, netuid), 1500000000); } #[test] @@ -239,7 +599,7 @@ fn test_burn_adjustment_with_moving_average() { let netuid: u16 = 2; let tempo: u16 = 13; - let burn_cost: u64 = 1000; + let burn_cost: u64 = 1000000000; let adjustment_interval = 1; let target_registrations_per_interval = 1; add_network(&mut deps.storage, netuid, tempo, 0); @@ -291,7 +651,8 @@ fn test_burn_adjustment_with_moving_average() { // Check the adjusted burn. // 0.5 * 1000 + 0.5 * 1500 = 1250 - assert_eq!(get_burn_as_u64(&deps.storage, netuid), 1250); + // assert_eq!(get_burn_as_u64(&deps.storage, netuid), 1250000000); + assert_eq!(get_burn_as_u64(&deps.storage, netuid), 1250001907); } #[test] @@ -305,7 +666,7 @@ fn test_burn_adjustment_case_a() { let netuid: u16 = 2; let tempo: u16 = 13; - let burn_cost: u64 = 1000; + let burn_cost: u64 = 1000000000; let adjustment_interval = 1; let target_registrations_per_interval = 1; let start_diff: u64 = 10_000; @@ -406,7 +767,7 @@ fn test_burn_adjustment_case_b() { let netuid: u16 = 2; let tempo: u16 = 13; - let burn_cost: u64 = 1000; + let burn_cost: u64 = 1000000000; let adjustment_interval = 1; let target_registrations_per_interval = 1; let start_diff: u64 = 20_000; @@ -485,7 +846,7 @@ fn test_burn_adjustment_case_b() { // and the difficulty has not changed. let adjusted_burn = get_burn_as_u64(&deps.storage, netuid); assert!(adjusted_burn > burn_cost); - assert_eq!(adjusted_burn, 2_000); + assert_eq!(adjusted_burn, 2000000000); let adjusted_diff = get_difficulty_as_u64(&deps.storage, netuid); assert_eq!(adjusted_diff, start_diff); @@ -502,7 +863,7 @@ fn test_burn_adjustment_case_c() { let netuid: u16 = 2; let tempo: u16 = 13; - let burn_cost: u64 = 1000; + let burn_cost: u64 = 1000000000; let adjustment_interval = 1; let target_registrations_per_interval = 4; // Needs registrations < 4 to trigger let start_diff: u64 = 20_000; @@ -586,7 +947,7 @@ fn test_burn_adjustment_case_c() { // and the difficulty has not changed. let adjusted_burn = get_burn_as_u64(&deps.storage, netuid); assert!(adjusted_burn < burn_cost); - assert_eq!(adjusted_burn, 875); + assert_eq!(adjusted_burn, 875000000); let adjusted_diff = get_difficulty_as_u64(&deps.storage, netuid); assert_eq!(adjusted_diff, start_diff); @@ -699,7 +1060,7 @@ fn test_burn_adjustment_case_e() { let netuid: u16 = 2; let tempo: u16 = 13; - let burn_cost: u64 = 1000; + let burn_cost: u64 = 1000000000; let adjustment_interval = 1; let target_registrations_per_interval: u16 = 3; let start_diff: u64 = 20_000; @@ -761,7 +1122,7 @@ fn test_burn_adjustment_case_e() { // Check the adjusted BURN has DECREASED. let adjusted_burn = get_burn_as_u64(&deps.storage, netuid); assert!(adjusted_burn < burn_cost); - assert_eq!(adjusted_burn, 833); + assert_eq!(adjusted_burn, 833333333); // Check the adjusted POW difficulty has DECREASED. let adjusted_diff = get_difficulty_as_u64(&deps.storage, netuid); @@ -780,7 +1141,7 @@ fn test_burn_adjustment_case_f() { let netuid: u16 = 2; let tempo: u16 = 13; - let burn_cost: u64 = 1000; + let burn_cost: u64 = 1000000000; let adjustment_interval = 1; let target_registrations_per_interval: u16 = 1; let start_diff: u64 = 20_000; @@ -842,7 +1203,7 @@ fn test_burn_adjustment_case_f() { // Check the adjusted BURN has INCREASED. let adjusted_burn = get_burn_as_u64(&deps.storage, netuid); assert!(adjusted_burn > burn_cost); - assert_eq!(adjusted_burn, 1_500); + assert_eq!(adjusted_burn, 1_500_000_000); // Check the adjusted POW difficulty has INCREASED. let adjusted_diff = get_difficulty_as_u64(&deps.storage, netuid); @@ -863,7 +1224,7 @@ fn test_burn_adjustment_case_e_zero_registrations() { let netuid: u16 = 2; let tempo: u16 = 13; - let burn_cost: u64 = 1000; + let burn_cost: u64 = 1000000000; let adjustment_interval = 0; let target_registrations_per_interval: u16 = 1; let start_diff: u64 = 20_000; @@ -889,7 +1250,7 @@ fn test_burn_adjustment_case_e_zero_registrations() { // Check the adjusted BURN has DECREASED. let adjusted_burn = get_burn_as_u64(&deps.storage, netuid); assert!(adjusted_burn < burn_cost); - assert_eq!(adjusted_burn, 500); + assert_eq!(adjusted_burn, 500000000); // Check the adjusted POW difficulty has DECREASED. let adjusted_diff = get_difficulty_as_u64(&deps.storage, netuid); diff --git a/src/tests/epoch.rs b/src/tests/epoch.rs index 859feee..32f0217 100644 --- a/src/tests/epoch.rs +++ b/src/tests/epoch.rs @@ -1,16 +1,16 @@ use crate::contract::execute; -use crate::epoch::{epoch, epoch_dense, get_bonds}; +use crate::epoch::{epoch, get_bonds}; use crate::msg::ExecuteMsg; use crate::registration::create_work_for_block_number; use crate::root::{get_subnet_emission_value, set_emission_values}; use crate::staking::{ - add_balance_to_coldkey_account, get_total_stake, get_total_stake_for_hotkey, - increase_stake_on_coldkey_hotkey_account, + get_total_stake, get_total_stake_for_hotkey, increase_stake_on_coldkey_hotkey_account, }; use crate::test_helpers::{ - add_network, instantiate_contract, pow_register_ok_neuron, run_step_to_block, set_weights, - step_block, TestDeps, ROOT, + add_balance_to_coldkey_account, add_network, instantiate_contract, pow_register_ok_neuron, + run_step_to_block, set_weights, step_block, }; +use crate::tests::block_step::epoch_dense; use crate::uids::{append_neuron, get_hotkey_for_net_and_uid, get_subnetwork_n}; use crate::utils::{ get_activity_cutoff, get_consensus_for_uid, get_dividends_for_uid, get_emission_for_uid, @@ -21,7 +21,7 @@ use crate::utils::{ set_target_registrations_per_interval, set_weights_set_rate_limit, }; use cosmwasm_std::testing::mock_info; -use cosmwasm_std::{Addr, Api, Deps, DepsMut, Env, Storage}; +use cosmwasm_std::{Addr, Api, DepsMut, Env, Storage}; use rand::{distributions::Uniform, rngs::StdRng, seq::SliceRandom, thread_rng, Rng, SeedableRng}; use std::time::Instant; use substrate_fixed::transcendental::{cos, ln, sqrt, PI}; diff --git a/src/tests/graph.rs b/src/tests/graph.rs new file mode 100644 index 0000000..bcc9b86 --- /dev/null +++ b/src/tests/graph.rs @@ -0,0 +1,240 @@ +use crate::math::{ + col_clip_sparse, inplace_col_normalize_sparse, inplace_normalize, inplace_normalize_using_sum, + mat_ema_sparse, matmul_sparse, matmul_transpose_sparse, row_hadamard_sparse, row_sum_sparse, + vecdiv, weighted_median_col_sparse, +}; +use std::collections::HashMap; +use substrate_fixed::types::{I32F32, I64F64, I96F32}; + +pub fn find_intersection(arr1: &[i32], arr2: &[i32]) -> Vec { + let mut intersection = Vec::new(); + + for &num1 in arr1 { + for &num2 in arr2 { + if num1 == num2 { + intersection.push(num1); + break; + } + } + } + + intersection +} +pub fn cosine_similarity(a: &[i32], b: &[i32]) -> f64 { + let intersection = find_intersection(a, b); + + intersection.len() as f64 / ((a.len() * b.len()) as f64).sqrt() +} + +struct UserOutLink { + user_id: u16, + out_link: u64, +} + +// struct Pair { +// user_id: u16, +// cosim: I32F32, +// } + +#[test] +pub fn test() { + #[rustfmt::skip] + let user_out_links = vec![ + UserOutLink { user_id: 1, out_link: 1 }, + UserOutLink { user_id: 1, out_link: 2 }, + UserOutLink { user_id: 1, out_link: 3 }, + UserOutLink { user_id: 1, out_link: 4 }, + UserOutLink { user_id: 2, out_link: 3 }, + UserOutLink { user_id: 2, out_link: 5 }, + UserOutLink { user_id: 2, out_link: 6 }, + UserOutLink { user_id: 3, out_link: 6 }, + UserOutLink { user_id: 3, out_link: 1 }, + UserOutLink { user_id: 3, out_link: 5 }, + UserOutLink { user_id: 3, out_link: 2 }, + UserOutLink { user_id: 3, out_link: 7 }, + UserOutLink { user_id: 3, out_link: 8 }, + ]; + + // Create a user-outlink matrix + let mut user_out_link_matrix: HashMap> = HashMap::new(); + for uol in user_out_links { + user_out_link_matrix + .entry(uol.user_id) + .or_insert_with(Vec::new) + .push(uol.out_link as i32); + } + + let mut sparseWeightsMatrix: Vec> = vec![vec![]; 4]; + + // Compute cosine similarity between each pair of users + for (&user_id1, out_links1) in &user_out_link_matrix { + for (&user_id2, out_links2) in &user_out_link_matrix { + if user_id1 != user_id2 { + let cosim = cosine_similarity(out_links1, out_links2); + sparseWeightsMatrix[user_id1 as usize].push((user_id2, I32F32::from_num(cosim))); + + println!( + "Cosine similarity between user {} and user {}: {:.2}", + user_id1, user_id2, cosim + ); + } + } + } + + // ============= + // == Weights == + // ============= + + let n = 4u16; + + println!("Sparse Matrix: : {:?}", &sparseWeightsMatrix); + + let active_stake: Vec = vec![ + I32F32::from_num(0), + I32F32::from_num(2000u16), + I32F32::from_num(3000u16), + I32F32::from_num(4000u16), + ]; + + let mut bonds: Vec> = vec![vec![]; n as usize]; + + println!("Stake: {:?}", &active_stake); + + // ================================ + // == Consensus, Validator Trust == + // ================================ + + // Compute preranks: r_j = SUM(i) w_ij * s_i + let preranks: Vec = matmul_sparse(&sparseWeightsMatrix, &active_stake, n); + println!("Preranks: {:?}", &preranks); + + // Clip weights at majority consensus + let kappa: I32F32 = I32F32::from_num(32_767) / I32F32::from_num(u16::MAX); // consensus majority ratio, e.g. 51%. + println!("Kappa: {:?}", &kappa); + + let consensus: Vec = + weighted_median_col_sparse(&active_stake, &sparseWeightsMatrix, n, kappa); + println!("Consensus {:?}", &consensus); + + let weights: Vec> = col_clip_sparse(&sparseWeightsMatrix, &consensus); + println!("Weights: {:?}", &weights); + + let validator_trust: Vec = row_sum_sparse(&weights); + println!("Validator trust: {:?}", &validator_trust); + + // ============================= + // == Ranks, Trust, Incentive == + // ============================= + + // Compute ranks: r_j = SUM(i) w_ij * s_i. + let mut ranks: Vec = matmul_sparse(&weights, &active_stake, n); + println!("Ranks: {:?}", &ranks); + + // Compute server trust: ratio of rank after vs. rank before. + let trust: Vec = vecdiv(&ranks, &preranks); + // range: I32F32(0, 1) + println!("Trust: {:?}", &trust); + + inplace_normalize(&mut ranks); // range: I32F32(0, 1) + let incentive: Vec = ranks.clone(); + println!("Incentive: {:?}", &incentive); + + // ========================= + // == Bonds and Dividends == + // ========================= + + // Access network bonds. + // let mut bonds: Vec> = get_bonds_sparse(store, netuid); + println!("Bonds: {:?}", &bonds); + + // Compute bonds delta column normalized. + // ΔB = W◦S (outdated W masked) + let mut bonds_delta: Vec> = row_hadamard_sparse(&weights, &active_stake); + println!("ΔBonds: {:?}", &bonds_delta); + + // Normalize bonds delta. + // sum_i b_ij = 1 + inplace_col_normalize_sparse(&mut bonds_delta, n); + println!("ΔBonds (norm): {:?}", &bonds_delta); + + // Compute bonds moving average. + let bonds_moving_average: I64F64 = I64F64::from_num(900_000) / I64F64::from_num(1_000_000); + let alpha: I32F32 = I32F32::from_num(1) - I32F32::from_num(bonds_moving_average); + let mut ema_bonds: Vec> = mat_ema_sparse(&bonds_delta, &bonds, alpha); + + // Normalize EMA bonds. + // sum_i b_ij = 1 + inplace_col_normalize_sparse(&mut ema_bonds, n); + println!("EMA Bonds: {:?}", &ema_bonds); + + // Compute dividends: d_i = SUM(j) b_ij * inc_j. + // range: I32F32(0, 1) + let mut dividends: Vec = matmul_transpose_sparse(&ema_bonds, &incentive); + inplace_normalize(&mut dividends); + println!("Dividends: {:?}", ÷nds); + + // ================================= + // == Emission and Pruning scores == + // ================================= + + // TODO TODO + + // Compute normalized emission scores. range: I32F32(0, 1) + let combined_emission: Vec = incentive + .iter() + .zip(dividends.clone()) + .map(|(ii, di)| ii + di) + .collect(); + let emission_sum: I32F32 = combined_emission.iter().sum(); + + let mut normalized_server_emission: Vec = incentive.clone(); // Servers get incentive. + let mut normalized_validator_emission: Vec = dividends.clone(); // Validators get dividends. + let mut normalized_combined_emission: Vec = combined_emission.clone(); + // Normalize on the sum of incentive + dividends. + inplace_normalize_using_sum(&mut normalized_server_emission, emission_sum); + inplace_normalize_using_sum(&mut normalized_validator_emission, emission_sum); + inplace_normalize(&mut normalized_combined_emission); + + let token_emission = 1000000000u64; + // Compute rao based emission scores. range: I96F32(0, rao_emission) + let float_token_emission: I96F32 = I96F32::from_num(token_emission); + + let server_emission: Vec = normalized_server_emission + .iter() + .map(|se: &I32F32| I96F32::from_num(*se) * float_token_emission) + .collect(); + let server_emission: Vec = server_emission + .iter() + .map(|e: &I96F32| e.to_num::()) + .collect(); + + let validator_emission: Vec = normalized_validator_emission + .iter() + .map(|ve: &I32F32| I96F32::from_num(*ve) * float_token_emission) + .collect(); + let validator_emission: Vec = validator_emission + .iter() + .map(|e: &I96F32| e.to_num::()) + .collect(); + + // Only used to track emission in storage. + let combined_emission: Vec = normalized_combined_emission + .iter() + .map(|ce: &I32F32| I96F32::from_num(*ce) * float_token_emission) + .collect(); + let combined_emission: Vec = combined_emission + .iter() + .map(|e: &I96F32| e.to_num::()) + .collect(); + + println!("nSE: {:?}", &normalized_server_emission); + println!("SE: {:?}", &server_emission); + println!("nVE: {:?}", &normalized_validator_emission); + println!("VE: {:?}", &validator_emission); + println!("nCE: {:?}", &normalized_combined_emission); + println!("CE: {:?}", &combined_emission); + + // Set pruning scores using combined emission scores. + let pruning_scores: Vec = normalized_combined_emission.clone(); + println!("Psc: {:?}", &pruning_scores); +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 7e0fa33..913a971 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,6 +1,7 @@ mod block_step; mod difficulty; mod epoch; +mod graph; mod neuron_info; mod registration; mod root; diff --git a/src/tests/registration.rs b/src/tests/registration.rs index 4e265bb..88073d0 100644 --- a/src/tests/registration.rs +++ b/src/tests/registration.rs @@ -5,11 +5,11 @@ use crate::contract::execute; use crate::msg::ExecuteMsg; use crate::registration::{create_work_for_block_number, get_neuron_to_prune}; use crate::serving::get_axon_info; -use crate::staking::{add_balance_to_coldkey_account, get_owning_coldkey_for_hotkey}; +use crate::staking::get_owning_coldkey_for_hotkey; use crate::state::AxonInfoOf; use crate::test_helpers::{ - add_network, burned_register_ok_neuron, instantiate_contract, pow_register_ok_neuron, - register_ok_neuron, run_step_to_block, step_block, + add_balance_to_coldkey_account, add_network, burned_register_ok_neuron, instantiate_contract, + pow_register_ok_neuron, register_ok_neuron, run_step_to_block, step_block, }; use crate::uids::{ get_hotkey_for_net_and_uid, get_stake_for_uid_and_subnetwork, get_subnetwork_n, @@ -172,16 +172,17 @@ fn test_burned_registration_ok() { // Give it some $$$ in his coldkey balance add_balance_to_coldkey_account(&Addr::unchecked(coldkey_account_id), 10000); - let result = execute( - deps.as_mut(), - env.clone(), - mock_info(coldkey_account_id, &[]), - ExecuteMsg::BurnedRegister { + assert_eq!( + burned_register_ok_neuron( + deps.as_mut(), + env.clone(), netuid, - hotkey: hotkey_account_id.to_string(), - }, + hotkey_account_id, + coldkey_account_id, + ) + .is_ok(), + true ); - assert!(result.is_ok()); // Check if balance has decreased to pay for the burn. // assert_eq!( @@ -221,7 +222,7 @@ fn test_burn_adjustment() { let netuid: u16 = 2; let tempo: u16 = 13; - let burn_cost: u64 = 1000; + let burn_cost: u64 = 1000000000; let adjustment_interval = 1; let target_registrations_per_interval = 1; add_network(&mut deps.storage, netuid, tempo, 0); @@ -270,7 +271,7 @@ fn test_burn_adjustment() { step_block(deps.as_mut(), &mut env).unwrap(); // Check the adjusted burn. - assert_eq!(get_burn_as_u64(&deps.storage, netuid), 1500) + assert_eq!(get_burn_as_u64(&deps.storage, netuid), 1500000000) } #[test] diff --git a/src/tests/root.rs b/src/tests/root.rs index c088f63..35eda7a 100644 --- a/src/tests/root.rs +++ b/src/tests/root.rs @@ -5,25 +5,26 @@ use crate::registration::create_work_for_block_number; use crate::root::{ get_all_subnet_netuids, get_max_subnets, get_network_lock_cost, get_num_subnets, get_subnet_emission_value, if_subnet_exist, remove_network, root_epoch, - set_lock_reduction_interval, set_network_last_lock, + set_lock_reduction_interval, }; -use crate::staking::{add_balance_to_coldkey_account, hotkey_is_delegate}; +use crate::staking::hotkey_is_delegate; use crate::state_info::get_state_info; use crate::test_helpers::{ - add_network, add_stake, burned_register_ok_neuron, instantiate_contract, - pow_register_ok_neuron, register_network, root_register, set_weights, step_block, + add_balance_to_coldkey_account, add_network, add_stake, burned_register_ok_neuron, + instantiate_contract, pow_register_ok_neuron, register_network, root_register, set_weights, + step_block, }; use crate::uids::{get_subnetwork_n, get_uid_for_net_and_hotkey, is_hotkey_registered_on_network}; use crate::utils::{ - get_pending_emission, get_total_issuance, set_burn, set_difficulty, set_max_allowed_uids, - set_max_registrations_per_block, set_target_registrations_per_interval, set_tempo, - set_weights_set_rate_limit, + do_sudo_set_block_emission, get_pending_emission, get_total_issuance, set_block_emission, + set_burn, set_difficulty, set_max_allowed_uids, set_max_registrations_per_block, + set_target_registrations_per_interval, set_tempo, set_weights_set_rate_limit, }; use crate::ContractError; #[test] fn test_root_register_network_exist() { - let (mut deps, mut env) = instantiate_contract(); + let (mut deps, env) = instantiate_contract(); let hotkey_account_id = "addr1"; let coldkey_account_id = "addr667"; @@ -42,7 +43,7 @@ fn test_root_register_network_exist() { #[test] fn test_root_register_normal_on_root_fails() { - let (mut deps, mut env) = instantiate_contract(); + let (mut deps, env) = instantiate_contract(); // Test fails because normal registrations are not allowed // on the root network. @@ -89,7 +90,7 @@ fn test_root_register_normal_on_root_fails() { #[test] fn test_root_register_stake_based_pruning_works() { - let (mut deps, mut env) = instantiate_contract(); + let (mut deps, env) = instantiate_contract(); // Add two networks. let root_netuid: u16 = 0; @@ -211,6 +212,7 @@ fn test_root_register_stake_based_pruning_works() { #[test] fn test_root_set_weights() { let (mut deps, mut env) = instantiate_contract(); + set_block_emission(&mut deps.storage, 1_000_000_000); let n: usize = 10; let root_netuid: u16 = 0; @@ -357,6 +359,7 @@ fn test_root_set_weights() { #[test] fn test_root_set_weights_out_of_order_netuids() { let (mut deps, mut env) = instantiate_contract(); + set_block_emission(&mut deps.storage, 1_000_000_000); let n: usize = 10; let root_netuid: u16 = 0; @@ -539,28 +542,28 @@ fn test_root_subnet_creation_deletion() { // // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 1, lock_reduction_interval: 2, current_block: 1, mult: 2 lock_cost: 200000000000 assert_eq!( get_network_lock_cost(&deps.storage, &deps.api, env.block.height).unwrap(), - 200_000_000_000 + 20_000_000_000 ); // Doubles from previous subnet creation step_block(deps.as_mut(), &mut env).unwrap(); // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 1, lock_reduction_interval: 2, current_block: 2, mult: 2 lock_cost: 150000000000 assert_eq!( get_network_lock_cost(&deps.storage, &deps.api, env.block.height).unwrap(), - 150_000_000_000 + 15_000_000_000 ); // Reduced by 50% step_block(deps.as_mut(), &mut env).unwrap(); // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 1, lock_reduction_interval: 2, current_block: 3, mult: 2 lock_cost: 100000000000 assert_eq!( get_network_lock_cost(&deps.storage, &deps.api, env.block.height).unwrap(), - 100_000_000_000 + 10_000_000_000 ); // Reduced another 50% step_block(deps.as_mut(), &mut env).unwrap(); // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 1, lock_reduction_interval: 2, current_block: 4, mult: 2 lock_cost: 100000000000 assert_eq!( get_network_lock_cost(&deps.storage, &deps.api, env.block.height).unwrap(), - 100_000_000_000 + 10_000_000_000 ); // Reaches min value assert_eq!( register_network(deps.as_mut(), env.clone(), owner).is_ok(), @@ -569,7 +572,7 @@ fn test_root_subnet_creation_deletion() { // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 4, lock_reduction_interval: 2, current_block: 4, mult: 2 lock_cost: 200000000000 assert_eq!( get_network_lock_cost(&deps.storage, &deps.api, env.block.height).unwrap(), - 200_000_000_000 + 20_000_000_000 ); // Doubles from previous subnet creation step_block(deps.as_mut(), &mut env).unwrap(); @@ -581,7 +584,7 @@ fn test_root_subnet_creation_deletion() { // last_lock: 150000000000, min_lock: 100000000000, last_lock_block: 5, lock_reduction_interval: 2, current_block: 5, mult: 2 lock_cost: 300000000000 assert_eq!( get_network_lock_cost(&deps.storage, &deps.api, env.block.height).unwrap(), - 300_000_000_000 + 30_000_000_000 ); // Doubles from previous subnet creation step_block(deps.as_mut(), &mut env).unwrap(); @@ -593,7 +596,7 @@ fn test_root_subnet_creation_deletion() { // last_lock: 225000000000, min_lock: 100000000000, last_lock_block: 6, lock_reduction_interval: 2, current_block: 6, mult: 2 lock_cost: 450000000000 assert_eq!( get_network_lock_cost(&deps.storage, &deps.api, env.block.height).unwrap(), - 450_000_000_000 + 45_000_000_000 ); // Increasing step_block(deps.as_mut(), &mut env).unwrap(); @@ -605,7 +608,7 @@ fn test_root_subnet_creation_deletion() { // last_lock: 337500000000, min_lock: 100000000000, last_lock_block: 7, lock_reduction_interval: 2, current_block: 7, mult: 2 lock_cost: 675000000000 assert_eq!( get_network_lock_cost(&deps.storage, &deps.api, env.block.height).unwrap(), - 675_000_000_000 + 67_500_000_000 ); // Increasing. assert_eq!( register_network(deps.as_mut(), env.clone(), owner).is_ok(), @@ -614,7 +617,7 @@ fn test_root_subnet_creation_deletion() { // last_lock: 337500000000, min_lock: 100000000000, last_lock_block: 7, lock_reduction_interval: 2, current_block: 7, mult: 2 lock_cost: 675000000000 assert_eq!( get_network_lock_cost(&deps.storage, &deps.api, env.block.height).unwrap(), - 1_350_000_000_000 + 135_000_000_000 ); // Double increasing. assert_eq!( register_network(deps.as_mut(), env.clone(), owner).is_ok(), @@ -622,38 +625,39 @@ fn test_root_subnet_creation_deletion() { ); assert_eq!( get_network_lock_cost(&deps.storage, &deps.api, env.block.height).unwrap(), - 2_700_000_000_000 + 270_000_000_000 ); // Double increasing again. // Now drop it like its hot to min again. step_block(deps.as_mut(), &mut env).unwrap(); assert_eq!( get_network_lock_cost(&deps.storage, &deps.api, env.block.height).unwrap(), - 2_025_000_000_000 + 202_500_000_000 ); // 675_000_000_000 decreasing. step_block(deps.as_mut(), &mut env).unwrap(); assert_eq!( get_network_lock_cost(&deps.storage, &deps.api, env.block.height).unwrap(), - 1_350_000_000_000 + 135_000_000_000 ); // 675_000_000_000 decreasing. step_block(deps.as_mut(), &mut env).unwrap(); assert_eq!( get_network_lock_cost(&deps.storage, &deps.api, env.block.height).unwrap(), - 675_000_000_000 + 67_500_000_000 ); // 675_000_000_000 decreasing. step_block(deps.as_mut(), &mut env).unwrap(); assert_eq!( get_network_lock_cost(&deps.storage, &deps.api, env.block.height).unwrap(), - 100_000_000_000 + 10_000_000_000 ); // 675_000_000_000 decreasing with 100000000000 min } #[test] fn test_network_pruning() { let (mut deps, mut env) = instantiate_contract(); + set_block_emission(&mut deps.storage, 1_000_000_000); assert_eq!(get_total_issuance(&deps.storage), 0); diff --git a/src/tests/serving.rs b/src/tests/serving.rs index fd88bf3..6b292bb 100644 --- a/src/tests/serving.rs +++ b/src/tests/serving.rs @@ -26,7 +26,7 @@ mod test { } #[test] fn test_serving_ok() { - let (mut deps, mut env) = instantiate_contract(); + let (mut deps, env) = instantiate_contract(); let hotkey_account_id = "addr1"; let netuid: u16 = 1; @@ -77,7 +77,7 @@ fn test_serving_ok() { #[test] fn test_serving_set_metadata_update() { - let (mut deps, mut env) = instantiate_contract(); + let (mut deps, env) = instantiate_contract(); let hotkey_account_id = "addr1"; let netuid: u16 = 1; @@ -323,7 +323,7 @@ fn test_axon_invalid_port() { #[test] fn test_prometheus_serving_ok() { - let (mut deps, mut env) = instantiate_contract(); + let (mut deps, env) = instantiate_contract(); let hotkey_account_id = "addr1"; let netuid: u16 = 1; @@ -369,7 +369,7 @@ fn test_prometheus_serving_ok() { #[test] fn test_prometheus_serving_set_metadata_update() { - let (mut deps, mut env) = instantiate_contract(); + let (mut deps, env) = instantiate_contract(); let hotkey_account_id = "addr1"; let netuid: u16 = 1; diff --git a/src/tests/uids.rs b/src/tests/uids.rs index 87d5a2e..0433847 100644 --- a/src/tests/uids.rs +++ b/src/tests/uids.rs @@ -21,7 +21,7 @@ use crate::uids::{ #[test] fn test_replace_neuron() { - let (mut deps, mut env) = instantiate_contract(); + let (mut deps, env) = instantiate_contract(); let netuid: u16 = 1; let tempo: u16 = 13; @@ -60,7 +60,7 @@ fn test_replace_neuron() { .unwrap(); // Replace the neuron. - replace_neuron( + let _msgs = replace_neuron( &mut deps.storage, &deps.api, netuid, @@ -94,12 +94,12 @@ fn test_replace_neuron() { &deps.storage, &Addr::unchecked(new_hotkey_account_id), )); - assert_eq!(curr_hotkey, new_hotkey_account_id.clone()); + assert_eq!(curr_hotkey, new_hotkey_account_id); } #[test] fn test_replace_neuron_multiple_subnets() { - let (mut deps, mut env) = instantiate_contract(); + let (mut deps, env) = instantiate_contract(); let block_number: u64 = 0; let netuid: u16 = 1; @@ -125,7 +125,7 @@ fn test_replace_neuron_multiple_subnets() { netuid1, block_number, 111111 * 5, - &hotkey_account_id.clone(), + &hotkey_account_id, ); let coldkey_account_id = "addr1234"; @@ -178,7 +178,7 @@ fn test_replace_neuron_multiple_subnets() { // Replace the neuron. // Only replace on ONE network. - replace_neuron( + let _msgs = replace_neuron( &mut deps.storage, &deps.api, netuid, @@ -208,7 +208,7 @@ fn test_replace_neuron_multiple_subnets() { #[test] fn test_replace_neuron_multiple_subnets_unstake_all() { - let (mut deps, mut env) = instantiate_contract(); + let (mut deps, env) = instantiate_contract(); let block_number: u64 = 0; let netuid: u16 = 1; @@ -235,7 +235,7 @@ fn test_replace_neuron_multiple_subnets_unstake_all() { netuid1, block_number, 111111 * 5, - &hotkey_account_id.clone(), + &hotkey_account_id, ); let coldkey_account_id = "1234"; @@ -326,7 +326,7 @@ fn test_replace_neuron_multiple_subnets_unstake_all() { ); // Replace the neuron. - replace_neuron( + let _msgs = replace_neuron( &mut deps.storage, &deps.api, netuid, @@ -375,7 +375,7 @@ fn test_replace_neuron_multiple_subnets_unstake_all() { ); // replace on second network - replace_neuron( + let _msgs = replace_neuron( &mut deps.storage, &deps.api, netuid1, diff --git a/src/tests/weights.rs b/src/tests/weights.rs index 7bad9df..c09cb30 100644 --- a/src/tests/weights.rs +++ b/src/tests/weights.rs @@ -1,5 +1,5 @@ use cosmwasm_std::Addr; -use cw_multi_test::Executor; + use substrate_fixed::types::I32F32; use crate::epoch::get_weights; @@ -332,7 +332,7 @@ fn test_weights_err_has_duplicate_ids() { register_ok_neuron(deps.as_mut(), env.clone(), netuid, "addr1", "addr1", 100000).is_ok(), true ); - let neuron_uid = + let _neuron_uid = get_uid_for_net_and_hotkey(&deps.storage, netuid, &Addr::unchecked("addr1")).unwrap(); // uid 2 @@ -340,7 +340,7 @@ fn test_weights_err_has_duplicate_ids() { register_ok_neuron(deps.as_mut(), env.clone(), netuid, "addr2", "addr2", 100000).is_ok(), true ); - let neuron_uid = + let _neuron_uid = get_uid_for_net_and_hotkey(&deps.storage, netuid, &Addr::unchecked("addr2")).unwrap(); // uid 3 @@ -348,7 +348,7 @@ fn test_weights_err_has_duplicate_ids() { register_ok_neuron(deps.as_mut(), env.clone(), netuid, "addr3", "addr3", 100000).is_ok(), true ); - let neuron_uid = + let _neuron_uid = get_uid_for_net_and_hotkey(&deps.storage, netuid, &Addr::unchecked("addr3")).unwrap(); let weights_keys: Vec = vec![1, 1, 1]; // Contains duplicates @@ -457,7 +457,7 @@ fn test_set_weights_err_not_active() { .is_ok(), true ); - let neuron_uid = + let _neuron_uid = get_uid_for_net_and_hotkey(&deps.storage, netuid, &Addr::unchecked("addr666")).unwrap(); let weights_keys: Vec = vec![0]; // Uid 0 is valid. @@ -731,13 +731,13 @@ fn test_set_weights_sum_larger_than_u16_max() { #[test] fn test_check_length_allows_singleton() { - let (mut deps, env) = instantiate_contract(); + let (mut deps, _) = instantiate_contract(); let netuid = 2; let tempo: u16 = 13; add_network(&mut deps.storage, netuid, tempo, 0); - let hotkey_account = Addr::unchecked("addr1"); + let _hotkey_account = Addr::unchecked("addr1"); let max_allowed: u16 = 1; let min_allowed_weights = max_allowed; @@ -756,13 +756,13 @@ fn test_check_length_allows_singleton() { #[test] fn test_check_length_weights_length_exceeds_min_allowed() { - let (mut deps, env) = instantiate_contract(); + let (mut deps, _env) = instantiate_contract(); let netuid = 2; let tempo: u16 = 13; add_network(&mut deps.storage, netuid, tempo, 0); - let hotkey_account = Addr::unchecked("addr1"); + let _hotkey_account = Addr::unchecked("addr1"); let max_allowed: u16 = 3; let min_allowed_weights = max_allowed; @@ -863,7 +863,7 @@ fn test_normalize_weights_does_not_mutate_when_sum_not_zero() { #[test] fn test_max_weight_limited_allow_self_weights_to_exceed_max_weight_limit() { - let (mut deps, env) = instantiate_contract(); + let (mut deps, _env) = instantiate_contract(); let netuid = 2; let tempo: u16 = 13; @@ -886,7 +886,7 @@ fn test_max_weight_limited_allow_self_weights_to_exceed_max_weight_limit() { #[test] fn test_max_weight_limited_when_weight_limit_is_u16_max() { - let (mut deps, env) = instantiate_contract(); + let (mut deps, _env) = instantiate_contract(); let netuid = 2; let tempo: u16 = 13; @@ -910,7 +910,7 @@ fn test_max_weight_limited_when_weight_limit_is_u16_max() { #[test] fn test_max_weight_limited_when_max_weight_is_within_limit() { - let (mut deps, env) = instantiate_contract(); + let (mut deps, _env) = instantiate_contract(); let netuid = 2; let tempo: u16 = 13; @@ -935,7 +935,7 @@ fn test_max_weight_limited_when_max_weight_is_within_limit() { #[test] fn test_max_weight_limited_when_guard_checks_are_not_triggered() { - let (mut deps, env) = instantiate_contract(); + let (mut deps, _env) = instantiate_contract(); let netuid = 2; let tempo: u16 = 13; @@ -1019,7 +1019,7 @@ fn test_check_len_uids_within_allowed_within_network_pool() { let tempo: u16 = 13; add_network(&mut deps.storage, netuid, tempo, 0); - let max_registrations_per_block: u16 = 100; + let _max_registrations_per_block: u16 = 100; assert_eq!( register_ok_neuron(deps.as_mut(), env.clone(), netuid, "addr1", "addr1", 0).is_ok(), @@ -1055,7 +1055,7 @@ fn test_check_len_uids_within_allowed_not_within_network_pool() { let tempo: u16 = 13; add_network(&mut deps.storage, netuid, tempo, 0); - let max_registrations_per_block: u16 = 100; + let _max_registrations_per_block: u16 = 100; assert_eq!( register_ok_neuron(deps.as_mut(), env.clone(), netuid, "addr1", "addr1", 0).is_ok(), @@ -1070,7 +1070,7 @@ fn test_check_len_uids_within_allowed_not_within_network_pool() { true ); - let max_allowed = get_subnetwork_n(&deps.storage, netuid); + let _max_allowed = get_subnetwork_n(&deps.storage, netuid); let max_default_allowed = 256; // set during add_network as default let uids: Vec = Vec::from_iter((0..(max_default_allowed + 1)).map(|uid| uid)); diff --git a/src/uids.rs b/src/uids.rs index b260755..7b040ea 100644 --- a/src/uids.rs +++ b/src/uids.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Addr, Api, Order, StdError, StdResult, Storage}; +use cosmwasm_std::{Addr, Api, CosmosMsg, Order, StdError, StdResult, Storage}; use crate::staking::unstake_all_coldkeys_from_hotkey_account; use crate::state::{ @@ -21,9 +21,9 @@ pub fn replace_neuron( uid_to_replace: u16, new_hotkey: &Addr, block_number: u64, -) -> Result<(), ContractError> { +) -> Result, ContractError> { api.debug(&format!( - "replace_neuron( netuid: {:?} | uid_to_replace: {:?} | new_hotkey: {:?} ) ", + "👾 replace_neuron ( netuid: {:?} | uid_to_replace: {:?} | new_hotkey: {:?} ) ", netuid, uid_to_replace, new_hotkey.to_string() @@ -38,11 +38,12 @@ pub fn replace_neuron( KEYS.remove(store, (netuid.clone(), uid_to_replace)); // 2a. Check if the uid is registered in any other subnetworks. + let mut msgs: Vec = Vec::new(); let hotkey_is_registered_on_any_network: bool = is_hotkey_registered_on_any_network(store, &old_hotkey); if !hotkey_is_registered_on_any_network { // If not, unstake all coldkeys under this hotkey. - unstake_all_coldkeys_from_hotkey_account(store, &old_hotkey); + msgs = unstake_all_coldkeys_from_hotkey_account(store, &old_hotkey)?; } // 3. Create new set memberships. @@ -64,12 +65,7 @@ pub fn replace_neuron( )?; // Fill block at registration. IS_NETWORK_MEMBER.save(store, (&new_hotkey.clone(), netuid.clone()), &true)?; // Fill network is member. - // TODO added because original use default value - // no need because we init during account creation with not exist - // TOTAL_HOTKEY_STAKE.save(store, new_hotkey.clone(), &0u64)?; - // TOTAL_COLDKEY_STAKE.save(store, new_hotkey.clone(), &0u64)?; - - Ok(()) + Ok(msgs) } // Appends the uid to the network. @@ -82,7 +78,14 @@ pub fn append_neuron( ) -> Result<(), StdError> { // 1. Get the next uid. This is always equal to subnetwork_n. let next_uid: u16 = get_subnetwork_n(store, netuid.clone()); - // api.debug(&format!("append_neuron( netuid: {:?} | next_uid: {:?} | new_hotkey: {:?} ) ", netuid, new_hotkey.to_string(), next_uid.clone() )); + + api.debug(&format!( + "👾 append_neuron ( netuid: {:?} | next_uid: {:?} | new_hotkey: {:?} ) ", + netuid, + new_hotkey.to_string(), + next_uid.clone() + )); + // 2. Get and increase the uid count. SUBNETWORK_N.save(store, netuid.clone(), &(next_uid.clone() + 1))?; @@ -203,7 +206,7 @@ pub fn get_uid_for_net_and_hotkey( } // Returns the stake of the uid on network or 0 if it doesnt exist. -// +#[cfg(test)] pub fn get_stake_for_uid_and_subnetwork(store: &dyn Storage, netuid: u16, neuron_uid: u16) -> u64 { return if KEYS.has(store, (netuid, neuron_uid)) { let hotkey = get_hotkey_for_net_and_uid(store, netuid, neuron_uid).unwrap(); @@ -214,7 +217,7 @@ pub fn get_stake_for_uid_and_subnetwork(store: &dyn Storage, netuid: u16, neuron } // Return the total number of subnetworks available on the chain. -// +#[cfg(test)] pub fn get_number_of_subnets(store: &dyn Storage) -> u16 { let mut number_of_subnets: u16 = 0; for _ in SUBNETWORK_N.range(store, None, None, Order::Descending) { diff --git a/src/utils.rs b/src/utils.rs index 0bd21cc..f9316a1 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -10,11 +10,11 @@ use crate::state::{ EMISSION_VALUES, IMMUNITY_PERIOD, INCENTIVE, KAPPA, LAST_ADJUSTMENT_BLOCK, LAST_MECHANISM_STEP_BLOCK, LAST_TX_BLOCK, LAST_UPDATE, MAX_ALLOWED_UIDS, MAX_ALLOWED_VALIDATORS, MAX_BURN, MAX_DIFFICULTY, MAX_REGISTRATION_PER_BLOCK, - MAX_WEIGHTS_LIMIT, MIN_ALLOWED_WEIGHTS, MIN_BURN, MIN_DIFFICULTY, NETWORK_IMMUNITY_PERIOD, - NETWORK_LOCK_REDUCTION_INTERVAL, NETWORK_MIN_LOCK_COST, NETWORK_RATE_LIMIT, - NETWORK_REGISTRATION_ALLOWED, PENDING_EMISSION, POW_REGISTRATIONS_THIS_INTERVAL, - PRUNING_SCORES, RANK, RAO_RECYCLED_FOR_REGISTRATION, REGISTRATIONS_THIS_BLOCK, - REGISTRATIONS_THIS_INTERVAL, RHO, ROOT, SCALING_LAW_POWER, SERVING_RATE_LIMIT, SUBNETWORK_N, + MAX_WEIGHTS_LIMIT, METADATA, MIN_ALLOWED_WEIGHTS, MIN_BURN, MIN_DIFFICULTY, + NETWORK_IMMUNITY_PERIOD, NETWORK_LOCK_REDUCTION_INTERVAL, NETWORK_MIN_LOCK_COST, + NETWORK_RATE_LIMIT, NETWORK_REGISTRATION_ALLOWED, PENDING_EMISSION, + POW_REGISTRATIONS_THIS_INTERVAL, PRUNING_SCORES, RANK, RAO_RECYCLED_FOR_REGISTRATION, + REGISTRATIONS_THIS_BLOCK, REGISTRATIONS_THIS_INTERVAL, RHO, ROOT, SERVING_RATE_LIMIT, SUBNET_LIMIT, SUBNET_LOCKED, SUBNET_OWNER, SUBNET_OWNER_CUT, TARGET_REGISTRATIONS_PER_INTERVAL, TEMPO, TOTAL_ISSUANCE, TRUST, TX_RATE_LIMIT, VALIDATOR_PERMIT, VALIDATOR_PRUNE_LEN, VALIDATOR_TRUST, WEIGHTS_SET_RATE_LIMIT, WEIGHTS_VERSION_KEY, @@ -32,10 +32,17 @@ pub fn ensure_subnet_owner_or_root( if_subnet_exist(store, netuid), ContractError::NetworkDoesNotExist {} ); - ensure!( - SUBNET_OWNER.load(store, netuid).unwrap() == coldkey, - ContractError::Unauthorized {} - ); + + let subnet_owner = SUBNET_OWNER.load(store, netuid); + let root = ROOT.load(store)?; + if subnet_owner.is_ok() { + ensure!( + subnet_owner.unwrap() == coldkey || root == coldkey, + ContractError::Unauthorized {} + ); + } else { + ensure!(root == coldkey, ContractError::Unauthorized {}); + } Ok(()) } @@ -48,16 +55,19 @@ pub fn ensure_root(store: &dyn Storage, address: &Addr) -> Result<(), ContractEr // ======================== // ==== Global Setters ==== // ======================== +#[cfg(test)] pub fn set_tempo(store: &mut dyn Storage, netuid: u16, tempo: u16) { TEMPO.save(store, netuid, &tempo).unwrap(); } +#[cfg(test)] pub fn set_last_adjustment_block(store: &mut dyn Storage, netuid: u16, last_adjustment_block: u64) { LAST_ADJUSTMENT_BLOCK .save(store, netuid, &last_adjustment_block) .unwrap(); } +#[cfg(test)] pub fn set_blocks_since_last_step( store: &mut dyn Storage, netuid: u16, @@ -68,6 +78,7 @@ pub fn set_blocks_since_last_step( .unwrap(); } +#[cfg(test)] pub fn set_registrations_this_block( store: &mut dyn Storage, netuid: u16, @@ -78,6 +89,7 @@ pub fn set_registrations_this_block( .unwrap(); } +#[cfg(test)] pub fn set_last_mechanism_step_block( store: &mut dyn Storage, netuid: u16, @@ -88,6 +100,7 @@ pub fn set_last_mechanism_step_block( .unwrap(); } +#[cfg(test)] pub fn set_registrations_this_interval( store: &mut dyn Storage, netuid: u16, @@ -98,6 +111,7 @@ pub fn set_registrations_this_interval( .unwrap(); } +#[cfg(test)] pub fn set_pow_registrations_this_interval( store: &mut dyn Storage, netuid: u16, @@ -108,6 +122,7 @@ pub fn set_pow_registrations_this_interval( .unwrap(); } +#[cfg(test)] pub fn set_burn_registrations_this_interval( store: &mut dyn Storage, netuid: u16, @@ -121,6 +136,7 @@ pub fn set_burn_registrations_this_interval( // ======================== // ==== Global Getters ==== // ======================== +#[cfg(test)] pub fn get_total_issuance(store: &dyn Storage) -> u64 { TOTAL_ISSUANCE.load(store).unwrap() } @@ -132,10 +148,12 @@ pub fn get_block_emission(store: &dyn Storage) -> u64 { // ============================== // ==== YumaConsensus params ==== // ============================== +#[cfg(test)] pub fn get_rank(store: &dyn Storage, netuid: u16) -> Vec { RANK.load(store, netuid).unwrap() } +#[cfg(test)] pub fn get_trust(store: &dyn Storage, netuid: u16) -> Vec { TRUST.load(store, netuid).unwrap() } @@ -144,18 +162,22 @@ pub fn get_active(store: &dyn Storage, netuid: u16) -> Vec { ACTIVE.load(store, netuid).unwrap() } +#[cfg(test)] pub fn get_emission(store: &dyn Storage, netuid: u16) -> Vec { EMISSION.load(store, netuid).unwrap() } +#[cfg(test)] pub fn get_consensus(store: &dyn Storage, netuid: u16) -> Vec { CONSENSUS.load(store, netuid).unwrap() } +#[cfg(test)] pub fn get_incentive(store: &dyn Storage, netuid: u16) -> Vec { INCENTIVE.load(store, netuid).unwrap() } +#[cfg(test)] pub fn get_dividends(store: &dyn Storage, netuid: u16) -> Vec { DIVIDENDS.load(store, netuid).unwrap() } @@ -164,10 +186,12 @@ pub fn get_last_update(store: &dyn Storage, netuid: u16) -> Vec { LAST_UPDATE.load(store, netuid).unwrap() } +#[cfg(test)] pub fn get_pruning_score(store: &dyn Storage, netuid: u16) -> Vec { PRUNING_SCORES.load(store, netuid).unwrap() } +#[cfg(test)] pub fn get_validator_trust(store: &dyn Storage, netuid: u16) -> Vec { VALIDATOR_TRUST.load(store, netuid).unwrap() } @@ -199,18 +223,11 @@ pub fn set_active_for_uid(store: &mut dyn Storage, netuid: u16, uid: u16, active pub fn set_pruning_score_for_uid( store: &mut dyn Storage, - api: &dyn Api, + _api: &dyn Api, netuid: u16, uid: u16, pruning_score: u16, ) { - api.debug(&format!("netuid = {:?}", netuid)); - api.debug(&format!( - "SubnetworkN.load( netuid ) = {:?}", - SUBNETWORK_N.load(store, netuid).unwrap() - )); - api.debug(&format!("uid = {:?}", uid)); - // assert!(uid < SubnetworkN.load(netuid)); PRUNING_SCORES .update::<_, ContractError>(store, netuid, |v| { let mut v = v.unwrap(); @@ -345,10 +362,12 @@ pub fn get_emission_value(store: &dyn Storage, netuid: u16) -> u64 { EMISSION_VALUES.load(store, netuid).unwrap() } +#[cfg(test)] pub fn get_pending_emission(store: &dyn Storage, netuid: u16) -> u64 { PENDING_EMISSION.load(store, netuid).unwrap() } +#[cfg(test)] pub fn get_last_adjustment_block(store: &dyn Storage, netuid: u16) -> u64 { LAST_ADJUSTMENT_BLOCK.load(store, netuid).unwrap() } @@ -367,6 +386,7 @@ pub fn get_registrations_this_block(store: &dyn Storage, netuid: u16) -> u16 { .unwrap_or_default() } +#[cfg(test)] pub fn get_last_mechanism_step_block(store: &dyn Storage, netuid: u16) -> u64 { LAST_MECHANISM_STEP_BLOCK.load(store, netuid).unwrap() } @@ -375,10 +395,12 @@ pub fn get_registrations_this_interval(store: &dyn Storage, netuid: u16) -> u16 REGISTRATIONS_THIS_INTERVAL.load(store, netuid).unwrap() } +#[cfg(test)] pub fn get_pow_registrations_this_interval(store: &dyn Storage, netuid: u16) -> u16 { POW_REGISTRATIONS_THIS_INTERVAL.load(store, netuid).unwrap() } +#[cfg(test)] pub fn get_burn_registrations_this_interval(store: &dyn Storage, netuid: u16) -> u16 { BURN_REGISTRATIONS_THIS_INTERVAL .load(store, netuid) @@ -422,6 +444,7 @@ pub fn set_subnet_locked_balance(store: &mut dyn Storage, netuid: u16, amount: u SUBNET_LOCKED.save(store, netuid, &amount).unwrap(); } +#[cfg(test)] pub fn get_subnet_locked_balance(store: &mut dyn Storage, netuid: u16) -> u64 { SUBNET_LOCKED.load(store, netuid).unwrap() } @@ -440,7 +463,7 @@ pub fn do_sudo_set_default_take( DEFAULT_TAKE.save(deps.storage, &default_take)?; deps.api.debug(&format!( - "DefaultTakeSet( default_take: {:?} ) ", + "🛸 DefaultTakeSet ( default_take: {:?} ) ", default_take )); @@ -469,7 +492,7 @@ pub fn do_sudo_set_tx_rate_limit( TX_RATE_LIMIT.save(deps.storage, &tx_rate_limit)?; deps.api.debug(&format!( - "TxRateLimitSet( tx_rate_limit: {:?} ) ", + "🛸 TxRateLimitSet ( tx_rate_limit: {:?} ) ", tx_rate_limit )); @@ -482,6 +505,7 @@ pub fn get_serving_rate_limit(store: &dyn Storage, netuid: u16) -> u64 { SERVING_RATE_LIMIT.load(store, netuid).unwrap() } +#[cfg(test)] pub fn set_serving_rate_limit(store: &mut dyn Storage, netuid: u16, rate_limit: u64) { SERVING_RATE_LIMIT.save(store, netuid, &rate_limit).unwrap() } @@ -498,7 +522,7 @@ pub fn do_sudo_set_serving_rate_limit( SERVING_RATE_LIMIT.save(deps.storage, netuid, &serving_rate_limit)?; deps.api.debug(&format!( - "ServingRateLimitSet( serving_rate_limit: {:?} ) ", + "🛸 ServingRateLimitSet ( serving_rate_limit: {:?} ) ", serving_rate_limit )); @@ -508,10 +532,12 @@ pub fn do_sudo_set_serving_rate_limit( .add_attribute("serving_rate_limit", format!("{}", serving_rate_limit))) } +#[cfg(test)] pub fn get_min_difficulty(store: &dyn Storage, netuid: u16) -> u64 { MIN_DIFFICULTY.load(store, netuid).unwrap() } +#[cfg(test)] pub fn set_min_difficulty(store: &mut dyn Storage, netuid: u16, min_difficulty: u64) { MIN_DIFFICULTY.save(store, netuid, &min_difficulty).unwrap() } @@ -533,7 +559,7 @@ pub fn do_sudo_set_min_difficulty( MIN_DIFFICULTY.save(deps.storage, netuid, &min_difficulty)?; deps.api.debug(&format!( - "MinDifficultySet( netuid: {:?} min_difficulty: {:?} ) ", + "🛸 MinDifficultySet ( netuid: {:?} min_difficulty: {:?} ) ", netuid, min_difficulty )); @@ -543,10 +569,12 @@ pub fn do_sudo_set_min_difficulty( .add_attribute("min_diffuculty", format!("{}", min_difficulty))) } +#[cfg(test)] pub fn get_max_difficulty(store: &dyn Storage, netuid: u16) -> u64 { MAX_DIFFICULTY.load(store, netuid).unwrap() } +#[cfg(test)] pub fn set_max_difficulty(store: &mut dyn Storage, netuid: u16, max_difficulty: u64) { MAX_DIFFICULTY.save(store, netuid, &max_difficulty).unwrap() } @@ -568,7 +596,7 @@ pub fn do_sudo_set_max_difficulty( MAX_DIFFICULTY.save(deps.storage, netuid, &max_difficulty)?; deps.api.debug(&format!( - "MaxDifficultySet( netuid: {:?} max_difficulty: {:?} ) ", + "🛸 MaxDifficultySet ( netuid: {:?} max_difficulty: {:?} ) ", netuid, max_difficulty )); @@ -578,10 +606,12 @@ pub fn do_sudo_set_max_difficulty( .add_attribute("max_difficulty", format!("{}", max_difficulty))) } +#[cfg(test)] pub fn get_weights_version_key(store: &dyn Storage, netuid: u16) -> u64 { WEIGHTS_VERSION_KEY.load(store, netuid).unwrap() } +#[cfg(test)] pub fn set_weights_version_key(store: &mut dyn Storage, netuid: u16, version_key: u64) { WEIGHTS_VERSION_KEY .save(store, netuid, &version_key) @@ -597,14 +627,9 @@ pub fn do_sudo_set_weights_version_key( ) -> Result { ensure_subnet_owner_or_root(deps.storage, &info.sender, netuid)?; - ensure!( - if_subnet_exist(deps.storage, netuid), - ContractError::NetworkDoesNotExist {} - ); - WEIGHTS_VERSION_KEY.save(deps.storage, netuid, &weights_version_key)?; deps.api.debug(&format!( - "WeightsVersionKeySet( netuid: {:?} weights_version_key: {:?} ) ", + "🛸 WeightsVersionKeySet ( netuid: {:?} weights_version_key: {:?} ) ", netuid, weights_version_key )); @@ -618,6 +643,7 @@ pub fn get_weights_set_rate_limit(store: &dyn Storage, netuid: u16) -> u64 { WEIGHTS_SET_RATE_LIMIT.load(store, netuid).unwrap() } +#[cfg(test)] pub fn set_weights_set_rate_limit(store: &mut dyn Storage, netuid: u16, rate_limit: u64) { WEIGHTS_SET_RATE_LIMIT .save(store, netuid, &rate_limit) @@ -633,15 +659,10 @@ pub fn do_sudo_set_weights_set_rate_limit( ) -> Result { ensure_subnet_owner_or_root(deps.storage, &info.sender, netuid)?; - ensure!( - if_subnet_exist(deps.storage, netuid), - ContractError::NetworkDoesNotExist {} - ); - WEIGHTS_SET_RATE_LIMIT.save(deps.storage, netuid, &weights_set_rate_limit)?; deps.api.debug(&format!( - "WeightsSetRateLimitSet( netuid: {:?} weights_set_rate_limit: {:?} ) ", + "🛸 WeightsSetRateLimitSet ( netuid: {:?} weights_set_rate_limit: {:?} ) ", netuid, weights_set_rate_limit )); @@ -654,10 +675,12 @@ pub fn do_sudo_set_weights_set_rate_limit( )) } +#[cfg(test)] pub fn get_adjustment_interval(store: &dyn Storage, netuid: u16) -> u16 { ADJUSTMENT_INTERVAL.load(store, netuid).unwrap() } +#[cfg(test)] pub fn set_adjustment_interval(store: &mut dyn Storage, netuid: u16, adjustment_interval: u16) { ADJUSTMENT_INTERVAL .save(store, netuid, &adjustment_interval) @@ -681,7 +704,7 @@ pub fn do_sudo_set_adjustment_interval( ADJUSTMENT_INTERVAL.save(deps.storage, netuid, &adjustment_interval)?; deps.api.debug(&format!( - "AdjustmentIntervalSet( netuid: {:?} adjustment_interval: {:?} ) ", + "🛸 AdjustmentIntervalSet ( netuid: {:?} adjustment_interval: {:?} ) ", netuid, adjustment_interval )); @@ -691,10 +714,12 @@ pub fn do_sudo_set_adjustment_interval( .add_attribute("adjustment_interval", format!("{}", adjustment_interval))) } +#[cfg(test)] pub fn get_adjustment_alpha(store: &dyn Storage, netuid: u16) -> u64 { ADJUSTMENTS_ALPHA.load(store, netuid).unwrap() } +#[cfg(test)] pub fn set_adjustment_alpha(store: &mut dyn Storage, netuid: u16, adjustments_alpha: u64) { ADJUSTMENTS_ALPHA .save(store, netuid, &adjustments_alpha) @@ -718,7 +743,7 @@ pub fn do_sudo_set_adjustment_alpha( ADJUSTMENTS_ALPHA.save(deps.storage, netuid, &adjustment_alpha)?; deps.api.debug(&format!( - "AdjustmentAlphaSet( adjustment_alpha: {:?} ) ", + "🛸 AdjustmentAlphaSet ( adjustment_alpha: {:?} ) ", adjustment_alpha )); @@ -728,6 +753,7 @@ pub fn do_sudo_set_adjustment_alpha( .add_attribute("adjustment_alpha", format!("{}", adjustment_alpha))) } +#[cfg(test)] pub fn get_validator_prune_len(store: &dyn Storage, netuid: u16) -> u64 { VALIDATOR_PRUNE_LEN.load(store, netuid).unwrap() } @@ -749,7 +775,7 @@ pub fn do_sudo_set_validator_prune_len( VALIDATOR_PRUNE_LEN.save(deps.storage, netuid, &validator_prune_len)?; deps.api.debug(&format!( - "ValidatorPruneLenSet( netuid: {:?} validator_prune_len: {:?} ) ", + "🛸 ValidatorPruneLenSet ( netuid: {:?} validator_prune_len: {:?} ) ", netuid, validator_prune_len )); @@ -759,47 +785,11 @@ pub fn do_sudo_set_validator_prune_len( .add_attribute("validator_prune_len", format!("{}", validator_prune_len))) } -pub fn get_scaling_law_power(store: &dyn Storage, netuid: u16) -> u16 { - SCALING_LAW_POWER.load(store, netuid).unwrap() -} - -pub fn do_sudo_set_scaling_law_power( - deps: DepsMut, - _env: Env, - info: MessageInfo, - netuid: u16, - scaling_law_power: u16, -) -> Result { - ensure_root(deps.storage, &info.sender)?; - - ensure!( - if_subnet_exist(deps.storage, netuid), - ContractError::NetworkDoesNotExist {} - ); - - // The scaling law power must be between 0 and 100 => 0% and 100% - ensure!( - scaling_law_power > 100, - ContractError::StorageValueOutOfRange {} - ); - - SCALING_LAW_POWER.save(deps.storage, netuid, &scaling_law_power)?; - - deps.api.debug(&format!( - "ScalingLawPowerSet( netuid: {:?} scaling_law_power: {:?} ) ", - netuid, scaling_law_power - )); - - Ok(Response::default() - .add_attribute("active", "scaling_law_power_set") - .add_attribute("netuid", format!("{}", netuid)) - .add_attribute("scaling_law_power", format!("{}", scaling_law_power))) -} - pub fn get_max_weight_limit(store: &dyn Storage, netuid: u16) -> u16 { MAX_WEIGHTS_LIMIT.load(store, netuid).unwrap() } +#[cfg(test)] pub fn set_max_weight_limit(store: &mut dyn Storage, netuid: u16, max_weights: u16) { MAX_WEIGHTS_LIMIT.save(store, netuid, &max_weights).unwrap() } @@ -813,15 +803,10 @@ pub fn do_sudo_set_max_weight_limit( ) -> Result { ensure_subnet_owner_or_root(deps.storage, &info.sender, netuid)?; - ensure!( - if_subnet_exist(deps.storage, netuid), - ContractError::NetworkDoesNotExist {} - ); - MAX_WEIGHTS_LIMIT.save(deps.storage, netuid, &max_weight_limit)?; deps.api.debug(&format!( - "MaxWeightLimitSet( netuid: {:?} max_weight_limit: {:?} ) ", + "🛸 MaxWeightLimitSet ( netuid: {:?} max_weight_limit: {:?} ) ", netuid, max_weight_limit )); @@ -835,6 +820,7 @@ pub fn get_immunity_period(store: &dyn Storage, netuid: u16) -> u16 { IMMUNITY_PERIOD.load(store, netuid).unwrap() } +#[cfg(test)] pub fn set_immunity_period(store: &mut dyn Storage, netuid: u16, immunity_period: u16) { IMMUNITY_PERIOD .save(store, netuid, &immunity_period) @@ -850,11 +836,6 @@ pub fn do_sudo_set_immunity_period( ) -> Result { ensure_subnet_owner_or_root(deps.storage, &info.sender, netuid)?; - ensure!( - if_subnet_exist(deps.storage, netuid), - ContractError::NetworkDoesNotExist {} - ); - ensure!( immunity_period <= 7200, ContractError::StorageValueOutOfRange {} @@ -863,7 +844,7 @@ pub fn do_sudo_set_immunity_period( IMMUNITY_PERIOD.save(deps.storage, netuid, &immunity_period)?; deps.api.debug(&format!( - "ImmunityPeriodSet( netuid: {:?} immunity_period: {:?} ) ", + "🛸 ImmunityPeriodSet ( netuid: {:?} immunity_period: {:?} ) ", netuid, immunity_period )); @@ -873,10 +854,12 @@ pub fn do_sudo_set_immunity_period( .add_attribute("immunity_period", format!("{}", immunity_period))) } +#[cfg(test)] pub fn get_min_allowed_weights(store: &dyn Storage, netuid: u16) -> u16 { MIN_ALLOWED_WEIGHTS.load(store, netuid).unwrap() } +#[cfg(test)] pub fn set_min_allowed_weights(store: &mut dyn Storage, netuid: u16, min_weights: u16) { MIN_ALLOWED_WEIGHTS .save(store, netuid, &min_weights) @@ -892,15 +875,10 @@ pub fn do_sudo_set_min_allowed_weights( ) -> Result { ensure_subnet_owner_or_root(deps.storage, &info.sender, netuid)?; - ensure!( - if_subnet_exist(deps.storage, netuid), - ContractError::NetworkDoesNotExist {} - ); - MIN_ALLOWED_WEIGHTS.save(deps.storage, netuid, &min_allowed_weights)?; deps.api.debug(&format!( - "MinAllowedWeightSet( netuid: {:?} min_allowed_weights: {:?} ) ", + "🛸 MinAllowedWeightSet ( netuid: {:?} min_allowed_weights: {:?} ) ", netuid, min_allowed_weights )); @@ -914,6 +892,7 @@ pub fn get_max_allowed_uids(store: &dyn Storage, netuid: u16) -> u16 { MAX_ALLOWED_UIDS.load(store, netuid).unwrap() } +#[cfg(test)] pub fn set_max_allowed_uids(store: &mut dyn Storage, netuid: u16, max_allowed_uids: u16) { MAX_ALLOWED_UIDS .save(store, netuid, &max_allowed_uids) @@ -942,7 +921,7 @@ pub fn do_sudo_set_max_allowed_uids( MAX_ALLOWED_UIDS.save(deps.storage, netuid, &max_allowed_uids)?; deps.api.debug(&format!( - "MaxAllowedUidsSet( netuid: {:?} max_allowed_uids: {:?} ) ", + "🛸 MaxAllowedUidsSet ( netuid: {:?} max_allowed_uids: {:?} ) ", netuid, max_allowed_uids )); @@ -973,7 +952,7 @@ pub fn do_sudo_set_kappa( KAPPA.save(deps.storage, netuid, &kappa)?; deps.api.debug(&format!( - "KappaSet( netuid: {:?} kappa: {:?} ) ", + "🛸 KappaSet ( netuid: {:?} kappa: {:?} ) ", netuid, kappa )); @@ -1003,8 +982,10 @@ pub fn do_sudo_set_rho( RHO.save(deps.storage, netuid, &rho)?; - deps.api - .debug(&format!("RhoSet( netuid: {:?} rho: {:?} ) ", netuid, rho)); + deps.api.debug(&format!( + "🛸 RhoSet ( netuid: {:?} rho: {:?} ) ", + netuid, rho + )); Ok(Response::default() .add_attribute("active", "rho_set") @@ -1016,6 +997,7 @@ pub fn get_activity_cutoff(store: &dyn Storage, netuid: u16) -> u16 { ACTIVITY_CUTOFF.load(store, netuid).unwrap() } +#[cfg(test)] pub fn set_activity_cutoff(store: &mut dyn Storage, netuid: u16, activity_cutoff: u16) { ACTIVITY_CUTOFF .save(store, netuid, &activity_cutoff) @@ -1031,15 +1013,10 @@ pub fn do_sudo_set_activity_cutoff( ) -> Result { ensure_subnet_owner_or_root(deps.storage, &info.sender, netuid)?; - ensure!( - if_subnet_exist(deps.storage, netuid), - ContractError::NetworkDoesNotExist {} - ); - ACTIVITY_CUTOFF.save(deps.storage, netuid, &activity_cutoff)?; deps.api.debug(&format!( - "ActivityCutoffSet( netuid: {:?} activity_cutoff: {:?} ) ", + "🛸 ActivityCutoffSet ( netuid: {:?} activity_cutoff: {:?} ) ", netuid, activity_cutoff )); @@ -1049,10 +1026,12 @@ pub fn do_sudo_set_activity_cutoff( .add_attribute("activity_cutoff", format!("{}", activity_cutoff))) } +#[cfg(test)] pub fn get_network_registration_allowed(store: &dyn Storage, netuid: u16) -> bool { NETWORK_REGISTRATION_ALLOWED.load(store, netuid).unwrap() } +#[cfg(test)] pub fn set_network_registration_allowed( store: &mut dyn Storage, netuid: u16, @@ -1075,7 +1054,7 @@ pub fn do_sudo_set_network_registration_allowed( NETWORK_REGISTRATION_ALLOWED.save(deps.storage, netuid, ®istration_allowed)?; deps.api.debug(&format!( - "NetworkRegistrationAllowed( registration_allowed: {:?} ) ", + "🛸 NetworkRegistrationAllowed ( registration_allowed: {:?} ) ", registration_allowed )); @@ -1091,6 +1070,7 @@ pub fn get_target_registrations_per_interval(store: &dyn Storage, netuid: u16) - .unwrap() } +#[cfg(test)] pub fn set_target_registrations_per_interval( store: &mut dyn Storage, netuid: u16, @@ -1122,7 +1102,7 @@ pub fn do_sudo_set_target_registrations_per_interval( )?; deps.api.debug(&format!( - "RegistrationPerIntervalSet( netuid: {:?} target_registrations_per_interval: {:?} ) ", + "🛸 RegistrationPerIntervalSet ( netuid: {:?} target_registrations_per_interval: {:?} ) ", netuid, target_registrations_per_interval )); @@ -1139,10 +1119,12 @@ pub fn get_burn_as_u64(store: &dyn Storage, netuid: u16) -> u64 { BURN.load(store, netuid).unwrap() } +#[cfg(test)] pub fn set_burn(store: &mut dyn Storage, netuid: u16, burn: u64) { BURN.save(store, netuid, &burn).unwrap(); } +#[cfg(test)] pub fn get_min_burn_as_u64(store: &dyn Storage, netuid: u16) -> u64 { MIN_BURN.load(store, netuid).unwrap() } @@ -1164,7 +1146,7 @@ pub fn do_sudo_set_min_burn( MIN_BURN.save(deps.storage, netuid, &min_burn)?; deps.api.debug(&format!( - "MinBurnSet( netuid: {:?} min_burn: {:?} ) ", + "🛸 MinBurnSet ( netuid: {:?} min_burn: {:?} ) ", netuid, min_burn )); @@ -1174,6 +1156,7 @@ pub fn do_sudo_set_min_burn( .add_attribute("min_burn", format!("{}", min_burn))) } +#[cfg(test)] pub fn get_max_burn_as_u64(store: &dyn Storage, netuid: u16) -> u64 { MAX_BURN.load(store, netuid).unwrap() } @@ -1195,7 +1178,7 @@ pub fn do_sudo_set_max_burn( MAX_BURN.save(deps.storage, netuid, &max_burn)?; deps.api.debug(&format!( - "MaxBurnSet( netuid: {:?} max_burn: {:?} ) ", + "🛸 MaxBurnSet ( netuid: {:?} max_burn: {:?} ) ", netuid, max_burn )); @@ -1209,6 +1192,7 @@ pub fn get_difficulty_as_u64(store: &dyn Storage, netuid: u16) -> u64 { DIFFICULTY.load(store, netuid).unwrap() } +#[cfg(test)] pub fn set_difficulty(store: &mut dyn Storage, netuid: u16, difficulty: u64) { DIFFICULTY.save(store, netuid, &difficulty).unwrap(); } @@ -1230,7 +1214,7 @@ pub fn do_sudo_set_difficulty( DIFFICULTY.save(deps.storage, netuid, &difficulty)?; deps.api.debug(&format!( - "DifficultySet( netuid: {:?} difficulty: {:?} ) ", + "🛸 DifficultySet ( netuid: {:?} difficulty: {:?} ) ", netuid, difficulty )); @@ -1244,6 +1228,7 @@ pub fn get_max_allowed_validators(store: &dyn Storage, netuid: u16) -> u16 { MAX_ALLOWED_VALIDATORS.load(store, netuid).unwrap() } +#[cfg(test)] pub fn set_max_allowed_validators(store: &mut dyn Storage, netuid: u16, max_allowed: u16) { MAX_ALLOWED_VALIDATORS .save(store, netuid, &max_allowed) @@ -1259,11 +1244,6 @@ pub fn do_sudo_set_max_allowed_validators( ) -> Result { ensure_subnet_owner_or_root(deps.storage, &info.sender, netuid)?; - ensure!( - if_subnet_exist(deps.storage, netuid), - ContractError::NetworkDoesNotExist {} - ); - ensure!( max_allowed_validators <= get_max_allowed_uids(deps.storage, netuid), ContractError::StorageValueOutOfRange {} @@ -1272,7 +1252,7 @@ pub fn do_sudo_set_max_allowed_validators( MAX_ALLOWED_VALIDATORS.save(deps.storage, netuid, &max_allowed_validators)?; deps.api.debug(&format!( - "MaxAllowedValidatorsSet( netuid: {:?} max_allowed_validators: {:?} ) ", + "🛸 MaxAllowedValidatorsSet ( netuid: {:?} max_allowed_validators: {:?} ) ", netuid, max_allowed_validators )); @@ -1306,7 +1286,7 @@ pub fn do_sudo_set_bonds_moving_average( BONDS_MOVING_AVERAGE.save(deps.storage, netuid, &bonds_moving_average)?; deps.api.debug(&format!( - "BondsMovingAverageSet( netuid: {:?} bonds_moving_average: {:?} ) ", + "🛸 BondsMovingAverageSet ( netuid: {:?} bonds_moving_average: {:?} ) ", netuid, bonds_moving_average )); @@ -1320,6 +1300,7 @@ pub fn get_max_registrations_per_block(store: &dyn Storage, netuid: u16) -> u16 MAX_REGISTRATION_PER_BLOCK.load(store, netuid).unwrap() } +#[cfg(test)] pub fn set_max_registrations_per_block( store: &mut dyn Storage, netuid: u16, @@ -1347,7 +1328,7 @@ pub fn do_sudo_set_max_registrations_per_block( MAX_REGISTRATION_PER_BLOCK.save(deps.storage, netuid, &max_registrations_per_block)?; deps.api.debug(&format!( - "MaxRegistrationsPerBlock( netuid: {:?} max_registrations_per_block: {:?} ) ", + "🛸 MaxRegistrationsPerBlock ( netuid: {:?} max_registrations_per_block: {:?} ) ", netuid, max_registrations_per_block )); @@ -1364,6 +1345,7 @@ pub fn get_subnet_owner(store: &dyn Storage, netuid: u16) -> Addr { SUBNET_OWNER.load(store, netuid).unwrap() } +#[cfg(test)] pub fn get_subnet_owner_cut(store: &dyn Storage) -> u16 { SUBNET_OWNER_CUT.load(store).unwrap() } @@ -1379,7 +1361,7 @@ pub fn do_sudo_set_subnet_owner_cut( SUBNET_OWNER_CUT.save(deps.storage, &subnet_owner_cut)?; deps.api.debug(&format!( - "SubnetOwnerCut( subnet_owner_cut: {:?} ) ", + "🛸 SubnetOwnerCut ( subnet_owner_cut: {:?} ) ", subnet_owner_cut )); @@ -1399,7 +1381,7 @@ pub fn do_sudo_set_network_rate_limit( NETWORK_RATE_LIMIT.save(deps.storage, &rate_limit)?; deps.api.debug(&format!( - "NetworkRateLimit( rate_limit: {:?} ) ", + "🛸 NetworkRateLimit ( rate_limit: {:?} ) ", rate_limit )); @@ -1425,7 +1407,7 @@ pub fn do_sudo_set_tempo( TEMPO.save(deps.storage, netuid, &tempo)?; deps.api.debug(&format!( - "TempoSet( netuid: {:?} tempo: {:?} ) ", + "🛸 TempoSet ( netuid: {:?} tempo: {:?} ) ", netuid, tempo )); @@ -1495,7 +1477,7 @@ pub fn do_sudo_set_network_immunity_period( NETWORK_IMMUNITY_PERIOD.save(deps.storage, &immunity_period)?; deps.api.debug(&format!( - "NetworkImmunityPeriod( period: {:?} ) ", + "🛸 NetworkImmunityPeriod ( period: {:?} ) ", immunity_period )); @@ -1515,7 +1497,7 @@ pub fn do_sudo_set_network_min_lock_cost( NETWORK_MIN_LOCK_COST.save(deps.storage, &lock_cost)?; deps.api.debug(&format!( - "NetworkMinLockCost( lock_cost: {:?} ) ", + "🛸 NetworkMinLockCost ( lock_cost: {:?} ) ", lock_cost )); @@ -1534,8 +1516,10 @@ pub fn do_sudo_set_subnet_limit( SUBNET_LIMIT.save(deps.storage, &max_subnets)?; - deps.api - .debug(&format!("SubnetLimit( max_subnets: {:?} ) ", max_subnets)); + deps.api.debug(&format!( + "🛸 SubnetLimit ( max_subnets: {:?} ) ", + max_subnets + )); Ok(Response::default() .add_attribute("action", "subnet_limit_set") @@ -1553,7 +1537,7 @@ pub fn do_sudo_set_lock_reduction_interval( NETWORK_LOCK_REDUCTION_INTERVAL.save(deps.storage, &interval)?; deps.api.debug(&format!( - "NetworkLockReductionInterval( interval: {:?} ) ", + "🛸 NetworkLockReductionInterval ( interval: {:?} ) ", interval )); @@ -1576,7 +1560,7 @@ pub fn do_sudo_set_validator_permit_for_uid( set_validator_permit_for_uid(deps.storage, netuid, uid, validator_permit); deps.api.debug(&format!( - "VALIDATOR_PERMIT( netuid: {:?} uid: {:?} validator_permit: {:?} ) ", + "🛸 ValidatorPermit ( netuid: {:?} uid: {:?} validator_permit: {:?} ) ", netuid, uid, validator_permit, )); @@ -1587,6 +1571,11 @@ pub fn do_sudo_set_validator_permit_for_uid( .add_attribute("validator_permit", format!("{}", validator_permit))) } +#[cfg(test)] +pub fn set_block_emission(store: &mut dyn Storage, emission: u64) { + BLOCK_EMISSION.save(store, &emission).unwrap(); +} + pub fn do_sudo_set_block_emission( deps: DepsMut, _env: Env, @@ -1598,9 +1587,27 @@ pub fn do_sudo_set_block_emission( BLOCK_EMISSION.save(deps.storage, &emission)?; deps.api - .debug(&format!("BLOCK_EMISSION( emission: {:?} ) ", emission)); + .debug(&format!("🛸 BlockEmission ( emission: {:?} ) ", emission)); Ok(Response::default() .add_attribute("action", "block_emission_set") - .add_attribute("netuid", format!("{}", emission))) + .add_attribute("emission", format!("{}", emission))) +} + +pub fn do_sudo_set_subnet_metadata( + deps: DepsMut, + _env: Env, + info: MessageInfo, + netuid: u16, + particle: String, +) -> Result { + ensure_subnet_owner_or_root(deps.storage, &info.sender, netuid)?; + ensure!(particle.len() == 46, ContractError::MetadataSizeError {}); + + METADATA.save(deps.storage, netuid, &particle)?; + + Ok(Response::default() + .add_attribute("action", "metadata_set") + .add_attribute("netuid", format!("{}", netuid)) + .add_attribute("metadata", format!("{}", particle))) } diff --git a/src/weights.rs b/src/weights.rs index 60a6fc7..66296f4 100644 --- a/src/weights.rs +++ b/src/weights.rs @@ -85,13 +85,10 @@ pub fn do_set_weights( ) -> Result { // --- 1. Check the caller's signature. This is the hotkey of a registered account. let hotkey = info.sender; - // deps.api.debug(&format!( - // "do_set_weights( origin:{:?} netuid:{:?}, uids:{:?}, values:{:?})", - // hotkey, - // netuid, - // uids, - // values - // )); + deps.api.debug(&format!( + "💡 do_set_weights ( origin:{:?} netuid:{:?}, uids:{:?}, values:{:?})", + hotkey, netuid, uids, values + )); // --- 2. Check that the length of uid list and value list are equal for this network. ensure!( @@ -200,7 +197,7 @@ pub fn do_set_weights( // --- 18. Emit the tracking event. deps.api.debug(&format!( - "WeightsSet( netuid:{:?}, neuron_uid:{:?} )", + "💡 WeightsSet ( netuid:{:?}, neuron_uid:{:?} )", netuid, neuron_uid )); @@ -225,7 +222,7 @@ pub fn check_version_key( ) -> bool { let network_version_key: u64 = WEIGHTS_VERSION_KEY.load(store, netuid).unwrap(); api.debug(&format!( - "check_version_key( network_version_key:{:?}, version_key:{:?} )", + "💡 check_version_key ( network_version_key:{:?}, version_key:{:?} )", network_version_key.clone(), version_key )); @@ -263,7 +260,7 @@ pub fn contains_invalid_uids( for uid in uids { if !is_uid_exist_on_network(store, netuid, uid.clone()) { api.debug(&format!( - "contains_invalid_uids( netuid:{:?}, uid:{:?} does not exist on network. )", + "💡 contains_invalid_uids ( netuid:{:?}, uid:{:?} does not exist on network. )", netuid, uids )); return true; @@ -337,6 +334,7 @@ pub fn check_length( } // Implace normalizes the passed positive integer weights so that they sum to u16 max value. +#[cfg(test)] pub fn normalize_weights(mut weights: Vec) -> Vec { let sum: u64 = weights.iter().map(|x| *x as u64).sum(); if sum.clone() == 0 { @@ -407,17 +405,20 @@ pub fn get_network_weights(store: &dyn Storage, netuid: u16) -> StdResult StdResult>> { +pub fn get_network_weights_sparse( + store: &dyn Storage, + netuid: u16, +) -> StdResult>> { let n: usize = get_subnetwork_n(store, netuid) as usize; - let mut weights: Vec> = vec![ vec![]; n ]; + let mut weights: Vec> = vec![vec![]; n]; for item in WEIGHTS .prefix(netuid) .range(store, None, None, Order::Ascending) { let (uid_i, weights_i) = item.unwrap(); for (uid_j, weight_ij) in weights_i.iter() { - weights [ uid_i as usize ].push( ( *uid_j, *weight_ij )); + weights[uid_i as usize].push((*uid_j, *weight_ij)); } } Ok(weights) -} \ No newline at end of file +}