From c3ef1afe561e59edb52ccd7f906c5b097a0e9cfd Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Wed, 15 Oct 2025 09:05:58 -0700 Subject: [PATCH] init commit (wip) --- pallets/admin-utils/src/benchmarking.rs | 122 +- pallets/admin-utils/src/lib.rs | 304 +- pallets/admin-utils/src/tests/mod.rs | 510 ++-- pallets/subtensor/src/benchmarks.rs | 202 +- pallets/subtensor/src/coinbase/block_step.rs | 230 +- pallets/subtensor/src/lib.rs | 51 +- pallets/subtensor/src/macros/dispatches.rs | 12 +- pallets/subtensor/src/macros/errors.rs | 2 + pallets/subtensor/src/macros/events.rs | 12 + pallets/subtensor/src/macros/hooks.rs | 2 +- pallets/subtensor/src/migrations/mod.rs | 1 - pallets/subtensor/src/rpc_info/metagraph.rs | 25 +- pallets/subtensor/src/rpc_info/subnet_info.rs | 34 +- pallets/subtensor/src/subnets/registration.rs | 285 +- pallets/subtensor/src/tests/registration.rs | 2456 +++-------------- pallets/subtensor/src/tests/senate.rs | 9 - pallets/subtensor/src/tests/subnet.rs | 5 - pallets/subtensor/src/tests/swap_coldkey.rs | 3 - pallets/subtensor/src/utils/misc.rs | 51 +- precompiles/src/subnet.rs | 33 +- runtime/src/lib.rs | 7 - 21 files changed, 1183 insertions(+), 3173 deletions(-) diff --git a/pallets/admin-utils/src/benchmarking.rs b/pallets/admin-utils/src/benchmarking.rs index 7e6e17dd5..fdb73d296 100644 --- a/pallets/admin-utils/src/benchmarking.rs +++ b/pallets/admin-utils/src/benchmarking.rs @@ -71,31 +71,31 @@ mod benchmarks { _(RawOrigin::Root, 1u16.into()/*netuid*/, 100u64/*serving_rate_limit*/)/*sudo_set_serving_rate_limit*/; } - #[benchmark] - fn sudo_set_max_difficulty() { - // disable admin freeze window - pallet_subtensor::Pallet::::set_admin_freeze_window(0); - pallet_subtensor::Pallet::::init_new_network( - 1u16.into(), /*netuid*/ - 1u16, /*tempo*/ - ); - - #[extrinsic_call] - _(RawOrigin::Root, 1u16.into()/*netuid*/, 10000u64/*max_difficulty*/)/*sudo_set_max_difficulty*/; - } - - #[benchmark] - fn sudo_set_min_difficulty() { - // disable admin freeze window - pallet_subtensor::Pallet::::set_admin_freeze_window(0); - pallet_subtensor::Pallet::::init_new_network( - 1u16.into(), /*netuid*/ - 1u16, /*tempo*/ - ); - - #[extrinsic_call] - _(RawOrigin::Root, 1u16.into()/*netuid*/, 1000u64/*min_difficulty*/)/*sudo_set_min_difficulty*/; - } + // #[benchmark] + // fn sudo_set_max_difficulty() { + // // disable admin freeze window + // pallet_subtensor::Pallet::::set_admin_freeze_window(0); + // pallet_subtensor::Pallet::::init_new_network( + // 1u16.into(), /*netuid*/ + // 1u16, /*tempo*/ + // ); + + // #[extrinsic_call] + // _(RawOrigin::Root, 1u16.into()/*netuid*/, 10000u64/*max_difficulty*/)/*sudo_set_max_difficulty*/; + // } + + // #[benchmark] + // fn sudo_set_min_difficulty() { + // // disable admin freeze window + // pallet_subtensor::Pallet::::set_admin_freeze_window(0); + // pallet_subtensor::Pallet::::init_new_network( + // 1u16.into(), /*netuid*/ + // 1u16, /*tempo*/ + // ); + + // #[extrinsic_call] + // _(RawOrigin::Root, 1u16.into()/*netuid*/, 1000u64/*min_difficulty*/)/*sudo_set_min_difficulty*/; + // } #[benchmark] fn sudo_set_weights_set_rate_limit() { @@ -162,18 +162,18 @@ mod benchmarks { _(RawOrigin::Root, 1u16.into()/*netuid*/, 10u16/*max_allowed_validators*/)/*sudo_set_max_allowed_validators*/; } - #[benchmark] - fn sudo_set_difficulty() { - // disable admin freeze window - pallet_subtensor::Pallet::::set_admin_freeze_window(0); - pallet_subtensor::Pallet::::init_new_network( - 1u16.into(), /*netuid*/ - 1u16, /*tempo*/ - ); + // #[benchmark] + // fn sudo_set_difficulty() { + // // disable admin freeze window + // pallet_subtensor::Pallet::::set_admin_freeze_window(0); + // pallet_subtensor::Pallet::::init_new_network( + // 1u16.into(), /*netuid*/ + // 1u16, /*tempo*/ + // ); - #[extrinsic_call] - _(RawOrigin::Root, 1u16.into()/*netuid*/, 1200000u64/*difficulty*/)/*sudo_set_difficulty*/; - } + // #[extrinsic_call] + // _(RawOrigin::Root, 1u16.into()/*netuid*/, 1200000u64/*difficulty*/)/*sudo_set_difficulty*/; + // } #[benchmark] fn sudo_set_adjustment_interval() { @@ -318,31 +318,31 @@ mod benchmarks { _(RawOrigin::Root, 1u16.into()/*netuid*/, 100u16/*max_registrations*/)/*sudo_set_max_registrations_per_block*/; } - #[benchmark] - fn sudo_set_max_burn() { - // disable admin freeze window - pallet_subtensor::Pallet::::set_admin_freeze_window(0); - pallet_subtensor::Pallet::::init_new_network( - 1u16.into(), /*netuid*/ - 1u16, /*tempo*/ - ); - - #[extrinsic_call] - _(RawOrigin::Root, 1u16.into()/*netuid*/, 2_000_000_000.into()/*max_burn*/)/*sudo_set_max_burn*/; - } - - #[benchmark] - fn sudo_set_min_burn() { - // disable admin freeze window - pallet_subtensor::Pallet::::set_admin_freeze_window(0); - pallet_subtensor::Pallet::::init_new_network( - 1u16.into(), /*netuid*/ - 1u16, /*tempo*/ - ); - - #[extrinsic_call] - _(RawOrigin::Root, 1u16.into()/*netuid*/, 10.into()/*min_burn*/)/*sudo_set_min_burn*/; - } + // #[benchmark] + // fn sudo_set_max_burn() { + // // disable admin freeze window + // pallet_subtensor::Pallet::::set_admin_freeze_window(0); + // pallet_subtensor::Pallet::::init_new_network( + // 1u16.into(), /*netuid*/ + // 1u16, /*tempo*/ + // ); + + // #[extrinsic_call] + // _(RawOrigin::Root, 1u16.into()/*netuid*/, 2_000_000_000.into()/*max_burn*/)/*sudo_set_max_burn*/; + // } + + // #[benchmark] + // fn sudo_set_min_burn() { + // // disable admin freeze window + // pallet_subtensor::Pallet::::set_admin_freeze_window(0); + // pallet_subtensor::Pallet::::init_new_network( + // 1u16.into(), /*netuid*/ + // 1u16, /*tempo*/ + // ); + + // #[extrinsic_call] + // _(RawOrigin::Root, 1u16.into()/*netuid*/, 10.into()/*min_burn*/)/*sudo_set_min_burn*/; + // } #[benchmark] fn sudo_set_network_registration_allowed() { diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 66e7eab31..fda743f63 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -247,61 +247,61 @@ pub mod pallet { /// The extrinsic sets the minimum difficulty for a subnet. /// It is only callable by the root account or subnet owner. /// The extrinsic will call the Subtensor pallet to set the minimum difficulty. - #[pallet::call_index(4)] - #[pallet::weight(Weight::from_parts(26_390_000, 0) - .saturating_add(::DbWeight::get().reads(3_u64)) - .saturating_add(::DbWeight::get().writes(1_u64)))] - pub fn sudo_set_min_difficulty( - origin: OriginFor, - netuid: NetUid, - min_difficulty: u64, - ) -> DispatchResult { - pallet_subtensor::Pallet::::ensure_root_with_rate_limit(origin, netuid)?; - - ensure!( - pallet_subtensor::Pallet::::if_subnet_exist(netuid), - Error::::SubnetDoesNotExist - ); - pallet_subtensor::Pallet::::set_min_difficulty(netuid, min_difficulty); - log::debug!( - "MinDifficultySet( netuid: {netuid:?} min_difficulty: {min_difficulty:?} ) " - ); - Ok(()) - } + // #[pallet::call_index(4)] + // #[pallet::weight(Weight::from_parts(26_390_000, 0) + // .saturating_add(::DbWeight::get().reads(3_u64)) + // .saturating_add(::DbWeight::get().writes(1_u64)))] + // pub fn sudo_set_min_difficulty( + // origin: OriginFor, + // netuid: NetUid, + // min_difficulty: u64, + // ) -> DispatchResult { + // pallet_subtensor::Pallet::::ensure_root_with_rate_limit(origin, netuid)?; + + // ensure!( + // pallet_subtensor::Pallet::::if_subnet_exist(netuid), + // Error::::SubnetDoesNotExist + // ); + // pallet_subtensor::Pallet::::set_min_difficulty(netuid, min_difficulty); + // log::debug!( + // "MinDifficultySet( netuid: {netuid:?} min_difficulty: {min_difficulty:?} ) " + // ); + // Ok(()) + // } /// The extrinsic sets the maximum difficulty for a subnet. /// It is only callable by the root account or subnet owner. /// The extrinsic will call the Subtensor pallet to set the maximum difficulty. - #[pallet::call_index(5)] - #[pallet::weight(Weight::from_parts(26_990_000, 0) - .saturating_add(::DbWeight::get().reads(3_u64)) - .saturating_add(::DbWeight::get().writes(1_u64)))] - pub fn sudo_set_max_difficulty( - origin: OriginFor, - netuid: NetUid, - max_difficulty: u64, - ) -> DispatchResult { - let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( - origin, - netuid, - &[Hyperparameter::MaxDifficulty.into()], - )?; - - ensure!( - pallet_subtensor::Pallet::::if_subnet_exist(netuid), - Error::::SubnetDoesNotExist - ); - pallet_subtensor::Pallet::::set_max_difficulty(netuid, max_difficulty); - log::debug!( - "MaxDifficultySet( netuid: {netuid:?} max_difficulty: {max_difficulty:?} ) " - ); - pallet_subtensor::Pallet::::record_owner_rl( - maybe_owner, - netuid, - &[Hyperparameter::MaxDifficulty.into()], - ); - Ok(()) - } + // #[pallet::call_index(5)] + // #[pallet::weight(Weight::from_parts(26_990_000, 0) + // .saturating_add(::DbWeight::get().reads(3_u64)) + // .saturating_add(::DbWeight::get().writes(1_u64)))] + // pub fn sudo_set_max_difficulty( + // origin: OriginFor, + // netuid: NetUid, + // max_difficulty: u64, + // ) -> DispatchResult { + // let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( + // origin, + // netuid, + // &[Hyperparameter::MaxDifficulty.into()], + // )?; + + // ensure!( + // pallet_subtensor::Pallet::::if_subnet_exist(netuid), + // Error::::SubnetDoesNotExist + // ); + // pallet_subtensor::Pallet::::set_max_difficulty(netuid, max_difficulty); + // log::debug!( + // "MaxDifficultySet( netuid: {netuid:?} max_difficulty: {max_difficulty:?} ) " + // ); + // pallet_subtensor::Pallet::::record_owner_rl( + // maybe_owner, + // netuid, + // &[Hyperparameter::MaxDifficulty.into()], + // ); + // Ok(()) + // } /// The extrinsic sets the weights version key for a subnet. /// It is only callable by the root account or subnet owner. @@ -758,107 +758,107 @@ pub mod pallet { Ok(()) } - /// The extrinsic sets the minimum burn for a subnet. - /// It is only callable by root and subnet owner. - /// The extrinsic will call the Subtensor pallet to set the minimum burn. - #[pallet::call_index(22)] - #[pallet::weight(Weight::from_parts(29_970_000, 0) - .saturating_add(::DbWeight::get().reads(4_u64)) - .saturating_add(::DbWeight::get().writes(1_u64)))] - pub fn sudo_set_min_burn( - origin: OriginFor, - netuid: NetUid, - min_burn: TaoCurrency, - ) -> DispatchResult { - let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( - origin, - netuid, - &[Hyperparameter::MinBurn.into()], - )?; - ensure!( - pallet_subtensor::Pallet::::if_subnet_exist(netuid), - Error::::SubnetDoesNotExist - ); - ensure!( - min_burn < T::MinBurnUpperBound::get(), - Error::::ValueNotInBounds - ); - // Min burn must be less than max burn - ensure!( - min_burn < pallet_subtensor::Pallet::::get_max_burn(netuid), - Error::::ValueNotInBounds - ); - pallet_subtensor::Pallet::::set_min_burn(netuid, min_burn); - log::debug!("MinBurnSet( netuid: {netuid:?} min_burn: {min_burn:?} ) "); - pallet_subtensor::Pallet::::record_owner_rl( - maybe_owner, - netuid, - &[Hyperparameter::MinBurn.into()], - ); - Ok(()) - } - - /// The extrinsic sets the maximum burn for a subnet. - /// It is only callable by root and subnet owner. - /// The extrinsic will call the Subtensor pallet to set the maximum burn. - #[pallet::call_index(23)] - #[pallet::weight(Weight::from_parts(30_510_000, 0) - .saturating_add(::DbWeight::get().reads(4_u64)) - .saturating_add(::DbWeight::get().writes(1_u64)))] - pub fn sudo_set_max_burn( - origin: OriginFor, - netuid: NetUid, - max_burn: TaoCurrency, - ) -> DispatchResult { - let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( - origin, - netuid, - &[Hyperparameter::MaxBurn.into()], - )?; - ensure!( - pallet_subtensor::Pallet::::if_subnet_exist(netuid), - Error::::SubnetDoesNotExist - ); - ensure!( - max_burn > T::MaxBurnLowerBound::get(), - Error::::ValueNotInBounds - ); - // Max burn must be greater than min burn - ensure!( - max_burn > pallet_subtensor::Pallet::::get_min_burn(netuid), - Error::::ValueNotInBounds - ); - pallet_subtensor::Pallet::::set_max_burn(netuid, max_burn); - log::debug!("MaxBurnSet( netuid: {netuid:?} max_burn: {max_burn:?} ) "); - pallet_subtensor::Pallet::::record_owner_rl( - maybe_owner, - netuid, - &[Hyperparameter::MaxBurn.into()], - ); - Ok(()) - } - - /// The extrinsic sets the difficulty for a subnet. - /// It is only callable by the root account or subnet owner. - /// The extrinsic will call the Subtensor pallet to set the difficulty. - #[pallet::call_index(24)] - #[pallet::weight(Weight::from_parts(38_500_000, 0) - .saturating_add(::DbWeight::get().reads(3_u64)) - .saturating_add(::DbWeight::get().writes(1_u64)))] - pub fn sudo_set_difficulty( - origin: OriginFor, - netuid: NetUid, - difficulty: u64, - ) -> DispatchResult { - pallet_subtensor::Pallet::::ensure_root_with_rate_limit(origin, netuid)?; - ensure!( - pallet_subtensor::Pallet::::if_subnet_exist(netuid), - Error::::SubnetDoesNotExist - ); - pallet_subtensor::Pallet::::set_difficulty(netuid, difficulty); - log::debug!("DifficultySet( netuid: {netuid:?} difficulty: {difficulty:?} ) "); - Ok(()) - } + // /// The extrinsic sets the minimum burn for a subnet. + // /// It is only callable by root and subnet owner. + // /// The extrinsic will call the Subtensor pallet to set the minimum burn. + // #[pallet::call_index(22)] + // #[pallet::weight(Weight::from_parts(29_970_000, 0) + // .saturating_add(::DbWeight::get().reads(4_u64)) + // .saturating_add(::DbWeight::get().writes(1_u64)))] + // pub fn sudo_set_min_burn( + // origin: OriginFor, + // netuid: NetUid, + // min_burn: TaoCurrency, + // ) -> DispatchResult { + // let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( + // origin, + // netuid, + // &[Hyperparameter::MinBurn.into()], + // )?; + // ensure!( + // pallet_subtensor::Pallet::::if_subnet_exist(netuid), + // Error::::SubnetDoesNotExist + // ); + // ensure!( + // min_burn < T::MinBurnUpperBound::get(), + // Error::::ValueNotInBounds + // ); + // // Min burn must be less than max burn + // ensure!( + // min_burn < pallet_subtensor::Pallet::::get_max_burn(netuid), + // Error::::ValueNotInBounds + // ); + // pallet_subtensor::Pallet::::set_min_burn(netuid, min_burn); + // log::debug!("MinBurnSet( netuid: {netuid:?} min_burn: {min_burn:?} ) "); + // pallet_subtensor::Pallet::::record_owner_rl( + // maybe_owner, + // netuid, + // &[Hyperparameter::MinBurn.into()], + // ); + // Ok(()) + // } + + // /// The extrinsic sets the maximum burn for a subnet. + // /// It is only callable by root and subnet owner. + // /// The extrinsic will call the Subtensor pallet to set the maximum burn. + // #[pallet::call_index(23)] + // #[pallet::weight(Weight::from_parts(30_510_000, 0) + // .saturating_add(::DbWeight::get().reads(4_u64)) + // .saturating_add(::DbWeight::get().writes(1_u64)))] + // pub fn sudo_set_max_burn( + // origin: OriginFor, + // netuid: NetUid, + // max_burn: TaoCurrency, + // ) -> DispatchResult { + // let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( + // origin, + // netuid, + // &[Hyperparameter::MaxBurn.into()], + // )?; + // ensure!( + // pallet_subtensor::Pallet::::if_subnet_exist(netuid), + // Error::::SubnetDoesNotExist + // ); + // ensure!( + // max_burn > T::MaxBurnLowerBound::get(), + // Error::::ValueNotInBounds + // ); + // // Max burn must be greater than min burn + // ensure!( + // max_burn > pallet_subtensor::Pallet::::get_min_burn(netuid), + // Error::::ValueNotInBounds + // ); + // pallet_subtensor::Pallet::::set_max_burn(netuid, max_burn); + // log::debug!("MaxBurnSet( netuid: {netuid:?} max_burn: {max_burn:?} ) "); + // pallet_subtensor::Pallet::::record_owner_rl( + // maybe_owner, + // netuid, + // &[Hyperparameter::MaxBurn.into()], + // ); + // Ok(()) + // } + + // /// The extrinsic sets the difficulty for a subnet. + // /// It is only callable by the root account or subnet owner. + // /// The extrinsic will call the Subtensor pallet to set the difficulty. + // #[pallet::call_index(24)] + // #[pallet::weight(Weight::from_parts(38_500_000, 0) + // .saturating_add(::DbWeight::get().reads(3_u64)) + // .saturating_add(::DbWeight::get().writes(1_u64)))] + // pub fn sudo_set_difficulty( + // origin: OriginFor, + // netuid: NetUid, + // difficulty: u64, + // ) -> DispatchResult { + // pallet_subtensor::Pallet::::ensure_root_with_rate_limit(origin, netuid)?; + // ensure!( + // pallet_subtensor::Pallet::::if_subnet_exist(netuid), + // Error::::SubnetDoesNotExist + // ); + // pallet_subtensor::Pallet::::set_difficulty(netuid, difficulty); + // log::debug!("DifficultySet( netuid: {netuid:?} difficulty: {difficulty:?} ) "); + // Ok(()) + // } /// The extrinsic sets the maximum allowed validators for a subnet. /// It is only callable by the root account. diff --git a/pallets/admin-utils/src/tests/mod.rs b/pallets/admin-utils/src/tests/mod.rs index 4e534c321..96777b228 100644 --- a/pallets/admin-utils/src/tests/mod.rs +++ b/pallets/admin-utils/src/tests/mod.rs @@ -67,71 +67,71 @@ fn test_sudo_set_serving_rate_limit() { }); } -#[test] -fn test_sudo_set_min_difficulty() { - new_test_ext().execute_with(|| { - let netuid = NetUid::from(1); - let to_be_set: u64 = 10; - add_network(netuid, 10); - let init_value: u64 = SubtensorModule::get_min_difficulty(netuid); - assert_eq!( - AdminUtils::sudo_set_min_difficulty( - <::RuntimeOrigin>::signed(U256::from(1)), - netuid, - to_be_set - ), - Err(DispatchError::BadOrigin) - ); - assert_eq!( - AdminUtils::sudo_set_min_difficulty( - <::RuntimeOrigin>::root(), - netuid.next(), - to_be_set - ), - Err(Error::::SubnetDoesNotExist.into()) - ); - assert_eq!(SubtensorModule::get_min_difficulty(netuid), init_value); - assert_ok!(AdminUtils::sudo_set_min_difficulty( - <::RuntimeOrigin>::root(), - netuid, - to_be_set - )); - assert_eq!(SubtensorModule::get_min_difficulty(netuid), to_be_set); - }); -} - -#[test] -fn test_sudo_set_max_difficulty() { - new_test_ext().execute_with(|| { - let netuid = NetUid::from(1); - let to_be_set: u64 = 10; - add_network(netuid, 10); - let init_value: u64 = SubtensorModule::get_max_difficulty(netuid); - assert_eq!( - AdminUtils::sudo_set_max_difficulty( - <::RuntimeOrigin>::signed(U256::from(1)), - netuid, - to_be_set - ), - Err(DispatchError::BadOrigin) - ); - assert_eq!( - AdminUtils::sudo_set_max_difficulty( - <::RuntimeOrigin>::root(), - netuid.next(), - to_be_set - ), - Err(Error::::SubnetDoesNotExist.into()) - ); - assert_eq!(SubtensorModule::get_max_difficulty(netuid), init_value); - assert_ok!(AdminUtils::sudo_set_max_difficulty( - <::RuntimeOrigin>::root(), - netuid, - to_be_set - )); - assert_eq!(SubtensorModule::get_max_difficulty(netuid), to_be_set); - }); -} +// #[test] +// fn test_sudo_set_min_difficulty() { +// new_test_ext().execute_with(|| { +// let netuid = NetUid::from(1); +// let to_be_set: u64 = 10; +// add_network(netuid, 10); +// let init_value: u64 = SubtensorModule::get_min_difficulty(netuid); +// assert_eq!( +// AdminUtils::sudo_set_min_difficulty( +// <::RuntimeOrigin>::signed(U256::from(1)), +// netuid, +// to_be_set +// ), +// Err(DispatchError::BadOrigin) +// ); +// assert_eq!( +// AdminUtils::sudo_set_min_difficulty( +// <::RuntimeOrigin>::root(), +// netuid.next(), +// to_be_set +// ), +// Err(Error::::SubnetDoesNotExist.into()) +// ); +// assert_eq!(SubtensorModule::get_min_difficulty(netuid), init_value); +// assert_ok!(AdminUtils::sudo_set_min_difficulty( +// <::RuntimeOrigin>::root(), +// netuid, +// to_be_set +// )); +// assert_eq!(SubtensorModule::get_min_difficulty(netuid), to_be_set); +// }); +// } + +// #[test] +// fn test_sudo_set_max_difficulty() { +// new_test_ext().execute_with(|| { +// let netuid = NetUid::from(1); +// let to_be_set: u64 = 10; +// add_network(netuid, 10); +// let init_value: u64 = SubtensorModule::get_max_difficulty(netuid); +// assert_eq!( +// AdminUtils::sudo_set_max_difficulty( +// <::RuntimeOrigin>::signed(U256::from(1)), +// netuid, +// to_be_set +// ), +// Err(DispatchError::BadOrigin) +// ); +// assert_eq!( +// AdminUtils::sudo_set_max_difficulty( +// <::RuntimeOrigin>::root(), +// netuid.next(), +// to_be_set +// ), +// Err(Error::::SubnetDoesNotExist.into()) +// ); +// assert_eq!(SubtensorModule::get_max_difficulty(netuid), init_value); +// assert_ok!(AdminUtils::sudo_set_max_difficulty( +// <::RuntimeOrigin>::root(), +// netuid, +// to_be_set +// )); +// assert_eq!(SubtensorModule::get_max_difficulty(netuid), to_be_set); +// }); +// } #[test] fn test_sudo_set_weights_version_key() { @@ -518,9 +518,13 @@ fn test_sudo_set_max_allowed_uids() { MaxRegistrationsPerBlock::::insert(netuid, 256); TargetRegistrationsPerInterval::::insert(netuid, 256); - // Register some neurons + // Register some neurons (fund each signer before registration) for i in 0..=8 { - register_ok_neuron(netuid, U256::from(i * 1000), U256::from(i * 1000 + i), 0); + let hk = U256::from(i * 1000); + let ck = U256::from(i * 1000 + i); + let price = SubtensorModule::get_burn(netuid); + SubtensorModule::add_balance_to_coldkey_account(&hk, price.saturating_mul(10)); + register_ok_neuron(netuid, hk, ck, 0); } // Bad origin that is not root or subnet owner @@ -755,50 +759,50 @@ fn test_sudo_set_target_registrations_per_interval() { }); } -#[test] -fn test_sudo_set_difficulty() { - new_test_ext().execute_with(|| { - let netuid = NetUid::from(1); - let to_be_set: u64 = 10; - add_network(netuid, 10); - let init_value: u64 = SubtensorModule::get_difficulty_as_u64(netuid); - assert_eq!( - AdminUtils::sudo_set_difficulty( - <::RuntimeOrigin>::signed(U256::from(1)), - netuid, - to_be_set - ), - Err(DispatchError::BadOrigin) - ); - assert_eq!( - AdminUtils::sudo_set_difficulty( - <::RuntimeOrigin>::root(), - netuid.next(), - to_be_set - ), - Err(Error::::SubnetDoesNotExist.into()) - ); - assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), init_value); - assert_ok!(AdminUtils::sudo_set_difficulty( - <::RuntimeOrigin>::root(), - netuid, - to_be_set - )); - assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), to_be_set); - - // Test that SN owner can't set difficulty - pallet_subtensor::SubnetOwner::::insert(netuid, U256::from(1)); - assert_eq!( - AdminUtils::sudo_set_difficulty( - <::RuntimeOrigin>::signed(U256::from(1)), - netuid, - init_value - ), - Err(DispatchError::BadOrigin) - ); - assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), to_be_set); // no change - }); -} +// #[test] +// fn test_sudo_set_difficulty() { +// new_test_ext().execute_with(|| { +// let netuid = NetUid::from(1); +// let to_be_set: u64 = 10; +// add_network(netuid, 10); +// let init_value: u64 = SubtensorModule::get_difficulty_as_u64(netuid); +// assert_eq!( +// AdminUtils::sudo_set_difficulty( +// <::RuntimeOrigin>::signed(U256::from(1)), +// netuid, +// to_be_set +// ), +// Err(DispatchError::BadOrigin) +// ); +// assert_eq!( +// AdminUtils::sudo_set_difficulty( +// <::RuntimeOrigin>::root(), +// netuid.next(), +// to_be_set +// ), +// Err(Error::::SubnetDoesNotExist.into()) +// ); +// assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), init_value); +// assert_ok!(AdminUtils::sudo_set_difficulty( +// <::RuntimeOrigin>::root(), +// netuid, +// to_be_set +// )); +// assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), to_be_set); + +// // Test that SN owner can't set difficulty +// pallet_subtensor::SubnetOwner::::insert(netuid, U256::from(1)); +// assert_eq!( +// AdminUtils::sudo_set_difficulty( +// <::RuntimeOrigin>::signed(U256::from(1)), +// netuid, +// init_value +// ), +// Err(DispatchError::BadOrigin) +// ); +// assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), to_be_set); // no change +// }); +// } #[test] fn test_sudo_set_max_allowed_validators() { @@ -1684,6 +1688,10 @@ fn test_sets_a_lower_value_clears_small_nominations() { let netuid = NetUid::from(2); add_network(netuid, 10); + // Fund the signer of `register()` (hotkey acts as "coldkey" signer in the helper) + let price = SubtensorModule::get_burn(netuid); + SubtensorModule::add_balance_to_coldkey_account(&hotkey, price.saturating_mul(10)); + // Register a neuron register_ok_neuron(netuid, hotkey, owner_coldkey, 0); @@ -1697,6 +1705,9 @@ fn test_sets_a_lower_value_clears_small_nominations() { initial_nominator_min_required_stake * default_min_stake.to_u64() / 1_000_000 ); + // Fund the staker for the upcoming stake + SubtensorModule::add_balance_to_coldkey_account(&staker_coldkey, 1_000_000_000_000); + // Stake to the hotkey as staker_coldkey SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( &hotkey, @@ -2040,15 +2051,14 @@ fn test_freeze_window_blocks_root_and_owner() { <::RuntimeOrigin>::root(), 3 )); - // Advance to a block where remaining < 3 run_to_block((tempo - 2).into()); // Root should be blocked during freeze window assert_noop!( - AdminUtils::sudo_set_min_burn( + AdminUtils::sudo_set_max_allowed_validators( <::RuntimeOrigin>::root(), netuid, - 123.into() + 1 ), SubtensorError::::AdminActionProhibitedDuringWeightsWindow ); @@ -2068,64 +2078,64 @@ fn test_freeze_window_blocks_root_and_owner() { }); } -#[test] -fn test_sudo_set_min_burn() { - new_test_ext().execute_with(|| { - let netuid = NetUid::from(1); - let to_be_set = TaoCurrency::from(1_000_000); - add_network(netuid, 10); - let init_value = SubtensorModule::get_min_burn(netuid); - - // Simple case - assert_ok!(AdminUtils::sudo_set_min_burn( - <::RuntimeOrigin>::root(), - netuid, - TaoCurrency::from(to_be_set) - )); - assert_ne!(SubtensorModule::get_min_burn(netuid), init_value); - assert_eq!(SubtensorModule::get_min_burn(netuid), to_be_set); - - // Unknown subnet - assert_err!( - AdminUtils::sudo_set_min_burn( - <::RuntimeOrigin>::root(), - NetUid::from(42), - TaoCurrency::from(to_be_set) - ), - Error::::SubnetDoesNotExist - ); - - // Non subnet owner - assert_err!( - AdminUtils::sudo_set_min_burn( - <::RuntimeOrigin>::signed(U256::from(1)), - netuid, - TaoCurrency::from(to_be_set) - ), - DispatchError::BadOrigin - ); - - // Above upper bound - assert_err!( - AdminUtils::sudo_set_min_burn( - <::RuntimeOrigin>::root(), - netuid, - ::MinBurnUpperBound::get() + 1.into() - ), - Error::::ValueNotInBounds - ); - - // Above max burn - assert_err!( - AdminUtils::sudo_set_min_burn( - <::RuntimeOrigin>::root(), - netuid, - SubtensorModule::get_max_burn(netuid) + 1.into() - ), - Error::::ValueNotInBounds - ); - }); -} +// #[test] +// fn test_sudo_set_min_burn() { +// new_test_ext().execute_with(|| { +// let netuid = NetUid::from(1); +// let to_be_set = TaoCurrency::from(1_000_000); +// add_network(netuid, 10); +// let init_value = SubtensorModule::get_min_burn(netuid); + +// // Simple case +// assert_ok!(AdminUtils::sudo_set_min_burn( +// <::RuntimeOrigin>::root(), +// netuid, +// TaoCurrency::from(to_be_set) +// )); +// assert_ne!(SubtensorModule::get_min_burn(netuid), init_value); +// assert_eq!(SubtensorModule::get_min_burn(netuid), to_be_set); + +// // Unknown subnet +// assert_err!( +// AdminUtils::sudo_set_min_burn( +// <::RuntimeOrigin>::root(), +// NetUid::from(42), +// TaoCurrency::from(to_be_set) +// ), +// Error::::SubnetDoesNotExist +// ); + +// // Non subnet owner +// assert_err!( +// AdminUtils::sudo_set_min_burn( +// <::RuntimeOrigin>::signed(U256::from(1)), +// netuid, +// TaoCurrency::from(to_be_set) +// ), +// DispatchError::BadOrigin +// ); + +// // Above upper bound +// assert_err!( +// AdminUtils::sudo_set_min_burn( +// <::RuntimeOrigin>::root(), +// netuid, +// ::MinBurnUpperBound::get() + 1.into() +// ), +// Error::::ValueNotInBounds +// ); + +// // Above max burn +// assert_err!( +// AdminUtils::sudo_set_min_burn( +// <::RuntimeOrigin>::root(), +// netuid, +// SubtensorModule::get_max_burn(netuid) + 1.into() +// ), +// Error::::ValueNotInBounds +// ); +// }); +// } #[test] fn test_owner_hyperparam_update_rate_limit_enforced() { @@ -2300,64 +2310,64 @@ fn test_owner_hyperparam_rate_limit_independent_per_param() { }); } -#[test] -fn test_sudo_set_max_burn() { - new_test_ext().execute_with(|| { - let netuid = NetUid::from(1); - let to_be_set = TaoCurrency::from(100_000_001); - add_network(netuid, 10); - let init_value = SubtensorModule::get_max_burn(netuid); - - // Simple case - assert_ok!(AdminUtils::sudo_set_max_burn( - <::RuntimeOrigin>::root(), - netuid, - TaoCurrency::from(to_be_set) - )); - assert_ne!(SubtensorModule::get_max_burn(netuid), init_value); - assert_eq!(SubtensorModule::get_max_burn(netuid), to_be_set); - - // Unknown subnet - assert_err!( - AdminUtils::sudo_set_max_burn( - <::RuntimeOrigin>::root(), - NetUid::from(42), - TaoCurrency::from(to_be_set) - ), - Error::::SubnetDoesNotExist - ); - - // Non subnet owner - assert_err!( - AdminUtils::sudo_set_max_burn( - <::RuntimeOrigin>::signed(U256::from(1)), - netuid, - TaoCurrency::from(to_be_set) - ), - DispatchError::BadOrigin - ); - - // Below lower bound - assert_err!( - AdminUtils::sudo_set_max_burn( - <::RuntimeOrigin>::root(), - netuid, - ::MaxBurnLowerBound::get() - 1.into() - ), - Error::::ValueNotInBounds - ); - - // Below min burn - assert_err!( - AdminUtils::sudo_set_max_burn( - <::RuntimeOrigin>::root(), - netuid, - SubtensorModule::get_min_burn(netuid) - 1.into() - ), - Error::::ValueNotInBounds - ); - }); -} +// #[test] +// fn test_sudo_set_max_burn() { +// new_test_ext().execute_with(|| { +// let netuid = NetUid::from(1); +// let to_be_set = TaoCurrency::from(100_000_001); +// add_network(netuid, 10); +// let init_value = SubtensorModule::get_max_burn(netuid); + +// // Simple case +// assert_ok!(AdminUtils::sudo_set_max_burn( +// <::RuntimeOrigin>::root(), +// netuid, +// TaoCurrency::from(to_be_set) +// )); +// assert_ne!(SubtensorModule::get_max_burn(netuid), init_value); +// assert_eq!(SubtensorModule::get_max_burn(netuid), to_be_set); + +// // Unknown subnet +// assert_err!( +// AdminUtils::sudo_set_max_burn( +// <::RuntimeOrigin>::root(), +// NetUid::from(42), +// TaoCurrency::from(to_be_set) +// ), +// Error::::SubnetDoesNotExist +// ); + +// // Non subnet owner +// assert_err!( +// AdminUtils::sudo_set_max_burn( +// <::RuntimeOrigin>::signed(U256::from(1)), +// netuid, +// TaoCurrency::from(to_be_set) +// ), +// DispatchError::BadOrigin +// ); + +// // Below lower bound +// assert_err!( +// AdminUtils::sudo_set_max_burn( +// <::RuntimeOrigin>::root(), +// netuid, +// ::MaxBurnLowerBound::get() - 1.into() +// ), +// Error::::ValueNotInBounds +// ); + +// // Below min burn +// assert_err!( +// AdminUtils::sudo_set_max_burn( +// <::RuntimeOrigin>::root(), +// netuid, +// SubtensorModule::get_min_burn(netuid) - 1.into() +// ), +// Error::::ValueNotInBounds +// ); +// }); +// } #[test] fn test_sudo_set_mechanism_count() { @@ -2478,11 +2488,15 @@ fn test_trim_to_max_allowed_uids() { let mechanism_count = MechId::from(4); MechanismCountCurrent::::insert(netuid, mechanism_count); - // Add some neurons + // Add some neurons (fund each signer before registration) let max_n = 16; for i in 1..=max_n { let n = i * 1000; - register_ok_neuron(netuid, U256::from(n), U256::from(n + i), 0); + let hk = U256::from(n); + let ck = U256::from(n + i); + let price = SubtensorModule::get_burn(netuid); + SubtensorModule::add_balance_to_coldkey_account(&hk, price.saturating_mul(10)); + register_ok_neuron(netuid, hk, ck, 0); } // Run some block to ensure stake weights are set and that we are past the immunity period @@ -2559,15 +2573,12 @@ fn test_trim_to_max_allowed_uids() { ); // Populate Weights and Bonds storage items to test trimming - // Create weights and bonds that span across the range that will be trimmed for uid in 0..max_n { let mut weights = Vec::new(); let mut bonds = Vec::new(); - // Add connections to all other uids, including those that will be trimmed for target_uid in 0..max_n { if target_uid != uid { - // Use some non-zero values to make the test more meaningful let weight_value = (uid + target_uid) % 1000; let bond_value = (uid * target_uid) % 1000; weights.push((target_uid, weight_value)); @@ -2753,11 +2764,15 @@ fn test_trim_to_max_allowed_uids_too_many_immune() { ImmuneOwnerUidsLimit::::insert(netuid, 2); MinAllowedUids::::set(netuid, 2); - // Add 5 neurons + // Add 5 neurons (fund each signer before registration) let max_n = 5; for i in 1..=max_n { let n = i * 1000; - register_ok_neuron(netuid, U256::from(n), U256::from(n + i), 0); + let hk = U256::from(n); + let ck = U256::from(n + i); + let price = SubtensorModule::get_burn(netuid); + SubtensorModule::add_balance_to_coldkey_account(&hk, price.saturating_mul(10)); + register_ok_neuron(netuid, hk, ck, 0); } // Run some blocks to ensure stake weights are set @@ -2772,8 +2787,7 @@ fn test_trim_to_max_allowed_uids_too_many_immune() { Keys::::insert(netuid, 1, owner_hotkey2); Uids::::insert(netuid, owner_hotkey2, 1); - // Set temporally immune uids (2 UIDs) to make total immune count 4 out of 5 (80%) - // Set their registration block to current block to make them temporally immune + // Set temporally immune uids (2 UIDs) let current_block = frame_system::Pallet::::block_number(); for uid in 2..4 { let hotkey = U256::from(uid * 1000 + 1000); @@ -2782,7 +2796,7 @@ fn test_trim_to_max_allowed_uids_too_many_immune() { BlockAtRegistration::::insert(netuid, uid, current_block); } - // Try to trim to 4 UIDs - this should fail because 4/4 = 100% immune (>= 80%) + // Try to trim to 4 UIDs - should fail (immune >= 80%) assert_err!( AdminUtils::sudo_trim_to_max_allowed_uids( <::RuntimeOrigin>::root(), @@ -2792,7 +2806,7 @@ fn test_trim_to_max_allowed_uids_too_many_immune() { pallet_subtensor::Error::::TrimmingWouldExceedMaxImmunePercentage ); - // Try to trim to 3 UIDs - this should also fail because 4/3 > 80% immune (>= 80%) + // Try to trim to 3 UIDs - should fail (immune >= 80%) assert_err!( AdminUtils::sudo_trim_to_max_allowed_uids( <::RuntimeOrigin>::root(), @@ -2803,7 +2817,7 @@ fn test_trim_to_max_allowed_uids_too_many_immune() { ); // Now test a scenario where trimming should succeed - // Remove one immune UID to make it 3 immune out of 4 total + // Remove one immune UID to make it lower let uid_to_remove = 3; let hotkey_to_remove = U256::from(uid_to_remove * 1000 + 1000); #[allow(unknown_lints)] @@ -2811,7 +2825,7 @@ fn test_trim_to_max_allowed_uids_too_many_immune() { Uids::::remove(netuid, hotkey_to_remove); BlockAtRegistration::::remove(netuid, uid_to_remove); - // Remove another immune UID to make it 2 immune out of 3 total + // Remove another immune UID let uid_to_remove2 = 2; let hotkey_to_remove2 = U256::from(uid_to_remove2 * 1000 + 1000); #[allow(unknown_lints)] @@ -2820,7 +2834,7 @@ fn test_trim_to_max_allowed_uids_too_many_immune() { BlockAtRegistration::::remove(netuid, uid_to_remove2); // Now we have 2 immune out of 2 total UIDs - // Try to trim to 1 UID - this should fail because 2/1 is impossible, but the check prevents it + // Try to trim to 1 UID - invalid assert_err!( AdminUtils::sudo_trim_to_max_allowed_uids( <::RuntimeOrigin>::root(), @@ -2841,9 +2855,13 @@ fn test_sudo_set_min_allowed_uids() { MaxRegistrationsPerBlock::::insert(netuid, 256); TargetRegistrationsPerInterval::::insert(netuid, 256); - // Register some neurons + // Register some neurons (fund each signer before registration) for i in 0..=16 { - register_ok_neuron(netuid, U256::from(i * 1000), U256::from(i * 1000 + i), 0); + let hk = U256::from(i * 1000); + let ck = U256::from(i * 1000 + i); + let price = SubtensorModule::get_burn(netuid); + SubtensorModule::add_balance_to_coldkey_account(&hk, price.saturating_mul(10)); + register_ok_neuron(netuid, hk, ck, 0); } // Normal case diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 5b73ac3f4..554b90fe8 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -72,11 +72,10 @@ mod pallet_benchmarks { let coldkey: T::AccountId = account("Test", 0, seed); seed += 1; - Subtensor::::set_burn(netuid, 1.into()); let amount_to_be_staked: u64 = 1_000_000; Subtensor::::add_balance_to_coldkey_account(&coldkey, amount_to_be_staked); - assert_ok!(Subtensor::::do_burned_registration( + assert_ok!(Subtensor::::do_registration( RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone() @@ -105,7 +104,6 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, tempo); SubtokenEnabled::::insert(netuid, true); - Subtensor::::set_burn(netuid, 1.into()); Subtensor::::set_network_registration_allowed(netuid, true); Subtensor::::set_max_allowed_uids(netuid, 4096); @@ -116,7 +114,7 @@ mod pallet_benchmarks { let amount = TaoCurrency::from(60_000_000); Subtensor::::add_balance_to_coldkey_account(&coldkey, total_stake.into()); - assert_ok!(Subtensor::::do_burned_registration( + assert_ok!(Subtensor::::do_registration( RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone() @@ -136,22 +134,22 @@ mod pallet_benchmarks { let netuid = NetUid::from(1); let caller: T::AccountId = whitelisted_caller(); let version: u32 = 2; - let ip: u128 = 1676056785; - let port: u16 = 128; - let ip_type: u8 = 4; - let protocol: u8 = 0; - let placeholder1: u8 = 0; - let placeholder2: u8 = 0; + let ip: u128 = 1676056785u128; + let port: u16 = 128u16; + let ip_type: u8 = 4u8; + let protocol: u8 = 0u8; + let placeholder1: u8 = 0u8; + let placeholder2: u8 = 0u8; Subtensor::::init_new_network(netuid, 1); SubtokenEnabled::::insert(netuid, true); - Subtensor::::set_max_allowed_uids(netuid, 4096); + Subtensor::::set_max_allowed_uids(netuid, 4096u16); - let reg_fee = Subtensor::::get_burn(netuid); - let deposit = reg_fee.saturating_mul(2.into()); - Subtensor::::add_balance_to_coldkey_account(&caller, deposit.into()); + let reg_fee: u64 = Subtensor::::get_burn(netuid); + let deposit_u64: u64 = reg_fee.saturating_mul(2u64); + Subtensor::::add_balance_to_coldkey_account(&caller, deposit_u64); - assert_ok!(Subtensor::::do_burned_registration( + assert_ok!(Subtensor::::do_registration( RawOrigin::Signed(caller.clone()).into(), netuid, caller.clone() @@ -177,19 +175,19 @@ mod pallet_benchmarks { let netuid = NetUid::from(1); let caller: T::AccountId = whitelisted_caller(); let version: u32 = 2; - let ip: u128 = 1676056785; - let port: u16 = 128; - let ip_type: u8 = 4; + let ip: u128 = 1676056785u128; + let port: u16 = 128u16; + let ip_type: u8 = 4u8; Subtensor::::init_new_network(netuid, 1); SubtokenEnabled::::insert(netuid, true); - Subtensor::::set_max_allowed_uids(netuid, 4096); + Subtensor::::set_max_allowed_uids(netuid, 4096u16); - let reg_fee = Subtensor::::get_burn(netuid); - let deposit = reg_fee.saturating_mul(2.into()); - Subtensor::::add_balance_to_coldkey_account(&caller, deposit.into()); + let reg_fee: u64 = Subtensor::::get_burn(netuid); + let deposit_u64: u64 = reg_fee.saturating_mul(2u64); + Subtensor::::add_balance_to_coldkey_account(&caller, deposit_u64); - assert_ok!(Subtensor::::do_burned_registration( + assert_ok!(Subtensor::::do_registration( RawOrigin::Signed(caller.clone()).into(), netuid, caller.clone() @@ -207,23 +205,22 @@ mod pallet_benchmarks { ); } - #[benchmark] - fn burned_register() { - let netuid = NetUid::from(1); - let seed: u32 = 1; - let hotkey: T::AccountId = account("Alice", 0, seed); - let coldkey: T::AccountId = account("Test", 0, seed); + // #[benchmark] + // fn burned_register() { + // let netuid = NetUid::from(1); + // let seed: u32 = 1; + // let hotkey: T::AccountId = account("Alice", 0, seed); + // let coldkey: T::AccountId = account("Test", 0, seed); - Subtensor::::init_new_network(netuid, 1); - SubtokenEnabled::::insert(netuid, true); - Subtensor::::set_burn(netuid, 1.into()); + // Subtensor::::init_new_network(netuid, 1); + // SubtokenEnabled::::insert(netuid, true); - let amount: u64 = 1_000_000; - Subtensor::::add_balance_to_coldkey_account(&coldkey, amount); + // let amount: u64 = 1_000_000; + // Subtensor::::add_balance_to_coldkey_account(&coldkey, amount); - #[extrinsic_call] - _(RawOrigin::Signed(coldkey.clone()), netuid, hotkey.clone()); - } + // #[extrinsic_call] + // _(RawOrigin::Signed(coldkey.clone()), netuid, hotkey.clone()); + // } #[benchmark] fn root_register() { @@ -234,7 +231,6 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, 1); SubtokenEnabled::::insert(netuid, true); - Subtensor::::set_burn(netuid, 1.into()); Subtensor::::set_network_registration_allowed(netuid, true); Subtensor::::set_max_allowed_uids(netuid, 4096); assert_eq!(Subtensor::::get_max_allowed_uids(netuid), 4096); @@ -242,7 +238,7 @@ mod pallet_benchmarks { let amount: u64 = 100_000_000_000_000; Subtensor::::add_balance_to_coldkey_account(&coldkey, amount); - assert_ok!(Subtensor::::do_burned_registration( + assert_ok!(Subtensor::::do_registration( RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone() @@ -392,17 +388,17 @@ mod pallet_benchmarks { let netuid = NetUid::from(1); let coldkey: T::AccountId = account("Cold", 0, 1); let hotkey: T::AccountId = account("Hot", 0, 1); - let take: u16 = 1000; + let take: u16 = 1000u16; Subtensor::::init_new_network(netuid, 1); Subtensor::::set_network_registration_allowed(netuid, true); SubtokenEnabled::::insert(netuid, true); - let reg_fee = Subtensor::::get_burn(netuid); - let deposit = reg_fee.saturating_mul(2.into()); - Subtensor::::add_balance_to_coldkey_account(&coldkey, deposit.into()); + let reg_fee: u64 = Subtensor::::get_burn(netuid); + let deposit_u64: u64 = reg_fee.saturating_mul(2u64); + Subtensor::::add_balance_to_coldkey_account(&coldkey, deposit_u64); - assert_ok!(Subtensor::::do_burned_registration( + assert_ok!(Subtensor::::do_registration( RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone() @@ -547,11 +543,10 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, 1); SubtokenEnabled::::insert(netuid, true); Subtensor::::set_network_registration_allowed(netuid, true); - Subtensor::::set_burn(netuid, 1.into()); let amount_to_be_staked = 1_000_000_000; Subtensor::::add_balance_to_coldkey_account(&coldkey, amount_to_be_staked); - assert_ok!(Subtensor::::do_burned_registration( + assert_ok!(Subtensor::::do_registration( RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone() @@ -590,11 +585,10 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, 1); SubtokenEnabled::::insert(netuid, true); Subtensor::::set_network_registration_allowed(netuid, true); - Subtensor::::set_burn(netuid, 1.into()); let amount_to_be_staked: u64 = 1_000_000_000; Subtensor::::add_balance_to_coldkey_account(&coldkey, amount_to_be_staked); - assert_ok!(Subtensor::::do_burned_registration( + assert_ok!(Subtensor::::do_registration( RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone() @@ -632,12 +626,11 @@ mod pallet_benchmarks { SubtokenEnabled::::insert(netuid, true); Subtensor::::set_network_registration_allowed(netuid, true); - Subtensor::::set_burn(netuid, 1.into()); let amount_to_be_staked = 1_000_000; Subtensor::::add_balance_to_coldkey_account(&coldkey, amount_to_be_staked); SubnetOwner::::set(netuid, coldkey.clone()); - assert_ok!(Subtensor::::do_burned_registration( + assert_ok!(Subtensor::::do_registration( RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone() @@ -677,7 +670,6 @@ mod pallet_benchmarks { Subtensor::::init_new_network(netuid, tempo); SubtokenEnabled::::insert(netuid, true); - Subtensor::::set_burn(netuid, 1.into()); Subtensor::::set_network_registration_allowed(netuid, true); Subtensor::::set_max_allowed_uids(netuid, 4096); @@ -694,7 +686,7 @@ mod pallet_benchmarks { SubnetTAO::::insert(netuid, tao_reserve); SubnetAlphaIn::::insert(netuid, alpha_in); - assert_ok!(Subtensor::::do_burned_registration( + assert_ok!(Subtensor::::do_registration( RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone() @@ -721,10 +713,16 @@ mod pallet_benchmarks { SubtokenEnabled::::insert(netuid, true); Subtensor::::init_new_network(netuid, 1); - let burn_fee = Subtensor::::get_burn(netuid); - let stake_tao = DefaultMinStake::::get().saturating_mul(10.into()); - let deposit = burn_fee.saturating_mul(2.into()).saturating_add(stake_tao); - Subtensor::::add_balance_to_coldkey_account(&coldkey, deposit.into()); + // Base burn fee in u64. + let burn_fee_u64: u64 = Subtensor::::get_burn(netuid); + + // Stake requirement in TaoCurrency (wrapper around u64). + let stake_tao: TaoCurrency = DefaultMinStake::::get().saturating_mul(10u64.into()); + + // Fund the account in base currency units (u64). + let stake_u64: u64 = u64::from(stake_tao); + let deposit_u64: u64 = burn_fee_u64.saturating_mul(2u64).saturating_add(stake_u64); + Subtensor::::add_balance_to_coldkey_account(&coldkey, deposit_u64); assert_ok!(Subtensor::::burned_register( RawOrigin::Signed(coldkey.clone()).into(), @@ -732,9 +730,11 @@ mod pallet_benchmarks { origin.clone() )); - SubnetTAO::::insert(netuid, deposit); - SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(deposit.to_u64())); - TotalStake::::set(deposit); + // Mirror that value in pallet accounting where TaoCurrency/AlphaCurrency are required. + let deposit_tao: TaoCurrency = deposit_u64.into(); + SubnetTAO::::insert(netuid, deposit_tao); + SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(u64::from(deposit_tao))); + TotalStake::::set(deposit_tao); assert_ok!(Subtensor::::add_stake_limit( RawOrigin::Signed(coldkey.clone()).into(), @@ -782,7 +782,6 @@ mod pallet_benchmarks { let coldkey: T::AccountId = account("Test", 0, seed); let hotkey: T::AccountId = account("Alice", 0, seed); - Subtensor::::set_burn(netuid, 1.into()); let limit = TaoCurrency::from(1_000_000_000); let tao_reserve = TaoCurrency::from(150_000_000_000); @@ -793,7 +792,7 @@ mod pallet_benchmarks { let wallet_bal = 1000000u32.into(); Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), wallet_bal); - assert_ok!(Subtensor::::do_burned_registration( + assert_ok!(Subtensor::::do_registration( RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone() @@ -899,10 +898,14 @@ mod pallet_benchmarks { SubtokenEnabled::::insert(netuid, true); Subtensor::::init_new_network(netuid, 1); - let reg_fee = Subtensor::::get_burn(netuid); - let stake_tao = DefaultMinStake::::get().saturating_mul(10.into()); - let deposit = reg_fee.saturating_mul(2.into()).saturating_add(stake_tao); - Subtensor::::add_balance_to_coldkey_account(&coldkey, deposit.into()); + let reg_fee: u64 = Subtensor::::get_burn(netuid); + let stake_tao: TaoCurrency = DefaultMinStake::::get().saturating_mul(10u64.into()); + + // Fund with base currency (u64) + let deposit_u64: u64 = reg_fee + .saturating_mul(2u64) + .saturating_add(u64::from(stake_tao)); + Subtensor::::add_balance_to_coldkey_account(&coldkey, deposit_u64); assert_ok!(Subtensor::::burned_register( RawOrigin::Signed(coldkey.clone()).into(), @@ -910,9 +913,11 @@ mod pallet_benchmarks { hot.clone() )); - SubnetTAO::::insert(netuid, deposit); - SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(deposit.to_u64())); - TotalStake::::set(deposit); + // Mirror into pallet ledgers (TaoCurrency/AlphaCurrency) + let deposit_tao: TaoCurrency = deposit_u64.into(); + SubnetTAO::::insert(netuid, deposit_tao); + SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(u64::from(deposit_tao))); + TotalStake::::set(deposit_tao); assert_ok!(Subtensor::::add_stake_limit( RawOrigin::Signed(coldkey.clone()).into(), @@ -954,10 +959,13 @@ mod pallet_benchmarks { SubtokenEnabled::::insert(netuid2, true); Subtensor::::init_new_network(netuid2, 1); - let reg_fee = Subtensor::::get_burn(netuid1); - let stake_tao = DefaultMinStake::::get().saturating_mul(10.into()); - let deposit = reg_fee.saturating_mul(2.into()).saturating_add(stake_tao); - Subtensor::::add_balance_to_coldkey_account(&coldkey, deposit.into()); + let reg_fee: u64 = Subtensor::::get_burn(netuid1); + let stake_tao: TaoCurrency = DefaultMinStake::::get().saturating_mul(10u64.into()); + + let deposit_u64: u64 = reg_fee + .saturating_mul(2u64) + .saturating_add(u64::from(stake_tao)); + Subtensor::::add_balance_to_coldkey_account(&coldkey, deposit_u64); assert_ok!(Subtensor::::burned_register( RawOrigin::Signed(coldkey.clone()).into(), @@ -965,11 +973,12 @@ mod pallet_benchmarks { hot.clone() )); - SubnetTAO::::insert(netuid1, deposit); - SubnetAlphaIn::::insert(netuid1, AlphaCurrency::from(deposit.to_u64())); - SubnetTAO::::insert(netuid2, deposit); - SubnetAlphaIn::::insert(netuid2, AlphaCurrency::from(deposit.to_u64())); - TotalStake::::set(deposit); + let deposit_tao: TaoCurrency = deposit_u64.into(); + SubnetTAO::::insert(netuid1, deposit_tao); + SubnetAlphaIn::::insert(netuid1, AlphaCurrency::from(u64::from(deposit_tao))); + SubnetTAO::::insert(netuid2, deposit_tao); + SubnetAlphaIn::::insert(netuid2, AlphaCurrency::from(u64::from(deposit_tao))); + TotalStake::::set(deposit_tao); assert_ok!(Subtensor::::add_stake_limit( RawOrigin::Signed(coldkey.clone()).into(), @@ -1008,8 +1017,8 @@ mod pallet_benchmarks { Subtensor::::set_network_pow_registration_allowed(netuid, true); SubtokenEnabled::::insert(netuid, true); - let reg_fee = Subtensor::::get_burn(netuid); - Subtensor::::add_balance_to_coldkey_account(&hotkey, reg_fee.to_u64().saturating_mul(2)); + let reg_fee: u64 = Subtensor::::get_burn(netuid); + Subtensor::::add_balance_to_coldkey_account(&hotkey, reg_fee.saturating_mul(2u64)); assert_ok!(Subtensor::::burned_register( RawOrigin::Signed(hotkey.clone()).into(), @@ -1048,8 +1057,8 @@ mod pallet_benchmarks { SubtokenEnabled::::insert(netuid, true); Subtensor::::set_commit_reveal_weights_enabled(netuid, false); - let reg_fee = Subtensor::::get_burn(netuid); - Subtensor::::add_balance_to_coldkey_account(&hotkey, reg_fee.to_u64().saturating_mul(2)); + let reg_fee: u64 = Subtensor::::get_burn(netuid); + Subtensor::::add_balance_to_coldkey_account(&hotkey, reg_fee.saturating_mul(2u64)); assert_ok!(Subtensor::::burned_register( RawOrigin::Signed(hotkey.clone()).into(), @@ -1116,21 +1125,21 @@ mod pallet_benchmarks { let caller: T::AccountId = whitelisted_caller(); let netuid = NetUid::from(1); let version: u32 = 1; - let ip: u128 = 0xC0A8_0001; - let port: u16 = 30333; - let ip_type: u8 = 4; - let proto: u8 = 0; - let p1: u8 = 0; - let p2: u8 = 0; + let ip: u128 = 0xC0A8_0001u128; + let port: u16 = 30333u16; + let ip_type: u8 = 4u8; + let proto: u8 = 0u8; + let p1: u8 = 0u8; + let p2: u8 = 0u8; let cert: Vec = vec![]; Subtensor::::init_new_network(netuid, 1); Subtensor::::set_network_registration_allowed(netuid, true); SubtokenEnabled::::insert(netuid, true); - let reg_fee = Subtensor::::get_burn(netuid); - let deposit = reg_fee.saturating_mul(2.into()); - Subtensor::::add_balance_to_coldkey_account(&caller, deposit.into()); + let reg_fee: u64 = Subtensor::::get_burn(netuid); + let deposit_u64: u64 = reg_fee.saturating_mul(2u64); + Subtensor::::add_balance_to_coldkey_account(&caller, deposit_u64); assert_ok!(Subtensor::::burned_register( RawOrigin::Signed(caller.clone()).into(), @@ -1273,14 +1282,13 @@ mod pallet_benchmarks { let coldkey: T::AccountId = account("Test", 0, seed); let hotkey: T::AccountId = account("Alice", 0, seed); - Subtensor::::set_burn(netuid, 1.into()); SubnetTAO::::insert(netuid, TaoCurrency::from(150_000_000_000)); SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(100_000_000_000)); Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), 1000000u32.into()); - assert_ok!(Subtensor::::do_burned_registration( + assert_ok!(Subtensor::::do_registration( RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone() @@ -1321,7 +1329,6 @@ mod pallet_benchmarks { let coldkey: T::AccountId = account("Test", 0, seed); let hotkey: T::AccountId = account("Alice", 0, seed); - Subtensor::::set_burn(netuid, 1.into()); let limit = TaoCurrency::from(1_000_000_000); let tao_reserve = TaoCurrency::from(150_000_000_000); @@ -1332,7 +1339,7 @@ mod pallet_benchmarks { let wallet_bal = 1000000u32.into(); Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), wallet_bal); - assert_ok!(Subtensor::::do_burned_registration( + assert_ok!(Subtensor::::do_registration( RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone() @@ -1533,11 +1540,8 @@ mod pallet_benchmarks { Subtensor::::set_network_pow_registration_allowed(netuid, true); SubtokenEnabled::::insert(netuid, true); - let reg_fee = Subtensor::::get_burn(netuid); - Subtensor::::add_balance_to_coldkey_account( - &hotkey, - reg_fee.saturating_mul(2.into()).into(), - ); + let reg_fee: u64 = Subtensor::::get_burn(netuid); + Subtensor::::add_balance_to_coldkey_account(&hotkey, reg_fee.saturating_mul(2u64)); assert_ok!(Subtensor::::burned_register( RawOrigin::Signed(hotkey.clone()).into(), diff --git a/pallets/subtensor/src/coinbase/block_step.rs b/pallets/subtensor/src/coinbase/block_step.rs index 6a96090b0..b7e8880cc 100644 --- a/pallets/subtensor/src/coinbase/block_step.rs +++ b/pallets/subtensor/src/coinbase/block_step.rs @@ -8,18 +8,16 @@ impl Pallet { pub fn block_step() -> Result<(), &'static str> { let block_number: u64 = Self::get_current_block_as_u64(); log::debug!("block_step for block: {block_number:?} "); - // --- 1. Adjust difficulties. - Self::adjust_registration_terms_for_networks(); - // --- 2. Get the current coinbase emission. + // --- 1. Get the current coinbase emission. let block_emission: U96F32 = U96F32::saturating_from_num( Self::get_block_emission() .unwrap_or(TaoCurrency::ZERO) .to_u64(), ); log::debug!("Block emission: {block_emission:?}"); - // --- 3. Run emission through network. + // --- 2. Run emission through network. Self::run_coinbase(block_emission); - // --- 4. Set pending children on the epoch; but only after the coinbase has been run. + // --- 3. Set pending children on the epoch; but only after the coinbase has been run. Self::try_set_pending_children(block_number); // Return ok. Ok(()) @@ -33,226 +31,4 @@ impl Pallet { } } } - - /// Adjusts the network difficulties/burns of every active network. Resetting state parameters. - /// - pub fn adjust_registration_terms_for_networks() { - log::debug!("adjust_registration_terms_for_networks"); - - // --- 1. Iterate through each network. - for (netuid, _) in NetworksAdded::::iter() { - // --- 2. Pull counters for network difficulty. - let last_adjustment_block: u64 = Self::get_last_adjustment_block(netuid); - let adjustment_interval: u16 = Self::get_adjustment_interval(netuid); - let current_block: u64 = Self::get_current_block_as_u64(); - log::debug!( - "netuid: {netuid:?} last_adjustment_block: {last_adjustment_block:?} adjustment_interval: {adjustment_interval:?} current_block: {current_block:?}" - ); - - // --- 3. Check if we are at the adjustment interval for this network. - // If so, we need to adjust the registration difficulty based on target and actual registrations. - if current_block.saturating_sub(last_adjustment_block) >= adjustment_interval as u64 { - log::debug!("interval reached."); - - // --- 4. Get the current counters for this network w.r.t burn and difficulty values. - let current_burn = Self::get_burn(netuid); - let current_difficulty: u64 = Self::get_difficulty_as_u64(netuid); - let registrations_this_interval: u16 = - Self::get_registrations_this_interval(netuid); - let pow_registrations_this_interval: u16 = - Self::get_pow_registrations_this_interval(netuid); - let burn_registrations_this_interval: u16 = - Self::get_burn_registrations_this_interval(netuid); - let target_registrations_this_interval: u16 = - Self::get_target_registrations_per_interval(netuid); - // --- 5. Adjust burn + pow - // There are six cases to consider. A, B, C, D, E, F - if registrations_this_interval > target_registrations_this_interval { - #[allow(clippy::comparison_chain)] - if pow_registrations_this_interval > burn_registrations_this_interval { - // A. There are too many registrations this interval and most of them are pow registrations - // this triggers an increase in the pow difficulty. - // pow_difficulty ++ - Self::set_difficulty( - netuid, - Self::upgraded_difficulty( - netuid, - current_difficulty, - registrations_this_interval, - target_registrations_this_interval, - ), - ); - } else if pow_registrations_this_interval < burn_registrations_this_interval { - // B. There are too many registrations this interval and most of them are burn registrations - // this triggers an increase in the burn cost. - // burn_cost ++ - Self::set_burn( - netuid, - Self::upgraded_burn( - netuid, - current_burn, - registrations_this_interval, - target_registrations_this_interval, - ), - ); - } else { - // F. There are too many registrations this interval and the pow and burn registrations are equal - // this triggers an increase in the burn cost and pow difficulty - // burn_cost ++ - Self::set_burn( - netuid, - Self::upgraded_burn( - netuid, - current_burn, - registrations_this_interval, - target_registrations_this_interval, - ), - ); - // pow_difficulty ++ - Self::set_difficulty( - netuid, - Self::upgraded_difficulty( - netuid, - current_difficulty, - registrations_this_interval, - target_registrations_this_interval, - ), - ); - } - } else { - // Not enough registrations this interval. - #[allow(clippy::comparison_chain)] - if pow_registrations_this_interval > burn_registrations_this_interval { - // C. There are not enough registrations this interval and most of them are pow registrations - // this triggers a decrease in the burn cost - // burn_cost -- - Self::set_burn( - netuid, - Self::upgraded_burn( - netuid, - current_burn, - registrations_this_interval, - target_registrations_this_interval, - ), - ); - } else if pow_registrations_this_interval < burn_registrations_this_interval { - // D. There are not enough registrations this interval and most of them are burn registrations - // this triggers a decrease in the pow difficulty - // pow_difficulty -- - Self::set_difficulty( - netuid, - Self::upgraded_difficulty( - netuid, - current_difficulty, - registrations_this_interval, - target_registrations_this_interval, - ), - ); - } else { - // E. There are not enough registrations this interval and the pow and burn registrations are equal - // this triggers a decrease in the burn cost and pow difficulty - // burn_cost -- - Self::set_burn( - netuid, - Self::upgraded_burn( - netuid, - current_burn, - registrations_this_interval, - target_registrations_this_interval, - ), - ); - // pow_difficulty -- - Self::set_difficulty( - netuid, - Self::upgraded_difficulty( - netuid, - current_difficulty, - registrations_this_interval, - target_registrations_this_interval, - ), - ); - } - } - - // --- 6. Drain all counters for this network for this interval. - Self::set_last_adjustment_block(netuid, current_block); - Self::set_registrations_this_interval(netuid, 0); - Self::set_pow_registrations_this_interval(netuid, 0); - Self::set_burn_registrations_this_interval(netuid, 0); - } else { - log::debug!("interval not reached."); - } - - // --- 7. Drain block registrations for each network. Needed for registration rate limits. - Self::set_registrations_this_block(netuid, 0); - } - } - - /// Calculates the upgraded difficulty by multiplying the current difficulty by the ratio ( reg_actual + reg_target / reg_target + reg_target ) - /// We use U110F18 to avoid any overflows on u64. Also min_difficulty and max_difficulty bound the range. - /// - pub fn upgraded_difficulty( - netuid: NetUid, - current_difficulty: u64, - registrations_this_interval: u16, - target_registrations_per_interval: u16, - ) -> u64 { - let updated_difficulty: U110F18 = U110F18::saturating_from_num(current_difficulty) - .saturating_mul(U110F18::saturating_from_num( - registrations_this_interval.saturating_add(target_registrations_per_interval), - )) - .safe_div(U110F18::saturating_from_num( - target_registrations_per_interval.saturating_add(target_registrations_per_interval), - )); - let alpha: U110F18 = U110F18::saturating_from_num(Self::get_adjustment_alpha(netuid)) - .safe_div(U110F18::saturating_from_num(u64::MAX)); - let next_value: U110F18 = alpha - .saturating_mul(U110F18::saturating_from_num(current_difficulty)) - .saturating_add( - U110F18::saturating_from_num(1.0) - .saturating_sub(alpha) - .saturating_mul(updated_difficulty), - ); - if next_value >= U110F18::saturating_from_num(Self::get_max_difficulty(netuid)) { - Self::get_max_difficulty(netuid) - } else if next_value <= U110F18::saturating_from_num(Self::get_min_difficulty(netuid)) { - return Self::get_min_difficulty(netuid); - } else { - return next_value.saturating_to_num::(); - } - } - - /// Calculates the upgraded burn by multiplying the current burn by the ratio ( reg_actual + reg_target / reg_target + reg_target ) - /// We use U110F18 to avoid any overflows on u64. Also min_burn and max_burn bound the range. - /// - pub fn upgraded_burn( - netuid: NetUid, - current_burn: TaoCurrency, - registrations_this_interval: u16, - target_registrations_per_interval: u16, - ) -> TaoCurrency { - let updated_burn: U110F18 = U110F18::saturating_from_num(current_burn) - .saturating_mul(U110F18::saturating_from_num( - registrations_this_interval.saturating_add(target_registrations_per_interval), - )) - .safe_div(U110F18::saturating_from_num( - target_registrations_per_interval.saturating_add(target_registrations_per_interval), - )); - let alpha: U110F18 = U110F18::saturating_from_num(Self::get_adjustment_alpha(netuid)) - .safe_div(U110F18::saturating_from_num(u64::MAX)); - let next_value: U110F18 = alpha - .saturating_mul(U110F18::saturating_from_num(current_burn)) - .saturating_add( - U110F18::saturating_from_num(1.0) - .saturating_sub(alpha) - .saturating_mul(updated_burn), - ); - if next_value >= U110F18::saturating_from_num(Self::get_max_burn(netuid)) { - Self::get_max_burn(netuid) - } else if next_value <= U110F18::saturating_from_num(Self::get_min_burn(netuid)) { - return Self::get_min_burn(netuid); - } else { - return next_value.saturating_to_num::().into(); - } - } } diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index c52c589ad..383ce4830 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -81,7 +81,10 @@ pub mod pallet { use pallet_drand::types::RoundNumber; use runtime_common::prod_or_fast; use sp_core::{ConstU32, H160, H256}; - use sp_runtime::traits::{Dispatchable, TrailingZeroInput}; + use sp_runtime::{ + FixedU128, + traits::{Dispatchable, TrailingZeroInput}, + }; use sp_std::collections::vec_deque::VecDeque; use sp_std::vec; use sp_std::vec::Vec; @@ -1924,6 +1927,52 @@ pub mod pallet { pub type MechanismEmissionSplit = StorageMap<_, Twox64Concat, NetUid, Vec, OptionQuery>; + #[pallet::storage] + /// Blocks per halving of the registration burn price for a given subnet. + /// - Key: `NetUid` + /// - Value: `u64` (blocks) + /// - Default (via ValueQuery): `0` (interpreted as "unset"; runtime helper applies 360) + pub type BurnHalfLife = StorageMap<_, Blake2_128Concat, NetUid, u64, ValueQuery>; + + #[pallet::storage] + /// Multiplier applied to the burn price **the block after** a registration. + /// - Key: `NetUid` + /// - Value: `FixedU128` + /// - Default (via ValueQuery): `0` (interpreted as "unset"; runtime helper applies 2.0) + pub type BurnIncreaseMult = + StorageMap<_, Blake2_128Concat, NetUid, FixedU128, ValueQuery>; + + #[pallet::storage] + /// Current burn price in base units (e.g., RAO) **at the last anchoring point**. + /// Actual "now" price is derived by applying queued bumps (if effective) and + /// stepwise half-life decay from `BurnLastUpdate`. + /// - Key: `NetUid` + /// - Value: `u128` (base units) + /// - Default (via ValueQuery): `0` (interpreted as "unset"; runtime helper applies 1 TAO) + pub type BurnPrice = StorageMap<_, Blake2_128Concat, NetUid, u128, ValueQuery>; + + #[pallet::storage] + /// Block number of the last anchor used for stepwise half-life decay. + /// - Key: `NetUid` + /// - Value: `u64` (block number) + /// - Default (via ValueQuery): `0` (interpreted as "unset"; set to current block on init) + pub type BurnLastUpdate = StorageMap<_, Blake2_128Concat, NetUid, u64, ValueQuery>; + + #[pallet::storage] + /// Number of price-bump applications queued by registrations in the current block. + /// They take effect **at `BurnPendingFrom`** (typically next block). + /// - Key: `NetUid` + /// - Value: `u32` + /// - Default: `0` + pub type BurnPendingBumps = StorageMap<_, Blake2_128Concat, NetUid, u32, ValueQuery>; + + #[pallet::storage] + /// First block at which the queued bumps in `BurnPendingBumps` become effective. + /// - Key: `NetUid` + /// - Value: `u64` (block number) + /// - Default: `0` (means "no pending bumps") + pub type BurnPendingFrom = StorageMap<_, Blake2_128Concat, NetUid, u64, ValueQuery>; + /// ================== /// ==== Genesis ===== /// ================== diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 01f064fae..ce1fcf220 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -1017,13 +1017,13 @@ mod dispatches { pub fn register( origin: OriginFor, netuid: NetUid, - block_number: u64, - nonce: u64, - work: Vec, + _block_number: u64, + _nonce: u64, + _work: Vec, hotkey: T::AccountId, - coldkey: T::AccountId, + _coldkey: T::AccountId, ) -> DispatchResult { - Self::do_registration(origin, netuid, block_number, nonce, work, hotkey, coldkey) + Self::do_registration(origin, netuid, hotkey) } /// Register the hotkey to root network @@ -1054,7 +1054,7 @@ mod dispatches { netuid: NetUid, hotkey: T::AccountId, ) -> DispatchResult { - Self::do_burned_registration(origin, netuid, hotkey) + Self::do_registration(origin, netuid, hotkey) } /// The extrinsic for user to change its hotkey in subnet or all subnets. diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index 759e74f6e..57b59185a 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -264,5 +264,7 @@ mod errors { TrimmingWouldExceedMaxImmunePercentage, /// Violating the rules of Childkey-Parentkey consistency ChildParentInconsistency, + /// The caller is attempting to register a neuron with insufficient funds. + NotEnoughBalanceToRegister, } } diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index c34219d53..c67f80973 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -456,5 +456,17 @@ mod events { /// The account ID of the hotkey. hotkey: T::AccountId, }, + + /// Burn half-life was (re)set for a subnet. + /// (netuid, half_life_blocks) + BurnHalfLifeSet(NetUid, u64), + + /// Burn increase multiplier was (re)set for a subnet. + /// (netuid, multiplier as FixedU128) + BurnIncreaseMultSet(NetUid, FixedU128), + + /// Burn price lazily initialized for a subnet. + /// (netuid, initial_price_base_units) + BurnPriceInitialized(NetUid, u128), } } diff --git a/pallets/subtensor/src/macros/hooks.rs b/pallets/subtensor/src/macros/hooks.rs index 20651f68f..e255887c7 100644 --- a/pallets/subtensor/src/macros/hooks.rs +++ b/pallets/subtensor/src/macros/hooks.rs @@ -90,7 +90,7 @@ mod hooks { // Upgrade identities to V2 .saturating_add(migrations::migrate_identities_v2::migrate_identities_to_v2::()) // Set the min burn across all subnets to a new minimum - .saturating_add(migrations::migrate_set_min_burn::migrate_set_min_burn::()) + //.saturating_add(migrations::migrate_set_min_burn::migrate_set_min_burn::()) // Set the min difficulty across all subnets to a new minimum .saturating_add(migrations::migrate_set_min_difficulty::migrate_set_min_difficulty::()) // Remove Stake map entries diff --git a/pallets/subtensor/src/migrations/mod.rs b/pallets/subtensor/src/migrations/mod.rs index e92b86aa2..76b7434d4 100644 --- a/pallets/subtensor/src/migrations/mod.rs +++ b/pallets/subtensor/src/migrations/mod.rs @@ -37,7 +37,6 @@ pub mod migrate_remove_zero_total_hotkey_alpha; pub mod migrate_reset_bonds_moving_average; pub mod migrate_reset_max_burn; pub mod migrate_set_first_emission_block_number; -pub mod migrate_set_min_burn; pub mod migrate_set_min_difficulty; pub mod migrate_set_nominator_min_stake; pub mod migrate_set_registration_enable; diff --git a/pallets/subtensor/src/rpc_info/metagraph.rs b/pallets/subtensor/src/rpc_info/metagraph.rs index 2ec772b2c..efc52e12a 100644 --- a/pallets/subtensor/src/rpc_info/metagraph.rs +++ b/pallets/subtensor/src/rpc_info/metagraph.rs @@ -694,7 +694,7 @@ impl Pallet { alpha_in_emission: SubnetAlphaInEmission::::get(netuid).into(), // amount injected outstanding per block tao_in_emission: SubnetTaoInEmission::::get(netuid).into(), // amount of tao injected per block pending_alpha_emission: PendingEmission::::get(netuid).into(), // pending alpha to be distributed - pending_root_emission: PendingRootDivs::::get(netuid).into(), // panding tao for root divs to be distributed + pending_root_emission: PendingRootDivs::::get(netuid).into(), // pending tao for root divs to be distributed subnet_volume: subnet_volume.into(), moving_price: SubnetMovingPrice::::get(netuid), @@ -716,16 +716,19 @@ impl Pallet { registration_allowed: Self::get_network_registration_allowed(netuid), // allows registrations. pow_registration_allowed: Self::get_network_pow_registration_allowed(netuid), // allows pow registrations. difficulty: Self::get_difficulty_as_u64(netuid).into(), // current difficulty. - burn: Self::get_burn(netuid).into(), + burn: TaoCurrency::from(Self::get_burn(netuid)).into(), + immunity_period: Self::get_immunity_period(netuid).into(), // subnet miner immunity period min_difficulty: Self::get_min_difficulty(netuid).into(), // min pow difficulty max_difficulty: Self::get_max_difficulty(netuid).into(), // max pow difficulty - min_burn: Self::get_min_burn(netuid).into(), // min tao burn - max_burn: Self::get_max_burn(netuid).into(), // max tao burn - adjustment_alpha: Self::get_adjustment_alpha(netuid).into(), // adjustment speed for registration params. - adjustment_interval: Self::get_adjustment_interval(netuid).into(), // pow and burn adjustment interval - target_regs_per_interval: Self::get_target_registrations_per_interval(netuid).into(), // target registrations per interval - max_regs_per_block: Self::get_max_registrations_per_block(netuid).into(), // max registrations per block. + + min_burn: TaoCurrency::ZERO.into(), + max_burn: TaoCurrency::MAX.into(), + + adjustment_alpha: Self::get_adjustment_alpha(netuid).into(), // legacy field still exposed + adjustment_interval: Self::get_adjustment_interval(netuid).into(), // legacy field still exposed + target_regs_per_interval: Self::get_target_registrations_per_interval(netuid).into(), // legacy + max_regs_per_block: Self::get_max_registrations_per_block(netuid).into(), // legacy serving_rate_limit: Self::get_serving_rate_limit(netuid).into(), // axon serving rate limit // CR @@ -1093,7 +1096,7 @@ impl Pallet { Some(SelectiveMetagraphIndex::Burn) => SelectiveMetagraph { netuid: netuid.into(), - burn: Some(Self::get_burn(netuid).into()), + burn: Some(TaoCurrency::from(Self::get_burn(netuid)).into()), ..Default::default() }, @@ -1114,12 +1117,12 @@ impl Pallet { }, Some(SelectiveMetagraphIndex::MinBurn) => SelectiveMetagraph { netuid: netuid.into(), - min_burn: Some(Self::get_min_burn(netuid).into()), + min_burn: Some(TaoCurrency::ZERO.into()), ..Default::default() }, Some(SelectiveMetagraphIndex::MaxBurn) => SelectiveMetagraph { netuid: netuid.into(), - max_burn: Some(Self::get_max_burn(netuid).into()), + max_burn: Some(TaoCurrency::MAX.into()), ..Default::default() }, Some(SelectiveMetagraphIndex::AdjustmentAlpha) => SelectiveMetagraph { diff --git a/pallets/subtensor/src/rpc_info/subnet_info.rs b/pallets/subtensor/src/rpc_info/subnet_info.rs index 6a7966b4f..f3f0613a5 100644 --- a/pallets/subtensor/src/rpc_info/subnet_info.rs +++ b/pallets/subtensor/src/rpc_info/subnet_info.rs @@ -141,12 +141,10 @@ impl Pallet { let max_allowed_uids = Self::get_max_allowed_uids(netuid); let blocks_since_last_step = Self::get_blocks_since_last_step(netuid); let tempo = Self::get_tempo(netuid); - let burn = Compact::from(Self::get_burn(netuid)); + let burn: Compact = Compact::from(TaoCurrency::from(Self::get_burn(netuid))); + // DEPRECATED let network_connect: Vec<[u16; 2]> = Vec::<[u16; 2]>::new(); - // DEPRECATED for ( _netuid_, con_req) in < NetworkConnect as IterableStorageDoubleMap >::iter_prefix(netuid) { - // network_connect.push([_netuid_, con_req]); - // } Some(SubnetInfo { rho: rho.into(), @@ -209,14 +207,12 @@ impl Pallet { let max_allowed_uids = Self::get_max_allowed_uids(netuid); let blocks_since_last_step = Self::get_blocks_since_last_step(netuid); let tempo = Self::get_tempo(netuid); - let burn = Compact::from(Self::get_burn(netuid)); + + let burn: Compact = Compact::from(TaoCurrency::from(Self::get_burn(netuid))); let identity: Option = SubnetIdentitiesV3::::get(netuid); // DEPRECATED let network_connect: Vec<[u16; 2]> = Vec::<[u16; 2]>::new(); - // DEPRECATED for ( _netuid_, con_req) in < NetworkConnect as IterableStorageDoubleMap >::iter_prefix(netuid) { - // network_connect.push([_netuid_, con_req]); - // } Some(SubnetInfov2 { rho: rho.into(), @@ -282,8 +278,11 @@ impl Pallet { let activity_cutoff = Self::get_activity_cutoff(netuid); let registration_allowed = Self::get_network_registration_allowed(netuid); let target_regs_per_interval = Self::get_target_registrations_per_interval(netuid); - let min_burn = Self::get_min_burn(netuid); - let max_burn = Self::get_max_burn(netuid); + + // Old getters removed under the new burn mechanism: use sentinel values. + let min_burn: TaoCurrency = TaoCurrency::ZERO; + let max_burn: TaoCurrency = TaoCurrency::MAX; + let bonds_moving_avg = Self::get_bonds_moving_average(netuid); let max_regs_per_block = Self::get_max_registrations_per_block(netuid); let serving_rate_limit = Self::get_serving_rate_limit(netuid); @@ -325,7 +324,6 @@ impl Pallet { liquid_alpha_enabled, }) } - pub fn get_subnet_hyperparams_v2(netuid: NetUid) -> Option { if !Self::if_subnet_exist(netuid) { return None; @@ -345,8 +343,11 @@ impl Pallet { let activity_cutoff = Self::get_activity_cutoff(netuid); let registration_allowed = Self::get_network_registration_allowed(netuid); let target_regs_per_interval = Self::get_target_registrations_per_interval(netuid); - let min_burn = Self::get_min_burn(netuid); - let max_burn = Self::get_max_burn(netuid); + + // Old getters removed under the new burn mechanism: use sentinel values. + let min_burn: TaoCurrency = TaoCurrency::ZERO; + let max_burn: TaoCurrency = TaoCurrency::MAX; + let bonds_moving_avg = Self::get_bonds_moving_average(netuid); let max_regs_per_block = Self::get_max_registrations_per_block(netuid); let serving_rate_limit = Self::get_serving_rate_limit(netuid); @@ -358,9 +359,10 @@ impl Pallet { let liquid_alpha_enabled = Self::get_liquid_alpha_enabled(netuid); let (alpha_low, alpha_high): (u16, u16) = Self::get_alpha_values(netuid); let alpha_sigmoid_steepness = Self::get_alpha_sigmoid_steepness(netuid); - let yuma_version: u16 = match Self::get_yuma3_enabled(netuid) { - true => 3u16, - false => 2u16, + let yuma_version: u16 = if Self::get_yuma3_enabled(netuid) { + 3u16 + } else { + 2u16 }; let subnet_token_enabled = Self::get_subtoken_enabled(netuid); let transfers_enabled = Self::get_transfer_toggle(netuid); diff --git a/pallets/subtensor/src/subnets/registration.rs b/pallets/subtensor/src/subnets/registration.rs index b71aa68a0..f5e95feea 100644 --- a/pallets/subtensor/src/subnets/registration.rs +++ b/pallets/subtensor/src/subnets/registration.rs @@ -1,7 +1,7 @@ use super::*; use sp_core::{H256, U256}; use sp_io::hashing::{keccak_256, sha2_256}; -use sp_runtime::Saturating; +use sp_runtime::{FixedPointNumber, FixedU128, Saturating}; use subtensor_runtime_common::{Currency, NetUid}; use subtensor_swap_interface::SwapHandler; use system::pallet_prelude::BlockNumberFor; @@ -64,7 +64,7 @@ impl Pallet { /// * 'HotKeyAlreadyRegisteredInSubNet': /// - The hotkey is already registered on this network. /// - pub fn do_burned_registration( + pub fn do_registration( origin: T::RuntimeOrigin, netuid: NetUid, hotkey: T::AccountId, @@ -86,49 +86,35 @@ impl Pallet { Error::::SubNetRegistrationDisabled ); - // --- 4. Ensure we are not exceeding the max allowed registrations per block. - ensure!( - Self::get_registrations_this_block(netuid) - < Self::get_max_registrations_per_block(netuid), - Error::::TooManyRegistrationsThisBlock - ); - - // --- 4. Ensure we are not exceeding the max allowed registrations per interval. - ensure!( - Self::get_registrations_this_interval(netuid) - < Self::get_target_registrations_per_interval(netuid).saturating_mul(3), - Error::::TooManyRegistrationsThisInterval - ); - // --- 4. Ensure that the key is not already registered. ensure!( !Uids::::contains_key(netuid, &hotkey), Error::::HotKeyAlreadyRegisteredInSubNet ); - // --- 7. Ensure the callers coldkey has enough stake to perform the transaction. + // --- 5. Ensure the callers coldkey has enough balance to pay the current (block-by-block) burn price. let registration_cost = Self::get_burn(netuid); ensure!( Self::can_remove_balance_from_coldkey_account(&coldkey, registration_cost.into()), - Error::::NotEnoughBalanceToStake + Error::::NotEnoughBalanceToRegister ); // If the network account does not exist we will create it here. Self::create_account_if_non_existent(&coldkey, &hotkey); - // --- 8. Ensure that the pairing is correct. + // --- 6. Ensure that the pairing is correct. ensure!( Self::coldkey_owns_hotkey(&coldkey, &hotkey), Error::::NonAssociatedColdKey ); - // --- 9. Possibly there are no neuron slots at all. + // --- 7. Possibly there are no neuron slots at all. ensure!( Self::get_max_allowed_uids(netuid) != 0, Error::::NoNeuronIdAvailable ); - // --- 10. Ensure the remove operation from the coldkey is a success. + // --- 8. Remove funds from coldkey (actual amount burned is returned). let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, registration_cost.into())?; @@ -147,180 +133,123 @@ impl Pallet { // Actually perform the registration. let neuron_uid: u16 = Self::register_neuron(netuid, &hotkey); - // --- 14. Record the registration and increment block and interval counters. + // --- 9. Record the registration and increment counters. BurnRegistrationsThisInterval::::mutate(netuid, |val| val.saturating_inc()); RegistrationsThisInterval::::mutate(netuid, |val| val.saturating_inc()); RegistrationsThisBlock::::mutate(netuid, |val| val.saturating_inc()); - Self::increase_rao_recycled(netuid, Self::get_burn(netuid).into()); - // --- 15. Deposit successful event. - log::debug!("NeuronRegistered( netuid:{netuid:?} uid:{neuron_uid:?} hotkey:{hotkey:?} ) "); + // Account for recycled RAO using the actual amount burned. + Self::increase_rao_recycled(netuid, actual_burn_amount); + + // --- 10. Schedule a burn-price bump effective **next block**. + Self::schedule_burn_price_bump(netuid); + + // --- 11. Deposit successful event. + log::debug!("NeuronRegistered( netuid:{netuid:?} uid:{neuron_uid:?} hotkey:{hotkey:?} )"); Self::deposit_event(Event::NeuronRegistered(netuid, neuron_uid, hotkey)); - // --- 16. Ok and done. Ok(()) } - /// ---- The implementation for the extrinsic do_registration. - /// - /// # Args: - /// *'origin': (RuntimeOrigin): - /// - The signature of the calling hotkey. - /// - /// *'netuid' (u16): - /// - The u16 network identifier. - /// - /// *'block_number' ( u64 ): - /// - Block hash used to prove work done. - /// - /// *'nonce' ( u64 ): - /// - Positive integer nonce used in POW. - /// - /// *'work' ( Vec ): - /// - Vector encoded bytes representing work done. - /// - /// *'hotkey' ( T::AccountId ): - /// - Hotkey to be registered to the network. - /// - /// *'coldkey' ( T::AccountId ): - /// - Associated coldkey account. - /// - /// # Event: - /// *NeuronRegistered; - /// - On successfully registereing a uid to a neuron slot on a subnetwork. - /// - /// # Raises: - /// *'MechanismDoesNotExist': - /// - Attempting to registed to a non existent network. - /// - /// *'TooManyRegistrationsThisBlock': - /// - This registration exceeds the total allowed on this network this block. - /// - /// *'HotKeyAlreadyRegisteredInSubNet': - /// - The hotkey is already registered on this network. - /// - /// *'InvalidWorkBlock': - /// - The work has been performed on a stale, future, or non existent block. - /// - /// *'InvalidDifficulty': - /// - The work does not match the difficutly. - /// - /// *'InvalidSeal': - /// - The seal is incorrect. - /// - pub fn do_registration( - origin: T::RuntimeOrigin, - netuid: NetUid, - block_number: u64, - nonce: u64, - work: Vec, - hotkey: T::AccountId, - coldkey: T::AccountId, - ) -> DispatchResult { - // --- 1. Check that the caller has signed the transaction. - let signing_origin = ensure_signed(origin)?; - log::debug!( - "do_registration( origin:{signing_origin:?} netuid:{netuid:?} hotkey:{hotkey:?}, coldkey:{coldkey:?} )" - ); - - ensure!( - signing_origin == hotkey, - Error::::TransactorAccountShouldBeHotKey - ); - - // --- 2. Ensure the passed network is valid. - ensure!( - !netuid.is_root(), - Error::::RegistrationNotPermittedOnRootSubnet - ); - ensure!(Self::if_subnet_exist(netuid), Error::::SubnetNotExists); - - // --- 3. Ensure the passed network allows registrations. - ensure!( - Self::get_network_pow_registration_allowed(netuid), - Error::::SubNetRegistrationDisabled - ); - - // --- 4. Ensure we are not exceeding the max allowed registrations per block. - ensure!( - Self::get_registrations_this_block(netuid) - < Self::get_max_registrations_per_block(netuid), - Error::::TooManyRegistrationsThisBlock - ); + pub fn initialize_burn_price_if_needed(netuid: NetUid, now: u64) { + const ONE_TAO_BASE_UNITS: u128 = 1_000_000_000u128; - // --- 5. Ensure we are not exceeding the max allowed registrations per interval. - ensure!( - Self::get_registrations_this_interval(netuid) - < Self::get_target_registrations_per_interval(netuid).saturating_mul(3), - Error::::TooManyRegistrationsThisInterval - ); - - // --- 6. Ensure that the key is not already registered. - ensure!( - !Uids::::contains_key(netuid, &hotkey), - Error::::HotKeyAlreadyRegisteredInSubNet - ); - - // --- 7. Ensure the passed block number is valid, not in the future or too old. - // Work must have been done within 3 blocks (stops long range attacks). - let current_block_number: u64 = Self::get_current_block_as_u64(); - ensure!( - block_number <= current_block_number, - Error::::InvalidWorkBlock - ); - ensure!( - current_block_number.saturating_sub(block_number) < 3, - Error::::InvalidWorkBlock - ); - - // --- 8. Ensure the supplied work passes the difficulty. - let difficulty: U256 = Self::get_difficulty(netuid); - let work_hash: H256 = Self::vec_to_hash(work.clone()); - ensure!( - Self::hash_meets_difficulty(&work_hash, difficulty), - Error::::InvalidDifficulty - ); // Check that the work meets difficulty. - - // --- 7. Check Work is the product of the nonce, the block number, and hotkey. Add this as used work. - let seal: H256 = Self::create_seal_hash(block_number, nonce, &hotkey); - ensure!(seal == work_hash, Error::::InvalidSeal); - UsedWork::::insert(work.clone(), current_block_number); - - // DEPRECATED --- 8. Ensure that the key passes the registration requirement - // ensure!( - // Self::passes_network_connection_requirement(netuid, &hotkey), - // Error::::DidNotPassConnectedNetworkRequirement - // ); + // Default params if unset. + if BurnHalfLife::::get(netuid) == 0 { + BurnHalfLife::::insert(netuid, 360u64); + Self::deposit_event(Event::BurnHalfLifeSet(netuid, 360)); + } + if BurnIncreaseMult::::get(netuid).is_zero() { + // Use from_u32 for a literal 2.0 in fixed-point. + let two = FixedU128::from_u32(2); + BurnIncreaseMult::::insert(netuid, two); + Self::deposit_event(Event::BurnIncreaseMultSet(netuid, two)); + } - // --- 9. If the network account does not exist we will create it here. - Self::create_account_if_non_existent(&coldkey, &hotkey); + // Initial price for new subnets (1 TAO). + if BurnPrice::::get(netuid) == 0 { + BurnPrice::::insert(netuid, ONE_TAO_BASE_UNITS); + BurnLastUpdate::::insert(netuid, now); + BurnPendingBumps::::insert(netuid, 0); + BurnPendingFrom::::insert(netuid, 0); + Self::deposit_event(Event::BurnPriceInitialized(netuid, ONE_TAO_BASE_UNITS)); + } + } - // --- 10. Ensure that the pairing is correct. - ensure!( - Self::coldkey_owns_hotkey(&coldkey, &hotkey), - Error::::NonAssociatedColdKey - ); + /// Schedules the price bump so it takes effect **the next block**. + /// Multiple registrations within the same block accumulate multiplicatively and + /// will all apply at once on the next block. + pub fn schedule_burn_price_bump(netuid: NetUid) { + let now = Self::get_current_block_as_u64(); + BurnPendingBumps::::mutate(netuid, |n| *n = n.saturating_add(1)); + BurnPendingFrom::::mutate(netuid, |at| { + // If nothing pending or a past effective block is recorded, set to next block. + if *at <= now { + *at = now.saturating_add(1); + } + // else keep the earlier effective-from block so bumps coalesce. + }); + } - // Possibly there is no neuron slots at all. - ensure!( - Self::get_max_allowed_uids(netuid) != 0, - Error::::NoNeuronIdAvailable - ); + /// Internal: exponentiation by squaring for FixedU128. + pub fn fixed_pow_u32(base: FixedU128, exp: u32) -> FixedU128 { + if exp == 0 { + return FixedU128::one(); + } + let mut result = FixedU128::one(); + let mut b = base; + let mut e = exp; + while e > 0 { + if (e & 1) == 1 { + result = result.saturating_mul(b); + } + e >>= 1; + if e > 0 { + b = b.saturating_mul(b); + } + } + result + } - // Actually perform the registration. - let neuron_uid: u16 = Self::register_neuron(netuid, &hotkey); + /// Brings the burn price forward to now + pub fn update_burn_price_to_block(netuid: NetUid, now: u64) { + let mut price: u128 = BurnPrice::::get(netuid); + let mut last_anchor: u64 = BurnLastUpdate::::get(netuid); + let half_life: u64 = core::cmp::max(BurnHalfLife::::get(netuid), 1); // avoid div by 0 + + // 1) Apply queued bumps if we have reached their effective block. + let pending_from = BurnPendingFrom::::get(netuid); + let pending_ct = BurnPendingBumps::::get(netuid); + if pending_ct > 0 && now >= pending_from && pending_from > 0 { + let mult = BurnIncreaseMult::::get(netuid); + let bump = Self::fixed_pow_u32(mult, pending_ct); + price = bump.saturating_mul_int(price); + BurnPendingBumps::::insert(netuid, 0); + BurnPendingFrom::::insert(netuid, 0); + } - // --- 12. Record the registration and increment block and interval counters. - POWRegistrationsThisInterval::::mutate(netuid, |val| val.saturating_inc()); - RegistrationsThisInterval::::mutate(netuid, |val| val.saturating_inc()); - RegistrationsThisBlock::::mutate(netuid, |val| val.saturating_inc()); + // 2) Apply stepwise halving according to BurnHalfLife. + let delta_blocks = now.saturating_sub(last_anchor); + if delta_blocks >= half_life { + let halvings = delta_blocks / half_life; + // Divide by 2^halvings, keeping price >= 1. Cap loop for safety. + let mut h = core::cmp::min(halvings as u32, 128); + while h > 0 && price > 1 { + price = price.saturating_div(2); + h -= 1; + } + // Move the anchor to the last halving boundary. + last_anchor = last_anchor.saturating_add(halvings.saturating_mul(half_life)); + } - // --- 13. Deposit successful event. - log::debug!("NeuronRegistered( netuid:{netuid:?} uid:{neuron_uid:?} hotkey:{hotkey:?} ) "); - Self::deposit_event(Event::NeuronRegistered(netuid, neuron_uid, hotkey)); + // Floor at 1 unit to avoid zero price. + if price == 0 { + price = 1; + } - // --- 14. Ok and done. - Ok(()) + // 3) Persist. + BurnPrice::::insert(netuid, price); + BurnLastUpdate::::insert(netuid, last_anchor); } pub fn do_faucet( diff --git a/pallets/subtensor/src/tests/registration.rs b/pallets/subtensor/src/tests/registration.rs index 48e887d60..0af2c0813 100644 --- a/pallets/subtensor/src/tests/registration.rs +++ b/pallets/subtensor/src/tests/registration.rs @@ -1,1163 +1,332 @@ #![allow(clippy::unwrap_used)] +use super::mock::*; use crate::*; -use approx::assert_abs_diff_eq; -use frame_support::dispatch::DispatchInfo; -use frame_support::sp_runtime::{DispatchError, transaction_validity::TransactionSource}; -use frame_support::traits::Currency; -use frame_support::{assert_err, assert_noop, assert_ok}; -use frame_system::{Config, RawOrigin}; +use frame_support::{assert_err, assert_noop, assert_ok, sp_runtime::FixedU128, traits::Currency}; +use frame_system::Config; use sp_core::U256; -use sp_runtime::traits::{DispatchInfoOf, TransactionExtension, TxBaseImplication}; use subtensor_runtime_common::{AlphaCurrency, Currency as CurrencyT, NetUid, NetUidStorageIndex}; -use super::mock; -use super::mock::*; -use crate::transaction_extension::SubtensorTransactionExtension; -use crate::{AxonInfoOf, CustomTransactionError, Error}; - /******************************************** subscribing::subscribe() tests *********************************************/ #[test] -fn test_registration_difficulty() { - new_test_ext(1).execute_with(|| { - assert_eq!(SubtensorModule::get_difficulty(1.into()).as_u64(), 10000); - }); -} - -#[test] -fn test_registration_invalid_seal_hotkey() { +fn test_burn_price_init_defaults() { new_test_ext(1).execute_with(|| { - let block_number: u64 = 0; let netuid = NetUid::from(1); - let tempo: u16 = 13; - let hotkey_account_id_1: U256 = U256::from(1); - let hotkey_account_id_2: U256 = U256::from(2); - let coldkey_account_id: U256 = U256::from(667); // Neighbour of the beast, har har - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 0, - &hotkey_account_id_1, - ); - let (nonce2, work2): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 0, - &hotkey_account_id_1, - ); + add_network(netuid, 13, 0); - //add network - add_network(netuid, tempo, 0); + let now = SubtensorModule::get_current_block_as_u64(); + SubtensorModule::initialize_burn_price_if_needed(netuid, now); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id_1), - netuid, - block_number, - nonce, - work.clone(), - hotkey_account_id_1, - coldkey_account_id - )); - let result = SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id_2), - netuid, - block_number, - nonce2, - work2.clone(), - hotkey_account_id_2, - coldkey_account_id, + // Defaults configured by initialize_burn_price_if_needed + assert_eq!(BurnHalfLife::::get(netuid), 360); + assert_eq!( + BurnIncreaseMult::::get(netuid), + FixedU128::from_u32(2) ); - assert_eq!(result, Err(Error::::InvalidSeal.into())); + assert_eq!(BurnPrice::::get(netuid), 1_000_000_000u128); // 1 TAO base units + assert_eq!(BurnLastUpdate::::get(netuid), now); + assert_eq!(BurnPendingBumps::::get(netuid), 0); + assert_eq!(BurnPendingFrom::::get(netuid), 0); }); } #[test] -fn test_registration_ok() { +fn test_burn_increase_mult_default_getter() { new_test_ext(1).execute_with(|| { - let block_number: u64 = 0; let netuid = NetUid::from(1); - let tempo: u16 = 13; - let hotkey_account_id: U256 = U256::from(1); - let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 129123813, - &hotkey_account_id, - ); - - //add network - add_network(netuid, tempo, 0); - - // Subscribe and check extrinsic output - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id), - netuid, - block_number, - nonce, - work, - hotkey_account_id, - coldkey_account_id - )); - - // Check if neuron has added to the specified network(netuid) - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 1); + add_network(netuid, 13, 0); - //check if hotkey is added to the Hotkeys + // Clear to zero (default). Getter should return 2.0 + BurnIncreaseMult::::insert(netuid, FixedU128::zero()); assert_eq!( - SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey_account_id), - coldkey_account_id + SubtensorModule::get_burn_increase_mult(netuid), + FixedU128::from_u32(2) ); - // Check if the neuron has added to the Keys - let neuron_uid = - SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).unwrap(); - - assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).is_ok()); - // Check if neuron has added to Uids - let neuro_uid = - SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).unwrap(); - assert_eq!(neuro_uid, neuron_uid); - - // Check if the balance of this hotkey account for this subnetwork == 0 + // Non-zero should be returned verbatim. + BurnIncreaseMult::::insert(netuid, FixedU128::from_u32(3)); assert_eq!( - SubtensorModule::get_stake_for_uid_and_subnetwork(netuid, neuron_uid), - AlphaCurrency::ZERO + SubtensorModule::get_burn_increase_mult(netuid), + FixedU128::from_u32(3) ); }); } #[test] -fn test_registration_without_neuron_slot() { +fn test_burn_price_halves_after_half_life() { new_test_ext(1).execute_with(|| { - let block_number: u64 = 0; let netuid = NetUid::from(1); - let tempo: u16 = 13; - let hotkey_account_id: U256 = U256::from(1); - let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 129123813, - &hotkey_account_id, - ); - - //add network - add_network(netuid, tempo, 0); - SubtensorModule::set_max_allowed_uids(netuid, 0); - - assert_noop!( - SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id), - netuid, - block_number, - nonce, - work, - hotkey_account_id, - coldkey_account_id - ), - Error::::NoNeuronIdAvailable - ); - }); -} + add_network(netuid, 13, 0); -#[test] -fn test_registration_under_limit() { - new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let block_number: u64 = 0; - let hotkey_account_id: U256 = U256::from(1); - let coldkey_account_id = U256::from(667); - let who: ::AccountId = hotkey_account_id; + // Initialize to set defaults (half-life, multiplier, initial price). + let now = SubtensorModule::get_current_block_as_u64(); + SubtensorModule::initialize_burn_price_if_needed(netuid, now); - let max_registrants = 2; - SubtensorModule::set_target_registrations_per_interval(netuid, max_registrants); + let price0 = BurnPrice::::get(netuid); + let hl_u64 = BurnHalfLife::::get(netuid); + assert!(hl_u64 > 0); - let (nonce, work) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 129123813, - &hotkey_account_id, - ); - let work_clone = work.clone(); - let call = crate::Call::register { - netuid, - block_number, - nonce, - work: work_clone, - hotkey: hotkey_account_id, - coldkey: coldkey_account_id, - }; - let info: DispatchInfo = - DispatchInfoOf::<::RuntimeCall>::default(); - let extension = SubtensorTransactionExtension::::new(); - //does not actually call register - let result = extension.validate( - RawOrigin::Signed(who).into(), - &call.into(), - &info, - 10, - (), - &TxBaseImplication(()), - TransactionSource::External, - ); - assert_ok!(result); + // step_block expects u16; in our tests the half-life is small (e.g., 360), so this fits. + let hl_steps: u16 = hl_u64.try_into().expect("half-life fits u16 in tests"); + step_block(hl_steps); - //actually call register - add_network(netuid, 13, 0); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id), - netuid, - block_number, - nonce, - work, - hotkey_account_id, - coldkey_account_id - )); + let now2 = SubtensorModule::get_current_block_as_u64(); + SubtensorModule::update_burn_price_to_block(netuid, now2); - let current_registrants = SubtensorModule::get_registrations_this_interval(netuid); - let target_registrants = SubtensorModule::get_target_registrations_per_interval(netuid); - assert!(current_registrants <= target_registrants); + // Integer halving with possible +1 rounding tolerance. + let price1 = BurnPrice::::get(netuid); + let target = price0 / 2; + assert!(price1 == target || price1 == target.saturating_add(1)); }); } #[test] -fn test_registration_rate_limit_exceeded() { +fn test_burn_price_multiple_halvings() { new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let block_number: u64 = 0; - let hotkey_account_id: U256 = U256::from(1); - let coldkey_account_id = U256::from(667); - let who: ::AccountId = hotkey_account_id; + let netuid = NetUid::from(7); + add_network(netuid, 5, 0); - let target_registrants = 1; - let max_registrants = target_registrants * 3; - SubtensorModule::set_target_registrations_per_interval(netuid, target_registrants); - SubtensorModule::set_registrations_this_interval(netuid, max_registrants); + let start = SubtensorModule::get_current_block_as_u64(); + SubtensorModule::initialize_burn_price_if_needed(netuid, start); + let p0 = BurnPrice::::get(netuid); + let hl_u64 = BurnHalfLife::::get(netuid); - let (nonce, work) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 129123813, - &hotkey_account_id, - ); - let call = crate::Call::register { - netuid, - block_number, - nonce, - work, - hotkey: hotkey_account_id, - coldkey: coldkey_account_id, - }; - let info: DispatchInfo = - DispatchInfoOf::<::RuntimeCall>::default(); - let extension = SubtensorTransactionExtension::::new(); - let result = extension.validate( - RawOrigin::Signed(who).into(), - &call.into(), - &info, - 10, - (), - &TxBaseImplication(()), - TransactionSource::External, - ); + // Advance by 3 * half-life; convert to u16 for the test harness. + let three_hl_u64 = hl_u64.saturating_mul(3); + let steps: u16 = three_hl_u64 + .try_into() + .expect("3*half-life fits u16 in tests"); + step_block(steps); - // Expectation: The transaction should be rejected - assert_eq!( - result.unwrap_err(), - CustomTransactionError::RateLimitExceeded.into() - ); + let now3 = SubtensorModule::get_current_block_as_u64(); + SubtensorModule::update_burn_price_to_block(netuid, now3); - let current_registrants = SubtensorModule::get_registrations_this_interval(netuid); - assert!(current_registrants <= max_registrants); + // After 3 halvings, price ≈ p0 / 8 (allow +1 rounding tolerance). + let p3 = BurnPrice::::get(netuid); + let tgt = p0 / 8; + assert!(p3 == tgt || p3 == tgt.saturating_add(1)); }); } -/******************************************** - registration::do_burned_registration tests -*********************************************/ - #[test] -fn test_burned_registration_under_limit() { +fn test_burn_price_bump_applies_next_block() { new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let hotkey_account_id: U256 = U256::from(1); - let coldkey_account_id = U256::from(667); - let who: ::AccountId = coldkey_account_id; - let burn_cost = 1000; - // Set the burn cost - SubtensorModule::set_burn(netuid, burn_cost.into()); - - let reserve = 1_000_000_000_000; - mock::setup_reserves(netuid, reserve.into(), reserve.into()); - - add_network(netuid, 13, 0); // Add the network - // Give it some TAO to the coldkey balance; more than the burn cost - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, burn_cost + 10_000); + let netuid = NetUid::from(11); + add_network(netuid, 13, 0); - let target_registrants = 2; - let max_registrants = target_registrants * 3; // Maximum is 3 times the target - SubtensorModule::set_target_registrations_per_interval(netuid, target_registrants); + // Initialize + let now = SubtensorModule::get_current_block_as_u64(); + SubtensorModule::initialize_burn_price_if_needed(netuid, now); - let call_burned_register: crate::Call = crate::Call::burned_register { - netuid, - hotkey: hotkey_account_id, - }; - - let info: DispatchInfo = - DispatchInfoOf::<::RuntimeCall>::default(); - let extension = SubtensorTransactionExtension::::new(); - //does not actually call register - let burned_register_result = extension.validate( - RawOrigin::Signed(who).into(), - &call_burned_register.into(), - &info, - 10, - (), - &TxBaseImplication(()), - TransactionSource::External, - ); - assert_ok!(burned_register_result); + // Prepare swap reserves and funds + let reserve = 1_000_000_000_000u64; + setup_reserves(netuid, reserve.into(), reserve.into()); + let price_now = SubtensorModule::get_burn(netuid); + let cold = U256::from(999); + let hot = U256::from(123); + SubtensorModule::add_balance_to_coldkey_account(&cold, price_now.saturating_mul(10)); - //actually call register + // One registration this block schedules a bump for next block assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(coldkey_account_id), + <::RuntimeOrigin>::signed(cold), netuid, - hotkey_account_id, + hot )); - let current_registrants = SubtensorModule::get_registrations_this_interval(netuid); - assert!(current_registrants <= max_registrants); - }); -} - -#[test] -fn test_burned_registration_rate_limit_exceeded() { - new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let hotkey_account_id: U256 = U256::from(1); - let coldkey_account_id = U256::from(667); - let who: ::AccountId = coldkey_account_id; - - let target_registrants = 1; - let max_registrants = target_registrants * 3; // Maximum is 3 times the target - - SubtensorModule::set_target_registrations_per_interval(netuid, target_registrants); - // Set the current registrations to the maximum; should not be able to register more - SubtensorModule::set_registrations_this_interval(netuid, max_registrants); - - let call_burned_register: crate::Call = crate::Call::burned_register { - netuid, - hotkey: hotkey_account_id, - }; - - let info: DispatchInfo = - DispatchInfoOf::<::RuntimeCall>::default(); - let extension = SubtensorTransactionExtension::::new(); - let burned_register_result = extension.validate( - RawOrigin::Signed(who).into(), - &call_burned_register.into(), - &info, - 10, - (), - &TxBaseImplication(()), - TransactionSource::External, - ); - - // Expectation: The transaction should be rejected - assert_eq!( - burned_register_result.unwrap_err(), - CustomTransactionError::RateLimitExceeded.into() - ); + // Price must be unchanged within the same block + assert_eq!(SubtensorModule::get_burn(netuid), price_now); - let current_registrants = SubtensorModule::get_registrations_this_interval(netuid); - assert!(current_registrants <= max_registrants); + // Next block: multiplier applies + step_block(1); + let price_next = SubtensorModule::get_burn(netuid); + assert_eq!(price_next, price_now.saturating_mul(2)); }); } #[test] -fn test_burned_registration_rate_allows_burn_adjustment() { - // We need to be able to register more than the *target* registrations per interval +fn test_burn_price_multi_bumps_same_block_coalesce() { new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let hotkey_account_id: U256 = U256::from(1); - let coldkey_account_id = U256::from(667); - let who: ::AccountId = coldkey_account_id; - - let burn_cost = 1000; - // Set the burn cost - SubtensorModule::set_burn(netuid, burn_cost.into()); - - let reserve = 1_000_000_000_000; - mock::setup_reserves(netuid, reserve.into(), reserve.into()); - - add_network(netuid, 13, 0); // Add the network - // Give it some TAO to the coldkey balance; more than the burn cost - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, burn_cost + 10_000); + let netuid = NetUid::from(12); + add_network(netuid, 13, 0); - let target_registrants = 1; // Target is 1, but we can register more than that, up to some maximum. - SubtensorModule::set_target_registrations_per_interval(netuid, target_registrants); - // Set the current registrations to above the target; we should be able to register at least 1 more - SubtensorModule::set_registrations_this_interval(netuid, target_registrants); + // Initialize + let start = SubtensorModule::get_current_block_as_u64(); + SubtensorModule::initialize_burn_price_if_needed(netuid, start); - // Register one more, so the current registrations are above the target - let call_burned_register: crate::Call = crate::Call::burned_register { - netuid, - hotkey: hotkey_account_id, - }; - - let info: DispatchInfo = - DispatchInfoOf::<::RuntimeCall>::default(); - let extension = SubtensorTransactionExtension::::new(); - //does not actually call register - let burned_register_result = extension.validate( - RawOrigin::Signed(who).into(), - &call_burned_register.into(), - &info, - 10, - (), - &TxBaseImplication(()), - TransactionSource::External, - ); - assert_ok!(burned_register_result); + // Reserves and funds + let reserve = 1_000_000_000_000u64; + setup_reserves(netuid, reserve.into(), reserve.into()); + let price_now = SubtensorModule::get_burn(netuid); + let cold = U256::from(7777); + let hk1 = U256::from(1); + let hk2 = U256::from(2); + // Two regs in the same block both pay the same price_now + SubtensorModule::add_balance_to_coldkey_account(&cold, price_now.saturating_mul(10)); - //actually call register assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(coldkey_account_id), + <::RuntimeOrigin>::signed(cold), netuid, - hotkey_account_id + hk1 )); - - let current_registrants = SubtensorModule::get_registrations_this_interval(netuid); - assert!(current_registrants > target_registrants); // Should be able to register more than the target - }); -} - -#[test] -fn test_burned_registration_ok() { - new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let burn_cost = 1000; - let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har - //add network - SubtensorModule::set_burn(netuid, burn_cost.into()); - add_network(netuid, tempo, 0); - - let reserve = 1_000_000_000_000; - mock::setup_reserves(netuid, reserve.into(), reserve.into()); - - // 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), + <::RuntimeOrigin>::signed(cold), netuid, - hotkey_account_id + hk2 )); - // Check if balance has decreased to pay for the burn. - assert_eq!( - SubtensorModule::get_coldkey_balance(&coldkey_account_id), - 10000 - burn_cost - ); // funds drained on reg. - // Check if neuron has added to the specified network(netuid) - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 1); - //check if hotkey is added to the Hotkeys - assert_eq!( - SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey_account_id), - coldkey_account_id - ); - // Check if the neuron has added to the Keys - let neuron_uid = - SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).unwrap(); - assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).is_ok()); - // Check if neuron has added to Uids - let neuro_uid = - SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).unwrap(); - assert_eq!(neuro_uid, neuron_uid); - // Check if the balance of this hotkey account for this subnetwork == 0 - assert_eq!( - SubtensorModule::get_stake_for_uid_and_subnetwork(netuid, neuron_uid), - AlphaCurrency::ZERO - ); - }); -} -#[test] -fn test_burn_registration_without_neuron_slot() { - new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let burn_cost = 1000; - let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har - //add network - SubtensorModule::set_burn(netuid, burn_cost.into()); - add_network(netuid, tempo, 0); - // Give it some $$$ in his coldkey balance - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); - SubtensorModule::set_max_allowed_uids(netuid, 0); + // Not applied yet + assert_eq!(SubtensorModule::get_burn(netuid), price_now); - assert_noop!( - SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(coldkey_account_id), - netuid, - hotkey_account_id - ), - Error::::NoNeuronIdAvailable - ); + // Next block: two bumps coalesce -> 4x + step_block(1); + let price_next = SubtensorModule::get_burn(netuid); + assert_eq!(price_next, price_now.saturating_mul(4)); }); } #[test] -fn test_burn_registration_doesnt_write_on_failure() { +fn test_burn_price_bump_and_decay_commute() { + // With half-life = 1 block and one registration in block N: + // Next block (N+1) applies a 2x bump and a halving -> net effect ≈ 1x (original). new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let burn_cost = 1000; - let initial_balance = burn_cost * 10; - let coldkey_account_id = U256::from(987); - - // Add network and set burn cost - add_network(netuid, tempo, 0); - SubtensorModule::set_burn(netuid, burn_cost.into()); - // Give coldkey balance to pay for registration - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, initial_balance); - // Set max allowed uids to 0 so registration will fail, but only on last check. - SubtensorModule::set_max_allowed_uids(netuid, 0); + let netuid = NetUid::from(21); + add_network(netuid, 13, 0); - // We expect this to fail at the last ensure check. - assert_err!( - SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(coldkey_account_id), - netuid, - hotkey_account_id - ), - Error::::NoNeuronIdAvailable - ); + // Force HL=1 for this subnet + BurnHalfLife::::insert(netuid, 1); - // Make sure the coldkey balance is unchanged. - assert_eq!( - SubtensorModule::get_coldkey_balance(&coldkey_account_id), - initial_balance - ); - // Make sure the neuron is not registered. - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 0); - // Make sure the hotkey is not registered. - assert!(SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).is_err()); - }); -} + // Initialize + let now = SubtensorModule::get_current_block_as_u64(); + SubtensorModule::initialize_burn_price_if_needed(netuid, now); + let p0 = BurnPrice::::get(netuid); -#[test] -fn test_burn_adjustment() { - new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let tempo: u16 = 13; - let init_burn_cost: u64 = InitialMinBurn::get() + 10_000; - let adjustment_interval = 1; - let target_registrations_per_interval = 1; - add_network(netuid, tempo, 0); - SubtensorModule::set_burn(netuid, init_burn_cost.into()); - SubtensorModule::set_adjustment_interval(netuid, adjustment_interval); - SubtensorModule::set_adjustment_alpha(netuid, 58000); // Set to old value. - SubtensorModule::set_target_registrations_per_interval( - netuid, - target_registrations_per_interval, + // Reserves + funds + let reserve = 1_000_000_000_000u64; + setup_reserves(netuid, reserve.into(), reserve.into()); + let cold = U256::from(404); + let hot = U256::from(505); + SubtensorModule::add_balance_to_coldkey_account( + &cold, + SubtensorModule::get_burn(netuid).saturating_mul(5), ); - let reserve = 1_000_000_000_000; - mock::setup_reserves(netuid, reserve.into(), reserve.into()); - - // Register key 1. - let hotkey_account_id_1 = U256::from(1); - let coldkey_account_id_1 = U256::from(1); - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id_1, init_burn_cost); - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(hotkey_account_id_1), - netuid, - hotkey_account_id_1 - )); - - // Register key 2. - let hotkey_account_id_2 = U256::from(2); - let coldkey_account_id_2 = U256::from(2); - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id_2, init_burn_cost); + // Register once in this block -> schedules 2x bump for next block assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(hotkey_account_id_2), + <::RuntimeOrigin>::signed(cold), netuid, - hotkey_account_id_2 + hot )); - // We are over the number of regs allowed this interval. - // Step the block and trigger the adjustment. + // Advance 1 block (HL) -> bump (2x) then halving (/2) => ~p0 again step_block(1); - - // Check the adjusted burn is above the initial min burn. - assert!(SubtensorModule::get_burn(netuid) > init_burn_cost.into()); - assert_abs_diff_eq!( - SubtensorModule::get_burn(netuid), - (init_burn_cost.saturating_mul(3).saturating_div(2)).into(), // 1.5x - epsilon = 1000.into() + let p1 = BurnPrice::::get(netuid); + assert!( + p1 == p0 || p1 == p0.saturating_add(1), + "bump and decay commute" ); }); } #[test] -fn test_burn_registration_pruning_scenarios() { +fn test_burn_price_floor_nonzero() { new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let tempo: u16 = 13; - let burn_cost = 1000; - let coldkey_account_id = U256::from(667); - let max_allowed_uids = 6; - let immunity_period = 5000; - - const IS_IMMUNE: bool = true; - const NOT_IMMUNE: bool = false; - - // Initial setup - SubtensorModule::set_burn(netuid, burn_cost.into()); - SubtensorModule::set_max_allowed_uids(netuid, max_allowed_uids); - SubtensorModule::set_target_registrations_per_interval(netuid, max_allowed_uids); - SubtensorModule::set_immunity_period(netuid, immunity_period); - - let reserve = 1_000_000_000_000; - mock::setup_reserves(netuid, reserve.into(), reserve.into()); - - add_network(netuid, tempo, 0); - - let mint_balance = burn_cost * max_allowed_uids as u64 + 1_000_000_000; - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, mint_balance); - - // Register first half of neurons - for i in 0..3 { - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(coldkey_account_id), - netuid, - U256::from(i) - )); - step_block(1); - } - - // Note: pruning score is set to u16::MAX after getting neuron to prune - - // 1. Test if all immune neurons - assert_eq!(SubtensorModule::get_neuron_is_immune(netuid, 0), IS_IMMUNE); - assert_eq!(SubtensorModule::get_neuron_is_immune(netuid, 1), IS_IMMUNE); - assert_eq!(SubtensorModule::get_neuron_is_immune(netuid, 2), IS_IMMUNE); - - SubtensorModule::set_pruning_score_for_uid(netuid, 0, 100); - SubtensorModule::set_pruning_score_for_uid(netuid, 1, 75); - SubtensorModule::set_pruning_score_for_uid(netuid, 2, 50); - - // The immune neuron with the lowest score should be pruned - assert_eq!(SubtensorModule::get_neuron_to_prune(netuid), 2); - - // 2. Test tie-breaking for immune neurons - SubtensorModule::set_pruning_score_for_uid(netuid, 1, 50); - SubtensorModule::set_pruning_score_for_uid(netuid, 2, 50); - - // Should get the oldest neuron (i.e., neuron that was registered first) - assert_eq!(SubtensorModule::get_neuron_to_prune(netuid), 1); - - // 3. Test if no immune neurons - step_block(immunity_period); - - // ensure all neurons are non-immune - assert_eq!(SubtensorModule::get_neuron_is_immune(netuid, 0), NOT_IMMUNE); - assert_eq!(SubtensorModule::get_neuron_is_immune(netuid, 1), NOT_IMMUNE); - assert_eq!(SubtensorModule::get_neuron_is_immune(netuid, 2), NOT_IMMUNE); - - SubtensorModule::set_pruning_score_for_uid(netuid, 0, 100); - SubtensorModule::set_pruning_score_for_uid(netuid, 1, 50); - SubtensorModule::set_pruning_score_for_uid(netuid, 2, 75); - - // The non-immune neuron with the lowest score should be pruned - assert_eq!(SubtensorModule::get_neuron_to_prune(netuid), 1); + let netuid = NetUid::from(99); + add_network(netuid, 13, 0); - // 4. Test tie-breaking for non-immune neurons - SubtensorModule::set_pruning_score_for_uid(netuid, 1, 50); - SubtensorModule::set_pruning_score_for_uid(netuid, 2, 50); + // Force a tiny price and fast halving; it must not drop to 0 + BurnPrice::::insert(netuid, 1u128); + BurnLastUpdate::::insert(netuid, 0u64); + BurnHalfLife::::insert(netuid, 1u64); + BurnPendingBumps::::insert(netuid, 0u32); + BurnPendingFrom::::insert(netuid, 0u64); - // Should get the oldest non-immune neuron - assert_eq!(SubtensorModule::get_neuron_to_prune(netuid), 1); + step_block(100); + let now = SubtensorModule::get_current_block_as_u64(); + SubtensorModule::update_burn_price_to_block(netuid, now); - // 5. Test mixed immunity - // Register second batch of neurons (these will be non-immune) - for i in 3..6 { - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(coldkey_account_id), - netuid, - U256::from(i) - )); - step_block(1); - } - - // Ensure all new neurons are immune - assert_eq!(SubtensorModule::get_neuron_is_immune(netuid, 3), IS_IMMUNE); - assert_eq!(SubtensorModule::get_neuron_is_immune(netuid, 4), IS_IMMUNE); - assert_eq!(SubtensorModule::get_neuron_is_immune(netuid, 5), IS_IMMUNE); - - // Set pruning scores for all neurons - SubtensorModule::set_pruning_score_for_uid(netuid, 0, 75); // non-immune - SubtensorModule::set_pruning_score_for_uid(netuid, 1, 50); // non-immune - SubtensorModule::set_pruning_score_for_uid(netuid, 2, 60); // non-immune - SubtensorModule::set_pruning_score_for_uid(netuid, 3, 40); // immune - SubtensorModule::set_pruning_score_for_uid(netuid, 4, 55); // immune - SubtensorModule::set_pruning_score_for_uid(netuid, 5, 45); // immune - - // The non-immune neuron with the lowest score should be pruned - assert_eq!(SubtensorModule::get_neuron_to_prune(netuid), 1); - - // If we remove the lowest non-immune neuron, it should choose the next lowest non-immune - SubtensorModule::set_pruning_score_for_uid(netuid, 1, u16::MAX); - assert_eq!(SubtensorModule::get_neuron_to_prune(netuid), 2); - - // If we make all non-immune neurons have high scores, it should choose the oldest non-immune neuron - SubtensorModule::set_pruning_score_for_uid(netuid, 0, u16::MAX); - SubtensorModule::set_pruning_score_for_uid(netuid, 1, u16::MAX); - SubtensorModule::set_pruning_score_for_uid(netuid, 2, u16::MAX); - assert_eq!(SubtensorModule::get_neuron_to_prune(netuid), 0); + assert_eq!(BurnPrice::::get(netuid), 1u128, "price floored at 1"); + assert_eq!(SubtensorModule::get_burn(netuid) as u128, 1u128); }); } +/* -------------------------------------------------------------------------- */ +/* Burned registration flow */ +/* -------------------------------------------------------------------------- */ + #[test] -fn test_registration_too_many_registrations_per_block() { +fn test_registration_ok() { + // "Registration OK" under the new burned registration path. new_test_ext(1).execute_with(|| { let netuid = NetUid::from(1); let tempo: u16 = 13; + let hotkey = U256::from(1); + let coldkey = U256::from(667); + add_network(netuid, tempo, 0); - SubtensorModule::set_max_registrations_per_block(netuid, 10); - SubtensorModule::set_target_registrations_per_interval(netuid, 10); - assert_eq!(SubtensorModule::get_max_registrations_per_block(netuid), 10); - let block_number: u64 = 0; - let (nonce0, work0): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 3942084, - &U256::from(0), - ); - let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 11231312312, - &U256::from(1), - ); - let (nonce2, work2): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 212312414, - &U256::from(2), - ); - let (nonce3, work3): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 21813123, - &U256::from(3), - ); - let (nonce4, work4): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 148141209, - &U256::from(4), - ); - let (nonce5, work5): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 1245235534, - &U256::from(5), - ); - let (nonce6, work6): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 256234, - &U256::from(6), - ); - let (nonce7, work7): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 6923424, - &U256::from(7), - ); - let (nonce8, work8): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 124242, - &U256::from(8), - ); - let (nonce9, work9): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 153453, - &U256::from(9), - ); - let (nonce10, work10): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 345923888, - &U256::from(10), - ); - assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 10000); + // Setup swap reserves and sufficient coldkey funds + let reserve = 1_000_000_000_000u64; + setup_reserves(netuid, reserve.into(), reserve.into()); - // Subscribe and check extrinsic output - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(0)), - netuid, - block_number, - nonce0, - work0, - U256::from(0), - U256::from(0) - )); - assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 1); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(1)), - netuid, - block_number, - nonce1, - work1, - U256::from(1), - U256::from(1) - )); - assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 2); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(2)), - netuid, - block_number, - nonce2, - work2, - U256::from(2), - U256::from(2) - )); - assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 3); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(3)), - netuid, - block_number, - nonce3, - work3, - U256::from(3), - U256::from(3) - )); - assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 4); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(4)), - netuid, - block_number, - nonce4, - work4, - U256::from(4), - U256::from(4) - )); - assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 5); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(5)), - netuid, - block_number, - nonce5, - work5, - U256::from(5), - U256::from(5) - )); - assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 6); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(6)), - netuid, - block_number, - nonce6, - work6, - U256::from(6), - U256::from(6) - )); - assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 7); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(7)), - netuid, - block_number, - nonce7, - work7, - U256::from(7), - U256::from(7) - )); - assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 8); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(8)), - netuid, - block_number, - nonce8, - work8, - U256::from(8), - U256::from(8) - )); - assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 9); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(9)), + let burn_cost = SubtensorModule::get_burn(netuid); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, burn_cost.saturating_mul(10)); + + // Register + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(coldkey), netuid, - block_number, - nonce9, - work9, - U256::from(9), - U256::from(9) + hotkey )); - assert_eq!(SubtensorModule::get_registrations_this_block(netuid), 10); - let result = SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(10)), - netuid, - block_number, - nonce10, - work10, - U256::from(10), - U256::from(10), - ); - assert_eq!( - result, - Err(Error::::TooManyRegistrationsThisBlock.into()) - ); - }); -} -#[test] -fn test_registration_too_many_registrations_per_interval() { - new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let tempo: u16 = 13; - add_network(netuid, tempo, 0); - SubtensorModule::set_max_registrations_per_block(netuid, 11); - assert_eq!(SubtensorModule::get_max_registrations_per_block(netuid), 11); - SubtensorModule::set_target_registrations_per_interval(netuid, 3); - assert_eq!( - SubtensorModule::get_target_registrations_per_interval(netuid), - 3 - ); - // Then the max is 3 * 3 = 9 + // Neuron added + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 1); - let block_number: u64 = 0; - let (nonce0, work0): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 3942084, - &U256::from(0), - ); - let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 11231312312, - &U256::from(1), - ); - let (nonce2, work2): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 212312414, - &U256::from(2), - ); - let (nonce3, work3): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 21813123, - &U256::from(3), - ); - let (nonce4, work4): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 148141209, - &U256::from(4), - ); - let (nonce5, work5): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 1245235534, - &U256::from(5), - ); - let (nonce6, work6): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 256234, - &U256::from(6), - ); - let (nonce7, work7): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 6923424, - &U256::from(7), - ); - let (nonce8, work8): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 124242, - &U256::from(8), - ); - let (nonce9, work9): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 153453, - &U256::from(9), + // Ownership mapping + assert_eq!( + SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey), + coldkey ); - assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), 10000); - // Subscribe and check extrinsic output - // Try 10 registrations, this is less than the max per block, but more than the max per interval - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(0)), - netuid, - block_number, - nonce0, - work0, - U256::from(0), - U256::from(0) - )); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 1); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(1)), - netuid, - block_number, - nonce1, - work1, - U256::from(1), - U256::from(1) - )); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 2); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(2)), - netuid, - block_number, - nonce2, - work2, - U256::from(2), - U256::from(2) - )); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 3); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(3)), - netuid, - block_number, - nonce3, - work3, - U256::from(3), - U256::from(3) - )); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 4); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(4)), - netuid, - block_number, - nonce4, - work4, - U256::from(4), - U256::from(4) - )); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 5); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(5)), - netuid, - block_number, - nonce5, - work5, - U256::from(5), - U256::from(5) - )); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 6); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(6)), - netuid, - block_number, - nonce6, - work6, - U256::from(6), - U256::from(6) - )); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 7); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(7)), - netuid, - block_number, - nonce7, - work7, - U256::from(7), - U256::from(7) - )); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 8); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(8)), - netuid, - block_number, - nonce8, - work8, - U256::from(8), - U256::from(8) - )); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 9); - let result = SubtensorModule::register( - <::RuntimeOrigin>::signed(U256::from(9)), - netuid, - block_number, - nonce9, - work9, - U256::from(9), - U256::from(9), - ); + // UID mapping + zero alpha stake + let uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey).expect("uid exists"); assert_eq!( - result, - Err(Error::::TooManyRegistrationsThisInterval.into()) + SubtensorModule::get_stake_for_uid_and_subnetwork(netuid, uid), + AlphaCurrency::ZERO ); }); } -#[test] -fn test_registration_immunity_period() { //impl this test when epoch impl and calculating pruning score is done - // TODO: Implement this test -} - #[test] fn test_registration_already_active_hotkey() { new_test_ext(1).execute_with(|| { - let block_number: u64 = 0; let netuid = NetUid::from(1); let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 0, - &hotkey_account_id, - ); + let hotkey = U256::from(1); + let coldkey = U256::from(667); - //add network add_network(netuid, tempo, 0); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id), + // Reserves + funds + let reserve = 1_000_000_000_000u64; + setup_reserves(netuid, reserve.into(), reserve.into()); + let burn = SubtensorModule::get_burn(netuid); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, burn.saturating_mul(10)); + + // First registration OK + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(coldkey), netuid, - block_number, - nonce, - work, - hotkey_account_id, - coldkey_account_id + hotkey )); - let block_number: u64 = 0; - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 0, - &hotkey_account_id, - ); - let result = SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id), + // Second registration with same hotkey must fail + let result = SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(coldkey), netuid, - block_number, - nonce, - work, - hotkey_account_id, - coldkey_account_id, + hotkey, ); assert_eq!( result, @@ -1167,1174 +336,247 @@ fn test_registration_already_active_hotkey() { } #[test] -fn test_registration_invalid_seal() { +fn test_burned_registration_non_associated_coldkey() { + // Pre‑associate a hotkey with another coldkey. Attempting to register it using + // a different coldkey must fail with NonAssociatedColdKey. new_test_ext(1).execute_with(|| { - let block_number: u64 = 0; - let netuid = NetUid::from(1); - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); - let (nonce, work): (u64, Vec) = - SubtensorModule::create_work_for_block_number(netuid, 1, 0, &hotkey_account_id); - - //add network - add_network(netuid, tempo, 0); - - let result = SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id), - netuid, - block_number, - nonce, - work, - hotkey_account_id, - coldkey_account_id, - ); - assert_eq!(result, Err(Error::::InvalidSeal.into())); - }); -} + let netuid = NetUid::from(2); + add_network(netuid, 13, 0); -#[test] -fn test_registration_invalid_block_number() { - new_test_ext(1).execute_with(|| { - System::set_block_number(0); - let block_number: u64 = 1; - let netuid = NetUid::from(1); - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 0, - &hotkey_account_id, - ); + // Pre‑bind hotkey -> cold_A + let cold_a = U256::from(100); + let cold_b = U256::from(200); + let hk = U256::from(12345); + Owner::::insert(hk, cold_a); - //add network - add_network(netuid, tempo, 0); + // Setup reserves + fund cold_b + let reserve = 1_000_000_000_000u64; + setup_reserves(netuid, reserve.into(), reserve.into()); + let burn = SubtensorModule::get_burn(netuid); + SubtensorModule::add_balance_to_coldkey_account(&cold_b, burn.saturating_mul(10)); - let result = SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id), - netuid, - block_number, - nonce, - work, - hotkey_account_id, - coldkey_account_id, + // Attempt with cold_b + assert_err!( + SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(cold_b), + netuid, + hk + ), + Error::::NonAssociatedColdKey ); - assert_eq!(result, Err(Error::::InvalidWorkBlock.into())); }); } #[test] -fn test_registration_invalid_difficulty() { +fn test_burned_registration_disabled() { new_test_ext(1).execute_with(|| { - let block_number: u64 = 0; - let netuid = NetUid::from(1); - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 0, - &hotkey_account_id, - ); - - //add network - add_network(netuid, tempo, 0); - - SubtensorModule::set_difficulty(netuid, 18_446_744_073_709_551_615u64); + let netuid = NetUid::from(3); + add_network(netuid, 13, 0); - let result = SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id), - netuid, - block_number, - nonce, - work, - hotkey_account_id, - coldkey_account_id, - ); - assert_eq!(result, Err(Error::::InvalidDifficulty.into())); - }); -} + // Disable registration explicitly + SubtensorModule::set_network_registration_allowed(netuid, false); -#[test] -fn test_registration_failed_no_signature() { - new_test_ext(1).execute_with(|| { - let block_number: u64 = 1; - let netuid = NetUid::from(1); - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 0, - &hotkey_account_id, - ); + // Reserves + funds (even if funded, it should be blocked) + let reserve = 1_000_000_000_000u64; + setup_reserves(netuid, reserve.into(), reserve.into()); + let burn = SubtensorModule::get_burn(netuid); + let cold = U256::from(668); + let hot = U256::from(1); + SubtensorModule::add_balance_to_coldkey_account(&cold, burn.saturating_mul(2)); - // Subscribe and check extrinsic output - let result = SubtensorModule::register( - <::RuntimeOrigin>::none(), + let result = SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(cold), netuid, - block_number, - nonce, - work, - hotkey_account_id, - coldkey_account_id, - ); - assert_eq!(result, Err(DispatchError::BadOrigin)); - }); -} - -#[test] -fn test_registration_get_uid_to_prune_all_in_immunity_period() { - new_test_ext(1).execute_with(|| { - System::set_block_number(0); - let netuid = NetUid::from(1); - add_network(netuid, 1, 0); - log::info!("add network"); - register_ok_neuron(netuid, U256::from(0), U256::from(0), 39420842); - register_ok_neuron(netuid, U256::from(1), U256::from(1), 12412392); - SubtensorModule::set_pruning_score_for_uid(netuid, 0, 100); - SubtensorModule::set_pruning_score_for_uid(netuid, 1, 110); - SubtensorModule::set_immunity_period(netuid, 2); - assert_eq!(SubtensorModule::get_pruning_score_for_uid(netuid, 0), 100); - assert_eq!(SubtensorModule::get_pruning_score_for_uid(netuid, 1), 110); - assert_eq!(SubtensorModule::get_immunity_period(netuid), 2); - assert_eq!(SubtensorModule::get_current_block_as_u64(), 0); - assert_eq!( - SubtensorModule::get_neuron_block_at_registration(netuid, 0), - 0 + hot, ); - assert_eq!(SubtensorModule::get_neuron_to_prune(NetUid::ROOT), 0); - }); -} - -#[test] -fn test_registration_get_uid_to_prune_none_in_immunity_period() { - new_test_ext(1).execute_with(|| { - System::set_block_number(0); - let netuid = NetUid::from(1); - add_network(netuid, 1, 0); - log::info!("add network"); - register_ok_neuron(netuid, U256::from(0), U256::from(0), 39420842); - register_ok_neuron(netuid, U256::from(1), U256::from(1), 12412392); - SubtensorModule::set_pruning_score_for_uid(netuid, 0, 100); - SubtensorModule::set_pruning_score_for_uid(netuid, 1, 110); - SubtensorModule::set_immunity_period(netuid, 2); - assert_eq!(SubtensorModule::get_pruning_score_for_uid(netuid, 0), 100); - assert_eq!(SubtensorModule::get_pruning_score_for_uid(netuid, 1), 110); - assert_eq!(SubtensorModule::get_immunity_period(netuid), 2); - assert_eq!(SubtensorModule::get_current_block_as_u64(), 0); assert_eq!( - SubtensorModule::get_neuron_block_at_registration(netuid, 0), - 0 + result, + Err(Error::::SubNetRegistrationDisabled.into()) ); - step_block(3); - assert_eq!(SubtensorModule::get_current_block_as_u64(), 3); - assert_eq!(SubtensorModule::get_neuron_to_prune(NetUid::ROOT), 0); - }); -} - -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::registration::test_registration_get_uid_to_prune_owner_immortality --exact --show-output --nocapture -#[test] -fn test_registration_get_uid_to_prune_owner_immortality() { - new_test_ext(1).execute_with(|| { - [ - // Burn key limit to 1 - testing the limits - // Other owner's hotkey is pruned because there's only 1 immune key and - // pruning score of owner key is lower - (1, 1), - // Burn key limit to 2 - both owner keys are immune - (2, 2), - ] - .iter() - .for_each(|(limit, uid_to_prune)| { - let subnet_owner_ck = U256::from(0); - let subnet_owner_hk = U256::from(1); - - // Other hk owned by owner - let other_owner_hk = U256::from(2); - Owner::::insert(other_owner_hk, subnet_owner_ck); - OwnedHotkeys::::insert(subnet_owner_ck, vec![subnet_owner_hk, other_owner_hk]); - - // Another hk not owned by owner - let non_owner_hk = U256::from(3); - - let netuid = add_dynamic_network(&subnet_owner_hk, &subnet_owner_ck); - BlockAtRegistration::::insert(netuid, 1, 1); - BlockAtRegistration::::insert(netuid, 2, 2); - Uids::::insert(netuid, other_owner_hk, 1); - Uids::::insert(netuid, non_owner_hk, 2); - Keys::::insert(netuid, 1, other_owner_hk); - Keys::::insert(netuid, 2, non_owner_hk); - ImmunityPeriod::::insert(netuid, 1); - SubnetworkN::::insert(netuid, 3); - - step_block(10); - - ImmuneOwnerUidsLimit::::insert(netuid, *limit); - - // Set lower pruning score to sn owner keys - PruningScores::::insert(netuid, vec![0, 0, 1]); - - assert_eq!(SubtensorModule::get_neuron_to_prune(netuid), *uid_to_prune); - }); - }); -} - -// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::registration::test_registration_get_uid_to_prune_owner_immortality_all_immune --exact --show-output --nocapture -#[test] -fn test_registration_get_uid_to_prune_owner_immortality_all_immune() { - new_test_ext(1).execute_with(|| { - let limit = 2; - let uid_to_prune = 2; - let subnet_owner_ck = U256::from(0); - let subnet_owner_hk = U256::from(1); - - // Other hk owned by owner - let other_owner_hk = U256::from(2); - Owner::::insert(other_owner_hk, subnet_owner_ck); - OwnedHotkeys::::insert(subnet_owner_ck, vec![subnet_owner_hk, other_owner_hk]); - - // Another hk not owned by owner - let non_owner_hk = U256::from(3); - - let netuid = add_dynamic_network(&subnet_owner_hk, &subnet_owner_ck); - BlockAtRegistration::::insert(netuid, 0, 12); - BlockAtRegistration::::insert(netuid, 1, 11); - BlockAtRegistration::::insert(netuid, 2, 10); - Uids::::insert(netuid, other_owner_hk, 1); - Uids::::insert(netuid, non_owner_hk, 2); - Keys::::insert(netuid, 1, other_owner_hk); - Keys::::insert(netuid, 2, non_owner_hk); - ImmunityPeriod::::insert(netuid, 100); - SubnetworkN::::insert(netuid, 3); - - step_block(20); - - ImmuneOwnerUidsLimit::::insert(netuid, limit); - - // Set lower pruning score to sn owner keys - PruningScores::::insert(netuid, vec![0, 0, 1]); - - assert_eq!(SubtensorModule::get_neuron_to_prune(netuid), uid_to_prune); }); } #[test] -fn test_registration_pruning() { +fn test_burned_registration_without_neuron_slot() { new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let block_number: u64 = 0; + let netuid = NetUid::from(4); let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); - let (nonce0, work0): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 3942084, - &hotkey_account_id, - ); + let hot = U256::from(1); + let cold = U256::from(667); - //add network add_network(netuid, tempo, 0); + SubtensorModule::set_max_allowed_uids(netuid, 0); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id), - netuid, - block_number, - nonce0, - work0, - hotkey_account_id, - coldkey_account_id - )); - // - let neuron_uid = - SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id).unwrap(); - SubtensorModule::set_pruning_score_for_uid(netuid, neuron_uid, 2); - // - let hotkey_account_id1 = U256::from(2); - let coldkey_account_id1 = U256::from(668); - let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 11231312312, - &hotkey_account_id1, - ); + let reserve = 1_000_000_000_000u64; + setup_reserves(netuid, reserve.into(), reserve.into()); + let burn = SubtensorModule::get_burn(netuid); + SubtensorModule::add_balance_to_coldkey_account(&cold, burn.saturating_mul(2)); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id1), - netuid, - block_number, - nonce1, - work1, - hotkey_account_id1, - coldkey_account_id1 - )); - // - let neuron_uid1 = - SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id1).unwrap(); - SubtensorModule::set_pruning_score_for_uid(netuid, neuron_uid1, 3); - // - let hotkey_account_id2 = U256::from(3); - let coldkey_account_id2 = U256::from(669); - let (nonce2, work2): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 212312414, - &hotkey_account_id2, + assert_noop!( + SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(cold), + netuid, + hot + ), + Error::::NoNeuronIdAvailable ); - - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id2), - netuid, - block_number, - nonce2, - work2, - hotkey_account_id2, - coldkey_account_id2 - )); }); } #[test] -fn test_registration_get_neuron_metadata() { +fn test_last_update_correctness_burned() { new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let block_number: u64 = 0; + let netuid = NetUid::from(5); let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); - let (nonce0, work0): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 3942084, - &hotkey_account_id, - ); + let hot = U256::from(1); + let cold = U256::from(667); add_network(netuid, tempo, 0); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id), - netuid, - block_number, - nonce0, - work0, - hotkey_account_id, - coldkey_account_id - )); - // - //let neuron_id = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id); - // let neuron_uid = SubtensorModule::get_uid_for_net_and_hotkey( netuid, &hotkey_account_id ).unwrap(); - let neuron: AxonInfoOf = SubtensorModule::get_axon_info(netuid, &hotkey_account_id); - assert_eq!(neuron.ip, 0); - assert_eq!(neuron.version, 0); - assert_eq!(neuron.port, 0); - }); -} - -#[test] -fn test_registration_add_network_size() { - new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let netuid2 = NetUid::from(2); - let block_number: u64 = 0; - let hotkey_account_id = U256::from(1); - let hotkey_account_id1 = U256::from(2); - let hotkey_account_id2 = U256::from(3); - let (nonce0, work0): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 3942084, - &hotkey_account_id, - ); - let (nonce1, work1): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid2, - block_number, - 11231312312, - &hotkey_account_id1, - ); - let (nonce2, work2): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid2, - block_number, - 21813123, - &hotkey_account_id2, - ); - let coldkey_account_id = U256::from(667); + // Simulate existing neurons + let existing: u16 = 3; + SubnetworkN::::insert(netuid, existing); - add_network(netuid, 13, 0); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 0); + // No LastUpdate yet + LastUpdate::::remove(NetUidStorageIndex::from(netuid)); - add_network(netuid2, 13, 0); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 0); + // Reserves + fund + let reserve = 1_000_000_000_000u64; + setup_reserves(netuid, reserve.into(), reserve.into()); + let burn = SubtensorModule::get_burn(netuid); + SubtensorModule::add_balance_to_coldkey_account(&cold, burn.saturating_mul(5)); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id), + // Register + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(cold), netuid, - block_number, - nonce0, - work0, - hotkey_account_id, - coldkey_account_id + hot )); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 1); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid), 1); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id1), - netuid2, - block_number, - nonce1, - work1, - hotkey_account_id1, - coldkey_account_id - )); - assert_ok!(SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id2), - netuid2, - block_number, - nonce2, - work2, - hotkey_account_id2, - coldkey_account_id - )); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 2); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid2), 2); + // LastUpdate length should be existing + 1 + assert_eq!( + LastUpdate::::get(NetUidStorageIndex::from(netuid)).len(), + (existing + 1) as usize + ); }); } #[test] -fn test_burn_registration_increase_recycled_rao() { +fn test_burn_registration_increase_recycled_rao_dynamic() { new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let netuid2 = NetUid::from(2); + let netuid1 = NetUid::from(6); + let netuid2 = NetUid::from(7); - let hotkey_account_id = U256::from(1); - let coldkey_account_id = U256::from(667); + let cold1 = U256::from(1); // Also used as hotkey + let cold2 = U256::from(2); + let hot1 = cold1; + let hot2 = cold2; - // Give funds for burn. 1000 TAO - let _ = - Balances::deposit_creating(&coldkey_account_id, Balance::from(1_000_000_000_000_u64)); - - let reserve = 1_000_000_000_000; - mock::setup_reserves(netuid, reserve.into(), reserve.into()); - mock::setup_reserves(netuid2, reserve.into(), reserve.into()); - - add_network(netuid, 13, 0); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 0); + // Pre‑fund coldkeys generously + let _ = Balances::deposit_creating(&cold1, Balance::from(1_000_000_000_000_u64)); + let _ = Balances::deposit_creating(&cold2, Balance::from(1_000_000_000_000_u64)); + // Setup reserves for both nets + let reserve = 1_000_000_000_000u64; + add_network(netuid1, 13, 0); add_network(netuid2, 13, 0); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 0); + setup_reserves(netuid1, reserve.into(), reserve.into()); + setup_reserves(netuid2, reserve.into(), reserve.into()); run_to_block(1); - let burn_amount = SubtensorModule::get_burn(netuid); + let burn1 = SubtensorModule::get_burn(netuid1); assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(hotkey_account_id), - netuid, - hotkey_account_id + <::RuntimeOrigin>::signed(cold1), + netuid1, + hot1 )); - assert_eq!(SubtensorModule::get_rao_recycled(netuid), burn_amount); + assert_eq!(SubtensorModule::get_rao_recycled(netuid1), burn1.into()); run_to_block(2); - let burn_amount2 = SubtensorModule::get_burn(netuid2); + let burn2 = SubtensorModule::get_burn(netuid2); assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(hotkey_account_id), + <::RuntimeOrigin>::signed(cold1), netuid2, - hotkey_account_id + hot1 )); assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(U256::from(2)), + <::RuntimeOrigin>::signed(cold2), netuid2, - U256::from(2) + hot2 )); assert_eq!( SubtensorModule::get_rao_recycled(netuid2), - burn_amount2 * 2.into() + burn2.saturating_mul(2).into() ); - // Validate netuid is not affected. - assert_eq!(SubtensorModule::get_rao_recycled(netuid), burn_amount); + // Validate netuid1 is not affected + assert_eq!(SubtensorModule::get_rao_recycled(netuid1), burn1.into()); }); } -#[test] -fn test_full_pass_through() { - new_test_ext(1).execute_with(|| { - // Create 3 networks. - let netuid0 = NetUid::from(1); - let netuid1 = NetUid::from(2); - let netuid2 = NetUid::from(3); - - // With 3 tempos - let tempo0: u16 = 2; - let tempo1: u16 = 2; - let tempo2: u16 = 2; - - // Create 3 keys. - let hotkey0 = U256::from(0); - let hotkey1 = U256::from(1); - let hotkey2 = U256::from(2); - - // With 3 different coldkeys. - let coldkey0 = U256::from(0); - let coldkey1 = U256::from(1); - let coldkey2 = U256::from(2); - - // Add the 3 networks. - add_network(netuid0, tempo0, 0); - add_network(netuid1, tempo1, 0); - add_network(netuid2, tempo2, 0); - - // owners are not deregisterd - let dummy_owner = U256::from(99999); - crate::SubnetOwner::::insert(netuid0, dummy_owner); - crate::SubnetOwner::::insert(netuid1, dummy_owner); - crate::SubnetOwner::::insert(netuid2, dummy_owner); - - // Check their tempo. - assert_eq!(SubtensorModule::get_tempo(netuid0), tempo0); - assert_eq!(SubtensorModule::get_tempo(netuid1), tempo1); - assert_eq!(SubtensorModule::get_tempo(netuid2), tempo2); - - // Set their max allowed uids. - SubtensorModule::set_max_allowed_uids(netuid0, 2); - SubtensorModule::set_max_allowed_uids(netuid1, 2); - SubtensorModule::set_max_allowed_uids(netuid2, 2); - - // Check their max allowed. - assert_eq!(SubtensorModule::get_max_allowed_uids(netuid0), 2); - assert_eq!(SubtensorModule::get_max_allowed_uids(netuid0), 2); - assert_eq!(SubtensorModule::get_max_allowed_uids(netuid0), 2); - - // Set the max registration per block. - SubtensorModule::set_max_registrations_per_block(netuid0, 3); - SubtensorModule::set_max_registrations_per_block(netuid1, 3); - SubtensorModule::set_max_registrations_per_block(netuid2, 3); - assert_eq!(SubtensorModule::get_max_registrations_per_block(netuid0), 3); - assert_eq!(SubtensorModule::get_max_registrations_per_block(netuid1), 3); - assert_eq!(SubtensorModule::get_max_registrations_per_block(netuid2), 3); - - // Check that no one has registered yet. - assert_eq!(SubtensorModule::get_subnetwork_n(netuid0), 0); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid1), 0); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 0); - - // Registered the keys to all networks. - register_ok_neuron(netuid0, hotkey0, coldkey0, 39420842); - register_ok_neuron(netuid0, hotkey1, coldkey1, 12412392); - register_ok_neuron(netuid1, hotkey0, coldkey0, 21813123); - register_ok_neuron(netuid1, hotkey1, coldkey1, 25755207); - register_ok_neuron(netuid2, hotkey0, coldkey0, 251232207); - register_ok_neuron(netuid2, hotkey1, coldkey1, 159184122); - - // Check uids. - // n0 [ h0, h1 ] - // n1 [ h0, h1 ] - // n2 [ h0, h1 ] - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid0, 0).unwrap(), - hotkey0 - ); - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid1, 0).unwrap(), - hotkey0 - ); - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid2, 0).unwrap(), - hotkey0 - ); - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid0, 1).unwrap(), - hotkey1 - ); - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid1, 1).unwrap(), - hotkey1 - ); - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid2, 1).unwrap(), - hotkey1 - ); - - // Check registered networks. - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid0 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid1 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid2 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid0 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid1 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid2 ) ); - // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid0 ) ); - // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid1 ) ); - // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid2 ) ); - - // Check the number of registrations. - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid0), 2); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid1), 2); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid2), 2); - - // Get the number of uids in each network. - assert_eq!(SubtensorModule::get_subnetwork_n(netuid0), 2); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid1), 2); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 2); - - // Check the uids exist. - assert!(SubtensorModule::is_uid_exist_on_network(netuid0, 0)); - assert!(SubtensorModule::is_uid_exist_on_network(netuid1, 0)); - assert!(SubtensorModule::is_uid_exist_on_network(netuid2, 0)); - - // Check the other exists. - assert!(SubtensorModule::is_uid_exist_on_network(netuid0, 1)); - assert!(SubtensorModule::is_uid_exist_on_network(netuid1, 1)); - assert!(SubtensorModule::is_uid_exist_on_network(netuid2, 1)); - - // Get the hotkey under each uid. - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid0, 0).unwrap(), - hotkey0 - ); - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid1, 0).unwrap(), - hotkey0 - ); - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid2, 0).unwrap(), - hotkey0 - ); - - // Get the hotkey under the other uid. - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid0, 1).unwrap(), - hotkey1 - ); - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid1, 1).unwrap(), - hotkey1 - ); - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid2, 1).unwrap(), - hotkey1 - ); - - // Check for replacement. - assert_eq!(SubtensorModule::get_subnetwork_n(netuid0), 2); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid1), 2); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 2); - - // Register the 3rd hotkey. - register_ok_neuron(netuid0, hotkey2, coldkey2, 59420842); - register_ok_neuron(netuid1, hotkey2, coldkey2, 31813123); - register_ok_neuron(netuid2, hotkey2, coldkey2, 451232207); - - // Check for replacement. - assert_eq!(SubtensorModule::get_subnetwork_n(netuid0), 2); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid1), 2); - assert_eq!(SubtensorModule::get_subnetwork_n(netuid2), 2); - - // Check uids. - // n0 [ h0, h1 ] - // n1 [ h0, h1 ] - // n2 [ h0, h1 ] - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid0, 0).unwrap(), - hotkey2 - ); - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid1, 0).unwrap(), - hotkey2 - ); - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid2, 0).unwrap(), - hotkey2 - ); - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid0, 1).unwrap(), - hotkey1 - ); - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid1, 1).unwrap(), - hotkey1 - ); - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid2, 1).unwrap(), - hotkey1 - ); - - // Check registered networks. - // hotkey0 has been deregistered. - // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid0 ) ); - // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid1 ) ); - // assert!( !SubtensorModule::get_registered_networks_for_hotkey( &hotkey0 ).contains( &netuid2 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid0 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid1 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey1 ).contains( &netuid2 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid0 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid1 ) ); - // assert!( SubtensorModule::get_registered_networks_for_hotkey( &hotkey2 ).contains( &netuid2 ) ); - - // Check the registration counters. - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid0), 3); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid1), 3); - assert_eq!(SubtensorModule::get_registrations_this_interval(netuid2), 3); - - // Check the hotkeys are expected. - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid0, 0).unwrap(), - hotkey2 - ); - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid1, 0).unwrap(), - hotkey2 - ); - assert_eq!( - SubtensorModule::get_hotkey_for_net_and_uid(netuid2, 0).unwrap(), - hotkey2 - ); - }); -} - -// DEPRECATED #[test] -// fn test_network_connection_requirement() { -// new_test_ext(1).execute_with(|| { -// // Add a networks and connection requirements. -// let netuid_a: u16 = 0; -// let netuid_b: u16 = 1; -// add_network(netuid_a, 10, 0); -// add_network(netuid_b, 10, 0); - -// // Bulk values. -// let hotkeys: Vec = (0..=10).map(|x| U256::from(x)).collect(); -// let coldkeys: Vec = (0..=10).map(|x| U256::from(x)).collect(); - -// // Add a connection requirement between the A and B. A requires B. -// SubtensorModule::add_connection_requirement(netuid_a, netuid_b, u16::MAX); -// SubtensorModule::set_max_registrations_per_block(netuid_a, 10); // Enough for the below tests. -// SubtensorModule::set_max_registrations_per_block(netuid_b, 10); // Enough for the below tests. -// SubtensorModule::set_max_allowed_uids(netuid_a, 10); // Enough for the below tests. -// SubtensorModule::set_max_allowed_uids(netuid_b, 10); // Enough for the below tests. - -// // Attempt registration on A fails because the hotkey is not registered on network B. -// let (nonce, work): (u64, Vec) = -// SubtensorModule::create_work_for_block_number(netuid_a, 0, 3942084, &U256::from(0)); -// assert_eq!( -// SubtensorModule::register( -// <::RuntimeOrigin>::signed(hotkeys[0]), -// netuid_a, -// 0, -// nonce, -// work, -// hotkeys[0], -// coldkeys[0] -// ), -// Err(Error::::DidNotPassConnectedNetworkRequirement.into()) -// ); - -// // Attempt registration on B passes because there is no exterior requirement. -// let (nonce, work): (u64, Vec) = -// SubtensorModule::create_work_for_block_number(netuid_b, 0, 5942084, &U256::from(0)); -// assert_ok!(SubtensorModule::register( -// <::RuntimeOrigin>::signed(hotkeys[0]), -// netuid_b, -// 0, -// nonce, -// work, -// hotkeys[0], -// coldkeys[0] -// )); - -// // Attempt registration on A passes because this key is in the top 100 of keys on network B. -// let (nonce, work): (u64, Vec) = -// SubtensorModule::create_work_for_block_number(netuid_a, 0, 6942084, &U256::from(0)); -// assert_ok!(SubtensorModule::register( -// <::RuntimeOrigin>::signed(hotkeys[0]), -// netuid_a, -// 0, -// nonce, -// work, -// hotkeys[0], -// coldkeys[0] -// )); - -// // Lets attempt the key registration on A. Fails because we are not in B. -// let (nonce, work): (u64, Vec) = -// SubtensorModule::create_work_for_block_number(netuid_a, 0, 634242084, &U256::from(1)); -// assert_eq!( -// SubtensorModule::register( -// <::RuntimeOrigin>::signed(hotkeys[1]), -// netuid_a, -// 0, -// nonce, -// work, -// hotkeys[1], -// coldkeys[1] -// ), -// Err(Error::::DidNotPassConnectedNetworkRequirement.into()) -// ); - -// // Lets register the next key on B. Passes, np. -// let (nonce, work): (u64, Vec) = -// SubtensorModule::create_work_for_block_number(netuid_b, 0, 7942084, &U256::from(1)); -// assert_ok!(SubtensorModule::register( -// <::RuntimeOrigin>::signed(hotkeys[1]), -// netuid_b, -// 0, -// nonce, -// work, -// hotkeys[1], -// coldkeys[1] -// )); - -// // Lets make the connection requirement harder. Top 0th percentile. -// SubtensorModule::add_connection_requirement(netuid_a, netuid_b, 0); - -// // Attempted registration passes because the prunning score for hotkey_1 is the top keys on network B. -// let (nonce, work): (u64, Vec) = -// SubtensorModule::create_work_for_block_number(netuid_a, 0, 8942084, &U256::from(1)); -// assert_ok!(SubtensorModule::register( -// <::RuntimeOrigin>::signed(hotkeys[1]), -// netuid_a, -// 0, -// nonce, -// work, -// hotkeys[1], -// coldkeys[1] -// )); - -// // Lets register key 3 with lower prunning score. -// let (nonce, work): (u64, Vec) = -// SubtensorModule::create_work_for_block_number(netuid_b, 0, 9942084, &U256::from(2)); -// assert_ok!(SubtensorModule::register( -// <::RuntimeOrigin>::signed(hotkeys[2]), -// netuid_b, -// 0, -// nonce, -// work, -// hotkeys[2], -// coldkeys[2] -// )); -// SubtensorModule::set_pruning_score_for_uid( -// netuid_b, -// SubtensorModule::get_uid_for_net_and_hotkey(netuid_b, &hotkeys[2]).unwrap(), -// 0, -// ); // Set prunning score to 0. -// SubtensorModule::set_pruning_score_for_uid( -// netuid_b, -// SubtensorModule::get_uid_for_net_and_hotkey(netuid_b, &hotkeys[1]).unwrap(), -// 0, -// ); // Set prunning score to 0. -// SubtensorModule::set_pruning_score_for_uid( -// netuid_b, -// SubtensorModule::get_uid_for_net_and_hotkey(netuid_b, &hotkeys[0]).unwrap(), -// 0, -// ); // Set prunning score to 0. - -// // Lets register key 4 with higher prunining score. -// let (nonce, work): (u64, Vec) = -// SubtensorModule::create_work_for_block_number(netuid_b, 0, 10142084, &U256::from(3)); -// assert_ok!(SubtensorModule::register( -// <::RuntimeOrigin>::signed(hotkeys[3]), -// netuid_b, -// 0, -// nonce, -// work, -// hotkeys[3], -// coldkeys[3] -// )); -// SubtensorModule::set_pruning_score_for_uid( -// netuid_b, -// SubtensorModule::get_uid_for_net_and_hotkey(netuid_b, &hotkeys[3]).unwrap(), -// 1, -// ); // Set prunning score to 1. - -// // Attempted register of key 3 fails because of bad prunning score on B. -// let (nonce, work): (u64, Vec) = -// SubtensorModule::create_work_for_block_number(netuid_a, 0, 11142084, &U256::from(2)); -// assert_eq!( -// SubtensorModule::register( -// <::RuntimeOrigin>::signed(hotkeys[2]), -// netuid_a, -// 0, -// nonce, -// work, -// hotkeys[2], -// coldkeys[2] -// ), -// Err(Error::::DidNotPassConnectedNetworkRequirement.into()) -// ); - -// // Attempt to register key 4 passes because of best prunning score on B. -// let (nonce, work): (u64, Vec) = -// SubtensorModule::create_work_for_block_number(netuid_b, 0, 12142084, &U256::from(3)); -// assert_ok!(SubtensorModule::register( -// <::RuntimeOrigin>::signed(hotkeys[3]), -// netuid_a, -// 0, -// nonce, -// work, -// hotkeys[3], -// coldkeys[3] -// )); -// }); -// } +/* -------------------------------------------------------------------------- */ +/* Pruning behavior */ +/* -------------------------------------------------------------------------- */ #[test] -fn test_registration_origin_hotkey_mismatch() { +fn test_register_prunes_lowest_score_when_full() { new_test_ext(1).execute_with(|| { - let block_number: u64 = 0; - let netuid = NetUid::from(1); - let tempo: u16 = 13; - let hotkey_account_id_1: U256 = U256::from(1); - let hotkey_account_id_2: U256 = U256::from(2); - let coldkey_account_id: U256 = U256::from(668); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 0, - &hotkey_account_id_1, - ); + let netuid = NetUid::from(8); + add_network(netuid, 13, 0); - //add network - add_network(netuid, tempo, 0); + SubtensorModule::set_max_allowed_uids(netuid, 2); + SubtensorModule::set_immunity_period(netuid, 0); - let result = SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id_1), - netuid, - block_number, - nonce, - work.clone(), - hotkey_account_id_2, // Not the same as the origin. - coldkey_account_id, - ); - assert_eq!( - result, - Err(Error::::TransactorAccountShouldBeHotKey.into()) - ); - }); -} + // Reserves + funds for repeated registrations + let reserve = 1_000_000_000_000u64; + setup_reserves(netuid, reserve.into(), reserve.into()); -#[test] -fn test_registration_disabled() { - new_test_ext(1).execute_with(|| { - let block_number: u64 = 0; - let netuid = NetUid::from(1); - let tempo: u16 = 13; - let hotkey_account_id: U256 = U256::from(1); - let coldkey_account_id: U256 = U256::from(668); - let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( - netuid, - block_number, - 0, - &hotkey_account_id, - ); + let burn = SubtensorModule::get_burn(netuid); + let payer = U256::from(1000); + SubtensorModule::add_balance_to_coldkey_account(&payer, burn.saturating_mul(100)); - //add network - add_network(netuid, tempo, 0); - SubtensorModule::set_network_registration_allowed(netuid, false); - SubtensorModule::set_network_pow_registration_allowed(netuid, false); + // Register two hotkeys + let hk0 = U256::from(10); + let hk1 = U256::from(11); - let result = SubtensorModule::register( - <::RuntimeOrigin>::signed(hotkey_account_id), + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(payer), netuid, - block_number, - nonce, - work.clone(), - hotkey_account_id, - coldkey_account_id, - ); - assert_eq!( - result, - Err(Error::::SubNetRegistrationDisabled.into()) - ); - }); -} - -#[test] -fn test_last_update_correctness() { - new_test_ext(1).execute_with(|| { - let netuid = NetUid::from(1); - let tempo: u16 = 13; - let hotkey_account_id = U256::from(1); - let burn_cost = 1000; - let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har - //add network - SubtensorModule::set_burn(netuid, burn_cost.into()); - add_network(netuid, tempo, 0); + hk0 + )); + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(payer), + netuid, + hk1 + )); - let reserve = 1_000_000_000_000; - mock::setup_reserves(netuid, reserve.into(), reserve.into()); + // Ensure both exist and capture UIDs 0 and 1 + let uid0 = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hk0).unwrap(); + let uid1 = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hk1).unwrap(); + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 2); - // Simulate existing neurons - let existing_neurons = 3; - SubnetworkN::::insert(netuid, existing_neurons); + // Set pruning scores so uid1 is "worse" (lower) than uid0 + SubtensorModule::set_pruning_score_for_uid(netuid, uid0, 5); + SubtensorModule::set_pruning_score_for_uid(netuid, uid1, 1); - // Simulate no LastUpdate so far (can happen on mechanisms) - LastUpdate::::remove(NetUidStorageIndex::from(netuid)); - - // Give some $$$ to coldkey - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); - // Subscribe and check extrinsic output + // Third registration should prune uid1 + let hk2 = U256::from(12); assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(coldkey_account_id), + <::RuntimeOrigin>::signed(payer), netuid, - hotkey_account_id + hk2 )); - // Check that LastUpdate has existing_neurons + 1 elements now - assert_eq!( - LastUpdate::::get(NetUidStorageIndex::from(netuid)).len(), - (existing_neurons + 1) as usize - ); + // Still 2 neurons + assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 2); + + // uid1 should now map to hk2 + let now_hotkey_at_uid1 = SubtensorModule::get_hotkey_for_net_and_uid(netuid, uid1).unwrap(); + assert_eq!(now_hotkey_at_uid1, hk2); + + // uid0 should still map to hk0 + let now_hotkey_at_uid0 = SubtensorModule::get_hotkey_for_net_and_uid(netuid, uid0).unwrap(); + assert_eq!(now_hotkey_at_uid0, hk0); }); } - -// #[ignore] -// #[test] -// fn test_hotkey_swap_ok() { -// new_test_ext(1).execute_with(|| { -// let netuid = NetUid::from(1); -// let tempo: u16 = 13; -// let hotkey_account_id = U256::from(1); -// let burn_cost = 1000; -// let coldkey_account_id = U256::from(667); - -// SubtensorModule::set_burn(netuid, burn_cost); -// add_network(netuid, tempo, 0); - -// // Give it some $$$ in his coldkey balance -// SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10_000_000_000); - -// // Subscribe and check extrinsic output -// assert_ok!(SubtensorModule::burned_register( -// <::RuntimeOrigin>::signed(coldkey_account_id), -// netuid, -// hotkey_account_id -// )); - -// let new_hotkey = U256::from(1337); -// assert_ok!(SubtensorModule::swap_hotkey( -// <::RuntimeOrigin>::signed(coldkey_account_id), -// hotkey_account_id, -// new_hotkey -// )); -// assert_ne!( -// SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey_account_id), -// coldkey_account_id -// ); -// assert_eq!( -// SubtensorModule::get_owning_coldkey_for_hotkey(&new_hotkey), -// coldkey_account_id -// ); -// }); -// } - -// #[ignore] -// #[test] -// fn test_hotkey_swap_not_owner() { -// new_test_ext(1).execute_with(|| { -// let netuid = NetUid::from(1); -// let tempo: u16 = 13; -// let hotkey_account_id = U256::from(1); -// let burn_cost = 1000; -// let coldkey_account_id = U256::from(2); -// let not_owner_coldkey = U256::from(3); - -// SubtensorModule::set_burn(netuid, burn_cost); -// add_network(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 -// )); - -// let new_hotkey = U256::from(4); -// assert_err!( -// SubtensorModule::swap_hotkey( -// <::RuntimeOrigin>::signed(not_owner_coldkey), -// hotkey_account_id, -// new_hotkey -// ), -// Error::::NonAssociatedColdKey -// ); -// }); -// } - -// #[ignore] -// #[test] -// fn test_hotkey_swap_same_key() { -// new_test_ext(1).execute_with(|| { -// let netuid = NetUid::from(1); -// let tempo: u16 = 13; -// let hotkey_account_id = U256::from(1); -// let burn_cost = 1000; -// let coldkey_account_id = U256::from(2); - -// SubtensorModule::set_burn(netuid, burn_cost); -// add_network(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_err!( -// SubtensorModule::swap_hotkey( -// <::RuntimeOrigin>::signed(coldkey_account_id), -// hotkey_account_id, -// hotkey_account_id -// ), -// Error::::HotKeyAlreadyRegisteredInSubNet -// ); -// }); -// } - -// #[ignore] -// #[test] -// fn test_hotkey_swap_registered_key() { -// new_test_ext(1).execute_with(|| { -// let netuid = NetUid::from(1); -// let tempo: u16 = 13; -// let hotkey_account_id = U256::from(1); -// let burn_cost = 1000; -// let coldkey_account_id = U256::from(2); - -// SubtensorModule::set_burn(netuid, burn_cost); -// add_network(netuid, tempo, 0); - -// // Give it some $$$ in his coldkey balance -// SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 100_000_000_000); - -// // Subscribe and check extrinsic output -// assert_ok!(SubtensorModule::burned_register( -// <::RuntimeOrigin>::signed(coldkey_account_id), -// netuid, -// hotkey_account_id -// )); - -// let new_hotkey = U256::from(3); -// assert_ok!(SubtensorModule::burned_register( -// <::RuntimeOrigin>::signed(coldkey_account_id), -// netuid, -// new_hotkey -// )); - -// assert_err!( -// SubtensorModule::swap_hotkey( -// <::RuntimeOrigin>::signed(coldkey_account_id), -// hotkey_account_id, -// new_hotkey -// ), -// Error::::HotKeyAlreadyRegisteredInSubNet -// ); -// }); -// } diff --git a/pallets/subtensor/src/tests/senate.rs b/pallets/subtensor/src/tests/senate.rs index 8ad093d0a..6d5a84549 100644 --- a/pallets/subtensor/src/tests/senate.rs +++ b/pallets/subtensor/src/tests/senate.rs @@ -72,7 +72,6 @@ fn test_senate_join_works() { let stake = DefaultMinStake::::get() * 100.into(); //add network - SubtensorModule::set_burn(netuid, burn_cost.into()); add_network(netuid, tempo, 0); // Give it some $$$ in his coldkey balance SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); @@ -148,7 +147,6 @@ fn test_senate_vote_works() { let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har //add network - SubtensorModule::set_burn(netuid, burn_cost.into()); add_network(netuid, tempo, 0); // Give it some $$$ in his coldkey balance SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); @@ -264,7 +262,6 @@ fn test_senate_vote_not_member() { let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har //add network - SubtensorModule::set_burn(netuid, burn_cost.into()); add_network(netuid, tempo, 0); // Give it some $$$ in his coldkey balance SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); @@ -328,7 +325,6 @@ fn test_senate_leave_works() { let stake = DefaultMinStake::::get() * 10.into(); //add network - SubtensorModule::set_burn(netuid, burn_cost.into()); add_network(netuid, tempo, 0); // Give it some $$$ in his coldkey balance SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); @@ -406,7 +402,6 @@ fn test_senate_leave_vote_removal() { let stake = DefaultMinStake::::get() * 10.into(); //add network - SubtensorModule::set_burn(netuid, burn_cost.into()); add_network(netuid, tempo, 0); // Give it some $$$ in his coldkey balance SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, stake.into()); @@ -491,7 +486,6 @@ fn test_senate_leave_vote_removal() { // Add two networks. let other_netuid = NetUid::from(5); add_network(other_netuid, 1, 0); - SubtensorModule::set_burn(other_netuid, TaoCurrency::ZERO); SubtensorModule::set_max_registrations_per_block(other_netuid, 1000); SubtensorModule::set_target_registrations_per_interval(other_netuid, 1000); SubtensorModule::set_max_registrations_per_block(NetUid::ROOT, 1000); @@ -558,7 +552,6 @@ fn test_senate_not_leave_when_stake_removed() { let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har //add network - SubtensorModule::set_burn(netuid, burn_cost.into()); add_network(netuid, tempo, 0); // Give it some $$$ in his coldkey balance SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); @@ -645,7 +638,6 @@ fn test_senate_join_current_delegate() { let coldkey_account_id = U256::from(667); //add network - SubtensorModule::set_burn(netuid, burn_cost.into()); add_network(netuid, tempo, 0); // Give some coldkey balance SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); @@ -737,7 +729,6 @@ fn test_adjust_senate_events() { let replacement_hotkey_account_id = U256::from(7); // Will be added to the senate to replace hotkey_account_id //add network - SubtensorModule::set_burn(netuid, burn_cost.into()); add_network(netuid, tempo, 0); // Give some coldkey balance SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, balance_to_add); diff --git a/pallets/subtensor/src/tests/subnet.rs b/pallets/subtensor/src/tests/subnet.rs index a11eae759..2b158c253 100644 --- a/pallets/subtensor/src/tests/subnet.rs +++ b/pallets/subtensor/src/tests/subnet.rs @@ -66,7 +66,6 @@ fn test_do_start_call_fail_not_owner() { let wrong_owner_account_id = U256::from(2); let burn_cost = TaoCurrency::from(1000); //add network - SubtensorModule::set_burn(netuid, burn_cost); add_network_without_emission_block(netuid, tempo, 0); mock::setup_reserves(netuid, 1_000_000_000.into(), 1_000_000_000.into()); // Give it some $$$ in his coldkey balance @@ -96,7 +95,6 @@ fn test_do_start_call_fail_with_cannot_start_call_now() { let coldkey_account_id = U256::from(0); let burn_cost = TaoCurrency::from(1000); //add network - SubtensorModule::set_burn(netuid, burn_cost); add_network_without_emission_block(netuid, tempo, 0); mock::setup_reserves(netuid, 1_000_000_000.into(), 1_000_000_000.into()); // Give it some $$$ in his coldkey balance @@ -125,7 +123,6 @@ fn test_do_start_call_fail_for_set_again() { let hotkey_account_id = U256::from(1); let burn_cost = TaoCurrency::from(1000); - SubtensorModule::set_burn(netuid, burn_cost); add_network_without_emission_block(netuid, tempo, 0); assert_eq!(FirstEmissionBlockNumber::::get(netuid), None); @@ -691,8 +688,6 @@ fn test_subtoken_enable_ok_for_burn_register_before_enable() { let hotkey_account_2_id: U256 = U256::from(3); let burn_cost = TaoCurrency::from(1000); - // Set the burn cost - SubtensorModule::set_burn(netuid, burn_cost); // Add the networks with subtoken disabled add_network_disable_subtoken(netuid, 10, 0); add_network_disable_subtoken(netuid2, 10, 0); diff --git a/pallets/subtensor/src/tests/swap_coldkey.rs b/pallets/subtensor/src/tests/swap_coldkey.rs index 4c683671a..042623c8d 100644 --- a/pallets/subtensor/src/tests/swap_coldkey.rs +++ b/pallets/subtensor/src/tests/swap_coldkey.rs @@ -2038,7 +2038,6 @@ fn test_coldkey_swap_delegate_identity_updated() { let burn_cost = TaoCurrency::from(10); let tempo = 1; - SubtensorModule::set_burn(netuid, burn_cost); add_network(netuid, tempo, 0); SubtensorModule::add_balance_to_coldkey_account(&old_coldkey, 100_000_000_000); @@ -2091,7 +2090,6 @@ fn test_coldkey_swap_no_identity_no_changes() { let burn_cost = TaoCurrency::from(10); let tempo = 1; - SubtensorModule::set_burn(netuid, burn_cost); add_network(netuid, tempo, 0); SubtensorModule::add_balance_to_coldkey_account(&old_coldkey, 100_000_000_000); @@ -2129,7 +2127,6 @@ fn test_coldkey_swap_no_identity_no_changes_newcoldkey_exists() { let burn_cost = TaoCurrency::from(10); let tempo = 1; - SubtensorModule::set_burn(netuid, burn_cost); add_network(netuid, tempo, 0); SubtensorModule::add_balance_to_coldkey_account(&old_coldkey, 100_000_000_000); mock::setup_reserves(netuid, 1_000_000_000_000.into(), 1_000_000_000_000.into()); diff --git a/pallets/subtensor/src/utils/misc.rs b/pallets/subtensor/src/utils/misc.rs index a4d4755e5..7b475c484 100644 --- a/pallets/subtensor/src/utils/misc.rs +++ b/pallets/subtensor/src/utils/misc.rs @@ -6,7 +6,7 @@ use crate::system::{ use safe_math::*; use sp_core::Get; use sp_core::U256; -use sp_runtime::Saturating; +use sp_runtime::{FixedU128, Saturating}; use substrate_fixed::types::{I32F32, U96F32}; use subtensor_runtime_common::{AlphaCurrency, NetUid, NetUidStorageIndex, TaoCurrency}; @@ -663,27 +663,46 @@ impl Pallet { )); } - pub fn get_burn(netuid: NetUid) -> TaoCurrency { - Burn::::get(netuid) + /// Returns the current burn price for `netuid` in base units (e.g., RAO). + /// Implements the new BurnHalfLife / BurnIncreaseMult mechanism. + pub fn get_burn(netuid: NetUid) -> u64 { + let now = Self::get_current_block_as_u64(); + // Ensure defaults & initial state exist (e.g., 1 TAO for new subnets). + Self::initialize_burn_price_if_needed(netuid, now); + // Bring price state forward to `now`, applying queued bumps & decay. + Self::update_burn_price_to_block(netuid, now); + + // Read current price (stored as u128) and downcast safely. + let p: u128 = BurnPrice::::get(netuid); + p.min(u64::MAX as u128) as u64 } - pub fn set_burn(netuid: NetUid, burn: TaoCurrency) { - Burn::::insert(netuid, burn); + pub fn get_burn_half_life(netuid: NetUid) -> u64 { + let v = BurnHalfLife::::get(netuid); + if v == 0 { 360 } else { v } } - pub fn get_min_burn(netuid: NetUid) -> TaoCurrency { - MinBurn::::get(netuid) - } - pub fn set_min_burn(netuid: NetUid, min_burn: TaoCurrency) { - MinBurn::::insert(netuid, min_burn); - Self::deposit_event(Event::MinBurnSet(netuid, min_burn)); + pub fn set_burn_half_life(netuid: NetUid, half_life: u64) { + // protect against zero (treat as 1) + let hl = core::cmp::max(half_life, 1); + BurnHalfLife::::insert(netuid, hl); + Self::deposit_event(Event::BurnHalfLifeSet(netuid, hl)); } - pub fn get_max_burn(netuid: NetUid) -> TaoCurrency { - MaxBurn::::get(netuid) + pub fn get_burn_increase_mult(netuid: NetUid) -> FixedU128 { + let m = BurnIncreaseMult::::get(netuid); + if m.is_zero() { + FixedU128::from_u32(2) + } else { + m + } } - pub fn set_max_burn(netuid: NetUid, max_burn: TaoCurrency) { - MaxBurn::::insert(netuid, max_burn); - Self::deposit_event(Event::MaxBurnSet(netuid, max_burn)); + + pub fn set_burn_increase_mult(netuid: NetUid, mult: FixedU128) { + // Require >= 1.0 + let one = FixedU128::one(); + let m = if mult < one { one } else { mult }; + BurnIncreaseMult::::insert(netuid, m); + Self::deposit_event(Event::BurnIncreaseMultSet(netuid, m)); } pub fn get_difficulty_as_u64(netuid: NetUid) -> u64 { diff --git a/precompiles/src/subnet.rs b/precompiles/src/subnet.rs index 8b4d0eff8..398997ce8 100644 --- a/precompiles/src/subnet.rs +++ b/precompiles/src/subnet.rs @@ -179,15 +179,8 @@ where netuid: u16, min_difficulty: u64, ) -> EvmResult<()> { - let call = pallet_admin_utils::Call::::sudo_set_min_difficulty { - netuid: netuid.into(), - min_difficulty, - }; - - handle.try_dispatch_runtime_call::( - call, - RawOrigin::Signed(handle.caller_account_id::()), - ) + // DEPRECATED + Ok(()) } #[precompile::public("getMaxDifficulty(uint16)")] @@ -205,15 +198,8 @@ where netuid: u16, max_difficulty: u64, ) -> EvmResult<()> { - let call = pallet_admin_utils::Call::::sudo_set_max_difficulty { - netuid: netuid.into(), - max_difficulty, - }; - - handle.try_dispatch_runtime_call::( - call, - RawOrigin::Signed(handle.caller_account_id::()), - ) + // DEPRECATED + Ok(()) } #[precompile::public("getWeightsVersionKey(uint16)")] @@ -560,15 +546,8 @@ where netuid: u16, difficulty: u64, ) -> EvmResult<()> { - let call = pallet_admin_utils::Call::::sudo_set_difficulty { - netuid: netuid.into(), - difficulty, - }; - - handle.try_dispatch_runtime_call::( - call, - RawOrigin::Signed(handle.caller_account_id::()), - ) + // DEPRECATED + Ok(()) } #[precompile::public("getBondsMovingAverage(uint16)")] diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 5654def01..4cd4895ca 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -826,12 +826,6 @@ impl InstanceFilter for ProxyType { | RuntimeCall::AdminUtils( pallet_admin_utils::Call::sudo_set_serving_rate_limit { .. } ) - | RuntimeCall::AdminUtils( - pallet_admin_utils::Call::sudo_set_min_difficulty { .. } - ) - | RuntimeCall::AdminUtils( - pallet_admin_utils::Call::sudo_set_max_difficulty { .. } - ) | RuntimeCall::AdminUtils( pallet_admin_utils::Call::sudo_set_weights_version_key { .. } ) @@ -858,7 +852,6 @@ impl InstanceFilter for ProxyType { | RuntimeCall::AdminUtils( pallet_admin_utils::Call::sudo_set_network_pow_registration_allowed { .. } ) - | RuntimeCall::AdminUtils(pallet_admin_utils::Call::sudo_set_max_burn { .. }) | RuntimeCall::AdminUtils( pallet_admin_utils::Call::sudo_set_bonds_moving_average { .. } )