From 2b10e12b050ce1be6a943260fb0c4522b04d3bb3 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Mon, 17 Jun 2024 15:25:10 +0400 Subject: [PATCH 01/27] refactor: hotkey swap + tests --- pallets/subtensor/src/lib.rs | 13 +- pallets/subtensor/src/registration.rs | 138 +-- pallets/subtensor/src/swap.rs | 438 ++++++++++ pallets/subtensor/tests/mock.rs | 3 +- pallets/subtensor/tests/swap.rs | 1133 +++++++++++++++++++++++++ 5 files changed, 1581 insertions(+), 144 deletions(-) create mode 100644 pallets/subtensor/src/swap.rs create mode 100644 pallets/subtensor/tests/swap.rs diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index efb528cdeb..18ea0779f7 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -43,6 +43,7 @@ mod registration; mod root; mod serving; mod staking; +mod swap; mod uids; mod utils; mod weights; @@ -744,7 +745,7 @@ pub mod pallet { pub(super) type TxDelegateTakeRateLimit = StorageValue<_, u64, ValueQuery, DefaultTxDelegateTakeRateLimit>; #[pallet::storage] // --- MAP ( key ) --> last_block - pub(super) type LastTxBlock = + pub type LastTxBlock = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; #[pallet::storage] // --- MAP ( key ) --> last_block pub(super) type LastTxBlockDelegateTake = @@ -760,10 +761,10 @@ pub mod pallet { pub type ServingRateLimit = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultServingRateLimit>; #[pallet::storage] // --- MAP ( netuid, hotkey ) --> axon_info - pub(super) type Axons = + pub type Axons = StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, AxonInfoOf, OptionQuery>; #[pallet::storage] // --- MAP ( netuid, hotkey ) --> prometheus_info - pub(super) type Prometheus = StorageDoubleMap< + pub type Prometheus = StorageDoubleMap< _, Identity, u16, @@ -1017,13 +1018,13 @@ pub mod pallet { } #[pallet::storage] // --- DMAP ( netuid, hotkey ) --> uid - pub(super) type Uids = + pub type Uids = StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, u16, OptionQuery>; #[pallet::storage] // --- DMAP ( netuid, uid ) --> hotkey - pub(super) type Keys = + pub type Keys = StorageDoubleMap<_, Identity, u16, Identity, u16, T::AccountId, ValueQuery, DefaultKey>; #[pallet::storage] // --- DMAP ( netuid ) --> (hotkey, se, ve) - pub(super) type LoadedEmission = + pub type LoadedEmission = StorageMap<_, Identity, u16, Vec<(T::AccountId, u64, u64)>, OptionQuery>; #[pallet::storage] // --- DMAP ( netuid ) --> active diff --git a/pallets/subtensor/src/registration.rs b/pallets/subtensor/src/registration.rs index dda00db541..fe9e18702f 100644 --- a/pallets/subtensor/src/registration.rs +++ b/pallets/subtensor/src/registration.rs @@ -1,6 +1,5 @@ use super::*; -use frame_support::storage::IterableStorageDoubleMap; -use sp_core::{Get, H256, U256}; +use sp_core::{H256, U256}; use sp_io::hashing::{keccak_256, sha2_256}; use sp_runtime::Saturating; use system::pallet_prelude::BlockNumberFor; @@ -592,139 +591,4 @@ impl Pallet { (nonce, vec_work) } - pub fn do_swap_hotkey( - origin: T::RuntimeOrigin, - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - ) -> DispatchResultWithPostInfo { - let coldkey = ensure_signed(origin)?; - - let mut weight = T::DbWeight::get().reads_writes(2, 0); - ensure!( - Self::coldkey_owns_hotkey(&coldkey, old_hotkey), - Error::::NonAssociatedColdKey - ); - - let block: u64 = Self::get_current_block_as_u64(); - ensure!( - !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&coldkey), block), - Error::::HotKeySetTxRateLimitExceeded - ); - - weight.saturating_accrue(T::DbWeight::get().reads(2)); - - ensure!(old_hotkey != new_hotkey, Error::::NewHotKeyIsSameWithOld); - ensure!( - !Self::is_hotkey_registered_on_any_network(new_hotkey), - Error::::HotKeyAlreadyRegisteredInSubNet - ); - - weight.saturating_accrue( - T::DbWeight::get().reads((TotalNetworks::::get().saturating_add(1)) as u64), - ); - - let swap_cost = 1_000_000_000u64; - ensure!( - Self::can_remove_balance_from_coldkey_account(&coldkey, swap_cost), - Error::::NotEnoughBalanceToPaySwapHotKey - ); - let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?; - Self::burn_tokens(actual_burn_amount); - - Owner::::remove(old_hotkey); - Owner::::insert(new_hotkey, coldkey.clone()); - weight.saturating_accrue(T::DbWeight::get().writes(2)); - - if let Ok(total_hotkey_stake) = TotalHotkeyStake::::try_get(old_hotkey) { - TotalHotkeyStake::::remove(old_hotkey); - TotalHotkeyStake::::insert(new_hotkey, total_hotkey_stake); - - weight.saturating_accrue(T::DbWeight::get().writes(2)); - } - - if let Ok(delegate_take) = Delegates::::try_get(old_hotkey) { - Delegates::::remove(old_hotkey); - Delegates::::insert(new_hotkey, delegate_take); - - weight.saturating_accrue(T::DbWeight::get().writes(2)); - } - - if let Ok(last_tx) = LastTxBlock::::try_get(old_hotkey) { - LastTxBlock::::remove(old_hotkey); - LastTxBlock::::insert(new_hotkey, last_tx); - - weight.saturating_accrue(T::DbWeight::get().writes(2)); - } - - let mut coldkey_stake: Vec<(T::AccountId, u64)> = vec![]; - for (coldkey, stake_amount) in Stake::::iter_prefix(old_hotkey) { - coldkey_stake.push((coldkey.clone(), stake_amount)); - } - - let _ = Stake::::clear_prefix(old_hotkey, coldkey_stake.len() as u32, None); - weight.saturating_accrue(T::DbWeight::get().writes(coldkey_stake.len() as u64)); - - for (coldkey, stake_amount) in coldkey_stake { - Stake::::insert(new_hotkey, coldkey, stake_amount); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } - - let mut netuid_is_member: Vec = vec![]; - for netuid in as IterableStorageDoubleMap>::iter_key_prefix(old_hotkey) { - netuid_is_member.push(netuid); - } - - let _ = IsNetworkMember::::clear_prefix(old_hotkey, netuid_is_member.len() as u32, None); - weight.saturating_accrue(T::DbWeight::get().writes(netuid_is_member.len() as u64)); - - for netuid in netuid_is_member.iter() { - IsNetworkMember::::insert(new_hotkey, netuid, true); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } - - for netuid in netuid_is_member.iter() { - if let Ok(axon_info) = Axons::::try_get(netuid, old_hotkey) { - Axons::::remove(netuid, old_hotkey); - Axons::::insert(netuid, new_hotkey, axon_info); - - weight.saturating_accrue(T::DbWeight::get().writes(2)); - } - } - - for netuid in netuid_is_member.iter() { - if let Ok(uid) = Uids::::try_get(netuid, old_hotkey) { - Uids::::remove(netuid, old_hotkey); - Uids::::insert(netuid, new_hotkey, uid); - - weight.saturating_accrue(T::DbWeight::get().writes(2)); - - Keys::::insert(netuid, uid, new_hotkey); - - weight.saturating_accrue(T::DbWeight::get().writes(1)); - - LoadedEmission::::mutate(netuid, |emission_exists| match emission_exists { - Some(emissions) => { - if let Some(emission) = emissions.get_mut(uid as usize) { - let (_, se, ve) = emission; - *emission = (new_hotkey.clone(), *se, *ve); - } - } - None => {} - }); - - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } - } - - Self::set_last_tx_block(&coldkey, block); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - - Self::deposit_event(Event::HotkeySwapped { - coldkey, - old_hotkey: old_hotkey.clone(), - new_hotkey: new_hotkey.clone(), - }); - - Ok(Some(weight).into()) - } } diff --git a/pallets/subtensor/src/swap.rs b/pallets/subtensor/src/swap.rs new file mode 100644 index 0000000000..4d7aaf6f7f --- /dev/null +++ b/pallets/subtensor/src/swap.rs @@ -0,0 +1,438 @@ +use super::*; +use frame_support::{storage::IterableStorageDoubleMap, weights::Weight}; +use sp_core::Get; + +impl Pallet { + /// Swaps the hotkey of a coldkey account. + /// + /// # Arguments + /// + /// * `origin` - The origin of the transaction. + /// * `old_hotkey` - The old hotkey to be swapped. + /// * `new_hotkey` - The new hotkey to replace the old one. + /// + /// # Returns + /// + /// * `DispatchResultWithPostInfo` - The result of the dispatch. + /// + /// # Errors + /// + /// * `NonAssociatedColdKey` - If the coldkey does not own the old hotkey. + /// * `HotKeySetTxRateLimitExceeded` - If the transaction rate limit is exceeded. + /// * `NewHotKeyIsSameWithOld` - If the new hotkey is the same as the old hotkey. + /// * `HotKeyAlreadyRegisteredInSubNet` - If the new hotkey is already registered in the subnet. + /// * `NotEnoughBalanceToPaySwapHotKey` - If there is not enough balance to pay for the swap. + pub fn do_swap_hotkey( + origin: T::RuntimeOrigin, + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + ) -> DispatchResultWithPostInfo { + let coldkey = ensure_signed(origin)?; + + let mut weight = T::DbWeight::get().reads_writes(2, 0); + ensure!( + Self::coldkey_owns_hotkey(&coldkey, old_hotkey), + Error::::NonAssociatedColdKey + ); + + let block: u64 = Self::get_current_block_as_u64(); + ensure!( + !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&coldkey), block), + Error::::HotKeySetTxRateLimitExceeded + ); + + weight.saturating_accrue(T::DbWeight::get().reads(2)); + + ensure!(old_hotkey != new_hotkey, Error::::NewHotKeyIsSameWithOld); + ensure!( + !Self::is_hotkey_registered_on_any_network(new_hotkey), + Error::::HotKeyAlreadyRegisteredInSubNet + ); + + weight + .saturating_accrue(T::DbWeight::get().reads((TotalNetworks::::get() + 1u16) as u64)); + + let swap_cost = 1_000_000_000u64; + ensure!( + Self::can_remove_balance_from_coldkey_account(&coldkey, swap_cost), + Error::::NotEnoughBalanceToPaySwapHotKey + ); + let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?; + Self::burn_tokens(actual_burn_amount); + + Self::swap_owner(old_hotkey, new_hotkey, &coldkey, &mut weight)?; + Self::swap_total_hotkey_stake(old_hotkey, new_hotkey, &mut weight)?; + Self::swap_delegates(old_hotkey, new_hotkey, &mut weight)?; + Self::swap_last_tx_block(old_hotkey, new_hotkey, &mut weight)?; + Self::swap_stake(old_hotkey, new_hotkey, &mut weight)?; + + // Store the value of is_network_member for the old key + let netuid_is_member: Vec = Self::get_netuid_is_member(old_hotkey, &mut weight)?; + + Self::swap_is_network_member(old_hotkey, new_hotkey, &netuid_is_member, &mut weight)?; + Self::swap_axons(old_hotkey, new_hotkey, &netuid_is_member, &mut weight)?; + Self::swap_keys(old_hotkey, new_hotkey, &netuid_is_member, &mut weight)?; + Self::swap_loaded_emission(old_hotkey, new_hotkey, &netuid_is_member, &mut weight)?; + Self::swap_uids(old_hotkey, new_hotkey, &netuid_is_member, &mut weight)?; + Self::swap_prometheus(old_hotkey, new_hotkey, &netuid_is_member, &mut weight)?; + + Self::swap_total_hotkey_coldkey_stakes_this_interval(old_hotkey, new_hotkey, &mut weight)?; + + Self::set_last_tx_block(&coldkey, block); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + + Self::deposit_event(Event::HotkeySwapped { + coldkey, + old_hotkey: old_hotkey.clone(), + new_hotkey: new_hotkey.clone(), + }); + + Ok(Some(weight).into()) + } + + /// Retrieves the network membership status for a given hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The hotkey to check for network membership. + /// + /// # Returns + /// + /// * `Result, Error>` - A vector of network IDs where the hotkey is a member. + pub fn get_netuid_is_member( + old_hotkey: &T::AccountId, + weight: &mut Weight, + ) -> Result, Error> { + let netuid_is_member: Vec = + as IterableStorageDoubleMap<_, _, _>>::iter_prefix(old_hotkey) + .map(|(netuid, _)| netuid) + .collect(); + weight.saturating_accrue(T::DbWeight::get().reads(netuid_is_member.len() as u64)); + Ok(netuid_is_member) + } + + /// Swaps the owner of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `coldkey` - The coldkey owning the hotkey. + /// * `weight` - The weight of the transaction. + /// + /// # Returns + /// + /// * `Result<(), Error>` - The result of the operation. + pub fn swap_owner( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + coldkey: &T::AccountId, + weight: &mut Weight, + ) -> DispatchResult { + Owner::::remove(old_hotkey); + Owner::::insert(new_hotkey, coldkey.clone()); + weight.saturating_accrue(T::DbWeight::get().writes(2)); + Ok(()) + } + + /// Swaps the total stake of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `weight` - The weight of the transaction. + /// + /// # Returns + /// + /// * `Result<(), Error>` - The result of the operation. + pub fn swap_total_hotkey_stake( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + weight: &mut Weight, + ) -> DispatchResult { + if let Ok(total_hotkey_stake) = TotalHotkeyStake::::try_get(old_hotkey) { + TotalHotkeyStake::::remove(old_hotkey); + TotalHotkeyStake::::insert(new_hotkey, total_hotkey_stake); + weight.saturating_accrue(T::DbWeight::get().writes(2)); + } + Ok(()) + } + + /// Swaps the delegates of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `weight` - The weight of the transaction. + /// + /// # Returns + /// + /// * `Result<(), Error>` - The result of the operation. + pub fn swap_delegates( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + weight: &mut Weight, + ) -> DispatchResult { + if let Ok(delegate_take) = Delegates::::try_get(old_hotkey) { + Delegates::::remove(old_hotkey); + Delegates::::insert(new_hotkey, delegate_take); + weight.saturating_accrue(T::DbWeight::get().writes(2)); + } + Ok(()) + } + + /// Swaps the last transaction block of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `weight` - The weight of the transaction. + /// + /// # Returns + /// + /// * `Result<(), Error>` - The result of the operation. + pub fn swap_last_tx_block( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + weight: &mut Weight, + ) -> DispatchResult { + if let Ok(last_tx) = LastTxBlock::::try_get(old_hotkey) { + LastTxBlock::::remove(old_hotkey); + LastTxBlock::::insert(new_hotkey, last_tx); + weight.saturating_accrue(T::DbWeight::get().writes(2)); + } + Ok(()) + } + + /// Swaps the stake of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `weight` - The weight of the transaction. + /// + /// # Returns + /// + /// * `Result<(), Error>` - The result of the operation. + pub fn swap_stake( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + weight: &mut Weight, + ) -> DispatchResult { + let mut writes = 0; + let stakes: Vec<(T::AccountId, u64)> = Stake::::iter_prefix(old_hotkey).collect(); + for (coldkey, stake_amount) in stakes { + Stake::::insert(new_hotkey, &coldkey, stake_amount); + Stake::::remove(old_hotkey, &coldkey); + writes += 2; // One write for insert and one for remove + } + *weight += T::DbWeight::get().writes(writes as u64); + Ok(()) + } + /// Swaps the network membership status of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. + /// * `weight` - The weight of the transaction. + /// + /// # Returns + /// + /// * `Result<(), Error>` - The result of the operation. + pub fn swap_is_network_member( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + netuid_is_member: &Vec, + weight: &mut Weight, + ) -> DispatchResult { + let _ = IsNetworkMember::::clear_prefix(old_hotkey, netuid_is_member.len() as u32, None); + weight.saturating_accrue(T::DbWeight::get().writes(netuid_is_member.len() as u64)); + for netuid in netuid_is_member.iter() { + IsNetworkMember::::insert(new_hotkey, netuid, true); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + } + Ok(()) + } + + /// Swaps the axons of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. + /// * `weight` - The weight of the transaction. + /// + /// # Returns + /// + /// * `Result<(), Error>` - The result of the operation. + pub fn swap_axons( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + netuid_is_member: &Vec, + weight: &mut Weight, + ) -> DispatchResult { + for netuid in netuid_is_member.iter() { + if let Ok(axon_info) = Axons::::try_get(netuid, old_hotkey) { + Axons::::remove(netuid, old_hotkey); + Axons::::insert(netuid, new_hotkey, axon_info); + weight.saturating_accrue(T::DbWeight::get().writes(2)); + } + } + Ok(()) + } + /// Swaps the references in the keys storage map of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. + /// * `weight` - The weight of the transaction. + /// + /// # Returns + /// + /// * `Result<(), Error>` - The result of the operation. + pub fn swap_keys( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + netuid_is_member: &Vec, + weight: &mut Weight, + ) -> DispatchResult { + let mut writes = 0; + for netuid in netuid_is_member { + let keys: Vec<(u16, T::AccountId)> = Keys::::iter_prefix(netuid).collect(); + for (uid, key) in keys { + if key == *old_hotkey { + log::info!("old hotkey found: {:?}", old_hotkey); + Keys::::insert(netuid, uid, new_hotkey.clone()); + } + writes += 2; + } + } + log::info!("writes: {:?}", writes); + *weight += T::DbWeight::get().writes(writes as u64); + Ok(()) + } + + /// Swaps the loaded emission of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. + /// * `weight` - The weight of the transaction. + /// + /// # Returns + /// + /// * `Result<(), Error>` - The result of the operation. + pub fn swap_loaded_emission( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + netuid_is_member: &[u16], + weight: &mut Weight, + ) -> DispatchResult { + for netuid in netuid_is_member { + if let Some(mut emissions) = LoadedEmission::::get(netuid) { + for emission in emissions.iter_mut() { + if emission.0 == *old_hotkey { + emission.0 = new_hotkey.clone(); + } + } + LoadedEmission::::insert(netuid, emissions); + } + } + *weight += T::DbWeight::get().writes(netuid_is_member.len() as u64); + Ok(()) + } + + /// Swaps the UIDs of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. + /// * `weight` - The weight of the transaction. + /// + /// # Returns + /// + /// * `Result<(), Error>` - The result of the operation. + pub fn swap_uids( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + netuid_is_member: &Vec, + weight: &mut Weight, + ) -> DispatchResult { + for netuid in netuid_is_member.iter() { + if let Ok(uid) = Uids::::try_get(netuid, old_hotkey) { + Uids::::remove(netuid, old_hotkey); + Uids::::insert(netuid, new_hotkey, uid); + weight.saturating_accrue(T::DbWeight::get().writes(2)); + } + } + Ok(()) + } + + /// Swaps the Prometheus data of the hotkey. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. + /// * `weight` - The weight of the transaction. + /// + /// # Returns + /// + /// * `Result<(), Error>` - The result of the operation. + pub fn swap_prometheus( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + netuid_is_member: &Vec, + weight: &mut Weight, + ) -> DispatchResult { + for netuid in netuid_is_member.iter() { + if let Ok(prometheus_info) = Prometheus::::try_get(netuid, old_hotkey) { + Prometheus::::remove(netuid, old_hotkey); + Prometheus::::insert(netuid, new_hotkey, prometheus_info); + weight.saturating_accrue(T::DbWeight::get().writes(2)); + } + } + Ok(()) + } + + /// Swaps the total hotkey-coldkey stakes for the current interval. + /// + /// # Arguments + /// + /// * `old_hotkey` - The old hotkey. + /// * `new_hotkey` - The new hotkey. + /// * `weight` - The weight of the transaction. + /// + /// # Returns + /// + /// * `Result<(), Error>` - The result of the operation. + pub fn swap_total_hotkey_coldkey_stakes_this_interval( + old_hotkey: &T::AccountId, + new_hotkey: &T::AccountId, + weight: &mut Weight, + ) -> DispatchResult { + let stakes: Vec<(T::AccountId, (u64, u64))> = TotalHotkeyColdkeyStakesThisInterval::::iter_prefix(old_hotkey).collect(); + log::info!("Stakes to swap: {:?}", stakes); + for (coldkey, stake) in stakes { + log::info!("Swapping stake for coldkey: {:?}, stake: {:?}", coldkey, stake); + TotalHotkeyColdkeyStakesThisInterval::::insert(new_hotkey, &coldkey, stake); + TotalHotkeyColdkeyStakesThisInterval::::remove(old_hotkey, &coldkey); + weight.saturating_accrue(T::DbWeight::get().writes(2)); // One write for insert and one for remove + } + Ok(()) + } +} diff --git a/pallets/subtensor/tests/mock.rs b/pallets/subtensor/tests/mock.rs index 78aac3d95d..4ec4aa4150 100644 --- a/pallets/subtensor/tests/mock.rs +++ b/pallets/subtensor/tests/mock.rs @@ -1,5 +1,6 @@ #![allow(clippy::arithmetic_side_effects, clippy::unwrap_used)] +use frame_support::weights::constants::RocksDbWeight; use frame_support::{ assert_ok, derive_impl, dispatch::DispatchResultWithPostInfo, @@ -88,7 +89,7 @@ impl system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); type BlockLength = (); - type DbWeight = (); + type DbWeight = RocksDbWeight; type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Hash = H256; diff --git a/pallets/subtensor/tests/swap.rs b/pallets/subtensor/tests/swap.rs new file mode 100644 index 0000000000..d6052c8fc5 --- /dev/null +++ b/pallets/subtensor/tests/swap.rs @@ -0,0 +1,1133 @@ +use codec::Encode; +use frame_support::weights::Weight; +use frame_support::{assert_err, assert_ok}; +use frame_system::Config; +mod mock; +use mock::*; +use pallet_subtensor::*; +use sp_core::U256; + +#[test] +fn test_do_swap_hotkey_ok() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let swap_cost = 1_000_000_000u64; + + // Setup initial state + add_network(netuid, tempo, 0); + register_ok_neuron(netuid, old_hotkey, coldkey, 0); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, swap_cost); + + // Perform the swap + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey), + &old_hotkey, + &new_hotkey + )); + + // Verify the swap + assert_eq!( + SubtensorModule::get_owning_coldkey_for_hotkey(&new_hotkey), + coldkey + ); + assert_ne!( + SubtensorModule::get_owning_coldkey_for_hotkey(&old_hotkey), + coldkey + ); + + // Verify other storage changes + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&new_hotkey), + SubtensorModule::get_total_stake_for_hotkey(&old_hotkey) + ); + assert_eq!( + SubtensorModule::get_delegate(new_hotkey.encode()), + SubtensorModule::get_delegate(old_hotkey.encode()) + ); + assert_eq!( + SubtensorModule::get_last_tx_block(&new_hotkey), + SubtensorModule::get_last_tx_block(&old_hotkey) + ); + + // Verify raw storage maps + // Stake + for (coldkey, stake_amount) in Stake::::iter_prefix(&old_hotkey) { + assert_eq!(Stake::::get(&new_hotkey, &coldkey), stake_amount); + } + + let mut weight = Weight::zero(); + // UIDs + for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight).unwrap() { + assert_eq!( + Uids::::get(netuid, &new_hotkey), + Uids::::get(netuid, &old_hotkey) + ); + } + + // Prometheus + for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight).unwrap() { + assert_eq!( + Prometheus::::get(netuid, &new_hotkey), + Prometheus::::get(netuid, &old_hotkey) + ); + } + + // LoadedEmission + for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight).unwrap() { + assert_eq!( + LoadedEmission::::get(netuid).unwrap(), + LoadedEmission::::get(netuid).unwrap() + ); + } + + // IsNetworkMember + for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight).unwrap() { + assert!(IsNetworkMember::::contains_key(&new_hotkey, netuid)); + assert!(!IsNetworkMember::::contains_key(&old_hotkey, netuid)); + } + + // Owner + assert_eq!(Owner::::get(&new_hotkey), coldkey); + + // TotalHotkeyStake + assert_eq!( + TotalHotkeyStake::::get(&new_hotkey), + TotalHotkeyStake::::get(&old_hotkey) + ); + + // Delegates + assert_eq!( + Delegates::::get(&new_hotkey), + Delegates::::get(&old_hotkey) + ); + + // LastTxBlock + assert_eq!( + LastTxBlock::::get(&new_hotkey), + LastTxBlock::::get(&old_hotkey) + ); + + // Axons + for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight).unwrap() { + assert_eq!( + Axons::::get(netuid, &new_hotkey), + Axons::::get(netuid, &old_hotkey) + ); + } + + // TotalHotkeyColdkeyStakesThisInterval + assert_eq!( + TotalHotkeyColdkeyStakesThisInterval::::get(&new_hotkey, &coldkey), + TotalHotkeyColdkeyStakesThisInterval::::get(&old_hotkey, &coldkey) + ); + }); +} + +#[test] +fn test_do_swap_hotkey_ok_robust() { + new_test_ext(1).execute_with(|| { + let num_subnets: u16 = 10; + let tempo: u16 = 13; + let swap_cost = 1_000_000_000u64; + + // Create 10 sets of keys + let mut old_hotkeys = vec![]; + let mut new_hotkeys = vec![]; + let mut coldkeys = vec![]; + + for i in 0..10 { + old_hotkeys.push(U256::from(i * 2 + 1)); + new_hotkeys.push(U256::from(i * 2 + 2)); + coldkeys.push(U256::from(i * 2 + 11)); + } + + + // Setup initial state + for netuid in 1..=num_subnets { + add_network(netuid, tempo, 0); + SubtensorModule::set_max_registrations_per_block(netuid, 20); + SubtensorModule::set_target_registrations_per_interval(netuid, 1000); + log::info!("Registrations this interval for netuid {:?} is {:?}", netuid, SubtensorModule::get_target_registrations_per_interval(netuid)); + for i in 0..10 { + register_ok_neuron(netuid, old_hotkeys[i], coldkeys[i], 0); + } + } + + // Add balance to coldkeys for swap cost + for i in 0..10 { + SubtensorModule::add_balance_to_coldkey_account(&coldkeys[i], swap_cost); + } + + // Perform the swaps for only two hotkeys + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkeys[0]), + &old_hotkeys[0], + &new_hotkeys[0] + )); + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkeys[1]), + &old_hotkeys[1], + &new_hotkeys[1] + )); + + // Verify the swaps + for netuid in 1..=num_subnets { + for i in 0..10 { + if i == 0 || i == 1 { + assert_eq!( + SubtensorModule::get_owning_coldkey_for_hotkey(&new_hotkeys[i]), + coldkeys[i] + ); + assert_ne!( + SubtensorModule::get_owning_coldkey_for_hotkey(&old_hotkeys[i]), + coldkeys[i] + ); + + // Verify other storage changes + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey(&new_hotkeys[i]), + SubtensorModule::get_total_stake_for_hotkey(&old_hotkeys[i]) + ); + + assert_eq!( + SubtensorModule::get_delegate(new_hotkeys[i].encode()), + SubtensorModule::get_delegate(old_hotkeys[i].encode()) + ); + + assert_eq!( + SubtensorModule::get_last_tx_block(&new_hotkeys[i]), + SubtensorModule::get_last_tx_block(&old_hotkeys[i]) + ); + + // Verify raw storage maps + // Stake + for (coldkey, stake_amount) in Stake::::iter_prefix(&old_hotkeys[i]) { + assert_eq!(Stake::::get(&new_hotkeys[i], &coldkey), stake_amount); + } + + let mut weight = Weight::zero(); + // UIDs + for netuid in SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() { + assert_eq!( + Uids::::get(netuid, &new_hotkeys[i]), + Uids::::get(netuid, &old_hotkeys[i]) + ); + } + + // Prometheus + for netuid in SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() { + assert_eq!( + Prometheus::::get(netuid, &new_hotkeys[i]), + Prometheus::::get(netuid, &old_hotkeys[i]) + ); + } + + // LoadedEmission + for netuid in SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() { + assert_eq!( + LoadedEmission::::get(netuid).unwrap(), + LoadedEmission::::get(netuid).unwrap() + ); + } + + // IsNetworkMember + for netuid in SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() { + assert!(IsNetworkMember::::contains_key(&new_hotkeys[i], netuid)); + assert!(!IsNetworkMember::::contains_key(&old_hotkeys[i], netuid)); + } + + // Owner + assert_eq!(Owner::::get(&new_hotkeys[i]), coldkeys[i]); + } else { + // Ensure other hotkeys remain unchanged + assert_eq!( + SubtensorModule::get_owning_coldkey_for_hotkey(&old_hotkeys[i]), + coldkeys[i] + ); + assert_ne!( + SubtensorModule::get_owning_coldkey_for_hotkey(&new_hotkeys[i]), + coldkeys[i] + ); + } + } + } + }); +} + +#[test] +fn test_do_swap_hotkey_err_not_owner() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let not_owner_coldkey = U256::from(4); + let swap_cost = 1_000_000_000u64; + + // Setup initial state + add_network(netuid, tempo, 0); + register_ok_neuron(netuid, old_hotkey, coldkey, 0); + SubtensorModule::add_balance_to_coldkey_account(¬_owner_coldkey, swap_cost); + + // Attempt the swap with a non-owner coldkey + assert_err!( + SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(not_owner_coldkey), + &old_hotkey, + &new_hotkey + ), + Error::::NonAssociatedColdKey + ); + }); +} + +#[test] +fn test_swap_owner_success() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let mut weight = Weight::zero(); + + // Initialize Owner for old_hotkey + Owner::::insert(&old_hotkey, &coldkey); + + // Perform the swap + assert_ok!(SubtensorModule::swap_owner( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight + )); + + // Verify the swap + assert_eq!(Owner::::get(&new_hotkey), coldkey); + assert!(!Owner::::contains_key(&old_hotkey)); + }); +} + +#[test] +fn test_swap_owner_old_hotkey_not_exist() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let mut weight = Weight::zero(); + + // Ensure old_hotkey does not exist + assert!(!Owner::::contains_key(&old_hotkey)); + + // Perform the swap + assert_ok!(SubtensorModule::swap_owner( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight + )); + + // Verify the swap + assert_eq!(Owner::::get(&new_hotkey), coldkey); + assert!(!Owner::::contains_key(&old_hotkey)); + }); +} + +#[test] +fn test_swap_owner_new_hotkey_already_exists() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let another_coldkey = U256::from(4); + let mut weight = Weight::zero(); + + // Initialize Owner for old_hotkey and new_hotkey + Owner::::insert(&old_hotkey, &coldkey); + Owner::::insert(&new_hotkey, &another_coldkey); + + // Perform the swap + assert_ok!(SubtensorModule::swap_owner( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight + )); + + // Verify the swap + assert_eq!(Owner::::get(&new_hotkey), coldkey); + assert!(!Owner::::contains_key(&old_hotkey)); + }); +} + +#[test] +fn test_swap_owner_weight_update() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let mut weight = Weight::zero(); + + // Initialize Owner for old_hotkey + Owner::::insert(&old_hotkey, &coldkey); + + // Perform the swap + assert_ok!(SubtensorModule::swap_owner( + &old_hotkey, + &new_hotkey, + &coldkey, + &mut weight + )); + + // Verify the weight update + let expected_weight = ::DbWeight::get().writes(2); + assert_eq!(weight, expected_weight); + }); +} + +#[test] +fn test_swap_total_hotkey_stake_success() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let total_stake = 1000u64; + let mut weight = Weight::zero(); + + // Initialize TotalHotkeyStake for old_hotkey + TotalHotkeyStake::::insert(&old_hotkey, total_stake); + + // Perform the swap + assert_ok!(SubtensorModule::swap_total_hotkey_stake( + &old_hotkey, + &new_hotkey, + &mut weight + )); + + // Verify the swap + assert_eq!(TotalHotkeyStake::::get(&new_hotkey), total_stake); + assert!(!TotalHotkeyStake::::contains_key(&old_hotkey)); + }); +} + +#[test] +fn test_swap_total_hotkey_stake_old_hotkey_not_exist() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let mut weight = Weight::zero(); + + // Ensure old_hotkey does not exist + assert!(!TotalHotkeyStake::::contains_key(&old_hotkey)); + + // Perform the swap + assert_ok!(SubtensorModule::swap_total_hotkey_stake( + &old_hotkey, + &new_hotkey, + &mut weight + )); + + // Verify that new_hotkey does not have a stake + assert!(!TotalHotkeyStake::::contains_key(&new_hotkey)); + }); +} + +#[test] +fn test_swap_total_hotkey_stake_weight_update() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let total_stake = 1000u64; + let mut weight = Weight::zero(); + + // Initialize TotalHotkeyStake for old_hotkey + TotalHotkeyStake::::insert(&old_hotkey, total_stake); + + // Perform the swap + assert_ok!(SubtensorModule::swap_total_hotkey_stake( + &old_hotkey, + &new_hotkey, + &mut weight + )); + + // Verify the weight update + let expected_weight = ::DbWeight::get().writes(2); + assert_eq!(weight, expected_weight); + }); +} + +#[test] +fn test_swap_delegates_success() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let delegate_take = 10u16; + let mut weight = Weight::zero(); + + // Initialize Delegates for old_hotkey + Delegates::::insert(&old_hotkey, delegate_take); + + // Perform the swap + assert_ok!(SubtensorModule::swap_delegates( + &old_hotkey, + &new_hotkey, + &mut weight + )); + + // Verify the swap + assert_eq!(Delegates::::get(&new_hotkey), delegate_take); + assert!(!Delegates::::contains_key(&old_hotkey)); + }); +} + +#[test] +fn test_swap_delegates_old_hotkey_not_exist() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let mut weight = Weight::zero(); + + // Ensure old_hotkey does not exist + assert!(!Delegates::::contains_key(&old_hotkey)); + + // Perform the swap + assert_ok!(SubtensorModule::swap_delegates( + &old_hotkey, + &new_hotkey, + &mut weight + )); + + // Verify that new_hotkey does not have a delegate + assert!(!Delegates::::contains_key(&new_hotkey)); + }); +} + +#[test] +fn test_swap_delegates_weight_update() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let delegate_take = 10u16; + let mut weight = Weight::zero(); + + // Initialize Delegates for old_hotkey + Delegates::::insert(&old_hotkey, delegate_take); + + // Perform the swap + assert_ok!(SubtensorModule::swap_delegates( + &old_hotkey, + &new_hotkey, + &mut weight + )); + + // Verify the weight update + let expected_weight = ::DbWeight::get().writes(2); + assert_eq!(weight, expected_weight); + }); +} + +#[test] +fn test_swap_last_tx_block_success() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let last_tx_block = 100u64; + let mut weight = Weight::zero(); + + // Initialize LastTxBlock for old_hotkey + LastTxBlock::::insert(&old_hotkey, last_tx_block); + + // Perform the swap + assert_ok!(SubtensorModule::swap_last_tx_block( + &old_hotkey, + &new_hotkey, + &mut weight + )); + + // Verify the swap + assert_eq!(LastTxBlock::::get(&new_hotkey), last_tx_block); + assert!(!LastTxBlock::::contains_key(&old_hotkey)); + }); +} + +#[test] +fn test_swap_last_tx_block_old_hotkey_not_exist() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let mut weight = Weight::zero(); + + // Ensure old_hotkey does not exist + assert!(!LastTxBlock::::contains_key(&old_hotkey)); + + // Perform the swap + assert_ok!(SubtensorModule::swap_last_tx_block( + &old_hotkey, + &new_hotkey, + &mut weight + )); + + // Verify that new_hotkey does not have a last transaction block + assert!(!LastTxBlock::::contains_key(&new_hotkey)); + }); +} + +#[test] +fn test_swap_last_tx_block_weight_update() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let last_tx_block = 100u64; + let mut weight = Weight::zero(); + + // Initialize LastTxBlock for old_hotkey + LastTxBlock::::insert(&old_hotkey, last_tx_block); + + // Perform the swap + assert_ok!(SubtensorModule::swap_last_tx_block( + &old_hotkey, + &new_hotkey, + &mut weight + )); + + // Verify the weight update + let expected_weight = ::DbWeight::get().writes(2); + assert_eq!(weight, expected_weight); + }); +} + +#[test] +fn test_swap_stake_success() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let stake_amount = 1000u64; + let mut weight = Weight::zero(); + + // Initialize Stake for old_hotkey + Stake::::insert(&old_hotkey, &coldkey, stake_amount); + + // Perform the swap + assert_ok!(SubtensorModule::swap_stake( + &old_hotkey, + &new_hotkey, + &mut weight + )); + + // Verify the swap + assert_eq!(Stake::::get(&new_hotkey, &coldkey), stake_amount); + assert!(!Stake::::contains_key(&old_hotkey, &coldkey)); + }); +} + +#[test] +fn test_swap_stake_old_hotkey_not_exist() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let stake_amount = 1000u64; + let mut weight = Weight::zero(); + + // Initialize Stake for old_hotkey + Stake::::insert(&old_hotkey, &coldkey, stake_amount); + + // Ensure old_hotkey has a stake + assert!(Stake::::contains_key(&old_hotkey, &coldkey)); + + // Perform the swap + assert_ok!(SubtensorModule::swap_stake( + &old_hotkey, + &new_hotkey, + &mut weight + )); + + // Verify that new_hotkey has the stake and old_hotkey does not + assert!(Stake::::contains_key(&new_hotkey, &coldkey)); + assert!(!Stake::::contains_key(&old_hotkey, &coldkey)); + }); +} + +#[test] +fn test_swap_stake_weight_update() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let stake_amount = 1000u64; + let mut weight = Weight::zero(); + + // Initialize Stake for old_hotkey + Stake::::insert(&old_hotkey, &coldkey, stake_amount); + + // Perform the swap + assert_ok!(SubtensorModule::swap_stake( + &old_hotkey, + &new_hotkey, + &mut weight + )); + + // Verify the weight update + let expected_weight = ::DbWeight::get().writes(2); + assert_eq!(weight, expected_weight); + }); +} + +#[test] +fn test_swap_is_network_member_success() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let netuid_is_member = vec![1u16, 2u16]; + let mut weight = Weight::zero(); + + // Initialize IsNetworkMember for old_hotkey + for netuid in &netuid_is_member { + IsNetworkMember::::insert(&old_hotkey, netuid, true); + } + + // Perform the swap + assert_ok!(SubtensorModule::swap_is_network_member( + &old_hotkey, + &new_hotkey, + &netuid_is_member, + &mut weight + )); + + // Verify the swap + for netuid in &netuid_is_member { + assert!(IsNetworkMember::::contains_key(&new_hotkey, netuid)); + assert!(!IsNetworkMember::::contains_key(&old_hotkey, netuid)); + } + }); +} + +#[test] +fn test_swap_is_network_member_weight_update() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let netuid_is_member = vec![1u16, 2u16]; + let mut weight = Weight::zero(); + + // Initialize IsNetworkMember for old_hotkey + for netuid in &netuid_is_member { + IsNetworkMember::::insert(&old_hotkey, netuid, true); + } + + // Perform the swap + assert_ok!(SubtensorModule::swap_is_network_member( + &old_hotkey, + &new_hotkey, + &netuid_is_member, + &mut weight + )); + + // Verify the weight update + let expected_weight = ::DbWeight::get().writes(4); + assert_eq!(weight, expected_weight); + }); +} + +#[test] +fn test_swap_axons_success() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let netuid_is_member = vec![1u16, 2u16]; + let axon_info = AxonInfo { + block: 100, + version: 1, + ip: 0x1234567890abcdef, + port: 8080, + ip_type: 4, + protocol: 1, + placeholder1: 0, + placeholder2: 0, + }; + let mut weight = Weight::zero(); + + // Initialize Axons for old_hotkey + for netuid in &netuid_is_member { + Axons::::insert(netuid, &old_hotkey, axon_info.clone()); + } + + // Perform the swap + assert_ok!(SubtensorModule::swap_axons( + &old_hotkey, + &new_hotkey, + &netuid_is_member, + &mut weight + )); + + // Verify the swap + for netuid in &netuid_is_member { + assert_eq!(Axons::::get(netuid, &new_hotkey).unwrap(), axon_info); + assert!(!Axons::::contains_key(netuid, &old_hotkey)); + } + }); +} + +#[test] +fn test_swap_axons_weight_update() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let netuid_is_member = vec![1u16, 2u16]; + let axon_info = AxonInfo { + block: 100, + version: 1, + ip: 0x1234567890abcdef, + port: 8080, + ip_type: 4, + protocol: 1, + placeholder1: 0, + placeholder2: 0, + }; + let mut weight = Weight::zero(); + + // Initialize Axons for old_hotkey + for netuid in &netuid_is_member { + Axons::::insert(netuid, &old_hotkey, axon_info.clone()); + } + + // Perform the swap + assert_ok!(SubtensorModule::swap_axons( + &old_hotkey, + &new_hotkey, + &netuid_is_member, + &mut weight + )); + + // Verify the weight update + let expected_weight = ::DbWeight::get().writes(4); + assert_eq!(weight, expected_weight); + }); +} + +#[test] +fn test_swap_keys_success() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let netuid_is_member = vec![1u16, 2u16]; + let uid = 42u16; + let mut weight = Weight::zero(); + + // Initialize Keys for old_hotkey + for netuid in &netuid_is_member { + log::info!("Inserting old_hotkey:{:?} netuid:{:?}", old_hotkey, netuid); + Keys::::insert(*netuid, uid, &old_hotkey); + } + + // Perform the swap + assert_ok!(SubtensorModule::swap_keys( + &old_hotkey, + &new_hotkey, + &netuid_is_member, + &mut weight + )); + + // Verify the swap + for netuid in &netuid_is_member { + log::info!("neutuid, uid, hotkey: {:?}, {:?}, {:?}", netuid, uid, new_hotkey); + assert_eq!(Keys::::get(netuid, uid), new_hotkey); + } + }); +} + +#[test] +fn test_swap_keys_weight_update() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let netuid_is_member = vec![1u16, 2u16]; + let uid = 42u16; + let mut weight = Weight::zero(); + + // Initialize Keys for old_hotkey + for netuid in &netuid_is_member { + Keys::::insert(*netuid, uid, old_hotkey.clone()); + } + + // Perform the swap + assert_ok!(SubtensorModule::swap_keys( + &old_hotkey, + &new_hotkey, + &netuid_is_member, + &mut weight + )); + + // Verify the weight update + let expected_weight = ::DbWeight::get().writes(4); + assert_eq!(weight, expected_weight); + }); +} + +#[test] +fn test_swap_loaded_emission_success() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let netuid_is_member = vec![1u16, 2u16]; + let se = 100u64; + let ve = 200u64; + let mut weight = Weight::zero(); + + // Initialize LoadedEmission for old_hotkey + for netuid in &netuid_is_member { + LoadedEmission::::mutate(netuid, |emission_exists| { + if let Some(emissions) = emission_exists { + emissions.push((old_hotkey.clone(), se, ve)); + } else { + *emission_exists = Some(vec![(old_hotkey.clone(), se, ve)]); + } + }); + } + + // Perform the swap + assert_ok!(SubtensorModule::swap_loaded_emission( + &old_hotkey, + &new_hotkey, + &netuid_is_member, + &mut weight + )); + + // Verify the swap + for netuid in &netuid_is_member { + let emissions = LoadedEmission::::get(netuid).unwrap(); + assert!(emissions.iter().any(|(hk, _, _)| hk == &new_hotkey)); + assert!(!emissions.iter().any(|(hk, _, _)| hk == &old_hotkey)); + } + }); +} + +#[test] +fn test_swap_loaded_emission_weight_update() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let netuid_is_member = vec![1u16, 2u16]; + // let uid = 42u64; + let se = 100u64; + let ve = 200u64; + let mut weight = Weight::zero(); + + // Initialize LoadedEmission for old_hotkey + for netuid in &netuid_is_member { + LoadedEmission::::mutate(netuid, |emission_exists| { + if let Some(emissions) = emission_exists { + emissions.push((old_hotkey.clone(), se, ve)); + } else { + *emission_exists = Some(vec![(old_hotkey.clone(), se, ve)]); + } + }); + } + + // Perform the swap + assert_ok!(SubtensorModule::swap_loaded_emission( + &old_hotkey, + &new_hotkey, + &netuid_is_member, + &mut weight + )); + + // Verify the weight update + let expected_weight = ::DbWeight::get().writes(2); + assert_eq!(weight, expected_weight); + }); +} + +#[test] +fn test_swap_uids_success() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let netuid_is_member = vec![1u16, 2u16]; + let uid = 42u16; + let mut weight = Weight::zero(); + + // Initialize Uids for old_hotkey + for netuid in &netuid_is_member { + Uids::::insert(netuid, &old_hotkey, uid); + } + + // Perform the swap + assert_ok!(SubtensorModule::swap_uids( + &old_hotkey, + &new_hotkey, + &netuid_is_member, + &mut weight + )); + + // Verify the swap + for netuid in &netuid_is_member { + assert_eq!(Uids::::get(netuid, &new_hotkey).unwrap(), uid); + assert!(!Uids::::contains_key(netuid, &old_hotkey)); + } + }); +} + +#[test] +fn test_swap_uids_weight_update() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let netuid_is_member = vec![1u16, 2u16]; + let uid = 42u16; + let mut weight = Weight::zero(); + + // Initialize Uids for old_hotkey + for netuid in &netuid_is_member { + Uids::::insert(netuid, &old_hotkey, uid); + } + + // Perform the swap + assert_ok!(SubtensorModule::swap_uids( + &old_hotkey, + &new_hotkey, + &netuid_is_member, + &mut weight + )); + + // Verify the weight update + let expected_weight = ::DbWeight::get().writes(4); + assert_eq!(weight, expected_weight); + }); +} + +#[test] +fn test_swap_prometheus_success() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let netuid_is_member = vec![1u16, 2u16]; + let prometheus_info = PrometheusInfo { + block: 100, + version: 1, + ip: 0x1234567890abcdef, + port: 8080, + ip_type: 4, + }; + let mut weight = Weight::zero(); + + // Initialize Prometheus for old_hotkey + for netuid in &netuid_is_member { + Prometheus::::insert(netuid, &old_hotkey, prometheus_info.clone()); + } + + // Perform the swap + assert_ok!(SubtensorModule::swap_prometheus( + &old_hotkey, + &new_hotkey, + &netuid_is_member, + &mut weight + )); + + // Verify the swap + for netuid in &netuid_is_member { + assert_eq!( + Prometheus::::get(netuid, &new_hotkey).unwrap(), + prometheus_info + ); + assert!(!Prometheus::::contains_key(netuid, &old_hotkey)); + } + }); +} + +#[test] +fn test_swap_prometheus_weight_update() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let netuid_is_member = vec![1u16, 2u16]; + let prometheus_info = PrometheusInfo { + block: 100, + version: 1, + ip: 0x1234567890abcdef, + port: 8080, + ip_type: 4, + }; + let mut weight = Weight::zero(); + + // Initialize Prometheus for old_hotkey + for netuid in &netuid_is_member { + Prometheus::::insert(netuid, &old_hotkey, prometheus_info.clone()); + } + + // Perform the swap + assert_ok!(SubtensorModule::swap_prometheus( + &old_hotkey, + &new_hotkey, + &netuid_is_member, + &mut weight + )); + + // Verify the weight update + let expected_weight = ::DbWeight::get().writes(4); + assert_eq!(weight, expected_weight); + }); +} + +#[test] +fn test_swap_total_hotkey_coldkey_stakes_this_interval_success() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let stake = (1000u64, 42u64); // Example tuple value + let mut weight = Weight::zero(); + + // Initialize TotalHotkeyColdkeyStakesThisInterval for old_hotkey + TotalHotkeyColdkeyStakesThisInterval::::insert(&old_hotkey, &coldkey, stake); + + // Perform the swap + assert_ok!( + SubtensorModule::swap_total_hotkey_coldkey_stakes_this_interval( + &old_hotkey, + &new_hotkey, + &mut weight + ) + ); + + // Verify the swap + assert_eq!( + TotalHotkeyColdkeyStakesThisInterval::::get(&new_hotkey, &coldkey), + stake + ); + assert!(!TotalHotkeyColdkeyStakesThisInterval::::contains_key( + &old_hotkey, + &coldkey + )); + }); +} + +#[test] +fn test_swap_total_hotkey_coldkey_stakes_this_interval_weight_update() { + new_test_ext(1).execute_with(|| { + let old_hotkey = U256::from(1); + let new_hotkey = U256::from(2); + let coldkey = U256::from(3); + let stake = (1000u64, 42u64); + let mut weight = Weight::zero(); + + // Initialize TotalHotkeyColdkeyStakesThisInterval for old_hotkey + TotalHotkeyColdkeyStakesThisInterval::::insert(&old_hotkey, &coldkey, stake); + + // Perform the swap + assert_ok!( + SubtensorModule::swap_total_hotkey_coldkey_stakes_this_interval( + &old_hotkey, + &new_hotkey, + &mut weight + ) + ); + + // Verify the weight update + let expected_weight = ::DbWeight::get().writes(2); + assert_eq!(weight, expected_weight); + }); +} From 7eb29f9b55d0303ff8a95356f541ffc443b5e349 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Mon, 17 Jun 2024 15:29:54 +0400 Subject: [PATCH 02/27] chore: lints --- pallets/subtensor/src/swap.rs | 17 +++++++++----- pallets/subtensor/tests/swap.rs | 40 +++++++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/pallets/subtensor/src/swap.rs b/pallets/subtensor/src/swap.rs index 4d7aaf6f7f..aa0bbf812c 100644 --- a/pallets/subtensor/src/swap.rs +++ b/pallets/subtensor/src/swap.rs @@ -248,7 +248,7 @@ impl Pallet { pub fn swap_is_network_member( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, - netuid_is_member: &Vec, + netuid_is_member: &[u16], weight: &mut Weight, ) -> DispatchResult { let _ = IsNetworkMember::::clear_prefix(old_hotkey, netuid_is_member.len() as u32, None); @@ -275,7 +275,7 @@ impl Pallet { pub fn swap_axons( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, - netuid_is_member: &Vec, + netuid_is_member: &[u16], weight: &mut Weight, ) -> DispatchResult { for netuid in netuid_is_member.iter() { @@ -368,7 +368,7 @@ impl Pallet { pub fn swap_uids( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, - netuid_is_member: &Vec, + netuid_is_member: &[u16], weight: &mut Weight, ) -> DispatchResult { for netuid in netuid_is_member.iter() { @@ -396,7 +396,7 @@ impl Pallet { pub fn swap_prometheus( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, - netuid_is_member: &Vec, + netuid_is_member: &[u16], weight: &mut Weight, ) -> DispatchResult { for netuid in netuid_is_member.iter() { @@ -425,10 +425,15 @@ impl Pallet { new_hotkey: &T::AccountId, weight: &mut Weight, ) -> DispatchResult { - let stakes: Vec<(T::AccountId, (u64, u64))> = TotalHotkeyColdkeyStakesThisInterval::::iter_prefix(old_hotkey).collect(); + let stakes: Vec<(T::AccountId, (u64, u64))> = + TotalHotkeyColdkeyStakesThisInterval::::iter_prefix(old_hotkey).collect(); log::info!("Stakes to swap: {:?}", stakes); for (coldkey, stake) in stakes { - log::info!("Swapping stake for coldkey: {:?}, stake: {:?}", coldkey, stake); + log::info!( + "Swapping stake for coldkey: {:?}, stake: {:?}", + coldkey, + stake + ); TotalHotkeyColdkeyStakesThisInterval::::insert(new_hotkey, &coldkey, stake); TotalHotkeyColdkeyStakesThisInterval::::remove(old_hotkey, &coldkey); weight.saturating_accrue(T::DbWeight::get().writes(2)); // One write for insert and one for remove diff --git a/pallets/subtensor/tests/swap.rs b/pallets/subtensor/tests/swap.rs index d6052c8fc5..980f5b5a5f 100644 --- a/pallets/subtensor/tests/swap.rs +++ b/pallets/subtensor/tests/swap.rs @@ -145,13 +145,16 @@ fn test_do_swap_hotkey_ok_robust() { coldkeys.push(U256::from(i * 2 + 11)); } - // Setup initial state for netuid in 1..=num_subnets { add_network(netuid, tempo, 0); SubtensorModule::set_max_registrations_per_block(netuid, 20); SubtensorModule::set_target_registrations_per_interval(netuid, 1000); - log::info!("Registrations this interval for netuid {:?} is {:?}", netuid, SubtensorModule::get_target_registrations_per_interval(netuid)); + log::info!( + "Registrations this interval for netuid {:?} is {:?}", + netuid, + SubtensorModule::get_target_registrations_per_interval(netuid) + ); for i in 0..10 { register_ok_neuron(netuid, old_hotkeys[i], coldkeys[i], 0); } @@ -211,7 +214,9 @@ fn test_do_swap_hotkey_ok_robust() { let mut weight = Weight::zero(); // UIDs - for netuid in SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() { + for netuid in + SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() + { assert_eq!( Uids::::get(netuid, &new_hotkeys[i]), Uids::::get(netuid, &old_hotkeys[i]) @@ -219,7 +224,9 @@ fn test_do_swap_hotkey_ok_robust() { } // Prometheus - for netuid in SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() { + for netuid in + SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() + { assert_eq!( Prometheus::::get(netuid, &new_hotkeys[i]), Prometheus::::get(netuid, &old_hotkeys[i]) @@ -227,7 +234,9 @@ fn test_do_swap_hotkey_ok_robust() { } // LoadedEmission - for netuid in SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() { + for netuid in + SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() + { assert_eq!( LoadedEmission::::get(netuid).unwrap(), LoadedEmission::::get(netuid).unwrap() @@ -235,9 +244,17 @@ fn test_do_swap_hotkey_ok_robust() { } // IsNetworkMember - for netuid in SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() { - assert!(IsNetworkMember::::contains_key(&new_hotkeys[i], netuid)); - assert!(!IsNetworkMember::::contains_key(&old_hotkeys[i], netuid)); + for netuid in + SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() + { + assert!(IsNetworkMember::::contains_key( + &new_hotkeys[i], + netuid + )); + assert!(!IsNetworkMember::::contains_key( + &old_hotkeys[i], + netuid + )); } // Owner @@ -833,7 +850,12 @@ fn test_swap_keys_success() { // Verify the swap for netuid in &netuid_is_member { - log::info!("neutuid, uid, hotkey: {:?}, {:?}, {:?}", netuid, uid, new_hotkey); + log::info!( + "neutuid, uid, hotkey: {:?}, {:?}, {:?}", + netuid, + uid, + new_hotkey + ); assert_eq!(Keys::::get(netuid, uid), new_hotkey); } }); From 6ddcfe2cb63a724650a9d6e861fc8435557ee54c Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Mon, 17 Jun 2024 16:02:11 +0400 Subject: [PATCH 03/27] chore: clippy --- pallets/subtensor/tests/swap.rs | 189 ++++++++++++++++---------------- 1 file changed, 94 insertions(+), 95 deletions(-) diff --git a/pallets/subtensor/tests/swap.rs b/pallets/subtensor/tests/swap.rs index 980f5b5a5f..c9cb2a7af6 100644 --- a/pallets/subtensor/tests/swap.rs +++ b/pallets/subtensor/tests/swap.rs @@ -55,24 +55,24 @@ fn test_do_swap_hotkey_ok() { // Verify raw storage maps // Stake - for (coldkey, stake_amount) in Stake::::iter_prefix(&old_hotkey) { - assert_eq!(Stake::::get(&new_hotkey, &coldkey), stake_amount); + for (coldkey, stake_amount) in Stake::::iter_prefix(old_hotkey) { + assert_eq!(Stake::::get(new_hotkey, coldkey), stake_amount); } let mut weight = Weight::zero(); // UIDs for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight).unwrap() { assert_eq!( - Uids::::get(netuid, &new_hotkey), - Uids::::get(netuid, &old_hotkey) + Uids::::get(netuid, new_hotkey), + Uids::::get(netuid, old_hotkey) ); } // Prometheus for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight).unwrap() { assert_eq!( - Prometheus::::get(netuid, &new_hotkey), - Prometheus::::get(netuid, &old_hotkey) + Prometheus::::get(netuid, new_hotkey), + Prometheus::::get(netuid, old_hotkey) ); } @@ -86,43 +86,43 @@ fn test_do_swap_hotkey_ok() { // IsNetworkMember for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight).unwrap() { - assert!(IsNetworkMember::::contains_key(&new_hotkey, netuid)); - assert!(!IsNetworkMember::::contains_key(&old_hotkey, netuid)); + assert!(IsNetworkMember::::contains_key(new_hotkey, netuid)); + assert!(!IsNetworkMember::::contains_key(old_hotkey, netuid)); } // Owner - assert_eq!(Owner::::get(&new_hotkey), coldkey); + assert_eq!(Owner::::get(new_hotkey), coldkey); // TotalHotkeyStake assert_eq!( - TotalHotkeyStake::::get(&new_hotkey), - TotalHotkeyStake::::get(&old_hotkey) + TotalHotkeyStake::::get(new_hotkey), + TotalHotkeyStake::::get(old_hotkey) ); // Delegates assert_eq!( - Delegates::::get(&new_hotkey), - Delegates::::get(&old_hotkey) + Delegates::::get(new_hotkey), + Delegates::::get(old_hotkey) ); // LastTxBlock assert_eq!( - LastTxBlock::::get(&new_hotkey), - LastTxBlock::::get(&old_hotkey) + LastTxBlock::::get(new_hotkey), + LastTxBlock::::get(old_hotkey) ); // Axons for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight).unwrap() { assert_eq!( - Axons::::get(netuid, &new_hotkey), - Axons::::get(netuid, &old_hotkey) + Axons::::get(netuid, new_hotkey), + Axons::::get(netuid, old_hotkey) ); } // TotalHotkeyColdkeyStakesThisInterval assert_eq!( - TotalHotkeyColdkeyStakesThisInterval::::get(&new_hotkey, &coldkey), - TotalHotkeyColdkeyStakesThisInterval::::get(&old_hotkey, &coldkey) + TotalHotkeyColdkeyStakesThisInterval::::get(new_hotkey, coldkey), + TotalHotkeyColdkeyStakesThisInterval::::get(old_hotkey, coldkey) ); }); } @@ -161,8 +161,8 @@ fn test_do_swap_hotkey_ok_robust() { } // Add balance to coldkeys for swap cost - for i in 0..10 { - SubtensorModule::add_balance_to_coldkey_account(&coldkeys[i], swap_cost); + for coldkey in coldkeys.iter().take(10) { + SubtensorModule::add_balance_to_coldkey_account(coldkey, swap_cost); } // Perform the swaps for only two hotkeys @@ -178,7 +178,7 @@ fn test_do_swap_hotkey_ok_robust() { )); // Verify the swaps - for netuid in 1..=num_subnets { + for _netuid in 1..=num_subnets { for i in 0..10 { if i == 0 || i == 1 { assert_eq!( @@ -208,8 +208,8 @@ fn test_do_swap_hotkey_ok_robust() { // Verify raw storage maps // Stake - for (coldkey, stake_amount) in Stake::::iter_prefix(&old_hotkeys[i]) { - assert_eq!(Stake::::get(&new_hotkeys[i], &coldkey), stake_amount); + for (coldkey, stake_amount) in Stake::::iter_prefix(old_hotkeys[i]) { + assert_eq!(Stake::::get(new_hotkeys[i], coldkey), stake_amount); } let mut weight = Weight::zero(); @@ -218,8 +218,8 @@ fn test_do_swap_hotkey_ok_robust() { SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() { assert_eq!( - Uids::::get(netuid, &new_hotkeys[i]), - Uids::::get(netuid, &old_hotkeys[i]) + Uids::::get(netuid, new_hotkeys[i]), + Uids::::get(netuid, old_hotkeys[i]) ); } @@ -228,8 +228,8 @@ fn test_do_swap_hotkey_ok_robust() { SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() { assert_eq!( - Prometheus::::get(netuid, &new_hotkeys[i]), - Prometheus::::get(netuid, &old_hotkeys[i]) + Prometheus::::get(netuid, new_hotkeys[i]), + Prometheus::::get(netuid, old_hotkeys[i]) ); } @@ -248,17 +248,17 @@ fn test_do_swap_hotkey_ok_robust() { SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() { assert!(IsNetworkMember::::contains_key( - &new_hotkeys[i], + new_hotkeys[i], netuid )); assert!(!IsNetworkMember::::contains_key( - &old_hotkeys[i], + old_hotkeys[i], netuid )); } // Owner - assert_eq!(Owner::::get(&new_hotkeys[i]), coldkeys[i]); + assert_eq!(Owner::::get(new_hotkeys[i]), coldkeys[i]); } else { // Ensure other hotkeys remain unchanged assert_eq!( @@ -312,7 +312,7 @@ fn test_swap_owner_success() { let mut weight = Weight::zero(); // Initialize Owner for old_hotkey - Owner::::insert(&old_hotkey, &coldkey); + Owner::::insert(old_hotkey, coldkey); // Perform the swap assert_ok!(SubtensorModule::swap_owner( @@ -323,8 +323,8 @@ fn test_swap_owner_success() { )); // Verify the swap - assert_eq!(Owner::::get(&new_hotkey), coldkey); - assert!(!Owner::::contains_key(&old_hotkey)); + assert_eq!(Owner::::get(new_hotkey), coldkey); + assert!(!Owner::::contains_key(old_hotkey)); }); } @@ -337,7 +337,7 @@ fn test_swap_owner_old_hotkey_not_exist() { let mut weight = Weight::zero(); // Ensure old_hotkey does not exist - assert!(!Owner::::contains_key(&old_hotkey)); + assert!(!Owner::::contains_key(old_hotkey)); // Perform the swap assert_ok!(SubtensorModule::swap_owner( @@ -348,8 +348,8 @@ fn test_swap_owner_old_hotkey_not_exist() { )); // Verify the swap - assert_eq!(Owner::::get(&new_hotkey), coldkey); - assert!(!Owner::::contains_key(&old_hotkey)); + assert_eq!(Owner::::get(new_hotkey), coldkey); + assert!(!Owner::::contains_key(old_hotkey)); }); } @@ -363,8 +363,8 @@ fn test_swap_owner_new_hotkey_already_exists() { let mut weight = Weight::zero(); // Initialize Owner for old_hotkey and new_hotkey - Owner::::insert(&old_hotkey, &coldkey); - Owner::::insert(&new_hotkey, &another_coldkey); + Owner::::insert(old_hotkey, coldkey); + Owner::::insert(new_hotkey, another_coldkey); // Perform the swap assert_ok!(SubtensorModule::swap_owner( @@ -375,8 +375,8 @@ fn test_swap_owner_new_hotkey_already_exists() { )); // Verify the swap - assert_eq!(Owner::::get(&new_hotkey), coldkey); - assert!(!Owner::::contains_key(&old_hotkey)); + assert_eq!(Owner::::get(new_hotkey), coldkey); + assert!(!Owner::::contains_key(old_hotkey)); }); } @@ -389,7 +389,7 @@ fn test_swap_owner_weight_update() { let mut weight = Weight::zero(); // Initialize Owner for old_hotkey - Owner::::insert(&old_hotkey, &coldkey); + Owner::::insert(old_hotkey, coldkey); // Perform the swap assert_ok!(SubtensorModule::swap_owner( @@ -414,7 +414,7 @@ fn test_swap_total_hotkey_stake_success() { let mut weight = Weight::zero(); // Initialize TotalHotkeyStake for old_hotkey - TotalHotkeyStake::::insert(&old_hotkey, total_stake); + TotalHotkeyStake::::insert(old_hotkey, total_stake); // Perform the swap assert_ok!(SubtensorModule::swap_total_hotkey_stake( @@ -424,8 +424,8 @@ fn test_swap_total_hotkey_stake_success() { )); // Verify the swap - assert_eq!(TotalHotkeyStake::::get(&new_hotkey), total_stake); - assert!(!TotalHotkeyStake::::contains_key(&old_hotkey)); + assert_eq!(TotalHotkeyStake::::get(new_hotkey), total_stake); + assert!(!TotalHotkeyStake::::contains_key(old_hotkey)); }); } @@ -437,7 +437,7 @@ fn test_swap_total_hotkey_stake_old_hotkey_not_exist() { let mut weight = Weight::zero(); // Ensure old_hotkey does not exist - assert!(!TotalHotkeyStake::::contains_key(&old_hotkey)); + assert!(!TotalHotkeyStake::::contains_key(old_hotkey)); // Perform the swap assert_ok!(SubtensorModule::swap_total_hotkey_stake( @@ -447,7 +447,7 @@ fn test_swap_total_hotkey_stake_old_hotkey_not_exist() { )); // Verify that new_hotkey does not have a stake - assert!(!TotalHotkeyStake::::contains_key(&new_hotkey)); + assert!(!TotalHotkeyStake::::contains_key(new_hotkey)); }); } @@ -460,7 +460,7 @@ fn test_swap_total_hotkey_stake_weight_update() { let mut weight = Weight::zero(); // Initialize TotalHotkeyStake for old_hotkey - TotalHotkeyStake::::insert(&old_hotkey, total_stake); + TotalHotkeyStake::::insert(old_hotkey, total_stake); // Perform the swap assert_ok!(SubtensorModule::swap_total_hotkey_stake( @@ -484,7 +484,7 @@ fn test_swap_delegates_success() { let mut weight = Weight::zero(); // Initialize Delegates for old_hotkey - Delegates::::insert(&old_hotkey, delegate_take); + Delegates::::insert(old_hotkey, delegate_take); // Perform the swap assert_ok!(SubtensorModule::swap_delegates( @@ -494,8 +494,8 @@ fn test_swap_delegates_success() { )); // Verify the swap - assert_eq!(Delegates::::get(&new_hotkey), delegate_take); - assert!(!Delegates::::contains_key(&old_hotkey)); + assert_eq!(Delegates::::get(new_hotkey), delegate_take); + assert!(!Delegates::::contains_key(old_hotkey)); }); } @@ -507,7 +507,7 @@ fn test_swap_delegates_old_hotkey_not_exist() { let mut weight = Weight::zero(); // Ensure old_hotkey does not exist - assert!(!Delegates::::contains_key(&old_hotkey)); + assert!(!Delegates::::contains_key(old_hotkey)); // Perform the swap assert_ok!(SubtensorModule::swap_delegates( @@ -517,7 +517,7 @@ fn test_swap_delegates_old_hotkey_not_exist() { )); // Verify that new_hotkey does not have a delegate - assert!(!Delegates::::contains_key(&new_hotkey)); + assert!(!Delegates::::contains_key(new_hotkey)); }); } @@ -530,7 +530,7 @@ fn test_swap_delegates_weight_update() { let mut weight = Weight::zero(); // Initialize Delegates for old_hotkey - Delegates::::insert(&old_hotkey, delegate_take); + Delegates::::insert(old_hotkey, delegate_take); // Perform the swap assert_ok!(SubtensorModule::swap_delegates( @@ -554,7 +554,7 @@ fn test_swap_last_tx_block_success() { let mut weight = Weight::zero(); // Initialize LastTxBlock for old_hotkey - LastTxBlock::::insert(&old_hotkey, last_tx_block); + LastTxBlock::::insert(old_hotkey, last_tx_block); // Perform the swap assert_ok!(SubtensorModule::swap_last_tx_block( @@ -564,8 +564,8 @@ fn test_swap_last_tx_block_success() { )); // Verify the swap - assert_eq!(LastTxBlock::::get(&new_hotkey), last_tx_block); - assert!(!LastTxBlock::::contains_key(&old_hotkey)); + assert_eq!(LastTxBlock::::get(new_hotkey), last_tx_block); + assert!(!LastTxBlock::::contains_key(old_hotkey)); }); } @@ -577,7 +577,7 @@ fn test_swap_last_tx_block_old_hotkey_not_exist() { let mut weight = Weight::zero(); // Ensure old_hotkey does not exist - assert!(!LastTxBlock::::contains_key(&old_hotkey)); + assert!(!LastTxBlock::::contains_key(old_hotkey)); // Perform the swap assert_ok!(SubtensorModule::swap_last_tx_block( @@ -587,7 +587,7 @@ fn test_swap_last_tx_block_old_hotkey_not_exist() { )); // Verify that new_hotkey does not have a last transaction block - assert!(!LastTxBlock::::contains_key(&new_hotkey)); + assert!(!LastTxBlock::::contains_key(new_hotkey)); }); } @@ -600,7 +600,7 @@ fn test_swap_last_tx_block_weight_update() { let mut weight = Weight::zero(); // Initialize LastTxBlock for old_hotkey - LastTxBlock::::insert(&old_hotkey, last_tx_block); + LastTxBlock::::insert(old_hotkey, last_tx_block); // Perform the swap assert_ok!(SubtensorModule::swap_last_tx_block( @@ -625,7 +625,7 @@ fn test_swap_stake_success() { let mut weight = Weight::zero(); // Initialize Stake for old_hotkey - Stake::::insert(&old_hotkey, &coldkey, stake_amount); + Stake::::insert(old_hotkey, coldkey, stake_amount); // Perform the swap assert_ok!(SubtensorModule::swap_stake( @@ -635,8 +635,8 @@ fn test_swap_stake_success() { )); // Verify the swap - assert_eq!(Stake::::get(&new_hotkey, &coldkey), stake_amount); - assert!(!Stake::::contains_key(&old_hotkey, &coldkey)); + assert_eq!(Stake::::get(new_hotkey, coldkey), stake_amount); + assert!(!Stake::::contains_key(old_hotkey, coldkey)); }); } @@ -650,10 +650,10 @@ fn test_swap_stake_old_hotkey_not_exist() { let mut weight = Weight::zero(); // Initialize Stake for old_hotkey - Stake::::insert(&old_hotkey, &coldkey, stake_amount); + Stake::::insert(old_hotkey, coldkey, stake_amount); // Ensure old_hotkey has a stake - assert!(Stake::::contains_key(&old_hotkey, &coldkey)); + assert!(Stake::::contains_key(old_hotkey, coldkey)); // Perform the swap assert_ok!(SubtensorModule::swap_stake( @@ -663,8 +663,8 @@ fn test_swap_stake_old_hotkey_not_exist() { )); // Verify that new_hotkey has the stake and old_hotkey does not - assert!(Stake::::contains_key(&new_hotkey, &coldkey)); - assert!(!Stake::::contains_key(&old_hotkey, &coldkey)); + assert!(Stake::::contains_key(new_hotkey, coldkey)); + assert!(!Stake::::contains_key(old_hotkey, coldkey)); }); } @@ -678,7 +678,7 @@ fn test_swap_stake_weight_update() { let mut weight = Weight::zero(); // Initialize Stake for old_hotkey - Stake::::insert(&old_hotkey, &coldkey, stake_amount); + Stake::::insert(old_hotkey, coldkey, stake_amount); // Perform the swap assert_ok!(SubtensorModule::swap_stake( @@ -703,7 +703,7 @@ fn test_swap_is_network_member_success() { // Initialize IsNetworkMember for old_hotkey for netuid in &netuid_is_member { - IsNetworkMember::::insert(&old_hotkey, netuid, true); + IsNetworkMember::::insert(old_hotkey, netuid, true); } // Perform the swap @@ -716,8 +716,8 @@ fn test_swap_is_network_member_success() { // Verify the swap for netuid in &netuid_is_member { - assert!(IsNetworkMember::::contains_key(&new_hotkey, netuid)); - assert!(!IsNetworkMember::::contains_key(&old_hotkey, netuid)); + assert!(IsNetworkMember::::contains_key(new_hotkey, netuid)); + assert!(!IsNetworkMember::::contains_key(old_hotkey, netuid)); } }); } @@ -732,7 +732,7 @@ fn test_swap_is_network_member_weight_update() { // Initialize IsNetworkMember for old_hotkey for netuid in &netuid_is_member { - IsNetworkMember::::insert(&old_hotkey, netuid, true); + IsNetworkMember::::insert(old_hotkey, netuid, true); } // Perform the swap @@ -769,7 +769,7 @@ fn test_swap_axons_success() { // Initialize Axons for old_hotkey for netuid in &netuid_is_member { - Axons::::insert(netuid, &old_hotkey, axon_info.clone()); + Axons::::insert(netuid, old_hotkey, axon_info.clone()); } // Perform the swap @@ -782,8 +782,8 @@ fn test_swap_axons_success() { // Verify the swap for netuid in &netuid_is_member { - assert_eq!(Axons::::get(netuid, &new_hotkey).unwrap(), axon_info); - assert!(!Axons::::contains_key(netuid, &old_hotkey)); + assert_eq!(Axons::::get(netuid, new_hotkey).unwrap(), axon_info); + assert!(!Axons::::contains_key(netuid, old_hotkey)); } }); } @@ -808,7 +808,7 @@ fn test_swap_axons_weight_update() { // Initialize Axons for old_hotkey for netuid in &netuid_is_member { - Axons::::insert(netuid, &old_hotkey, axon_info.clone()); + Axons::::insert(netuid, old_hotkey, axon_info.clone()); } // Perform the swap @@ -837,7 +837,7 @@ fn test_swap_keys_success() { // Initialize Keys for old_hotkey for netuid in &netuid_is_member { log::info!("Inserting old_hotkey:{:?} netuid:{:?}", old_hotkey, netuid); - Keys::::insert(*netuid, uid, &old_hotkey); + Keys::::insert(*netuid, uid, old_hotkey); } // Perform the swap @@ -872,7 +872,7 @@ fn test_swap_keys_weight_update() { // Initialize Keys for old_hotkey for netuid in &netuid_is_member { - Keys::::insert(*netuid, uid, old_hotkey.clone()); + Keys::::insert(*netuid, uid, old_hotkey); } // Perform the swap @@ -903,9 +903,9 @@ fn test_swap_loaded_emission_success() { for netuid in &netuid_is_member { LoadedEmission::::mutate(netuid, |emission_exists| { if let Some(emissions) = emission_exists { - emissions.push((old_hotkey.clone(), se, ve)); + emissions.push((old_hotkey, se, ve)); } else { - *emission_exists = Some(vec![(old_hotkey.clone(), se, ve)]); + *emission_exists = Some(vec![(old_hotkey, se, ve)]); } }); } @@ -942,9 +942,9 @@ fn test_swap_loaded_emission_weight_update() { for netuid in &netuid_is_member { LoadedEmission::::mutate(netuid, |emission_exists| { if let Some(emissions) = emission_exists { - emissions.push((old_hotkey.clone(), se, ve)); + emissions.push((old_hotkey, se, ve)); } else { - *emission_exists = Some(vec![(old_hotkey.clone(), se, ve)]); + *emission_exists = Some(vec![(old_hotkey, se, ve)]); } }); } @@ -974,7 +974,7 @@ fn test_swap_uids_success() { // Initialize Uids for old_hotkey for netuid in &netuid_is_member { - Uids::::insert(netuid, &old_hotkey, uid); + Uids::::insert(netuid, old_hotkey, uid); } // Perform the swap @@ -987,8 +987,8 @@ fn test_swap_uids_success() { // Verify the swap for netuid in &netuid_is_member { - assert_eq!(Uids::::get(netuid, &new_hotkey).unwrap(), uid); - assert!(!Uids::::contains_key(netuid, &old_hotkey)); + assert_eq!(Uids::::get(netuid, new_hotkey).unwrap(), uid); + assert!(!Uids::::contains_key(netuid, old_hotkey)); } }); } @@ -1004,7 +1004,7 @@ fn test_swap_uids_weight_update() { // Initialize Uids for old_hotkey for netuid in &netuid_is_member { - Uids::::insert(netuid, &old_hotkey, uid); + Uids::::insert(netuid, old_hotkey, uid); } // Perform the swap @@ -1038,7 +1038,7 @@ fn test_swap_prometheus_success() { // Initialize Prometheus for old_hotkey for netuid in &netuid_is_member { - Prometheus::::insert(netuid, &old_hotkey, prometheus_info.clone()); + Prometheus::::insert(netuid, old_hotkey, prometheus_info.clone()); } // Perform the swap @@ -1052,10 +1052,10 @@ fn test_swap_prometheus_success() { // Verify the swap for netuid in &netuid_is_member { assert_eq!( - Prometheus::::get(netuid, &new_hotkey).unwrap(), + Prometheus::::get(netuid, new_hotkey).unwrap(), prometheus_info ); - assert!(!Prometheus::::contains_key(netuid, &old_hotkey)); + assert!(!Prometheus::::contains_key(netuid, old_hotkey)); } }); } @@ -1077,7 +1077,7 @@ fn test_swap_prometheus_weight_update() { // Initialize Prometheus for old_hotkey for netuid in &netuid_is_member { - Prometheus::::insert(netuid, &old_hotkey, prometheus_info.clone()); + Prometheus::::insert(netuid, old_hotkey, prometheus_info.clone()); } // Perform the swap @@ -1104,7 +1104,7 @@ fn test_swap_total_hotkey_coldkey_stakes_this_interval_success() { let mut weight = Weight::zero(); // Initialize TotalHotkeyColdkeyStakesThisInterval for old_hotkey - TotalHotkeyColdkeyStakesThisInterval::::insert(&old_hotkey, &coldkey, stake); + TotalHotkeyColdkeyStakesThisInterval::::insert(old_hotkey, coldkey, stake); // Perform the swap assert_ok!( @@ -1117,12 +1117,11 @@ fn test_swap_total_hotkey_coldkey_stakes_this_interval_success() { // Verify the swap assert_eq!( - TotalHotkeyColdkeyStakesThisInterval::::get(&new_hotkey, &coldkey), + TotalHotkeyColdkeyStakesThisInterval::::get(new_hotkey, coldkey), stake ); assert!(!TotalHotkeyColdkeyStakesThisInterval::::contains_key( - &old_hotkey, - &coldkey + old_hotkey, coldkey )); }); } @@ -1137,7 +1136,7 @@ fn test_swap_total_hotkey_coldkey_stakes_this_interval_weight_update() { let mut weight = Weight::zero(); // Initialize TotalHotkeyColdkeyStakesThisInterval for old_hotkey - TotalHotkeyColdkeyStakesThisInterval::::insert(&old_hotkey, &coldkey, stake); + TotalHotkeyColdkeyStakesThisInterval::::insert(old_hotkey, coldkey, stake); // Perform the swap assert_ok!( From 45e828d1f35b749c4ee87b517ce14f9e2859fe19 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Mon, 17 Jun 2024 17:31:13 +0400 Subject: [PATCH 04/27] chore: give 1k on faucet for easier to create networks locally --- pallets/subtensor/src/registration.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/registration.rs b/pallets/subtensor/src/registration.rs index fe9e18702f..9d95f52efa 100644 --- a/pallets/subtensor/src/registration.rs +++ b/pallets/subtensor/src/registration.rs @@ -394,7 +394,7 @@ impl Pallet { UsedWork::::insert(work.clone(), current_block_number); // --- 5. Add Balance via faucet. - let balance_to_add: u64 = 100_000_000_000; + let balance_to_add: u64 = 1_000_000_000_000; Self::coinbase(100_000_000_000); // We are creating tokens here from the coinbase. Self::add_balance_to_coldkey_account(&coldkey, balance_to_add); From c12ec3748134a8bae5a347529de21331234b7f90 Mon Sep 17 00:00:00 2001 From: Keith Date: Mon, 17 Jun 2024 23:25:14 +0900 Subject: [PATCH 05/27] Correct the expected weights on the register extrinsic --- pallets/subtensor/tests/registration.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pallets/subtensor/tests/registration.rs b/pallets/subtensor/tests/registration.rs index 0da10bc48e..8af83ad747 100644 --- a/pallets/subtensor/tests/registration.rs +++ b/pallets/subtensor/tests/registration.rs @@ -38,7 +38,9 @@ fn test_registration_subscribe_ok_dispatch_info_ok() { assert_eq!( call.get_dispatch_info(), DispatchInfo { - weight: frame_support::weights::Weight::from_parts(192_000_000, 0), + weight: frame_support::weights::Weight::from_parts(192_000_000, 0) + .saturating_add(::DbWeight::get().reads(24)) + .saturating_add(::DbWeight::get().writes(22)), class: DispatchClass::Normal, pays_fee: Pays::No } From 5eaa0883e232fc4eae653e8b8ffded3f323f3510 Mon Sep 17 00:00:00 2001 From: distributedstatemachine <112424909+distributedstatemachine@users.noreply.github.com> Date: Mon, 17 Jun 2024 21:26:39 +0400 Subject: [PATCH 06/27] Update pallets/subtensor/src/swap.rs Co-authored-by: Keith --- pallets/subtensor/src/swap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/swap.rs b/pallets/subtensor/src/swap.rs index aa0bbf812c..8185ba0f9f 100644 --- a/pallets/subtensor/src/swap.rs +++ b/pallets/subtensor/src/swap.rs @@ -7,7 +7,7 @@ impl Pallet { /// /// # Arguments /// - /// * `origin` - The origin of the transaction. + /// * `origin` - The origin of the transaction, and also the coldkey account. /// * `old_hotkey` - The old hotkey to be swapped. /// * `new_hotkey` - The new hotkey to replace the old one. /// From 969a4f89bbf325eb695f9d8904448ca7b0ee7a21 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Mon, 17 Jun 2024 21:31:34 +0400 Subject: [PATCH 07/27] chore: updates from using real weights in tests --- pallets/subtensor/tests/serving.rs | 4 ++-- pallets/subtensor/tests/staking.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pallets/subtensor/tests/serving.rs b/pallets/subtensor/tests/serving.rs index 851edeee27..41e9888ccb 100644 --- a/pallets/subtensor/tests/serving.rs +++ b/pallets/subtensor/tests/serving.rs @@ -50,7 +50,7 @@ fn test_serving_subscribe_ok_dispatch_info_ok() { assert_eq!( call.get_dispatch_info(), DispatchInfo { - weight: frame_support::weights::Weight::from_parts(46_000_000, 0), + weight: frame_support::weights::Weight::from_parts(246_000_000, 0), class: DispatchClass::Normal, pays_fee: Pays::No } @@ -295,7 +295,7 @@ fn test_prometheus_serving_subscribe_ok_dispatch_info_ok() { assert_eq!( call.get_dispatch_info(), DispatchInfo { - weight: frame_support::weights::Weight::from_parts(45_000_000, 0), + weight: frame_support::weights::Weight::from_parts(245_000_000, 0), class: DispatchClass::Normal, pays_fee: Pays::No } diff --git a/pallets/subtensor/tests/staking.rs b/pallets/subtensor/tests/staking.rs index 766b3a495b..529332f04b 100644 --- a/pallets/subtensor/tests/staking.rs +++ b/pallets/subtensor/tests/staking.rs @@ -26,7 +26,7 @@ fn test_add_stake_dispatch_info_ok() { assert_eq!( call.get_dispatch_info(), DispatchInfo { - weight: frame_support::weights::Weight::from_parts(124_000_000, 0), + weight: frame_support::weights::Weight::from_parts(1_074_000_000, 0), class: DispatchClass::Normal, pays_fee: Pays::No } @@ -532,7 +532,7 @@ fn test_remove_stake_dispatch_info_ok() { assert_eq!( call.get_dispatch_info(), DispatchInfo { - weight: frame_support::weights::Weight::from_parts(111_000_000, 0) + weight: frame_support::weights::Weight::from_parts(1_061_000_000, 0) .add_proof_size(43991), class: DispatchClass::Normal, pays_fee: Pays::No From 6b68263fdacf3d5da76e010e58cc882e842b7037 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Mon, 17 Jun 2024 22:21:54 +0400 Subject: [PATCH 08/27] chore: review comments , make swap cost a constant --- pallets/admin-utils/tests/mock.rs | 2 ++ pallets/subtensor/src/lib.rs | 8 ++++++++ pallets/subtensor/src/swap.rs | 22 ++++++++++++---------- pallets/subtensor/src/utils.rs | 5 +++++ pallets/subtensor/tests/mock.rs | 2 ++ pallets/subtensor/tests/registration.rs | 4 +++- runtime/src/lib.rs | 1 + 7 files changed, 33 insertions(+), 11 deletions(-) diff --git a/pallets/admin-utils/tests/mock.rs b/pallets/admin-utils/tests/mock.rs index 16a1f79f4f..a78eb6d3da 100644 --- a/pallets/admin-utils/tests/mock.rs +++ b/pallets/admin-utils/tests/mock.rs @@ -110,6 +110,7 @@ parameter_types! { pub const InitialSubnetLimit: u16 = 10; // Max 10 subnets. pub const InitialNetworkRateLimit: u64 = 0; pub const InitialTargetStakesPerInterval: u16 = 1; + pub const InitialHotkeySwapCost: u64 = 1_000_000_000; pub const InitialAlphaHigh: u16 = 58982; // Represents 0.9 as per the production default pub const InitialAlphaLow: u16 = 45875; // Represents 0.7 as per the production default pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn @@ -164,6 +165,7 @@ impl pallet_subtensor::Config for Test { type InitialSubnetLimit = InitialSubnetLimit; type InitialNetworkRateLimit = InitialNetworkRateLimit; type InitialTargetStakesPerInterval = InitialTargetStakesPerInterval; + type HotkeySwapCost = InitialHotkeySwapCost; type AlphaHigh = InitialAlphaHigh; type AlphaLow = InitialAlphaLow; type LiquidAlphaOn = InitialLiquidAlphaOn; diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 18ea0779f7..504a9340e3 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -241,6 +241,9 @@ pub mod pallet { /// Initial target stakes per interval issuance. #[pallet::constant] type InitialTargetStakesPerInterval: Get; + /// Cost of swapping a hotkey. + #[pallet::constant] + type HotkeySwapCost: Get; /// The upper bound for the alpha parameter. Used for Liquid Alpha. #[pallet::constant] type AlphaHigh: Get; @@ -274,6 +277,11 @@ pub mod pallet { pub fn TotalSupply() -> u64 { 21_000_000_000_000_000 // Rao => 21_000_000 Tao } + /// Hotkey swap cost. + #[pallet::type_value] + pub fn HotkeySwapCost() -> u64 { + 1_000_000_000 + } /// Default total stake. #[pallet::type_value] pub fn DefaultDefaultTake() -> u16 { diff --git a/pallets/subtensor/src/swap.rs b/pallets/subtensor/src/swap.rs index 8185ba0f9f..873dcaa12c 100644 --- a/pallets/subtensor/src/swap.rs +++ b/pallets/subtensor/src/swap.rs @@ -29,7 +29,15 @@ impl Pallet { ) -> DispatchResultWithPostInfo { let coldkey = ensure_signed(origin)?; - let mut weight = T::DbWeight::get().reads_writes(2, 0); + let mut weight = T::DbWeight::get().reads(2); + + ensure!(old_hotkey != new_hotkey, Error::::NewHotKeyIsSameWithOld); + ensure!( + !Self::is_hotkey_registered_on_any_network(new_hotkey), + Error::::HotKeyAlreadyRegisteredInSubNet + ); + + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 0)); ensure!( Self::coldkey_owns_hotkey(&coldkey, old_hotkey), Error::::NonAssociatedColdKey @@ -41,18 +49,12 @@ impl Pallet { Error::::HotKeySetTxRateLimitExceeded ); - weight.saturating_accrue(T::DbWeight::get().reads(2)); - - ensure!(old_hotkey != new_hotkey, Error::::NewHotKeyIsSameWithOld); - ensure!( - !Self::is_hotkey_registered_on_any_network(new_hotkey), - Error::::HotKeyAlreadyRegisteredInSubNet - ); - weight .saturating_accrue(T::DbWeight::get().reads((TotalNetworks::::get() + 1u16) as u64)); - let swap_cost = 1_000_000_000u64; + let swap_cost = Self::get_hotkey_swap_cost(); + log::info!("Swap cost: {:?}", swap_cost); + ensure!( Self::can_remove_balance_from_coldkey_account(&coldkey, swap_cost), Error::::NotEnoughBalanceToPaySwapHotKey diff --git a/pallets/subtensor/src/utils.rs b/pallets/subtensor/src/utils.rs index 193d625fc2..15d659a51d 100644 --- a/pallets/subtensor/src/utils.rs +++ b/pallets/subtensor/src/utils.rs @@ -3,6 +3,7 @@ use crate::{ system::{ensure_root, ensure_signed_or_root}, Error, }; +use sp_core::Get; use sp_core::U256; use substrate_fixed::types::I32F32; @@ -663,6 +664,10 @@ impl Pallet { NominatorMinRequiredStake::::put(min_stake); } + pub fn get_hotkey_swap_cost() -> u64 { + T::HotkeySwapCost::get() + } + pub fn get_alpha_values(netuid: u16) -> (u16, u16) { AlphaValues::::get(netuid) } diff --git a/pallets/subtensor/tests/mock.rs b/pallets/subtensor/tests/mock.rs index 4ec4aa4150..240f424489 100644 --- a/pallets/subtensor/tests/mock.rs +++ b/pallets/subtensor/tests/mock.rs @@ -161,6 +161,7 @@ parameter_types! { pub const InitialSubnetLimit: u16 = 10; // Max 10 subnets. pub const InitialNetworkRateLimit: u64 = 0; pub const InitialTargetStakesPerInterval: u16 = 2; + pub const InitialHotkeySwapCost: u64 = 1_000_000_000; pub const InitialAlphaHigh: u16 = 58982; // Represents 0.9 as per the production default pub const InitialAlphaLow: u16 = 45875; // Represents 0.7 as per the production default pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn @@ -370,6 +371,7 @@ impl pallet_subtensor::Config for Test { type InitialSubnetLimit = InitialSubnetLimit; type InitialNetworkRateLimit = InitialNetworkRateLimit; type InitialTargetStakesPerInterval = InitialTargetStakesPerInterval; + type HotkeySwapCost = InitialHotkeySwapCost; type AlphaHigh = InitialAlphaHigh; type AlphaLow = InitialAlphaLow; type LiquidAlphaOn = InitialLiquidAlphaOn; diff --git a/pallets/subtensor/tests/registration.rs b/pallets/subtensor/tests/registration.rs index 8af83ad747..77ec068fda 100644 --- a/pallets/subtensor/tests/registration.rs +++ b/pallets/subtensor/tests/registration.rs @@ -40,7 +40,9 @@ fn test_registration_subscribe_ok_dispatch_info_ok() { DispatchInfo { weight: frame_support::weights::Weight::from_parts(192_000_000, 0) .saturating_add(::DbWeight::get().reads(24)) - .saturating_add(::DbWeight::get().writes(22)), + .saturating_add( + ::DbWeight::get().writes(22) + ), class: DispatchClass::Normal, pays_fee: Pays::No } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 26b4aca4c9..af89c620c2 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -922,6 +922,7 @@ impl pallet_subtensor::Config for Runtime { type InitialSubnetLimit = SubtensorInitialSubnetLimit; type InitialNetworkRateLimit = SubtensorInitialNetworkRateLimit; type InitialTargetStakesPerInterval = SubtensorInitialTargetStakesPerInterval; + type HotkeySwapCost = ConstU64<1_000_000_000>; type AlphaHigh = InitialAlphaHigh; type AlphaLow = InitialAlphaLow; type LiquidAlphaOn = InitialLiquidAlphaOn; From ec27e77a43e38052eec20f34498079be695608f3 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Mon, 17 Jun 2024 22:37:26 +0400 Subject: [PATCH 09/27] chore: runtime consts --- runtime/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index af89c620c2..32a4f8b593 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -868,6 +868,7 @@ parameter_types! { pub const SubtensorInitialNetworkLockReductionInterval: u64 = 14 * 7200; pub const SubtensorInitialNetworkRateLimit: u64 = 7200; pub const SubtensorInitialTargetStakesPerInterval: u16 = 1; + pub const SubtensorInitialHotkeySwapCost: u64 = 1_000_000_000; pub const InitialAlphaHigh: u16 = 58982; // Represents 0.9 as per the production default pub const InitialAlphaLow: u16 = 45875; // Represents 0.7 as per the production default pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn @@ -922,7 +923,7 @@ impl pallet_subtensor::Config for Runtime { type InitialSubnetLimit = SubtensorInitialSubnetLimit; type InitialNetworkRateLimit = SubtensorInitialNetworkRateLimit; type InitialTargetStakesPerInterval = SubtensorInitialTargetStakesPerInterval; - type HotkeySwapCost = ConstU64<1_000_000_000>; + type HotkeySwapCost = SubtensorInitialHotkeySwapCost; type AlphaHigh = InitialAlphaHigh; type AlphaLow = InitialAlphaLow; type LiquidAlphaOn = InitialLiquidAlphaOn; From fc82551832fcb829cdeaec9000ff94823ff53c88 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 18 Jun 2024 01:09:59 +0400 Subject: [PATCH 10/27] chore: clear prefix for removing old value from stake map --- pallets/subtensor/src/swap.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pallets/subtensor/src/swap.rs b/pallets/subtensor/src/swap.rs index 873dcaa12c..5313113b7c 100644 --- a/pallets/subtensor/src/swap.rs +++ b/pallets/subtensor/src/swap.rs @@ -227,11 +227,13 @@ impl Pallet { ) -> DispatchResult { let mut writes = 0; let stakes: Vec<(T::AccountId, u64)> = Stake::::iter_prefix(old_hotkey).collect(); + let stake_count = stakes.len() as u32; for (coldkey, stake_amount) in stakes { Stake::::insert(new_hotkey, &coldkey, stake_amount); - Stake::::remove(old_hotkey, &coldkey); + let _ = Stake::::clear_prefix(old_hotkey, stake_count, None); writes += 2; // One write for insert and one for remove } + *weight += T::DbWeight::get().writes(writes as u64); Ok(()) } From 50574721d3d0958257b1a9a313b61fcca533646f Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 18 Jun 2024 01:26:04 +0400 Subject: [PATCH 11/27] chore: pr comments assert keys --- pallets/subtensor/tests/swap.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pallets/subtensor/tests/swap.rs b/pallets/subtensor/tests/swap.rs index c9cb2a7af6..04819211a6 100644 --- a/pallets/subtensor/tests/swap.rs +++ b/pallets/subtensor/tests/swap.rs @@ -178,7 +178,7 @@ fn test_do_swap_hotkey_ok_robust() { )); // Verify the swaps - for _netuid in 1..=num_subnets { + for netuid in 1..=num_subnets { for i in 0..10 { if i == 0 || i == 1 { assert_eq!( @@ -259,6 +259,13 @@ fn test_do_swap_hotkey_ok_robust() { // Owner assert_eq!(Owner::::get(new_hotkeys[i]), coldkeys[i]); + + // Keys + for (uid, hotkey) in Keys::::iter_prefix(netuid) { + if hotkey == old_hotkeys[i] { + assert_eq!(Keys::::get(netuid, uid), new_hotkeys[i]); + } + } } else { // Ensure other hotkeys remain unchanged assert_eq!( From dd9672ba0b575553bb5f6d0248b7f639e8b7a6b6 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 18 Jun 2024 01:28:57 +0400 Subject: [PATCH 12/27] chore: pr comments: remove last tx block --- pallets/subtensor/src/swap.rs | 24 ----------- pallets/subtensor/tests/swap.rs | 70 --------------------------------- 2 files changed, 94 deletions(-) diff --git a/pallets/subtensor/src/swap.rs b/pallets/subtensor/src/swap.rs index 5313113b7c..4f9eaf0477 100644 --- a/pallets/subtensor/src/swap.rs +++ b/pallets/subtensor/src/swap.rs @@ -65,7 +65,6 @@ impl Pallet { Self::swap_owner(old_hotkey, new_hotkey, &coldkey, &mut weight)?; Self::swap_total_hotkey_stake(old_hotkey, new_hotkey, &mut weight)?; Self::swap_delegates(old_hotkey, new_hotkey, &mut weight)?; - Self::swap_last_tx_block(old_hotkey, new_hotkey, &mut weight)?; Self::swap_stake(old_hotkey, new_hotkey, &mut weight)?; // Store the value of is_network_member for the old key @@ -185,29 +184,6 @@ impl Pallet { Ok(()) } - /// Swaps the last transaction block of the hotkey. - /// - /// # Arguments - /// - /// * `old_hotkey` - The old hotkey. - /// * `new_hotkey` - The new hotkey. - /// * `weight` - The weight of the transaction. - /// - /// # Returns - /// - /// * `Result<(), Error>` - The result of the operation. - pub fn swap_last_tx_block( - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - weight: &mut Weight, - ) -> DispatchResult { - if let Ok(last_tx) = LastTxBlock::::try_get(old_hotkey) { - LastTxBlock::::remove(old_hotkey); - LastTxBlock::::insert(new_hotkey, last_tx); - weight.saturating_accrue(T::DbWeight::get().writes(2)); - } - Ok(()) - } /// Swaps the stake of the hotkey. /// diff --git a/pallets/subtensor/tests/swap.rs b/pallets/subtensor/tests/swap.rs index 04819211a6..f73b6e3f2f 100644 --- a/pallets/subtensor/tests/swap.rs +++ b/pallets/subtensor/tests/swap.rs @@ -552,76 +552,6 @@ fn test_swap_delegates_weight_update() { }); } -#[test] -fn test_swap_last_tx_block_success() { - new_test_ext(1).execute_with(|| { - let old_hotkey = U256::from(1); - let new_hotkey = U256::from(2); - let last_tx_block = 100u64; - let mut weight = Weight::zero(); - - // Initialize LastTxBlock for old_hotkey - LastTxBlock::::insert(old_hotkey, last_tx_block); - - // Perform the swap - assert_ok!(SubtensorModule::swap_last_tx_block( - &old_hotkey, - &new_hotkey, - &mut weight - )); - - // Verify the swap - assert_eq!(LastTxBlock::::get(new_hotkey), last_tx_block); - assert!(!LastTxBlock::::contains_key(old_hotkey)); - }); -} - -#[test] -fn test_swap_last_tx_block_old_hotkey_not_exist() { - new_test_ext(1).execute_with(|| { - let old_hotkey = U256::from(1); - let new_hotkey = U256::from(2); - let mut weight = Weight::zero(); - - // Ensure old_hotkey does not exist - assert!(!LastTxBlock::::contains_key(old_hotkey)); - - // Perform the swap - assert_ok!(SubtensorModule::swap_last_tx_block( - &old_hotkey, - &new_hotkey, - &mut weight - )); - - // Verify that new_hotkey does not have a last transaction block - assert!(!LastTxBlock::::contains_key(new_hotkey)); - }); -} - -#[test] -fn test_swap_last_tx_block_weight_update() { - new_test_ext(1).execute_with(|| { - let old_hotkey = U256::from(1); - let new_hotkey = U256::from(2); - let last_tx_block = 100u64; - let mut weight = Weight::zero(); - - // Initialize LastTxBlock for old_hotkey - LastTxBlock::::insert(old_hotkey, last_tx_block); - - // Perform the swap - assert_ok!(SubtensorModule::swap_last_tx_block( - &old_hotkey, - &new_hotkey, - &mut weight - )); - - // Verify the weight update - let expected_weight = ::DbWeight::get().writes(2); - assert_eq!(weight, expected_weight); - }); -} - #[test] fn test_swap_stake_success() { new_test_ext(1).execute_with(|| { From 60019a91d063801f9dd93a286c9017009dfd473b Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 18 Jun 2024 01:36:55 +0400 Subject: [PATCH 13/27] chore: fmt --- pallets/subtensor/src/swap.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pallets/subtensor/src/swap.rs b/pallets/subtensor/src/swap.rs index 4f9eaf0477..e6f8fb6e6d 100644 --- a/pallets/subtensor/src/swap.rs +++ b/pallets/subtensor/src/swap.rs @@ -184,7 +184,6 @@ impl Pallet { Ok(()) } - /// Swaps the stake of the hotkey. /// /// # Arguments From 2cd90dd5312925114caa15f063dc22ee0de18ac1 Mon Sep 17 00:00:00 2001 From: Keith Date: Tue, 18 Jun 2024 11:52:55 +0900 Subject: [PATCH 14/27] Use concrete numbers for weight expectations --- pallets/subtensor/tests/registration.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pallets/subtensor/tests/registration.rs b/pallets/subtensor/tests/registration.rs index 77ec068fda..676d49a449 100644 --- a/pallets/subtensor/tests/registration.rs +++ b/pallets/subtensor/tests/registration.rs @@ -38,11 +38,7 @@ fn test_registration_subscribe_ok_dispatch_info_ok() { assert_eq!( call.get_dispatch_info(), DispatchInfo { - weight: frame_support::weights::Weight::from_parts(192_000_000, 0) - .saturating_add(::DbWeight::get().reads(24)) - .saturating_add( - ::DbWeight::get().writes(22) - ), + weight: frame_support::weights::Weight::from_parts(2_992_000_000, 0), class: DispatchClass::Normal, pays_fee: Pays::No } From 5743ae79d7c8de5fd8073da1b2ecfb931c6aa5c4 Mon Sep 17 00:00:00 2001 From: distributedstatemachine <112424909+distributedstatemachine@users.noreply.github.com> Date: Tue, 18 Jun 2024 09:28:45 +0400 Subject: [PATCH 15/27] Update pallets/subtensor/src/swap.rs Co-authored-by: orriin <167025436+orriin@users.noreply.github.com> --- pallets/subtensor/src/swap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/swap.rs b/pallets/subtensor/src/swap.rs index e6f8fb6e6d..0b527b935c 100644 --- a/pallets/subtensor/src/swap.rs +++ b/pallets/subtensor/src/swap.rs @@ -53,7 +53,7 @@ impl Pallet { .saturating_accrue(T::DbWeight::get().reads((TotalNetworks::::get() + 1u16) as u64)); let swap_cost = Self::get_hotkey_swap_cost(); - log::info!("Swap cost: {:?}", swap_cost); + log::debug!("Swap cost: {:?}", swap_cost); ensure!( Self::can_remove_balance_from_coldkey_account(&coldkey, swap_cost), From f358847c7eb02f6b557ca990f5e4b21e7aef57f7 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 18 Jun 2024 11:54:37 +0400 Subject: [PATCH 16/27] chore: add test_swap_hotkey_tx_rate_limit_exceeded --- pallets/subtensor/tests/swap.rs | 57 +++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/pallets/subtensor/tests/swap.rs b/pallets/subtensor/tests/swap.rs index f73b6e3f2f..3a2118c4a7 100644 --- a/pallets/subtensor/tests/swap.rs +++ b/pallets/subtensor/tests/swap.rs @@ -282,6 +282,63 @@ fn test_do_swap_hotkey_ok_robust() { }); } +#[test] +fn test_swap_hotkey_tx_rate_limit_exceeded() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + let old_hotkey = U256::from(1); + let new_hotkey_1 = U256::from(2); + let new_hotkey_2 = U256::from(4); + let coldkey = U256::from(3); + let swap_cost = 1_000_000_000u64*2; + + let tx_rate_limit = 1; + + // Get the current transaction rate limit + let current_tx_rate_limit = SubtensorModule::get_tx_rate_limit(); + log::info!("current_tx_rate_limit: {:?}", current_tx_rate_limit); + + // Set the transaction rate limit + SubtensorModule::set_tx_rate_limit(tx_rate_limit); + // assert the rate limit is set to 1000 blocks + assert_eq!(SubtensorModule::get_tx_rate_limit(), tx_rate_limit); + + // Setup initial state + add_network(netuid, tempo, 0); + register_ok_neuron(netuid, old_hotkey, coldkey, 0); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, swap_cost); + + // Perform the first swap + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey), + &old_hotkey, + &new_hotkey_1 + )); + + + // Attempt to perform another swap immediately, which should fail due to rate limit + assert_err!( + SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey), + &new_hotkey_1, + &new_hotkey_2 + ), + Error::::HotKeySetTxRateLimitExceeded + ); + + + // move in time past the rate limit + step_block(1001); + assert_ok!(SubtensorModule::do_swap_hotkey( + <::RuntimeOrigin>::signed(coldkey), + &new_hotkey_1, + &new_hotkey_2 + )); + + }); +} + #[test] fn test_do_swap_hotkey_err_not_owner() { new_test_ext(1).execute_with(|| { From 768e8e4fd4b9c33697c4c951a3db238fb63accf0 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 18 Jun 2024 11:58:33 +0400 Subject: [PATCH 17/27] chore: fmt --- pallets/subtensor/tests/swap.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/pallets/subtensor/tests/swap.rs b/pallets/subtensor/tests/swap.rs index 3a2118c4a7..40c9a9a2a2 100644 --- a/pallets/subtensor/tests/swap.rs +++ b/pallets/subtensor/tests/swap.rs @@ -291,7 +291,7 @@ fn test_swap_hotkey_tx_rate_limit_exceeded() { let new_hotkey_1 = U256::from(2); let new_hotkey_2 = U256::from(4); let coldkey = U256::from(3); - let swap_cost = 1_000_000_000u64*2; + let swap_cost = 1_000_000_000u64 * 2; let tx_rate_limit = 1; @@ -299,10 +299,10 @@ fn test_swap_hotkey_tx_rate_limit_exceeded() { let current_tx_rate_limit = SubtensorModule::get_tx_rate_limit(); log::info!("current_tx_rate_limit: {:?}", current_tx_rate_limit); - // Set the transaction rate limit - SubtensorModule::set_tx_rate_limit(tx_rate_limit); - // assert the rate limit is set to 1000 blocks - assert_eq!(SubtensorModule::get_tx_rate_limit(), tx_rate_limit); + // Set the transaction rate limit + SubtensorModule::set_tx_rate_limit(tx_rate_limit); + // assert the rate limit is set to 1000 blocks + assert_eq!(SubtensorModule::get_tx_rate_limit(), tx_rate_limit); // Setup initial state add_network(netuid, tempo, 0); @@ -316,7 +316,6 @@ fn test_swap_hotkey_tx_rate_limit_exceeded() { &new_hotkey_1 )); - // Attempt to perform another swap immediately, which should fail due to rate limit assert_err!( SubtensorModule::do_swap_hotkey( @@ -327,7 +326,6 @@ fn test_swap_hotkey_tx_rate_limit_exceeded() { Error::::HotKeySetTxRateLimitExceeded ); - // move in time past the rate limit step_block(1001); assert_ok!(SubtensorModule::do_swap_hotkey( @@ -335,7 +333,6 @@ fn test_swap_hotkey_tx_rate_limit_exceeded() { &new_hotkey_1, &new_hotkey_2 )); - }); } From cb078a202beb40993d6f1e158b475efb52c2c273 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 18 Jun 2024 14:36:08 +0400 Subject: [PATCH 18/27] chore: review comments --- pallets/subtensor/src/swap.rs | 107 ++++++++-------- pallets/subtensor/tests/swap.rs | 213 +++++++++----------------------- 2 files changed, 109 insertions(+), 211 deletions(-) diff --git a/pallets/subtensor/src/swap.rs b/pallets/subtensor/src/swap.rs index 0b527b935c..c203f89bc9 100644 --- a/pallets/subtensor/src/swap.rs +++ b/pallets/subtensor/src/swap.rs @@ -62,22 +62,22 @@ impl Pallet { let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?; Self::burn_tokens(actual_burn_amount); - Self::swap_owner(old_hotkey, new_hotkey, &coldkey, &mut weight)?; - Self::swap_total_hotkey_stake(old_hotkey, new_hotkey, &mut weight)?; - Self::swap_delegates(old_hotkey, new_hotkey, &mut weight)?; - Self::swap_stake(old_hotkey, new_hotkey, &mut weight)?; + Self::swap_owner(old_hotkey, new_hotkey, &coldkey, &mut weight); + Self::swap_total_hotkey_stake(old_hotkey, new_hotkey, &mut weight); + Self::swap_delegates(old_hotkey, new_hotkey, &mut weight); + Self::swap_stake(old_hotkey, new_hotkey, &mut weight); // Store the value of is_network_member for the old key - let netuid_is_member: Vec = Self::get_netuid_is_member(old_hotkey, &mut weight)?; + let netuid_is_member: Vec = Self::get_netuid_is_member(old_hotkey, &mut weight); - Self::swap_is_network_member(old_hotkey, new_hotkey, &netuid_is_member, &mut weight)?; - Self::swap_axons(old_hotkey, new_hotkey, &netuid_is_member, &mut weight)?; - Self::swap_keys(old_hotkey, new_hotkey, &netuid_is_member, &mut weight)?; - Self::swap_loaded_emission(old_hotkey, new_hotkey, &netuid_is_member, &mut weight)?; - Self::swap_uids(old_hotkey, new_hotkey, &netuid_is_member, &mut weight)?; - Self::swap_prometheus(old_hotkey, new_hotkey, &netuid_is_member, &mut weight)?; + Self::swap_is_network_member(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); + Self::swap_axons(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); + Self::swap_keys(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); + Self::swap_loaded_emission(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); + Self::swap_uids(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); + Self::swap_prometheus(old_hotkey, new_hotkey, &netuid_is_member, &mut weight); - Self::swap_total_hotkey_coldkey_stakes_this_interval(old_hotkey, new_hotkey, &mut weight)?; + Self::swap_total_hotkey_coldkey_stakes_this_interval(old_hotkey, new_hotkey, &mut weight); Self::set_last_tx_block(&coldkey, block); weight.saturating_accrue(T::DbWeight::get().writes(1)); @@ -100,16 +100,13 @@ impl Pallet { /// # Returns /// /// * `Result, Error>` - A vector of network IDs where the hotkey is a member. - pub fn get_netuid_is_member( - old_hotkey: &T::AccountId, - weight: &mut Weight, - ) -> Result, Error> { + pub fn get_netuid_is_member(old_hotkey: &T::AccountId, weight: &mut Weight) -> Vec { let netuid_is_member: Vec = as IterableStorageDoubleMap<_, _, _>>::iter_prefix(old_hotkey) .map(|(netuid, _)| netuid) .collect(); weight.saturating_accrue(T::DbWeight::get().reads(netuid_is_member.len() as u64)); - Ok(netuid_is_member) + netuid_is_member } /// Swaps the owner of the hotkey. @@ -129,11 +126,10 @@ impl Pallet { new_hotkey: &T::AccountId, coldkey: &T::AccountId, weight: &mut Weight, - ) -> DispatchResult { + ) { Owner::::remove(old_hotkey); Owner::::insert(new_hotkey, coldkey.clone()); weight.saturating_accrue(T::DbWeight::get().writes(2)); - Ok(()) } /// Swaps the total stake of the hotkey. @@ -144,20 +140,22 @@ impl Pallet { /// * `new_hotkey` - The new hotkey. /// * `weight` - The weight of the transaction. /// - /// # Returns + /// # Weight Calculation /// - /// * `Result<(), Error>` - The result of the operation. + /// * Reads: 1 if the old hotkey exists, otherwise 1 for the failed read. + /// * Writes: 2 if the old hotkey exists (one for removal and one for insertion). pub fn swap_total_hotkey_stake( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, weight: &mut Weight, - ) -> DispatchResult { + ) { if let Ok(total_hotkey_stake) = TotalHotkeyStake::::try_get(old_hotkey) { TotalHotkeyStake::::remove(old_hotkey); TotalHotkeyStake::::insert(new_hotkey, total_hotkey_stake); - weight.saturating_accrue(T::DbWeight::get().writes(2)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + } else { + weight.saturating_accrue(T::DbWeight::get().reads(1)); } - Ok(()) } /// Swaps the delegates of the hotkey. @@ -168,20 +166,22 @@ impl Pallet { /// * `new_hotkey` - The new hotkey. /// * `weight` - The weight of the transaction. /// - /// # Returns + /// # Weight Calculation /// - /// * `Result<(), Error>` - The result of the operation. + /// * Reads: 1 if the old hotkey exists, otherwise 1 for the failed read. + /// * Writes: 2 if the old hotkey exists (one for removal and one for insertion). pub fn swap_delegates( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, weight: &mut Weight, - ) -> DispatchResult { + ) { if let Ok(delegate_take) = Delegates::::try_get(old_hotkey) { Delegates::::remove(old_hotkey); Delegates::::insert(new_hotkey, delegate_take); - weight.saturating_accrue(T::DbWeight::get().writes(2)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + } else { + weight.saturating_accrue(T::DbWeight::get().reads(1)); } - Ok(()) } /// Swaps the stake of the hotkey. @@ -195,11 +195,7 @@ impl Pallet { /// # Returns /// /// * `Result<(), Error>` - The result of the operation. - pub fn swap_stake( - old_hotkey: &T::AccountId, - new_hotkey: &T::AccountId, - weight: &mut Weight, - ) -> DispatchResult { + pub fn swap_stake(old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, weight: &mut Weight) { let mut writes = 0; let stakes: Vec<(T::AccountId, u64)> = Stake::::iter_prefix(old_hotkey).collect(); let stake_count = stakes.len() as u32; @@ -210,7 +206,6 @@ impl Pallet { } *weight += T::DbWeight::get().writes(writes as u64); - Ok(()) } /// Swaps the network membership status of the hotkey. /// @@ -229,14 +224,13 @@ impl Pallet { new_hotkey: &T::AccountId, netuid_is_member: &[u16], weight: &mut Weight, - ) -> DispatchResult { + ) { let _ = IsNetworkMember::::clear_prefix(old_hotkey, netuid_is_member.len() as u32, None); weight.saturating_accrue(T::DbWeight::get().writes(netuid_is_member.len() as u64)); for netuid in netuid_is_member.iter() { IsNetworkMember::::insert(new_hotkey, netuid, true); weight.saturating_accrue(T::DbWeight::get().writes(1)); } - Ok(()) } /// Swaps the axons of the hotkey. @@ -248,24 +242,27 @@ impl Pallet { /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. /// * `weight` - The weight of the transaction. /// - /// # Returns + /// # Weight Calculation /// - /// * `Result<(), Error>` - The result of the operation. + /// * Reads: 1 for each network ID if the old hotkey exists in that network. + /// * Writes: 2 for each network ID if the old hotkey exists in that network (one for removal and one for insertion). pub fn swap_axons( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, netuid_is_member: &[u16], weight: &mut Weight, - ) -> DispatchResult { + ) { for netuid in netuid_is_member.iter() { if let Ok(axon_info) = Axons::::try_get(netuid, old_hotkey) { Axons::::remove(netuid, old_hotkey); Axons::::insert(netuid, new_hotkey, axon_info); - weight.saturating_accrue(T::DbWeight::get().writes(2)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + } else { + weight.saturating_accrue(T::DbWeight::get().reads(1)); } } - Ok(()) } + /// Swaps the references in the keys storage map of the hotkey. /// /// # Arguments @@ -281,9 +278,9 @@ impl Pallet { pub fn swap_keys( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, - netuid_is_member: &Vec, + netuid_is_member: &[u16], weight: &mut Weight, - ) -> DispatchResult { + ) { let mut writes = 0; for netuid in netuid_is_member { let keys: Vec<(u16, T::AccountId)> = Keys::::iter_prefix(netuid).collect(); @@ -297,7 +294,6 @@ impl Pallet { } log::info!("writes: {:?}", writes); *weight += T::DbWeight::get().writes(writes as u64); - Ok(()) } /// Swaps the loaded emission of the hotkey. @@ -317,7 +313,7 @@ impl Pallet { new_hotkey: &T::AccountId, netuid_is_member: &[u16], weight: &mut Weight, - ) -> DispatchResult { + ) { for netuid in netuid_is_member { if let Some(mut emissions) = LoadedEmission::::get(netuid) { for emission in emissions.iter_mut() { @@ -329,7 +325,6 @@ impl Pallet { } } *weight += T::DbWeight::get().writes(netuid_is_member.len() as u64); - Ok(()) } /// Swaps the UIDs of the hotkey. @@ -349,7 +344,7 @@ impl Pallet { new_hotkey: &T::AccountId, netuid_is_member: &[u16], weight: &mut Weight, - ) -> DispatchResult { + ) { for netuid in netuid_is_member.iter() { if let Ok(uid) = Uids::::try_get(netuid, old_hotkey) { Uids::::remove(netuid, old_hotkey); @@ -357,7 +352,6 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().writes(2)); } } - Ok(()) } /// Swaps the Prometheus data of the hotkey. @@ -369,23 +363,25 @@ impl Pallet { /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. /// * `weight` - The weight of the transaction. /// - /// # Returns + /// # Weight Calculation /// - /// * `Result<(), Error>` - The result of the operation. + /// * Reads: 1 for each network ID if the old hotkey exists in that network. + /// * Writes: 2 for each network ID if the old hotkey exists in that network (one for removal and one for insertion). pub fn swap_prometheus( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, netuid_is_member: &[u16], weight: &mut Weight, - ) -> DispatchResult { + ) { for netuid in netuid_is_member.iter() { if let Ok(prometheus_info) = Prometheus::::try_get(netuid, old_hotkey) { Prometheus::::remove(netuid, old_hotkey); Prometheus::::insert(netuid, new_hotkey, prometheus_info); - weight.saturating_accrue(T::DbWeight::get().writes(2)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + } else { + weight.saturating_accrue(T::DbWeight::get().reads(1)); } } - Ok(()) } /// Swaps the total hotkey-coldkey stakes for the current interval. @@ -403,7 +399,7 @@ impl Pallet { old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, weight: &mut Weight, - ) -> DispatchResult { + ) { let stakes: Vec<(T::AccountId, (u64, u64))> = TotalHotkeyColdkeyStakesThisInterval::::iter_prefix(old_hotkey).collect(); log::info!("Stakes to swap: {:?}", stakes); @@ -417,6 +413,5 @@ impl Pallet { TotalHotkeyColdkeyStakesThisInterval::::remove(old_hotkey, &coldkey); weight.saturating_accrue(T::DbWeight::get().writes(2)); // One write for insert and one for remove } - Ok(()) } } diff --git a/pallets/subtensor/tests/swap.rs b/pallets/subtensor/tests/swap.rs index 40c9a9a2a2..1bbe0344de 100644 --- a/pallets/subtensor/tests/swap.rs +++ b/pallets/subtensor/tests/swap.rs @@ -61,7 +61,7 @@ fn test_do_swap_hotkey_ok() { let mut weight = Weight::zero(); // UIDs - for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight).unwrap() { + for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight) { assert_eq!( Uids::::get(netuid, new_hotkey), Uids::::get(netuid, old_hotkey) @@ -69,7 +69,7 @@ fn test_do_swap_hotkey_ok() { } // Prometheus - for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight).unwrap() { + for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight) { assert_eq!( Prometheus::::get(netuid, new_hotkey), Prometheus::::get(netuid, old_hotkey) @@ -77,7 +77,7 @@ fn test_do_swap_hotkey_ok() { } // LoadedEmission - for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight).unwrap() { + for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight) { assert_eq!( LoadedEmission::::get(netuid).unwrap(), LoadedEmission::::get(netuid).unwrap() @@ -85,7 +85,7 @@ fn test_do_swap_hotkey_ok() { } // IsNetworkMember - for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight).unwrap() { + for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight) { assert!(IsNetworkMember::::contains_key(new_hotkey, netuid)); assert!(!IsNetworkMember::::contains_key(old_hotkey, netuid)); } @@ -112,7 +112,7 @@ fn test_do_swap_hotkey_ok() { ); // Axons - for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight).unwrap() { + for netuid in SubtensorModule::get_netuid_is_member(&old_hotkey, &mut weight) { assert_eq!( Axons::::get(netuid, new_hotkey), Axons::::get(netuid, old_hotkey) @@ -215,7 +215,7 @@ fn test_do_swap_hotkey_ok_robust() { let mut weight = Weight::zero(); // UIDs for netuid in - SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() + SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight) { assert_eq!( Uids::::get(netuid, new_hotkeys[i]), @@ -225,7 +225,7 @@ fn test_do_swap_hotkey_ok_robust() { // Prometheus for netuid in - SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() + SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight) { assert_eq!( Prometheus::::get(netuid, new_hotkeys[i]), @@ -235,7 +235,7 @@ fn test_do_swap_hotkey_ok_robust() { // LoadedEmission for netuid in - SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() + SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight) { assert_eq!( LoadedEmission::::get(netuid).unwrap(), @@ -245,7 +245,7 @@ fn test_do_swap_hotkey_ok_robust() { // IsNetworkMember for netuid in - SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight).unwrap() + SubtensorModule::get_netuid_is_member(&old_hotkeys[i], &mut weight) { assert!(IsNetworkMember::::contains_key( new_hotkeys[i], @@ -376,12 +376,7 @@ fn test_swap_owner_success() { Owner::::insert(old_hotkey, coldkey); // Perform the swap - assert_ok!(SubtensorModule::swap_owner( - &old_hotkey, - &new_hotkey, - &coldkey, - &mut weight - )); + SubtensorModule::swap_owner(&old_hotkey, &new_hotkey, &coldkey, &mut weight); // Verify the swap assert_eq!(Owner::::get(new_hotkey), coldkey); @@ -401,12 +396,7 @@ fn test_swap_owner_old_hotkey_not_exist() { assert!(!Owner::::contains_key(old_hotkey)); // Perform the swap - assert_ok!(SubtensorModule::swap_owner( - &old_hotkey, - &new_hotkey, - &coldkey, - &mut weight - )); + SubtensorModule::swap_owner(&old_hotkey, &new_hotkey, &coldkey, &mut weight); // Verify the swap assert_eq!(Owner::::get(new_hotkey), coldkey); @@ -428,12 +418,7 @@ fn test_swap_owner_new_hotkey_already_exists() { Owner::::insert(new_hotkey, another_coldkey); // Perform the swap - assert_ok!(SubtensorModule::swap_owner( - &old_hotkey, - &new_hotkey, - &coldkey, - &mut weight - )); + SubtensorModule::swap_owner(&old_hotkey, &new_hotkey, &coldkey, &mut weight); // Verify the swap assert_eq!(Owner::::get(new_hotkey), coldkey); @@ -453,12 +438,7 @@ fn test_swap_owner_weight_update() { Owner::::insert(old_hotkey, coldkey); // Perform the swap - assert_ok!(SubtensorModule::swap_owner( - &old_hotkey, - &new_hotkey, - &coldkey, - &mut weight - )); + SubtensorModule::swap_owner(&old_hotkey, &new_hotkey, &coldkey, &mut weight); // Verify the weight update let expected_weight = ::DbWeight::get().writes(2); @@ -478,11 +458,7 @@ fn test_swap_total_hotkey_stake_success() { TotalHotkeyStake::::insert(old_hotkey, total_stake); // Perform the swap - assert_ok!(SubtensorModule::swap_total_hotkey_stake( - &old_hotkey, - &new_hotkey, - &mut weight - )); + SubtensorModule::swap_total_hotkey_stake(&old_hotkey, &new_hotkey, &mut weight); // Verify the swap assert_eq!(TotalHotkeyStake::::get(new_hotkey), total_stake); @@ -501,11 +477,7 @@ fn test_swap_total_hotkey_stake_old_hotkey_not_exist() { assert!(!TotalHotkeyStake::::contains_key(old_hotkey)); // Perform the swap - assert_ok!(SubtensorModule::swap_total_hotkey_stake( - &old_hotkey, - &new_hotkey, - &mut weight - )); + SubtensorModule::swap_total_hotkey_stake(&old_hotkey, &new_hotkey, &mut weight); // Verify that new_hotkey does not have a stake assert!(!TotalHotkeyStake::::contains_key(new_hotkey)); @@ -524,14 +496,10 @@ fn test_swap_total_hotkey_stake_weight_update() { TotalHotkeyStake::::insert(old_hotkey, total_stake); // Perform the swap - assert_ok!(SubtensorModule::swap_total_hotkey_stake( - &old_hotkey, - &new_hotkey, - &mut weight - )); + SubtensorModule::swap_total_hotkey_stake(&old_hotkey, &new_hotkey, &mut weight); // Verify the weight update - let expected_weight = ::DbWeight::get().writes(2); + let expected_weight = ::DbWeight::get().reads_writes(1, 2); assert_eq!(weight, expected_weight); }); } @@ -548,11 +516,7 @@ fn test_swap_delegates_success() { Delegates::::insert(old_hotkey, delegate_take); // Perform the swap - assert_ok!(SubtensorModule::swap_delegates( - &old_hotkey, - &new_hotkey, - &mut weight - )); + SubtensorModule::swap_delegates(&old_hotkey, &new_hotkey, &mut weight); // Verify the swap assert_eq!(Delegates::::get(new_hotkey), delegate_take); @@ -571,11 +535,7 @@ fn test_swap_delegates_old_hotkey_not_exist() { assert!(!Delegates::::contains_key(old_hotkey)); // Perform the swap - assert_ok!(SubtensorModule::swap_delegates( - &old_hotkey, - &new_hotkey, - &mut weight - )); + SubtensorModule::swap_delegates(&old_hotkey, &new_hotkey, &mut weight); // Verify that new_hotkey does not have a delegate assert!(!Delegates::::contains_key(new_hotkey)); @@ -594,14 +554,10 @@ fn test_swap_delegates_weight_update() { Delegates::::insert(old_hotkey, delegate_take); // Perform the swap - assert_ok!(SubtensorModule::swap_delegates( - &old_hotkey, - &new_hotkey, - &mut weight - )); + SubtensorModule::swap_delegates(&old_hotkey, &new_hotkey, &mut weight); // Verify the weight update - let expected_weight = ::DbWeight::get().writes(2); + let expected_weight = ::DbWeight::get().reads_writes(1, 2); assert_eq!(weight, expected_weight); }); } @@ -619,11 +575,7 @@ fn test_swap_stake_success() { Stake::::insert(old_hotkey, coldkey, stake_amount); // Perform the swap - assert_ok!(SubtensorModule::swap_stake( - &old_hotkey, - &new_hotkey, - &mut weight - )); + SubtensorModule::swap_stake(&old_hotkey, &new_hotkey, &mut weight); // Verify the swap assert_eq!(Stake::::get(new_hotkey, coldkey), stake_amount); @@ -647,11 +599,7 @@ fn test_swap_stake_old_hotkey_not_exist() { assert!(Stake::::contains_key(old_hotkey, coldkey)); // Perform the swap - assert_ok!(SubtensorModule::swap_stake( - &old_hotkey, - &new_hotkey, - &mut weight - )); + SubtensorModule::swap_stake(&old_hotkey, &new_hotkey, &mut weight); // Verify that new_hotkey has the stake and old_hotkey does not assert!(Stake::::contains_key(new_hotkey, coldkey)); @@ -672,11 +620,7 @@ fn test_swap_stake_weight_update() { Stake::::insert(old_hotkey, coldkey, stake_amount); // Perform the swap - assert_ok!(SubtensorModule::swap_stake( - &old_hotkey, - &new_hotkey, - &mut weight - )); + SubtensorModule::swap_stake(&old_hotkey, &new_hotkey, &mut weight); // Verify the weight update let expected_weight = ::DbWeight::get().writes(2); @@ -698,12 +642,12 @@ fn test_swap_is_network_member_success() { } // Perform the swap - assert_ok!(SubtensorModule::swap_is_network_member( + SubtensorModule::swap_is_network_member( &old_hotkey, &new_hotkey, &netuid_is_member, - &mut weight - )); + &mut weight, + ); // Verify the swap for netuid in &netuid_is_member { @@ -727,12 +671,12 @@ fn test_swap_is_network_member_weight_update() { } // Perform the swap - assert_ok!(SubtensorModule::swap_is_network_member( + SubtensorModule::swap_is_network_member( &old_hotkey, &new_hotkey, &netuid_is_member, - &mut weight - )); + &mut weight, + ); // Verify the weight update let expected_weight = ::DbWeight::get().writes(4); @@ -764,12 +708,7 @@ fn test_swap_axons_success() { } // Perform the swap - assert_ok!(SubtensorModule::swap_axons( - &old_hotkey, - &new_hotkey, - &netuid_is_member, - &mut weight - )); + SubtensorModule::swap_axons(&old_hotkey, &new_hotkey, &netuid_is_member, &mut weight); // Verify the swap for netuid in &netuid_is_member { @@ -803,16 +742,12 @@ fn test_swap_axons_weight_update() { } // Perform the swap - assert_ok!(SubtensorModule::swap_axons( - &old_hotkey, - &new_hotkey, - &netuid_is_member, - &mut weight - )); + SubtensorModule::swap_axons(&old_hotkey, &new_hotkey, &netuid_is_member, &mut weight); // Verify the weight update - let expected_weight = ::DbWeight::get().writes(4); - assert_eq!(weight, expected_weight); + let expected_weight = netuid_is_member.len() as u64 + * ::DbWeight::get().reads_writes(1, 2); + assert_eq!(weight, expected_weight.into()); }); } @@ -832,12 +767,7 @@ fn test_swap_keys_success() { } // Perform the swap - assert_ok!(SubtensorModule::swap_keys( - &old_hotkey, - &new_hotkey, - &netuid_is_member, - &mut weight - )); + SubtensorModule::swap_keys(&old_hotkey, &new_hotkey, &netuid_is_member, &mut weight); // Verify the swap for netuid in &netuid_is_member { @@ -867,12 +797,7 @@ fn test_swap_keys_weight_update() { } // Perform the swap - assert_ok!(SubtensorModule::swap_keys( - &old_hotkey, - &new_hotkey, - &netuid_is_member, - &mut weight - )); + SubtensorModule::swap_keys(&old_hotkey, &new_hotkey, &netuid_is_member, &mut weight); // Verify the weight update let expected_weight = ::DbWeight::get().writes(4); @@ -902,12 +827,12 @@ fn test_swap_loaded_emission_success() { } // Perform the swap - assert_ok!(SubtensorModule::swap_loaded_emission( + SubtensorModule::swap_loaded_emission( &old_hotkey, &new_hotkey, &netuid_is_member, - &mut weight - )); + &mut weight, + ); // Verify the swap for netuid in &netuid_is_member { @@ -941,12 +866,12 @@ fn test_swap_loaded_emission_weight_update() { } // Perform the swap - assert_ok!(SubtensorModule::swap_loaded_emission( + SubtensorModule::swap_loaded_emission( &old_hotkey, &new_hotkey, &netuid_is_member, - &mut weight - )); + &mut weight, + ); // Verify the weight update let expected_weight = ::DbWeight::get().writes(2); @@ -969,12 +894,7 @@ fn test_swap_uids_success() { } // Perform the swap - assert_ok!(SubtensorModule::swap_uids( - &old_hotkey, - &new_hotkey, - &netuid_is_member, - &mut weight - )); + SubtensorModule::swap_uids(&old_hotkey, &new_hotkey, &netuid_is_member, &mut weight); // Verify the swap for netuid in &netuid_is_member { @@ -999,12 +919,7 @@ fn test_swap_uids_weight_update() { } // Perform the swap - assert_ok!(SubtensorModule::swap_uids( - &old_hotkey, - &new_hotkey, - &netuid_is_member, - &mut weight - )); + SubtensorModule::swap_uids(&old_hotkey, &new_hotkey, &netuid_is_member, &mut weight); // Verify the weight update let expected_weight = ::DbWeight::get().writes(4); @@ -1033,12 +948,7 @@ fn test_swap_prometheus_success() { } // Perform the swap - assert_ok!(SubtensorModule::swap_prometheus( - &old_hotkey, - &new_hotkey, - &netuid_is_member, - &mut weight - )); + SubtensorModule::swap_prometheus(&old_hotkey, &new_hotkey, &netuid_is_member, &mut weight); // Verify the swap for netuid in &netuid_is_member { @@ -1072,15 +982,11 @@ fn test_swap_prometheus_weight_update() { } // Perform the swap - assert_ok!(SubtensorModule::swap_prometheus( - &old_hotkey, - &new_hotkey, - &netuid_is_member, - &mut weight - )); + SubtensorModule::swap_prometheus(&old_hotkey, &new_hotkey, &netuid_is_member, &mut weight); // Verify the weight update - let expected_weight = ::DbWeight::get().writes(4); + let expected_weight = netuid_is_member.len() as u64 + * ::DbWeight::get().reads_writes(1, 2); assert_eq!(weight, expected_weight); }); } @@ -1098,12 +1004,10 @@ fn test_swap_total_hotkey_coldkey_stakes_this_interval_success() { TotalHotkeyColdkeyStakesThisInterval::::insert(old_hotkey, coldkey, stake); // Perform the swap - assert_ok!( - SubtensorModule::swap_total_hotkey_coldkey_stakes_this_interval( - &old_hotkey, - &new_hotkey, - &mut weight - ) + SubtensorModule::swap_total_hotkey_coldkey_stakes_this_interval( + &old_hotkey, + &new_hotkey, + &mut weight, ); // Verify the swap @@ -1130,12 +1034,11 @@ fn test_swap_total_hotkey_coldkey_stakes_this_interval_weight_update() { TotalHotkeyColdkeyStakesThisInterval::::insert(old_hotkey, coldkey, stake); // Perform the swap - assert_ok!( - SubtensorModule::swap_total_hotkey_coldkey_stakes_this_interval( - &old_hotkey, - &new_hotkey, - &mut weight - ) + + SubtensorModule::swap_total_hotkey_coldkey_stakes_this_interval( + &old_hotkey, + &new_hotkey, + &mut weight, ); // Verify the weight update From 814447f3d082522c3729c8a2938b153233b0af6e Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Fri, 21 Jun 2024 21:49:42 +0400 Subject: [PATCH 19/27] fix: pr comments --- pallets/subtensor/src/swap.rs | 35 ++++++++--------------------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/pallets/subtensor/src/swap.rs b/pallets/subtensor/src/swap.rs index c203f89bc9..692640d34f 100644 --- a/pallets/subtensor/src/swap.rs +++ b/pallets/subtensor/src/swap.rs @@ -99,7 +99,7 @@ impl Pallet { /// /// # Returns /// - /// * `Result, Error>` - A vector of network IDs where the hotkey is a member. + /// * `Vec` - A vector of network IDs where the hotkey is a member. pub fn get_netuid_is_member(old_hotkey: &T::AccountId, weight: &mut Weight) -> Vec { let netuid_is_member: Vec = as IterableStorageDoubleMap<_, _, _>>::iter_prefix(old_hotkey) @@ -118,9 +118,6 @@ impl Pallet { /// * `coldkey` - The coldkey owning the hotkey. /// * `weight` - The weight of the transaction. /// - /// # Returns - /// - /// * `Result<(), Error>` - The result of the operation. pub fn swap_owner( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, @@ -191,22 +188,23 @@ impl Pallet { /// * `old_hotkey` - The old hotkey. /// * `new_hotkey` - The new hotkey. /// * `weight` - The weight of the transaction. - /// - /// # Returns - /// - /// * `Result<(), Error>` - The result of the operation. pub fn swap_stake(old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, weight: &mut Weight) { let mut writes = 0; let stakes: Vec<(T::AccountId, u64)> = Stake::::iter_prefix(old_hotkey).collect(); let stake_count = stakes.len() as u32; + for (coldkey, stake_amount) in stakes { Stake::::insert(new_hotkey, &coldkey, stake_amount); - let _ = Stake::::clear_prefix(old_hotkey, stake_count, None); - writes += 2; // One write for insert and one for remove + writes += 1; // One write for insert } + + // Clear the prefix for the old hotkey after transferring all stakes + let _ = Stake::::clear_prefix(old_hotkey, stake_count, None); + writes += 1; // One write for clear_prefix *weight += T::DbWeight::get().writes(writes as u64); } + /// Swaps the network membership status of the hotkey. /// /// # Arguments @@ -215,10 +213,6 @@ impl Pallet { /// * `new_hotkey` - The new hotkey. /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. /// * `weight` - The weight of the transaction. - /// - /// # Returns - /// - /// * `Result<(), Error>` - The result of the operation. pub fn swap_is_network_member( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, @@ -271,10 +265,6 @@ impl Pallet { /// * `new_hotkey` - The new hotkey. /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. /// * `weight` - The weight of the transaction. - /// - /// # Returns - /// - /// * `Result<(), Error>` - The result of the operation. pub fn swap_keys( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, @@ -305,9 +295,6 @@ impl Pallet { /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. /// * `weight` - The weight of the transaction. /// - /// # Returns - /// - /// * `Result<(), Error>` - The result of the operation. pub fn swap_loaded_emission( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, @@ -336,9 +323,6 @@ impl Pallet { /// * `netuid_is_member` - A vector of network IDs where the hotkey is a member. /// * `weight` - The weight of the transaction. /// - /// # Returns - /// - /// * `Result<(), Error>` - The result of the operation. pub fn swap_uids( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, @@ -392,9 +376,6 @@ impl Pallet { /// * `new_hotkey` - The new hotkey. /// * `weight` - The weight of the transaction. /// - /// # Returns - /// - /// * `Result<(), Error>` - The result of the operation. pub fn swap_total_hotkey_coldkey_stakes_this_interval( old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, From 680e4ad684041363d7cce4b808e4db8f8e1074f2 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Fri, 21 Jun 2024 21:49:59 +0400 Subject: [PATCH 20/27] chore: lint --- pallets/subtensor/src/swap.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/swap.rs b/pallets/subtensor/src/swap.rs index 692640d34f..4f8097d262 100644 --- a/pallets/subtensor/src/swap.rs +++ b/pallets/subtensor/src/swap.rs @@ -192,12 +192,12 @@ impl Pallet { let mut writes = 0; let stakes: Vec<(T::AccountId, u64)> = Stake::::iter_prefix(old_hotkey).collect(); let stake_count = stakes.len() as u32; - + for (coldkey, stake_amount) in stakes { Stake::::insert(new_hotkey, &coldkey, stake_amount); writes += 1; // One write for insert } - + // Clear the prefix for the old hotkey after transferring all stakes let _ = Stake::::clear_prefix(old_hotkey, stake_count, None); writes += 1; // One write for clear_prefix From f7b567a8c05dd9b5d947abcb0335c6c85fc881b4 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Sat, 22 Jun 2024 00:48:02 +0400 Subject: [PATCH 21/27] fix: remove unused function --- pallets/subtensor/src/lib.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 504a9340e3..af05db7b26 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -277,11 +277,6 @@ pub mod pallet { pub fn TotalSupply() -> u64 { 21_000_000_000_000_000 // Rao => 21_000_000 Tao } - /// Hotkey swap cost. - #[pallet::type_value] - pub fn HotkeySwapCost() -> u64 { - 1_000_000_000 - } /// Default total stake. #[pallet::type_value] pub fn DefaultDefaultTake() -> u16 { From 78663d892547b787ebbf6cf7751e15ce828f0f6b Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 19 Jun 2024 11:49:25 -0400 Subject: [PATCH 22/27] add requirement for `devnet-companion` label for `devnet-ready` PRs --- .github/workflows/devnet-ready-labels.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/devnet-ready-labels.yml diff --git a/.github/workflows/devnet-ready-labels.yml b/.github/workflows/devnet-ready-labels.yml new file mode 100644 index 0000000000..25d9bc4791 --- /dev/null +++ b/.github/workflows/devnet-ready-labels.yml @@ -0,0 +1,17 @@ +name: Companion Labels (devnet) +on: + pull_request: + types: [opened, labeled, unlabeled, synchronize] + branches: [devnet-ready] +jobs: + check-labels: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: mheap/github-action-required-labels@v5 + with: + mode: minimum + count: 1 + labels: devnet-companion From 76d94396e6d9fec00f634d1f7ed772ba9a3d4881 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 19 Jun 2024 11:50:58 -0400 Subject: [PATCH 23/27] add testnet-ready labels check --- .github/workflows/devnet-ready-labels.yml | 2 +- .github/workflows/testnet-ready-labels.yml | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/testnet-ready-labels.yml diff --git a/.github/workflows/devnet-ready-labels.yml b/.github/workflows/devnet-ready-labels.yml index 25d9bc4791..ab53327e71 100644 --- a/.github/workflows/devnet-ready-labels.yml +++ b/.github/workflows/devnet-ready-labels.yml @@ -1,4 +1,4 @@ -name: Companion Labels (devnet) +name: devnet-companion Label Check on: pull_request: types: [opened, labeled, unlabeled, synchronize] diff --git a/.github/workflows/testnet-ready-labels.yml b/.github/workflows/testnet-ready-labels.yml new file mode 100644 index 0000000000..8570d20112 --- /dev/null +++ b/.github/workflows/testnet-ready-labels.yml @@ -0,0 +1,17 @@ +name: testnet-companion Label Check +on: + pull_request: + types: [opened, labeled, unlabeled, synchronize] + branches: [testnet-ready] +jobs: + check-labels: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: mheap/github-action-required-labels@v5 + with: + mode: minimum + count: 1 + labels: testnet-companion From 6bd2e423e345b74a6324db0ea92c6f1839a5cefe Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 19 Jun 2024 11:52:15 -0400 Subject: [PATCH 24/27] update CONTRIBUTING.md with additional info --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d3616041b2..084f3e9608 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,9 +15,9 @@ add appropriate labels to your PR as shown below. Three positive reviews are required. 4. Once the required passing reviews have been obtained, you are ready to request that your PR be included in the next `devnet` deploy. To do this, you should open a companion PR merging - your branch into the `devnet-ready` branch. You must include a link to the parent PR in the - description and preface your PR title with "(Devnet Ready)" or the PR will be - closed/ignored. + a copy of your branch into the `devnet-ready` branch. You must include a link to the parent + PR in the description and preface your PR title with "(Devnet Ready)" or the PR will be + closed/ignored. Your companion PR should have the `devnet-companion` label. 5. A core team administrator will review your "(Devnet Ready)" PR, verifying that it logically matches the changes introduced in the parent PR (there will sometimes be minor differences due to merge conflicts) and will either request changes or approve the PR and merge it. Once From ad85c272b2dfb199918a6588a1231e8601e0fa1d Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Wed, 19 Jun 2024 11:55:14 -0400 Subject: [PATCH 25/27] update docs --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 084f3e9608..132d360b86 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -86,11 +86,13 @@ | `runtime` | PR contains substantive changes to runtime / pallet code | none | | `breaking-change` | PR requires synchronized changes with bittensor | Triggers an automatic bot message so the relevant teams are made aware of the change well in advance | | `migration` | PR contains one or more migrations | none | +| `devnet-companion` | Designates a devnet companion PR | Presence of `devnet-companion` label is checked | | `devnet-ready` | PR's branch has been merged into the `devnet-ready` branch and will be included in the next `devnet` deploy | none | | `on-devnet` | PR has been deployed to `devnet` | Removes `devnet-ready` | | `devnet-pass` | PR has passed manual testing on `devnet` | `devnet-pass` or `devnet-skip` required | | `devnet-skip` | Allows a critical hotfix PR to skip required testing on `devnet` | `devnet-pass` or `devnet-skip` required | | `devnet-fail` | PR has failed manual testing on `devnet` and requires modification | none | +| `testnet-companion` | Designates a testnet companion PR | Presence of `testnet-companion` label is checked | | `on-testnet` | PR has been deployed to `testnet` | none | | `testnet-pass` | PR has passed manual testing on `testnet` | `testnet-pass` or `testnet-skip` required | | `testnet-skip` | Allows a critical hotfix PR to skip required manual testing and SOP on `testnet` | `testnet-pass` or `testnet-skip` required | From 66c87afe41c8cfaf48ae70f4f7d18f8de34232b3 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 21 Jun 2024 17:34:01 -0400 Subject: [PATCH 26/27] clippy fix --- pallets/subtensor/tests/swap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/tests/swap.rs b/pallets/subtensor/tests/swap.rs index 1bbe0344de..2a12ed3124 100644 --- a/pallets/subtensor/tests/swap.rs +++ b/pallets/subtensor/tests/swap.rs @@ -747,7 +747,7 @@ fn test_swap_axons_weight_update() { // Verify the weight update let expected_weight = netuid_is_member.len() as u64 * ::DbWeight::get().reads_writes(1, 2); - assert_eq!(weight, expected_weight.into()); + assert_eq!(weight, expected_weight); }); } From 01dca6a05f816c3da4cd8be84f3aab7885624744 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 25 Jun 2024 02:22:12 +0400 Subject: [PATCH 27/27] make clippy happy --- pallets/subtensor/src/registration.rs | 1 - pallets/subtensor/src/swap.rs | 21 +++++++++++---------- pallets/subtensor/tests/swap.rs | 2 ++ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/pallets/subtensor/src/registration.rs b/pallets/subtensor/src/registration.rs index 9d95f52efa..4688bcbb59 100644 --- a/pallets/subtensor/src/registration.rs +++ b/pallets/subtensor/src/registration.rs @@ -590,5 +590,4 @@ impl Pallet { let vec_work: Vec = Self::hash_to_vec(work); (nonce, vec_work) } - } diff --git a/pallets/subtensor/src/swap.rs b/pallets/subtensor/src/swap.rs index 4f8097d262..ce090d7361 100644 --- a/pallets/subtensor/src/swap.rs +++ b/pallets/subtensor/src/swap.rs @@ -49,8 +49,9 @@ impl Pallet { Error::::HotKeySetTxRateLimitExceeded ); - weight - .saturating_accrue(T::DbWeight::get().reads((TotalNetworks::::get() + 1u16) as u64)); + weight.saturating_accrue( + T::DbWeight::get().reads((TotalNetworks::::get().saturating_add(1u16)) as u64), + ); let swap_cost = Self::get_hotkey_swap_cost(); log::debug!("Swap cost: {:?}", swap_cost); @@ -189,20 +190,20 @@ impl Pallet { /// * `new_hotkey` - The new hotkey. /// * `weight` - The weight of the transaction. pub fn swap_stake(old_hotkey: &T::AccountId, new_hotkey: &T::AccountId, weight: &mut Weight) { - let mut writes = 0; + let mut writes: u64 = 0; let stakes: Vec<(T::AccountId, u64)> = Stake::::iter_prefix(old_hotkey).collect(); let stake_count = stakes.len() as u32; for (coldkey, stake_amount) in stakes { Stake::::insert(new_hotkey, &coldkey, stake_amount); - writes += 1; // One write for insert + writes = writes.saturating_add(1u64); // One write for insert } // Clear the prefix for the old hotkey after transferring all stakes let _ = Stake::::clear_prefix(old_hotkey, stake_count, None); - writes += 1; // One write for clear_prefix + writes = writes.saturating_add(1); // One write for insert; // One write for clear_prefix - *weight += T::DbWeight::get().writes(writes as u64); + weight.saturating_accrue(T::DbWeight::get().writes(writes)); } /// Swaps the network membership status of the hotkey. @@ -271,7 +272,7 @@ impl Pallet { netuid_is_member: &[u16], weight: &mut Weight, ) { - let mut writes = 0; + let mut writes: u64 = 0; for netuid in netuid_is_member { let keys: Vec<(u16, T::AccountId)> = Keys::::iter_prefix(netuid).collect(); for (uid, key) in keys { @@ -279,11 +280,11 @@ impl Pallet { log::info!("old hotkey found: {:?}", old_hotkey); Keys::::insert(netuid, uid, new_hotkey.clone()); } - writes += 2; + writes = writes.saturating_add(2u64); } } log::info!("writes: {:?}", writes); - *weight += T::DbWeight::get().writes(writes as u64); + weight.saturating_accrue(T::DbWeight::get().writes(writes)); } /// Swaps the loaded emission of the hotkey. @@ -311,7 +312,7 @@ impl Pallet { LoadedEmission::::insert(netuid, emissions); } } - *weight += T::DbWeight::get().writes(netuid_is_member.len() as u64); + weight.saturating_accrue(T::DbWeight::get().writes(netuid_is_member.len() as u64)); } /// Swaps the UIDs of the hotkey. diff --git a/pallets/subtensor/tests/swap.rs b/pallets/subtensor/tests/swap.rs index 2a12ed3124..af7d19d2d1 100644 --- a/pallets/subtensor/tests/swap.rs +++ b/pallets/subtensor/tests/swap.rs @@ -1,3 +1,5 @@ +#![allow(unused, clippy::indexing_slicing, clippy::panic, clippy::unwrap_used)] + use codec::Encode; use frame_support::weights::Weight; use frame_support::{assert_err, assert_ok};