diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 563dd211fe..089631db82 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -2190,10 +2190,11 @@ mod pallet_benchmarks { netuid, ); - assert!( - Lock::::iter_prefix((coldkey, netuid)) - .any(|(locked_hotkey, _)| locked_hotkey == hotkey_dest) - ); + // Lock moving temporarily disabled + // assert!( + // Lock::::iter_prefix((coldkey, netuid)) + // .any(|(locked_hotkey, _)| locked_hotkey == hotkey_dest) + // ); } impl_benchmark_test_suite!( diff --git a/pallets/subtensor/src/staking/lock.rs b/pallets/subtensor/src/staking/lock.rs index 05a2ebde61..9ea7dbab94 100644 --- a/pallets/subtensor/src/staking/lock.rs +++ b/pallets/subtensor/src/staking/lock.rs @@ -169,62 +169,65 @@ impl Pallet { /// If no lock exists, creates one. If one exists, the hotkey must match. /// Top-up adds to locked_mass after rolling forward. pub fn do_lock_stake( - coldkey: &T::AccountId, - netuid: NetUid, - hotkey: &T::AccountId, - amount: AlphaBalance, + _coldkey: &T::AccountId, + _netuid: NetUid, + _hotkey: &T::AccountId, + _amount: AlphaBalance, ) -> dispatch::DispatchResult { - ensure!(!amount.is_zero(), Error::::AmountTooLow); - Self::ensure_available_stake(coldkey, netuid, amount) - .map_err(|_| Error::::InsufficientStakeForLock)?; - - let now = Self::get_current_block_as_u64(); - let existing = Lock::::iter_prefix((coldkey, netuid)).next(); - - match existing { - None => { - Self::insert_lock_state( - coldkey, - netuid, - hotkey, - LockState { - locked_mass: amount, - unlocked_mass: 0.into(), - conviction: U64F64::saturating_from_num(0), - last_update: now, - }, - ); - } - Some((existing_hotkey, existing)) => { - ensure!(*hotkey == existing_hotkey, Error::::LockHotkeyMismatch); - - let lock = Self::roll_forward_lock(existing, now); - let new_locked = lock.locked_mass.saturating_add(amount); - Self::insert_lock_state( - coldkey, - netuid, - hotkey, - LockState { - locked_mass: new_locked, - unlocked_mass: lock.unlocked_mass, - conviction: lock.conviction, - last_update: now, - }, - ); - } - } - - // Update the total hotkey lock - Self::upsert_hotkey_lock(hotkey, netuid, amount); - - Self::deposit_event(Event::StakeLocked { - coldkey: coldkey.clone(), - hotkey: hotkey.clone(), - netuid, - amount, - }); - + // Temporarily disabled Ok(()) + + // ensure!(!amount.is_zero(), Error::::AmountTooLow); + // Self::ensure_available_stake(coldkey, netuid, amount) + // .map_err(|_| Error::::InsufficientStakeForLock)?; + + // let now = Self::get_current_block_as_u64(); + // let existing = Lock::::iter_prefix((coldkey, netuid)).next(); + + // match existing { + // None => { + // Self::insert_lock_state( + // coldkey, + // netuid, + // hotkey, + // LockState { + // locked_mass: amount, + // unlocked_mass: 0.into(), + // conviction: U64F64::saturating_from_num(0), + // last_update: now, + // }, + // ); + // } + // Some((existing_hotkey, existing)) => { + // ensure!(*hotkey == existing_hotkey, Error::::LockHotkeyMismatch); + + // let lock = Self::roll_forward_lock(existing, now); + // let new_locked = lock.locked_mass.saturating_add(amount); + // Self::insert_lock_state( + // coldkey, + // netuid, + // hotkey, + // LockState { + // locked_mass: new_locked, + // unlocked_mass: lock.unlocked_mass, + // conviction: lock.conviction, + // last_update: now, + // }, + // ); + // } + // } + + // // Update the total hotkey lock + // Self::upsert_hotkey_lock(hotkey, netuid, amount); + + // Self::deposit_event(Event::StakeLocked { + // coldkey: coldkey.clone(), + // hotkey: hotkey.clone(), + // netuid, + // amount, + // }); + + // Ok(()) } pub fn do_unlock_stake( @@ -527,71 +530,75 @@ impl Pallet { /// The conviction is reset to zero if the destination and source hotkeys /// are owned by different coldkeys, otherwise it is preserved. pub fn do_move_lock( - coldkey: &T::AccountId, - destination_hotkey: &T::AccountId, - netuid: NetUid, + _coldkey: &T::AccountId, + _destination_hotkey: &T::AccountId, + _netuid: NetUid, ) -> DispatchResult { - let now = Self::get_current_block_as_u64(); - - match Lock::::iter_prefix((coldkey, netuid)).next() { - Some((origin_hotkey, existing)) => { - let old_hotkey_owner = Self::get_owning_coldkey_for_hotkey(&origin_hotkey); - let new_hotkey_owner = Self::get_owning_coldkey_for_hotkey(destination_hotkey); - let same_owner = old_hotkey_owner != DefaultAccount::::get() - && new_hotkey_owner != DefaultAccount::::get() - && old_hotkey_owner == new_hotkey_owner; - - let mut existing_rolled = Self::roll_forward_lock(existing, now); - let existing_conviction = existing_rolled.conviction; - if !same_owner { - existing_rolled.conviction = U64F64::saturating_from_num(0); - } - - Lock::::remove((coldkey.clone(), netuid, origin_hotkey.clone())); - Self::insert_lock_state( - coldkey, - netuid, - destination_hotkey, - LockState { - locked_mass: existing_rolled.locked_mass, - unlocked_mass: existing_rolled.unlocked_mass, - conviction: existing_rolled.conviction, - last_update: now, - }, - ); - - // Update the total hotkey locks for destination hotkey - Self::upsert_hotkey_lock(destination_hotkey, netuid, existing_rolled.locked_mass); - - // Reduce the total hotkey locks and conviction for the origin hotkey - Self::reduce_hotkey_lock( - &origin_hotkey, - netuid, - existing_rolled.locked_mass, - existing_conviction, - ); - - // If the same coldkey owns both the origin and destination hotkeys, also - // transfer the conviction instead of resetting it - if same_owner { - HotkeyLock::::mutate(netuid, destination_hotkey, |dest_lock_opt| { - if let Some(dest_lock) = dest_lock_opt { - dest_lock.conviction = - dest_lock.conviction.saturating_add(existing_conviction); - } - }); - } + // Temporarily disabled + // TODO: When enabled, uncomment an assert in move_lock benchmark + Ok(()) - Self::deposit_event(Event::LockMoved { - coldkey: coldkey.clone(), - origin_hotkey, - destination_hotkey: destination_hotkey.clone(), - netuid, - }); - Ok(()) - } - None => Err(Error::::NoExistingLock.into()), - } + // let now = Self::get_current_block_as_u64(); + + // match Lock::::iter_prefix((coldkey, netuid)).next() { + // Some((origin_hotkey, existing)) => { + // let old_hotkey_owner = Self::get_owning_coldkey_for_hotkey(&origin_hotkey); + // let new_hotkey_owner = Self::get_owning_coldkey_for_hotkey(destination_hotkey); + // let same_owner = old_hotkey_owner != DefaultAccount::::get() + // && new_hotkey_owner != DefaultAccount::::get() + // && old_hotkey_owner == new_hotkey_owner; + + // let mut existing_rolled = Self::roll_forward_lock(existing, now); + // let existing_conviction = existing_rolled.conviction; + // if !same_owner { + // existing_rolled.conviction = U64F64::saturating_from_num(0); + // } + + // Lock::::remove((coldkey.clone(), netuid, origin_hotkey.clone())); + // Self::insert_lock_state( + // coldkey, + // netuid, + // destination_hotkey, + // LockState { + // locked_mass: existing_rolled.locked_mass, + // unlocked_mass: existing_rolled.unlocked_mass, + // conviction: existing_rolled.conviction, + // last_update: now, + // }, + // ); + + // // Update the total hotkey locks for destination hotkey + // Self::upsert_hotkey_lock(destination_hotkey, netuid, existing_rolled.locked_mass); + + // // Reduce the total hotkey locks and conviction for the origin hotkey + // Self::reduce_hotkey_lock( + // &origin_hotkey, + // netuid, + // existing_rolled.locked_mass, + // existing_conviction, + // ); + + // // If the same coldkey owns both the origin and destination hotkeys, also + // // transfer the conviction instead of resetting it + // if same_owner { + // HotkeyLock::::mutate(netuid, destination_hotkey, |dest_lock_opt| { + // if let Some(dest_lock) = dest_lock_opt { + // dest_lock.conviction = + // dest_lock.conviction.saturating_add(existing_conviction); + // } + // }); + // } + + // Self::deposit_event(Event::LockMoved { + // coldkey: coldkey.clone(), + // origin_hotkey, + // destination_hotkey: destination_hotkey.clone(), + // netuid, + // }); + // Ok(()) + // } + // None => Err(Error::::NoExistingLock.into()), + // } } pub fn auto_lock_owner_cut(netuid: NetUid, amount: AlphaBalance) { diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index e1aa5eb744..a5326ca395 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -235,6 +235,9 @@ impl Pallet { let owner_alpha_stake = AlphaBalance::ZERO; + // With the full lock retained in the reserve, this will normally be zero. + let tao_recycled_for_registration = actual_tao_lock_amount.saturating_sub(total_pool_tao); + // Core pool + ownership SubnetTAO::::insert(netuid_to_register, total_pool_tao); SubnetAlphaIn::::insert(netuid_to_register, total_pool_alpha); @@ -245,6 +248,15 @@ impl Pallet { SubnetAlphaInProvided::::insert(netuid_to_register, AlphaBalance::ZERO); SubnetAlphaOut::::insert(netuid_to_register, owner_alpha_stake); SubnetVolume::::insert(netuid_to_register, 0u128); + RAORecycledForRegistration::::insert(netuid_to_register, tao_recycled_for_registration); + + if tao_recycled_for_registration > TaoBalance::ZERO + && let Some(subnet_account_id) = Self::get_subnet_account_id(netuid_to_register) + { + // The subnet account ID is guaranteed to have adequate balance for this + // recycle because of transfer operation earlier. No need to check this result. + let _ = Self::recycle_tao(&subnet_account_id, tao_recycled_for_registration); + } if total_pool_tao > TaoBalance::ZERO { // Record in TotalStake the initial TAO in the pool. diff --git a/pallets/subtensor/src/tests/locks.rs b/pallets/subtensor/src/tests/locks.rs index 00472bebe5..b0b6aeaad6 100644 --- a/pallets/subtensor/src/tests/locks.rs +++ b/pallets/subtensor/src/tests/locks.rs @@ -67,6 +67,7 @@ fn get_alpha( // ========================================================================= #[test] +#[ignore] fn test_lock_stake_creates_new_lock() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -99,6 +100,7 @@ fn test_lock_stake_creates_new_lock() { } #[test] +#[ignore] fn test_lock_stake_emits_event() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -127,6 +129,7 @@ fn test_lock_stake_emits_event() { } #[test] +#[ignore] fn test_lock_stake_full_amount() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -190,6 +193,7 @@ fn test_available_to_unstake_no_lock() { } #[test] +#[ignore] fn test_available_to_unstake_with_lock() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -211,6 +215,7 @@ fn test_available_to_unstake_with_lock() { } #[test] +#[ignore] fn test_available_to_unstake_fully_locked() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -232,6 +237,7 @@ fn test_available_to_unstake_fully_locked() { // ========================================================================= #[test] +#[ignore] fn test_lock_stake_topup() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -277,6 +283,7 @@ fn test_lock_stake_topup() { } #[test] +#[ignore] fn test_lock_stake_topup_multiple_times() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -312,6 +319,7 @@ fn test_lock_stake_topup_multiple_times() { } #[test] +#[ignore] fn test_lock_stake_topup_same_block() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -346,6 +354,7 @@ fn test_lock_stake_topup_same_block() { // ========================================================================= #[test] +#[ignore] fn test_lock_stake_zero_amount() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -360,6 +369,7 @@ fn test_lock_stake_zero_amount() { } #[test] +#[ignore] fn test_lock_stake_exceeds_total_alpha() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -377,6 +387,7 @@ fn test_lock_stake_exceeds_total_alpha() { } #[test] +#[ignore] fn test_lock_stake_wrong_hotkey() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -399,6 +410,7 @@ fn test_lock_stake_wrong_hotkey() { } #[test] +#[ignore] fn test_lock_stake_topup_exceeds_total() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -476,6 +488,7 @@ fn test_exp_decay_clamps_large_dt_to_min_ratio() { } #[test] +#[ignore] fn test_roll_forward_locked_mass_no_change() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -503,6 +516,7 @@ fn test_roll_forward_locked_mass_no_change() { } #[test] +#[ignore] fn test_roll_forward_conviction_converges_to_lock() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -617,6 +631,7 @@ fn test_unstake_allowed_up_to_available() { } #[test] +#[ignore] fn test_unstake_blocked_by_lock() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -679,6 +694,7 @@ fn test_move_stake_same_coldkey_same_subnet_allowed() { } #[test] +#[ignore] fn test_do_transfer_stake_same_subnet_transfers_lock_to_destination_hotkey() { new_test_ext(1).execute_with(|| { let coldkey_sender = U256::from(1); @@ -739,6 +755,7 @@ fn test_do_transfer_stake_same_subnet_transfers_lock_to_destination_hotkey() { } #[test] +#[ignore] fn test_move_stake_cross_subnet_blocked_by_lock() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -777,6 +794,7 @@ fn test_move_stake_cross_subnet_blocked_by_lock() { } #[test] +#[ignore] fn test_transfer_stake_cross_coldkey_allowed_partial() { new_test_ext(1).execute_with(|| { let coldkey_sender = U256::from(1); @@ -833,6 +851,7 @@ fn test_transfer_stake_cross_coldkey_allowed_partial() { // ========================================================================= #[test] +#[ignore] fn test_lock_on_multiple_subnets() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -894,6 +913,7 @@ fn test_lock_on_multiple_subnets() { } #[test] +#[ignore] fn test_unstake_one_subnet_does_not_affect_other() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -958,6 +978,7 @@ fn test_unstake_one_subnet_does_not_affect_other() { // ========================================================================= #[test] +#[ignore] fn test_hotkey_conviction_single_locker() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -1036,6 +1057,7 @@ fn test_hotkey_conviction_multiple_lockers() { } #[test] +#[ignore] fn test_subnet_king_single_hotkey() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -1057,6 +1079,7 @@ fn test_subnet_king_single_hotkey() { } #[test] +#[ignore] fn test_subnet_king_highest_conviction_wins() { new_test_ext(1).execute_with(|| { let coldkey1 = U256::from(1); @@ -1216,6 +1239,7 @@ fn test_reduce_lock_no_lock() { } #[test] +#[ignore] fn test_reduce_lock_two_coldkeys() { new_test_ext(1).execute_with(|| { let coldkey1 = U256::from(1001); @@ -1304,6 +1328,7 @@ fn test_reduce_lock_two_coldkeys() { // ========================================================================= #[test] +#[ignore] fn test_coldkey_swap_swaps_lock() { new_test_ext(1).execute_with(|| { let old_coldkey = U256::from(1); @@ -1333,6 +1358,7 @@ fn test_coldkey_swap_swaps_lock() { } #[test] +#[ignore] fn test_coldkey_swap_lock_blocks_unstake() { new_test_ext(1).execute_with(|| { let old_coldkey = U256::from(1); @@ -1369,6 +1395,7 @@ fn test_coldkey_swap_lock_blocks_unstake() { } #[test] +#[ignore] // When both coldkeys already have unlocked-only lock state on the same subnet, the destination // hotkey key should be preserved and unlocked_mass should be accumulated onto that record. fn test_coldkey_swap_adds_unlocked_mass_into_existing_destination_lock() { @@ -1557,6 +1584,7 @@ fn test_failed_coldkey_swap_extrinsic_rolls_back_state_changes() { // ========================================================================= #[test] +#[ignore] fn test_hotkey_swap_swaps_locks_and_convictions() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -1622,6 +1650,7 @@ fn test_hotkey_swap_swaps_locks_and_convictions() { // ========================================================================= #[test] +#[ignore] fn test_lock_stake_extrinsic() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -1653,6 +1682,7 @@ fn test_lock_stake_extrinsic() { // ========================================================================= #[test] +#[ignore] fn test_recycle_alpha_checks_lock() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -1696,6 +1726,7 @@ fn test_recycle_alpha_checks_lock() { } #[test] +#[ignore] fn test_burn_alpha_checks_lock() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -1734,6 +1765,7 @@ fn test_burn_alpha_checks_lock() { // ========================================================================= #[test] +#[ignore] fn test_subnet_dissolution_orphans_locks() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -1981,6 +2013,7 @@ fn test_clear_small_nomination_reduces_only_tiny_amount_from_lock_state() { // ========================================================================= #[test] +#[ignore] fn test_emissions_do_not_break_lock_invariant() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -2015,6 +2048,7 @@ fn test_emissions_do_not_break_lock_invariant() { } #[test] +#[ignore] fn test_epoch_distribution_auto_locks_owner_cut() { new_test_ext(1).execute_with(|| { let subnet_owner_coldkey = U256::from(1001); @@ -2108,6 +2142,7 @@ fn test_epoch_distribution_auto_locks_owner_cut() { // ========================================================================= #[test] +#[ignore] fn test_neuron_replacement_does_not_affect_lock() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -2158,6 +2193,7 @@ fn test_neuron_replacement_does_not_affect_lock() { // ========================================================================= #[test] +#[ignore] fn test_moving_lock() { new_test_ext(1).execute_with(|| { let coldkey = U256::from(1); @@ -2203,6 +2239,7 @@ fn test_moving_lock() { } #[test] +#[ignore] fn test_moving_partial_lock() { new_test_ext(1).execute_with(|| { let coldkey1 = U256::from(1); @@ -2287,6 +2324,7 @@ fn test_moving_partial_lock() { } #[test] +#[ignore] fn test_moving_partial_lock_same_owners() { new_test_ext(1).execute_with(|| { let coldkey1 = U256::from(1); @@ -2371,6 +2409,7 @@ fn test_moving_partial_lock_same_owners() { } #[test] +#[ignore] // Moving a lock after partially unlocking it should preserve the coldkey's unavailable amount. fn test_moving_unlocked_lock_preserves_unavailable_amount() { new_test_ext(1).execute_with(|| { @@ -2435,6 +2474,7 @@ fn test_moving_unlocked_lock_preserves_unavailable_amount() { // ========================================================================= #[test] +#[ignore] // Fully unlocked stake should still be unavailable on the very next block. fn test_unlocked_amount_cannot_be_unstaked_immediately() { new_test_ext(1).execute_with(|| { @@ -2471,6 +2511,7 @@ fn test_unlocked_amount_cannot_be_unstaked_immediately() { } #[test] +#[ignore] // Fully unlocked stake should also be unavailable for immediate re-locking. fn test_unlocked_amount_cannot_be_relocked_immediately() { new_test_ext(1).execute_with(|| { @@ -2504,6 +2545,7 @@ fn test_unlocked_amount_cannot_be_relocked_immediately() { } #[test] +#[ignore] // Unlocking more than the currently locked mass must be rejected and leave the lock untouched. fn test_unlock_stake_rejects_amount_above_locked_mass() { new_test_ext(1).execute_with(|| { @@ -2533,6 +2575,7 @@ fn test_unlock_stake_rejects_amount_above_locked_mass() { } #[test] +#[ignore] // After one full UnlockRate period, unlocked_mass should decay to about e^-1 of its original value. fn test_roll_forward_unlocked_mass_decays() { new_test_ext(1).execute_with(|| { @@ -2576,6 +2619,7 @@ fn test_roll_forward_unlocked_mass_decays() { } #[test] +#[ignore] // Even after one UnlockRate period, a large fraction of a fully unlocked position should remain unavailable. fn test_unlock_decay_blocks_eighty_percent() { new_test_ext(1).execute_with(|| { @@ -2627,6 +2671,7 @@ fn test_unlock_decay_blocks_eighty_percent() { } #[test] +#[ignore] // If only half the position is unlocked, even 40% of the original position should still be blocked after one UnlockRate. fn test_unlock_decay_blocks_forty_percent_after_half_unlock() { new_test_ext(1).execute_with(|| { @@ -2679,6 +2724,7 @@ fn test_unlock_decay_blocks_forty_percent_after_half_unlock() { } #[test] +#[ignore] // After one UnlockRate on a fully unlocked position, 60% of the original should be available to re-lock, // and once re-locked it should no longer be immediately available to unstake. fn test_unlock_decay_allows_relock_then_blocks_unstake() { diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 00d3839fa7..85a35d21c8 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -272,7 +272,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: 406, + spec_version: 407, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,