From cc39b6e747edab4dbbc128c2bdf650234638d5b5 Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 20 Mar 2025 10:52:23 +0800 Subject: [PATCH 01/13] feature start call --- .../subtensor/src/coinbase/run_coinbase.rs | 3 +- pallets/subtensor/src/lib.rs | 6 ++- pallets/subtensor/src/macros/config.rs | 3 ++ pallets/subtensor/src/macros/dispatches.rs | 14 +++++ pallets/subtensor/src/macros/errors.rs | 4 ++ pallets/subtensor/src/macros/events.rs | 6 +++ pallets/subtensor/src/macros/hooks.rs | 4 +- .../migrate_set_last_emission_block_number.rs | 53 +++++++++++++++++++ pallets/subtensor/src/migrations/mod.rs | 1 + pallets/subtensor/src/subnets/subnet.rs | 34 ++++++++++++ pallets/subtensor/src/tests/migration.rs | 22 ++++++++ pallets/subtensor/src/tests/mock.rs | 2 + runtime/src/lib.rs | 2 + 13 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 pallets/subtensor/src/migrations/migrate_set_last_emission_block_number.rs diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 7836423868..92d7e3722a 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -37,10 +37,11 @@ impl Pallet { let current_block: u64 = Self::get_current_block_as_u64(); log::debug!("Current block: {:?}", current_block); - // --- 1. Get all netuids (filter out root.) + // --- 1. Get all netuids (filter out root and new subnet) let subnets: Vec = Self::get_all_subnet_netuids() .into_iter() .filter(|netuid| *netuid != 0) + .filter(|netuid| LastEmissionBlockNumber::::get(*netuid).is_some()) .collect(); log::debug!("All subnet netuids: {:?}", subnets); diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 03438aa637..3df312f92b 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1125,7 +1125,11 @@ pub mod pallet { /// ============================ /// ==== Subnet Parameters ===== /// ============================ - #[pallet::storage] // --- MAP ( netuid ) --> subnet mechanism + /// --- MAP ( netuid ) --> block number of last emission + #[pallet::storage] + pub type LastEmissionBlockNumber = StorageMap<_, Identity, u16, u64, OptionQuery>; + /// --- MAP ( netuid ) --> subnet mechanism + #[pallet::storage] pub type SubnetMechanism = StorageMap<_, Identity, u16, u16, ValueQuery, DefaultZeroU16>; #[pallet::storage] diff --git a/pallets/subtensor/src/macros/config.rs b/pallets/subtensor/src/macros/config.rs index af448c8771..889c7e5c5f 100644 --- a/pallets/subtensor/src/macros/config.rs +++ b/pallets/subtensor/src/macros/config.rs @@ -210,5 +210,8 @@ mod config { /// Initial EMA price halving period #[pallet::constant] type InitialEmaPriceHalvingPeriod: Get; + /// Block number for a new subnet accept the start call extrinsic. + #[pallet::constant] + type DurationOfStartCall: Get; } } diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index bcd2bb33f5..1635a78bb6 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1909,5 +1909,19 @@ mod dispatches { Ok(()) } + + /// Initiates a call on a subnet. + /// + #[pallet::call_index(92)] + #[pallet::weight(( + Weight::from_parts(3_000_000, 0).saturating_add(T::DbWeight::get().reads_writes(3, 3)), + DispatchClass::Operational, + Pays::Yes + ))] + pub fn start_call(origin: T::RuntimeOrigin, netuid: u16) -> DispatchResult { + let _ = Self::do_start_call(origin, netuid); + + Ok(()) + } } } diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index 1f189cd2f6..251669c860 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -195,5 +195,9 @@ mod errors { ActivityCutoffTooLow, /// Call is disabled CallDisabled, + /// LastEmissionBlockNumber is already set. + LastEmissionBlockNumberAlreadySet, + /// need wait for more blocks to accept the start call extrinsic. + NeedMoreBlocksToStarCall, } } diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index 834aa901fa..722ecd4205 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -275,5 +275,11 @@ mod events { /// Parameters: /// (netuid, new_hotkey) SubnetOwnerHotkeySet(u16, T::AccountId), + /// LastEmissionBlockNumber is set via start call extrinsic + /// + /// Parameters: + /// netuid + /// block number + LastEmissionBlockNumberSet(u16, u64), } } diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index df9dffabca..68cd2a7623 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -81,7 +81,9 @@ mod hooks { // Remove Stake map entries .saturating_add(migrations::migrate_remove_stake_map::migrate_remove_stake_map::()) // Remove unused maps entries - .saturating_add(migrations::migrate_remove_unused_maps_and_values::migrate_remove_unused_maps_and_values::()); + .saturating_add(migrations::migrate_remove_unused_maps_and_values::migrate_remove_unused_maps_and_values::()) + // Set last emission block number for all existed subnets before start call feature applied + .saturating_add(migrations::migrate_set_last_emission_block_number::migrate_set_last_emission_block_number::()); weight } diff --git a/pallets/subtensor/src/migrations/migrate_set_last_emission_block_number.rs b/pallets/subtensor/src/migrations/migrate_set_last_emission_block_number.rs new file mode 100644 index 0000000000..bc1f7b9abd --- /dev/null +++ b/pallets/subtensor/src/migrations/migrate_set_last_emission_block_number.rs @@ -0,0 +1,53 @@ +use super::*; +use crate::HasMigrationRun; +use frame_support::{traits::Get, weights::Weight}; +use scale_info::prelude::string::String; + +pub fn migrate_set_last_emission_block_number() -> Weight { + let migration_name = b"migrate_set_last_emission_block_number".to_vec(); + + let mut weight = T::DbWeight::get().reads(1); + if HasMigrationRun::::get(&migration_name) { + log::info!( + "Migration '{:?}' has already run. Skipping.", + String::from_utf8_lossy(&migration_name) + ); + return weight; + } + + log::info!( + "Running migration '{:?}'", + String::from_utf8_lossy(&migration_name) + ); + + // ------------------------------ + // Step 1: Set the last emission block for all subnets except root + // ------------------------------ + let netuids = Pallet::::get_all_subnet_netuids(); + let current_block_number = Pallet::::get_current_block_as_u64(); + for netuid in netuids.iter() { + if *netuid != 0 { + LastEmissionBlockNumber::::insert(netuid, current_block_number); + } + } + + // ------------------------------ + // Step 2: Mark Migration as Completed + // ------------------------------ + + HasMigrationRun::::insert(&migration_name, true); + weight = weight.saturating_add(T::DbWeight::get().reads(2)); + + if netuids.is_empty() { + weight = weight.saturating_add(T::DbWeight::get().writes(1_u64)); + } else { + weight = weight.saturating_add(T::DbWeight::get().writes(netuids.len() as u64)); + } + + log::info!( + "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 6af6ad2a56..cada8a9997 100644 --- a/pallets/subtensor/src/migrations/mod.rs +++ b/pallets/subtensor/src/migrations/mod.rs @@ -11,6 +11,7 @@ pub mod migrate_populate_owned_hotkeys; pub mod migrate_rao; pub mod migrate_remove_stake_map; pub mod migrate_remove_unused_maps_and_values; +pub mod migrate_set_last_emission_block_number; pub mod migrate_set_min_burn; pub mod migrate_set_min_difficulty; pub mod migrate_stake_threshold; diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index bf1806da14..f7f26e97e1 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -320,4 +320,38 @@ impl Pallet { ); } } + + /// Initiates a call on a subnet. + /// + pub fn do_start_call(origin: T::RuntimeOrigin, netuid: u16) -> DispatchResult { + ensure!( + Self::if_subnet_exist(netuid), + Error::::SubNetworkDoesNotExist + ); + Self::ensure_subnet_owner(origin, netuid)?; + ensure!( + LastEmissionBlockNumber::::get(netuid).is_none(), + Error::::LastEmissionBlockNumberAlreadySet + ); + + let registration_block_number = NetworkRegisteredAt::::get(netuid); + let current_block_number = Self::get_current_block_as_u64(); + + ensure!( + current_block_number + > registration_block_number.saturating_add(T::DurationOfStartCall::get()), + Error::::NeedMoreBlocksToStarCall + ); + + LastEmissionBlockNumber::::insert(netuid, current_block_number); + Self::deposit_event(Event::LastEmissionBlockNumberSet( + netuid, + current_block_number, + )); + Ok(()) + } + + pub fn is_valid_subnet_for_emission(netuid: u16) -> bool { + LastEmissionBlockNumber::::get(netuid).is_some() + } } diff --git a/pallets/subtensor/src/tests/migration.rs b/pallets/subtensor/src/tests/migration.rs index c0cbe1b81a..549bc329dd 100644 --- a/pallets/subtensor/src/tests/migration.rs +++ b/pallets/subtensor/src/tests/migration.rs @@ -11,6 +11,7 @@ use frame_support::{ traits::{StorageInstance, StoredMap}, weights::Weight, }; + use frame_system::Config; use sp_core::{H256, U256, crypto::Ss58Codec}; use sp_io::hashing::twox_128; @@ -416,3 +417,24 @@ fn test_migrate_subnet_volume() { assert_eq!(new_value, Some(old_value as u128)); }); } + +#[test] +fn test_migrate_set_last_emission_block_number() { + new_test_ext(1).execute_with(|| { + let netuids: [u16; 3] = [1, 2, 3]; + let block_number = 100; + for netuid in netuids.iter() { + add_network(*netuid, 1, 0); + } + run_to_block(block_number); + let weight = crate::migrations::migrate_set_last_emission_block_number::migrate_set_last_emission_block_number::(); + + let expected_weight: Weight = ::DbWeight::get().reads(3) + ::DbWeight::get().writes(netuids.len() as u64); + assert_eq!(weight, expected_weight); + + assert_eq!(LastEmissionBlockNumber::::get(0), None); + for netuid in netuids.iter() { + assert_eq!(LastEmissionBlockNumber::::get(netuid), Some(block_number)); + } +}); +} diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 0d979a6126..8afffb2a48 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -185,6 +185,7 @@ parameter_types! { pub const InitialDissolveNetworkScheduleDuration: u64 = 5 * 24 * 60 * 60 / 12; // Default as 5 days pub const InitialTaoWeight: u64 = 0; // 100% global weight. pub const InitialEmaPriceHalvingPeriod: u64 = 201_600_u64; // 4 weeks + pub const DurationOfStartCall: u64 = 7 * 24 * 60 * 60 / 12; // Default as 7 days } // Configure collective pallet for council @@ -408,6 +409,7 @@ impl crate::Config for Test { type InitialDissolveNetworkScheduleDuration = InitialDissolveNetworkScheduleDuration; type InitialTaoWeight = InitialTaoWeight; type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod; + type DurationOfStartCall = DurationOfStartCall; } pub struct OriginPrivilegeCmp; diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 25799a75c1..f9e05b66b3 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1018,6 +1018,7 @@ parameter_types! { pub const InitialDissolveNetworkScheduleDuration: BlockNumber = 5 * 24 * 60 * 60 / 12; // 5 days pub const SubtensorInitialTaoWeight: u64 = 971_718_665_099_567_868; // 0.05267697438728329% tao weight. pub const InitialEmaPriceHalvingPeriod: u64 = 201_600_u64; // 4 weeks + pub const DurationOfStartCall: u64 = 7 * 24 * 60 * 60 / 12; // 7 days } impl pallet_subtensor::Config for Runtime { @@ -1082,6 +1083,7 @@ impl pallet_subtensor::Config for Runtime { type InitialColdkeySwapScheduleDuration = InitialColdkeySwapScheduleDuration; type InitialDissolveNetworkScheduleDuration = InitialDissolveNetworkScheduleDuration; type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod; + type DurationOfStartCall = DurationOfStartCall; } use sp_runtime::BoundedVec; From dbce5ac0a496bddb4cf2af9e456443a8fba3dc45 Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 20 Mar 2025 12:22:57 +0800 Subject: [PATCH 02/13] commit Cargo.lock --- pallets/admin-utils/src/tests/mock.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pallets/admin-utils/src/tests/mock.rs b/pallets/admin-utils/src/tests/mock.rs index fc0d016198..43a40ec32e 100644 --- a/pallets/admin-utils/src/tests/mock.rs +++ b/pallets/admin-utils/src/tests/mock.rs @@ -135,6 +135,7 @@ parameter_types! { pub const InitialDissolveNetworkScheduleDuration: u64 = 5 * 24 * 60 * 60 / 12; // 5 days pub const InitialTaoWeight: u64 = u64::MAX/10; // 10% global weight. pub const InitialEmaPriceHalvingPeriod: u64 = 201_600_u64; // 4 weeks + pub const DurationOfStartCall: u64 = 7 * 24 * 60 * 60 / 12; // 7 days } impl pallet_subtensor::Config for Test { @@ -199,6 +200,7 @@ impl pallet_subtensor::Config for Test { type InitialDissolveNetworkScheduleDuration = InitialDissolveNetworkScheduleDuration; type InitialTaoWeight = InitialTaoWeight; type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod; + type DurationOfStartCall = DurationOfStartCall; } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] From 93dcb79fc3e2deab06e1c30c289c6ff2b757e325 Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 20 Mar 2025 13:07:33 +0800 Subject: [PATCH 03/13] fix test cases --- pallets/subtensor/src/tests/mock.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 8afffb2a48..297f67c84a 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -664,6 +664,7 @@ pub fn add_network(netuid: u16, tempo: u16, _modality: u16) { SubtensorModule::init_new_network(netuid, tempo); SubtensorModule::set_network_registration_allowed(netuid, true); SubtensorModule::set_network_pow_registration_allowed(netuid, true); + LastEmissionBlockNumber::::insert(netuid, 0); } #[allow(dead_code)] @@ -678,6 +679,7 @@ pub fn add_dynamic_network(hotkey: &U256, coldkey: &U256) -> u16 { )); NetworkRegistrationAllowed::::insert(netuid, true); NetworkPowRegistrationAllowed::::insert(netuid, true); + LastEmissionBlockNumber::::insert(netuid, 0); netuid } From d4d6748be639409dd0432828c5e1e7097db107d8 Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 20 Mar 2025 13:10:29 +0800 Subject: [PATCH 04/13] update runtime version --- 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 251d4537ba..8b390aaa59 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -205,7 +205,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: 253, + spec_version: 254, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From d6321c0e8d407660e616111357aec81adceb34ef Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 20 Mar 2025 18:24:05 +0800 Subject: [PATCH 05/13] commit Cargo.lock --- .../subtensor/src/coinbase/run_coinbase.rs | 3 +++ pallets/subtensor/src/macros/dispatches.rs | 2 +- pallets/subtensor/src/macros/errors.rs | 2 +- pallets/subtensor/src/subnets/subnet.rs | 4 ++-- pallets/subtensor/src/tests/mock.rs | 22 +++++++++++++++++++ pallets/subtensor/src/tests/mod.rs | 1 + 6 files changed, 30 insertions(+), 4 deletions(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 92d7e3722a..f5292281db 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -245,6 +245,9 @@ impl Pallet { pending_swapped, owner_cut, ); + + // Set last emission block + LastEmissionBlockNumber::::insert(netuid, Self::get_current_block_as_u64()) } else { // Increment BlocksSinceLastStep::::mutate(netuid, |total| *total = total.saturating_add(1)); diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index ed7507ffc9..51d5dcecf0 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1919,7 +1919,7 @@ mod dispatches { Pays::Yes ))] pub fn start_call(origin: T::RuntimeOrigin, netuid: u16) -> DispatchResult { - let _ = Self::do_start_call(origin, netuid); + Self::do_start_call(origin, netuid)?; Ok(()) } diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index c2696fcb8b..f0e40d4207 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -198,7 +198,7 @@ mod errors { /// LastEmissionBlockNumber is already set. LastEmissionBlockNumberAlreadySet, /// need wait for more blocks to accept the start call extrinsic. - NeedMoreBlocksToStarCall, + NeedWaitingMoreBlocksToStarCall, /// Not enough AlphaOut on the subnet to recycle NotEnoughAlphaOutToRecycle, } diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index f7f26e97e1..3f6a58371f 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -339,8 +339,8 @@ impl Pallet { ensure!( current_block_number - > registration_block_number.saturating_add(T::DurationOfStartCall::get()), - Error::::NeedMoreBlocksToStarCall + >= registration_block_number.saturating_add(T::DurationOfStartCall::get()), + Error::::NeedWaitingMoreBlocksToStarCall ); LastEmissionBlockNumber::::insert(netuid, current_block_number); diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 297f67c84a..525ab2b58d 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -667,6 +667,13 @@ pub fn add_network(netuid: u16, tempo: u16, _modality: u16) { LastEmissionBlockNumber::::insert(netuid, 0); } +#[allow(dead_code)] +pub fn add_network_without_emission_block(netuid: u16, tempo: u16, _modality: u16) { + SubtensorModule::init_new_network(netuid, tempo); + SubtensorModule::set_network_registration_allowed(netuid, true); + SubtensorModule::set_network_pow_registration_allowed(netuid, true); +} + #[allow(dead_code)] pub fn add_dynamic_network(hotkey: &U256, coldkey: &U256) -> u16 { let netuid = SubtensorModule::get_next_netuid(); @@ -683,6 +690,21 @@ pub fn add_dynamic_network(hotkey: &U256, coldkey: &U256) -> u16 { netuid } +#[allow(dead_code)] +pub fn add_dynamic_network_without_emission_block(hotkey: &U256, coldkey: &U256) -> u16 { + let netuid = SubtensorModule::get_next_netuid(); + let lock_cost = SubtensorModule::get_network_lock_cost(); + SubtensorModule::add_balance_to_coldkey_account(coldkey, lock_cost); + + assert_ok!(SubtensorModule::register_network( + RawOrigin::Signed(*coldkey).into(), + *hotkey + )); + NetworkRegistrationAllowed::::insert(netuid, true); + NetworkPowRegistrationAllowed::::insert(netuid, true); + netuid +} + // Helper function to set up a neuron with stake #[allow(dead_code)] pub fn setup_neuron_with_stake(netuid: u16, hotkey: U256, coldkey: U256, stake: u64) { diff --git a/pallets/subtensor/src/tests/mod.rs b/pallets/subtensor/src/tests/mod.rs index 8a9fa6b103..efd45ddef1 100644 --- a/pallets/subtensor/src/tests/mod.rs +++ b/pallets/subtensor/src/tests/mod.rs @@ -17,6 +17,7 @@ mod senate; mod serving; mod staking; mod staking2; +mod subnet; mod swap_coldkey; mod swap_hotkey; mod uids; From fdbbcec9d162fc53b108d009f5e5db3d6570bf76 Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 20 Mar 2025 18:24:34 +0800 Subject: [PATCH 06/13] more unit test --- pallets/subtensor/src/tests/subnet.rs | 222 ++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 pallets/subtensor/src/tests/subnet.rs diff --git a/pallets/subtensor/src/tests/subnet.rs b/pallets/subtensor/src/tests/subnet.rs new file mode 100644 index 0000000000..978c0509dd --- /dev/null +++ b/pallets/subtensor/src/tests/subnet.rs @@ -0,0 +1,222 @@ +use super::mock::*; +use crate::*; +use frame_support::{assert_noop, assert_ok}; +use frame_system::Config; +use sp_core::U256; + +/*************************** + pub fn do_start_call() tests +*****************************/ + +#[test] +fn test_do_start_call_ok() { + new_test_ext(0).execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + let coldkey_account_id = U256::from(0); + let hotkey_account_id = U256::from(1); + let burn_cost = 1000; + //add network + SubtensorModule::set_burn(netuid, burn_cost); + add_network_without_emission_block(netuid, tempo, 0); + assert_eq!(LastEmissionBlockNumber::::get(netuid), None); + + // Give it some $$$ in his coldkey balance + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); + + // Subscribe and check extrinsic output + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid, + hotkey_account_id + )); + + assert_eq!(SubnetOwner::::get(netuid), coldkey_account_id); + + let block_number = System::block_number() + DurationOfStartCall::get(); + System::set_block_number(block_number); + + assert_ok!(SubtensorModule::start_call( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid + )); + + assert_eq!( + LastEmissionBlockNumber::::get(netuid), + Some(block_number) + ); + }); +} + +#[test] +fn test_do_start_call_fail_with_not_existed_subnet() { + new_test_ext(0).execute_with(|| { + let netuid: u16 = 1; + let coldkey_account_id = U256::from(0); + assert_noop!( + SubtensorModule::start_call( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid + ), + Error::::SubNetworkDoesNotExist + ); + }); +} + +#[test] +fn test_do_start_call_fail_not_owner() { + new_test_ext(0).execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + let coldkey_account_id = U256::from(0); + let hotkey_account_id = U256::from(1); + let wrong_owner_account_id = U256::from(2); + let burn_cost = 1000; + //add network + SubtensorModule::set_burn(netuid, burn_cost); + add_network_without_emission_block(netuid, tempo, 0); + // Give it some $$$ in his coldkey balance + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); + + // Subscribe and check extrinsic output + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid, + hotkey_account_id + )); + + assert_eq!(SubnetOwner::::get(netuid), coldkey_account_id); + + System::set_block_number(System::block_number() + DurationOfStartCall::get()); + + assert_noop!( + SubtensorModule::start_call( + <::RuntimeOrigin>::signed(wrong_owner_account_id), + netuid + ), + DispatchError::BadOrigin + ); + }); +} + +#[test] +fn test_do_start_call_fail_with_cannot_start_call_now() { + new_test_ext(0).execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + let coldkey_account_id = U256::from(0); + let hotkey_account_id = U256::from(1); + let burn_cost = 1000; + //add network + SubtensorModule::set_burn(netuid, burn_cost); + add_network_without_emission_block(netuid, tempo, 0); + // Give it some $$$ in his coldkey balance + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); + + // Subscribe and check extrinsic output + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid, + hotkey_account_id + )); + + assert_eq!(SubnetOwner::::get(netuid), coldkey_account_id); + + assert_noop!( + SubtensorModule::start_call( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid + ), + Error::::NeedWaitingMoreBlocksToStarCall + ); + }); +} + +#[test] +fn test_do_start_call_fail_for_set_again() { + new_test_ext(0).execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + let coldkey_account_id = U256::from(0); + let hotkey_account_id = U256::from(1); + let burn_cost = 1000; + //add network + SubtensorModule::set_burn(netuid, burn_cost); + add_network_without_emission_block(netuid, tempo, 0); + assert_eq!(LastEmissionBlockNumber::::get(netuid), None); + + // Give it some $$$ in his coldkey balance + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); + + // Subscribe and check extrinsic output + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid, + hotkey_account_id + )); + + assert_eq!(SubnetOwner::::get(netuid), coldkey_account_id); + + let block_number = System::block_number() + DurationOfStartCall::get(); + System::set_block_number(block_number); + + assert_ok!(SubtensorModule::start_call( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid + )); + + assert_noop!( + SubtensorModule::start_call( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid + ), + Error::::LastEmissionBlockNumberAlreadySet + ); + }); +} + +#[test] +fn test_do_start_call_ok_with_updated_block_number_after_coinbase() { + new_test_ext(0).execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + let coldkey_account_id = U256::from(0); + let hotkey_account_id = U256::from(1); + let burn_cost = 1000; + //add network + SubtensorModule::set_burn(netuid, burn_cost); + add_network_without_emission_block(netuid, tempo, 0); + assert_eq!(LastEmissionBlockNumber::::get(netuid), None); + + // Give it some $$$ in his coldkey balance + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); + + // Subscribe and check extrinsic output + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid, + hotkey_account_id + )); + + assert_eq!(SubnetOwner::::get(netuid), coldkey_account_id); + + let block_number = System::block_number() + DurationOfStartCall::get(); + System::set_block_number(block_number); + + assert_ok!(SubtensorModule::start_call( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid + )); + + assert_eq!( + LastEmissionBlockNumber::::get(netuid), + Some(block_number) + ); + + step_block(tempo); + match LastEmissionBlockNumber::::get(netuid) { + Some(new_emission_block_number) => assert!(new_emission_block_number > block_number), + None => assert!(LastEmissionBlockNumber::::get(netuid).is_some()), + } + }); +} From b38e79d1b0fce003a5224f215a49da89a2b13e99 Mon Sep 17 00:00:00 2001 From: open-junius Date: Thu, 20 Mar 2025 22:58:28 +0800 Subject: [PATCH 07/13] add doc --- pallets/subtensor/src/macros/dispatches.rs | 7 ++++++- pallets/subtensor/src/subnets/subnet.rs | 21 ++++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 51d5dcecf0..5b9eb14e1d 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1912,6 +1912,12 @@ mod dispatches { /// Initiates a call on a subnet. /// + /// # Arguments + /// * `origin` - The origin of the call, which must be signed by the subnet owner. + /// * `netuid` - The unique identifier of the subnet on which the call is being initiated. + /// + /// # Events + /// Emits a `CallInitiated` event on success. #[pallet::call_index(92)] #[pallet::weight(( Weight::from_parts(3_000_000, 0).saturating_add(T::DbWeight::get().reads_writes(3, 3)), @@ -1920,7 +1926,6 @@ mod dispatches { ))] pub fn start_call(origin: T::RuntimeOrigin, netuid: u16) -> DispatchResult { Self::do_start_call(origin, netuid)?; - Ok(()) } diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index 3f6a58371f..fc29703cc7 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -321,8 +321,27 @@ impl Pallet { } } - /// Initiates a call on a subnet. + /// Execute the start call for a subnet. /// + /// This function is used to trigger the start call process for a subnet identified by `netuid`. + /// It ensures that the subnet exists, the caller is the subnet owner, + /// and the last emission block number has not been set yet. + /// It then sets the last emission block number to the current block number. + /// + /// # Parameters + /// + /// * `origin`: The origin of the call, which is used to ensure the caller is the subnet owner. + /// * `netuid`: The unique identifier of the subnet for which the start call process is being initiated. + /// + /// # Raises + /// + /// * `Error::::SubNetworkDoesNotExist`: If the subnet does not exist. + /// * `DispatchError::BadOrigin`: If the caller is not the subnet owner. + /// * `Error::::LastEmissionBlockNumberAlreadySet`: If the last emission block number has already been set. + /// + /// # Returns + /// + /// * `DispatchResult`: A result indicating the success or failure of the operation. pub fn do_start_call(origin: T::RuntimeOrigin, netuid: u16) -> DispatchResult { ensure!( Self::if_subnet_exist(netuid), From c86de44c0e23c6fcfb5db0e4e84aad51393d5e5f Mon Sep 17 00:00:00 2001 From: open-junius Date: Fri, 21 Mar 2025 15:04:36 +0800 Subject: [PATCH 08/13] benchmark file update --- pallets/subtensor/src/benchmarks.rs | 33 ++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 47dd7a5bc5..de8bd251f2 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -6,7 +6,7 @@ use crate::Pallet as Subtensor; use crate::*; use frame_benchmarking::{account, benchmarks, whitelisted_caller}; use frame_support::assert_ok; -use frame_system::RawOrigin; +use frame_system::{RawOrigin, pallet_prelude::BlockNumberFor}; pub use pallet::*; use sp_core::H256; use sp_runtime::traits::{BlakeTwo256, Hash}; @@ -658,4 +658,35 @@ benchmark_burn_alpha { }: burn_alpha(RawOrigin::Signed(coldkey), hotkey, alpha_amount, netuid) + +benchmark_start_call { + let caller: T::AccountId = whitelisted_caller::>(); + let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); + let netuid: u16 = 1; + let tempo: u16 = 1; + let seed: u32 = 1; + + // Set up coldkey and hotkey + let coldkey: T::AccountId = account("Test", 0, seed); + let hotkey: T::AccountId = account("Alice", 0, seed); + + // Initialize network + Subtensor::::init_new_network(netuid, tempo); + Subtensor::::set_network_registration_allowed(netuid, true); + + // Register the neuron + Subtensor::::set_burn(netuid, 1); + let amount_to_be_staked = 1000000u32.into(); + Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), amount_to_be_staked); + + assert_ok!(Subtensor::::do_burned_registration(RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone())); + assert_eq!(SubnetOwner::::get(netuid), coldkey.clone()); + assert_eq!(LastEmissionBlockNumber::::get(netuid), None); + let current_block: u64 = Subtensor::::get_current_block_as_u64(); + let duration = ::DurationOfStartCall::get(); + let block: BlockNumberFor = (current_block + duration).try_into().ok().expect(""); + frame_system::Pallet::::set_block_number(block); + +}: start_call(RawOrigin::Signed(coldkey), netuid) + } From abc3603752d914c337cefaa37936602883e03409 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 24 Mar 2025 09:42:10 +0800 Subject: [PATCH 09/13] rename the storage --- pallets/subtensor/src/benchmarks.rs | 2 +- .../subtensor/src/coinbase/run_coinbase.rs | 5 +---- pallets/subtensor/src/lib.rs | 2 +- pallets/subtensor/src/macros/dispatches.rs | 2 +- pallets/subtensor/src/macros/errors.rs | 4 ++-- pallets/subtensor/src/macros/events.rs | 4 ++-- .../migrate_set_last_emission_block_number.rs | 2 +- pallets/subtensor/src/subnets/subnet.rs | 14 ++++++------- pallets/subtensor/src/tests/migration.rs | 4 ++-- pallets/subtensor/src/tests/mock.rs | 4 ++-- pallets/subtensor/src/tests/subnet.rs | 20 +++++++++---------- 11 files changed, 30 insertions(+), 33 deletions(-) diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index de8bd251f2..1e0339268f 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -681,7 +681,7 @@ benchmark_start_call { assert_ok!(Subtensor::::do_burned_registration(RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone())); assert_eq!(SubnetOwner::::get(netuid), coldkey.clone()); - assert_eq!(LastEmissionBlockNumber::::get(netuid), None); + assert_eq!(FirstEmissionBlockNumber::::get(netuid), None); let current_block: u64 = Subtensor::::get_current_block_as_u64(); let duration = ::DurationOfStartCall::get(); let block: BlockNumberFor = (current_block + duration).try_into().ok().expect(""); diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index f5292281db..c33b0897a7 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -41,7 +41,7 @@ impl Pallet { let subnets: Vec = Self::get_all_subnet_netuids() .into_iter() .filter(|netuid| *netuid != 0) - .filter(|netuid| LastEmissionBlockNumber::::get(*netuid).is_some()) + .filter(|netuid| FirstEmissionBlockNumber::::get(*netuid).is_some()) .collect(); log::debug!("All subnet netuids: {:?}", subnets); @@ -245,9 +245,6 @@ impl Pallet { pending_swapped, owner_cut, ); - - // Set last emission block - LastEmissionBlockNumber::::insert(netuid, Self::get_current_block_as_u64()) } else { // Increment BlocksSinceLastStep::::mutate(netuid, |total| *total = total.saturating_add(1)); diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 3df312f92b..604b68ec3b 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1127,7 +1127,7 @@ pub mod pallet { /// ============================ /// --- MAP ( netuid ) --> block number of last emission #[pallet::storage] - pub type LastEmissionBlockNumber = StorageMap<_, Identity, u16, u64, OptionQuery>; + pub type FirstEmissionBlockNumber = StorageMap<_, Identity, u16, u64, OptionQuery>; /// --- MAP ( netuid ) --> subnet mechanism #[pallet::storage] pub type SubnetMechanism = diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 5b9eb14e1d..6b12b529cf 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1920,7 +1920,7 @@ mod dispatches { /// Emits a `CallInitiated` event on success. #[pallet::call_index(92)] #[pallet::weight(( - Weight::from_parts(3_000_000, 0).saturating_add(T::DbWeight::get().reads_writes(3, 3)), + Weight::from_parts(3_000_000, 0).saturating_add(T::DbWeight::get().reads_writes(6, 1)), DispatchClass::Operational, Pays::Yes ))] diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index f0e40d4207..ef965bf169 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -195,8 +195,8 @@ mod errors { ActivityCutoffTooLow, /// Call is disabled CallDisabled, - /// LastEmissionBlockNumber is already set. - LastEmissionBlockNumberAlreadySet, + /// FirstEmissionBlockNumber is already set. + FirstEmissionBlockNumberAlreadySet, /// need wait for more blocks to accept the start call extrinsic. NeedWaitingMoreBlocksToStarCall, /// Not enough AlphaOut on the subnet to recycle diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index 74a32932b4..04a2093abf 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -275,12 +275,12 @@ mod events { /// Parameters: /// (netuid, new_hotkey) SubnetOwnerHotkeySet(u16, T::AccountId), - /// LastEmissionBlockNumber is set via start call extrinsic + /// FirstEmissionBlockNumber is set via start call extrinsic /// /// Parameters: /// netuid /// block number - LastEmissionBlockNumberSet(u16, u64), + FirstEmissionBlockNumberSet(u16, u64), /// Alpha has been recycled, reducing AlphaOut on a subnet. /// diff --git a/pallets/subtensor/src/migrations/migrate_set_last_emission_block_number.rs b/pallets/subtensor/src/migrations/migrate_set_last_emission_block_number.rs index bc1f7b9abd..00e60a13cf 100644 --- a/pallets/subtensor/src/migrations/migrate_set_last_emission_block_number.rs +++ b/pallets/subtensor/src/migrations/migrate_set_last_emission_block_number.rs @@ -27,7 +27,7 @@ pub fn migrate_set_last_emission_block_number() -> Weight { let current_block_number = Pallet::::get_current_block_as_u64(); for netuid in netuids.iter() { if *netuid != 0 { - LastEmissionBlockNumber::::insert(netuid, current_block_number); + FirstEmissionBlockNumber::::insert(netuid, current_block_number); } } diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index fc29703cc7..58f3f9c6a1 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -337,7 +337,7 @@ impl Pallet { /// /// * `Error::::SubNetworkDoesNotExist`: If the subnet does not exist. /// * `DispatchError::BadOrigin`: If the caller is not the subnet owner. - /// * `Error::::LastEmissionBlockNumberAlreadySet`: If the last emission block number has already been set. + /// * `Error::::FirstEmissionBlockNumberAlreadySet`: If the last emission block number has already been set. /// /// # Returns /// @@ -349,8 +349,8 @@ impl Pallet { ); Self::ensure_subnet_owner(origin, netuid)?; ensure!( - LastEmissionBlockNumber::::get(netuid).is_none(), - Error::::LastEmissionBlockNumberAlreadySet + FirstEmissionBlockNumber::::get(netuid).is_none(), + Error::::FirstEmissionBlockNumberAlreadySet ); let registration_block_number = NetworkRegisteredAt::::get(netuid); @@ -362,15 +362,15 @@ impl Pallet { Error::::NeedWaitingMoreBlocksToStarCall ); - LastEmissionBlockNumber::::insert(netuid, current_block_number); - Self::deposit_event(Event::LastEmissionBlockNumberSet( + FirstEmissionBlockNumber::::insert(netuid, current_block_number + 1); + Self::deposit_event(Event::FirstEmissionBlockNumberSet( netuid, - current_block_number, + current_block_number + 1, )); Ok(()) } pub fn is_valid_subnet_for_emission(netuid: u16) -> bool { - LastEmissionBlockNumber::::get(netuid).is_some() + FirstEmissionBlockNumber::::get(netuid).is_some() } } diff --git a/pallets/subtensor/src/tests/migration.rs b/pallets/subtensor/src/tests/migration.rs index 549bc329dd..3864657432 100644 --- a/pallets/subtensor/src/tests/migration.rs +++ b/pallets/subtensor/src/tests/migration.rs @@ -432,9 +432,9 @@ fn test_migrate_set_last_emission_block_number() { let expected_weight: Weight = ::DbWeight::get().reads(3) + ::DbWeight::get().writes(netuids.len() as u64); assert_eq!(weight, expected_weight); - assert_eq!(LastEmissionBlockNumber::::get(0), None); + assert_eq!(FirstEmissionBlockNumber::::get(0), None); for netuid in netuids.iter() { - assert_eq!(LastEmissionBlockNumber::::get(netuid), Some(block_number)); + assert_eq!(FirstEmissionBlockNumber::::get(netuid), Some(block_number)); } }); } diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 525ab2b58d..04d6888595 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -664,7 +664,7 @@ pub fn add_network(netuid: u16, tempo: u16, _modality: u16) { SubtensorModule::init_new_network(netuid, tempo); SubtensorModule::set_network_registration_allowed(netuid, true); SubtensorModule::set_network_pow_registration_allowed(netuid, true); - LastEmissionBlockNumber::::insert(netuid, 0); + FirstEmissionBlockNumber::::insert(netuid, 0); } #[allow(dead_code)] @@ -686,7 +686,7 @@ pub fn add_dynamic_network(hotkey: &U256, coldkey: &U256) -> u16 { )); NetworkRegistrationAllowed::::insert(netuid, true); NetworkPowRegistrationAllowed::::insert(netuid, true); - LastEmissionBlockNumber::::insert(netuid, 0); + FirstEmissionBlockNumber::::insert(netuid, 0); netuid } diff --git a/pallets/subtensor/src/tests/subnet.rs b/pallets/subtensor/src/tests/subnet.rs index 978c0509dd..2378062b55 100644 --- a/pallets/subtensor/src/tests/subnet.rs +++ b/pallets/subtensor/src/tests/subnet.rs @@ -19,7 +19,7 @@ fn test_do_start_call_ok() { //add network SubtensorModule::set_burn(netuid, burn_cost); add_network_without_emission_block(netuid, tempo, 0); - assert_eq!(LastEmissionBlockNumber::::get(netuid), None); + assert_eq!(FirstEmissionBlockNumber::::get(netuid), None); // Give it some $$$ in his coldkey balance SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); @@ -42,8 +42,8 @@ fn test_do_start_call_ok() { )); assert_eq!( - LastEmissionBlockNumber::::get(netuid), - Some(block_number) + FirstEmissionBlockNumber::::get(netuid), + Some(block_number + 1) ); }); } @@ -143,7 +143,7 @@ fn test_do_start_call_fail_for_set_again() { //add network SubtensorModule::set_burn(netuid, burn_cost); add_network_without_emission_block(netuid, tempo, 0); - assert_eq!(LastEmissionBlockNumber::::get(netuid), None); + assert_eq!(FirstEmissionBlockNumber::::get(netuid), None); // Give it some $$$ in his coldkey balance SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); @@ -170,7 +170,7 @@ fn test_do_start_call_fail_for_set_again() { <::RuntimeOrigin>::signed(coldkey_account_id), netuid ), - Error::::LastEmissionBlockNumberAlreadySet + Error::::FirstEmissionBlockNumberAlreadySet ); }); } @@ -186,7 +186,7 @@ fn test_do_start_call_ok_with_updated_block_number_after_coinbase() { //add network SubtensorModule::set_burn(netuid, burn_cost); add_network_without_emission_block(netuid, tempo, 0); - assert_eq!(LastEmissionBlockNumber::::get(netuid), None); + assert_eq!(FirstEmissionBlockNumber::::get(netuid), None); // Give it some $$$ in his coldkey balance SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); @@ -209,14 +209,14 @@ fn test_do_start_call_ok_with_updated_block_number_after_coinbase() { )); assert_eq!( - LastEmissionBlockNumber::::get(netuid), - Some(block_number) + FirstEmissionBlockNumber::::get(netuid), + Some(block_number + 1) ); step_block(tempo); - match LastEmissionBlockNumber::::get(netuid) { + match FirstEmissionBlockNumber::::get(netuid) { Some(new_emission_block_number) => assert!(new_emission_block_number > block_number), - None => assert!(LastEmissionBlockNumber::::get(netuid).is_some()), + None => assert!(FirstEmissionBlockNumber::::get(netuid).is_some()), } }); } From 9d8877f65a7868c63a6a42af84c9ca911f208dd0 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 24 Mar 2025 09:54:00 +0800 Subject: [PATCH 10/13] cargo fix --- pallets/subtensor/src/subnets/subnet.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index 58f3f9c6a1..310c1d5fde 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -361,11 +361,12 @@ impl Pallet { >= registration_block_number.saturating_add(T::DurationOfStartCall::get()), Error::::NeedWaitingMoreBlocksToStarCall ); + let next_block_number = current_block_number.saturating_add(1); - FirstEmissionBlockNumber::::insert(netuid, current_block_number + 1); + FirstEmissionBlockNumber::::insert(netuid, next_block_number); Self::deposit_event(Event::FirstEmissionBlockNumberSet( netuid, - current_block_number + 1, + next_block_number, )); Ok(()) } From b8c8da75a4c4eb96491cfff421dab16f0f28b449 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 24 Mar 2025 20:02:38 +0800 Subject: [PATCH 11/13] commit Cargo.lock --- pallets/subtensor/src/benchmarks.rs | 2 +- .../subtensor/src/coinbase/run_coinbase.rs | 2 +- pallets/subtensor/src/lib.rs | 2 +- pallets/subtensor/src/macros/config.rs | 2 +- pallets/subtensor/src/macros/dispatches.rs | 2 +- pallets/subtensor/src/macros/hooks.rs | 2 +- .../migrate_set_last_emission_block_number.rs | 53 ------------------- pallets/subtensor/src/migrations/mod.rs | 2 +- pallets/subtensor/src/tests/migration.rs | 4 +- pallets/subtensor/src/tests/mock.rs | 2 +- 10 files changed, 10 insertions(+), 63 deletions(-) delete mode 100644 pallets/subtensor/src/migrations/migrate_set_last_emission_block_number.rs diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 1e0339268f..8d4457b0c9 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -684,7 +684,7 @@ benchmark_start_call { assert_eq!(FirstEmissionBlockNumber::::get(netuid), None); let current_block: u64 = Subtensor::::get_current_block_as_u64(); let duration = ::DurationOfStartCall::get(); - let block: BlockNumberFor = (current_block + duration).try_into().ok().expect(""); + let block: BlockNumberFor = (current_block + duration).try_into().ok().expect("can't convert to block number"); frame_system::Pallet::::set_block_number(block); }: start_call(RawOrigin::Signed(coldkey), netuid) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index c33b0897a7..7a29d4959a 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -37,7 +37,7 @@ impl Pallet { let current_block: u64 = Self::get_current_block_as_u64(); log::debug!("Current block: {:?}", current_block); - // --- 1. Get all netuids (filter out root and new subnet) + // --- 1. Get all netuids (filter out root and new subnet without first emission block) let subnets: Vec = Self::get_all_subnet_netuids() .into_iter() .filter(|netuid| *netuid != 0) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 604b68ec3b..1ec9cadb0a 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1125,7 +1125,7 @@ pub mod pallet { /// ============================ /// ==== Subnet Parameters ===== /// ============================ - /// --- MAP ( netuid ) --> block number of last emission + /// --- MAP ( netuid ) --> block number of first emission #[pallet::storage] pub type FirstEmissionBlockNumber = StorageMap<_, Identity, u16, u64, OptionQuery>; /// --- MAP ( netuid ) --> subnet mechanism diff --git a/pallets/subtensor/src/macros/config.rs b/pallets/subtensor/src/macros/config.rs index 889c7e5c5f..cf4d97b65b 100644 --- a/pallets/subtensor/src/macros/config.rs +++ b/pallets/subtensor/src/macros/config.rs @@ -210,7 +210,7 @@ mod config { /// Initial EMA price halving period #[pallet::constant] type InitialEmaPriceHalvingPeriod: Get; - /// Block number for a new subnet accept the start call extrinsic. + /// Block number after a new subnet accept the start call extrinsic. #[pallet::constant] type DurationOfStartCall: Get; } diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 6b12b529cf..9158073e17 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1917,7 +1917,7 @@ mod dispatches { /// * `netuid` - The unique identifier of the subnet on which the call is being initiated. /// /// # Events - /// Emits a `CallInitiated` event on success. + /// Emits a `FirstEmissionBlockNumberSet` event on success. #[pallet::call_index(92)] #[pallet::weight(( Weight::from_parts(3_000_000, 0).saturating_add(T::DbWeight::get().reads_writes(6, 1)), diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index 68cd2a7623..3203ae312c 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -83,7 +83,7 @@ mod hooks { // Remove unused maps entries .saturating_add(migrations::migrate_remove_unused_maps_and_values::migrate_remove_unused_maps_and_values::()) // Set last emission block number for all existed subnets before start call feature applied - .saturating_add(migrations::migrate_set_last_emission_block_number::migrate_set_last_emission_block_number::()); + .saturating_add(migrations::migrate_set_first_emission_block_number::migrate_set_first_emission_block_number::()); weight } diff --git a/pallets/subtensor/src/migrations/migrate_set_last_emission_block_number.rs b/pallets/subtensor/src/migrations/migrate_set_last_emission_block_number.rs deleted file mode 100644 index 00e60a13cf..0000000000 --- a/pallets/subtensor/src/migrations/migrate_set_last_emission_block_number.rs +++ /dev/null @@ -1,53 +0,0 @@ -use super::*; -use crate::HasMigrationRun; -use frame_support::{traits::Get, weights::Weight}; -use scale_info::prelude::string::String; - -pub fn migrate_set_last_emission_block_number() -> Weight { - let migration_name = b"migrate_set_last_emission_block_number".to_vec(); - - let mut weight = T::DbWeight::get().reads(1); - if HasMigrationRun::::get(&migration_name) { - log::info!( - "Migration '{:?}' has already run. Skipping.", - String::from_utf8_lossy(&migration_name) - ); - return weight; - } - - log::info!( - "Running migration '{:?}'", - String::from_utf8_lossy(&migration_name) - ); - - // ------------------------------ - // Step 1: Set the last emission block for all subnets except root - // ------------------------------ - let netuids = Pallet::::get_all_subnet_netuids(); - let current_block_number = Pallet::::get_current_block_as_u64(); - for netuid in netuids.iter() { - if *netuid != 0 { - FirstEmissionBlockNumber::::insert(netuid, current_block_number); - } - } - - // ------------------------------ - // Step 2: Mark Migration as Completed - // ------------------------------ - - HasMigrationRun::::insert(&migration_name, true); - weight = weight.saturating_add(T::DbWeight::get().reads(2)); - - if netuids.is_empty() { - weight = weight.saturating_add(T::DbWeight::get().writes(1_u64)); - } else { - weight = weight.saturating_add(T::DbWeight::get().writes(netuids.len() as u64)); - } - - log::info!( - "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 cada8a9997..19e057e3ec 100644 --- a/pallets/subtensor/src/migrations/mod.rs +++ b/pallets/subtensor/src/migrations/mod.rs @@ -11,7 +11,7 @@ pub mod migrate_populate_owned_hotkeys; pub mod migrate_rao; pub mod migrate_remove_stake_map; pub mod migrate_remove_unused_maps_and_values; -pub mod migrate_set_last_emission_block_number; +pub mod migrate_set_first_emission_block_number; pub mod migrate_set_min_burn; pub mod migrate_set_min_difficulty; pub mod migrate_stake_threshold; diff --git a/pallets/subtensor/src/tests/migration.rs b/pallets/subtensor/src/tests/migration.rs index 3864657432..2fac8c5db5 100644 --- a/pallets/subtensor/src/tests/migration.rs +++ b/pallets/subtensor/src/tests/migration.rs @@ -419,7 +419,7 @@ fn test_migrate_subnet_volume() { } #[test] -fn test_migrate_set_last_emission_block_number() { +fn test_migrate_set_first_emission_block_number() { new_test_ext(1).execute_with(|| { let netuids: [u16; 3] = [1, 2, 3]; let block_number = 100; @@ -427,7 +427,7 @@ fn test_migrate_set_last_emission_block_number() { add_network(*netuid, 1, 0); } run_to_block(block_number); - let weight = crate::migrations::migrate_set_last_emission_block_number::migrate_set_last_emission_block_number::(); + let weight = crate::migrations::migrate_set_first_emission_block_number::migrate_set_first_emission_block_number::(); let expected_weight: Weight = ::DbWeight::get().reads(3) + ::DbWeight::get().writes(netuids.len() as u64); assert_eq!(weight, expected_weight); diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 04d6888595..ea5e3d4492 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -664,7 +664,7 @@ pub fn add_network(netuid: u16, tempo: u16, _modality: u16) { SubtensorModule::init_new_network(netuid, tempo); SubtensorModule::set_network_registration_allowed(netuid, true); SubtensorModule::set_network_pow_registration_allowed(netuid, true); - FirstEmissionBlockNumber::::insert(netuid, 0); + FirstEmissionBlockNumber::::insert(netuid, 1); } #[allow(dead_code)] From 810f94c3b3e8989de92501fdb1274c9122c11421 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 24 Mar 2025 20:12:33 +0800 Subject: [PATCH 12/13] update migration name --- ...migrate_set_first_emission_block_number.rs | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 pallets/subtensor/src/migrations/migrate_set_first_emission_block_number.rs diff --git a/pallets/subtensor/src/migrations/migrate_set_first_emission_block_number.rs b/pallets/subtensor/src/migrations/migrate_set_first_emission_block_number.rs new file mode 100644 index 0000000000..04ad306218 --- /dev/null +++ b/pallets/subtensor/src/migrations/migrate_set_first_emission_block_number.rs @@ -0,0 +1,53 @@ +use super::*; +use crate::HasMigrationRun; +use frame_support::{traits::Get, weights::Weight}; +use scale_info::prelude::string::String; + +pub fn migrate_set_first_emission_block_number() -> Weight { + let migration_name = b"migrate_set_first_emission_block_number".to_vec(); + + let mut weight = T::DbWeight::get().reads(1); + if HasMigrationRun::::get(&migration_name) { + log::info!( + "Migration '{:?}' has already run. Skipping.", + String::from_utf8_lossy(&migration_name) + ); + return weight; + } + + log::info!( + "Running migration '{:?}'", + String::from_utf8_lossy(&migration_name) + ); + + // ------------------------------ + // Step 1: Set the first emission block for all subnets except root + // ------------------------------ + let netuids = Pallet::::get_all_subnet_netuids(); + let current_block_number = Pallet::::get_current_block_as_u64(); + for netuid in netuids.iter() { + if *netuid != 0 { + FirstEmissionBlockNumber::::insert(netuid, current_block_number); + } + } + + // ------------------------------ + // Step 2: Mark Migration as Completed + // ------------------------------ + + HasMigrationRun::::insert(&migration_name, true); + weight = weight.saturating_add(T::DbWeight::get().reads(2)); + + if netuids.is_empty() { + weight = weight.saturating_add(T::DbWeight::get().writes(1_u64)); + } else { + weight = weight.saturating_add(T::DbWeight::get().writes(netuids.len() as u64)); + } + + log::info!( + "Migration '{:?}' completed successfully.", + String::from_utf8_lossy(&migration_name) + ); + + weight +} From 5fb588a946530eb20d303d5d5030fb9d8350c516 Mon Sep 17 00:00:00 2001 From: open-junius Date: Mon, 24 Mar 2025 20:15:08 +0800 Subject: [PATCH 13/13] update coinbase test case --- pallets/subtensor/src/tests/subnet.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pallets/subtensor/src/tests/subnet.rs b/pallets/subtensor/src/tests/subnet.rs index 2378062b55..1daf19159f 100644 --- a/pallets/subtensor/src/tests/subnet.rs +++ b/pallets/subtensor/src/tests/subnet.rs @@ -176,7 +176,7 @@ fn test_do_start_call_fail_for_set_again() { } #[test] -fn test_do_start_call_ok_with_updated_block_number_after_coinbase() { +fn test_do_start_call_ok_with_same_block_number_after_coinbase() { new_test_ext(0).execute_with(|| { let netuid: u16 = 1; let tempo: u16 = 13; @@ -215,7 +215,9 @@ fn test_do_start_call_ok_with_updated_block_number_after_coinbase() { step_block(tempo); match FirstEmissionBlockNumber::::get(netuid) { - Some(new_emission_block_number) => assert!(new_emission_block_number > block_number), + Some(new_emission_block_number) => { + assert_eq!(new_emission_block_number, block_number + 1) + } None => assert!(FirstEmissionBlockNumber::::get(netuid).is_some()), } });