diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 80a375d103..03e087a929 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -314,33 +314,33 @@ benchmarks! { assert_ok!(Subtensor::::register_network(RawOrigin::Signed(coldkey.clone()).into())); }: dissolve_network(RawOrigin::Signed(coldkey), 1) - swap_hotkey { - let seed: u32 = 1; - let coldkey: T::AccountId = account("Alice", 0, seed); - let old_hotkey: T::AccountId = account("Bob", 0, seed); - let new_hotkey: T::AccountId = account("Charlie", 0, seed); - - let netuid = 1u16; - Subtensor::::init_new_network(netuid, 100); - Subtensor::::set_min_burn(netuid, 1); - Subtensor::::set_max_burn(netuid, 1); - Subtensor::::set_target_registrations_per_interval(netuid, 256); - Subtensor::::set_max_registrations_per_block(netuid, 256); - - Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), 10_000_000_000u64); - assert_ok!(Subtensor::::burned_register(RawOrigin::Signed(coldkey.clone()).into(), netuid, old_hotkey.clone())); - assert_ok!(Subtensor::::become_delegate(RawOrigin::Signed(coldkey.clone()).into(), old_hotkey.clone())); - - let max_uids = Subtensor::::get_max_allowed_uids(netuid) as u32; - for i in 0..max_uids - 1 { - let coldkey: T::AccountId = account("Axon", 0, i); - let hotkey: T::AccountId = account("Hotkey", 0, i); - - Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), 10_000_000_000u64); - assert_ok!(Subtensor::::burned_register(RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey)); - assert_ok!(Subtensor::::add_stake(RawOrigin::Signed(coldkey).into(), old_hotkey.clone(), 1_000_000_000)); - } - }: _(RawOrigin::Signed(coldkey), old_hotkey, new_hotkey) + // swap_hotkey { + // let seed: u32 = 1; + // let coldkey: T::AccountId = account("Alice", 0, seed); + // let old_hotkey: T::AccountId = account("Bob", 0, seed); + // let new_hotkey: T::AccountId = account("Charlie", 0, seed); + + // let netuid = 1u16; + // Subtensor::::init_new_network(netuid, 100); + // Subtensor::::set_min_burn(netuid, 1); + // Subtensor::::set_max_burn(netuid, 1); + // Subtensor::::set_target_registrations_per_interval(netuid, 256); + // Subtensor::::set_max_registrations_per_block(netuid, 256); + + // Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), 10_000_000_000u64); + // assert_ok!(Subtensor::::burned_register(RawOrigin::Signed(coldkey.clone()).into(), netuid, old_hotkey.clone())); + // assert_ok!(Subtensor::::become_delegate(RawOrigin::Signed(coldkey.clone()).into(), old_hotkey.clone())); + + // let max_uids = Subtensor::::get_max_allowed_uids(netuid) as u32; + // for i in 0..max_uids - 1 { + // let coldkey: T::AccountId = account("Axon", 0, i); + // let hotkey: T::AccountId = account("Hotkey", 0, i); + + // Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), 10_000_000_000u64); + // assert_ok!(Subtensor::::burned_register(RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey)); + // assert_ok!(Subtensor::::add_stake(RawOrigin::Signed(coldkey).into(), old_hotkey.clone(), 1_000_000_000)); + // } + // }: _(RawOrigin::Signed(coldkey), old_hotkey, new_hotkey) commit_weights { let tempo: u16 = 1; diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index aa7cafde0d..83b6a4005f 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -2061,17 +2061,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. /// @@ -2253,6 +2253,19 @@ pub mod pallet { pub fn dissolve_network(origin: OriginFor, netuid: u16) -> DispatchResult { Self::user_remove_network(origin, netuid) } + + /// Sets values for liquid alpha + #[pallet::call_index(64)] + #[pallet::weight((0, DispatchClass::Operational, Pays::No))] + pub fn sudo_hotfix_swap_coldkey_delegates( + origin: OriginFor, + old_coldkey: T::AccountId, + new_coldkey: T::AccountId, + ) -> DispatchResult { + ensure_root(origin)?; + Self::swap_hotfix(&old_coldkey, &new_coldkey); + Ok(()) + } } // ---- Subtensor helper functions. diff --git a/pallets/subtensor/src/swap.rs b/pallets/subtensor/src/swap.rs index 307aeb6411..ce9646d88a 100644 --- a/pallets/subtensor/src/swap.rs +++ b/pallets/subtensor/src/swap.rs @@ -851,7 +851,8 @@ impl Pallet { log::info!("Transferring stake for hotkey {:?}: {}", hotkey, stake); if stake > 0 { // Insert the stake for the hotkey and new coldkey - Stake::::insert(hotkey, new_coldkey, stake); + 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 @@ -861,6 +862,52 @@ impl Pallet { 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); @@ -888,13 +935,30 @@ impl Pallet { } // 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); - OwnedHotkeys::::insert(new_coldkey, old_owned_hotkeys); 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::::take(old_coldkey); - StakingHotkeys::::insert(new_coldkey, staking_hotkeys); + 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 @@ -907,6 +971,36 @@ impl Pallet { TotalColdkeyStake::::get(new_coldkey) ); } + + pub fn swap_hotfix(old_coldkey: &T::AccountId, new_coldkey: &T::AccountId) { + // let weight = T::DbWeight::get().reads_writes(2, 1); + let staking_hotkeys = StakingHotkeys::::get(old_coldkey); + for staking_hotkey in staking_hotkeys { + 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); + 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)); + } + } + } + + let mut existing_staking_hotkeys = StakingHotkeys::::get(new_coldkey); + + let staking_hotkeys = StakingHotkeys::::get(old_coldkey); + for hotkey in staking_hotkeys { + if !existing_staking_hotkeys.contains(&hotkey) { + existing_staking_hotkeys.push(hotkey); + } + } + StakingHotkeys::::insert(new_coldkey, existing_staking_hotkeys); + StakingHotkeys::::remove(old_coldkey); + } + /// Swaps the total hotkey-coldkey stakes for the current interval from the old coldkey to the new coldkey. /// /// # Arguments diff --git a/pallets/subtensor/tests/registration.rs b/pallets/subtensor/tests/registration.rs index 676d49a449..bd95ae3b14 100644 --- a/pallets/subtensor/tests/registration.rs +++ b/pallets/subtensor/tests/registration.rs @@ -1868,153 +1868,153 @@ fn test_registration_disabled() { }); } -#[ignore] -#[test] -fn test_hotkey_swap_ok() { - new_test_ext(1).execute_with(|| { - let netuid: u16 = 1; - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let burn_cost = 1000; - let coldkey_account_id = U256::from(667); - - SubtensorModule::set_burn(netuid, burn_cost); - add_network(netuid, tempo, 0); - - // Give it some $$$ in his coldkey balance - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10_000_000_000); - - // Subscribe and check extrinsic output - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(coldkey_account_id), - netuid, - hotkey_account_id - )); - - let new_hotkey = U256::from(1337); - assert_ok!(SubtensorModule::swap_hotkey( - <::RuntimeOrigin>::signed(coldkey_account_id), - hotkey_account_id, - new_hotkey - )); - assert_ne!( - SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey_account_id), - coldkey_account_id - ); - assert_eq!( - SubtensorModule::get_owning_coldkey_for_hotkey(&new_hotkey), - coldkey_account_id - ); - }); -} - -#[ignore] -#[test] -fn test_hotkey_swap_not_owner() { - new_test_ext(1).execute_with(|| { - let netuid: u16 = 1; - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let burn_cost = 1000; - let coldkey_account_id = U256::from(2); - let not_owner_coldkey = U256::from(3); - - SubtensorModule::set_burn(netuid, burn_cost); - add_network(netuid, tempo, 0); - - // Give it some $$$ in his coldkey balance - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); - - // Subscribe and check extrinsic output - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(coldkey_account_id), - netuid, - hotkey_account_id - )); - - let new_hotkey = U256::from(4); - assert_err!( - SubtensorModule::swap_hotkey( - <::RuntimeOrigin>::signed(not_owner_coldkey), - hotkey_account_id, - new_hotkey - ), - Error::::NonAssociatedColdKey - ); - }); -} - -#[ignore] -#[test] -fn test_hotkey_swap_same_key() { - new_test_ext(1).execute_with(|| { - let netuid: u16 = 1; - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let burn_cost = 1000; - let coldkey_account_id = U256::from(2); - - SubtensorModule::set_burn(netuid, burn_cost); - add_network(netuid, tempo, 0); - - // Give it some $$$ in his coldkey balance - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); +// #[ignore] +// #[test] +// fn test_hotkey_swap_ok() { +// new_test_ext(1).execute_with(|| { +// let netuid: u16 = 1; +// let tempo: u16 = 13; +// let hotkey_account_id = U256::from(1); +// let burn_cost = 1000; +// let coldkey_account_id = U256::from(667); + +// SubtensorModule::set_burn(netuid, burn_cost); +// add_network(netuid, tempo, 0); + +// // Give it some $$$ in his coldkey balance +// SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10_000_000_000); + +// // Subscribe and check extrinsic output +// assert_ok!(SubtensorModule::burned_register( +// <::RuntimeOrigin>::signed(coldkey_account_id), +// netuid, +// hotkey_account_id +// )); - // Subscribe and check extrinsic output - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(coldkey_account_id), - netuid, - hotkey_account_id - )); +// let new_hotkey = U256::from(1337); +// assert_ok!(SubtensorModule::swap_hotkey( +// <::RuntimeOrigin>::signed(coldkey_account_id), +// hotkey_account_id, +// new_hotkey +// )); +// assert_ne!( +// SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey_account_id), +// coldkey_account_id +// ); +// assert_eq!( +// SubtensorModule::get_owning_coldkey_for_hotkey(&new_hotkey), +// coldkey_account_id +// ); +// }); +// } - assert_err!( - SubtensorModule::swap_hotkey( - <::RuntimeOrigin>::signed(coldkey_account_id), - hotkey_account_id, - hotkey_account_id - ), - Error::::HotKeyAlreadyRegisteredInSubNet - ); - }); -} +// #[ignore] +// #[test] +// fn test_hotkey_swap_not_owner() { +// new_test_ext(1).execute_with(|| { +// let netuid: u16 = 1; +// let tempo: u16 = 13; +// let hotkey_account_id = U256::from(1); +// let burn_cost = 1000; +// let coldkey_account_id = U256::from(2); +// let not_owner_coldkey = U256::from(3); + +// SubtensorModule::set_burn(netuid, burn_cost); +// add_network(netuid, tempo, 0); + +// // Give it some $$$ in his coldkey balance +// SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); + +// // Subscribe and check extrinsic output +// assert_ok!(SubtensorModule::burned_register( +// <::RuntimeOrigin>::signed(coldkey_account_id), +// netuid, +// hotkey_account_id +// )); -#[ignore] -#[test] -fn test_hotkey_swap_registered_key() { - new_test_ext(1).execute_with(|| { - let netuid: u16 = 1; - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let burn_cost = 1000; - let coldkey_account_id = U256::from(2); +// let new_hotkey = U256::from(4); +// assert_err!( +// SubtensorModule::swap_hotkey( +// <::RuntimeOrigin>::signed(not_owner_coldkey), +// hotkey_account_id, +// new_hotkey +// ), +// Error::::NonAssociatedColdKey +// ); +// }); +// } - SubtensorModule::set_burn(netuid, burn_cost); - add_network(netuid, tempo, 0); +// #[ignore] +// #[test] +// fn test_hotkey_swap_same_key() { +// new_test_ext(1).execute_with(|| { +// let netuid: u16 = 1; +// let tempo: u16 = 13; +// let hotkey_account_id = U256::from(1); +// let burn_cost = 1000; +// let coldkey_account_id = U256::from(2); + +// SubtensorModule::set_burn(netuid, burn_cost); +// add_network(netuid, tempo, 0); + +// // Give it some $$$ in his coldkey balance +// SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); + +// // Subscribe and check extrinsic output +// assert_ok!(SubtensorModule::burned_register( +// <::RuntimeOrigin>::signed(coldkey_account_id), +// netuid, +// hotkey_account_id +// )); - // Give it some $$$ in his coldkey balance - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 100_000_000_000); +// assert_err!( +// SubtensorModule::swap_hotkey( +// <::RuntimeOrigin>::signed(coldkey_account_id), +// hotkey_account_id, +// hotkey_account_id +// ), +// Error::::HotKeyAlreadyRegisteredInSubNet +// ); +// }); +// } - // Subscribe and check extrinsic output - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(coldkey_account_id), - netuid, - hotkey_account_id - )); +// #[ignore] +// #[test] +// fn test_hotkey_swap_registered_key() { +// new_test_ext(1).execute_with(|| { +// let netuid: u16 = 1; +// let tempo: u16 = 13; +// let hotkey_account_id = U256::from(1); +// let burn_cost = 1000; +// let coldkey_account_id = U256::from(2); + +// SubtensorModule::set_burn(netuid, burn_cost); +// add_network(netuid, tempo, 0); + +// // Give it some $$$ in his coldkey balance +// SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 100_000_000_000); + +// // Subscribe and check extrinsic output +// assert_ok!(SubtensorModule::burned_register( +// <::RuntimeOrigin>::signed(coldkey_account_id), +// netuid, +// hotkey_account_id +// )); - let new_hotkey = U256::from(3); - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(coldkey_account_id), - netuid, - new_hotkey - )); +// let new_hotkey = U256::from(3); +// assert_ok!(SubtensorModule::burned_register( +// <::RuntimeOrigin>::signed(coldkey_account_id), +// netuid, +// new_hotkey +// )); - assert_err!( - SubtensorModule::swap_hotkey( - <::RuntimeOrigin>::signed(coldkey_account_id), - hotkey_account_id, - new_hotkey - ), - Error::::HotKeyAlreadyRegisteredInSubNet - ); - }); -} +// assert_err!( +// SubtensorModule::swap_hotkey( +// <::RuntimeOrigin>::signed(coldkey_account_id), +// hotkey_account_id, +// new_hotkey +// ), +// Error::::HotKeyAlreadyRegisteredInSubNet +// ); +// }); +// } diff --git a/pallets/subtensor/tests/swap.rs b/pallets/subtensor/tests/swap.rs index 2355dc960d..6acf0b8200 100644 --- a/pallets/subtensor/tests/swap.rs +++ b/pallets/subtensor/tests/swap.rs @@ -1205,6 +1205,7 @@ fn test_do_swap_coldkey_success() { }); } +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap -- test_swap_stake_for_coldkey --exact --nocaptur #[test] fn test_swap_stake_for_coldkey() { new_test_ext(1).execute_with(|| { @@ -1214,13 +1215,22 @@ fn test_swap_stake_for_coldkey() { let hotkey2 = U256::from(4); let stake_amount1 = 1000u64; let stake_amount2 = 2000u64; + let stake_amount3 = 3000u64; let total_stake = stake_amount1 + stake_amount2; let mut weight = Weight::zero(); // Setup initial state OwnedHotkeys::::insert(old_coldkey, vec![hotkey1, hotkey2]); + StakingHotkeys::::insert(old_coldkey, vec![hotkey1, hotkey2]); Stake::::insert(hotkey1, old_coldkey, stake_amount1); Stake::::insert(hotkey2, old_coldkey, stake_amount2); + assert_eq!(Stake::::get(hotkey1, old_coldkey), stake_amount1); + assert_eq!(Stake::::get(hotkey1, old_coldkey), stake_amount1); + + // Insert existing for same hotkey1 + Stake::::insert(hotkey1, new_coldkey, stake_amount3); + StakingHotkeys::::insert(new_coldkey, vec![hotkey1]); + TotalHotkeyStake::::insert(hotkey1, stake_amount1); TotalHotkeyStake::::insert(hotkey2, stake_amount2); TotalColdkeyStake::::insert(old_coldkey, total_stake); @@ -1236,6 +1246,12 @@ fn test_swap_stake_for_coldkey() { // Perform the swap SubtensorModule::swap_stake_for_coldkey(&old_coldkey, &new_coldkey, &mut weight); + // Verify stake is additive, not replaced + assert_eq!( + Stake::::get(hotkey1, new_coldkey), + stake_amount1 + stake_amount3 + ); + // Verify ownership transfer assert_eq!( SubtensorModule::get_owned_hotkeys(&new_coldkey), @@ -1243,6 +1259,104 @@ fn test_swap_stake_for_coldkey() { ); assert_eq!(SubtensorModule::get_owned_hotkeys(&old_coldkey), vec![]); + // Verify stake transfer + assert_eq!(Stake::::get(hotkey2, new_coldkey), stake_amount2); + assert_eq!(Stake::::get(hotkey1, old_coldkey), 0); + assert_eq!(Stake::::get(hotkey2, old_coldkey), 0); + + // Verify TotalColdkeyStake + assert_eq!(TotalColdkeyStake::::get(new_coldkey), total_stake); + assert_eq!(TotalColdkeyStake::::get(old_coldkey), 0); + + // Verify TotalHotkeyStake remains unchanged + assert_eq!(TotalHotkeyStake::::get(hotkey1), stake_amount1); + assert_eq!(TotalHotkeyStake::::get(hotkey2), stake_amount2); + + // Verify total stake and issuance remain unchanged + assert_eq!( + SubtensorModule::get_total_stake(), + initial_total_stake, + "Total stake changed unexpectedly" + ); + assert_eq!( + SubtensorModule::get_total_issuance(), + initial_total_issuance, + "Total issuance changed unexpectedly" + ); + }); +} + +#[test] +fn test_swap_staking_hotkeys_for_coldkey() { + 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); + let stake_amount1 = 1000u64; + let stake_amount2 = 2000u64; + let total_stake = stake_amount1 + stake_amount2; + let mut weight = Weight::zero(); + + // Setup initial state + OwnedHotkeys::::insert(old_coldkey, vec![hotkey1, hotkey2]); + Stake::::insert(hotkey1, old_coldkey, stake_amount1); + Stake::::insert(hotkey2, old_coldkey, stake_amount2); + StakingHotkeys::::insert(old_coldkey, vec![hotkey1, hotkey2]); + TotalHotkeyStake::::insert(hotkey1, stake_amount1); + TotalHotkeyStake::::insert(hotkey2, stake_amount2); + TotalColdkeyStake::::insert(old_coldkey, total_stake); + + // Set up total issuance + TotalIssuance::::put(total_stake); + TotalStake::::put(total_stake); + + // Perform the swap + SubtensorModule::swap_stake_for_coldkey(&old_coldkey, &new_coldkey, &mut weight); + + // Verify StakingHotkeys transfer + assert_eq!( + StakingHotkeys::::get(new_coldkey), + vec![hotkey1, hotkey2] + ); + assert_eq!(StakingHotkeys::::get(old_coldkey), vec![]); + }); +} + +#[test] +fn test_swap_delegated_stake_for_coldkey() { + 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); + let stake_amount1 = 1000u64; + let stake_amount2 = 2000u64; + let total_stake = stake_amount1 + stake_amount2; + let mut weight = Weight::zero(); + + // Notice hotkey1 and hotkey2 are not in OwnedHotkeys + // coldkey therefore delegates stake to them + + // Setup initial state + StakingHotkeys::::insert(old_coldkey, vec![hotkey1, hotkey2]); + Stake::::insert(hotkey1, old_coldkey, stake_amount1); + Stake::::insert(hotkey2, old_coldkey, stake_amount2); + TotalHotkeyStake::::insert(hotkey1, stake_amount1); + TotalHotkeyStake::::insert(hotkey2, stake_amount2); + TotalColdkeyStake::::insert(old_coldkey, total_stake); + + // Set up total issuance + TotalIssuance::::put(total_stake); + TotalStake::::put(total_stake); + + // Record initial values + let initial_total_issuance = SubtensorModule::get_total_issuance(); + let initial_total_stake = SubtensorModule::get_total_stake(); + + // Perform the swap + SubtensorModule::swap_stake_for_coldkey(&old_coldkey, &new_coldkey, &mut weight); + // Verify stake transfer assert_eq!(Stake::::get(hotkey1, new_coldkey), stake_amount1); assert_eq!(Stake::::get(hotkey2, new_coldkey), stake_amount2); @@ -1736,3 +1850,130 @@ fn test_swap_senate_member() { assert_eq!(weight, expected_weight); }); } + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap -- test_coldkey_delegations --exact --nocapture +#[test] +fn test_coldkey_delegations() { + new_test_ext(1).execute_with(|| { + let new_coldkey = U256::from(0); + let owner = U256::from(1); + let coldkey = U256::from(4); + let delegate = U256::from(2); + let netuid = 1u16; + add_network(netuid, 13, 0); + register_ok_neuron(netuid, delegate, owner, 0); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, 1000); + assert_ok!(SubtensorModule::do_become_delegate( + <::RuntimeOrigin>::signed(owner), + delegate, + u16::MAX / 10 + )); + assert_ok!(SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(coldkey), + delegate, + 100 + )); + assert_ok!(SubtensorModule::perform_swap_coldkey( + &coldkey, + &new_coldkey + )); + assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&delegate), 100); + assert_eq!(SubtensorModule::get_total_stake_for_coldkey(&coldkey), 0); + assert_eq!( + SubtensorModule::get_total_stake_for_coldkey(&new_coldkey), + 100 + ); + assert_eq!(Stake::::get(delegate, new_coldkey), 100); + assert_eq!(Stake::::get(delegate, coldkey), 0); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap -- test_sudo_hotfix_swap_coldkey_delegates --exact --nocapture +// #[test] +// fn test_sudo_hotfix_swap_coldkey_delegates() { +// new_test_ext(1).execute_with(|| { +// let new_coldkey = U256::from(0); +// let owner = U256::from(1); +// let coldkey = U256::from(4); +// let delegate = U256::from(2); +// let netuid = 1u16; +// add_network(netuid, 13, 0); +// register_ok_neuron(netuid, delegate, owner, 0); +// SubtensorModule::add_balance_to_coldkey_account(&coldkey, 1000); +// assert_ok!(SubtensorModule::do_become_delegate( +// <::RuntimeOrigin>::signed(owner), +// delegate, +// u16::MAX / 10 +// )); +// assert_ok!(SubtensorModule::add_stake( +// <::RuntimeOrigin>::signed(coldkey), +// delegate, +// 100 +// )); + +// assert_ok!(SubtensorModule::perform_swap_coldkey( +// &coldkey, +// &new_coldkey +// )); + +// assert_ok!(AdminUtils::sudo_hotfix_swap_coldkey_delegates( +// <::RuntimeOrigin>::root(), +// to_be_set +// )); + +// assert_eq!( SubtensorModule::get_total_stake_for_hotkey( &delegate), 100 ); +// assert_eq!( SubtensorModule::get_total_stake_for_coldkey( &coldkey), 0 ); +// assert_eq!( SubtensorModule::get_total_stake_for_coldkey( &new_coldkey), 100 ); +// assert_eq!( Stake::::get( delegate, new_coldkey ), 100 ); +// assert_eq!( Stake::::get( delegate, coldkey ), 0 ); + +// }); +// } + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap -- test_sudo_hotfix_swap_coldkey_delegates --exact --nocapture +#[test] +fn test_sudo_hotfix_swap_coldkey_delegates() { + new_test_ext(1).execute_with(|| { + let new_coldkey = U256::from(0); + let coldkey = U256::from(4); + assert_ok!(SubtensorModule::sudo_hotfix_swap_coldkey_delegates( + <::RuntimeOrigin>::root(), + coldkey, + new_coldkey + )); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test swap -- test_sudo_hotfix_swap_coldkey_delegates_with_broken_stake --exact --nocapture +#[test] +fn test_sudo_hotfix_swap_coldkey_delegates_with_broken_stake() { + new_test_ext(1).execute_with(|| { + let new_coldkey = U256::from(0); + let old_coldkey = U256::from(4); + let h1 = U256::from(5); + let h2 = U256::from(6); + let h3 = U256::from(7); + Stake::::insert(h3, old_coldkey, 100); + Stake::::insert(h2, old_coldkey, 100); + assert_eq!(Stake::::get(h3, old_coldkey), 100); + assert_eq!(Stake::::get(h2, old_coldkey), 100); + StakingHotkeys::::insert(new_coldkey, vec![h1, h2]); + StakingHotkeys::::insert(old_coldkey, vec![h3, h2]); + assert_ok!(SubtensorModule::sudo_hotfix_swap_coldkey_delegates( + <::RuntimeOrigin>::root(), + old_coldkey, + new_coldkey + )); + let hotkeys = StakingHotkeys::::get(new_coldkey); + assert_eq!(hotkeys.len(), 3); + assert_eq!(hotkeys[0], h1); + assert_eq!(hotkeys[1], h2); + assert_eq!(hotkeys[2], h3); + let hotkeys_old = StakingHotkeys::::get(old_coldkey); + assert_eq!(hotkeys_old.len(), 0); + assert_eq!(Stake::::get(h3, old_coldkey), 0); + assert_eq!(Stake::::get(h2, old_coldkey), 0); + assert_eq!(Stake::::get(h3, new_coldkey), 100); + assert_eq!(Stake::::get(h2, new_coldkey), 100); + }); +} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index b343ad0f06..d1fe2e0c9d 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: 162, + spec_version: 164, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,