use core::marker::PhantomData; use frame_support::dispatch::{DispatchInfo, GetDispatchInfo, PostDispatchInfo}; use frame_support::traits::ConstU32; use frame_support::traits::IsSubType; use frame_system::RawOrigin; use pallet_evm::{AddressMapping, PrecompileHandle}; use precompile_utils::{ EvmResult, prelude::{BoundedString, BoundedVec, UnboundedBytes}, }; use sp_core::H256; use sp_runtime::traits::{AsSystemOriginSigner, Dispatchable, UniqueSaturatedInto}; use sp_std::{vec, vec::Vec}; use subtensor_runtime_common::{NetUid, TaoBalance, Token}; use crate::{PrecompileExt, PrecompileHandleExt}; use pallet_subtensor::subnets::dissolution::DissolveCleanupPhase; pub struct SubnetPrecompile(PhantomData); impl PrecompileExt for SubnetPrecompile where R: frame_system::Config + pallet_balances::Config + pallet_evm::Config + pallet_subtensor::Config + pallet_admin_utils::Config + pallet_shield::Config + pallet_subtensor_proxy::Config + Send + Sync + scale_info::TypeInfo, R::AccountId: From<[u8; 32]> + Into<[u8; 32]>, ::RuntimeOrigin: AsSystemOriginSigner + Clone, ::RuntimeCall: From> + From> + GetDispatchInfo + Dispatchable + IsSubType> + IsSubType> + IsSubType> + IsSubType>, ::AddressMapping: AddressMapping, { const INDEX: u64 = 2051; } #[precompile_utils::precompile] impl SubnetPrecompile where R: frame_system::Config + pallet_balances::Config + pallet_evm::Config + pallet_subtensor::Config + pallet_shield::Config + pallet_admin_utils::Config + pallet_subtensor_proxy::Config + Send + Sync + scale_info::TypeInfo, R::AccountId: From<[u8; 32]> + Into<[u8; 32]>, ::RuntimeOrigin: AsSystemOriginSigner + Clone, ::RuntimeCall: From> + From> + GetDispatchInfo + Dispatchable + IsSubType> + IsSubType> + IsSubType> + IsSubType>, ::AddressMapping: AddressMapping, { #[precompile::public("registerNetwork(bytes32)")] #[precompile::payable] fn register_network(handle: &mut impl PrecompileHandle, hotkey: H256) -> EvmResult<()> { let hotkey = R::AccountId::from(hotkey.0); let call = pallet_subtensor::Call::::register_network_with_identity { hotkey, identity: None, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public( "registerNetwork(bytes32,string,string,string,string,string,string,string)" )] #[precompile::payable] #[allow(clippy::too_many_arguments)] fn register_network_with_identity( handle: &mut impl PrecompileHandle, hotkey: H256, subnet_name: BoundedString>, github_repo: BoundedString>, subnet_contact: BoundedString>, subnet_url: BoundedString>, discord: BoundedString>, description: BoundedString>, additional: BoundedString>, ) -> EvmResult<()> { let hotkey = R::AccountId::from(hotkey.0); let identity = pallet_subtensor::SubnetIdentityOfV3 { subnet_name: subnet_name.into(), github_repo: github_repo.into(), subnet_contact: subnet_contact.into(), subnet_url: subnet_url.into(), discord: discord.into(), description: description.into(), logo_url: vec![], additional: additional.into(), }; let call = pallet_subtensor::Call::::register_network_with_identity { hotkey, identity: Some(identity), }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public( "registerNetwork(bytes32,string,string,string,string,string,string,string,string)" )] #[precompile::payable] #[allow(clippy::too_many_arguments)] fn register_network_with_identity_v2( handle: &mut impl PrecompileHandle, hotkey: H256, subnet_name: BoundedString>, github_repo: BoundedString>, subnet_contact: BoundedString>, subnet_url: BoundedString>, discord: BoundedString>, description: BoundedString>, additional: BoundedString>, logo_url: BoundedString>, ) -> EvmResult<()> { let hotkey = R::AccountId::from(hotkey.0); let identity = pallet_subtensor::SubnetIdentityOfV3 { subnet_name: subnet_name.into(), github_repo: github_repo.into(), subnet_contact: subnet_contact.into(), subnet_url: subnet_url.into(), discord: discord.into(), description: description.into(), logo_url: logo_url.into(), additional: additional.into(), }; let call = pallet_subtensor::Call::::register_network_with_identity { hotkey, identity: Some(identity), }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getNetworkRegistrationBlock(uint16)")] #[precompile::view] fn get_network_registration_block( handle: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::NetworkRegisteredAt::::get( NetUid::from(netuid), )) } #[precompile::public("getRegisteredSubnetCounter(uint16)")] #[precompile::view] fn get_registered_subnet_counter( handle: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::RegisteredSubnetCounter::::get( NetUid::from(netuid), )) } #[precompile::public("getServingRateLimit(uint16)")] #[precompile::view] fn get_serving_rate_limit(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::ServingRateLimit::::get(NetUid::from( netuid, ))) } #[precompile::public("setServingRateLimit(uint16,uint64)")] #[precompile::payable] fn set_serving_rate_limit( handle: &mut impl PrecompileHandle, netuid: u16, serving_rate_limit: u64, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_serving_rate_limit { netuid: netuid.into(), serving_rate_limit, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getMinDifficulty(uint16)")] #[precompile::view] fn get_min_difficulty(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::MinDifficulty::::get(NetUid::from( netuid, ))) } #[precompile::public("setMinDifficulty(uint16,uint64)")] #[precompile::payable] fn set_min_difficulty( handle: &mut impl PrecompileHandle, netuid: u16, min_difficulty: u64, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_min_difficulty { netuid: netuid.into(), min_difficulty, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getMaxDifficulty(uint16)")] #[precompile::view] fn get_max_difficulty(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::MaxDifficulty::::get(NetUid::from( netuid, ))) } #[precompile::public("setMaxDifficulty(uint16,uint64)")] #[precompile::payable] fn set_max_difficulty( handle: &mut impl PrecompileHandle, netuid: u16, max_difficulty: u64, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_max_difficulty { netuid: netuid.into(), max_difficulty, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getWeightsVersionKey(uint16)")] #[precompile::view] fn get_weights_version_key(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::WeightsVersionKey::::get(NetUid::from( netuid, ))) } #[precompile::public("setWeightsVersionKey(uint16,uint64)")] #[precompile::payable] fn set_weights_version_key( handle: &mut impl PrecompileHandle, netuid: u16, weights_version_key: u64, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_weights_version_key { netuid: netuid.into(), weights_version_key, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getWeightsSetRateLimit(uint16)")] #[precompile::view] fn get_weights_set_rate_limit( handle: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::WeightsSetRateLimit::::get( NetUid::from(netuid), )) } #[precompile::public("setWeightsSetRateLimit(uint16,uint64)")] #[precompile::payable] fn set_weights_set_rate_limit( _handle: &mut impl PrecompileHandle, _netuid: u16, _weights_set_rate_limit: u64, ) -> EvmResult<()> { // DEPRECATED. Subnet owner cannot set weight setting rate limits Ok(()) } #[precompile::public("getAdjustmentAlpha(uint16)")] #[precompile::view] fn get_adjustment_alpha(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::AdjustmentAlpha::::get(NetUid::from( netuid, ))) } #[precompile::public("setAdjustmentAlpha(uint16,uint64)")] #[precompile::payable] fn set_adjustment_alpha( handle: &mut impl PrecompileHandle, netuid: u16, adjustment_alpha: u64, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_adjustment_alpha { netuid: netuid.into(), adjustment_alpha, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getMaxWeightLimit(uint16)")] #[precompile::view] fn get_max_weight_limit(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::Pallet::::get_max_weight_limit( NetUid::from(netuid), )) } #[precompile::public("getImmunityPeriod(uint16)")] #[precompile::view] fn get_immunity_period(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::ImmunityPeriod::::get(NetUid::from( netuid, ))) } #[precompile::public("setImmunityPeriod(uint16,uint16)")] #[precompile::payable] fn set_immunity_period( handle: &mut impl PrecompileHandle, netuid: u16, immunity_period: u16, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_immunity_period { netuid: netuid.into(), immunity_period, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getMinAllowedWeights(uint16)")] #[precompile::view] fn get_min_allowed_weights(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::MinAllowedWeights::::get(NetUid::from( netuid, ))) } #[precompile::public("setMinAllowedWeights(uint16,uint16)")] #[precompile::payable] fn set_min_allowed_weights( handle: &mut impl PrecompileHandle, netuid: u16, min_allowed_weights: u16, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_min_allowed_weights { netuid: netuid.into(), min_allowed_weights, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getKappa(uint16)")] #[precompile::view] fn get_kappa(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::Kappa::::get(NetUid::from(netuid))) } #[precompile::public("setKappa(uint16,uint16)")] #[precompile::payable] fn set_kappa(handle: &mut impl PrecompileHandle, netuid: u16, kappa: u16) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_kappa { netuid: netuid.into(), kappa, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getRho(uint16)")] #[precompile::view] fn get_rho(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::Rho::::get(NetUid::from(netuid))) } #[precompile::public("getAlphaSigmoidSteepness(uint16)")] #[precompile::view] fn get_alpha_sigmoid_steepness( handle: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::AlphaSigmoidSteepness::::get(NetUid::from(netuid)) as u16) } #[precompile::public("setRho(uint16,uint16)")] #[precompile::payable] fn set_rho(handle: &mut impl PrecompileHandle, netuid: u16, rho: u16) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_rho { netuid: netuid.into(), rho, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("setAlphaSigmoidSteepness(uint16,uint16)")] #[precompile::payable] fn set_alpha_sigmoid_steepness( handle: &mut impl PrecompileHandle, netuid: u16, steepness: u16, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_alpha_sigmoid_steepness { netuid: netuid.into(), steepness: (steepness as i16), }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getActivityCutoff(uint16)")] #[precompile::view] fn get_activity_cutoff(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::ActivityCutoff::::get(NetUid::from( netuid, ))) } #[precompile::public("setActivityCutoff(uint16,uint16)")] #[precompile::payable] fn set_activity_cutoff( handle: &mut impl PrecompileHandle, netuid: u16, activity_cutoff: u16, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_activity_cutoff { netuid: netuid.into(), activity_cutoff, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getActivityCutoffFactor(uint16)")] #[precompile::view] fn get_activity_cutoff_factor(_: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { Ok(pallet_subtensor::ActivityCutoffFactorMilli::::get( NetUid::from(netuid), )) } #[precompile::public("setActivityCutoffFactor(uint16,uint32)")] #[precompile::payable] fn set_activity_cutoff_factor( handle: &mut impl PrecompileHandle, netuid: u16, factor_milli: u32, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_activity_cutoff_factor { netuid: netuid.into(), factor_milli, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getNetworkRegistrationAllowed(uint16)")] #[precompile::view] fn get_network_registration_allowed( handle: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::NetworkRegistrationAllowed::::get( NetUid::from(netuid), )) } #[precompile::public("setNetworkRegistrationAllowed(uint16,bool)")] #[precompile::payable] fn set_network_registration_allowed( handle: &mut impl PrecompileHandle, netuid: u16, registration_allowed: bool, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_network_registration_allowed { netuid: netuid.into(), registration_allowed, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getNetworkPowRegistrationAllowed(uint16)")] #[precompile::view] fn get_network_pow_registration_allowed( handle: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::NetworkPowRegistrationAllowed::::get( NetUid::from(netuid), )) } #[precompile::public("setNetworkPowRegistrationAllowed(uint16,bool)")] #[precompile::payable] fn set_network_pow_registration_allowed( handle: &mut impl PrecompileHandle, netuid: u16, registration_allowed: bool, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_network_pow_registration_allowed { netuid: netuid.into(), registration_allowed, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getMinBurn(uint16)")] #[precompile::view] fn get_min_burn(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::MinBurn::::get(NetUid::from(netuid)).to_u64()) } #[precompile::public("setMinBurn(uint16,uint64)")] #[precompile::payable] fn set_min_burn( _handle: &mut impl PrecompileHandle, _netuid: u16, _min_burn: u64, ) -> EvmResult<()> { // DEPRECATED. The subnet owner cannot set the min burn anymore. Ok(()) } #[precompile::public("getMaxBurn(uint16)")] #[precompile::view] fn get_max_burn(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::MaxBurn::::get(NetUid::from(netuid)).to_u64()) } /// Return whether subnet owner-cut emission is automatically stake-locked. #[precompile::public("getOwnerCutAutoLockEnabled(uint16)")] #[precompile::view] fn get_owner_cut_auto_lock_enabled( handle: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::OwnerCutAutoLockEnabled::::get( NetUid::from(netuid), )) } /// Set whether subnet owner-cut emission is automatically stake-locked. #[precompile::public("setOwnerCutAutoLockEnabled(uint16,bool)")] #[precompile::payable] fn set_owner_cut_auto_lock_enabled( handle: &mut impl PrecompileHandle, netuid: u16, enabled: bool, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_owner_cut_auto_lock_enabled { netuid: NetUid::from(netuid), enabled, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("setMaxBurn(uint16,uint64)")] #[precompile::payable] fn set_max_burn( _handle: &mut impl PrecompileHandle, _netuid: u16, _max_burn: u64, ) -> EvmResult<()> { // DEPRECATED. The subnet owner cannot set the max burn anymore. Ok(()) } #[precompile::public("getDifficulty(uint16)")] #[precompile::view] fn get_difficulty(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::Difficulty::::get(NetUid::from(netuid))) } #[precompile::public("setDifficulty(uint16,uint64)")] #[precompile::payable] fn set_difficulty( handle: &mut impl PrecompileHandle, netuid: u16, difficulty: u64, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_difficulty { netuid: netuid.into(), difficulty, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getBondsMovingAverage(uint16)")] #[precompile::view] fn get_bonds_moving_average(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::BondsMovingAverage::::get( NetUid::from(netuid), )) } #[precompile::public("setBondsMovingAverage(uint16,uint64)")] #[precompile::payable] fn set_bonds_moving_average( handle: &mut impl PrecompileHandle, netuid: u16, bonds_moving_average: u64, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_bonds_moving_average { netuid: netuid.into(), bonds_moving_average, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getCommitRevealWeightsEnabled(uint16)")] #[precompile::view] fn get_commit_reveal_weights_enabled( handle: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::CommitRevealWeightsEnabled::::get( NetUid::from(netuid), )) } #[precompile::public("setCommitRevealWeightsEnabled(uint16,bool)")] #[precompile::payable] fn set_commit_reveal_weights_enabled( handle: &mut impl PrecompileHandle, netuid: u16, enabled: bool, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_commit_reveal_weights_enabled { netuid: netuid.into(), enabled, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getLiquidAlphaEnabled(uint16)")] #[precompile::view] fn get_liquid_alpha_enabled( handle: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::LiquidAlphaOn::::get(NetUid::from( netuid, ))) } #[precompile::public("setLiquidAlphaEnabled(uint16,bool)")] #[precompile::payable] fn set_liquid_alpha_enabled( handle: &mut impl PrecompileHandle, netuid: u16, enabled: bool, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_liquid_alpha_enabled { netuid: netuid.into(), enabled, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getYuma3Enabled(uint16)")] #[precompile::view] fn get_yuma3_enabled(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::Yuma3On::::get(NetUid::from(netuid))) } #[precompile::public("getBondsResetEnabled(uint16)")] #[precompile::view] fn get_bonds_reset_enabled(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::BondsResetOn::::get(NetUid::from( netuid, ))) } #[precompile::public("setYuma3Enabled(uint16,bool)")] #[precompile::payable] fn set_yuma3_enabled( handle: &mut impl PrecompileHandle, netuid: u16, enabled: bool, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_yuma3_enabled { netuid: netuid.into(), enabled, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("setBondsResetEnabled(uint16,bool)")] #[precompile::payable] fn set_bonds_reset_enabled( handle: &mut impl PrecompileHandle, netuid: u16, enabled: bool, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_bonds_reset_enabled { netuid: netuid.into(), enabled, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getAlphaValues(uint16)")] #[precompile::view] fn get_alpha_values(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult<(u16, u16)> { handle.record_db_reads::(1)?; Ok(pallet_subtensor::AlphaValues::::get(NetUid::from( netuid, ))) } #[precompile::public("setAlphaValues(uint16,uint16,uint16)")] #[precompile::payable] fn set_alpha_values( handle: &mut impl PrecompileHandle, netuid: u16, alpha_low: u16, alpha_high: u16, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_alpha_values { netuid: netuid.into(), alpha_low, alpha_high, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("getCommitRevealWeightsInterval(uint16)")] #[precompile::view] fn get_commit_reveal_weights_interval( handle: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::RevealPeriodEpochs::::get( NetUid::from(netuid), )) } #[precompile::public("setCommitRevealWeightsInterval(uint16,uint64)")] #[precompile::payable] fn set_commit_reveal_weights_interval( handle: &mut impl PrecompileHandle, netuid: u16, interval: u64, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_commit_reveal_weights_interval { netuid: netuid.into(), interval, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("toggleTransfers(uint16,bool)")] #[precompile::payable] fn toggle_transfers( handle: &mut impl PrecompileHandle, netuid: u16, toggle: bool, ) -> EvmResult<()> { let call = pallet_admin_utils::Call::::sudo_set_toggle_transfer { netuid: netuid.into(), toggle, }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("isSubnetDissolving(uint16)")] #[precompile::view] fn is_subnet_dissolving(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::DissolveCleanupQueue::::get().contains(&NetUid::from(netuid))) } #[precompile::public("getSubnetDissolutionStatus(uint16)")] #[precompile::view] fn get_subnet_dissolution_status( handle: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult<(bool, bool, u8)> { handle.record_db_reads::(2)?; let netuid = NetUid::from(netuid); let is_queued = pallet_subtensor::DissolveCleanupQueue::::get().contains(&netuid); match pallet_subtensor::CurrentDissolveCleanupStatus::::get() { Some(status) if status.netuid == netuid => { Ok((true, true, dissolution_cleanup_phase_code(&status.phase))) } _ => Ok((is_queued, false, 0)), } } #[precompile::public( "setSubnetIdentity(uint16,string,string,string,string,string,string,string,string)" )] #[allow(clippy::too_many_arguments)] fn set_subnet_identity( handle: &mut impl PrecompileHandle, netuid: u16, subnet_name: BoundedString>, github_repo: BoundedString>, subnet_contact: BoundedString>, subnet_url: BoundedString>, discord: BoundedString>, description: BoundedString>, logo_url: BoundedString>, additional: BoundedString>, ) -> EvmResult<()> { let call = pallet_subtensor::Call::::set_subnet_identity { netuid: NetUid::from(netuid), subnet_name: subnet_name.into(), github_repo: github_repo.into(), subnet_contact: subnet_contact.into(), subnet_url: subnet_url.into(), discord: discord.into(), description: description.into(), logo_url: logo_url.into(), additional: additional.into(), }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("updateSubnetSymbol(uint16,string)")] fn update_subnet_symbol( handle: &mut impl PrecompileHandle, netuid: u16, symbol: BoundedString>, ) -> EvmResult<()> { let call = pallet_subtensor::Call::::update_symbol { netuid: NetUid::from(netuid), symbol: symbol.into(), }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("triggerEpoch(uint16)")] fn trigger_epoch(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult<()> { let call = pallet_subtensor::Call::::trigger_epoch { netuid: NetUid::from(netuid), }; handle.try_dispatch_runtime_call::( call, RawOrigin::Signed(handle.caller_account_id::()), ) } #[precompile::public("setBondsPenalty(uint16,uint16)")] fn set_bonds_penalty( handle: &mut impl PrecompileHandle, netuid: u16, bonds_penalty: u16, ) -> EvmResult<()> { dispatch_admin( handle, pallet_admin_utils::Call::::sudo_set_bonds_penalty { netuid: netuid.into(), bonds_penalty, }, ) } #[precompile::public("setMaxAllowedUids(uint16,uint16)")] fn set_max_allowed_uids( handle: &mut impl PrecompileHandle, netuid: u16, max_allowed_uids: u16, ) -> EvmResult<()> { dispatch_admin( handle, pallet_admin_utils::Call::::sudo_set_max_allowed_uids { netuid: netuid.into(), max_allowed_uids, }, ) } #[precompile::public("setMaxBurnV2(uint16,uint64)")] fn set_max_burn_v2( handle: &mut impl PrecompileHandle, netuid: u16, max_burn: u64, ) -> EvmResult<()> { dispatch_admin( handle, pallet_admin_utils::Call::::sudo_set_max_burn { netuid: netuid.into(), max_burn: TaoBalance::from(max_burn), }, ) } #[precompile::public("setMechanismCount(uint16,uint8)")] fn set_mechanism_count( handle: &mut impl PrecompileHandle, netuid: u16, mechanism_count: u8, ) -> EvmResult<()> { dispatch_admin( handle, pallet_admin_utils::Call::::sudo_set_mechanism_count { netuid: netuid.into(), mechanism_count: mechanism_count.into(), }, ) } #[precompile::public("setMechanismEmissionSplit(uint16,bool,uint16[])")] fn set_mechanism_emission_split( handle: &mut impl PrecompileHandle, netuid: u16, has_split: bool, split: BoundedVec>, ) -> EvmResult<()> { dispatch_admin( handle, pallet_admin_utils::Call::::sudo_set_mechanism_emission_split { netuid: netuid.into(), maybe_split: has_split.then(|| Vec::::from(split)), }, ) } #[precompile::public("setMinBurnV2(uint16,uint64)")] fn set_min_burn_v2( handle: &mut impl PrecompileHandle, netuid: u16, min_burn: u64, ) -> EvmResult<()> { dispatch_admin( handle, pallet_admin_utils::Call::::sudo_set_min_burn { netuid: netuid.into(), min_burn: TaoBalance::from(min_burn), }, ) } #[precompile::public("setOwnerCutEnabled(uint16,bool)")] fn set_owner_cut_enabled( handle: &mut impl PrecompileHandle, netuid: u16, enabled: bool, ) -> EvmResult<()> { dispatch_admin( handle, pallet_admin_utils::Call::::sudo_set_owner_cut_enabled { netuid: netuid.into(), enabled, }, ) } #[precompile::public("setOwnerImmuneNeuronLimit(uint16,uint16)")] fn set_owner_immune_neuron_limit( handle: &mut impl PrecompileHandle, netuid: u16, immune_neurons: u16, ) -> EvmResult<()> { dispatch_admin( handle, pallet_admin_utils::Call::::sudo_set_owner_immune_neuron_limit { netuid: netuid.into(), immune_neurons, }, ) } #[precompile::public("setTempo(uint16,uint16)")] fn set_tempo(handle: &mut impl PrecompileHandle, netuid: u16, tempo: u16) -> EvmResult<()> { dispatch_admin( handle, pallet_admin_utils::Call::::sudo_set_tempo { netuid: netuid.into(), tempo, }, ) } #[precompile::public("trimToMaxAllowedUids(uint16,uint16)")] fn trim_to_max_allowed_uids( handle: &mut impl PrecompileHandle, netuid: u16, max_n: u16, ) -> EvmResult<()> { dispatch_admin( handle, pallet_admin_utils::Call::::sudo_trim_to_max_allowed_uids { netuid: netuid.into(), max_n, }, ) } #[precompile::public("getSubnetMetadata(uint16)")] #[precompile::view] fn get_subnet_metadata( handle: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult<(UnboundedBytes, H256, H256, u16, u8)> { handle.record_db_reads::(5)?; let netuid = NetUid::from(netuid); let recycle_or_burn = match pallet_subtensor::RecycleOrBurn::::get(netuid) { pallet_subtensor::RecycleOrBurnEnum::Burn => 0, pallet_subtensor::RecycleOrBurnEnum::Recycle => 1, }; Ok(( UnboundedBytes::from(pallet_subtensor::TokenSymbol::::get(netuid)), account_to_h256(pallet_subtensor::SubnetOwner::::get(netuid)), account_to_h256(pallet_subtensor::SubnetOwnerHotkey::::get(netuid)), pallet_subtensor::Tempo::::get(netuid), recycle_or_burn, )) } #[precompile::public("getSubnetCapacityConfig(uint16)")] #[precompile::view] fn get_subnet_capacity_config( handle: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult<(u16, u16, u16, u16, u16, u16, u16, u16, bool, bool, u16, u8)> { handle.record_db_reads::(12)?; let netuid = NetUid::from(netuid); Ok(( pallet_subtensor::MinAllowedUids::::get(netuid), pallet_subtensor::MaxAllowedUids::::get(netuid), pallet_subtensor::MaxAllowedValidators::::get(netuid), pallet_subtensor::AdjustmentInterval::::get(netuid), pallet_subtensor::TargetRegistrationsPerInterval::::get(netuid), pallet_subtensor::MinNonImmuneUids::::get(netuid), pallet_subtensor::ImmuneOwnerUidsLimit::::get(netuid), pallet_subtensor::BondsPenalty::::get(netuid), pallet_subtensor::OwnerCutEnabled::::get(netuid), pallet_subtensor::TransferToggle::::get(netuid), pallet_subtensor::MaxRegistrationsPerBlock::::get(netuid), pallet_subtensor::MechanismCountCurrent::::get(netuid).into(), )) } #[precompile::public("getMechanismEmissionSplit(uint16)")] #[precompile::view] fn get_mechanism_emission_split( handle: &mut impl PrecompileHandle, netuid: u16, ) -> EvmResult<(bool, Vec)> { handle.record_db_reads::(1)?; Ok( match pallet_subtensor::MechanismEmissionSplit::::get(NetUid::from(netuid)) { Some(split) => (true, split), None => (false, Vec::new()), }, ) } #[precompile::public("getBurnConfig(uint16)")] #[precompile::view] fn get_burn_config(handle: &mut impl PrecompileHandle, netuid: u16) -> EvmResult<(u16, u128)> { handle.record_db_reads::(2)?; let netuid = NetUid::from(netuid); Ok(( pallet_subtensor::BurnHalfLife::::get(netuid), pallet_subtensor::BurnIncreaseMult::::get(netuid).to_bits(), )) } #[precompile::public("getGlobalNetworkLimits()")] #[precompile::view] fn get_global_network_limits( handle: &mut impl PrecompileHandle, ) -> EvmResult<(u16, u16, u16, u64, u16, u16, u64, u64, u64, u64, u64, u16)> { handle.record_db_reads::(12)?; Ok(( pallet_subtensor::MinActivityCutoff::::get(), pallet_subtensor::AdminFreezeWindow::::get(), pallet_subtensor::OwnerHyperparamRateLimit::::get(), pallet_subtensor::DissolveNetworkScheduleDuration::::get().unique_saturated_into(), pallet_subtensor::SubnetLimit::::get(), pallet_subtensor::TotalNetworks::::get(), pallet_subtensor::NetworkImmunityPeriod::::get(), pallet_subtensor::StartCallDelay::::get(), pallet_subtensor::NetworkMinLockCost::::get().to_u64(), pallet_subtensor::NetworkLastLockCost::::get().to_u64(), pallet_subtensor::NetworkLockReductionInterval::::get(), pallet_subtensor::SubnetOwnerCut::::get(), )) } #[precompile::public("getGlobalRateLimits()")] #[precompile::view] fn get_global_rate_limits( handle: &mut impl PrecompileHandle, ) -> EvmResult<(u64, u64, u64, u64, u64, u8)> { handle.record_db_reads::(6)?; Ok(( pallet_subtensor::NetworkRateLimit::::get(), pallet_subtensor::WeightsVersionKeyRateLimit::::get(), pallet_subtensor::TxRateLimit::::get(), pallet_subtensor::TxDelegateTakeRateLimit::::get(), pallet_subtensor::TxChildkeyTakeRateLimit::::get(), pallet_subtensor::MaxEpochsPerBlock::::get(), )) } #[precompile::public("getGlobalProtocolConfig()")] #[precompile::view] fn get_global_protocol_config( handle: &mut impl PrecompileHandle, ) -> EvmResult<(u8, u16, u64, u64)> { handle.record_db_reads::(4)?; Ok(( pallet_subtensor::MaxMechanismCount::::get().into(), pallet_subtensor::CommitRevealWeightsVersion::::get(), pallet_subtensor::NetworkRegistrationStartBlock::::get(), pallet_subtensor::TaoInRefundDeploymentBlock::::get(), )) } } fn account_to_h256>(account: AccountId) -> H256 { H256::from(account.into()) } fn dispatch_admin( handle: &mut impl PrecompileHandle, call: pallet_admin_utils::Call, ) -> EvmResult<()> where R: frame_system::Config + pallet_balances::Config + pallet_evm::Config + pallet_subtensor::Config + pallet_admin_utils::Config + pallet_shield::Config + pallet_subtensor_proxy::Config + Send + Sync + scale_info::TypeInfo, R::AccountId: From<[u8; 32]> + Into<[u8; 32]>, ::RuntimeOrigin: AsSystemOriginSigner + Clone, ::RuntimeCall: From> + GetDispatchInfo + Dispatchable + IsSubType> + IsSubType> + IsSubType> + IsSubType>, ::AddressMapping: AddressMapping, { let caller = handle.caller_account_id::(); handle.try_dispatch_runtime_call::(call, RawOrigin::Signed(caller)) } /// Stable, append-only EVM codes for the runtime's detailed cleanup phases. /// /// These values intentionally do not use the Rust enum discriminant. Runtime /// phases may be reordered internally without changing the Solidity contract. fn dissolution_cleanup_phase_code(phase: &DissolveCleanupPhase) -> u8 { match phase { DissolveCleanupPhase::SubnetRootDividendsRootClaimable => 1, DissolveCleanupPhase::SubnetRootDividendsRootClaimed => 2, DissolveCleanupPhase::AlphaInOutStakesGetTotalAlphaValue => 3, DissolveCleanupPhase::AlphaInOutStakesSettleStakes => 4, DissolveCleanupPhase::AlphaInOutStakesAlpha => 5, DissolveCleanupPhase::AlphaInOutStakesHotkeyTotals => 6, DissolveCleanupPhase::AlphaInOutStakesLocks => 7, DissolveCleanupPhase::AlphaInOutStakesDecayingLocks => 8, DissolveCleanupPhase::AlphaInOutStakes => 9, DissolveCleanupPhase::ProtocolLiquidity => 10, DissolveCleanupPhase::PurgeNetuid => 11, DissolveCleanupPhase::NetworkIsNetworkMember => 12, DissolveCleanupPhase::NetworkParameters => 13, DissolveCleanupPhase::NetworkMapParameters => 14, DissolveCleanupPhase::NetworkUpdateWeightsOnRoot => 15, DissolveCleanupPhase::NetworkChildkeyTake => 16, DissolveCleanupPhase::NetworkChildkeys => 17, DissolveCleanupPhase::NetworkParentkeys => 18, DissolveCleanupPhase::NetworkLastHotkeyEmissionOnNetuid => 19, DissolveCleanupPhase::NetworkTotalHotkeyAlphaLastEpoch => 20, DissolveCleanupPhase::NetworkTransactionKeyLastBlock => 21, DissolveCleanupPhase::NetworkLock => 22, DissolveCleanupPhase::NetworkDecayingLock => 23, DissolveCleanupPhase::SubnetBasketHoldingsToRoot => 24, DissolveCleanupPhase::NetworkPendingBasketDeposits => 25, DissolveCleanupPhase::NetworkAlphaAssetCounters => 26, } } #[cfg(test)] mod tests { #![allow( clippy::arithmetic_side_effects, clippy::expect_used, clippy::unwrap_used )] use super::*; use crate::PrecompileExt; use crate::mock::{ AccountId, Runtime, addr_from_index, assert_static_call, execute_precompile, mapped_account, new_test_ext, precompiles, selector_u32, }; use precompile_utils::solidity::encode_with_selector; use precompile_utils::testing::PrecompileTesterExt; use sp_core::{H160, H256, U256}; use subtensor_runtime_common::TaoBalance; const TEST_NETUID_U16: u16 = 1; const TEST_TEMPO: u16 = 100; fn setup_owner_subnet(caller: H160) -> NetUid { let netuid = NetUid::from(TEST_NETUID_U16); let owner = mapped_account(caller); let owner_hotkey = AccountId::from([0x55; 32]); pallet_subtensor::Pallet::::init_new_network(netuid, TEST_TEMPO); pallet_subtensor::SubnetOwner::::insert(netuid, owner); pallet_subtensor::SubnetOwnerHotkey::::insert(netuid, owner_hotkey); pallet_subtensor::AdminFreezeWindow::::set(0); pallet_subtensor::OwnerHyperparamRateLimit::::set(0); netuid } fn add_balance_to_coldkey_account(coldkey: &sp_core::crypto::AccountId32, tao: TaoBalance) { let credit = pallet_subtensor::Pallet::::mint_tao(tao); let _ = pallet_subtensor::Pallet::::spend_tao(coldkey, credit, tao).unwrap(); } #[test] fn subnet_precompile_registers_network_without_identity() { new_test_ext().execute_with(|| { let caller = addr_from_index(0x5000); let caller_account = mapped_account(caller); let hotkey = AccountId::from([0x44; 32]); let precompiles = precompiles::>(); let precompile_addr = addr_from_index(SubnetPrecompile::::INDEX); add_balance_to_coldkey_account(&caller_account, 1_000_000_000_000_u64.into()); let total_before = pallet_subtensor::TotalNetworks::::get(); let netuid = pallet_subtensor::Pallet::::get_next_netuid(); precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("registerNetwork(bytes32)"), (H256::from_slice(hotkey.as_ref()),), ), ) .execute_returns(()); let total_after = pallet_subtensor::TotalNetworks::::get(); assert_eq!(total_after, total_before + 1); assert_eq!( pallet_subtensor::SubnetOwner::::get(netuid), caller_account ); assert!(!pallet_subtensor::SubnetIdentitiesV3::::contains_key(netuid)); }); } #[test] fn subnet_precompile_registers_network_with_identity() { new_test_ext().execute_with(|| { let caller = addr_from_index(0x5002); let caller_account = mapped_account(caller); let hotkey = AccountId::from([0x45; 32]); let precompiles = precompiles::>(); let precompile_addr = addr_from_index(SubnetPrecompile::::INDEX); add_balance_to_coldkey_account( &caller_account, 1_000_000_000_000_u64.into(), ); let total_before = pallet_subtensor::TotalNetworks::::get(); let netuid = pallet_subtensor::Pallet::::get_next_netuid(); precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32( "registerNetwork(bytes32,string,string,string,string,string,string,string)", ), ( H256::from_slice(hotkey.as_ref()), precompile_utils::solidity::codec::UnboundedString::from("name"), precompile_utils::solidity::codec::UnboundedString::from("repo"), precompile_utils::solidity::codec::UnboundedString::from("contact"), precompile_utils::solidity::codec::UnboundedString::from("subnetUrl"), precompile_utils::solidity::codec::UnboundedString::from("discord"), precompile_utils::solidity::codec::UnboundedString::from("description"), precompile_utils::solidity::codec::UnboundedString::from("additional"), ), ), ) .execute_returns(()); let total_after = pallet_subtensor::TotalNetworks::::get(); assert_eq!(total_after, total_before + 1); assert_eq!(pallet_subtensor::SubnetOwner::::get(netuid), caller_account); assert!(pallet_subtensor::SubnetIdentitiesV3::::contains_key(netuid)); }); } #[test] fn subnet_precompile_sets_and_gets_owner_cut_auto_lock() { new_test_ext().execute_with(|| { let caller = addr_from_index(0x5003); let netuid = setup_owner_subnet(caller); let precompiles = precompiles::>(); let precompile_addr = addr_from_index(SubnetPrecompile::::INDEX); precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("getOwnerCutAutoLockEnabled(uint16)"), (TEST_NETUID_U16,), ), ) .with_static_call(true) .expect_cost( precompile_utils::prelude::RuntimeHelper::::db_read_gas_cost(), ) .execute_returns(false); precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("setOwnerCutAutoLockEnabled(uint16,bool)"), (TEST_NETUID_U16, true), ), ) .execute_returns(()); assert!(pallet_subtensor::OwnerCutAutoLockEnabled::::get( netuid )); precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("getOwnerCutAutoLockEnabled(uint16)"), (TEST_NETUID_U16,), ), ) .with_static_call(true) .expect_cost( precompile_utils::prelude::RuntimeHelper::::db_read_gas_cost(), ) .execute_returns(true); }); } #[test] fn subnet_precompile_sets_and_gets_owner_hyperparameters() { new_test_ext().execute_with(|| { let caller = addr_from_index(0x5001); let netuid = setup_owner_subnet(caller); let precompiles = precompiles::>(); let precompile_addr = addr_from_index(SubnetPrecompile::::INDEX); precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("setServingRateLimit(uint16,uint64)"), (TEST_NETUID_U16, 100_u64), ), ) .execute_returns(()); assert_eq!( pallet_subtensor::ServingRateLimit::::get(netuid), 100 ); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("getServingRateLimit(uint16)"), (TEST_NETUID_U16,), ), U256::from(100_u64), ); precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("setMaxDifficulty(uint16,uint64)"), (TEST_NETUID_U16, 102_u64), ), ) .execute_returns(()); assert_eq!(pallet_subtensor::MaxDifficulty::::get(netuid), 102); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector(selector_u32("getMaxDifficulty(uint16)"), (TEST_NETUID_U16,)), U256::from(102_u64), ); precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("setWeightsVersionKey(uint16,uint64)"), (TEST_NETUID_U16, 103_u64), ), ) .execute_returns(()); assert_eq!( pallet_subtensor::WeightsVersionKey::::get(netuid), 103 ); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("getWeightsVersionKey(uint16)"), (TEST_NETUID_U16,), ), U256::from(103_u64), ); precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("setAdjustmentAlpha(uint16,uint64)"), (TEST_NETUID_U16, 105_u64), ), ) .execute_returns(()); assert_eq!( pallet_subtensor::AdjustmentAlpha::::get(netuid), 105 ); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("getAdjustmentAlpha(uint16)"), (TEST_NETUID_U16,), ), U256::from(105_u64), ); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("getMaxWeightLimit(uint16)"), (TEST_NETUID_U16,), ), U256::from(0xFFFF_u64), ); precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("setImmunityPeriod(uint16,uint16)"), (TEST_NETUID_U16, 107_u16), ), ) .execute_returns(()); assert_eq!( pallet_subtensor::ImmunityPeriod::::get(netuid), 107 ); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("getImmunityPeriod(uint16)"), (TEST_NETUID_U16,), ), U256::from(107_u64), ); precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("setMinAllowedWeights(uint16,uint16)"), (TEST_NETUID_U16, 108_u16), ), ) .execute_returns(()); assert_eq!( pallet_subtensor::MinAllowedWeights::::get(netuid), 108 ); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("getMinAllowedWeights(uint16)"), (TEST_NETUID_U16,), ), U256::from(108_u64), ); precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("setRho(uint16,uint16)"), (TEST_NETUID_U16, 110_u16), ), ) .execute_returns(()); assert_eq!(pallet_subtensor::Rho::::get(netuid), 110); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector(selector_u32("getRho(uint16)"), (TEST_NETUID_U16,)), U256::from(110_u64), ); let activity_cutoff = pallet_subtensor::MinActivityCutoff::::get() + 1; precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("setActivityCutoff(uint16,uint16)"), (TEST_NETUID_U16, activity_cutoff), ), ) .execute_returns(()); assert_eq!( pallet_subtensor::ActivityCutoff::::get(netuid), activity_cutoff ); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("getActivityCutoff(uint16)"), (TEST_NETUID_U16,), ), U256::from(activity_cutoff), ); let factor_milli: u32 = 1_500; precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("setActivityCutoffFactor(uint16,uint32)"), (TEST_NETUID_U16, factor_milli), ), ) .execute_returns(()); assert_eq!( pallet_subtensor::ActivityCutoffFactorMilli::::get(netuid), factor_milli ); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("getActivityCutoffFactor(uint16)"), (TEST_NETUID_U16,), ), U256::from(factor_milli), ); precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("setBondsMovingAverage(uint16,uint64)"), (TEST_NETUID_U16, 115_u64), ), ) .execute_returns(()); assert_eq!( pallet_subtensor::BondsMovingAverage::::get(netuid), 115 ); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("getBondsMovingAverage(uint16)"), (TEST_NETUID_U16,), ), U256::from(115_u64), ); precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("setCommitRevealWeightsEnabled(uint16,bool)"), (TEST_NETUID_U16, true), ), ) .execute_returns(()); assert!(pallet_subtensor::CommitRevealWeightsEnabled::::get(netuid)); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("getCommitRevealWeightsEnabled(uint16)"), (TEST_NETUID_U16,), ), U256::one(), ); precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("setLiquidAlphaEnabled(uint16,bool)"), (TEST_NETUID_U16, true), ), ) .execute_returns(()); assert!(pallet_subtensor::LiquidAlphaOn::::get(netuid)); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("getLiquidAlphaEnabled(uint16)"), (TEST_NETUID_U16,), ), U256::one(), ); precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("setYuma3Enabled(uint16,bool)"), (TEST_NETUID_U16, true), ), ) .execute_returns(()); assert!(pallet_subtensor::Yuma3On::::get(netuid)); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector(selector_u32("getYuma3Enabled(uint16)"), (TEST_NETUID_U16,)), U256::one(), ); precompiles .prepare_test( caller, precompile_addr, encode_with_selector( selector_u32("setCommitRevealWeightsInterval(uint16,uint64)"), (TEST_NETUID_U16, 99_u64), ), ) .execute_returns(()); assert_eq!( pallet_subtensor::RevealPeriodEpochs::::get(netuid), 99 ); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("getCommitRevealWeightsInterval(uint16)"), (TEST_NETUID_U16,), ), U256::from(99_u64), ); }); } #[test] fn subnet_precompile_gets_network_registered_block() { new_test_ext().execute_with(|| { let caller = addr_from_index(0x5003); let netuid = setup_owner_subnet(caller); let precompiles = precompiles::>(); let precompile_addr = addr_from_index(SubnetPrecompile::::INDEX); let registration_block: u64 = 42; pallet_subtensor::NetworkRegisteredAt::::insert(netuid, registration_block); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("getNetworkRegistrationBlock(uint16)"), (TEST_NETUID_U16,), ), U256::from(registration_block), ); pallet_subtensor::NetworkRegisteredAt::::remove(netuid); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("getNetworkRegistrationBlock(uint16)"), (TEST_NETUID_U16,), ), U256::zero(), ); }); } #[test] fn subnet_precompile_gets_registered_subnet_counter() { new_test_ext().execute_with(|| { let caller = addr_from_index(0x5003); let netuid = setup_owner_subnet(caller); let precompiles = precompiles::>(); let precompile_addr = addr_from_index(SubnetPrecompile::::INDEX); pallet_subtensor::RegisteredSubnetCounter::::insert(netuid, 7); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("getRegisteredSubnetCounter(uint16)"), (TEST_NETUID_U16,), ), U256::from(7_u64), ); pallet_subtensor::RegisteredSubnetCounter::::remove(netuid); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("getRegisteredSubnetCounter(uint16)"), (TEST_NETUID_U16,), ), U256::zero(), ); }); } #[test] fn subnet_precompile_is_subnet_dissolving() { new_test_ext().execute_with(|| { let caller = addr_from_index(0x5003); let netuid = setup_owner_subnet(caller); let precompiles = precompiles::>(); let precompile_addr = addr_from_index(SubnetPrecompile::::INDEX); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("isSubnetDissolving(uint16)"), (TEST_NETUID_U16,), ), U256::zero(), ); pallet_subtensor::DissolveCleanupQueue::::set(vec![netuid]); assert_static_call( &precompiles, caller, precompile_addr, encode_with_selector( selector_u32("isSubnetDissolving(uint16)"), (TEST_NETUID_U16,), ), U256::one(), ); }); } #[test] fn subnet_precompile_reports_stable_dissolution_cleanup_status() { new_test_ext().execute_with(|| { let caller = addr_from_index(0x5003); let netuid = setup_owner_subnet(caller); let precompiles = precompiles::>(); let precompile_addr = addr_from_index(SubnetPrecompile::::INDEX); let input = || { encode_with_selector( selector_u32("getSubnetDissolutionStatus(uint16)"), (TEST_NETUID_U16,), ) }; precompiles .prepare_test(caller, precompile_addr, input()) .with_static_call(true) .execute_returns((false, false, 0_u8)); pallet_subtensor::DissolveCleanupQueue::::set(vec![netuid]); precompiles .prepare_test(caller, precompile_addr, input()) .with_static_call(true) .execute_returns((true, false, 0_u8)); let mut status = pallet_subtensor::subnets::dissolution::DissolveCleanupStatus::new(netuid); status.set_phase(DissolveCleanupPhase::AlphaInOutStakesSettleStakes); pallet_subtensor::CurrentDissolveCleanupStatus::::set(Some(status)); precompiles .prepare_test(caller, precompile_addr, input()) .with_static_call(true) .execute_returns((true, true, 4_u8)); }); } #[test] fn dissolution_cleanup_phase_codes_are_stable() { let phases = [ (DissolveCleanupPhase::SubnetRootDividendsRootClaimable, 1), (DissolveCleanupPhase::SubnetRootDividendsRootClaimed, 2), (DissolveCleanupPhase::AlphaInOutStakesGetTotalAlphaValue, 3), (DissolveCleanupPhase::AlphaInOutStakesSettleStakes, 4), (DissolveCleanupPhase::AlphaInOutStakesAlpha, 5), (DissolveCleanupPhase::AlphaInOutStakesHotkeyTotals, 6), (DissolveCleanupPhase::AlphaInOutStakesLocks, 7), (DissolveCleanupPhase::AlphaInOutStakesDecayingLocks, 8), (DissolveCleanupPhase::AlphaInOutStakes, 9), (DissolveCleanupPhase::ProtocolLiquidity, 10), (DissolveCleanupPhase::PurgeNetuid, 11), (DissolveCleanupPhase::NetworkIsNetworkMember, 12), (DissolveCleanupPhase::NetworkParameters, 13), (DissolveCleanupPhase::NetworkMapParameters, 14), (DissolveCleanupPhase::NetworkUpdateWeightsOnRoot, 15), (DissolveCleanupPhase::NetworkChildkeyTake, 16), (DissolveCleanupPhase::NetworkChildkeys, 17), (DissolveCleanupPhase::NetworkParentkeys, 18), (DissolveCleanupPhase::NetworkLastHotkeyEmissionOnNetuid, 19), (DissolveCleanupPhase::NetworkTotalHotkeyAlphaLastEpoch, 20), (DissolveCleanupPhase::NetworkTransactionKeyLastBlock, 21), (DissolveCleanupPhase::NetworkLock, 22), (DissolveCleanupPhase::NetworkDecayingLock, 23), (DissolveCleanupPhase::SubnetBasketHoldingsToRoot, 24), (DissolveCleanupPhase::NetworkPendingBasketDeposits, 25), (DissolveCleanupPhase::NetworkAlphaAssetCounters, 26), ]; for (phase, expected) in phases { assert_eq!(dissolution_cleanup_phase_code(&phase), expected); } } #[test] fn subnet_state_views_return_grouped_runtime_configuration() { new_test_ext().execute_with(|| { let caller = addr_from_index(0x5020); let netuid = setup_owner_subnet(caller); let address = addr_from_index(SubnetPrecompile::::INDEX); let precompiles = precompiles::>(); precompiles .prepare_test( caller, address, encode_with_selector( selector_u32("getSubnetMetadata(uint16)"), (TEST_NETUID_U16,), ), ) .with_static_call(true) .execute_returns(( UnboundedBytes::from(pallet_subtensor::TokenSymbol::::get(netuid)), account_to_h256(pallet_subtensor::SubnetOwner::::get(netuid)), account_to_h256(pallet_subtensor::SubnetOwnerHotkey::::get(netuid)), pallet_subtensor::Tempo::::get(netuid), 0_u8, )); precompiles .prepare_test( caller, address, encode_with_selector( selector_u32("getSubnetCapacityConfig(uint16)"), (TEST_NETUID_U16,), ), ) .with_static_call(true) .execute_returns(( pallet_subtensor::MinAllowedUids::::get(netuid), pallet_subtensor::MaxAllowedUids::::get(netuid), pallet_subtensor::MaxAllowedValidators::::get(netuid), pallet_subtensor::AdjustmentInterval::::get(netuid), pallet_subtensor::TargetRegistrationsPerInterval::::get(netuid), pallet_subtensor::MinNonImmuneUids::::get(netuid), pallet_subtensor::ImmuneOwnerUidsLimit::::get(netuid), pallet_subtensor::BondsPenalty::::get(netuid), pallet_subtensor::OwnerCutEnabled::::get(netuid), pallet_subtensor::TransferToggle::::get(netuid), pallet_subtensor::MaxRegistrationsPerBlock::::get(netuid), u8::from(pallet_subtensor::MechanismCountCurrent::::get( netuid, )), )); precompiles .prepare_test( caller, address, encode_with_selector( selector_u32("getMechanismEmissionSplit(uint16)"), (TEST_NETUID_U16,), ), ) .with_static_call(true) .execute_returns((false, Vec::::new())); precompiles .prepare_test( caller, address, encode_with_selector(selector_u32("getBurnConfig(uint16)"), (TEST_NETUID_U16,)), ) .with_static_call(true) .execute_returns(( pallet_subtensor::BurnHalfLife::::get(netuid), pallet_subtensor::BurnIncreaseMult::::get(netuid).to_bits(), )); let dissolve_schedule_duration: u64 = pallet_subtensor::DissolveNetworkScheduleDuration::::get() .unique_saturated_into(); precompiles .prepare_test( caller, address, selector_u32("getGlobalNetworkLimits()") .to_be_bytes() .to_vec(), ) .with_static_call(true) .execute_returns(( pallet_subtensor::MinActivityCutoff::::get(), pallet_subtensor::AdminFreezeWindow::::get(), pallet_subtensor::OwnerHyperparamRateLimit::::get(), dissolve_schedule_duration, pallet_subtensor::SubnetLimit::::get(), pallet_subtensor::TotalNetworks::::get(), pallet_subtensor::NetworkImmunityPeriod::::get(), pallet_subtensor::StartCallDelay::::get(), pallet_subtensor::NetworkMinLockCost::::get().to_u64(), pallet_subtensor::NetworkLastLockCost::::get().to_u64(), pallet_subtensor::NetworkLockReductionInterval::::get(), pallet_subtensor::SubnetOwnerCut::::get(), )); precompiles .prepare_test( caller, address, selector_u32("getGlobalRateLimits()").to_be_bytes().to_vec(), ) .with_static_call(true) .execute_returns(( pallet_subtensor::NetworkRateLimit::::get(), pallet_subtensor::WeightsVersionKeyRateLimit::::get(), pallet_subtensor::TxRateLimit::::get(), pallet_subtensor::TxDelegateTakeRateLimit::::get(), pallet_subtensor::TxChildkeyTakeRateLimit::::get(), pallet_subtensor::MaxEpochsPerBlock::::get(), )); precompiles .prepare_test( caller, address, selector_u32("getGlobalProtocolConfig()") .to_be_bytes() .to_vec(), ) .with_static_call(true) .execute_returns(( u8::from(pallet_subtensor::MaxMechanismCount::::get()), pallet_subtensor::CommitRevealWeightsVersion::::get(), pallet_subtensor::NetworkRegistrationStartBlock::::get(), pallet_subtensor::TaoInRefundDeploymentBlock::::get(), )); }); } #[test] fn added_admin_call_preserves_subnet_owner_authorization() { new_test_ext().execute_with(|| { let owner = addr_from_index(0x5010); let non_owner = addr_from_index(0x5011); let netuid = setup_owner_subnet(owner); let address = addr_from_index(SubnetPrecompile::::INDEX); let input = encode_with_selector( selector_u32("setBondsPenalty(uint16,uint16)"), (TEST_NETUID_U16, 123u16), ); precompiles::>() .prepare_test(owner, address, input.clone()) .execute_returns(()); assert_eq!(pallet_subtensor::BondsPenalty::::get(netuid), 123); let rejected = execute_precompile( &precompiles::>(), address, non_owner, input, U256::zero(), ); assert!(matches!(rejected, Some(Err(_)))); assert_eq!(pallet_subtensor::BondsPenalty::::get(netuid), 123); }); } }