From c55b22642e48310d01f37ae88092e15c204be39a Mon Sep 17 00:00:00 2001 From: JohnReedV <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 27 Jan 2025 17:58:53 -0800 Subject: [PATCH 01/12] add new fields to ChainIdentity and SubnetIdentity --- pallets/subtensor/rpc/src/lib.rs | 24 ++++ pallets/subtensor/runtime-api/src/lib.rs | 2 + pallets/subtensor/src/coinbase/root.rs | 6 +- pallets/subtensor/src/lib.rs | 65 ++++++++- pallets/subtensor/src/macros/dispatches.rs | 30 ++++- .../subtensor/src/migrations/migrate_rao.rs | 7 +- .../subtensor/src/rpc_info/dynamic_info.rs | 6 +- pallets/subtensor/src/rpc_info/metagraph.rs | 46 +++---- pallets/subtensor/src/rpc_info/subnet_info.rs | 97 ++++++++++++++ pallets/subtensor/src/subnets/subnet.rs | 4 +- pallets/subtensor/src/swap/swap_coldkey.rs | 4 +- pallets/subtensor/src/tests/serving.rs | 125 ++++++++++++++---- pallets/subtensor/src/tests/swap_coldkey.rs | 49 +++---- pallets/subtensor/src/utils/identity.rs | 31 +++-- runtime/src/lib.rs | 15 +++ 15 files changed, 410 insertions(+), 101 deletions(-) diff --git a/pallets/subtensor/rpc/src/lib.rs b/pallets/subtensor/rpc/src/lib.rs index cdbcebcacb..0df96eda65 100644 --- a/pallets/subtensor/rpc/src/lib.rs +++ b/pallets/subtensor/rpc/src/lib.rs @@ -49,6 +49,10 @@ pub trait SubtensorCustomApi { fn get_subnet_info_v2(&self, netuid: u16, at: Option) -> RpcResult>; #[method(name = "subnetInfo_getSubnetsInf_v2")] fn get_subnets_info_v2(&self, at: Option) -> RpcResult>; + #[method(name = "subnetInfo_getSubnetInfo_v3")] + fn get_subnet_info_v3(&self, netuid: u16, at: Option) -> RpcResult>; + #[method(name = "subnetInfo_getSubnetsInf_v3")] + fn get_subnets_info_v3(&self, at: Option) -> RpcResult>; #[method(name = "subnetInfo_getSubnetHyperparams")] fn get_subnet_hyperparams(&self, netuid: u16, at: Option) -> RpcResult>; #[method(name = "subnetInfo_getAllDynamicInfo")] @@ -298,6 +302,26 @@ where .map_err(|e| Error::RuntimeError(format!("Unable to get subnets info: {:?}", e)).into()) } + fn get_subnet_info_v3( + &self, + netuid: u16, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_subnet_info_v3(at, netuid) + .map_err(|e| Error::RuntimeError(format!("Unable to get subnet info: {:?}", e)).into()) + } + + fn get_subnets_info_v3(&self, at: Option<::Hash>) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_subnets_info_v3(at) + .map_err(|e| Error::RuntimeError(format!("Unable to get subnets info: {:?}", e)).into()) + } + fn get_network_lock_cost(&self, at: Option<::Hash>) -> RpcResult { let api = self.client.runtime_api(); let at = at.unwrap_or_else(|| self.client.info().best_hash); diff --git a/pallets/subtensor/runtime-api/src/lib.rs b/pallets/subtensor/runtime-api/src/lib.rs index cdcd6ed390..8a3e8aba94 100644 --- a/pallets/subtensor/runtime-api/src/lib.rs +++ b/pallets/subtensor/runtime-api/src/lib.rs @@ -23,6 +23,8 @@ sp_api::decl_runtime_apis! { fn get_subnets_info() -> Vec; fn get_subnet_info_v2(netuid: u16) -> Vec; fn get_subnets_info_v2() -> Vec; + fn get_subnet_info_v3(netuid: u16) -> Vec; + fn get_subnets_info_v3()-> Vec; fn get_subnet_hyperparams(netuid: u16) -> Vec; fn get_all_dynamic_info() -> Vec; fn get_all_metagraphs() -> Vec; diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index 3f83f934f1..5968a73761 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -479,7 +479,7 @@ impl Pallet { ); // --- 4. Remove the subnet identity if it exists. - if SubnetIdentities::::take(netuid).is_some() { + if SubnetIdentitiesV2::::take(netuid).is_some() { Self::deposit_event(Event::SubnetIdentityRemoved(netuid)); } @@ -590,8 +590,8 @@ impl Pallet { SubnetOwner::::remove(netuid); // --- 13. Remove subnet identity if it exists. - if SubnetIdentities::::contains_key(netuid) { - SubnetIdentities::::remove(netuid); + if SubnetIdentitiesV2::::contains_key(netuid) { + SubnetIdentitiesV2::::remove(netuid); Self::deposit_event(Event::SubnetIdentityRemoved(netuid)); } } diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 3fd67e0d8e..9f6844d8f5 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -189,10 +189,10 @@ pub mod pallet { pub ip_type: u8, } - /// Struct for ChainIdentities. + /// Struct for ChainIdentities. (DEPRECATED for V2) pub type ChainIdentityOf = ChainIdentity; - /// Data structure for Chain Identities. + /// Data structure for Chain Identities. (DEPRECATED for V2) #[crate::freeze_struct("bbfd00438dbe2b58")] #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)] pub struct ChainIdentity { @@ -210,9 +210,32 @@ pub mod pallet { pub additional: Vec, } - /// Struct for SubnetIdentities. + /// Struct for ChainIdentities. + pub type ChainIdentityOfV2 = ChainIdentityV2; + + /// Data structure for Chain Identities. + #[crate::freeze_struct("ad72a270be7b59d7")] + #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)] + pub struct ChainIdentityV2 { + /// The name of the chain identity + pub name: Vec, + /// The URL associated with the chain identity + pub url: Vec, + /// The github repository associated with the identity + pub github_repo: Vec, + /// The image representation of the chain identity + pub image: Vec, + /// The Discord information for the chain identity + pub discord: Vec, + /// A description of the chain identity + pub description: Vec, + /// Additional information about the chain identity + pub additional: Vec, + } + + /// Struct for SubnetIdentities. (DEPRECATED for V2) pub type SubnetIdentityOf = SubnetIdentity; - /// Data structure for Subnet Identities + /// Data structure for Subnet Identities. (DEPRECATED for V2) #[crate::freeze_struct("f448dc3dad763108")] #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)] pub struct SubnetIdentity { @@ -223,6 +246,28 @@ pub mod pallet { /// The subnet's contact pub subnet_contact: Vec, } + + /// Struct for SubnetIdentitiesV2. + pub type SubnetIdentityOfV2 = SubnetIdentityV2; + /// Data structure for Subnet Identities + #[crate::freeze_struct("e002be4cd05d7b3e")] + #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)] + pub struct SubnetIdentityV2 { + /// The name of the subnet + pub subnet_name: Vec, + /// The github repository associated with the subnet + pub github_repo: Vec, + /// The subnet's contact + pub subnet_contact: Vec, + /// The subnet's website + pub subnet_url: Vec, + /// The subnet's discord + pub discord: Vec, + /// The subnet's description + pub description: Vec, + /// Additional information about the subnet + pub additional: Vec, + } /// ============================ /// ==== Staking + Accounts ==== /// ============================ @@ -1398,14 +1443,22 @@ pub mod pallet { PrometheusInfoOf, OptionQuery, >; - #[pallet::storage] // --- MAP ( coldkey ) --> identity + #[pallet::storage] // --- MAP ( coldkey ) --> identity. (DEPRECATED for V2) pub type Identities = StorageMap<_, Blake2_128Concat, T::AccountId, ChainIdentityOf, OptionQuery>; - #[pallet::storage] // --- MAP ( netuid ) --> identity + #[pallet::storage] // --- MAP ( coldkey ) --> identity + pub type IdentitiesV2 = + StorageMap<_, Blake2_128Concat, T::AccountId, ChainIdentityOfV2, OptionQuery>; + + #[pallet::storage] // --- MAP ( netuid ) --> identity. (DEPRECATED for V2) pub type SubnetIdentities = StorageMap<_, Blake2_128Concat, u16, SubnetIdentityOf, OptionQuery>; + #[pallet::storage] // --- MAP ( netuid ) --> identityV2 + pub type SubnetIdentitiesV2 = + StorageMap<_, Blake2_128Concat, u16, SubnetIdentityOfV2, OptionQuery>; + /// ================================= /// ==== Axon / Promo Endpoints ===== /// ================================= diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index d9eafffa7a..b29db14c26 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1453,12 +1453,22 @@ mod dispatches { origin: OriginFor, name: Vec, url: Vec, + github_repo: Vec, image: Vec, discord: Vec, description: Vec, additional: Vec, ) -> DispatchResult { - Self::do_set_identity(origin, name, url, image, discord, description, additional) + Self::do_set_identity( + origin, + name, + url, + github_repo, + image, + discord, + description, + additional, + ) } /// ---- Set the identity information for a subnet. @@ -1487,8 +1497,22 @@ mod dispatches { subnet_name: Vec, github_repo: Vec, subnet_contact: Vec, + subnet_url: Vec, + discord: Vec, + description: Vec, + additional: Vec, ) -> DispatchResult { - Self::do_set_subnet_identity(origin, netuid, subnet_name, github_repo, subnet_contact) + Self::do_set_subnet_identity( + origin, + netuid, + subnet_name, + github_repo, + subnet_contact, + subnet_url, + discord, + description, + additional, + ) } /// User register a new subnetwork @@ -1499,7 +1523,7 @@ mod dispatches { pub fn register_network_with_identity( origin: OriginFor, hotkey: T::AccountId, - identity: Option, + identity: Option, ) -> DispatchResult { Self::do_register_network(origin, &hotkey, 1, identity) } diff --git a/pallets/subtensor/src/migrations/migrate_rao.rs b/pallets/subtensor/src/migrations/migrate_rao.rs index 3c034b7dad..6273b06c80 100644 --- a/pallets/subtensor/src/migrations/migrate_rao.rs +++ b/pallets/subtensor/src/migrations/migrate_rao.rs @@ -105,19 +105,20 @@ pub fn migrate_rao() -> Weight { let _neuron_uid: u16 = Pallet::::register_neuron(*netuid, &owner_coldkey); } // Register the neuron immediately. - if !Identities::::contains_key(owner_coldkey.clone()) { + if !IdentitiesV2::::contains_key(owner_coldkey.clone()) { // Set the identitiy for the Owner coldkey if non existent. - let identity = ChainIdentityOf { + let identity = ChainIdentityOfV2 { name: format!("Owner{}", netuid).as_bytes().to_vec(), url: Vec::new(), image: Vec::new(), + github_repo: Vec::new(), discord: Vec::new(), description: Vec::new(), additional: Vec::new(), }; // Validate the created identity and set it. if Pallet::::is_valid_identity(&identity) { - Identities::::insert(owner_coldkey.clone(), identity.clone()); + IdentitiesV2::::insert(owner_coldkey.clone(), identity.clone()); } } } diff --git a/pallets/subtensor/src/rpc_info/dynamic_info.rs b/pallets/subtensor/src/rpc_info/dynamic_info.rs index a8ffd85495..1ec021988f 100644 --- a/pallets/subtensor/src/rpc_info/dynamic_info.rs +++ b/pallets/subtensor/src/rpc_info/dynamic_info.rs @@ -4,7 +4,7 @@ use codec::Compact; use frame_support::pallet_prelude::{Decode, Encode}; use subtensor_macros::freeze_struct; -#[freeze_struct("44fd17b240416875")] +#[freeze_struct("e425055e357d7a13")] #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct DynamicInfo { netuid: Compact, @@ -25,7 +25,7 @@ pub struct DynamicInfo { pending_alpha_emission: Compact, pending_root_emission: Compact, network_registered_at: Compact, - subnet_identity: Option, + subnet_identity: Option, } impl Pallet { @@ -61,7 +61,7 @@ impl Pallet { pending_alpha_emission: PendingEmission::::get(netuid).into(), pending_root_emission: PendingRootDivs::::get(netuid).into(), network_registered_at: NetworkRegisteredAt::::get(netuid).into(), - subnet_identity: SubnetIdentities::::get(netuid), + subnet_identity: SubnetIdentitiesV2::::get(netuid), }) } pub fn get_all_dynamic_info() -> Vec>> { diff --git a/pallets/subtensor/src/rpc_info/metagraph.rs b/pallets/subtensor/src/rpc_info/metagraph.rs index 1e77e5fe6a..9415d193e1 100644 --- a/pallets/subtensor/src/rpc_info/metagraph.rs +++ b/pallets/subtensor/src/rpc_info/metagraph.rs @@ -6,7 +6,7 @@ use frame_support::pallet_prelude::{Decode, Encode}; use substrate_fixed::types::I64F64; use subtensor_macros::freeze_struct; -#[freeze_struct("bce2310daa502e48")] +#[freeze_struct("b80fd826ead2df2f")] #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct Metagraph { // Subnet index @@ -15,7 +15,7 @@ pub struct Metagraph { // Name and symbol name: Vec>, // name symbol: Vec>, // token symbol - identity: Option, // identity information. + identity: Option, // identity information. network_registered_at: Compact, // block at registration // Keys for owner. @@ -80,24 +80,24 @@ pub struct Metagraph { bonds_moving_avg: Compact, // Bonds moving avg // Metagraph info. - hotkeys: Vec, // hotkey per UID - coldkeys: Vec, // coldkey per UID - identities: Vec>, // coldkeys identities - axons: Vec, // UID axons. - active: Vec, // Avtive per UID - validator_permit: Vec, // Val permit per UID - pruning_score: Vec>, // Pruning per UID - last_update: Vec>, // Last update per UID - emission: Vec>, // Emission per UID - dividends: Vec>, // Dividends per UID - incentives: Vec>, // Mining incentives per UID - consensus: Vec>, // Consensus per UID - trust: Vec>, // Trust per UID - rank: Vec>, // Rank per UID - block_at_registration: Vec>, // Reg block per UID - alpha_stake: Vec>, // Alpha staked per UID - tao_stake: Vec>, // TAO staked per UID - total_stake: Vec>, // Total stake per UID + hotkeys: Vec, // hotkey per UID + coldkeys: Vec, // coldkey per UID + identities: Vec>, // coldkeys identities + axons: Vec, // UID axons. + active: Vec, // Avtive per UID + validator_permit: Vec, // Val permit per UID + pruning_score: Vec>, // Pruning per UID + last_update: Vec>, // Last update per UID + emission: Vec>, // Emission per UID + dividends: Vec>, // Dividends per UID + incentives: Vec>, // Mining incentives per UID + consensus: Vec>, // Consensus per UID + trust: Vec>, // Trust per UID + rank: Vec>, // Rank per UID + block_at_registration: Vec>, // Reg block per UID + alpha_stake: Vec>, // Alpha staked per UID + tao_stake: Vec>, // TAO staked per UID + total_stake: Vec>, // Total stake per UID // Dividend break down. tao_dividends_per_hotkey: Vec<(T::AccountId, Compact)>, // List of dividend payouts in tao via root. @@ -114,7 +114,7 @@ impl Pallet { let mut hotkeys: Vec = vec![]; let mut coldkeys: Vec = vec![]; let mut block_at_registration: Vec> = vec![]; - let mut identities: Vec> = vec![]; + let mut identities: Vec> = vec![]; let mut axons: Vec = vec![]; for uid in 0..n { let hotkey = Keys::::get(netuid, uid); @@ -122,7 +122,7 @@ impl Pallet { hotkeys.push(hotkey.clone()); coldkeys.push(coldkey.clone()); block_at_registration.push(BlockAtRegistration::::get(netuid, uid).into()); - identities.push(Identities::::get(coldkey.clone())); + identities.push(IdentitiesV2::::get(coldkey.clone())); axons.push(Self::get_axon_info(netuid, &hotkey)); } let mut tao_dividends_per_hotkey: Vec<(T::AccountId, Compact)> = vec![]; @@ -154,7 +154,7 @@ impl Pallet { .into_iter() .map(Compact) .collect(), // Symbol. - identity: SubnetIdentities::::get(netuid), // identity information. + identity: SubnetIdentitiesV2::::get(netuid), // identity information. network_registered_at: NetworkRegisteredAt::::get(netuid).into(), // block at registration // Keys for owner. diff --git a/pallets/subtensor/src/rpc_info/subnet_info.rs b/pallets/subtensor/src/rpc_info/subnet_info.rs index bdd420821a..5003ec5f63 100644 --- a/pallets/subtensor/src/rpc_info/subnet_info.rs +++ b/pallets/subtensor/src/rpc_info/subnet_info.rs @@ -51,6 +51,30 @@ pub struct SubnetInfov2 { identity: Option, } +#[freeze_struct("dd91200554b75bc4")] +#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] +pub struct SubnetInfov3 { + netuid: Compact, + rho: Compact, + kappa: Compact, + difficulty: Compact, + immunity_period: Compact, + max_allowed_validators: Compact, + min_allowed_weights: Compact, + max_weights_limit: Compact, + scaling_law_power: Compact, + subnetwork_n: Compact, + max_allowed_uids: Compact, + blocks_since_last_step: Compact, + tempo: Compact, + network_modality: Compact, + network_connect: Vec<[u16; 2]>, + emission_values: Compact, + burn: Compact, + owner: T::AccountId, + identity: Option, +} + #[freeze_struct("55b472510f10e76a")] #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct SubnetHyperparams { @@ -225,6 +249,79 @@ impl Pallet { subnets_info } + + pub fn get_subnet_info_v3(netuid: u16) -> Option> { + if !Self::if_subnet_exist(netuid) { + return None; + } + + let rho = Self::get_rho(netuid); + let kappa = Self::get_kappa(netuid); + let difficulty: Compact = Self::get_difficulty_as_u64(netuid).into(); + let immunity_period = Self::get_immunity_period(netuid); + let max_allowed_validators = Self::get_max_allowed_validators(netuid); + let min_allowed_weights = Self::get_min_allowed_weights(netuid); + let max_weights_limit = Self::get_max_weight_limit(netuid); + let scaling_law_power = Self::get_scaling_law_power(netuid); + let subnetwork_n = Self::get_subnetwork_n(netuid); + let max_allowed_uids = Self::get_max_allowed_uids(netuid); + let blocks_since_last_step = Self::get_blocks_since_last_step(netuid); + let tempo = Self::get_tempo(netuid); + let network_modality = >::get(netuid); + let emission_values = Self::get_emission_value(netuid); + let burn: Compact = Self::get_burn_as_u64(netuid).into(); + let identity: Option = SubnetIdentitiesV2::::get(netuid); + + // DEPRECATED + let network_connect: Vec<[u16; 2]> = Vec::<[u16; 2]>::new(); + // DEPRECATED for ( _netuid_, con_req) in < NetworkConnect as IterableStorageDoubleMap >::iter_prefix(netuid) { + // network_connect.push([_netuid_, con_req]); + // } + + Some(SubnetInfov3 { + rho: rho.into(), + kappa: kappa.into(), + difficulty, + immunity_period: immunity_period.into(), + netuid: netuid.into(), + max_allowed_validators: max_allowed_validators.into(), + min_allowed_weights: min_allowed_weights.into(), + max_weights_limit: max_weights_limit.into(), + scaling_law_power: scaling_law_power.into(), + subnetwork_n: subnetwork_n.into(), + max_allowed_uids: max_allowed_uids.into(), + blocks_since_last_step: blocks_since_last_step.into(), + tempo: tempo.into(), + network_modality: network_modality.into(), + network_connect, + emission_values: emission_values.into(), + burn, + owner: Self::get_subnet_owner(netuid), + identity, + }) + } + + pub fn get_subnets_info_v3() -> Vec>> { + let mut subnet_netuids = Vec::::new(); + let mut max_netuid: u16 = 0; + for (netuid, added) in as IterableStorageMap>::iter() { + if added { + subnet_netuids.push(netuid); + if netuid > max_netuid { + max_netuid = netuid; + } + } + } + + let mut subnets_info = Vec::>>::new(); + for netuid_ in 0..=max_netuid { + if subnet_netuids.contains(&netuid_) { + subnets_info.push(Self::get_subnet_info_v3(netuid_)); + } + } + + subnets_info + } pub fn get_subnet_hyperparams(netuid: u16) -> Option { if !Self::if_subnet_exist(netuid) { return None; diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index 942f6fe8ba..7a3b256327 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -160,7 +160,7 @@ impl Pallet { origin: T::RuntimeOrigin, hotkey: &T::AccountId, mechid: u16, - identity: Option, + identity: Option, ) -> DispatchResult { // --- 1. Ensure the caller is a signed user. let coldkey = ensure_signed(origin)?; @@ -260,7 +260,7 @@ impl Pallet { Error::::InvalidIdentity ); - SubnetIdentities::::insert(netuid_to_register, identity_value); + SubnetIdentitiesV2::::insert(netuid_to_register, identity_value); Self::deposit_event(Event::SubnetIdentitySet(netuid_to_register)); } diff --git a/pallets/subtensor/src/swap/swap_coldkey.rs b/pallets/subtensor/src/swap/swap_coldkey.rs index 075538421b..b505cd58e9 100644 --- a/pallets/subtensor/src/swap/swap_coldkey.rs +++ b/pallets/subtensor/src/swap/swap_coldkey.rs @@ -52,8 +52,8 @@ impl Pallet { weight = weight.saturating_add(T::DbWeight::get().reads(1)); // 5. Swap the identity if the old coldkey has one - if let Some(identity) = Identities::::take(old_coldkey) { - Identities::::insert(new_coldkey, identity); + if let Some(identity) = IdentitiesV2::::take(old_coldkey) { + IdentitiesV2::::insert(new_coldkey, identity); } // 6. Ensure sufficient balance for the swap cost diff --git a/pallets/subtensor/src/tests/serving.rs b/pallets/subtensor/src/tests/serving.rs index 32b604ba5a..f7ce4d6a2b 100644 --- a/pallets/subtensor/src/tests/serving.rs +++ b/pallets/subtensor/src/tests/serving.rs @@ -625,6 +625,7 @@ fn test_do_set_identity() { // Prepare identity data let name = b"Alice".to_vec(); let url = b"https://alice.com".to_vec(); + let git = b"https://github.com".to_vec(); let image = b"alice.jpg".to_vec(); let discord = b"alice#1234".to_vec(); let description = b"Alice's identity".to_vec(); @@ -635,6 +636,7 @@ fn test_do_set_identity() { <::RuntimeOrigin>::signed(coldkey), name.clone(), url.clone(), + git.clone(), image.clone(), discord.clone(), description.clone(), @@ -642,7 +644,7 @@ fn test_do_set_identity() { )); // Check if identity is set correctly - let stored_identity = Identities::::get(coldkey).expect("Identity should be set"); + let stored_identity = IdentitiesV2::::get(coldkey).expect("Identity should be set"); assert_eq!(stored_identity.name, name); assert_eq!(stored_identity.url, url); assert_eq!(stored_identity.image, image); @@ -657,6 +659,7 @@ fn test_do_set_identity() { <::RuntimeOrigin>::signed(coldkey_without_hotkey), name.clone(), url.clone(), + git.clone(), image.clone(), discord.clone(), description.clone(), @@ -672,6 +675,7 @@ fn test_do_set_identity() { <::RuntimeOrigin>::signed(coldkey), new_name.clone(), new_url.clone(), + git.clone(), image.clone(), discord.clone(), description.clone(), @@ -679,7 +683,7 @@ fn test_do_set_identity() { )); let updated_identity = - Identities::::get(coldkey).expect("Updated identity should be set"); + IdentitiesV2::::get(coldkey).expect("Updated identity should be set"); assert_eq!(updated_identity.name, new_name); assert_eq!(updated_identity.url, new_url); @@ -693,6 +697,7 @@ fn test_do_set_identity() { long_data.clone(), long_data.clone(), long_data.clone(), + long_data.clone(), long_data.clone() ), Error::::InvalidIdentity @@ -705,9 +710,10 @@ fn test_do_set_identity() { fn test_is_valid_identity() { new_test_ext(1).execute_with(|| { // Test valid identity - let valid_identity = ChainIdentity { + let valid_identity = ChainIdentityV2 { name: vec![0; 256], url: vec![0; 256], + github_repo: vec![0; 256], image: vec![0; 1024], discord: vec![0; 256], description: vec![0; 1024], @@ -716,9 +722,10 @@ fn test_is_valid_identity() { assert!(SubtensorModule::is_valid_identity(&valid_identity)); // Test identity with total length exactly at the maximum - let max_length_identity = ChainIdentity { + let max_length_identity = ChainIdentityV2 { name: vec![0; 256], url: vec![0; 256], + github_repo: vec![0; 256], image: vec![0; 1024], discord: vec![0; 256], description: vec![0; 1024], @@ -727,9 +734,10 @@ fn test_is_valid_identity() { assert!(SubtensorModule::is_valid_identity(&max_length_identity)); // Test identity with total length exceeding the maximum - let invalid_length_identity = ChainIdentity { + let invalid_length_identity = ChainIdentityV2 { name: vec![0; 257], url: vec![0; 256], + github_repo: vec![0; 256], image: vec![0; 1024], discord: vec![0; 256], description: vec![0; 1024], @@ -740,9 +748,10 @@ fn test_is_valid_identity() { )); // Test identity with one field exceeding its maximum - let invalid_field_identity = ChainIdentity { + let invalid_field_identity = ChainIdentityV2 { name: vec![0; 257], url: vec![0; 256], + github_repo: vec![0; 256], image: vec![0; 1024], discord: vec![0; 256], description: vec![0; 1024], @@ -751,9 +760,10 @@ fn test_is_valid_identity() { assert!(!SubtensorModule::is_valid_identity(&invalid_field_identity)); // Test identity with empty fields - let empty_identity = ChainIdentity { + let empty_identity = ChainIdentityV2 { name: vec![], url: vec![], + github_repo: vec![], image: vec![], discord: vec![], description: vec![], @@ -762,9 +772,10 @@ fn test_is_valid_identity() { assert!(SubtensorModule::is_valid_identity(&empty_identity)); // Test identity with some empty and some filled fields - let mixed_identity = ChainIdentity { + let mixed_identity = ChainIdentityV2 { name: b"Alice".to_vec(), url: b"https://alice.com".to_vec(), + github_repo: vec![], image: vec![], discord: b"alice#1234".to_vec(), description: vec![], @@ -773,9 +784,10 @@ fn test_is_valid_identity() { assert!(SubtensorModule::is_valid_identity(&mixed_identity)); // Test identity with all fields at maximum allowed length - let max_field_identity = ChainIdentity { + let max_field_identity = ChainIdentityV2 { name: vec![0; 256], url: vec![0; 256], + github_repo: vec![0; 256], image: vec![0; 1024], discord: vec![0; 256], description: vec![0; 1024], @@ -800,6 +812,7 @@ fn test_set_and_get_identity() { // Prepare identity data let name = b"Bob".to_vec(); let url = b"https://bob.com".to_vec(); + let git = b"https://github.com".to_vec(); let image = b"bob.jpg".to_vec(); let discord = b"bob#5678".to_vec(); let description = b"Bob's identity".to_vec(); @@ -810,6 +823,7 @@ fn test_set_and_get_identity() { <::RuntimeOrigin>::signed(coldkey), name.clone(), url.clone(), + git.clone(), image.clone(), discord.clone(), description.clone(), @@ -817,7 +831,7 @@ fn test_set_and_get_identity() { )); // Get and verify identity - let stored_identity = Identities::::get(coldkey).expect("Identity should be set"); + let stored_identity = IdentitiesV2::::get(coldkey).expect("Identity should be set"); assert_eq!(stored_identity.name, name); assert_eq!(stored_identity.url, url); assert_eq!(stored_identity.image, image); @@ -832,6 +846,7 @@ fn test_set_and_get_identity() { <::RuntimeOrigin>::signed(coldkey), new_name.clone(), new_url.clone(), + git.clone(), image.clone(), discord.clone(), description.clone(), @@ -840,7 +855,7 @@ fn test_set_and_get_identity() { // Get and verify updated identity let updated_identity = - Identities::::get(coldkey).expect("Updated identity should be set"); + IdentitiesV2::::get(coldkey).expect("Updated identity should be set"); assert_eq!(updated_identity.name, new_name); assert_eq!(updated_identity.url, new_url); assert_eq!(updated_identity.image, image); @@ -850,7 +865,7 @@ fn test_set_and_get_identity() { // Verify non-existent identity let non_existent_coldkey = U256::from(999); - assert!(Identities::::get(non_existent_coldkey).is_none()); + assert!(IdentitiesV2::::get(non_existent_coldkey).is_none()); }); } @@ -903,6 +918,10 @@ fn test_do_set_subnet_identity() { let subnet_name = b"Test Subnet".to_vec(); let github_repo = b"https://github.com/test/subnet".to_vec(); let subnet_contact = b"contact@testsubnet.com".to_vec(); + let subnet_url = b"subnet.com".to_vec(); + let discord = b"discord.com".to_vec(); + let description = b"I am the describer".to_vec(); + let additional = b"tao foreva".to_vec(); // Set subnet identity assert_ok!(SubtensorModule::do_set_subnet_identity( @@ -910,12 +929,16 @@ fn test_do_set_subnet_identity() { netuid, subnet_name.clone(), github_repo.clone(), - subnet_contact.clone() + subnet_contact.clone(), + subnet_url.clone(), + discord.clone(), + description.clone(), + additional.clone(), )); // Check if subnet identity is set correctly let stored_identity = - SubnetIdentities::::get(netuid).expect("Subnet identity should be set"); + SubnetIdentitiesV2::::get(netuid).expect("Subnet identity should be set"); assert_eq!(stored_identity.subnet_name, subnet_name); assert_eq!(stored_identity.github_repo, github_repo); assert_eq!(stored_identity.subnet_contact, subnet_contact); @@ -928,7 +951,11 @@ fn test_do_set_subnet_identity() { netuid, subnet_name.clone(), github_repo.clone(), - subnet_contact.clone() + subnet_contact.clone(), + subnet_url.clone(), + discord.clone(), + description.clone(), + additional.clone(), ), Error::::NotSubnetOwner ); @@ -941,11 +968,15 @@ fn test_do_set_subnet_identity() { netuid, new_subnet_name.clone(), new_github_repo.clone(), - subnet_contact.clone() + subnet_contact.clone(), + subnet_url.clone(), + discord.clone(), + description.clone(), + additional.clone(), )); let updated_identity = - SubnetIdentities::::get(netuid).expect("Updated subnet identity should be set"); + SubnetIdentitiesV2::::get(netuid).expect("Updated subnet identity should be set"); assert_eq!(updated_identity.subnet_name, new_subnet_name); assert_eq!(updated_identity.github_repo, new_github_repo); @@ -957,7 +988,11 @@ fn test_do_set_subnet_identity() { netuid, long_data.clone(), long_data.clone(), - long_data.clone() + long_data.clone(), + long_data.clone(), + long_data.clone(), + long_data.clone(), + long_data.clone(), ), Error::::InvalidIdentity ); @@ -969,56 +1004,80 @@ fn test_do_set_subnet_identity() { fn test_is_valid_subnet_identity() { new_test_ext(1).execute_with(|| { // Test valid subnet identity - let valid_identity = SubnetIdentity { + let valid_identity = SubnetIdentityV2 { subnet_name: vec![0; 256], github_repo: vec![0; 1024], subnet_contact: vec![0; 1024], + subnet_url: vec![0; 1024], + discord: vec![0; 256], + description: vec![0; 1024], + additional: vec![0; 1024], }; assert!(SubtensorModule::is_valid_subnet_identity(&valid_identity)); // Test subnet identity with total length exactly at the maximum - let max_length_identity = SubnetIdentity { + let max_length_identity = SubnetIdentityV2 { subnet_name: vec![0; 256], github_repo: vec![0; 1024], subnet_contact: vec![0; 1024], + subnet_url: vec![0; 1024], + discord: vec![0; 256], + description: vec![0; 1024], + additional: vec![0; 1024], }; assert!(SubtensorModule::is_valid_subnet_identity( &max_length_identity )); // Test subnet identity with total length exceeding the maximum - let invalid_length_identity = SubnetIdentity { + let invalid_length_identity = SubnetIdentityV2 { subnet_name: vec![0; 257], github_repo: vec![0; 1024], subnet_contact: vec![0; 1024], + subnet_url: vec![0; 1024], + discord: vec![0; 256], + description: vec![0; 1024], + additional: vec![0; 1024], }; assert!(!SubtensorModule::is_valid_subnet_identity( &invalid_length_identity )); // Test subnet identity with one field exceeding its maximum - let invalid_field_identity = SubnetIdentity { + let invalid_field_identity = SubnetIdentityV2 { subnet_name: vec![0; 257], github_repo: vec![0; 1024], subnet_contact: vec![0; 1024], + subnet_url: vec![0; 1024], + discord: vec![0; 256], + description: vec![0; 1024], + additional: vec![0; 1024], }; assert!(!SubtensorModule::is_valid_subnet_identity( &invalid_field_identity )); // Test subnet identity with empty fields - let empty_identity = SubnetIdentity { + let empty_identity = SubnetIdentityV2 { subnet_name: vec![], github_repo: vec![], subnet_contact: vec![], + subnet_url: vec![], + discord: vec![], + description: vec![], + additional: vec![], }; assert!(SubtensorModule::is_valid_subnet_identity(&empty_identity)); // Test subnet identity with some empty and some filled fields - let mixed_identity = SubnetIdentity { + let mixed_identity = SubnetIdentityV2 { subnet_name: b"Test Subnet".to_vec(), github_repo: vec![], subnet_contact: b"contact@testsubnet.com".to_vec(), + subnet_url: b"https://testsubnet.com".to_vec(), + discord: vec![], + description: b"A description".to_vec(), + additional: vec![], }; assert!(SubtensorModule::is_valid_subnet_identity(&mixed_identity)); }); @@ -1034,6 +1093,10 @@ fn test_set_identity_for_non_existent_subnet() { let subnet_name = b"Non-existent Subnet".to_vec(); let github_repo = b"https://github.com/test/nonexistent".to_vec(); let subnet_contact = b"contact@nonexistent.com".to_vec(); + let subnet_url = b"subnet.com".to_vec(); + let discord = b"discord.com".to_vec(); + let description = b"I am the describer".to_vec(); + let additional = b"tao foreva".to_vec(); // Attempt to set identity for a non-existent subnet assert_noop!( @@ -1042,7 +1105,11 @@ fn test_set_identity_for_non_existent_subnet() { netuid, subnet_name.clone(), github_repo.clone(), - subnet_contact.clone() + subnet_contact.clone(), + subnet_url.clone(), + discord.clone(), + description.clone(), + additional.clone(), ), Error::::NotSubnetOwner // Since there's no owner, it should fail ); @@ -1056,12 +1123,20 @@ fn test_set_subnet_identity_dispatch_info_ok() { let subnet_name: Vec = b"JesusSubnet".to_vec(); let github_repo: Vec = b"bible.com".to_vec(); let subnet_contact: Vec = b"https://www.vatican.va".to_vec(); + let subnet_url = b"subnet.com".to_vec(); + let discord = b"discord.com".to_vec(); + let description = b"I am the describer".to_vec(); + let additional = b"tao foreva".to_vec(); let call: RuntimeCall = RuntimeCall::SubtensorModule(SubtensorCall::set_subnet_identity { netuid, subnet_name, github_repo, subnet_contact, + subnet_url, + discord, + description, + additional, }); let dispatch_info: DispatchInfo = call.get_dispatch_info(); diff --git a/pallets/subtensor/src/tests/swap_coldkey.rs b/pallets/subtensor/src/tests/swap_coldkey.rs index f21af56cf9..7761005780 100644 --- a/pallets/subtensor/src/tests/swap_coldkey.rs +++ b/pallets/subtensor/src/tests/swap_coldkey.rs @@ -673,19 +673,20 @@ fn test_do_swap_coldkey_success() { // Insert an Identity let name: Vec = b"The fourth Coolest Identity".to_vec(); - let identity: ChainIdentity = ChainIdentity { + let identity: ChainIdentityV2 = ChainIdentityV2 { name: name.clone(), url: vec![], + github_repo: vec![], image: vec![], discord: vec![], description: vec![], additional: vec![], }; - Identities::::insert(old_coldkey, identity.clone()); + IdentitiesV2::::insert(old_coldkey, identity.clone()); - assert!(Identities::::get(old_coldkey).is_some()); - assert!(Identities::::get(new_coldkey).is_none()); + assert!(IdentitiesV2::::get(old_coldkey).is_some()); + assert!(IdentitiesV2::::get(new_coldkey).is_none()); // Log state after adding stake log::info!( @@ -774,10 +775,10 @@ fn test_do_swap_coldkey_success() { ); // Verify identities were swapped - assert!(Identities::::get(old_coldkey).is_none()); - assert!(Identities::::get(new_coldkey).is_some()); + assert!(IdentitiesV2::::get(old_coldkey).is_none()); + assert!(IdentitiesV2::::get(new_coldkey).is_some()); assert_eq!( - Identities::::get(new_coldkey).expect("Expected an Identity"), + IdentitiesV2::::get(new_coldkey).expect("Expected an Identity"), identity ); @@ -1887,19 +1888,20 @@ fn test_coldkey_swap_delegate_identity_updated() { )); let name: Vec = b"The Third Coolest Identity".to_vec(); - let identity: ChainIdentity = ChainIdentity { + let identity: ChainIdentityV2 = ChainIdentityV2 { name: name.clone(), url: vec![], image: vec![], + github_repo: vec![], discord: vec![], description: vec![], additional: vec![], }; - Identities::::insert(old_coldkey, identity.clone()); + IdentitiesV2::::insert(old_coldkey, identity.clone()); - assert!(Identities::::get(old_coldkey).is_some()); - assert!(Identities::::get(new_coldkey).is_none()); + assert!(IdentitiesV2::::get(old_coldkey).is_some()); + assert!(IdentitiesV2::::get(new_coldkey).is_none()); assert_ok!(SubtensorModule::do_swap_coldkey( &old_coldkey, @@ -1907,10 +1909,10 @@ fn test_coldkey_swap_delegate_identity_updated() { burn_cost )); - assert!(Identities::::get(old_coldkey).is_none()); - assert!(Identities::::get(new_coldkey).is_some()); + assert!(IdentitiesV2::::get(old_coldkey).is_none()); + assert!(IdentitiesV2::::get(new_coldkey).is_some()); assert_eq!( - Identities::::get(new_coldkey).expect("Expected an Identity"), + IdentitiesV2::::get(new_coldkey).expect("Expected an Identity"), identity ); }); @@ -1938,7 +1940,7 @@ fn test_coldkey_swap_no_identity_no_changes() { )); // Ensure the old coldkey does not have an identity before the swap - assert!(Identities::::get(old_coldkey).is_none()); + assert!(IdentitiesV2::::get(old_coldkey).is_none()); // Perform the coldkey swap assert_ok!(SubtensorModule::do_swap_coldkey( @@ -1948,8 +1950,8 @@ fn test_coldkey_swap_no_identity_no_changes() { )); // Ensure no identities have been changed - assert!(Identities::::get(old_coldkey).is_none()); - assert!(Identities::::get(new_coldkey).is_none()); + assert!(IdentitiesV2::::get(old_coldkey).is_none()); + assert!(IdentitiesV2::::get(new_coldkey).is_none()); }); } @@ -1974,19 +1976,20 @@ fn test_coldkey_swap_no_identity_no_changes_newcoldkey_exists() { )); let name: Vec = b"The Coolest Identity".to_vec(); - let identity: ChainIdentity = ChainIdentity { + let identity: ChainIdentityV2 = ChainIdentityV2 { name: name.clone(), url: vec![], + github_repo: vec![], image: vec![], discord: vec![], description: vec![], additional: vec![], }; - Identities::::insert(new_coldkey, identity.clone()); + IdentitiesV2::::insert(new_coldkey, identity.clone()); // Ensure the new coldkey does have an identity before the swap - assert!(Identities::::get(new_coldkey).is_some()); - assert!(Identities::::get(old_coldkey).is_none()); + assert!(IdentitiesV2::::get(new_coldkey).is_some()); + assert!(IdentitiesV2::::get(old_coldkey).is_none()); // Perform the coldkey swap assert_ok!(SubtensorModule::do_swap_coldkey( @@ -1996,8 +1999,8 @@ fn test_coldkey_swap_no_identity_no_changes_newcoldkey_exists() { )); // Ensure no identities have been changed - assert!(Identities::::get(old_coldkey).is_none()); - assert!(Identities::::get(new_coldkey).is_some()); + assert!(IdentitiesV2::::get(old_coldkey).is_none()); + assert!(IdentitiesV2::::get(new_coldkey).is_some()); }); } diff --git a/pallets/subtensor/src/utils/identity.rs b/pallets/subtensor/src/utils/identity.rs index 7babb04f4f..b721664f0f 100644 --- a/pallets/subtensor/src/utils/identity.rs +++ b/pallets/subtensor/src/utils/identity.rs @@ -27,6 +27,7 @@ impl Pallet { origin: T::RuntimeOrigin, name: Vec, url: Vec, + github_repo: Vec, image: Vec, discord: Vec, description: Vec, @@ -47,9 +48,10 @@ impl Pallet { ); // Create the identity struct with the provided information - let identity = ChainIdentityOf { + let identity = ChainIdentityOfV2 { name, url, + github_repo, image, discord, description, @@ -63,7 +65,7 @@ impl Pallet { ); // Store the validated identity in the blockchain state - Identities::::insert(coldkey.clone(), identity.clone()); + IdentitiesV2::::insert(coldkey.clone(), identity.clone()); // Log the identity set event log::debug!("ChainIdentitySet( coldkey:{:?} ) ", coldkey.clone()); @@ -98,6 +100,10 @@ impl Pallet { subnet_name: Vec, github_repo: Vec, subnet_contact: Vec, + subnet_url: Vec, + discord: Vec, + description: Vec, + additional: Vec, ) -> dispatch::DispatchResult { // Ensure the call is signed and get the signer's (coldkey) account let coldkey = ensure_signed(origin)?; @@ -109,10 +115,14 @@ impl Pallet { ); // Create the identity struct with the provided information - let identity: SubnetIdentityOf = SubnetIdentityOf { + let identity: SubnetIdentityOfV2 = SubnetIdentityOfV2 { subnet_name, github_repo, subnet_contact, + subnet_url, + discord, + description, + additional, }; // Validate the created identity @@ -122,7 +132,7 @@ impl Pallet { ); // Store the validated identity in the blockchain state - SubnetIdentities::::insert(netuid, identity.clone()); + SubnetIdentitiesV2::::insert(netuid, identity.clone()); // Log the identity set event log::info!("SubnetIdentitySet( netuid:{:?} ) ", netuid); @@ -147,7 +157,7 @@ impl Pallet { /// # Returns /// /// * `bool` - Returns true if the Identity is valid, false otherwise. - pub fn is_valid_identity(identity: &ChainIdentityOf) -> bool { + pub fn is_valid_identity(identity: &ChainIdentityOfV2) -> bool { let total_length = identity .name .len() @@ -157,9 +167,10 @@ impl Pallet { .saturating_add(identity.description.len()) .saturating_add(identity.additional.len()); - total_length <= 256 + 256 + 1024 + 256 + 1024 + 1024 + total_length <= 256 + 256 + 256 + 1024 + 256 + 1024 + 1024 && identity.name.len() <= 256 && identity.url.len() <= 256 + && identity.github_repo.len() <= 256 && identity.image.len() <= 1024 && identity.discord.len() <= 256 && identity.description.len() <= 1024 @@ -179,16 +190,20 @@ impl Pallet { /// # Returns /// /// * `bool` - Returns true if the SubnetIdentity is valid, false otherwise. - pub fn is_valid_subnet_identity(identity: &SubnetIdentityOf) -> bool { + pub fn is_valid_subnet_identity(identity: &SubnetIdentityOfV2) -> bool { let total_length = identity .subnet_name .len() .saturating_add(identity.github_repo.len()) .saturating_add(identity.subnet_contact.len()); - total_length <= 256 + 1024 + 1024 + total_length <= 256 + 1024 + 1024 + 1024 + 256 + 1024 + 1024 && identity.subnet_name.len() <= 256 && identity.github_repo.len() <= 1024 && identity.subnet_contact.len() <= 1024 + && identity.subnet_url.len() <= 1024 + && identity.discord.len() <= 256 + && identity.description.len() <= 1024 + && identity.additional.len() <= 1024 } } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 372c9a9815..74524e2a96 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -2096,6 +2096,21 @@ impl_runtime_apis! { result.encode() } + fn get_subnet_info_v3(netuid: u16) -> Vec { + let _result = SubtensorModule::get_subnet_info_v3(netuid); + if _result.is_some() { + let result = _result.expect("Could not get SubnetInfo"); + result.encode() + } else { + vec![] + } + } + + fn get_subnets_info_v3() -> Vec { + let result = SubtensorModule::get_subnets_info_v3(); + result.encode() + } + fn get_subnet_hyperparams(netuid: u16) -> Vec { let _result = SubtensorModule::get_subnet_hyperparams(netuid); if _result.is_some() { From 0c5eaecf59f485a38b56bb9bb022da2dbe829729 Mon Sep 17 00:00:00 2001 From: JohnReedV <87283488+JohnReedV@users.noreply.github.com> Date: Tue, 28 Jan 2025 09:52:06 -0800 Subject: [PATCH 02/12] add migration and test --- pallets/subtensor/src/macros/hooks.rs | 4 +- .../src/migrations/migrate_identities_v2.rs | 91 ++++++++++++++ pallets/subtensor/src/migrations/mod.rs | 1 + pallets/subtensor/src/tests/serving.rs | 112 ++++++++++++++++++ 4 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 pallets/subtensor/src/migrations/migrate_identities_v2.rs diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index 2a43238ab3..d3b08c51ac 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -76,7 +76,9 @@ mod hooks { // Migrate to RAO .saturating_add(migrations::migrate_rao::migrate_rao::()) // Fix the IsNetworkMember map to be consistent with other storage maps - .saturating_add(migrations::migrate_fix_is_network_member::migrate_fix_is_network_member::()); + .saturating_add(migrations::migrate_fix_is_network_member::migrate_fix_is_network_member::()) + // Upgrade identities to V2 + .saturating_add(migrations::migrate_identities_v2::migrate_identities_to_v2::()); weight } diff --git a/pallets/subtensor/src/migrations/migrate_identities_v2.rs b/pallets/subtensor/src/migrations/migrate_identities_v2.rs new file mode 100644 index 0000000000..505b617b2f --- /dev/null +++ b/pallets/subtensor/src/migrations/migrate_identities_v2.rs @@ -0,0 +1,91 @@ +use super::*; +use frame_support::weights::Weight; +use log; +use scale_info::prelude::{string::String, vec::Vec}; + +pub fn migrate_identities_to_v2() -> Weight { + use frame_support::traits::Get; + let migration_name = b"migrate_identities_to_v2".to_vec(); + + // Start counting weight + let mut weight = T::DbWeight::get().reads(1); + + // Check if we already ran this migration + if HasMigrationRun::::get(&migration_name) { + log::info!( + target: "runtime", + "Migration '{:?}' has already run. Skipping.", + String::from_utf8_lossy(&migration_name) + ); + return weight; + } + + log::info!( + target: "runtime", + "Running migration '{}'", + String::from_utf8_lossy(&migration_name) + ); + + // ----------------------------- + // 1) Migrate Chain Identities + // ----------------------------- + let old_identities = Identities::::iter().collect::>(); + for (account_id, old_identity) in old_identities.clone() { + let new_identity = ChainIdentityV2 { + name: old_identity.name, + url: old_identity.url, + github_repo: Vec::new(), + image: old_identity.image, + discord: old_identity.discord, + description: old_identity.description, + additional: old_identity.additional, + }; + + // Insert into the new storage map + IdentitiesV2::::insert(&account_id, &new_identity); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); + + Identities::::remove(&account_id); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); + } + + weight = weight.saturating_add(T::DbWeight::get().reads(old_identities.len() as u64)); + + // ----------------------------- + // 2) Migrate Subnet Identities + // ----------------------------- + let old_subnet_identities = SubnetIdentities::::iter().collect::>(); + for (netuid, old_subnet_identity) in old_subnet_identities.clone() { + let new_subnet_identity = SubnetIdentityV2 { + subnet_name: old_subnet_identity.subnet_name, + github_repo: old_subnet_identity.github_repo, + subnet_contact: old_subnet_identity.subnet_contact, + subnet_url: Vec::new(), + discord: Vec::new(), + description: Vec::new(), + additional: Vec::new(), + }; + + // Insert into the new storage map + SubnetIdentitiesV2::::insert(netuid, &new_subnet_identity); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); + + SubnetIdentities::::remove(netuid); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); + } + weight = weight.saturating_add(T::DbWeight::get().reads(old_subnet_identities.len() as u64)); + + // ----------------------------- + // Mark the migration as done + // ----------------------------- + HasMigrationRun::::insert(&migration_name, true); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); + + log::info!( + target: "runtime", + "Migration '{}' completed successfully.", + String::from_utf8_lossy(&migration_name) + ); + + weight +} diff --git a/pallets/subtensor/src/migrations/mod.rs b/pallets/subtensor/src/migrations/mod.rs index 6cf358c4db..5af200d62f 100644 --- a/pallets/subtensor/src/migrations/mod.rs +++ b/pallets/subtensor/src/migrations/mod.rs @@ -6,6 +6,7 @@ pub mod migrate_delete_subnet_21; pub mod migrate_delete_subnet_3; pub mod migrate_fix_is_network_member; pub mod migrate_fix_total_coldkey_stake; +pub mod migrate_identities_v2; pub mod migrate_init_total_issuance; pub mod migrate_populate_owned_hotkeys; pub mod migrate_populate_staking_hotkeys; diff --git a/pallets/subtensor/src/tests/serving.rs b/pallets/subtensor/src/tests/serving.rs index f7ce4d6a2b..52b8f8b08f 100644 --- a/pallets/subtensor/src/tests/serving.rs +++ b/pallets/subtensor/src/tests/serving.rs @@ -899,6 +899,118 @@ fn test_migrate_set_hotkey_identities() { }); } +#[test] +fn test_migrate_identities_to_v2() { + new_test_ext(1).execute_with(|| { + let account_id_1 = U256::from(1); + let account_id_2 = U256::from(2); + + let chainone_name = b"ChainOne".to_vec(); + let chainone_url = b"https://chainone.example".to_vec(); + let chainone_image = b"some_image_data".to_vec(); + let chainone_discord = b"discord#1".to_vec(); + let chainone_description = b"Old chain identity".to_vec(); + let chainone_additional = b"extra-info".to_vec(); + + let chaintwo_name = b"ChainTwo".to_vec(); + let chaintwo_url = b"https://chaintwo.example".to_vec(); + let chaintwo_description = b"Another chain identity".to_vec(); + + Identities::::insert( + account_id_1, + ChainIdentity { + name: chainone_name.clone(), + url: chainone_url.clone(), + image: chainone_image.clone(), + discord: chainone_discord.clone(), + description: chainone_description.clone(), + additional: chainone_additional.clone(), + }, + ); + + Identities::::insert( + account_id_2, + ChainIdentity { + name: chaintwo_name.clone(), + url: chaintwo_url.clone(), + image: b"".to_vec(), + discord: b"".to_vec(), + description: chaintwo_description.clone(), + additional: b"".to_vec(), + }, + ); + + let old_subnet_name = b"SubnetExample".to_vec(); + let old_github_repo = b"https://github.com/org/repo".to_vec(); + let old_subnet_contact = b"subnet@example".to_vec(); + + SubnetIdentities::::insert( + 42u16, + SubnetIdentity { + subnet_name: old_subnet_name.clone(), + github_repo: old_github_repo.clone(), + subnet_contact: old_subnet_contact.clone(), + }, + ); + + assert!(Identities::::get(account_id_1).is_some()); + assert!(Identities::::get(account_id_2).is_some()); + assert!(SubnetIdentities::::get(42u16).is_some()); + assert!(!HasMigrationRun::::get( + b"migrate_identities_to_v2".to_vec() + )); + + let weight = crate::migrations::migrate_identities_v2::migrate_identities_to_v2::(); + + assert!( + HasMigrationRun::::get(b"migrate_identities_to_v2".to_vec()), + "Expected HasMigrationRun to be true after migration" + ); + assert!(Identities::::get(account_id_1).is_none()); + assert!(Identities::::get(account_id_2).is_none()); + assert!(SubnetIdentities::::get(42u16).is_none()); + + let new_identity_1 = IdentitiesV2::::get(account_id_1) + .expect("ChainOne should be migrated to IdentitiesV2"); + let expected_github_repo = b"".to_vec(); + + assert_eq!(new_identity_1.name, chainone_name); + assert_eq!(new_identity_1.url, chainone_url); + assert_eq!(new_identity_1.github_repo, expected_github_repo); + assert_eq!(new_identity_1.image, chainone_image); + assert_eq!(new_identity_1.discord, chainone_discord); + assert_eq!(new_identity_1.description, chainone_description); + assert_eq!(new_identity_1.additional, chainone_additional); + + let new_identity_2 = IdentitiesV2::::get(account_id_2) + .expect("ChainTwo should be migrated to IdentitiesV2"); + assert_eq!(new_identity_2.name, chaintwo_name); + assert_eq!(new_identity_2.url, chaintwo_url); + assert_eq!(new_identity_2.github_repo, b"".to_vec()); + + let new_subnet_identity = SubnetIdentitiesV2::::get(42u16) + .expect("SubnetExample should be migrated to SubnetIdentitiesV2"); + + let expected_subnet_url = b"".to_vec(); + let expected_discord = b"".to_vec(); + let expected_description = b"".to_vec(); + let expected_additional = b"".to_vec(); + + assert_eq!(new_subnet_identity.subnet_name, old_subnet_name); + assert_eq!(new_subnet_identity.github_repo, old_github_repo); + assert_eq!(new_subnet_identity.subnet_contact, old_subnet_contact); + assert_eq!(new_subnet_identity.subnet_url, expected_subnet_url); + assert_eq!(new_subnet_identity.discord, expected_discord); + assert_eq!(new_subnet_identity.description, expected_description); + assert_eq!(new_subnet_identity.additional, expected_additional); + + assert!( + weight != Weight::zero(), + "Migration weight should be non-zero" + ); + }); +} + // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test serving -- test_do_set_subnet_identity --exact --nocapture #[test] fn test_do_set_subnet_identity() { From ea96beca7a0c347f0b68835857df2598232b9e8d Mon Sep 17 00:00:00 2001 From: JohnReedV <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 3 Feb 2025 09:22:48 -0800 Subject: [PATCH 03/12] address freeze_struct --- pallets/subtensor/src/rpc_info/dynamic_info.rs | 2 +- pallets/subtensor/src/rpc_info/metagraph.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/rpc_info/dynamic_info.rs b/pallets/subtensor/src/rpc_info/dynamic_info.rs index 213fc7654a..554e79eef8 100644 --- a/pallets/subtensor/src/rpc_info/dynamic_info.rs +++ b/pallets/subtensor/src/rpc_info/dynamic_info.rs @@ -4,7 +4,7 @@ use codec::Compact; use frame_support::pallet_prelude::{Decode, Encode}; use subtensor_macros::freeze_struct; -#[freeze_struct("e425055e357d7a13")] +#[freeze_struct("66f29110b41779af")] #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct DynamicInfo { netuid: Compact, diff --git a/pallets/subtensor/src/rpc_info/metagraph.rs b/pallets/subtensor/src/rpc_info/metagraph.rs index 33fde563c9..b4238f601f 100644 --- a/pallets/subtensor/src/rpc_info/metagraph.rs +++ b/pallets/subtensor/src/rpc_info/metagraph.rs @@ -6,7 +6,7 @@ use frame_support::pallet_prelude::{Decode, Encode}; use substrate_fixed::types::I64F64; use subtensor_macros::freeze_struct; -#[freeze_struct("b80fd826ead2df2f")] +#[freeze_struct("66f29110b41779af")] #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct Metagraph { // Subnet index From a7232b06fa624a5105cbf23584d5c185bfa121df Mon Sep 17 00:00:00 2001 From: JohnReedV <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 3 Feb 2025 09:27:26 -0800 Subject: [PATCH 04/12] rename commit_reveal_period --- pallets/subtensor/src/rpc_info/subnet_info.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pallets/subtensor/src/rpc_info/subnet_info.rs b/pallets/subtensor/src/rpc_info/subnet_info.rs index 5003ec5f63..2ced07a1b5 100644 --- a/pallets/subtensor/src/rpc_info/subnet_info.rs +++ b/pallets/subtensor/src/rpc_info/subnet_info.rs @@ -75,7 +75,7 @@ pub struct SubnetInfov3 { identity: Option, } -#[freeze_struct("55b472510f10e76a")] +#[freeze_struct("a2dd2fcd6f4d4ff8")] #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct SubnetHyperparams { rho: Compact, @@ -100,7 +100,7 @@ pub struct SubnetHyperparams { max_validators: Compact, adjustment_alpha: Compact, difficulty: Compact, - commit_reveal_weights_interval: Compact, + commit_reveal_period: Compact, commit_reveal_weights_enabled: bool, alpha_high: Compact, alpha_low: Compact, @@ -377,7 +377,7 @@ impl Pallet { max_validators: max_validators.into(), adjustment_alpha: adjustment_alpha.into(), difficulty: difficulty.into(), - commit_reveal_weights_interval: commit_reveal_periods.into(), + commit_reveal_period: commit_reveal_periods.into(), commit_reveal_weights_enabled, alpha_high: alpha_high.into(), alpha_low: alpha_low.into(), From 12f483c2e7e7a00a5f84660ba769475c2e4b149b Mon Sep 17 00:00:00 2001 From: JohnReedV <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 3 Feb 2025 10:01:33 -0800 Subject: [PATCH 05/12] remove subnet_info_v3 --- pallets/subtensor/rpc/src/lib.rs | 24 ------ pallets/subtensor/runtime-api/src/lib.rs | 2 - pallets/subtensor/src/rpc_info/subnet_info.rs | 78 +------------------ runtime/src/lib.rs | 15 ---- 4 files changed, 3 insertions(+), 116 deletions(-) diff --git a/pallets/subtensor/rpc/src/lib.rs b/pallets/subtensor/rpc/src/lib.rs index 0df96eda65..cdbcebcacb 100644 --- a/pallets/subtensor/rpc/src/lib.rs +++ b/pallets/subtensor/rpc/src/lib.rs @@ -49,10 +49,6 @@ pub trait SubtensorCustomApi { fn get_subnet_info_v2(&self, netuid: u16, at: Option) -> RpcResult>; #[method(name = "subnetInfo_getSubnetsInf_v2")] fn get_subnets_info_v2(&self, at: Option) -> RpcResult>; - #[method(name = "subnetInfo_getSubnetInfo_v3")] - fn get_subnet_info_v3(&self, netuid: u16, at: Option) -> RpcResult>; - #[method(name = "subnetInfo_getSubnetsInf_v3")] - fn get_subnets_info_v3(&self, at: Option) -> RpcResult>; #[method(name = "subnetInfo_getSubnetHyperparams")] fn get_subnet_hyperparams(&self, netuid: u16, at: Option) -> RpcResult>; #[method(name = "subnetInfo_getAllDynamicInfo")] @@ -302,26 +298,6 @@ where .map_err(|e| Error::RuntimeError(format!("Unable to get subnets info: {:?}", e)).into()) } - fn get_subnet_info_v3( - &self, - netuid: u16, - at: Option<::Hash>, - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = at.unwrap_or_else(|| self.client.info().best_hash); - - api.get_subnet_info_v3(at, netuid) - .map_err(|e| Error::RuntimeError(format!("Unable to get subnet info: {:?}", e)).into()) - } - - fn get_subnets_info_v3(&self, at: Option<::Hash>) -> RpcResult> { - let api = self.client.runtime_api(); - let at = at.unwrap_or_else(|| self.client.info().best_hash); - - api.get_subnets_info_v3(at) - .map_err(|e| Error::RuntimeError(format!("Unable to get subnets info: {:?}", e)).into()) - } - fn get_network_lock_cost(&self, at: Option<::Hash>) -> RpcResult { let api = self.client.runtime_api(); let at = at.unwrap_or_else(|| self.client.info().best_hash); diff --git a/pallets/subtensor/runtime-api/src/lib.rs b/pallets/subtensor/runtime-api/src/lib.rs index 75d0916dd0..31f351aeb6 100644 --- a/pallets/subtensor/runtime-api/src/lib.rs +++ b/pallets/subtensor/runtime-api/src/lib.rs @@ -23,8 +23,6 @@ sp_api::decl_runtime_apis! { fn get_subnets_info() -> Vec; fn get_subnet_info_v2(netuid: u16) -> Vec; fn get_subnets_info_v2() -> Vec; - fn get_subnet_info_v3(netuid: u16) -> Vec; - fn get_subnets_info_v3()-> Vec; fn get_subnet_hyperparams(netuid: u16) -> Vec; fn get_all_dynamic_info() -> Vec; fn get_all_metagraphs() -> Vec; diff --git a/pallets/subtensor/src/rpc_info/subnet_info.rs b/pallets/subtensor/src/rpc_info/subnet_info.rs index 2ced07a1b5..65851d36cf 100644 --- a/pallets/subtensor/src/rpc_info/subnet_info.rs +++ b/pallets/subtensor/src/rpc_info/subnet_info.rs @@ -27,7 +27,7 @@ pub struct SubnetInfo { owner: T::AccountId, } -#[freeze_struct("65f931972fa13222")] +#[freeze_struct("c46dc4e2d4d9f8a3")] #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct SubnetInfov2 { netuid: Compact, @@ -48,7 +48,7 @@ pub struct SubnetInfov2 { emission_values: Compact, burn: Compact, owner: T::AccountId, - identity: Option, + identity: Option, } #[freeze_struct("dd91200554b75bc4")] @@ -198,7 +198,7 @@ impl Pallet { let network_modality = >::get(netuid); let emission_values = Self::get_emission_value(netuid); let burn: Compact = Self::get_burn_as_u64(netuid).into(); - let identity: Option = SubnetIdentities::::get(netuid); + let identity: Option = SubnetIdentitiesV2::::get(netuid); // DEPRECATED let network_connect: Vec<[u16; 2]> = Vec::<[u16; 2]>::new(); @@ -250,78 +250,6 @@ impl Pallet { subnets_info } - pub fn get_subnet_info_v3(netuid: u16) -> Option> { - if !Self::if_subnet_exist(netuid) { - return None; - } - - let rho = Self::get_rho(netuid); - let kappa = Self::get_kappa(netuid); - let difficulty: Compact = Self::get_difficulty_as_u64(netuid).into(); - let immunity_period = Self::get_immunity_period(netuid); - let max_allowed_validators = Self::get_max_allowed_validators(netuid); - let min_allowed_weights = Self::get_min_allowed_weights(netuid); - let max_weights_limit = Self::get_max_weight_limit(netuid); - let scaling_law_power = Self::get_scaling_law_power(netuid); - let subnetwork_n = Self::get_subnetwork_n(netuid); - let max_allowed_uids = Self::get_max_allowed_uids(netuid); - let blocks_since_last_step = Self::get_blocks_since_last_step(netuid); - let tempo = Self::get_tempo(netuid); - let network_modality = >::get(netuid); - let emission_values = Self::get_emission_value(netuid); - let burn: Compact = Self::get_burn_as_u64(netuid).into(); - let identity: Option = SubnetIdentitiesV2::::get(netuid); - - // DEPRECATED - let network_connect: Vec<[u16; 2]> = Vec::<[u16; 2]>::new(); - // DEPRECATED for ( _netuid_, con_req) in < NetworkConnect as IterableStorageDoubleMap >::iter_prefix(netuid) { - // network_connect.push([_netuid_, con_req]); - // } - - Some(SubnetInfov3 { - rho: rho.into(), - kappa: kappa.into(), - difficulty, - immunity_period: immunity_period.into(), - netuid: netuid.into(), - max_allowed_validators: max_allowed_validators.into(), - min_allowed_weights: min_allowed_weights.into(), - max_weights_limit: max_weights_limit.into(), - scaling_law_power: scaling_law_power.into(), - subnetwork_n: subnetwork_n.into(), - max_allowed_uids: max_allowed_uids.into(), - blocks_since_last_step: blocks_since_last_step.into(), - tempo: tempo.into(), - network_modality: network_modality.into(), - network_connect, - emission_values: emission_values.into(), - burn, - owner: Self::get_subnet_owner(netuid), - identity, - }) - } - - pub fn get_subnets_info_v3() -> Vec>> { - let mut subnet_netuids = Vec::::new(); - let mut max_netuid: u16 = 0; - for (netuid, added) in as IterableStorageMap>::iter() { - if added { - subnet_netuids.push(netuid); - if netuid > max_netuid { - max_netuid = netuid; - } - } - } - - let mut subnets_info = Vec::>>::new(); - for netuid_ in 0..=max_netuid { - if subnet_netuids.contains(&netuid_) { - subnets_info.push(Self::get_subnet_info_v3(netuid_)); - } - } - - subnets_info - } pub fn get_subnet_hyperparams(netuid: u16) -> Option { if !Self::if_subnet_exist(netuid) { return None; diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 85aa209938..d9c4fcd99d 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -2096,21 +2096,6 @@ impl_runtime_apis! { result.encode() } - fn get_subnet_info_v3(netuid: u16) -> Vec { - let _result = SubtensorModule::get_subnet_info_v3(netuid); - if _result.is_some() { - let result = _result.expect("Could not get SubnetInfo"); - result.encode() - } else { - vec![] - } - } - - fn get_subnets_info_v3() -> Vec { - let result = SubtensorModule::get_subnets_info_v3(); - result.encode() - } - fn get_subnet_hyperparams(netuid: u16) -> Vec { let _result = SubtensorModule::get_subnet_hyperparams(netuid); if _result.is_some() { From ea136bb6ddb1d43b622a44888d0bb774d1161391 Mon Sep 17 00:00:00 2001 From: JohnReedV <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 3 Feb 2025 10:10:30 -0800 Subject: [PATCH 06/12] address lint --- pallets/subtensor/src/rpc_info/dynamic_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/rpc_info/dynamic_info.rs b/pallets/subtensor/src/rpc_info/dynamic_info.rs index 554e79eef8..4046246be6 100644 --- a/pallets/subtensor/src/rpc_info/dynamic_info.rs +++ b/pallets/subtensor/src/rpc_info/dynamic_info.rs @@ -4,7 +4,7 @@ use codec::Compact; use frame_support::pallet_prelude::{Decode, Encode}; use subtensor_macros::freeze_struct; -#[freeze_struct("66f29110b41779af")] +#[freeze_struct("6f2a966922016f51")] #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct DynamicInfo { netuid: Compact, From 2d32d96b3b2157d4ce11f55068ab95824e4b52e8 Mon Sep 17 00:00:00 2001 From: JohnReedV <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 3 Feb 2025 10:32:22 -0800 Subject: [PATCH 07/12] update register_network with identity precompile --- runtime/src/precompiles/subnet.rs | 181 ++++++++++++++++++++++++++++-- 1 file changed, 172 insertions(+), 9 deletions(-) diff --git a/runtime/src/precompiles/subnet.rs b/runtime/src/precompiles/subnet.rs index 9944572c51..d62a0efd04 100644 --- a/runtime/src/precompiles/subnet.rs +++ b/runtime/src/precompiles/subnet.rs @@ -5,8 +5,8 @@ use pallet_evm::{ AddressMapping, ExitError, HashedAddressMapping, PrecompileFailure, PrecompileHandle, PrecompileResult, }; -use sp_runtime::traits::BlakeTwo256; use sp_runtime::AccountId32; +use sp_runtime::{traits::BlakeTwo256, Vec}; use sp_std::vec; pub const SUBNET_PRECOMPILE_INDEX: u64 = 2051; // bytes with max lenght 1K @@ -62,14 +62,26 @@ impl SubnetPrecompile { ) } 33.. => { - let (hotkey, subnet_name, github_repo, subnet_contact) = - Self::parse_register_network_parameters(data)?; + let ( + hotkey, + subnet_name, + github_repo, + subnet_contact, + subnet_url, + discord, + description, + additional, + ) = Self::parse_register_network_parameters(data)?; - let identity: pallet_subtensor::SubnetIdentityOf = - pallet_subtensor::SubnetIdentityOf { + let identity: pallet_subtensor::SubnetIdentityOfV2 = + pallet_subtensor::SubnetIdentityOfV2 { subnet_name, github_repo, subnet_contact, + subnet_url, + discord, + description, + additional, }; // Create the register_network callcle @@ -98,12 +110,24 @@ impl SubnetPrecompile { fn parse_register_network_parameters( data: &[u8], - ) -> Result<(AccountId32, vec::Vec, vec::Vec, vec::Vec), PrecompileFailure> { + ) -> Result< + ( + AccountId32, + Vec, + Vec, + Vec, + Vec, + Vec, + Vec, + Vec, + ), + PrecompileFailure, + > { let (pubkey, dynamic_params) = get_pubkey(data)?; let dynamic_data_len = dynamic_params.len(); let mut buf = [0_u8; 4]; - // get all start point for three data items: name, repo and contact + // get all start points for the data items: name, repo, contact, url, discord, description, additional buf.copy_from_slice(get_slice(data, 60, 64)?); let subnet_name_start: usize = u32::from_be_bytes(buf) as usize; if subnet_name_start > dynamic_data_len { @@ -140,6 +164,54 @@ impl SubnetPrecompile { }); } + buf.copy_from_slice(get_slice(data, 156, 160)?); + let subnet_url_start: usize = u32::from_be_bytes(buf) as usize; + if subnet_url_start > dynamic_data_len { + log::error!( + "the start position of subnet_url as {} is too big ", + subnet_url_start + ); + return Err(PrecompileFailure::Error { + exit_status: ExitError::InvalidRange, + }); + } + + buf.copy_from_slice(get_slice(data, 188, 192)?); + let discord_start: usize = u32::from_be_bytes(buf) as usize; + if discord_start > dynamic_data_len { + log::error!( + "the start position of discord as {} is too big ", + discord_start + ); + return Err(PrecompileFailure::Error { + exit_status: ExitError::InvalidRange, + }); + } + + buf.copy_from_slice(get_slice(data, 220, 224)?); + let description_start: usize = u32::from_be_bytes(buf) as usize; + if description_start > dynamic_data_len { + log::error!( + "the start position of description as {} is too big ", + description_start + ); + return Err(PrecompileFailure::Error { + exit_status: ExitError::InvalidRange, + }); + } + + buf.copy_from_slice(get_slice(data, 252, 256)?); + let additional_start: usize = u32::from_be_bytes(buf) as usize; + if additional_start > dynamic_data_len { + log::error!( + "the start position of additional as {} is too big ", + additional_start + ); + return Err(PrecompileFailure::Error { + exit_status: ExitError::InvalidRange, + }); + } + // get name buf.copy_from_slice(get_slice( data, @@ -149,7 +221,10 @@ impl SubnetPrecompile { let subnet_name_len: usize = u32::from_be_bytes(buf) as usize; if subnet_name_len > MAX_SINGLE_PARAMETER_SIZE { - log::error!("the length of subnet nae as {} is too big", subnet_name_len); + log::error!( + "the length of subnet name as {} is too big", + subnet_name_len + ); return Err(PrecompileFailure::Error { exit_status: ExitError::InvalidRange, }); @@ -210,6 +285,94 @@ impl SubnetPrecompile { subnet_contact_start + subnet_contact_len + 32, )?); - Ok((pubkey, name_vec, repo_vec, contact_vec)) + // get subnet_url + buf.copy_from_slice(get_slice( + data, + subnet_url_start + 28, + subnet_url_start + 32, + )?); + let subnet_url_len: usize = u32::from_be_bytes(buf) as usize; + if subnet_url_len > MAX_SINGLE_PARAMETER_SIZE { + log::error!("the length of subnet_url as {} is too big", subnet_url_len); + return Err(PrecompileFailure::Error { + exit_status: ExitError::InvalidRange, + }); + } + let mut url_vec = vec![0; subnet_url_len]; + url_vec.copy_from_slice(get_slice( + data, + subnet_url_start + 32, + subnet_url_start + subnet_url_len + 32, + )?); + + // get discord + buf.copy_from_slice(get_slice(data, discord_start + 28, discord_start + 32)?); + let discord_len: usize = u32::from_be_bytes(buf) as usize; + if discord_len > MAX_SINGLE_PARAMETER_SIZE { + log::error!("the length of discord as {} is too big", discord_len); + return Err(PrecompileFailure::Error { + exit_status: ExitError::InvalidRange, + }); + } + let mut discord_vec = vec![0; discord_len]; + discord_vec.copy_from_slice(get_slice( + data, + discord_start + 32, + discord_start + discord_len + 32, + )?); + + // get description + buf.copy_from_slice(get_slice( + data, + description_start + 28, + description_start + 32, + )?); + let description_len: usize = u32::from_be_bytes(buf) as usize; + if description_len > MAX_SINGLE_PARAMETER_SIZE { + log::error!( + "the length of description as {} is too big", + description_len + ); + return Err(PrecompileFailure::Error { + exit_status: ExitError::InvalidRange, + }); + } + let mut description_vec = vec![0; description_len]; + description_vec.copy_from_slice(get_slice( + data, + description_start + 32, + description_start + description_len + 32, + )?); + + // get additional + buf.copy_from_slice(get_slice( + data, + additional_start + 28, + additional_start + 32, + )?); + let additional_len: usize = u32::from_be_bytes(buf) as usize; + if additional_len > MAX_SINGLE_PARAMETER_SIZE { + log::error!("the length of additional as {} is too big", additional_len); + return Err(PrecompileFailure::Error { + exit_status: ExitError::InvalidRange, + }); + } + let mut additional_vec = vec![0; additional_len]; + additional_vec.copy_from_slice(get_slice( + data, + additional_start + 32, + additional_start + additional_len + 32, + )?); + + Ok(( + pubkey, + name_vec, + repo_vec, + contact_vec, + url_vec, + discord_vec, + description_vec, + additional_vec, + )) } } From 913fb1a4bac8ba8c6ae5f3130bde568c6477576e Mon Sep 17 00:00:00 2001 From: JohnReedV <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:00:21 -0800 Subject: [PATCH 08/12] remove SubnetInfov3 struct --- pallets/subtensor/src/rpc_info/subnet_info.rs | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/pallets/subtensor/src/rpc_info/subnet_info.rs b/pallets/subtensor/src/rpc_info/subnet_info.rs index 65851d36cf..ce59a4406b 100644 --- a/pallets/subtensor/src/rpc_info/subnet_info.rs +++ b/pallets/subtensor/src/rpc_info/subnet_info.rs @@ -51,30 +51,6 @@ pub struct SubnetInfov2 { identity: Option, } -#[freeze_struct("dd91200554b75bc4")] -#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] -pub struct SubnetInfov3 { - netuid: Compact, - rho: Compact, - kappa: Compact, - difficulty: Compact, - immunity_period: Compact, - max_allowed_validators: Compact, - min_allowed_weights: Compact, - max_weights_limit: Compact, - scaling_law_power: Compact, - subnetwork_n: Compact, - max_allowed_uids: Compact, - blocks_since_last_step: Compact, - tempo: Compact, - network_modality: Compact, - network_connect: Vec<[u16; 2]>, - emission_values: Compact, - burn: Compact, - owner: T::AccountId, - identity: Option, -} - #[freeze_struct("a2dd2fcd6f4d4ff8")] #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct SubnetHyperparams { From 69d2b778e5185d9e99de429b142ecc3c72addcd0 Mon Sep 17 00:00:00 2001 From: JohnReedV <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:04:38 -0800 Subject: [PATCH 09/12] rename emission_values => emission_value --- pallets/subtensor/src/rpc_info/subnet_info.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pallets/subtensor/src/rpc_info/subnet_info.rs b/pallets/subtensor/src/rpc_info/subnet_info.rs index ce59a4406b..a72da1c0c6 100644 --- a/pallets/subtensor/src/rpc_info/subnet_info.rs +++ b/pallets/subtensor/src/rpc_info/subnet_info.rs @@ -27,7 +27,7 @@ pub struct SubnetInfo { owner: T::AccountId, } -#[freeze_struct("c46dc4e2d4d9f8a3")] +#[freeze_struct("da372105ad6aacb0")] #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct SubnetInfov2 { netuid: Compact, @@ -45,7 +45,7 @@ pub struct SubnetInfov2 { tempo: Compact, network_modality: Compact, network_connect: Vec<[u16; 2]>, - emission_values: Compact, + emission_value: Compact, burn: Compact, owner: T::AccountId, identity: Option, @@ -172,7 +172,7 @@ impl Pallet { let blocks_since_last_step = Self::get_blocks_since_last_step(netuid); let tempo = Self::get_tempo(netuid); let network_modality = >::get(netuid); - let emission_values = Self::get_emission_value(netuid); + let emission_value = Self::get_emission_value(netuid); let burn: Compact = Self::get_burn_as_u64(netuid).into(); let identity: Option = SubnetIdentitiesV2::::get(netuid); @@ -198,7 +198,7 @@ impl Pallet { tempo: tempo.into(), network_modality: network_modality.into(), network_connect, - emission_values: emission_values.into(), + emission_value: emission_value.into(), burn, owner: Self::get_subnet_owner(netuid), identity, From 6766f1d4500113d898a27678870314332a3144ac Mon Sep 17 00:00:00 2001 From: JohnReedV <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:34:21 -0800 Subject: [PATCH 10/12] bump spec --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 63a03c1ad8..b3f617edd4 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -220,7 +220,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: 225, + spec_version: 226, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 0213918c3716f9f99d1ee8bf30ff9334e6bec5d1 Mon Sep 17 00:00:00 2001 From: JohnReedV <87283488+JohnReedV@users.noreply.github.com> Date: Tue, 4 Feb 2025 12:06:08 -0800 Subject: [PATCH 11/12] use saturating math --- pallets/subtensor/src/utils/identity.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/utils/identity.rs b/pallets/subtensor/src/utils/identity.rs index b721664f0f..0e83205cc0 100644 --- a/pallets/subtensor/src/utils/identity.rs +++ b/pallets/subtensor/src/utils/identity.rs @@ -167,7 +167,15 @@ impl Pallet { .saturating_add(identity.description.len()) .saturating_add(identity.additional.len()); - total_length <= 256 + 256 + 256 + 1024 + 256 + 1024 + 1024 + let max_length: usize = 256_usize + .saturating_add(256) + .saturating_add(256) + .saturating_add(1024) + .saturating_add(256) + .saturating_add(1024) + .saturating_add(1024); + + total_length <= max_length && identity.name.len() <= 256 && identity.url.len() <= 256 && identity.github_repo.len() <= 256 @@ -197,7 +205,15 @@ impl Pallet { .saturating_add(identity.github_repo.len()) .saturating_add(identity.subnet_contact.len()); - total_length <= 256 + 1024 + 1024 + 1024 + 256 + 1024 + 1024 + let max_length: usize = 256_usize + .saturating_add(1024) + .saturating_add(1024) + .saturating_add(1024) + .saturating_add(256) + .saturating_add(1024) + .saturating_add(1024); + + total_length <= max_length && identity.subnet_name.len() <= 256 && identity.github_repo.len() <= 1024 && identity.subnet_contact.len() <= 1024 From 6c946db3a919b13c43c987e5df16fed7c4b548f4 Mon Sep 17 00:00:00 2001 From: JohnReedV <87283488+JohnReedV@users.noreply.github.com> Date: Wed, 5 Feb 2025 09:46:36 -0800 Subject: [PATCH 12/12] bump spec --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index a9a4bd2ca8..25f01692a8 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: 226, + spec_version: 227, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,