diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 6a353eafbb..baed738ea6 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -44,7 +44,7 @@ mod registration; mod root; mod serving; mod staking; -mod swap; +mod swap_coldkey; mod swap_hotkey; mod uids; mod utils; @@ -726,7 +726,7 @@ pub mod pallet { #[pallet::storage] // --- MAP ( netuid ) --> last_mechanism_step_block pub type LastMechansimStepBlock = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultLastMechanismStepBlock>; - #[pallet::storage] // --- MAP ( netuid ) --> subnet_owner + #[pallet::storage] // --- MAP ( netuid ) --> (cold) subnet_owner pub type SubnetOwner = StorageMap<_, Identity, u16, T::AccountId, ValueQuery, DefaultSubnetOwner>; #[pallet::storage] // --- MAP ( netuid ) --> subnet_locked @@ -801,10 +801,10 @@ pub mod pallet { #[pallet::storage] // --- ITEM ( tx_rate_limit ) pub type TxDelegateTakeRateLimit = StorageValue<_, u64, ValueQuery, DefaultTxDelegateTakeRateLimit>; - #[pallet::storage] // --- MAP ( key ) --> last_block + #[pallet::storage] // --- MAP ( hotkey ) --> last_block pub type LastTxBlock = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; - #[pallet::storage] // --- MAP ( key ) --> last_block + #[pallet::storage] // --- MAP ( hotkey ) --> last_block pub type LastTxBlockDelegateTake = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; @@ -2065,17 +2065,17 @@ pub mod pallet { } /// The extrinsic for user to change its hotkey - ///#[pallet::call_index(70)] - ///#[pallet::weight((Weight::from_parts(1_940_000_000, 0) - ///.saturating_add(T::DbWeight::get().reads(272)) - ///.saturating_add(T::DbWeight::get().writes(527)), DispatchClass::Operational, Pays::No))] - ///pub fn swap_hotkey( - /// origin: OriginFor, - /// hotkey: T::AccountId, - /// new_hotkey: T::AccountId, - ///) -> DispatchResultWithPostInfo { - /// Self::do_swap_hotkey(origin, &hotkey, &new_hotkey) - ///} + #[pallet::call_index(70)] + #[pallet::weight((Weight::from_parts(1_940_000_000, 0) + .saturating_add(T::DbWeight::get().reads(272)) + .saturating_add(T::DbWeight::get().writes(527)), DispatchClass::Operational, Pays::No))] + pub fn swap_hotkey( + origin: OriginFor, + hotkey: T::AccountId, + new_hotkey: T::AccountId, + ) -> DispatchResultWithPostInfo { + Self::do_swap_hotkey(origin, &hotkey, &new_hotkey) + } /// The extrinsic for user to change the coldkey associated with their account. /// diff --git a/pallets/subtensor/src/swap.rs b/pallets/subtensor/src/swap_coldkey.rs similarity index 51% rename from pallets/subtensor/src/swap.rs rename to pallets/subtensor/src/swap_coldkey.rs index b6b0e9ba73..04d9a22dc7 100644 --- a/pallets/subtensor/src/swap.rs +++ b/pallets/subtensor/src/swap_coldkey.rs @@ -1,8 +1,6 @@ use super::*; use crate::MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP; -use frame_support::traits::fungible::Mutate; -use frame_support::traits::tokens::Preservation; -use frame_support::{storage::IterableStorageDoubleMap, weights::Weight}; +use frame_support::weights::Weight; use sp_core::{Get, U256}; impl Pallet { @@ -11,7 +9,6 @@ impl Pallet { /// # Arguments /// /// * `origin` - The origin of the call, which must be signed by the old coldkey. - /// * `old_coldkey` - The account ID of the old coldkey. /// * `new_coldkey` - The account ID of the new coldkey. /// /// # Returns @@ -21,10 +18,9 @@ impl Pallet { /// # Errors /// /// This function will return an error if: - /// - The caller is not the old coldkey. - /// - The new coldkey is the same as the old coldkey. - /// - The new coldkey is already associated with other hotkeys. - /// - The transaction rate limit for coldkey swaps has been exceeded. + /// - The caller is not a valid signed origin. + /// - The old coldkey (caller) is in arbitration. + /// - The new coldkey is already associated with other hotkeys or is a hotkey itself. /// - There's not enough balance to pay for the swap. /// /// # Events @@ -38,56 +34,205 @@ impl Pallet { origin: T::RuntimeOrigin, new_coldkey: &T::AccountId, ) -> DispatchResultWithPostInfo { + // 1. Ensure the origin is signed and get the old coldkey let old_coldkey = ensure_signed(origin)?; + + // 2. Check if the old coldkey is in arbitration ensure!( !Self::coldkey_in_arbitration(&old_coldkey), Error::::ColdkeyIsInArbitration ); + // 3. Initialize the weight for this operation let mut weight: Weight = T::DbWeight::get().reads(2); - // Check that the coldkey is a new key (does not exist elsewhere.) + // 4. Ensure the new coldkey is not associated with any hotkeys ensure!( - !Self::coldkey_has_associated_hotkeys(new_coldkey), + StakingHotkeys::::get(new_coldkey).is_empty(), Error::::ColdKeyAlreadyAssociated ); - // Check that the new coldkey is not a hotkey. + + // 5. Ensure the new coldkey is not a hotkey ensure!( !Self::hotkey_account_exists(new_coldkey), Error::::ColdKeyAlreadyAssociated ); - // Calculate and charge the swap fee + // 6. Calculate the swap cost and ensure sufficient balance let swap_cost = Self::get_key_swap_cost(); log::debug!("Coldkey swap cost: {:?}", swap_cost); - ensure!( Self::can_remove_balance_from_coldkey_account(&old_coldkey, swap_cost), Error::::NotEnoughBalanceToPaySwapColdKey ); + + // 7. Remove and burn the swap cost from the old coldkey's account let actual_burn_amount = Self::remove_balance_from_coldkey_account(&old_coldkey, swap_cost)?; Self::burn_tokens(actual_burn_amount); + // 8. Update the weight for the balance operations weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - // Actually do the swap. - weight = weight.saturating_add( - Self::perform_swap_coldkey(&old_coldkey, new_coldkey) - .map_err(|_| Error::::ColdkeySwapError)?, - ); + // 9. Perform the actual coldkey swap + let _ = Self::perform_swap_coldkey(&old_coldkey, new_coldkey, &mut weight); + // 10. Update the last transaction block for the new coldkey Self::set_last_tx_block(new_coldkey, Self::get_current_block_as_u64()); weight.saturating_accrue(T::DbWeight::get().writes(1)); + // 11. Emit the ColdkeySwapped event Self::deposit_event(Event::ColdkeySwapped { old_coldkey: old_coldkey.clone(), new_coldkey: new_coldkey.clone(), }); + // 12. Return the result with the updated weight Ok(Some(weight).into()) } + /// Performs the actual coldkey swap operation, transferring all associated data and balances from the old coldkey to the new coldkey. + /// + /// # Arguments + /// + /// * `old_coldkey` - The account ID of the old coldkey. + /// * `new_coldkey` - The account ID of the new coldkey. + /// * `weight` - A mutable reference to the current transaction weight. + /// + /// # Returns + /// + /// Returns a `DispatchResult` indicating success or failure of the operation. + /// + /// # Steps + /// + /// 1. Swap TotalHotkeyColdkeyStakesThisInterval: + /// - For each hotkey owned by the old coldkey, transfer its stake and block data to the new coldkey. + /// + /// 2. Swap subnet ownership: + /// - For each subnet, if the old coldkey is the owner, transfer ownership to the new coldkey. + /// + /// 3. Swap Stakes: + /// - For each hotkey staking for the old coldkey, transfer its stake to the new coldkey. + /// + /// 4. Swap total coldkey stake: + /// - Transfer the total stake from the old coldkey to the new coldkey. + /// + /// 5. Swap StakingHotkeys: + /// - Transfer the list of staking hotkeys from the old coldkey to the new coldkey. + /// + /// 6. Swap hotkey owners: + /// - For each hotkey owned by the old coldkey, transfer ownership to the new coldkey. + /// - Update the list of owned hotkeys for both old and new coldkeys. + /// + /// 7. Transfer remaining balance: + /// - Transfer any remaining balance from the old coldkey to the new coldkey. + /// + /// Throughout the process, the function updates the transaction weight to reflect the operations performed. + /// + /// # Notes + /// + /// This function is a critical part of the coldkey swap process and should be called only after all necessary checks and validations have been performed. + pub fn perform_swap_coldkey( + old_coldkey: &T::AccountId, + new_coldkey: &T::AccountId, + weight: &mut Weight, + ) -> DispatchResult { + // 1. Swap TotalHotkeyColdkeyStakesThisInterval + // TotalHotkeyColdkeyStakesThisInterval: MAP ( hotkey, coldkey ) --> ( stake, block ) | Stake of the hotkey for the coldkey. + for hotkey in OwnedHotkeys::::get(old_coldkey).iter() { + let (stake, block) = + TotalHotkeyColdkeyStakesThisInterval::::get(&hotkey, old_coldkey); + TotalHotkeyColdkeyStakesThisInterval::::remove(&hotkey, old_coldkey); + TotalHotkeyColdkeyStakesThisInterval::::insert(&hotkey, new_coldkey, (stake, block)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + } + + // 2. Swap subnet owner. + // SubnetOwner: MAP ( netuid ) --> (coldkey) | Owner of the subnet. + for netuid in Self::get_all_subnet_netuids() { + let subnet_owner = SubnetOwner::::get(netuid); + if subnet_owner == *old_coldkey { + SubnetOwner::::insert(netuid, new_coldkey.clone()); + } + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + } + + // 3. Swap Stake. + // Stake: MAP ( hotkey, coldkey ) --> u64 | Stake of the hotkey for the coldkey. + for hotkey in StakingHotkeys::::get(old_coldkey) { + // Get the stake on the old (hot,coldkey) account. + let old_stake: u64 = Stake::::get(&hotkey, old_coldkey); + // Get the stake on the new (hot,coldkey) account. + let new_stake: u64 = Stake::::get(&hotkey, new_coldkey); + // Add the stake to new account. + Stake::::insert(&hotkey, new_coldkey, new_stake.saturating_add(old_stake)); + // Remove the value from the old account. + Stake::::remove(&hotkey, old_coldkey); + // Add the weight for the read and write. + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + } + + // 4. Swap total coldkey stake. + // TotalColdkeyStake: MAP ( coldkey ) --> u64 | Total stake of the coldkey. + let old_coldkey_stake: u64 = TotalColdkeyStake::::get(old_coldkey); + // Get the stake of the new coldkey. + let new_coldkey_stake: u64 = TotalColdkeyStake::::get(new_coldkey); + // Remove the value from the old account. + TotalColdkeyStake::::insert(old_coldkey, 0); + // Add the stake to new account. + TotalColdkeyStake::::insert( + new_coldkey, + new_coldkey_stake.saturating_add(old_coldkey_stake), + ); + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + + // 5. Swap StakingHotkeys. + // StakingHotkeys: MAP ( coldkey ) --> Vec | Hotkeys staking for the coldkey. + let old_staking_hotkeys: Vec = StakingHotkeys::::get(old_coldkey); + let mut new_staking_hotkeys: Vec = StakingHotkeys::::get(new_coldkey); + for hotkey in old_staking_hotkeys { + // If the hotkey is not already in the new coldkey, add it. + if !new_staking_hotkeys.contains(&hotkey) { + new_staking_hotkeys.push(hotkey); + } + } + StakingHotkeys::::remove(old_coldkey); + StakingHotkeys::::insert(new_coldkey, new_staking_hotkeys); + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + + // 6. Swap hotkey owners. + // Owner: MAP ( hotkey ) --> coldkey | Owner of the hotkey. + // OwnedHotkeys: MAP ( coldkey ) --> Vec | Hotkeys owned by the coldkey. + let old_owned_hotkeys: Vec = OwnedHotkeys::::get(old_coldkey); + let mut new_owned_hotkeys: Vec = OwnedHotkeys::::get(new_coldkey); + for owned_hotkey in old_owned_hotkeys.iter() { + // Remove the hotkey from the old coldkey. + Owner::::remove(owned_hotkey); + // Add the hotkey to the new coldkey. + Owner::::insert(owned_hotkey, new_coldkey.clone()); + // Addd the owned hotkey to the new set of owned hotkeys. + if !new_owned_hotkeys.contains(owned_hotkey) { + new_owned_hotkeys.push(owned_hotkey.clone()); + } + } + OwnedHotkeys::::remove(old_coldkey); + OwnedHotkeys::::insert(new_coldkey, new_owned_hotkeys); + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + + // 7. Transfer remaining balance. + // Balance: MAP ( coldkey ) --> u64 | Balance of the coldkey. + // Transfer any remaining balance from old_coldkey to new_coldkey + let remaining_balance = Self::get_coldkey_balance(old_coldkey); + if remaining_balance > 0 { + Self::kill_coldkey_account(old_coldkey, remaining_balance)?; + Self::add_balance_to_coldkey_account(new_coldkey, remaining_balance); + } + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + + // Return ok. + Ok(()) + } + /// Checks if a coldkey is currently in arbitration. /// /// # Arguments @@ -303,334 +448,176 @@ impl Pallet { // Only remove ColdkeySwapDestinations if there's a single destination ColdkeySwapDestinations::::remove(&coldkey_i); weight_used = weight_used.saturating_add(T::DbWeight::get().writes(1)); - Self::perform_swap_coldkey(coldkey_i, new_coldkey).map(|weight| { - weight_used = weight_used.saturating_add(weight); - keys_swapped = keys_swapped.saturating_add(1); - })?; + keys_swapped = keys_swapped.saturating_add(1); + let _ = Self::perform_swap_coldkey(coldkey_i, new_coldkey, &mut weight_used); } } Ok(weight_used) } - pub fn perform_swap_coldkey( - old_coldkey: &T::AccountId, - new_coldkey: &T::AccountId, - ) -> Result { - log::info!( - "Performing swap for coldkey: {:?} to {:?}", - old_coldkey, - new_coldkey - ); - // Init the weight. - let mut weight = frame_support::weights::Weight::from_parts(0, 0); - - // Swap coldkey references in storage maps - // NOTE The order of these calls is important - Self::swap_stake_for_coldkey(old_coldkey, new_coldkey, &mut weight); - Self::swap_total_hotkey_coldkey_stakes_this_interval_for_coldkey( - old_coldkey, - new_coldkey, - &mut weight, - ); - Self::swap_subnet_owner_for_coldkey(old_coldkey, new_coldkey, &mut weight); - - // Transfer any remaining balance from old_coldkey to new_coldkey - let remaining_balance = Self::get_coldkey_balance(old_coldkey); - if remaining_balance > 0 { - if let Err(e) = Self::kill_coldkey_account(old_coldkey, remaining_balance) { - return Err(e.into()); - } - Self::add_balance_to_coldkey_account(new_coldkey, remaining_balance); - } - - // Swap the coldkey. - let total_balance: u64 = Self::get_coldkey_balance(old_coldkey); - if total_balance > 0 { - // Attempt to transfer the entire total balance to new_coldkey. - T::Currency::transfer( - old_coldkey, - new_coldkey, - total_balance, - Preservation::Expendable, - )?; - } - - Ok(weight) - } - - /// Retrieves the network membership status for a given hotkey. - /// - /// # Arguments - /// - /// * `old_hotkey` - The hotkey to check for network membership. - /// - /// # Returns - /// - /// * `Vec` - A vector of network IDs where the hotkey is a member. - pub fn get_netuid_is_member(old_hotkey: &T::AccountId, weight: &mut Weight) -> Vec { - let netuid_is_member: Vec = - as IterableStorageDoubleMap<_, _, _>>::iter_prefix(old_hotkey) - .map(|(netuid, _)| netuid) - .collect(); - weight.saturating_accrue(T::DbWeight::get().reads(netuid_is_member.len() as u64)); - netuid_is_member - } - - /// Swaps the total stake associated with a coldkey from the old coldkey to the new coldkey. - /// - /// # Arguments - /// - /// * `old_coldkey` - The AccountId of the old coldkey. - /// * `new_coldkey` - The AccountId of the new coldkey. - /// * `weight` - Mutable reference to the weight of the transaction. - /// - /// # Effects - /// - /// * Removes the total stake from the old coldkey. - /// * Inserts the total stake for the new coldkey. - /// * Updates the transaction weight. - pub fn swap_total_coldkey_stake( - old_coldkey: &T::AccountId, - new_coldkey: &T::AccountId, - weight: &mut Weight, - ) { - let stake = TotalColdkeyStake::::get(old_coldkey); - TotalColdkeyStake::::remove(old_coldkey); - TotalColdkeyStake::::insert(new_coldkey, stake); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - } - - /// Swaps the stake associated with a coldkey from the old coldkey to the new coldkey. - /// - /// # Arguments - /// - /// * `old_coldkey` - The AccountId of the old coldkey. - /// * `new_coldkey` - The AccountId of the new coldkey. - /// * `weight` - Mutable reference to the weight of the transaction. - /// - /// # Effects - /// - /// * Transfers all stakes from the old coldkey to the new coldkey. - /// * Updates the ownership of hotkeys. - /// * Updates the total stake for both old and new coldkeys. - /// * Updates the transaction weight. - /// - - pub fn swap_stake_for_coldkey( - old_coldkey: &T::AccountId, - new_coldkey: &T::AccountId, - weight: &mut Weight, - ) { - // Retrieve the list of hotkeys owned by the old coldkey - let old_owned_hotkeys: Vec = OwnedHotkeys::::get(old_coldkey); - - // Initialize the total transferred stake to zero - let mut total_transferred_stake: u64 = 0u64; - - // Log the total stake of old and new coldkeys before the swap - log::info!( - "Before swap - Old coldkey total stake: {}", - TotalColdkeyStake::::get(old_coldkey) - ); - log::info!( - "Before swap - New coldkey total stake: {}", - TotalColdkeyStake::::get(new_coldkey) - ); - - // Iterate over each hotkey owned by the old coldkey - for hotkey in old_owned_hotkeys.iter() { - // Retrieve and remove the stake associated with the hotkey and old coldkey - let stake: u64 = Stake::::take(hotkey, old_coldkey); - log::info!("Transferring stake for hotkey {:?}: {}", hotkey, stake); - if stake > 0 { - // Insert the stake for the hotkey and new coldkey - let old_stake = Stake::::get(hotkey, new_coldkey); - Stake::::insert(hotkey, new_coldkey, stake.saturating_add(old_stake)); - total_transferred_stake = total_transferred_stake.saturating_add(stake); - - // Update the owner of the hotkey to the new coldkey - Owner::::insert(hotkey, new_coldkey); - - // Update the transaction weight - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - } - } - log::info!( - "Starting transfer of delegated stakes for old coldkey: {:?}", - old_coldkey - ); - - for staking_hotkey in StakingHotkeys::::get(old_coldkey) { - log::info!("Processing staking hotkey: {:?}", staking_hotkey); - if Stake::::contains_key(staking_hotkey.clone(), old_coldkey) { - let hotkey = &staking_hotkey; - // Retrieve and remove the stake associated with the hotkey and old coldkey - let stake: u64 = Stake::::get(hotkey, old_coldkey); - Stake::::remove(hotkey, old_coldkey); - log::info!( - "Transferring delegated stake for hotkey {:?}: {}", - hotkey, - stake - ); - if stake > 0 { - // Insert the stake for the hotkey and new coldkey - let old_stake = Stake::::get(hotkey, new_coldkey); - Stake::::insert(hotkey, new_coldkey, stake.saturating_add(old_stake)); - total_transferred_stake = total_transferred_stake.saturating_add(stake); - log::info!( - "Updated stake for hotkey {:?} under new coldkey {:?}: {}", - hotkey, - new_coldkey, - stake.saturating_add(old_stake) - ); - - // Update the transaction weight - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 1)); - } - } else { - log::info!( - "No stake found for staking hotkey {:?} under old coldkey {:?}", - staking_hotkey, - old_coldkey - ); - weight.saturating_accrue(T::DbWeight::get().reads(1)); - } - } - - log::info!( - "Completed transfer of delegated stakes for old coldkey: {:?}", - old_coldkey - ); - - // Log the total transferred stake - log::info!("Total transferred stake: {}", total_transferred_stake); - - // Update the total stake for both old and new coldkeys if any stake was transferred - if total_transferred_stake > 0 { - let old_coldkey_stake: u64 = TotalColdkeyStake::::take(old_coldkey); // Remove it here. - let new_coldkey_stake: u64 = TotalColdkeyStake::::get(new_coldkey); - - TotalColdkeyStake::::insert(old_coldkey, 0); - TotalColdkeyStake::::insert( - new_coldkey, - new_coldkey_stake.saturating_add(old_coldkey_stake), - ); - - log::info!("Updated old coldkey stake from {} to 0", old_coldkey_stake); - log::info!( - "Updated new coldkey stake from {} to {}", - new_coldkey_stake, - new_coldkey_stake.saturating_add(old_coldkey_stake) - ); - - // Update the transaction weight - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - } - - // Update the list of owned hotkeys for both old and new coldkeys - - let mut new_owned_hotkeys = OwnedHotkeys::::get(new_coldkey); - for hotkey in old_owned_hotkeys { - if !new_owned_hotkeys.contains(&hotkey) { - new_owned_hotkeys.push(hotkey); - } - } - - OwnedHotkeys::::insert(new_coldkey, new_owned_hotkeys); - OwnedHotkeys::::remove(old_coldkey); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - - // Update the staking hotkeys for both old and new coldkeys - let staking_hotkeys: Vec = StakingHotkeys::::get(old_coldkey); - - let mut existing_staking_hotkeys = StakingHotkeys::::get(new_coldkey); - for hotkey in staking_hotkeys { - if !existing_staking_hotkeys.contains(&hotkey) { - existing_staking_hotkeys.push(hotkey); - } - } - - StakingHotkeys::::remove(old_coldkey); - StakingHotkeys::::insert(new_coldkey, existing_staking_hotkeys); - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - - // Log the total stake of old and new coldkeys after the swap - log::info!( - "After swap - Old coldkey total stake: {}", - TotalColdkeyStake::::get(old_coldkey) - ); - log::info!( - "After swap - New coldkey total stake: {}", - TotalColdkeyStake::::get(new_coldkey) - ); - } - - /// Swaps the total hotkey-coldkey stakes for the current interval from the old coldkey to the new coldkey. - /// - /// # Arguments - /// - /// * `old_coldkey` - The AccountId of the old coldkey. - /// * `new_coldkey` - The AccountId of the new coldkey. - /// * `weight` - Mutable reference to the weight of the transaction. - /// - /// # Effects - /// - /// * Removes all total hotkey-coldkey stakes for the current interval associated with the old coldkey. - /// * Inserts all total hotkey-coldkey stakes for the current interval for the new coldkey. - /// * Updates the transaction weight. - pub fn swap_total_hotkey_coldkey_stakes_this_interval_for_coldkey( - old_coldkey: &T::AccountId, - new_coldkey: &T::AccountId, - weight: &mut Weight, - ) { - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 0)); - for hotkey in OwnedHotkeys::::get(old_coldkey).iter() { - let (stake, block) = - TotalHotkeyColdkeyStakesThisInterval::::get(&hotkey, old_coldkey); - TotalHotkeyColdkeyStakesThisInterval::::remove(&hotkey, old_coldkey); - TotalHotkeyColdkeyStakesThisInterval::::insert(&hotkey, new_coldkey, (stake, block)); - weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); - } - } - - /// Checks if a coldkey has any associated hotkeys. - /// - /// # Arguments - /// - /// * `coldkey` - The AccountId of the coldkey to check. - /// - /// # Returns - /// - /// * `bool` - True if the coldkey has any associated hotkeys, false otherwise. - pub fn coldkey_has_associated_hotkeys(coldkey: &T::AccountId) -> bool { - !StakingHotkeys::::get(coldkey).is_empty() - } - - /// Swaps the subnet owner from the old coldkey to the new coldkey for all networks where the old coldkey is the owner. - /// - /// # Arguments - /// - /// * `old_coldkey` - The AccountId of the old coldkey. - /// * `new_coldkey` - The AccountId of the new coldkey. - /// * `weight` - Mutable reference to the weight of the transaction. - /// - /// # Effects - /// - /// * Updates the subnet owner to the new coldkey for all networks where the old coldkey was the owner. - /// * Updates the transaction weight. - pub fn swap_subnet_owner_for_coldkey( - old_coldkey: &T::AccountId, - new_coldkey: &T::AccountId, - weight: &mut Weight, - ) { - for netuid in 0..=TotalNetworks::::get() { - let subnet_owner = SubnetOwner::::get(netuid); - if subnet_owner == *old_coldkey { - SubnetOwner::::insert(netuid, new_coldkey.clone()); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } - } - weight.saturating_accrue(T::DbWeight::get().reads(TotalNetworks::::get() as u64)); - } + // /// Swaps the stake associated with a coldkey from the old coldkey to the new coldkey. + // /// + // /// # Arguments + // /// + // /// * `old_coldkey` - The AccountId of the old coldkey. + // /// * `new_coldkey` - The AccountId of the new coldkey. + // /// * `weight` - Mutable reference to the weight of the transaction. + // /// + // /// # Effects + // /// + // /// * Transfers all stakes from the old coldkey to the new coldkey. + // /// * Updates the ownership of hotkeys. + // /// * Updates the total stake for both old and new coldkeys. + // /// * Updates the transaction weight. + // /// + + // pub fn swap_stake_for_coldkey( + // old_coldkey: &T::AccountId, + // new_coldkey: &T::AccountId, + // weight: &mut Weight, + // ) { + // // Retrieve the list of hotkeys owned by the old coldkey + // let old_owned_hotkeys: Vec = OwnedHotkeys::::get(old_coldkey); + + // // Initialize the total transferred stake to zero + // let mut total_transferred_stake: u64 = 0u64; + + // // Log the total stake of old and new coldkeys before the swap + // log::info!( + // "Before swap - Old coldkey total stake: {}", + // TotalColdkeyStake::::get(old_coldkey) + // ); + // log::info!( + // "Before swap - New coldkey total stake: {}", + // TotalColdkeyStake::::get(new_coldkey) + // ); + + // // Iterate over each hotkey owned by the old coldkey + // for hotkey in old_owned_hotkeys.iter() { + // // Retrieve and remove the stake associated with the hotkey and old coldkey + // let stake: u64 = Stake::::take(hotkey, old_coldkey); + // log::info!("Transferring stake for hotkey {:?}: {}", hotkey, stake); + // if stake > 0 { + // // Insert the stake for the hotkey and new coldkey + // let old_stake = Stake::::get(hotkey, new_coldkey); + // Stake::::insert(hotkey, new_coldkey, stake.saturating_add(old_stake)); + // total_transferred_stake = total_transferred_stake.saturating_add(stake); + + // // Update the owner of the hotkey to the new coldkey + // Owner::::insert(hotkey, new_coldkey); + + // // Update the transaction weight + // weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + // } + // } + // log::info!( + // "Starting transfer of delegated stakes for old coldkey: {:?}", + // old_coldkey + // ); + + // for staking_hotkey in StakingHotkeys::::get(old_coldkey) { + // log::info!("Processing staking hotkey: {:?}", staking_hotkey); + // if Stake::::contains_key(staking_hotkey.clone(), old_coldkey) { + // let hotkey = &staking_hotkey; + // // Retrieve and remove the stake associated with the hotkey and old coldkey + // let stake: u64 = Stake::::get(hotkey, old_coldkey); + // Stake::::remove(hotkey, old_coldkey); + // log::info!( + // "Transferring delegated stake for hotkey {:?}: {}", + // hotkey, + // stake + // ); + // if stake > 0 { + // // Insert the stake for the hotkey and new coldkey + // let old_stake = Stake::::get(hotkey, new_coldkey); + // Stake::::insert(hotkey, new_coldkey, stake.saturating_add(old_stake)); + // total_transferred_stake = total_transferred_stake.saturating_add(stake); + // log::info!( + // "Updated stake for hotkey {:?} under new coldkey {:?}: {}", + // hotkey, + // new_coldkey, + // stake.saturating_add(old_stake) + // ); + + // // Update the transaction weight + // weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 1)); + // } + // } else { + // log::info!( + // "No stake found for staking hotkey {:?} under old coldkey {:?}", + // staking_hotkey, + // old_coldkey + // ); + // weight.saturating_accrue(T::DbWeight::get().reads(1)); + // } + // } + + // log::info!( + // "Completed transfer of delegated stakes for old coldkey: {:?}", + // old_coldkey + // ); + + // // Log the total transferred stake + // log::info!("Total transferred stake: {}", total_transferred_stake); + + // // Update the total stake for both old and new coldkeys if any stake was transferred + // if total_transferred_stake > 0 { + // let old_coldkey_stake: u64 = TotalColdkeyStake::::take(old_coldkey); // Remove it here. + // let new_coldkey_stake: u64 = TotalColdkeyStake::::get(new_coldkey); + + // TotalColdkeyStake::::insert(old_coldkey, 0); + // TotalColdkeyStake::::insert( + // new_coldkey, + // new_coldkey_stake.saturating_add(old_coldkey_stake), + // ); + + // log::info!("Updated old coldkey stake from {} to 0", old_coldkey_stake); + // log::info!( + // "Updated new coldkey stake from {} to {}", + // new_coldkey_stake, + // new_coldkey_stake.saturating_add(old_coldkey_stake) + // ); + + // // Update the transaction weight + // weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + // } + + // // Update the list of owned hotkeys for both old and new coldkeys + + // let mut new_owned_hotkeys = OwnedHotkeys::::get(new_coldkey); + // for hotkey in old_owned_hotkeys { + // if !new_owned_hotkeys.contains(&hotkey) { + // new_owned_hotkeys.push(hotkey); + // } + // } + + // OwnedHotkeys::::insert(new_coldkey, new_owned_hotkeys); + // OwnedHotkeys::::remove(old_coldkey); + // weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); + + // // Update the staking hotkeys for both old and new coldkeys + // let staking_hotkeys: Vec = StakingHotkeys::::get(old_coldkey); + + // let mut existing_staking_hotkeys = StakingHotkeys::::get(new_coldkey); + // for hotkey in staking_hotkeys { + // if !existing_staking_hotkeys.contains(&hotkey) { + // existing_staking_hotkeys.push(hotkey); + // } + // } + + // StakingHotkeys::::remove(old_coldkey); + // StakingHotkeys::::insert(new_coldkey, existing_staking_hotkeys); + // weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + + // // Log the total stake of old and new coldkeys after the swap + // log::info!( + // "After swap - Old coldkey total stake: {}", + // TotalColdkeyStake::::get(old_coldkey) + // ); + // log::info!( + // "After swap - New coldkey total stake: {}", + // TotalColdkeyStake::::get(new_coldkey) + // ); + // } } diff --git a/pallets/subtensor/tests/swap.rs b/pallets/subtensor/tests/swap_coldkey.rs similarity index 62% rename from pallets/subtensor/tests/swap.rs rename to pallets/subtensor/tests/swap_coldkey.rs index 0a3a85dff3..9203e2b3f9 100644 --- a/pallets/subtensor/tests/swap.rs +++ b/pallets/subtensor/tests/swap_coldkey.rs @@ -1,5 +1,4 @@ #![allow(unused, clippy::indexing_slicing, clippy::panic, clippy::unwrap_used)] - use codec::Encode; use frame_support::weights::Weight; use frame_support::{assert_err, assert_noop, assert_ok}; @@ -7,8 +6,473 @@ use frame_system::{Config, RawOrigin}; mod mock; use mock::*; use pallet_subtensor::*; +use sp_core::H256; use sp_core::U256; +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_total_hotkey_coldkey_stakes_this_interval --exact --nocapture +#[test] +fn test_swap_total_hotkey_coldkey_stakes_this_interval() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let hotkey = U256::from(3); + let stake = 100; + let block = 42; + + OwnedHotkeys::::insert(old_coldkey, vec![hotkey]); + TotalHotkeyColdkeyStakesThisInterval::::insert(hotkey, old_coldkey, (stake, block)); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert!(!TotalHotkeyColdkeyStakesThisInterval::::contains_key( + hotkey, + old_coldkey + )); + assert_eq!( + TotalHotkeyColdkeyStakesThisInterval::::get(hotkey, new_coldkey), + (stake, block) + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_subnet_owner --exact --nocapture +#[test] +fn test_swap_subnet_owner() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let netuid = 1u16; + + add_network(netuid, 1, 0); + SubnetOwner::::insert(netuid, old_coldkey); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert_eq!(SubnetOwner::::get(netuid), new_coldkey); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_stake --exact --nocapture +#[test] +fn test_swap_stake() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let hotkey = U256::from(3); + let stake = 100; + + StakingHotkeys::::insert(old_coldkey, vec![hotkey]); + Stake::::insert(hotkey, old_coldkey, stake); + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert!(!Stake::::contains_key(hotkey, old_coldkey)); + assert_eq!(Stake::::get(hotkey, new_coldkey), stake); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_total_coldkey_stake --exact --nocapture +#[test] +fn test_swap_total_coldkey_stake() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let stake = 100; + + TotalColdkeyStake::::insert(old_coldkey, stake); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert_eq!(TotalColdkeyStake::::get(old_coldkey), 0); + assert_eq!(TotalColdkeyStake::::get(new_coldkey), stake); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_staking_hotkeys --exact --nocapture +#[test] +fn test_swap_staking_hotkeys() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let hotkey = U256::from(3); + + StakingHotkeys::::insert(old_coldkey, vec![hotkey]); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert!(StakingHotkeys::::get(old_coldkey).is_empty()); + assert_eq!(StakingHotkeys::::get(new_coldkey), vec![hotkey]); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_hotkey_owners --exact --nocapture +#[test] +fn test_swap_hotkey_owners() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let hotkey = U256::from(3); + + Owner::::insert(hotkey, old_coldkey); + OwnedHotkeys::::insert(old_coldkey, vec![hotkey]); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert_eq!(Owner::::get(hotkey), new_coldkey); + assert!(OwnedHotkeys::::get(old_coldkey).is_empty()); + assert_eq!(OwnedHotkeys::::get(new_coldkey), vec![hotkey]); + }); +} +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_transfer_remaining_balance --exact --nocapture +#[test] +fn test_transfer_remaining_balance() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let balance = 100; + + SubtensorModule::add_balance_to_coldkey_account(&old_coldkey, balance); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert_eq!(SubtensorModule::get_coldkey_balance(&old_coldkey), 0); + assert_eq!(SubtensorModule::get_coldkey_balance(&new_coldkey), balance); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_with_no_stake --exact --nocapture +#[test] +fn test_swap_with_no_stake() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert_eq!(TotalColdkeyStake::::get(old_coldkey), 0); + assert_eq!(TotalColdkeyStake::::get(new_coldkey), 0); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_with_multiple_hotkeys --exact --nocapture +#[test] +fn test_swap_with_multiple_hotkeys() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let hotkey1 = U256::from(3); + let hotkey2 = U256::from(4); + + OwnedHotkeys::::insert(old_coldkey, vec![hotkey1, hotkey2]); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert!(OwnedHotkeys::::get(old_coldkey).is_empty()); + assert_eq!( + OwnedHotkeys::::get(new_coldkey), + vec![hotkey1, hotkey2] + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_with_multiple_subnets --exact --nocapture +#[test] +fn test_swap_with_multiple_subnets() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let netuid1 = 1u16; + let netuid2 = 2u16; + + add_network(netuid1, 1, 0); + add_network(netuid2, 1, 0); + SubnetOwner::::insert(netuid1, old_coldkey); + SubnetOwner::::insert(netuid2, old_coldkey); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert_eq!(SubnetOwner::::get(netuid1), new_coldkey); + assert_eq!(SubnetOwner::::get(netuid2), new_coldkey); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_with_zero_balance --exact --nocapture +#[test] +fn test_swap_with_zero_balance() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert_eq!(Balances::free_balance(old_coldkey), 0); + assert_eq!(Balances::free_balance(new_coldkey), 0); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_idempotency --exact --nocapture +#[test] +fn test_swap_idempotency() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let stake = 100; + + TotalColdkeyStake::::insert(old_coldkey, stake); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert_eq!(TotalColdkeyStake::::get(old_coldkey), 0); + assert_eq!(TotalColdkeyStake::::get(new_coldkey), stake); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_with_max_values --exact --nocapture +#[test] +fn test_swap_with_max_values() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let max_stake = u64::MAX; + + TotalColdkeyStake::::insert(old_coldkey, max_stake); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert_eq!(TotalColdkeyStake::::get(old_coldkey), 0); + assert_eq!(TotalColdkeyStake::::get(new_coldkey), max_stake); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_with_non_existent_new_coldkey --exact --nocapture +#[test] +fn test_swap_with_non_existent_new_coldkey() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let stake = 100; + + TotalColdkeyStake::::insert(old_coldkey, stake); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert_eq!(TotalColdkeyStake::::get(old_coldkey), 0); + assert_eq!(TotalColdkeyStake::::get(new_coldkey), stake); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_with_overflow_in_stake_addition --exact --nocapture +#[test] +fn test_swap_with_overflow_in_stake_addition() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let max_stake = u64::MAX; + + TotalColdkeyStake::::insert(old_coldkey, max_stake); + TotalColdkeyStake::::insert(new_coldkey, 1); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert_eq!(TotalColdkeyStake::::get(old_coldkey), 0); + assert_eq!(TotalColdkeyStake::::get(new_coldkey), max_stake); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_with_max_hotkeys --exact --nocapture +#[test] +fn test_swap_with_max_hotkeys() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let max_hotkeys = 1000; + let hotkeys: Vec = (0..max_hotkeys).map(U256::from).collect(); + + OwnedHotkeys::::insert(old_coldkey, hotkeys.clone()); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert!(OwnedHotkeys::::get(old_coldkey).is_empty()); + assert_eq!(OwnedHotkeys::::get(new_coldkey), hotkeys); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_effect_on_delegated_stake --exact --nocapture +#[test] +fn test_swap_effect_on_delegated_stake() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let delegator = U256::from(3); + let hotkey = U256::from(4); + let stake = 100; + + StakingHotkeys::::insert(old_coldkey, vec![hotkey]); + StakingHotkeys::::insert(delegator, vec![hotkey]); + Stake::::insert(hotkey, old_coldkey, stake); + Stake::::insert(hotkey, delegator, stake); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert_eq!(Stake::::get(hotkey, new_coldkey), stake); + assert_eq!(Stake::::get(hotkey, delegator), stake); + assert_eq!(Stake::::get(hotkey, old_coldkey), 0); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_concurrent_modifications --exact --nocapture +#[test] +fn test_swap_concurrent_modifications() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let hotkey = U256::from(3); + let netuid: u16 = 1; + let initial_stake = 100; + let additional_stake = 50; + + StakingHotkeys::::insert(old_coldkey, vec![hotkey]); + Stake::::insert(hotkey, old_coldkey, initial_stake); + + // Simulate concurrent stake addition + add_network(netuid, 1, 1); + SubtensorModule::add_balance_to_coldkey_account(&new_coldkey, additional_stake); + register_ok_neuron(netuid, hotkey, new_coldkey, 1001000); + assert_ok!(SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(new_coldkey), + hotkey, + additional_stake + )); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + assert_eq!( + Stake::::get(hotkey, new_coldkey), + initial_stake + additional_stake - 1 + ); + assert!(!Stake::::contains_key(hotkey, old_coldkey)); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test swap_coldkey -- test_swap_with_invalid_subnet_ownership --exact --nocapture +#[test] +fn test_swap_with_invalid_subnet_ownership() { + new_test_ext(1).execute_with(|| { + let old_coldkey = U256::from(1); + let new_coldkey = U256::from(2); + let netuid = 1u16; + + SubnetOwner::::insert(netuid, old_coldkey); + + // Simulate an invalid state where the subnet owner doesn't match the old_coldkey + SubnetOwner::::insert(netuid, U256::from(3)); + + let mut weight = Weight::zero(); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &old_coldkey, + &new_coldkey, + &mut weight + )); + + // The swap should not affect the mismatched subnet ownership + assert_eq!(SubnetOwner::::get(netuid), U256::from(3)); + }); +} + #[test] fn test_do_swap_coldkey_success() { new_test_ext(1).execute_with(|| { @@ -180,7 +644,7 @@ fn test_swap_stake_for_coldkey() { let initial_total_stake = SubtensorModule::get_total_stake(); // Perform the swap - SubtensorModule::swap_stake_for_coldkey(&old_coldkey, &new_coldkey, &mut weight); + SubtensorModule::perform_swap_coldkey(&old_coldkey, &new_coldkey, &mut weight); // Verify stake is additive, not replaced assert_eq!( @@ -222,6 +686,7 @@ fn test_swap_stake_for_coldkey() { }); } +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap_coldkey -- test_swap_staking_hotkeys_for_coldkey --exact --nocapture #[test] fn test_swap_staking_hotkeys_for_coldkey() { new_test_ext(1).execute_with(|| { @@ -248,7 +713,7 @@ fn test_swap_staking_hotkeys_for_coldkey() { TotalStake::::put(total_stake); // Perform the swap - SubtensorModule::swap_stake_for_coldkey(&old_coldkey, &new_coldkey, &mut weight); + SubtensorModule::perform_swap_coldkey(&old_coldkey, &new_coldkey, &mut weight); // Verify StakingHotkeys transfer assert_eq!( @@ -259,6 +724,7 @@ fn test_swap_staking_hotkeys_for_coldkey() { }); } +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap_coldkey -- test_swap_delegated_stake_for_coldkey --exact --nocapture #[test] fn test_swap_delegated_stake_for_coldkey() { new_test_ext(1).execute_with(|| { @@ -291,7 +757,7 @@ fn test_swap_delegated_stake_for_coldkey() { let initial_total_stake = SubtensorModule::get_total_stake(); // Perform the swap - SubtensorModule::swap_stake_for_coldkey(&old_coldkey, &new_coldkey, &mut weight); + SubtensorModule::perform_swap_coldkey(&old_coldkey, &new_coldkey, &mut weight); // Verify stake transfer assert_eq!(Stake::::get(hotkey1, new_coldkey), stake_amount1); @@ -321,6 +787,7 @@ fn test_swap_delegated_stake_for_coldkey() { }); } +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap_coldkey -- test_swap_total_hotkey_coldkey_stakes_this_interval_for_coldkey --exact --nocapture #[test] fn test_swap_total_hotkey_coldkey_stakes_this_interval_for_coldkey() { new_test_ext(1).execute_with(|| { @@ -340,11 +807,7 @@ fn test_swap_total_hotkey_coldkey_stakes_this_interval_for_coldkey() { OwnedHotkeys::::insert(old_coldkey, vec![hotkey1, hotkey2]); // Perform the swap - SubtensorModule::swap_total_hotkey_coldkey_stakes_this_interval_for_coldkey( - &old_coldkey, - &new_coldkey, - &mut weight, - ); + SubtensorModule::perform_swap_coldkey(&old_coldkey, &new_coldkey, &mut weight); // Verify the swap assert_eq!( @@ -363,13 +826,10 @@ fn test_swap_total_hotkey_coldkey_stakes_this_interval_for_coldkey() { old_coldkey, hotkey2 )); - - // Verify weight update - let expected_weight = ::DbWeight::get().reads_writes(5, 4); - assert_eq!(weight, expected_weight); }); } +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap_coldkey -- test_swap_subnet_owner_for_coldkey --exact --nocapture #[test] fn test_swap_subnet_owner_for_coldkey() { new_test_ext(1).execute_with(|| { @@ -380,6 +840,8 @@ fn test_swap_subnet_owner_for_coldkey() { let mut weight = Weight::zero(); // Initialize SubnetOwner for old_coldkey + add_network(netuid1, 13, 0); + add_network(netuid2, 14, 0); SubnetOwner::::insert(netuid1, old_coldkey); SubnetOwner::::insert(netuid2, old_coldkey); @@ -387,18 +849,15 @@ fn test_swap_subnet_owner_for_coldkey() { TotalNetworks::::put(3); // Perform the swap - SubtensorModule::swap_subnet_owner_for_coldkey(&old_coldkey, &new_coldkey, &mut weight); + SubtensorModule::perform_swap_coldkey(&old_coldkey, &new_coldkey, &mut weight); // Verify the swap assert_eq!(SubnetOwner::::get(netuid1), new_coldkey); assert_eq!(SubnetOwner::::get(netuid2), new_coldkey); - - // Verify weight update - let expected_weight = ::DbWeight::get().reads_writes(3, 2); - assert_eq!(weight, expected_weight); }); } +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap_coldkey -- test_do_swap_coldkey_with_subnet_ownership --exact --nocapture #[test] fn test_do_swap_coldkey_with_subnet_ownership() { new_test_ext(1).execute_with(|| { @@ -432,7 +891,7 @@ fn test_do_swap_coldkey_with_subnet_ownership() { assert_eq!(SubnetOwner::::get(netuid), new_coldkey); }); } - +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap_coldkey -- test_coldkey_has_associated_hotkeys --exact --nocapture #[test] fn test_coldkey_has_associated_hotkeys() { new_test_ext(1).execute_with(|| { @@ -447,7 +906,7 @@ fn test_coldkey_has_associated_hotkeys() { }); } -// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap -- test_coldkey_swap_total --exact --nocapture +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap_coldkey -- test_coldkey_swap_total --exact --nocapture #[test] fn test_coldkey_swap_total() { new_test_ext(1).execute_with(|| { @@ -669,9 +1128,11 @@ fn test_coldkey_swap_total() { // Perform the swap let new_coldkey = U256::from(1100); assert_eq!(SubtensorModule::get_total_stake_for_coldkey(&coldkey), 600); + let mut weight = Weight::zero(); assert_ok!(SubtensorModule::perform_swap_coldkey( &coldkey, - &new_coldkey + &new_coldkey, + &mut weight )); assert_eq!( SubtensorModule::get_total_stake_for_coldkey(&new_coldkey), @@ -741,7 +1202,7 @@ fn test_coldkey_swap_total() { ); }); } - +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap_coldkey -- test_swap_senate_member --exact --nocapture #[test] fn test_swap_senate_member() { new_test_ext(1).execute_with(|| { @@ -787,7 +1248,7 @@ fn test_swap_senate_member() { }); } -// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap -- test_coldkey_delegations --exact --nocapture +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap_coldkey -- test_coldkey_delegations --exact --nocapture #[test] fn test_coldkey_delegations() { new_test_ext(1).execute_with(|| { @@ -809,9 +1270,11 @@ fn test_coldkey_delegations() { delegate, 100 )); + let mut weight = Weight::zero(); assert_ok!(SubtensorModule::perform_swap_coldkey( &coldkey, - &new_coldkey + &new_coldkey, + &mut weight )); assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&delegate), 100); assert_eq!(SubtensorModule::get_total_stake_for_coldkey(&coldkey), 0); diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 2b9bb2595a..0018da2e0b 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -139,7 +139,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 188, + spec_version: 189, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,