From f33d70155e9f7df9f59211298c820fe6ce6f49b1 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Wed, 14 Aug 2024 14:52:22 -0700 Subject: [PATCH 01/10] add subnet identities --- pallets/subtensor/src/coinbase/root.rs | 9 +- pallets/subtensor/src/lib.rs | 16 ++ pallets/subtensor/src/macros/dispatches.rs | 30 ++++ pallets/subtensor/src/macros/events.rs | 2 + pallets/subtensor/src/rpc_info/subnet_info.rs | 5 +- pallets/subtensor/src/utils/identity.rs | 85 +++++++++ pallets/subtensor/tests/serving.rs | 165 ++++++++++++++++++ 7 files changed, 308 insertions(+), 4 deletions(-) diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index 974931e8f..8dc9d7a03 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -1008,14 +1008,17 @@ impl Pallet { Error::::NotSubnetOwner ); - // --- 4. Explicitly erase the network and all its parameters. + // --- 4. Remove the subnet identity if it exists. + SubnetIdentities::::remove(netuid); + + // --- 5. Explicitly erase the network and all its parameters. Self::remove_network(netuid); - // --- 5. Emit the NetworkRemoved event. + // --- 6. Emit the NetworkRemoved event. log::info!("NetworkRemoved( netuid:{:?} )", netuid); Self::deposit_event(Event::NetworkRemoved(netuid)); - // --- 6. Return success. + // --- 7. Return success. Ok(()) } diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index b305661f7..a132390aa 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -152,6 +152,18 @@ pub mod pallet { pub additional: Vec, } + /// Struct for Prometheus. + pub type SubnetIdentityOf = SubnetIdentity; + /// Data structure for Prometheus information. + #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)] + pub struct SubnetIdentity { + /// The name of the subnet + pub subnet_name: Vec, + /// The github repository associated with the chain identity + pub github_repo: Vec, + /// The subnet's contact + pub subnet_contact: Vec, + } /// ============================ /// ==== Staking + Accounts ==== /// ============================ @@ -1080,6 +1092,10 @@ pub mod pallet { pub type Identities = StorageMap<_, Blake2_128Concat, T::AccountId, ChainIdentityOf, OptionQuery>; + #[pallet::storage] // --- MAP ( netuid ) --> identity + pub type SubnetIdentities = + StorageMap<_, Blake2_128Concat, u16, SubnetIdentityOf, OptionQuery>; + /// ================================= /// ==== Axon / Promo Endpoints ===== /// ================================= diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 00865f8db..242885ecd 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -937,5 +937,35 @@ mod dispatches { ) -> DispatchResult { Self::do_set_identity(origin, name, url, image, discord, description, additional) } + + /// ---- Set the identity information for a subnet. + /// # Args: + /// * `origin` - (::Origin): + /// - The signature of the calling coldkey, which must be the owner of the subnet. + /// + /// * `netuid` (u16): + /// - The unique network identifier of the subnet. + /// + /// * `subnet_name` (Vec): + /// - The name of the subnet. + /// + /// * `github_repo` (Vec): + /// - The GitHub repository associated with the subnet identity. + /// + /// * `subnet_contact` (Vec): + /// - The contact information for the subnet. + #[pallet::call_index(69)] + #[pallet::weight((Weight::from_parts(45_000_000, 0) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Normal, Pays::Yes))] + pub fn set_subnet_identity( + origin: OriginFor, + netuid: u16, + subnet_name: Vec, + github_repo: Vec, + subnet_contact: Vec, + ) -> DispatchResult { + Self::do_set_subnet_identity(origin, netuid, subnet_name, github_repo, subnet_contact) + } } } diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index 694b9779f..b67a778b9 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -179,5 +179,7 @@ mod events { NetworkMaxStakeSet(u16, u64), /// The identity of a coldkey has been set ChainIdentitySet(T::AccountId), + /// The identity of a subnet has been set + SubnetIdentitySet(u16), } } diff --git a/pallets/subtensor/src/rpc_info/subnet_info.rs b/pallets/subtensor/src/rpc_info/subnet_info.rs index 4e9e756a0..6e8b4bdc5 100644 --- a/pallets/subtensor/src/rpc_info/subnet_info.rs +++ b/pallets/subtensor/src/rpc_info/subnet_info.rs @@ -4,7 +4,7 @@ use frame_support::storage::IterableStorageMap; extern crate alloc; use codec::Compact; -#[freeze_struct("fe79d58173da662a")] +#[freeze_struct("ccca539640c3f631")] #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct SubnetInfo { netuid: Compact, @@ -25,6 +25,7 @@ pub struct SubnetInfo { emission_values: Compact, burn: Compact, owner: T::AccountId, + identity: Option, } #[freeze_struct("55b472510f10e76a")] @@ -80,6 +81,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); // DEPRECATED let network_connect: Vec<[u16; 2]> = Vec::<[u16; 2]>::new(); @@ -106,6 +108,7 @@ impl Pallet { emission_values: emission_values.into(), burn, owner: Self::get_subnet_owner(netuid), + identity, }) } diff --git a/pallets/subtensor/src/utils/identity.rs b/pallets/subtensor/src/utils/identity.rs index 1c9c3c25d..605700983 100644 --- a/pallets/subtensor/src/utils/identity.rs +++ b/pallets/subtensor/src/utils/identity.rs @@ -75,6 +75,65 @@ impl Pallet { Ok(()) } + /// Sets the identity for a subnet. + /// + /// This function allows the owner of a subnet to set or update the identity information associated with the subnet. + /// It verifies that the caller is the owner of the specified subnet, validates the provided identity information, + /// and then stores it in the blockchain state. + /// + /// # Arguments + /// + /// * `origin` - The origin of the call, which should be a signed extrinsic. + /// * `netuid` - The unique identifier for the subnet. + /// * `subnet_name` - The name of the subnet to be associated with the identity. + /// * `github_repo` - The GitHub repository URL associated with the subnet identity. + /// * `subnet_contact` - Contact information for the subnet. + /// + /// # Returns + /// + /// Returns `Ok(())` if the subnet identity is successfully set, otherwise returns an error. + pub fn do_set_subnet_identity( + origin: T::RuntimeOrigin, + netuid: u16, + subnet_name: Vec, + github_repo: Vec, + subnet_contact: Vec, + ) -> dispatch::DispatchResult { + // Ensure the call is signed and get the signer's (coldkey) account + let coldkey = ensure_signed(origin)?; + + // Ensure that the coldkey owns the subnet + ensure!( + Self::get_subnet_owner(netuid) == coldkey, + Error::::NotSubnetOwner + ); + + // Create the identity struct with the provided information + let identity: SubnetIdentityOf = SubnetIdentityOf { + subnet_name, + github_repo, + subnet_contact, + }; + + // Validate the created identity + ensure!( + Self::is_valid_subnet_identity(&identity), + Error::::InvalidIdentity + ); + + // Store the validated identity in the blockchain state + SubnetIdentities::::insert(netuid, identity.clone()); + + // Log the identity set event + log::info!("SubnetIdentitySet( netuid:{:?} ) ", netuid); + + // Emit an event to notify that an identity has been set + Self::deposit_event(Event::SubnetIdentitySet(netuid)); + + // Return Ok to indicate successful execution + Ok(()) + } + /// Validates the given ChainIdentityOf struct. /// /// This function checks if the total length of all fields in the ChainIdentityOf struct @@ -106,4 +165,30 @@ impl Pallet { && identity.description.len() <= 1024 && identity.additional.len() <= 1024 } + + /// Validates the given SubnetIdentityOf struct. + /// + /// This function checks if the total length of all fields in the SubnetIdentityOf struct + /// is less than or equal to 2304 bytes, and if each individual field is also + /// within its respective maximum byte limit. + /// + /// # Arguments + /// + /// * `identity` - A reference to the SubnetIdentityOf struct to be validated. + /// + /// # Returns + /// + /// * `bool` - Returns true if the SubnetIdentity is valid, false otherwise. + pub fn is_valid_subnet_identity(identity: &SubnetIdentityOf) -> 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 + && identity.subnet_name.len() <= 256 + && identity.github_repo.len() <= 1024 + && identity.subnet_contact.len() <= 1024 + } } diff --git a/pallets/subtensor/tests/serving.rs b/pallets/subtensor/tests/serving.rs index b0eada8e6..3da807fea 100644 --- a/pallets/subtensor/tests/serving.rs +++ b/pallets/subtensor/tests/serving.rs @@ -827,3 +827,168 @@ fn test_migrate_set_hotkey_identities() { ); }); } + +// 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() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let netuid = 1; + + // Register a hotkey for the coldkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set coldkey as the owner of the subnet + SubnetOwner::::insert(netuid, coldkey); + + // Prepare subnet identity data + 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(); + + // Set subnet identity + assert_ok!(SubtensorModule::do_set_subnet_identity( + <::RuntimeOrigin>::signed(coldkey), + netuid, + subnet_name.clone(), + github_repo.clone(), + subnet_contact.clone() + )); + + // Check if subnet identity is set correctly + let stored_identity = + SubnetIdentities::::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); + + // Test setting subnet identity by non-owner + let non_owner_coldkey = U256::from(2); + assert_noop!( + SubtensorModule::do_set_subnet_identity( + <::RuntimeOrigin>::signed(non_owner_coldkey), + netuid, + subnet_name.clone(), + github_repo.clone(), + subnet_contact.clone() + ), + Error::::NotSubnetOwner + ); + + // Test updating an existing subnet identity + let new_subnet_name = b"Updated Subnet".to_vec(); + let new_github_repo = b"https://github.com/test/subnet-updated".to_vec(); + assert_ok!(SubtensorModule::do_set_subnet_identity( + <::RuntimeOrigin>::signed(coldkey), + netuid, + new_subnet_name.clone(), + new_github_repo.clone(), + subnet_contact.clone() + )); + + let updated_identity = + SubnetIdentities::::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); + + // Test setting subnet identity with invalid data (exceeding 1024 bytes total) + let long_data = vec![0; 1025]; + assert_noop!( + SubtensorModule::do_set_subnet_identity( + <::RuntimeOrigin>::signed(coldkey), + netuid, + long_data.clone(), + long_data.clone(), + long_data.clone() + ), + Error::::InvalidIdentity + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test serving -- test_is_valid_subnet_identity --exact --nocapture +#[test] +fn test_is_valid_subnet_identity() { + new_test_ext(1).execute_with(|| { + // Test valid subnet identity + let valid_identity = SubnetIdentity { + subnet_name: vec![0; 256], + github_repo: vec![0; 1024], + subnet_contact: 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 { + subnet_name: vec![0; 256], + github_repo: vec![0; 1024], + subnet_contact: 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 { + subnet_name: vec![0; 257], + github_repo: vec![0; 1024], + subnet_contact: 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 { + subnet_name: vec![0; 257], + github_repo: vec![0; 1024], + subnet_contact: vec![0; 1024], + }; + assert!(!SubtensorModule::is_valid_subnet_identity( + &invalid_field_identity + )); + + // Test subnet identity with empty fields + let empty_identity = SubnetIdentity { + subnet_name: vec![], + github_repo: vec![], + subnet_contact: vec![], + }; + assert!(SubtensorModule::is_valid_subnet_identity(&empty_identity)); + + // Test subnet identity with some empty and some filled fields + let mixed_identity = SubnetIdentity { + subnet_name: b"Test Subnet".to_vec(), + github_repo: vec![], + subnet_contact: b"contact@testsubnet.com".to_vec(), + }; + assert!(SubtensorModule::is_valid_subnet_identity(&mixed_identity)); + }); +} + +#[test] +fn test_set_identity_for_non_existent_subnet() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let netuid = 999; // Non-existent subnet ID + + // Subnet identity data + 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(); + + // Attempt to set identity for a non-existent subnet + assert_noop!( + SubtensorModule::do_set_subnet_identity( + <::RuntimeOrigin>::signed(coldkey), + netuid, + subnet_name.clone(), + github_repo.clone(), + subnet_contact.clone() + ), + Error::::NotSubnetOwner // Since there's no owner, it should fail + ); + }); +} From fa8da4c5c725b90b25bc896865e7d598f54c3fc8 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Thu, 15 Aug 2024 09:43:07 -0700 Subject: [PATCH 02/10] fix comments --- pallets/subtensor/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index a132390aa..f9f5197c7 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -133,9 +133,9 @@ pub mod pallet { pub ip_type: u8, } - /// Struct for Prometheus. + /// Struct for ChainIdentities. pub type ChainIdentityOf = ChainIdentity; - /// Data structure for Prometheus information. + /// Data structure for Chain Identities. #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)] pub struct ChainIdentity { /// The name of the chain identity @@ -152,9 +152,9 @@ pub mod pallet { pub additional: Vec, } - /// Struct for Prometheus. + /// Struct for SubnetIdentities. pub type SubnetIdentityOf = SubnetIdentity; - /// Data structure for Prometheus information. + /// Data structure for Subnet Identities #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)] pub struct SubnetIdentity { /// The name of the subnet From ba508aaf3bbdfb5b3c071310b3a57362a6822b60 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Thu, 15 Aug 2024 10:01:19 -0700 Subject: [PATCH 03/10] freeze SubnetIdentity struct --- pallets/subtensor/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index f9f5197c7..dfac0d603 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -60,7 +60,7 @@ extern crate alloc; #[frame_support::pallet] pub mod pallet { - use crate::migrations; + use crate::{freeze_struct, migrations}; use frame_support::{ dispatch::GetDispatchInfo, pallet_prelude::{DispatchResult, StorageMap, ValueQuery, *}, @@ -155,6 +155,7 @@ pub mod pallet { /// Struct for SubnetIdentities. pub type SubnetIdentityOf = SubnetIdentity; /// Data structure for Subnet Identities + #[freeze_struct("f448dc3dad763108")] #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)] pub struct SubnetIdentity { /// The name of the subnet From f373434fc73d16f4027c6fda98576a04369799d2 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Thu, 15 Aug 2024 12:36:44 -0700 Subject: [PATCH 04/10] add identities to subnet registration process --- pallets/admin-utils/tests/tests.rs | 2 +- pallets/subtensor/src/benchmarks.rs | 4 +- pallets/subtensor/src/coinbase/root.rs | 36 +++++++--- pallets/subtensor/src/macros/dispatches.rs | 7 +- pallets/subtensor/src/macros/events.rs | 2 + pallets/subtensor/tests/epoch.rs | 4 +- pallets/subtensor/tests/migration.rs | 3 +- pallets/subtensor/tests/root.rs | 83 +++++++++++++++++----- pallets/subtensor/tests/serving.rs | 22 ++++++ 9 files changed, 130 insertions(+), 33 deletions(-) diff --git a/pallets/admin-utils/tests/tests.rs b/pallets/admin-utils/tests/tests.rs index 6e78a1ed6..3e57f74fe 100644 --- a/pallets/admin-utils/tests/tests.rs +++ b/pallets/admin-utils/tests/tests.rs @@ -1243,7 +1243,7 @@ fn test_sudo_get_set_alpha() { DispatchError::BadOrigin ); - assert_ok!(SubtensorModule::register_network(signer.clone())); + assert_ok!(SubtensorModule::register_network(signer.clone(), None)); assert_ok!(AdminUtils::sudo_set_alpha_values( signer.clone(), diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 03e087a92..ba51f0d78 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -299,7 +299,7 @@ benchmarks! { let amount: u64 = 1; let amount_to_be_staked = 100_000_000_000_000u64; Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), amount_to_be_staked); - }: register_network(RawOrigin::Signed(coldkey)) + }: register_network(RawOrigin::Signed(coldkey), None) benchmark_dissolve_network { let seed : u32 = 1; @@ -311,7 +311,7 @@ benchmarks! { let amount: u64 = 1; let amount_to_be_staked = 100_000_000_000_000u64; Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), amount_to_be_staked); - assert_ok!(Subtensor::::register_network(RawOrigin::Signed(coldkey.clone()).into())); + assert_ok!(Subtensor::::register_network(RawOrigin::Signed(coldkey.clone()).into(), None)); }: dissolve_network(RawOrigin::Signed(coldkey), 1) // swap_hotkey { diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index 8dc9d7a03..9786f13fd 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -894,17 +894,24 @@ impl Pallet { /// Facilitates user registration of a new subnetwork. /// /// # Args: - /// * 'origin': ('T::RuntimeOrigin'): The calling origin. Must be signed. + /// * `origin` (`T::RuntimeOrigin`): The calling origin. Must be signed. + /// * `identity` (`Option`): Optional identity to be associated with the new subnetwork. /// - /// # Event: - /// * 'NetworkAdded': Emitted when a new network is successfully added. + /// # Events: + /// * `NetworkAdded(netuid, modality)`: Emitted when a new network is successfully added. + /// * `SubnetIdentitySet(netuid)`: Emitted when a custom identity is set for a new subnetwork. + /// * `NetworkRemoved(netuid)`: Emitted when an existing network is removed to make room for the new one. + /// * `SubnetIdentityRemoved(netuid)`: Emitted when the identity of a removed network is also deleted. /// /// # Raises: /// * 'TxRateLimitExceeded': If the rate limit for network registration is exceeded. /// * 'NotEnoughBalanceToStake': If there isn't enough balance to stake for network registration. /// * 'BalanceWithdrawalError': If an error occurs during balance withdrawal for network registration. /// - pub fn user_add_network(origin: T::RuntimeOrigin) -> dispatch::DispatchResult { + pub fn user_add_network( + origin: T::RuntimeOrigin, + identity: Option, + ) -> dispatch::DispatchResult { // --- 0. Ensure the caller is a signed user. let coldkey = ensure_signed(origin)?; @@ -948,6 +955,11 @@ impl Pallet { Self::remove_network(netuid_to_prune); log::debug!("remove_network: {:?}", netuid_to_prune,); Self::deposit_event(Event::NetworkRemoved(netuid_to_prune)); + + if SubnetIdentities::::take(netuid_to_prune).is_some() { + Self::deposit_event(Event::SubnetIdentityRemoved(netuid_to_prune)); + } + netuid_to_prune } }; @@ -961,13 +973,19 @@ impl Pallet { Self::init_new_network(netuid_to_register, 360); log::debug!("init_new_network: {:?}", netuid_to_register,); - // --- 7. Set netuid storage. + // --- 7. Remove the identity if it exists + if let Some(identity_value) = identity { + SubnetIdentities::::insert(netuid_to_register, identity_value); + Self::deposit_event(Event::SubnetIdentitySet(netuid_to_register)); + } + + // --- 8. Set netuid storage. let current_block_number: u64 = Self::get_current_block_as_u64(); NetworkLastRegistered::::set(current_block_number); NetworkRegisteredAt::::insert(netuid_to_register, current_block_number); SubnetOwner::::insert(netuid_to_register, coldkey); - // --- 8. Emit the NetworkAdded event. + // --- 9. Emit the NetworkAdded event. log::info!( "NetworkAdded( netuid:{:?}, modality:{:?} )", netuid_to_register, @@ -975,7 +993,7 @@ impl Pallet { ); Self::deposit_event(Event::NetworkAdded(netuid_to_register, 0)); - // --- 9. Return success. + // --- 10. Return success. Ok(()) } @@ -1009,7 +1027,9 @@ impl Pallet { ); // --- 4. Remove the subnet identity if it exists. - SubnetIdentities::::remove(netuid); + if SubnetIdentities::::take(netuid).is_some() { + Self::deposit_event(Event::SubnetIdentityRemoved(netuid)); + } // --- 5. Explicitly erase the network and all its parameters. Self::remove_network(netuid); diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 242885ecd..59de17b60 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -798,8 +798,11 @@ mod dispatches { #[pallet::weight((Weight::from_parts(157_000_000, 0) .saturating_add(T::DbWeight::get().reads(16)) .saturating_add(T::DbWeight::get().writes(30)), DispatchClass::Operational, Pays::No))] - pub fn register_network(origin: OriginFor) -> DispatchResult { - Self::user_add_network(origin) + pub fn register_network( + origin: OriginFor, + identity: Option, + ) -> DispatchResult { + Self::user_add_network(origin, identity) } /// Facility extrinsic for user to get taken from faucet diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index b67a778b9..a0ec67861 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -181,5 +181,7 @@ mod events { ChainIdentitySet(T::AccountId), /// The identity of a subnet has been set SubnetIdentitySet(u16), + /// The identity of a subnet has been removed + SubnetIdentityRemoved(u16), } } diff --git a/pallets/subtensor/tests/epoch.rs b/pallets/subtensor/tests/epoch.rs index b639a4ac4..5e4d0b79c 100644 --- a/pallets/subtensor/tests/epoch.rs +++ b/pallets/subtensor/tests/epoch.rs @@ -1501,7 +1501,7 @@ fn test_set_alpha_disabled() { assert_ok!(SubtensorModule::root_register(signer.clone(), hotkey,)); assert_ok!(SubtensorModule::add_stake(signer.clone(), hotkey, 1000)); // Only owner can set alpha values - assert_ok!(SubtensorModule::register_network(signer.clone())); + assert_ok!(SubtensorModule::register_network(signer.clone(), None)); // Explicitly set to false SubtensorModule::set_liquid_alpha_enabled(netuid, false); @@ -2584,7 +2584,7 @@ fn test_get_set_alpha() { DispatchError::BadOrigin ); - assert_ok!(SubtensorModule::register_network(signer.clone())); + assert_ok!(SubtensorModule::register_network(signer.clone(), None)); assert_ok!(SubtensorModule::do_set_alpha_values( signer.clone(), diff --git a/pallets/subtensor/tests/migration.rs b/pallets/subtensor/tests/migration.rs index 2a1388237..95479d7d7 100644 --- a/pallets/subtensor/tests/migration.rs +++ b/pallets/subtensor/tests/migration.rs @@ -170,7 +170,8 @@ fn test_total_issuance_global() { SubtensorModule::add_balance_to_coldkey_account(&owner, lockcost); // Add a balance of 20000 to the coldkey account. assert_eq!(SubtensorModule::get_total_issuance(), 0); // initial is zero. assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + None )); SubtensorModule::set_max_allowed_uids(netuid, 1); // Set the maximum allowed unique identifiers for the network to 1. assert_eq!(SubtensorModule::get_total_issuance(), 0); // initial is zero. diff --git a/pallets/subtensor/tests/root.rs b/pallets/subtensor/tests/root.rs index 84df71d83..b40cd788d 100644 --- a/pallets/subtensor/tests/root.rs +++ b/pallets/subtensor/tests/root.rs @@ -4,8 +4,9 @@ use crate::mock::*; use frame_support::{assert_err, assert_ok}; use frame_system::Config; use frame_system::{EventRecord, Phase}; -use pallet_subtensor::migrations; use pallet_subtensor::Error; +use pallet_subtensor::{migrations, SubnetIdentity}; +use pallet_subtensor::{SubnetIdentities, SubnetIdentityOf}; use sp_core::{Get, H256, U256}; mod mock; @@ -235,7 +236,8 @@ fn test_root_set_weights() { for netuid in 1..n { log::debug!("Adding network with netuid: {}", netuid); assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(U256::from(netuid + 456)) + <::RuntimeOrigin>::signed(U256::from(netuid + 456)), + None )); } @@ -380,7 +382,8 @@ fn test_root_set_weights_out_of_order_netuids() { if netuid % 2 == 0 { assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(U256::from(netuid)) + <::RuntimeOrigin>::signed(U256::from(netuid)), + None )); } else { add_network(netuid as u16 * 10, 1000, 0) @@ -471,14 +474,16 @@ fn test_root_subnet_creation_deletion() { SubtensorModule::add_balance_to_coldkey_account(&owner, 1_000_000_000_000_000); // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 0, lock_reduction_interval: 2, current_block: 0, mult: 1 lock_cost: 100000000000 assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + None )); // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 0, lock_reduction_interval: 2, current_block: 0, mult: 1 lock_cost: 100000000000 assert_eq!(SubtensorModule::get_network_lock_cost(), 100_000_000_000); step_block(1); // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 0, lock_reduction_interval: 2, current_block: 1, mult: 1 lock_cost: 100000000000 assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + None )); // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 1, lock_reduction_interval: 2, current_block: 1, mult: 2 lock_cost: 200000000000 assert_eq!(SubtensorModule::get_network_lock_cost(), 200_000_000_000); // Doubles from previous subnet creation @@ -492,38 +497,44 @@ fn test_root_subnet_creation_deletion() { // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 1, lock_reduction_interval: 2, current_block: 4, mult: 2 lock_cost: 100000000000 assert_eq!(SubtensorModule::get_network_lock_cost(), 100_000_000_000); // Reaches min value assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + None )); // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 4, lock_reduction_interval: 2, current_block: 4, mult: 2 lock_cost: 200000000000 assert_eq!(SubtensorModule::get_network_lock_cost(), 200_000_000_000); // Doubles from previous subnet creation step_block(1); // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 4, lock_reduction_interval: 2, current_block: 5, mult: 2 lock_cost: 150000000000 assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + None )); // last_lock: 150000000000, min_lock: 100000000000, last_lock_block: 5, lock_reduction_interval: 2, current_block: 5, mult: 2 lock_cost: 300000000000 assert_eq!(SubtensorModule::get_network_lock_cost(), 300_000_000_000); // Doubles from previous subnet creation step_block(1); // last_lock: 150000000000, min_lock: 100000000000, last_lock_block: 5, lock_reduction_interval: 2, current_block: 6, mult: 2 lock_cost: 225000000000 assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + None )); // last_lock: 225000000000, min_lock: 100000000000, last_lock_block: 6, lock_reduction_interval: 2, current_block: 6, mult: 2 lock_cost: 450000000000 assert_eq!(SubtensorModule::get_network_lock_cost(), 450_000_000_000); // Increasing step_block(1); // last_lock: 225000000000, min_lock: 100000000000, last_lock_block: 6, lock_reduction_interval: 2, current_block: 7, mult: 2 lock_cost: 337500000000 assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + None )); // last_lock: 337500000000, min_lock: 100000000000, last_lock_block: 7, lock_reduction_interval: 2, current_block: 7, mult: 2 lock_cost: 675000000000 assert_eq!(SubtensorModule::get_network_lock_cost(), 675_000_000_000); // Increasing. assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + None )); // last_lock: 337500000000, min_lock: 100000000000, last_lock_block: 7, lock_reduction_interval: 2, current_block: 7, mult: 2 lock_cost: 675000000000 assert_eq!(SubtensorModule::get_network_lock_cost(), 1_350_000_000_000); // Double increasing. assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + None )); assert_eq!(SubtensorModule::get_network_lock_cost(), 2_700_000_000_000); // Double increasing again. @@ -572,7 +583,8 @@ fn test_network_pruning() { 1_000 )); assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(cold) + <::RuntimeOrigin>::signed(cold), + None )); log::debug!("Adding network with netuid: {}", (i as u16) + 1); assert!(SubtensorModule::if_subnet_exist((i as u16) + 1)); @@ -645,17 +657,20 @@ fn test_network_prune_results() { SubtensorModule::add_balance_to_coldkey_account(&owner, 1_000_000_000_000_000); assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + None )); step_block(3); assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + None )); step_block(3); assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + None )); step_block(3); @@ -699,7 +714,8 @@ fn test_weights_after_network_pruning() { // Register a network assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(cold) + <::RuntimeOrigin>::signed(cold), + None )); log::debug!("Adding network with netuid: {}", (i as u16) + 1); @@ -759,7 +775,8 @@ fn test_weights_after_network_pruning() { assert_eq!(latest_weights[0][1], 21845); assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(cold) + <::RuntimeOrigin>::signed(cold), + None )); // Subnet should not exist, as it would replace a previous subnet. @@ -979,3 +996,35 @@ fn test_dissolve_network_does_not_exist_err() { ); }); } + +#[test] +fn test_user_add_network_with_identity_fields_ok() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let balance = SubtensorModule::get_network_lock_cost() + 10_000; + + 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 identity_value: SubnetIdentity = SubnetIdentityOf { + subnet_name: subnet_name.clone(), + github_repo: github_repo.clone(), + subnet_contact: subnet_contact.clone(), + }; + + SubtensorModule::add_balance_to_coldkey_account(&coldkey, balance); + + // Call the function with the identity. + assert_ok!(SubtensorModule::user_add_network( + RuntimeOrigin::signed(coldkey), + Some(identity_value.clone()) + )); + + // Retrieve and verify the stored identity. + let stored_identity: SubnetIdentity = SubnetIdentities::::get(1).unwrap(); + assert_eq!(stored_identity.subnet_name, subnet_name); + assert_eq!(stored_identity.github_repo, github_repo); + assert_eq!(stored_identity.subnet_contact, subnet_contact); + }); +} diff --git a/pallets/subtensor/tests/serving.rs b/pallets/subtensor/tests/serving.rs index 3da807fea..49a963951 100644 --- a/pallets/subtensor/tests/serving.rs +++ b/pallets/subtensor/tests/serving.rs @@ -992,3 +992,25 @@ fn test_set_identity_for_non_existent_subnet() { ); }); } + +#[test] +fn test_set_subnet_identity_dispatch_info_ok() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + 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 call: RuntimeCall = RuntimeCall::SubtensorModule(SubtensorCall::set_subnet_identity { + netuid, + subnet_name, + github_repo, + subnet_contact, + }); + + let dispatch_info: DispatchInfo = call.get_dispatch_info(); + + assert_eq!(dispatch_info.class, DispatchClass::Normal); + assert_eq!(dispatch_info.pays_fee, Pays::Yes); + }); +} From 74256020f45b4d7633cfb32d99250fbb02a7209e Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Thu, 15 Aug 2024 12:53:43 -0700 Subject: [PATCH 05/10] check if identity is valid --- pallets/subtensor/src/coinbase/root.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index 9786f13fd..3dbb42d27 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -973,8 +973,13 @@ impl Pallet { Self::init_new_network(netuid_to_register, 360); log::debug!("init_new_network: {:?}", netuid_to_register,); - // --- 7. Remove the identity if it exists + // --- 7. Remove the identity if it exists if let Some(identity_value) = identity { + ensure!( + Self::is_valid_subnet_identity(&identity_value), + Error::::InvalidIdentity + ); + SubnetIdentities::::insert(netuid_to_register, identity_value); Self::deposit_event(Event::SubnetIdentitySet(netuid_to_register)); } From 136dd471cdf15c8c6b0d9b96fdecfe1361075ef4 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Fri, 16 Aug 2024 09:35:15 -0700 Subject: [PATCH 06/10] Expand test --- pallets/subtensor/src/coinbase/root.rs | 2 +- pallets/subtensor/tests/root.rs | 77 ++++++++++++++++++++------ 2 files changed, 60 insertions(+), 19 deletions(-) diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index 3dbb42d27..a657bf1f5 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -973,7 +973,7 @@ impl Pallet { Self::init_new_network(netuid_to_register, 360); log::debug!("init_new_network: {:?}", netuid_to_register,); - // --- 7. Remove the identity if it exists + // --- 7. Add the identity if it exists if let Some(identity_value) = identity { ensure!( Self::is_valid_subnet_identity(&identity_value), diff --git a/pallets/subtensor/tests/root.rs b/pallets/subtensor/tests/root.rs index b40cd788d..c134e499e 100644 --- a/pallets/subtensor/tests/root.rs +++ b/pallets/subtensor/tests/root.rs @@ -1000,31 +1000,72 @@ fn test_dissolve_network_does_not_exist_err() { #[test] fn test_user_add_network_with_identity_fields_ok() { new_test_ext(1).execute_with(|| { - let coldkey = U256::from(1); - let balance = SubtensorModule::get_network_lock_cost() + 10_000; + let coldkey_1 = U256::from(1); + let coldkey_2 = U256::from(2); + let balance_1 = SubtensorModule::get_network_lock_cost() + 10_000; + + let subnet_name_1: Vec = b"GenericSubnet1".to_vec(); + let github_repo_1: Vec = b"GenericSubnet1.com".to_vec(); + let subnet_contact_1: Vec = b"https://www.GenericSubnet1.co".to_vec(); + + let identity_value_1: SubnetIdentity = SubnetIdentityOf { + subnet_name: subnet_name_1.clone(), + github_repo: github_repo_1.clone(), + subnet_contact: subnet_contact_1.clone(), + }; - 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_name_2: Vec = b"DistinctSubnet2".to_vec(); + let github_repo_2: Vec = b"https://github.com/DistinctRepo2".to_vec(); + let subnet_contact_2: Vec = b"https://contact2.example.com".to_vec(); - let identity_value: SubnetIdentity = SubnetIdentityOf { - subnet_name: subnet_name.clone(), - github_repo: github_repo.clone(), - subnet_contact: subnet_contact.clone(), + let identity_value_2: SubnetIdentity = SubnetIdentityOf { + subnet_name: subnet_name_2.clone(), + github_repo: github_repo_2.clone(), + subnet_contact: subnet_contact_2.clone(), }; - SubtensorModule::add_balance_to_coldkey_account(&coldkey, balance); + SubtensorModule::add_balance_to_coldkey_account(&coldkey_1, balance_1); + + assert_ok!(SubtensorModule::user_add_network( + RuntimeOrigin::signed(coldkey_1), + Some(identity_value_1.clone()) + )); + + let balance_2 = SubtensorModule::get_network_lock_cost() + 10_000; + SubtensorModule::add_balance_to_coldkey_account(&coldkey_2, balance_2); - // Call the function with the identity. assert_ok!(SubtensorModule::user_add_network( - RuntimeOrigin::signed(coldkey), - Some(identity_value.clone()) + RuntimeOrigin::signed(coldkey_2), + Some(identity_value_2.clone()) + )); + + let stored_identity_1: SubnetIdentity = SubnetIdentities::::get(1).unwrap(); + assert_eq!(stored_identity_1.subnet_name, subnet_name_1); + assert_eq!(stored_identity_1.github_repo, github_repo_1); + assert_eq!(stored_identity_1.subnet_contact, subnet_contact_1); + + let stored_identity_2: SubnetIdentity = SubnetIdentities::::get(2).unwrap(); + assert_eq!(stored_identity_2.subnet_name, subnet_name_2); + assert_eq!(stored_identity_2.github_repo, github_repo_2); + assert_eq!(stored_identity_2.subnet_contact, subnet_contact_2); + + // Now remove the first network. + assert_ok!(SubtensorModule::user_remove_network( + RuntimeOrigin::signed(coldkey_1), + 1 )); - // Retrieve and verify the stored identity. - let stored_identity: SubnetIdentity = SubnetIdentities::::get(1).unwrap(); - assert_eq!(stored_identity.subnet_name, subnet_name); - assert_eq!(stored_identity.github_repo, github_repo); - assert_eq!(stored_identity.subnet_contact, subnet_contact); + // Verify that the first network and identity have been removed. + assert!(SubnetIdentities::::get(1).is_none()); + + // Ensure the second network and identity are still intact. + let stored_identity_2_after_removal: SubnetIdentity = + SubnetIdentities::::get(2).unwrap(); + assert_eq!(stored_identity_2_after_removal.subnet_name, subnet_name_2); + assert_eq!(stored_identity_2_after_removal.github_repo, github_repo_2); + assert_eq!( + stored_identity_2_after_removal.subnet_contact, + subnet_contact_2 + ); }); } From fd379bc6bade3be746e08d7e42691c43da731443 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Fri, 16 Aug 2024 10:32:09 -0700 Subject: [PATCH 07/10] match existing pattern --- pallets/subtensor/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index dfac0d603..3262132fb 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -60,7 +60,7 @@ extern crate alloc; #[frame_support::pallet] pub mod pallet { - use crate::{freeze_struct, migrations}; + use crate::migrations; use frame_support::{ dispatch::GetDispatchInfo, pallet_prelude::{DispatchResult, StorageMap, ValueQuery, *}, @@ -155,7 +155,7 @@ pub mod pallet { /// Struct for SubnetIdentities. pub type SubnetIdentityOf = SubnetIdentity; /// Data structure for Subnet Identities - #[freeze_struct("f448dc3dad763108")] + #[crate::freeze_struct("f448dc3dad763108")] #[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)] pub struct SubnetIdentity { /// The name of the subnet From 57ed878d7561fddbc27f7c9ca47ae845533d8192 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 19 Aug 2024 09:56:35 -0700 Subject: [PATCH 08/10] fix pallet index conflict --- pallets/subtensor/src/macros/dispatches.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 08a3c578e..f96170626 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1080,7 +1080,7 @@ mod dispatches { /// /// * `subnet_contact` (Vec): /// - The contact information for the subnet. - #[pallet::call_index(69)] + #[pallet::call_index(73)] #[pallet::weight((Weight::from_parts(45_000_000, 0) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Normal, Pays::Yes))] From 166674684f9e733aadef51ef4c66789c4168419d Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Tue, 20 Aug 2024 07:46:25 -0700 Subject: [PATCH 09/10] fix pallet index conflict --- pallets/subtensor/src/macros/dispatches.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 92d9f329f..9ad71d0c9 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1179,7 +1179,7 @@ mod dispatches { /// /// * `subnet_contact` (Vec): /// - The contact information for the subnet. - #[pallet::call_index(73)] + #[pallet::call_index(78)] #[pallet::weight((Weight::from_parts(45_000_000, 0) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Normal, Pays::Yes))] From 979d46d5ca0252db93f12e81ae0934f7ce328baf Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Thu, 22 Aug 2024 08:48:10 -1000 Subject: [PATCH 10/10] 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 e6c0e9d32..9ad0624d0 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -142,7 +142,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: 193, + spec_version: 194, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,