diff --git a/.github/workflows/benchmark-weights.yml b/.github/workflows/benchmark-weights.yml deleted file mode 100644 index e69de29bb..000000000 diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 90e0c1292..e8f37526e 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -1287,6 +1287,26 @@ pub mod pallet { ensure_root(origin)?; T::Grandpa::schedule_change(next_authorities, in_blocks, forced) } + + /// Enables or disables Liquid Alpha for a given subnet. + /// + /// # Parameters + /// - `origin`: The origin of the call, which must be the root account or subnet owner. + /// - `netuid`: The unique identifier for the subnet. + /// - `enabled`: A boolean flag to enable or disable Liquid Alpha. + /// + /// # Weight + /// This function has a fixed weight of 0 and is classified as an operational transaction that does not incur any fees. + #[pallet::call_index(61)] + #[pallet::weight((0, DispatchClass::Operational, Pays::No))] + pub fn sudo_set_toggle_transfer( + origin: OriginFor, + netuid: u16, + toggle: bool, + ) -> DispatchResult { + pallet_subtensor::Pallet::::ensure_subnet_owner_or_root(origin, netuid)?; + pallet_subtensor::Pallet::::toggle_transfer(netuid, toggle) + } } } diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index 5968a7376..c8d2a43a9 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -722,6 +722,14 @@ impl Pallet { Self::deposit_event(Event::NetworkLockCostReductionIntervalSet(interval)); } pub fn get_lock_reduction_interval() -> u64 { - NetworkLockReductionInterval::::get() + let interval: I64F64 = + I64F64::saturating_from_num(NetworkLockReductionInterval::::get()); + let block_emission: I64F64 = + I64F64::saturating_from_num(Self::get_block_emission().unwrap_or(1_000_000_000)); + let halving: I64F64 = block_emission + .checked_div(I64F64::saturating_from_num(1_000_000_000)) + .unwrap_or(I64F64::saturating_from_num(0.0)); + let halved_interval: I64F64 = interval.saturating_mul(halving); + halved_interval.saturating_to_num::() } } diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index bb463e556..90c7b99c6 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -138,8 +138,10 @@ impl Pallet { for netuid_i in subnets.iter() { // Get alpha out. let alpha_out_i: I96F32 = *alpha_out.get(netuid_i).unwrap_or(&asfloat!(0)); + log::debug!("alpha_out_i: {:?}", alpha_out_i); // Calculate the owner cut. let owner_cut_i: I96F32 = alpha_out_i.saturating_mul(cut_percent); + log::debug!("owner_cut_i: {:?}", owner_cut_i); // Save owner cut. *owner_cuts.entry(*netuid_i).or_insert(asfloat!(0)) = owner_cut_i; // Save new alpha_out. @@ -155,24 +157,33 @@ impl Pallet { for netuid_i in subnets.iter() { // Get remaining alpha out. let alpha_out_i: I96F32 = *alpha_out.get(netuid_i).unwrap_or(&asfloat!(0.0)); + log::debug!("alpha_out_i: {:?}", alpha_out_i); // Get total TAO on root. let root_tao: I96F32 = asfloat!(SubnetTAO::::get(0)); + log::debug!("root_tao: {:?}", root_tao); // Get total ALPHA on subnet. let alpha_issuance: I96F32 = asfloat!(Self::get_alpha_issuance(*netuid_i)); + log::debug!("alpha_issuance: {:?}", alpha_issuance); // Get tao_weight let tao_weight: I96F32 = root_tao.saturating_mul(Self::get_tao_weight()); + log::debug!("tao_weight: {:?}", tao_weight); // Get root proportional dividends. let root_proportion: I96F32 = tao_weight .checked_div(tao_weight.saturating_add(alpha_issuance)) .unwrap_or(asfloat!(0.0)); + log::debug!("root_proportion: {:?}", root_proportion); // Get root proportion of alpha_out dividends. let root_alpha: I96F32 = root_proportion .saturating_mul(alpha_out_i) // Total alpha emission per block remaining. .saturating_mul(asfloat!(0.5)); // 50% to validators. // Remove root alpha from alpha_out. + log::debug!("root_alpha: {:?}", root_alpha); + // Get pending alpha as original alpha_out - root_alpha. let pending_alpha: I96F32 = alpha_out_i.saturating_sub(root_alpha); + log::debug!("pending_alpha: {:?}", pending_alpha); // Sell root emission through the pool. let root_tao: u64 = Self::swap_alpha_for_tao(*netuid_i, tou64!(root_alpha)); + log::debug!("root_tao: {:?}", root_tao); // Accumulate alpha emission in pending. PendingAlphaSwapped::::mutate(*netuid_i, |total| { *total = total.saturating_add(tou64!(root_alpha)); @@ -238,6 +249,11 @@ impl Pallet { BlocksSinceLastStep::::mutate(netuid, |total| *total = total.saturating_add(1)); } } + + // --- 8. Apply pending childkeys of this subnet for the next epoch + for netuid in subnets.iter() { + Self::do_set_pending_children(*netuid); + } } pub fn drain_pending_emission( @@ -261,6 +277,7 @@ impl Pallet { // Run the epoch. let hotkey_emission: Vec<(T::AccountId, u64, u64)> = Self::epoch(netuid, pending_alpha.saturating_add(pending_swapped)); + log::debug!("hotkey_emission: {:?}", hotkey_emission); // Accumulate emission of dividends and incentive per hotkey. let mut incentives: BTreeMap = BTreeMap::new(); @@ -282,8 +299,10 @@ impl Pallet { .or_insert(asfloat!(parent_div)); } } + log::debug!("incentives: {:?}", incentives); + log::debug!("dividends: {:?}", dividends); - // Accumulate root divs and alpha_divs. For each hotkye we compute their + // Accumulate root divs and alpha_divs. For each hotkey we compute their // local and root dividend proportion based on their alpha_stake/root_stake let mut total_root_divs: I96F32 = asfloat!(0); let mut root_dividends: BTreeMap = BTreeMap::new(); @@ -300,19 +319,15 @@ impl Pallet { let root_alpha: I96F32 = root_stake.saturating_mul(Self::get_tao_weight()); // Get total from root and local let total_alpha: I96F32 = alpha_stake.saturating_add(root_alpha); - // Compute alpha prop. - let alpha_prop: I96F32 = alpha_stake.checked_div(total_alpha).unwrap_or(zero); // Copmute root prop. let root_prop: I96F32 = root_alpha.checked_div(total_alpha).unwrap_or(zero); - // Compute alpha dividends - let alpha_divs: I96F32 = dividend.saturating_mul(alpha_prop); // Compute root dividends let root_divs: I96F32 = dividend.saturating_mul(root_prop); // Record the root dividends. alpha_dividends .entry(hotkey.clone()) - .and_modify(|e| *e = e.saturating_add(alpha_divs)) - .or_insert(alpha_divs); + .and_modify(|e| *e = e.saturating_add(dividend)) + .or_insert(dividend); // Record the alpha_dividends. root_dividends .entry(hotkey.clone()) @@ -321,6 +336,8 @@ impl Pallet { // Accumulate total root divs. total_root_divs = total_root_divs.saturating_add(root_divs); } + log::debug!("alpha_dividends: {:?}", alpha_dividends); + log::debug!("root_dividends: {:?}", root_dividends); // Compute root divs as TAO. Here we take let mut tao_dividends: BTreeMap = BTreeMap::new(); @@ -335,6 +352,7 @@ impl Pallet { .and_modify(|e| *e = root_tao) .or_insert(root_tao); } + log::debug!("tao_dividends: {:?}", tao_dividends); // Distribute the owner cut. if let Ok(owner_coldkey) = SubnetOwner::::try_get(netuid) { @@ -363,6 +381,8 @@ impl Pallet { // Distribute alpha divs. let _ = AlphaDividendsPerSubnet::::clear_prefix(netuid, u32::MAX, None); for (hotkey, mut alpha_divs) in alpha_dividends { + log::debug!("hotkey: {:?} alpha_divs: {:?}", hotkey, alpha_divs); + // Get take prop let alpha_take: I96F32 = Self::get_hotkey_take_float(&hotkey).saturating_mul(alpha_divs); @@ -386,6 +406,7 @@ impl Pallet { // Distribute root tao divs. let _ = TaoDividendsPerSubnet::::clear_prefix(netuid, u32::MAX, None); for (hotkey, mut root_tao) in tao_dividends { + log::debug!("hotkey: {:?} root_tao: {:?}", hotkey, root_tao); // Get take prop let tao_take: I96F32 = Self::get_hotkey_take_float(&hotkey).saturating_mul(root_tao); // Remove take prop from root_tao diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index d76caf894..f9c1364a9 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1114,6 +1114,9 @@ pub mod pallet { /// ============================ /// ==== Subnet Locks ===== /// ============================ + #[pallet::storage] // --- MAP ( netuid ) --> transfer_toggle + pub type TransferToggle = + StorageMap<_, Identity, u16, bool, ValueQuery, DefaultTrue>; #[pallet::storage] // --- MAP ( netuid ) --> total_subnet_locked pub type SubnetLocked = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64>; @@ -1645,6 +1648,7 @@ pub enum CustomTransactionError { RateLimitExceeded, InsufficientLiquidity, SlippageTooHigh, + TransferDisallowed, BadRequest, } @@ -1660,6 +1664,7 @@ impl From for u8 { CustomTransactionError::RateLimitExceeded => 6, CustomTransactionError::InsufficientLiquidity => 7, CustomTransactionError::SlippageTooHigh => 8, + CustomTransactionError::TransferDisallowed => 9, CustomTransactionError::BadRequest => 255, } } @@ -1735,6 +1740,10 @@ where CustomTransactionError::SlippageTooHigh.into(), ) .into()), + Error::::TransferDisallowed => Err(InvalidTransaction::Custom( + CustomTransactionError::TransferDisallowed.into(), + ) + .into()), _ => Err( InvalidTransaction::Custom(CustomTransactionError::BadRequest.into()).into(), ), @@ -1959,6 +1968,7 @@ where *alpha_amount, *alpha_amount, None, + false, )) } Some(Call::transfer_stake { @@ -1979,6 +1989,7 @@ where *alpha_amount, *alpha_amount, None, + true, )) } Some(Call::swap_stake { @@ -1998,6 +2009,7 @@ where *alpha_amount, *alpha_amount, None, + false, )) } Some(Call::swap_stake_limit { @@ -2026,6 +2038,7 @@ where *alpha_amount, max_amount, Some(*allow_partial), + false, )) } Some(Call::register { netuid, .. } | Call::burned_register { netuid, .. }) => { diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index 926aead58..8515b5fe7 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -189,5 +189,7 @@ mod errors { InsufficientLiquidity, /// Slippage is too high for the transaction. SlippageTooHigh, + /// Subnet disallows transfer. + TransferDisallowed, } } diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index 6dd6ddad2..40890b018 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -265,5 +265,11 @@ mod events { /// Parameters: /// (coldkey, hotkey, origin_netuid, destination_netuid, amount) StakeSwapped(T::AccountId, T::AccountId, u16, u16, u64), + + /// Event called when transfer is toggled on a subnet. + /// + /// Parameters: + /// (netuid, bool) + TransferToggle(u16, bool), } } diff --git a/pallets/subtensor/src/migrations/migrate_rao.rs b/pallets/subtensor/src/migrations/migrate_rao.rs index d33414580..6baa9d039 100644 --- a/pallets/subtensor/src/migrations/migrate_rao.rs +++ b/pallets/subtensor/src/migrations/migrate_rao.rs @@ -6,7 +6,6 @@ use sp_runtime::format; use substrate_fixed::types::U64F64; use super::*; -use crate::subnets::subnet::POOL_INITIAL_TAO; pub fn migrate_rao() -> Weight { let migration_name = b"migrate_rao".to_vec(); @@ -76,18 +75,23 @@ pub fn migrate_rao() -> Weight { // Put initial TAO from lock into subnet TAO and produce numerically equal amount of Alpha // The initial TAO is the locked amount, with a minimum of 1 RAO and a cap of 100 TAO. - let pool_initial_tao = POOL_INITIAL_TAO.min(lock.max(1)); + let pool_initial_tao = Pallet::::get_network_min_lock(); + if lock < pool_initial_tao { + let difference: u64 = pool_initial_tao.saturating_sub(lock); + TotalIssuance::::mutate(|total| { + *total = total.saturating_add(difference); + }); + } let remaining_lock = lock.saturating_sub(pool_initial_tao); // Refund the owner for the remaining lock. Pallet::::add_balance_to_coldkey_account(&owner, remaining_lock); - SubnetTAO::::insert(netuid, pool_initial_tao); // Set TAO to the lock. - - SubnetAlphaIn::::insert( - netuid, - pool_initial_tao.saturating_mul(netuids.len() as u64), - ); // Set AlphaIn to the initial alpha distribution. - + SubnetLocked::::insert(netuid, 0); // Clear lock amount. + SubnetTAO::::insert(netuid, pool_initial_tao); + TotalStake::::mutate(|total| { + *total = total.saturating_add(pool_initial_tao); + }); // Increase total stake. + SubnetAlphaIn::::insert(netuid, pool_initial_tao); // Set initial alpha to pool initial tao. SubnetAlphaOut::::insert(netuid, 0); // Set zero subnet alpha out. SubnetMechanism::::insert(netuid, 1); // Convert to dynamic immediately with initialization. Tempo::::insert(netuid, DefaultTempo::::get()); diff --git a/pallets/subtensor/src/staking/move_stake.rs b/pallets/subtensor/src/staking/move_stake.rs index a60191de8..fe5fbd45c 100644 --- a/pallets/subtensor/src/staking/move_stake.rs +++ b/pallets/subtensor/src/staking/move_stake.rs @@ -47,6 +47,7 @@ impl Pallet { alpha_amount, None, None, + false, )?; // Log the event. @@ -96,6 +97,16 @@ impl Pallet { /// /// # Events /// Emits a `StakeTransferred` event upon successful completion of the transfer. + pub fn toggle_transfer(netuid: u16, toggle: bool) -> dispatch::DispatchResult { + TransferToggle::::insert(netuid, toggle); + log::debug!( + "TransferToggle( netuid: {:?}, toggle: {:?} ) ", + netuid, + toggle + ); + Self::deposit_event(Event::TransferToggle(netuid, toggle)); + Ok(()) + } pub fn do_transfer_stake( origin: T::RuntimeOrigin, destination_coldkey: T::AccountId, @@ -118,6 +129,7 @@ impl Pallet { alpha_amount, None, None, + true, )?; // 9. Emit an event for logging/monitoring. @@ -187,6 +199,7 @@ impl Pallet { alpha_amount, None, None, + false, )?; // Emit an event for logging. @@ -258,6 +271,7 @@ impl Pallet { alpha_amount, Some(limit_price), Some(allow_partial), + false, )?; // Emit an event for logging. @@ -293,6 +307,7 @@ impl Pallet { alpha_amount: u64, maybe_limit_price: Option, maybe_allow_partial: Option, + check_transfer_toggle: bool, ) -> Result> { // Calculate the maximum amount that can be executed let max_amount = if let Some(limit_price) = maybe_limit_price { @@ -312,6 +327,7 @@ impl Pallet { alpha_amount, max_amount, maybe_allow_partial, + check_transfer_toggle, )?; // Unstake from the origin subnet, returning TAO (or a 1:1 equivalent). diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs index 4db9bebeb..e32509971 100644 --- a/pallets/subtensor/src/staking/stake_utils.rs +++ b/pallets/subtensor/src/staking/stake_utils.rs @@ -845,6 +845,7 @@ impl Pallet { alpha_amount: u64, max_amount: u64, maybe_allow_partial: Option, + check_transfer_toggle: bool, ) -> Result<(), Error> { // Ensure that both subnets exist. ensure!( @@ -899,6 +900,18 @@ impl Pallet { } } + if check_transfer_toggle { + // Ensure transfer is toggled. + ensure!( + TransferToggle::::get(origin_netuid), + Error::::TransferDisallowed + ); + ensure!( + TransferToggle::::get(destination_netuid), + Error::::TransferDisallowed + ); + } + Ok(()) } } diff --git a/pallets/subtensor/src/subnets/registration.rs b/pallets/subtensor/src/subnets/registration.rs index bce9ea25c..009ec6841 100644 --- a/pallets/subtensor/src/subnets/registration.rs +++ b/pallets/subtensor/src/subnets/registration.rs @@ -425,6 +425,14 @@ impl Pallet { } for neuron_uid in 0..neurons_n { + // Do not deregister the owner + if let Ok(hotkey) = Self::get_hotkey_for_net_and_uid(netuid, neuron_uid) { + let coldkey = Self::get_owning_coldkey_for_hotkey(&hotkey); + if Self::get_subnet_owner(netuid) == coldkey { + continue; + } + } + let pruning_score: u16 = Self::get_pruning_score_for_uid(netuid, neuron_uid); let block_at_registration: u64 = Self::get_neuron_block_at_registration(netuid, neuron_uid); diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index 58df2e4ad..505905af9 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -2,8 +2,6 @@ use super::*; use frame_support::IterableStorageMap; use sp_core::Get; -pub(crate) const POOL_INITIAL_TAO: u64 = 100_000_000_000; - impl Pallet { /// Retrieves the unique identifier (UID) for the root network. /// @@ -237,16 +235,11 @@ impl Pallet { // Put initial TAO from lock into subnet TAO and produce numerically equal amount of Alpha // The initial TAO is the locked amount, with a minimum of 1 RAO and a cap of 100 TAO. - let pool_initial_tao = POOL_INITIAL_TAO.min(actual_tao_lock_amount.max(1)); - + let pool_initial_tao = Self::get_network_min_lock(); let actual_tao_lock_amount_less_pool_tao = actual_tao_lock_amount.saturating_sub(pool_initial_tao); SubnetTAO::::insert(netuid_to_register, pool_initial_tao); - SubnetAlphaIn::::insert( - netuid_to_register, - pool_initial_tao.saturating_mul(Self::get_all_subnet_netuids().len() as u64), - ); // Set AlphaIn to the initial alpha distribution. - + SubnetAlphaIn::::insert(netuid_to_register, pool_initial_tao); SubnetOwner::::insert(netuid_to_register, coldkey.clone()); SubnetOwnerHotkey::::insert(netuid_to_register, hotkey.clone()); TotalStakeAtDynamic::::insert(netuid_to_register, TotalStake::::get()); diff --git a/pallets/subtensor/src/subnets/uids.rs b/pallets/subtensor/src/subnets/uids.rs index 6b1fa5c6b..8eec0fdab 100644 --- a/pallets/subtensor/src/subnets/uids.rs +++ b/pallets/subtensor/src/subnets/uids.rs @@ -42,6 +42,20 @@ impl Pallet { // 1. Get the old hotkey under this position. let old_hotkey: T::AccountId = Keys::::get(netuid, uid_to_replace); + // Do not deregister the owner + let coldkey = Self::get_owning_coldkey_for_hotkey(&old_hotkey); + if Self::get_subnet_owner(netuid) == coldkey { + log::warn!( + "replace_neuron: Skipped replacement because neuron belongs to the subnet owner. \ + netuid: {:?}, uid_to_replace: {:?}, new_hotkey: {:?}, owner_coldkey: {:?}", + netuid, + uid_to_replace, + new_hotkey, + coldkey + ); + return; + } + // 2. Remove previous set memberships. Uids::::remove(netuid, old_hotkey.clone()); IsNetworkMember::::remove(old_hotkey.clone(), netuid); diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 2ddb73bb8..1fa0298ce 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -360,3 +360,408 @@ fn test_coinbase_alpha_issuance_with_cap_trigger_and_block_emission() { // No emission. }); } + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_owner_cut_base --exact --show-output --nocapture +#[test] +fn test_owner_cut_base() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + add_network(netuid, 1, 0); + SubtensorModule::set_tempo(netuid, 10000); // Large number (dont drain) + SubtensorModule::set_subnet_owner_cut(0); + SubtensorModule::run_coinbase(I96F32::from_num(0)); + assert_eq!(PendingOwnerCut::::get(netuid), 0); // No cut + SubtensorModule::set_subnet_owner_cut(u16::MAX); + SubtensorModule::run_coinbase(I96F32::from_num(0)); + assert_eq!(PendingOwnerCut::::get(netuid), 1_000_000_000); // Full cut. + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_pending_swapped --exact --show-output --nocapture +#[test] +fn test_pending_swapped() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let emission: u64 = 1_000_000; + add_network(netuid, 1, 0); + SubtensorModule::run_coinbase(I96F32::from_num(0)); + assert_eq!(PendingAlphaSwapped::::get(netuid), 0); // Zero tao weight and no root. + SubnetTAO::::insert(0, 1_000_000_000); // Add root weight. + SubtensorModule::run_coinbase(I96F32::from_num(0)); + assert_eq!(PendingAlphaSwapped::::get(netuid), 0); // Zero tao weight with 1 root. + SubtensorModule::set_tempo(netuid, 10000); // Large number (dont drain) + SubtensorModule::set_tao_weight(u64::MAX); // Set TAO weight to 1.0 + SubtensorModule::run_coinbase(I96F32::from_num(0)); + assert_eq!(PendingAlphaSwapped::::get(netuid), 125000000); // 1 TAO / ( 1 + 3 ) = 0.25 * 1 / 2 = 125000000 + assert_eq!( + PendingEmission::::get(netuid), + 1_000_000_000 - 125000000 + ); // 1 - swapped. + assert_eq!(PendingRootDivs::::get(netuid), 125000000); // swapped * (price = 1) + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_drain_base --exact --show-output --nocapture +#[test] +fn test_drain_base() { + new_test_ext(1).execute_with(|| SubtensorModule::drain_pending_emission(0, 0, 0, 0, 0)); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_drain_base_with_subnet --exact --show-output --nocapture +#[test] +fn test_drain_base_with_subnet() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + add_network(netuid, 1, 0); + SubtensorModule::drain_pending_emission(netuid, 0, 0, 0, 0) + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_drain_base_with_subnet_with_single_staker_not_registered --exact --show-output --nocapture +#[test] +fn test_drain_base_with_subnet_with_single_staker_not_registered() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + add_network(netuid, 1, 0); + let hotkey = U256::from(1); + let coldkey = U256::from(2); + let stake_before: u64 = 1_000_000_000; + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey, + &coldkey, + netuid, + stake_before, + ); + let pending_alpha: u64 = 1_000_000_000; + SubtensorModule::drain_pending_emission(netuid, pending_alpha, 0, 0, 0); + let stake_after = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid); + assert_eq!(stake_before, stake_after); // Not registered. + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_drain_base_with_subnet_with_single_staker_registered --exact --show-output --nocapture +#[test] +fn test_drain_base_with_subnet_with_single_staker_registered() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + add_network(netuid, 1, 0); + let hotkey = U256::from(1); + let coldkey = U256::from(2); + let stake_before: u64 = 1_000_000_000; + register_ok_neuron(netuid, hotkey, coldkey, 0); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey, + &coldkey, + netuid, + stake_before, + ); + let pending_alpha: u64 = 1_000_000_000; + SubtensorModule::drain_pending_emission(netuid, pending_alpha, 0, 0, 0); + let stake_after = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid); + close(stake_before + pending_alpha, stake_after, 10); // Registered gets all emission. + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_drain_base_with_subnet_with_single_staker_registered_root_weight --exact --show-output --nocapture +#[test] +fn test_drain_base_with_subnet_with_single_staker_registered_root_weight() { + new_test_ext(1).execute_with(|| { + let root: u16 = 0; + let netuid: u16 = 1; + add_network(netuid, 1, 0); + let hotkey = U256::from(1); + let coldkey = U256::from(2); + let stake_before: u64 = 1_000_000_000; + // register_ok_neuron(root, hotkey, coldkey, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + SubtensorModule::set_tao_weight(u64::MAX); // Set TAO weight to 1.0 + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey, + &coldkey, + root, + stake_before, + ); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey, + &coldkey, + netuid, + stake_before, + ); + let pending_tao: u64 = 1_000_000_000; + let pending_alpha: u64 = 1_000_000_000; + SubtensorModule::drain_pending_emission(netuid, pending_alpha, pending_tao, 0, 0); + let stake_after = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid); + let root_after = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, root); + close(stake_before + pending_alpha, stake_after, 10); // Registered gets all alpha emission. + close(stake_before + pending_tao, root_after, 10); // Registered gets all tao emission + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_drain_base_with_subnet_with_two_stakers_registered --exact --show-output --nocapture +#[test] +fn test_drain_base_with_subnet_with_two_stakers_registered() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + add_network(netuid, 1, 0); + let hotkey1 = U256::from(1); + let hotkey2 = U256::from(2); + let coldkey = U256::from(3); + let stake_before: u64 = 1_000_000_000; + register_ok_neuron(netuid, hotkey1, coldkey, 0); + register_ok_neuron(netuid, hotkey2, coldkey, 0); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey1, + &coldkey, + netuid, + stake_before, + ); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey2, + &coldkey, + netuid, + stake_before, + ); + let pending_alpha: u64 = 1_000_000_000; + SubtensorModule::drain_pending_emission(netuid, pending_alpha, 0, 0, 0); + let stake_after1 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey1, &coldkey, netuid); + let stake_after2 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey2, &coldkey, netuid); + close(stake_before + pending_alpha / 2, stake_after1, 10); // Registered gets 1/2 emission + close(stake_before + pending_alpha / 2, stake_after2, 10); // Registered gets 1/2 emission. + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_drain_base_with_subnet_with_two_stakers_registered_and_root --exact --show-output --nocapture +#[test] +fn test_drain_base_with_subnet_with_two_stakers_registered_and_root() { + new_test_ext(1).execute_with(|| { + let root: u16 = 0; + let netuid: u16 = 1; + add_network(netuid, 1, 0); + let hotkey1 = U256::from(1); + let hotkey2 = U256::from(2); + let coldkey = U256::from(3); + let stake_before: u64 = 1_000_000_000; + register_ok_neuron(netuid, hotkey1, coldkey, 0); + register_ok_neuron(netuid, hotkey2, coldkey, 0); + SubtensorModule::set_tao_weight(u64::MAX); // Set TAO weight to 1.0 + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey1, + &coldkey, + netuid, + stake_before, + ); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey1, + &coldkey, + root, + stake_before, + ); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey2, + &coldkey, + netuid, + stake_before, + ); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey2, + &coldkey, + root, + stake_before, + ); + let pending_tao: u64 = 1_000_000_000; + let pending_alpha: u64 = 1_000_000_000; + SubtensorModule::drain_pending_emission(netuid, pending_alpha, pending_tao, 0, 0); + let stake_after1 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey1, &coldkey, netuid); + let root_after1 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey1, &coldkey, root); + let stake_after2 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey2, &coldkey, netuid); + let root_after2 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey2, &coldkey, root); + close(stake_before + pending_alpha / 2, stake_after1, 10); // Registered gets 1/2 emission + close(stake_before + pending_alpha / 2, stake_after2, 10); // Registered gets 1/2 emission. + close(stake_before + pending_tao / 2, root_after1, 10); // Registered gets 1/2 tao emission + close(stake_before + pending_tao / 2, root_after2, 10); // Registered gets 1/2 tao emission + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_amounts --exact --show-output --nocapture +#[test] +fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_amounts() { + new_test_ext(1).execute_with(|| { + let root: u16 = 0; + let netuid: u16 = 1; + add_network(netuid, 1, 0); + let hotkey1 = U256::from(1); + let hotkey2 = U256::from(2); + let coldkey = U256::from(3); + let stake_before: u64 = 1_000_000_000; + register_ok_neuron(netuid, hotkey1, coldkey, 0); + register_ok_neuron(netuid, hotkey2, coldkey, 0); + SubtensorModule::set_tao_weight(u64::MAX); // Set TAO weight to 1.0 + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey1, + &coldkey, + netuid, + stake_before, + ); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey1, + &coldkey, + root, + 2 * stake_before, // Hotkey 1 has twice as much root weight. + ); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey2, + &coldkey, + netuid, + stake_before, + ); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey2, + &coldkey, + root, + stake_before, + ); + let pending_tao: u64 = 1_000_000_000; + let pending_alpha: u64 = 1_000_000_000; + SubtensorModule::drain_pending_emission(netuid, pending_alpha, pending_tao, 0, 0); + let stake_after1 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey1, &coldkey, netuid); + let root_after1 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey1, &coldkey, root); + let stake_after2 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey2, &coldkey, netuid); + let root_after2 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey2, &coldkey, root); + let expected_stake = I96F32::from_num(stake_before) + + I96F32::from_num(pending_alpha) * I96F32::from_num(3.0 / 5.0); + close(expected_stake.to_num::(), stake_after1, 10); // Registered gets 60% of emission + let expected_stake2 = I96F32::from_num(stake_before) + + I96F32::from_num(pending_alpha) * I96F32::from_num(2.0 / 5.0); + close(expected_stake2.to_num::(), stake_after2, 10); // Registered gets 40% emission + let expected_root1 = I96F32::from_num(2 * stake_before) + + I96F32::from_num(pending_tao) * I96F32::from_num(2.0 / 3.0); + close(expected_root1.to_num::(), root_after1, 10); // Registered gets 2/3 tao emission + let expected_root2 = I96F32::from_num(stake_before) + + I96F32::from_num(pending_tao) * I96F32::from_num(1.0 / 3.0); + close(expected_root2.to_num::(), root_after2, 10); // Registered gets 1/3 tao emission + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_amounts_half_tao_weight --exact --show-output --nocapture +#[test] +fn test_drain_base_with_subnet_with_two_stakers_registered_and_root_different_amounts_half_tao_weight( +) { + new_test_ext(1).execute_with(|| { + let root: u16 = 0; + let netuid: u16 = 1; + add_network(netuid, 1, 0); + let hotkey1 = U256::from(1); + let hotkey2 = U256::from(2); + let coldkey = U256::from(3); + let stake_before: u64 = 1_000_000_000; + register_ok_neuron(netuid, hotkey1, coldkey, 0); + register_ok_neuron(netuid, hotkey2, coldkey, 0); + SubtensorModule::set_tao_weight(u64::MAX / 2); // Set TAO weight to 0.5 + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey1, + &coldkey, + netuid, + stake_before, + ); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey1, + &coldkey, + root, + 2 * stake_before, // Hotkey 1 has twice as much root weight. + ); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey2, + &coldkey, + netuid, + stake_before, + ); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &hotkey2, + &coldkey, + root, + stake_before, + ); + let pending_tao: u64 = 1_000_000_000; + let pending_alpha: u64 = 1_000_000_000; + SubtensorModule::drain_pending_emission(netuid, pending_alpha, pending_tao, 0, 0); + let stake_after1 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey1, &coldkey, netuid); + let root_after1 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey1, &coldkey, root); + let stake_after2 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey2, &coldkey, netuid); + let root_after2 = + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey2, &coldkey, root); + // hotkey 1 has (1 + (2 * 0.5))/( 1 + 1*0.5 + 1 + (2 * 0.5)) = 0.5714285714 of the hotkey emission. + let expected_stake = I96F32::from_num(stake_before) + + I96F32::from_num(pending_alpha) * I96F32::from_num(0.5714285714); + close(expected_stake.to_num::(), stake_after1, 10); + // hotkey 2 has (1 + 1*0.5)/( 1 + 1*0.5 + 1 + (2 * 0.5)) = 0.4285714286 of the hotkey emission. + let expected_stake2 = I96F32::from_num(stake_before) + + I96F32::from_num(pending_alpha) * I96F32::from_num(0.4285714286); + close(expected_stake2.to_num::(), stake_after2, 10); + // hotkey 1 has 2 / 3 root tao + let expected_root1 = I96F32::from_num(2 * stake_before) + + I96F32::from_num(pending_tao) * I96F32::from_num(2.0 / 3.0); + close(expected_root1.to_num::(), root_after1, 10); + // hotkey 1 has 1 / 3 root tao + let expected_root2 = I96F32::from_num(stake_before) + + I96F32::from_num(pending_tao) * I96F32::from_num(1.0 / 3.0); + close(expected_root2.to_num::(), root_after2, 10); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_drain_alpha_childkey_parentkey --exact --show-output --nocapture +#[test] +fn test_drain_alpha_childkey_parentkey() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + add_network(netuid, 1, 0); + let parent = U256::from(1); + let child = U256::from(2); + let coldkey = U256::from(3); + let stake_before: u64 = 1_000_000_000; + register_ok_neuron(netuid, child, coldkey, 0); + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( + &parent, + &coldkey, + netuid, + stake_before, + ); + mock_set_children_no_epochs(netuid, &parent, &[(u64::MAX, child)]); + + // Childkey take is 10% + ChildkeyTake::::insert(child, netuid, u16::MAX / 10); + + let pending_alpha: u64 = 1_000_000_000; + SubtensorModule::drain_pending_emission(netuid, pending_alpha, 0, 0, 0); + let parent_stake_after = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); + let child_stake_after = SubtensorModule::get_stake_for_hotkey_on_subnet(&child, netuid); + + // Child gets 10%, parent gets 90% + let expected = I96F32::from_num(stake_before) + + I96F32::from_num(pending_alpha) * I96F32::from_num(9.0 / 10.0); + log::info!( + "expected: {:?}, parent_stake_after: {:?}", + expected.to_num::(), + parent_stake_after + ); + close(expected.to_num::(), parent_stake_after, 10_000); + let expected = I96F32::from_num(pending_alpha) / I96F32::from_num(10); + close(expected.to_num::(), child_stake_after, 10_000); + }); +} diff --git a/pallets/subtensor/src/tests/difficulty.rs b/pallets/subtensor/src/tests/difficulty.rs index 1cd1ecc7e..d6c151b64 100644 --- a/pallets/subtensor/src/tests/difficulty.rs +++ b/pallets/subtensor/src/tests/difficulty.rs @@ -13,6 +13,10 @@ fn test_registration_difficulty_adjustment() { let tempo: u16 = 1; let modality: u16 = 1; add_network(netuid, tempo, modality); + + // owners are not deregistered + crate::SubnetOwner::::insert(netuid, U256::from(99999)); + SubtensorModule::set_min_difficulty(netuid, 10000); assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 10000); // Check initial difficulty. assert_eq!(SubtensorModule::get_last_adjustment_block(netuid), 0); // Last adjustment block starts at 0. diff --git a/pallets/subtensor/src/tests/migration.rs b/pallets/subtensor/src/tests/migration.rs index f321267fb..be30b2266 100644 --- a/pallets/subtensor/src/tests/migration.rs +++ b/pallets/subtensor/src/tests/migration.rs @@ -551,7 +551,7 @@ fn test_migrate_commit_reveal_2() { }); } -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --workspace --test migration -- test_migrate_rao --exact --nocapture +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::migration::test_migrate_rao --exact --show-output --nocapture #[test] fn test_migrate_rao() { new_test_ext(1).execute_with(|| { @@ -565,6 +565,7 @@ fn test_migrate_rao() { let coldkey3 = U256::from(5); let stake_amount: u64 = 1_000_000_000; let lock_amount: u64 = 500; + NetworkMinLockCost::::set(500); // Add networks root and alpha add_network(netuid_0, 1, 0); @@ -600,7 +601,7 @@ fn test_migrate_rao() { assert_eq!(SubnetTAO::::get(netuid_0), 4 * stake_amount); // Root has everything assert_eq!(SubnetTAO::::get(netuid_1), lock_amount); // Initial Rao amount. assert_eq!(SubnetAlphaIn::::get(netuid_0), 1); // No Alpha in pool on root. - assert_eq!(SubnetAlphaIn::::get(netuid_1), 2 * lock_amount); // Initial Rao amount == num_subnets * lock_amount + assert_eq!(SubnetAlphaIn::::get(netuid_1), lock_amount); // Initial Rao amount == num_subnets * lock_amount assert_eq!(SubnetAlphaOut::::get(netuid_0), 4 * stake_amount); // All stake is outstanding. assert_eq!(SubnetAlphaOut::::get(netuid_1), 0); // No stake outstanding. diff --git a/pallets/subtensor/src/tests/move_stake.rs b/pallets/subtensor/src/tests/move_stake.rs index f0a35f91a..ce0ce37fc 100644 --- a/pallets/subtensor/src/tests/move_stake.rs +++ b/pallets/subtensor/src/tests/move_stake.rs @@ -1539,3 +1539,73 @@ fn test_swap_stake_limit_validate() { ); }); } + +#[test] +fn test_stake_transfers_disabled_validate() { + // Testing the signed extension validate function + // correctly filters the `transfer_stake` transaction. + + new_test_ext(0).execute_with(|| { + let subnet_owner_coldkey = U256::from(1001); + let subnet_owner_hotkey = U256::from(1002); + let origin_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); + let destination_netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); + + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let destination_coldkey = U256::from(3); + let stake_amount = 100_000_000_000; + + SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey); + let unstake_amount = + SubtensorModule::stake_into_subnet(&hotkey, &coldkey, origin_netuid, stake_amount, 0); + + // Swap stake limit call + let call = RuntimeCall::SubtensorModule(SubtensorCall::transfer_stake { + destination_coldkey, + hotkey, + origin_netuid, + destination_netuid, + alpha_amount: unstake_amount, + }); + + let info: crate::DispatchInfo = + crate::DispatchInfoOf::<::RuntimeCall>::default(); + + let extension = crate::SubtensorSignedExtension::::new(); + + // Disable transfers in origin subnet + TransferToggle::::insert(origin_netuid, false); + TransferToggle::::insert(destination_netuid, true); + + // Submit to the signed extension validate function + let result1 = extension.validate(&coldkey, &call.clone(), &info, 10); + assert_err!( + result1, + crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom( + CustomTransactionError::TransferDisallowed.into() + )) + ); + + // Disable transfers in destination subnet + TransferToggle::::insert(origin_netuid, true); + TransferToggle::::insert(destination_netuid, false); + + // Submit to the signed extension validate function + let result2 = extension.validate(&coldkey, &call.clone(), &info, 10); + assert_err!( + result2, + crate::TransactionValidityError::Invalid(crate::InvalidTransaction::Custom( + CustomTransactionError::TransferDisallowed.into() + )) + ); + + // Enable transfers + TransferToggle::::insert(origin_netuid, true); + TransferToggle::::insert(destination_netuid, true); + + // Submit to the signed extension validate function + let result3 = extension.validate(&coldkey, &call.clone(), &info, 10); + assert_ok!(result3); + }); +} diff --git a/pallets/subtensor/src/tests/networks.rs b/pallets/subtensor/src/tests/networks.rs index 61fed23bf..ad50c69e8 100644 --- a/pallets/subtensor/src/tests/networks.rs +++ b/pallets/subtensor/src/tests/networks.rs @@ -282,6 +282,7 @@ fn test_schedule_dissolve_network_execution_with_coldkey_swap() { }) } +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::networks::test_register_subnet_low_lock_cost --exact --show-output --nocapture #[test] fn test_register_subnet_low_lock_cost() { new_test_ext(1).execute_with(|| { @@ -298,26 +299,22 @@ fn test_register_subnet_low_lock_cost() { assert!(SubtensorModule::if_subnet_exist(netuid)); // Ensure that both Subnet TAO and Subnet Alpha In equal to (actual) lock_cost - assert_eq!( - SubnetTAO::::get(netuid), - lock_cost - ExistentialDeposit::get(), - ); - assert_eq!( - SubnetAlphaIn::::get(netuid), - lock_cost - ExistentialDeposit::get(), - ); + assert_eq!(SubnetTAO::::get(netuid), lock_cost,); + assert_eq!(SubnetAlphaIn::::get(netuid), lock_cost,); }) } +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::networks::test_register_subnet_high_lock_cost --exact --show-output --nocapture #[test] fn test_register_subnet_high_lock_cost() { new_test_ext(1).execute_with(|| { - NetworkMinLockCost::::set(1_000_000_000_000); - NetworkLastLockCost::::set(1_000_000_000_000); + let lock_cost: u64 = 1_000_000_000_000; + NetworkMinLockCost::::set(lock_cost); + NetworkLastLockCost::::set(lock_cost); // Make sure lock cost is higher than 100 TAO let lock_cost = SubtensorModule::get_network_lock_cost(); - assert!(lock_cost > 100_000_000_000); + assert!(lock_cost >= 1_000_000_000_000); let subnet_owner_coldkey = U256::from(1); let subnet_owner_hotkey = U256::from(2); @@ -325,7 +322,7 @@ fn test_register_subnet_high_lock_cost() { assert!(SubtensorModule::if_subnet_exist(netuid)); // Ensure that both Subnet TAO and Subnet Alpha In equal to 100 TAO - assert_eq!(SubnetTAO::::get(netuid), 100_000_000_000,); - assert_eq!(SubnetAlphaIn::::get(netuid), 100_000_000_000,); + assert_eq!(SubnetTAO::::get(netuid), lock_cost); + assert_eq!(SubnetAlphaIn::::get(netuid), lock_cost); }) } diff --git a/pallets/subtensor/src/tests/registration.rs b/pallets/subtensor/src/tests/registration.rs index 768d923d0..d3bf61494 100644 --- a/pallets/subtensor/src/tests/registration.rs +++ b/pallets/subtensor/src/tests/registration.rs @@ -1560,6 +1560,12 @@ fn test_full_pass_through() { add_network(netuid1, tempo1, 0); add_network(netuid2, tempo2, 0); + // owners are not deregisterd + let dummy_owner = U256::from(99999); + crate::SubnetOwner::::insert(netuid0, dummy_owner); + crate::SubnetOwner::::insert(netuid1, dummy_owner); + crate::SubnetOwner::::insert(netuid2, dummy_owner); + // Check their tempo. assert_eq!(SubtensorModule::get_tempo(netuid0), tempo0); assert_eq!(SubtensorModule::get_tempo(netuid1), tempo1); diff --git a/pallets/subtensor/src/tests/uids.rs b/pallets/subtensor/src/tests/uids.rs index b45a156a9..acf405726 100644 --- a/pallets/subtensor/src/tests/uids.rs +++ b/pallets/subtensor/src/tests/uids.rs @@ -250,3 +250,88 @@ fn test_neuron_certificate() { assert_err!(NeuronCertificate::try_from(data), ()); }); } + +#[test] +fn test_replace_neuron_subnet_owner_not_replaced() { + new_test_ext(1).execute_with(|| { + let owner_hotkey = U256::from(100); + let owner_coldkey = U256::from(999); + let new_hotkey_account_id = U256::from(2); + + let netuid = add_dynamic_network(&owner_hotkey, &owner_coldkey); + let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &owner_hotkey) + .expect("Owner neuron should be registered by add_dynamic_network"); + + let current_block = SubtensorModule::get_current_block_as_u64(); + SubtensorModule::replace_neuron(netuid, neuron_uid, &new_hotkey_account_id, current_block); + + let still_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &owner_hotkey); + assert_ok!(still_uid); + assert_eq!( + still_uid.unwrap(), + neuron_uid, + "UID should remain unchanged for subnet owner" + ); + + let new_key_uid = + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &new_hotkey_account_id); + assert_err!(new_key_uid, Error::::HotKeyNotRegisteredInSubNet,); + }); +} + +#[test] +fn test_get_neuron_to_prune_owner_not_pruned() { + new_test_ext(1).execute_with(|| { + let owner_hotkey = U256::from(123); + let owner_coldkey = U256::from(999); + + let netuid = add_dynamic_network(&owner_hotkey, &owner_coldkey); + + SubtensorModule::set_max_registrations_per_block(netuid, 100); + SubtensorModule::set_target_registrations_per_interval(netuid, 100); + SubnetOwner::::insert(netuid, owner_coldkey); + + let owner_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &owner_hotkey) + .expect("Owner neuron should already be registered by add_dynamic_network"); + + let additional_hotkey_1 = U256::from(1000); + let additional_coldkey_1 = U256::from(2000); + + let additional_hotkey_2 = U256::from(1001); + let additional_coldkey_2 = U256::from(2001); + + register_ok_neuron(netuid, additional_hotkey_1, additional_coldkey_1, 0); + let uid_1 = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &additional_hotkey_1) + .expect("Should be registered"); + + register_ok_neuron(netuid, additional_hotkey_2, additional_coldkey_2, 1); + let uid_2 = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &additional_hotkey_2) + .expect("Should be registered"); + + SubtensorModule::set_pruning_score_for_uid(netuid, owner_uid, 0); + SubtensorModule::set_pruning_score_for_uid(netuid, uid_1, 1); + SubtensorModule::set_pruning_score_for_uid(netuid, uid_2, 2); + + let pruned_uid = SubtensorModule::get_neuron_to_prune(netuid); + + // - The pruned UID must be `uid_1` (score=1). + // - The owner's UID remains unpruned. + assert_eq!( + pruned_uid, uid_1, + "Should prune the neuron with pruning score=1, not the owner (score=0)." + ); + + let pruned_score = SubtensorModule::get_pruning_score_for_uid(netuid, uid_1); + assert_eq!( + pruned_score, + u16::MAX, + "Pruned neuron's score should be set to u16::MAX" + ); + + let owner_score = SubtensorModule::get_pruning_score_for_uid(netuid, owner_uid); + assert_eq!( + owner_score, 0, + "Owner's pruning score remains 0, indicating it was skipped" + ); + }); +} diff --git a/pallets/subtensor/src/utils/try_state.rs b/pallets/subtensor/src/utils/try_state.rs index db7e4352e..ffa586911 100644 --- a/pallets/subtensor/src/utils/try_state.rs +++ b/pallets/subtensor/src/utils/try_state.rs @@ -1,7 +1,6 @@ use frame_support::traits::fungible::Inspect; use super::*; -use crate::subnets::subnet::POOL_INITIAL_TAO; impl Pallet { /// Checks [`TotalIssuance`] equals the sum of currency issuance, total stake, and total subnet @@ -51,7 +50,7 @@ impl Pallet { // root network doesn't have initial pool TAO acc } else { - acc.saturating_sub(POOL_INITIAL_TAO) + acc.saturating_sub(Self::get_network_min_lock()) } }); diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 84283b034..7b5a71601 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -229,7 +229,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: 227, + spec_version: 228, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/runtime/src/precompiles/mod.rs b/runtime/src/precompiles/mod.rs index 3857affb7..29e05cb00 100644 --- a/runtime/src/precompiles/mod.rs +++ b/runtime/src/precompiles/mod.rs @@ -146,7 +146,7 @@ pub fn get_pubkey(data: &[u8]) -> Result<(AccountId32, vec::Vec), Precompile Ok(( pubkey.into(), - data.get(4..) + data.get(32..) .map_or_else(vec::Vec::new, |slice| slice.to_vec()), )) }