diff --git a/evm-tests/src/subtensor.ts b/evm-tests/src/subtensor.ts index e1091c1645..ab1508e4b4 100644 --- a/evm-tests/src/subtensor.ts +++ b/evm-tests/src/subtensor.ts @@ -7,7 +7,7 @@ import { convertH160ToSS58, convertPublicKeyToSs58, ethAddressToH160 } from './a import { tao } from './balance-math' import internal from "stream"; -// create a new subnet and return netuid +// create a new subnet and return netuid export async function addNewSubnetwork(api: TypedApi, hotkey: KeyPair, coldkey: KeyPair) { const alice = getAliceSigner() const totalNetworks = await api.query.SubtensorModule.TotalNetworks.getValue() @@ -392,13 +392,13 @@ export async function disableAdminFreezeWindowAndOwnerHyperparamRateLimit(api: T } const currentOwnerHyperparamRateLimit = await api.query.SubtensorModule.OwnerHyperparamRateLimit.getValue() - if (currentOwnerHyperparamRateLimit !== BigInt(0)) { + if (currentOwnerHyperparamRateLimit !== 0) { // Set OwnerHyperparamRateLimit to 0 - const setOwnerRateLimit = api.tx.AdminUtils.sudo_set_owner_hparam_rate_limit({ limit: BigInt(0) }) + const setOwnerRateLimit = api.tx.AdminUtils.sudo_set_owner_hparam_rate_limit({ epochs: 0 }) const sudoOwnerRateTx = api.tx.Sudo.sudo({ call: setOwnerRateLimit.decodedCall }) await waitForTransactionWithRetry(api, sudoOwnerRateTx, alice) } assert.equal(0, await api.query.SubtensorModule.AdminFreezeWindow.getValue()) assert.equal(BigInt(0), await api.query.SubtensorModule.OwnerHyperparamRateLimit.getValue()) -} \ No newline at end of file +} diff --git a/pallets/admin-utils/src/benchmarking.rs b/pallets/admin-utils/src/benchmarking.rs index 54ede60a18..6a06e754b9 100644 --- a/pallets/admin-utils/src/benchmarking.rs +++ b/pallets/admin-utils/src/benchmarking.rs @@ -416,7 +416,7 @@ mod benchmarks { // disable admin freeze window pallet_subtensor::Pallet::::set_admin_freeze_window(0); #[extrinsic_call] - _(RawOrigin::Root, 10u64/*limit*/)/*sudo_set_owner_hparam_rate_limit*/; + _(RawOrigin::Root, 2u16/*epochs*/)/*sudo_set_owner_hparam_rate_limit*/; } #[benchmark] diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 14c5121f41..84de882ac6 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -25,7 +25,7 @@ pub mod pallet { use frame_support::{dispatch::DispatchResult, pallet_prelude::StorageMap}; use frame_system::pallet_prelude::*; use pallet_evm_chain_id::{self, ChainId}; - use pallet_subtensor::utils::rate_limiting::TransactionType; + use pallet_subtensor::utils::rate_limiting::{Hyperparameter, TransactionType}; use sp_runtime::BoundedVec; use substrate_fixed::types::I96F32; use subtensor_runtime_common::{NetUid, SubId, TaoCurrency}; @@ -216,14 +216,14 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::ServingRateLimit.into()], )?; pallet_subtensor::Pallet::::set_serving_rate_limit(netuid, serving_rate_limit); log::debug!("ServingRateLimitSet( serving_rate_limit: {serving_rate_limit:?} ) "); pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::ServingRateLimit.into()], ); Ok(()) } @@ -268,7 +268,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::MaxDifficulty.into()], )?; ensure!( @@ -282,7 +282,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::MaxDifficulty.into()], ); Ok(()) } @@ -302,10 +302,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin.clone(), netuid, - &[ - TransactionType::OwnerHyperparamUpdate, - TransactionType::SetWeightsVersionKey, - ], + &[TransactionType::SetWeightsVersionKey], )?; ensure!( @@ -316,10 +313,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[ - TransactionType::OwnerHyperparamUpdate, - TransactionType::SetWeightsVersionKey, - ], + &[TransactionType::SetWeightsVersionKey], ); pallet_subtensor::Pallet::::set_weights_version_key(netuid, weights_version_key); @@ -399,7 +393,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::AdjustmentAlpha.into()], )?; ensure!( @@ -410,7 +404,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::AdjustmentAlpha.into()], ); log::debug!("AdjustmentAlphaSet( adjustment_alpha: {adjustment_alpha:?} ) "); Ok(()) @@ -431,7 +425,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::MaxWeightLimit.into()], )?; ensure!( @@ -442,7 +436,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::MaxWeightLimit.into()], ); log::debug!( "MaxWeightLimitSet( netuid: {netuid:?} max_weight_limit: {max_weight_limit:?} ) " @@ -465,7 +459,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::ImmunityPeriod.into()], )?; ensure!( pallet_subtensor::Pallet::::if_subnet_exist(netuid), @@ -476,7 +470,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::ImmunityPeriod.into()], ); log::debug!( "ImmunityPeriodSet( netuid: {netuid:?} immunity_period: {immunity_period:?} ) " @@ -499,7 +493,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::MinAllowedWeights.into()], )?; ensure!( @@ -513,7 +507,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::MinAllowedWeights.into()], ); Ok(()) } @@ -557,7 +551,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::Kappa.into()], )?; ensure!( @@ -569,7 +563,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::Kappa.into()], ); Ok(()) } @@ -585,7 +579,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::Rho.into()], )?; ensure!( @@ -597,7 +591,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::Rho.into()], ); Ok(()) } @@ -617,7 +611,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::ActivityCutoff.into()], )?; ensure!( @@ -637,7 +631,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::ActivityCutoff.into()], ); Ok(()) } @@ -685,7 +679,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::PowRegistrationAllowed.into()], )?; pallet_subtensor::Pallet::::set_network_pow_registration_allowed( @@ -698,7 +692,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::PowRegistrationAllowed.into()], ); Ok(()) } @@ -746,7 +740,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::MinBurn.into()], )?; ensure!( pallet_subtensor::Pallet::::if_subnet_exist(netuid), @@ -766,7 +760,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::MinBurn.into()], ); Ok(()) } @@ -786,7 +780,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::MaxBurn.into()], )?; ensure!( pallet_subtensor::Pallet::::if_subnet_exist(netuid), @@ -806,7 +800,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::MaxBurn.into()], ); Ok(()) } @@ -881,7 +875,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::BondsMovingAverage.into()], )?; if maybe_owner.is_some() { ensure!( @@ -901,7 +895,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::BondsMovingAverage.into()], ); Ok(()) } @@ -921,7 +915,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::BondsPenalty.into()], )?; ensure!( @@ -933,7 +927,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::BondsPenalty.into()], ); Ok(()) } @@ -1205,7 +1199,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::CommitRevealEnabled.into()], )?; ensure!( @@ -1218,7 +1212,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::CommitRevealEnabled.into()], ); Ok(()) } @@ -1242,14 +1236,14 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::LiquidAlphaEnabled.into()], )?; pallet_subtensor::Pallet::::set_liquid_alpha_enabled(netuid, enabled); log::debug!("LiquidAlphaEnableToggled( netuid: {netuid:?}, Enabled: {enabled:?} ) "); pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::LiquidAlphaEnabled.into()], ); Ok(()) } @@ -1266,7 +1260,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin.clone(), netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::AlphaValues.into()], )?; let res = pallet_subtensor::Pallet::::do_set_alpha_values( origin, netuid, alpha_low, alpha_high, @@ -1275,7 +1269,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::AlphaValues.into()], ); } res @@ -1373,7 +1367,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::WeightCommitInterval.into()], )?; ensure!( @@ -1387,7 +1381,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::WeightCommitInterval.into()], ); Ok(()) @@ -1465,14 +1459,14 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::TransferEnabled.into()], )?; let res = pallet_subtensor::Pallet::::toggle_transfer(netuid, toggle); if res.is_ok() { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::TransferEnabled.into()], ); } res @@ -1607,7 +1601,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin.clone(), netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::AlphaSigmoidSteepness.into()], )?; ensure!( @@ -1627,7 +1621,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::AlphaSigmoidSteepness.into()], ); Ok(()) } @@ -1651,7 +1645,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::Yuma3Enabled.into()], )?; pallet_subtensor::Pallet::::set_yuma3_enabled(netuid, enabled); @@ -1660,7 +1654,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::Yuma3Enabled.into()], ); Ok(()) } @@ -1684,7 +1678,7 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::BondsResetEnabled.into()], )?; pallet_subtensor::Pallet::::set_bonds_reset(netuid, enabled); @@ -1693,7 +1687,7 @@ pub mod pallet { pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::BondsResetEnabled.into()], ); Ok(()) } @@ -1797,13 +1791,13 @@ pub mod pallet { let maybe_owner = pallet_subtensor::Pallet::::ensure_sn_owner_or_root_with_limits( origin, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::ImmuneNeuronLimit.into()], )?; pallet_subtensor::Pallet::::set_owner_immune_neuron_limit(netuid, immune_neurons)?; pallet_subtensor::Pallet::::record_owner_rl( maybe_owner, netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::ImmuneNeuronLimit.into()], ); Ok(()) } @@ -1838,7 +1832,7 @@ pub mod pallet { Ok(()) } - /// Sets the owner hyperparameter rate limit (in blocks). + /// Sets the owner hyperparameter rate limit in epochs (global multiplier). /// Only callable by root. #[pallet::call_index(75)] #[pallet::weight(( @@ -1849,11 +1843,11 @@ pub mod pallet { ))] pub fn sudo_set_owner_hparam_rate_limit( origin: OriginFor, - limit: u64, + epochs: u16, ) -> DispatchResult { ensure_root(origin)?; - pallet_subtensor::Pallet::::set_owner_hyperparam_rate_limit(limit); - log::debug!("OwnerHyperparamRateLimitSet( limit: {limit:?} ) "); + pallet_subtensor::Pallet::::set_owner_hyperparam_rate_limit(epochs); + log::debug!("OwnerHyperparamRateLimitSet( epochs: {epochs:?} ) "); Ok(()) } diff --git a/pallets/admin-utils/src/tests/mod.rs b/pallets/admin-utils/src/tests/mod.rs index b4741bbfd9..124efc859d 100644 --- a/pallets/admin-utils/src/tests/mod.rs +++ b/pallets/admin-utils/src/tests/mod.rs @@ -7,7 +7,7 @@ use frame_support::{ use frame_system::Config; use pallet_subtensor::{Error as SubtensorError, SubnetOwner, Tempo, WeightsVersionKeyRateLimit}; // use pallet_subtensor::{migrations, Event}; -use pallet_subtensor::Event; +use pallet_subtensor::{Event, utils::rate_limiting::TransactionType}; use sp_consensus_grandpa::AuthorityId as GrandpaId; use sp_core::{Get, Pair, U256, ed25519}; use substrate_fixed::types::I96F32; @@ -188,11 +188,10 @@ fn test_sudo_set_weights_version_key_rate_limit() { // Try to set again with // Assert rate limit not passed - assert!(!SubtensorModule::passes_rate_limit_on_subnet( - &pallet_subtensor::utils::rate_limiting::TransactionType::SetWeightsVersionKey, - &sn_owner, - netuid - )); + assert!( + !TransactionType::SetWeightsVersionKey + .passes_rate_limit_on_subnet::(&sn_owner, netuid) + ); // Try transaction assert_noop!( @@ -206,11 +205,10 @@ fn test_sudo_set_weights_version_key_rate_limit() { // Wait for rate limit to pass run_to_block(rate_limit_period + 1); - assert!(SubtensorModule::passes_rate_limit_on_subnet( - &pallet_subtensor::utils::rate_limiting::TransactionType::SetWeightsVersionKey, - &sn_owner, - netuid - )); + assert!( + TransactionType::SetWeightsVersionKey + .passes_rate_limit_on_subnet::(&sn_owner, netuid) + ); // Try transaction assert_ok!(AdminUtils::sudo_set_weights_version_key( @@ -1973,7 +1971,7 @@ fn test_sudo_set_admin_freeze_window_and_rate() { )); assert_eq!(pallet_subtensor::AdminFreezeWindow::::get(), 7); - // Owner hyperparam rate limit setter + // Owner hyperparam tempos setter assert_eq!( AdminUtils::sudo_set_owner_hparam_rate_limit( <::RuntimeOrigin>::signed(U256::from(1)), @@ -2097,10 +2095,12 @@ fn test_owner_hyperparam_update_rate_limit_enforced() { let owner: U256 = U256::from(5); SubnetOwner::::insert(netuid, owner); - // Configure owner hyperparam RL to 2 blocks - assert_ok!(AdminUtils::sudo_set_owner_hparam_rate_limit( + // Set tempo to 1 so owner hyperparam RL = 2 tempos = 2 blocks + SubtensorModule::set_tempo(netuid, 1); + // Disable admin freeze window to avoid blocking on small tempo + assert_ok!(AdminUtils::sudo_set_admin_freeze_window( <::RuntimeOrigin>::root(), - 2 + 0 )); // First update succeeds @@ -2140,10 +2140,9 @@ fn test_owner_hyperparam_update_rate_limit_enforced() { }); } -// Verifies that when the owner hyperparameter rate limit is left at its default (0), hyperparameter -// updates are not blocked until a non-zero value is set. +// Verifies that owner hyperparameter rate limit is enforced based on tempo (2 tempos). #[test] -fn test_hyperparam_rate_limit_not_blocking_with_default() { +fn test_hyperparam_rate_limit_enforced_by_tempo() { new_test_ext().execute_with(|| { // Setup subnet and owner let netuid = NetUid::from(42); @@ -2151,23 +2150,111 @@ fn test_hyperparam_rate_limit_not_blocking_with_default() { let owner: U256 = U256::from(77); SubnetOwner::::insert(netuid, owner); - // Read the default (unset) owner hyperparam rate limit - let default_limit = pallet_subtensor::OwnerHyperparamRateLimit::::get(); - - assert_eq!(default_limit, 0); + // Set tempo to 1 so RL = 2 blocks + SubtensorModule::set_tempo(netuid, 1); + // Disable admin freeze window to avoid blocking on small tempo + assert_ok!(AdminUtils::sudo_set_admin_freeze_window( + <::RuntimeOrigin>::root(), + 0 + )); - // First owner update should always succeed + // First owner update should succeed assert_ok!(AdminUtils::sudo_set_kappa( <::RuntimeOrigin>::signed(owner), netuid, 1 )); - // With default == 0, second immediate update should also pass (no rate limiting) + // Immediate second update should fail due to tempo-based RL + assert_noop!( + AdminUtils::sudo_set_kappa(<::RuntimeOrigin>::signed(owner), netuid, 2), + SubtensorError::::TxRateLimitExceeded + ); + + // Advance 2 blocks (2 tempos with tempo=1) then succeed + run_to_block(SubtensorModule::get_current_block_as_u64() + 2); + assert_ok!(AdminUtils::sudo_set_kappa( + <::RuntimeOrigin>::signed(owner), + netuid, + 3 + )); + }); +} + +// Verifies owner hyperparameters are rate-limited independently per parameter. +// Setting one hyperparameter should not block setting a different hyperparameter +// during the same rate-limit window, but it should still block itself. +#[test] +fn test_owner_hyperparam_rate_limit_independent_per_param() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(7); + add_network(netuid, 10); + + // Set subnet owner + let owner: U256 = U256::from(123); + SubnetOwner::::insert(netuid, owner); + + // Use small tempo to make RL short and deterministic (2 blocks when tempo=1) + SubtensorModule::set_tempo(netuid, 1); + // Disable admin freeze window so it doesn't interfere with small tempo + assert_ok!(AdminUtils::sudo_set_admin_freeze_window( + <::RuntimeOrigin>::root(), + 0 + )); + + // First update to kappa should succeed assert_ok!(AdminUtils::sudo_set_kappa( <::RuntimeOrigin>::signed(owner), netuid, - 2 + 10 + )); + + // Immediate second update to the SAME param (kappa) should be blocked by RL + assert_noop!( + AdminUtils::sudo_set_kappa( + <::RuntimeOrigin>::signed(owner), + netuid, + 11 + ), + SubtensorError::::TxRateLimitExceeded + ); + + // Updating a DIFFERENT param (rho) should pass immediately — independent RL key + assert_ok!(AdminUtils::sudo_set_rho( + <::RuntimeOrigin>::signed(owner), + netuid, + 5 + )); + + // kappa should still be blocked until its own RL window passes + assert_noop!( + AdminUtils::sudo_set_kappa( + <::RuntimeOrigin>::signed(owner), + netuid, + 12 + ), + SubtensorError::::TxRateLimitExceeded + ); + + // rho should also be blocked for itself immediately after being set + assert_noop!( + AdminUtils::sudo_set_rho(<::RuntimeOrigin>::signed(owner), netuid, 6), + SubtensorError::::TxRateLimitExceeded + ); + + // Advance enough blocks to pass the RL window (2 blocks when tempo=1 and default epochs=2) + run_to_block(SubtensorModule::get_current_block_as_u64() + 2); + + // Now both hyperparameters can be updated again + assert_ok!(AdminUtils::sudo_set_kappa( + <::RuntimeOrigin>::signed(owner), + netuid, + 13 + )); + assert_ok!(AdminUtils::sudo_set_rho( + <::RuntimeOrigin>::signed(owner), + netuid, + 7 )); }); } diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 18dfca8ea9..cdee675b00 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -42,7 +42,7 @@ pub mod staking; pub mod subnets; pub mod swap; pub mod utils; -use crate::utils::rate_limiting::TransactionType; +use crate::utils::rate_limiting::{Hyperparameter, TransactionType}; use macros::{config, dispatches, errors, events, genesis, hooks}; #[cfg(test)] @@ -860,18 +860,18 @@ pub mod pallet { 50400 } - #[pallet::type_value] - /// Default value for subnet owner hyperparameter update rate limit (in blocks) - pub fn DefaultOwnerHyperparamRateLimit() -> u64 { - 0 - } - #[pallet::type_value] /// Default number of terminal blocks in a tempo during which admin operations are prohibited pub fn DefaultAdminFreezeWindow() -> u16 { 10 } + #[pallet::type_value] + /// Default number of tempos for owner hyperparameter update rate limit + pub fn DefaultOwnerHyperparamRateLimit() -> u16 { + 2 + } + #[pallet::type_value] /// Default value for ck burn, 18%. pub fn DefaultCKBurn() -> u64 { @@ -888,9 +888,9 @@ pub mod pallet { StorageValue<_, u16, ValueQuery, DefaultAdminFreezeWindow>; #[pallet::storage] - /// Global rate limit (in blocks) for subnet owner hyperparameter updates - pub type OwnerHyperparamRateLimit = - StorageValue<_, u64, ValueQuery, DefaultOwnerHyperparamRateLimit>; + /// Global number of epochs used to rate limit subnet owner hyperparameter updates + pub type OwnerHyperparamRateLimit = + StorageValue<_, u16, ValueQuery, DefaultOwnerHyperparamRateLimit>; #[pallet::storage] pub type ColdkeySwapScheduleDuration = @@ -2194,7 +2194,7 @@ pub enum RateLimitKey { // The setting sn owner hotkey operation is rate limited per netuid SetSNOwnerHotkey(NetUid), // Generic rate limit for subnet-owner hyperparameter updates (per netuid) - OwnerHyperparamUpdate(NetUid), + OwnerHyperparamUpdate(NetUid, Hyperparameter), // Subnet registration rate limit NetworkLastRegistered, // Last tx block limit per account ID diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index a0779cd8b1..bb41c063ea 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -116,8 +116,8 @@ mod events { TxChildKeyTakeRateLimitSet(u64), /// setting the admin freeze window length (last N blocks of tempo) AdminFreezeWindowSet(u16), - /// setting the owner hyperparameter rate limit (in blocks) - OwnerHyperparamRateLimitSet(u64), + /// setting the owner hyperparameter rate limit in epochs + OwnerHyperparamRateLimitSet(u16), /// minimum childkey take set MinChildKeyTakeSet(u16), /// maximum childkey take set diff --git a/pallets/subtensor/src/staking/set_children.rs b/pallets/subtensor/src/staking/set_children.rs index 139ea82c5d..c6c37f7e96 100644 --- a/pallets/subtensor/src/staking/set_children.rs +++ b/pallets/subtensor/src/staking/set_children.rs @@ -48,10 +48,9 @@ impl Pallet { // Ensure the hotkey passes the rate limit. ensure!( - Self::passes_rate_limit_on_subnet( - &TransactionType::SetChildren, // Set children. - &hotkey, // Specific to a hotkey. - netuid, // Specific to a subnet. + TransactionType::SetChildren.passes_rate_limit_on_subnet::( + &hotkey, // Specific to a hotkey. + netuid, // Specific to a subnet. ), Error::::TxRateLimitExceeded ); @@ -111,12 +110,7 @@ impl Pallet { // Set last transaction block let current_block = Self::get_current_block_as_u64(); - Self::set_last_transaction_block_on_subnet( - &hotkey, - netuid, - &TransactionType::SetChildren, - current_block, - ); + TransactionType::SetChildren.set_last_block_on_subnet::(&hotkey, netuid, current_block); // Calculate cool-down block let cooldown_block = @@ -319,10 +313,9 @@ impl Pallet { if take > current_take { // Ensure the hotkey passes the rate limit. ensure!( - Self::passes_rate_limit_on_subnet( - &TransactionType::SetChildkeyTake, // Set childkey take. - &hotkey, // Specific to a hotkey. - netuid, // Specific to a subnet. + TransactionType::SetChildkeyTake.passes_rate_limit_on_subnet::( + &hotkey, // Specific to a hotkey. + netuid, // Specific to a subnet. ), Error::::TxChildkeyTakeRateLimitExceeded ); @@ -330,10 +323,9 @@ impl Pallet { // Set last transaction block let current_block = Self::get_current_block_as_u64(); - Self::set_last_transaction_block_on_subnet( + TransactionType::SetChildkeyTake.set_last_block_on_subnet::( &hotkey, netuid, - &TransactionType::SetChildkeyTake, current_block, ); @@ -341,10 +333,9 @@ impl Pallet { ChildkeyTake::::insert(hotkey.clone(), netuid, take); // Update the last transaction block - Self::set_last_transaction_block_on_subnet( + TransactionType::SetChildkeyTake.set_last_block_on_subnet::( &hotkey, netuid, - &TransactionType::SetChildkeyTake, current_block, ); diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index 38be89cba0..6241c54ef7 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -135,7 +135,7 @@ impl Pallet { // --- 4. Rate limit for network registrations. let current_block = Self::get_current_block_as_u64(); ensure!( - Self::passes_rate_limit(&TransactionType::RegisterNetwork, &coldkey), + TransactionType::RegisterNetwork.passes_rate_limit::(&coldkey), Error::::NetworkTxRateLimitExceeded ); @@ -391,8 +391,7 @@ impl Pallet { // Rate limit: 1 call per week ensure!( - Self::passes_rate_limit_on_subnet( - &TransactionType::SetSNOwnerHotkey, + TransactionType::SetSNOwnerHotkey.passes_rate_limit_on_subnet::( hotkey, // ignored netuid, // Specific to a subnet. ), @@ -401,10 +400,9 @@ impl Pallet { // Set last transaction block let current_block = Self::get_current_block_as_u64(); - Self::set_last_transaction_block_on_subnet( + TransactionType::SetSNOwnerHotkey.set_last_block_on_subnet::( hotkey, netuid, - &TransactionType::SetSNOwnerHotkey, current_block, ); diff --git a/pallets/subtensor/src/tests/children.rs b/pallets/subtensor/src/tests/children.rs index 1208add954..67dfe47fbe 100644 --- a/pallets/subtensor/src/tests/children.rs +++ b/pallets/subtensor/src/tests/children.rs @@ -955,17 +955,15 @@ fn test_childkey_take_rate_limiting() { // Helper function to log rate limit information let log_rate_limit_info = || { let current_block = SubtensorModule::get_current_block_as_u64(); - let last_block = SubtensorModule::get_last_transaction_block_on_subnet( + let last_block = TransactionType::SetChildkeyTake.last_block_on_subnet::( &hotkey, netuid, - &TransactionType::SetChildkeyTake, ); - let passes = SubtensorModule::passes_rate_limit_on_subnet( - &TransactionType::SetChildkeyTake, + let passes = TransactionType::SetChildkeyTake.passes_rate_limit_on_subnet::( &hotkey, netuid, ); - let limit = SubtensorModule::get_rate_limit_on_subnet(&TransactionType::SetChildkeyTake, netuid); + let limit = TransactionType::SetChildkeyTake.rate_limit_on_subnet::(netuid); log::info!( "Rate limit info: current_block: {}, last_block: {}, limit: {}, passes: {}, diff: {}", current_block, @@ -2489,12 +2487,7 @@ fn test_revoke_child_no_min_stake_check() { assert_eq!(children_after, vec![(proportion, child)]); // Bypass tx rate limit - SubtensorModule::set_last_transaction_block_on_subnet( - &parent, - netuid, - &TransactionType::SetChildren, - 0, - ); + TransactionType::SetChildren.set_last_block_on_subnet::(&parent, netuid, 0); // Schedule parent-child relationship revokation assert_ok!(SubtensorModule::do_schedule_children( @@ -2609,18 +2602,13 @@ fn test_set_children_rate_limit_fail_then_succeed() { // Try again after rate limit period has passed // Check rate limit - let limit = - SubtensorModule::get_rate_limit_on_subnet(&TransactionType::SetChildren, netuid); + let limit = TransactionType::SetChildren.rate_limit_on_subnet::(netuid); // Step that many blocks step_block(limit as u16); // Verify rate limit passes - assert!(SubtensorModule::passes_rate_limit_on_subnet( - &TransactionType::SetChildren, - &hotkey, - netuid - )); + assert!(TransactionType::SetChildren.passes_rate_limit_on_subnet::(&hotkey, netuid)); // Try again mock_set_children(&coldkey, &hotkey, netuid, &[(100, child2)]); diff --git a/pallets/subtensor/src/tests/ensure.rs b/pallets/subtensor/src/tests/ensure.rs index a8b3843fa3..298339defa 100644 --- a/pallets/subtensor/src/tests/ensure.rs +++ b/pallets/subtensor/src/tests/ensure.rs @@ -4,8 +4,8 @@ use sp_core::U256; use subtensor_runtime_common::NetUid; use super::mock::*; -use crate::utils::rate_limiting::TransactionType; -use crate::{RateLimitKey, SubnetOwner, SubtokenEnabled}; +use crate::utils::rate_limiting::{Hyperparameter, TransactionType}; +use crate::{OwnerHyperparamRateLimit, SubnetOwner, SubtokenEnabled}; #[test] fn ensure_subnet_owner_returns_who_and_checks_ownership() { @@ -94,33 +94,32 @@ fn ensure_owner_or_root_with_limits_checks_rl_and_freeze() { SubtokenEnabled::::insert(netuid, true); let owner: U256 = U256::from(5); SubnetOwner::::insert(netuid, owner); - // Set freeze window to 3 - let freeze_window = 3; - crate::Pallet::::set_admin_freeze_window(freeze_window); + // Set freeze window to 0 initially to avoid blocking when tempo is small + crate::Pallet::::set_admin_freeze_window(0); + + // Set tempo to 1 so owner hyperparam RL = 2 blocks + crate::Pallet::::set_tempo(netuid, 1); - // Set owner RL to 2 blocks - crate::Pallet::::set_owner_hyperparam_rate_limit(2); + assert_eq!(OwnerHyperparamRateLimit::::get(), 2); // Outside freeze window initially; should pass and return Some(owner) let res = crate::Pallet::::ensure_sn_owner_or_root_with_limits( <::RuntimeOrigin>::signed(owner), netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::Kappa.into()], ) .expect("should pass"); assert_eq!(res, Some(owner)); // Simulate previous update at current block -> next call should fail due to rate limit let now = crate::Pallet::::get_current_block_as_u64(); - crate::Pallet::::set_rate_limited_last_block( - &RateLimitKey::OwnerHyperparamUpdate(netuid), - now, - ); + TransactionType::from(Hyperparameter::Kappa) + .set_last_block_on_subnet::(&owner, netuid, now); assert_noop!( crate::Pallet::::ensure_sn_owner_or_root_with_limits( <::RuntimeOrigin>::signed(owner), netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::Kappa.into()], ), crate::Error::::TxRateLimitExceeded ); @@ -130,11 +129,15 @@ fn ensure_owner_or_root_with_limits_checks_rl_and_freeze() { assert_ok!(crate::Pallet::::ensure_sn_owner_or_root_with_limits( <::RuntimeOrigin>::signed(owner), netuid, - &[TransactionType::OwnerHyperparamUpdate] + &[Hyperparameter::Kappa.into()] )); // Now advance into the freeze window; ensure blocks // (using loop for clarity, because epoch calculation function uses netuid) + // Restore tempo and configure freeze window for this part + let freeze_window = 3; + crate::Pallet::::set_tempo(netuid, tempo); + crate::Pallet::::set_admin_freeze_window(freeze_window); let freeze_window = freeze_window as u64; loop { let cur = crate::Pallet::::get_current_block_as_u64(); @@ -148,7 +151,7 @@ fn ensure_owner_or_root_with_limits_checks_rl_and_freeze() { crate::Pallet::::ensure_sn_owner_or_root_with_limits( <::RuntimeOrigin>::signed(owner), netuid, - &[TransactionType::OwnerHyperparamUpdate], + &[Hyperparameter::Kappa.into()], ), crate::Error::::AdminActionProhibitedDuringWeightsWindow ); diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 28da96687a..672b1e44dd 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -948,7 +948,7 @@ pub fn mock_set_children_no_epochs(netuid: NetUid, parent: &U256, child_vec: &[( #[allow(dead_code)] pub fn step_rate_limit(transaction_type: &TransactionType, netuid: NetUid) { // Check rate limit - let limit = SubtensorModule::get_rate_limit_on_subnet(transaction_type, netuid); + let limit = transaction_type.rate_limit_on_subnet::(netuid); // Step that many blocks step_block(limit as u16); diff --git a/pallets/subtensor/src/transaction_extension.rs b/pallets/subtensor/src/transaction_extension.rs index 62c6a3c8ca..b56dff0ea0 100644 --- a/pallets/subtensor/src/transaction_extension.rs +++ b/pallets/subtensor/src/transaction_extension.rs @@ -279,7 +279,7 @@ where .map(|validity| (validity, Some(who.clone()), origin.clone())) } Some(Call::register_network { .. }) => { - if !Pallet::::passes_rate_limit(&TransactionType::RegisterNetwork, who) { + if !TransactionType::RegisterNetwork.passes_rate_limit::(who) { return Err(CustomTransactionError::RateLimitExceeded.into()); } diff --git a/pallets/subtensor/src/utils/misc.rs b/pallets/subtensor/src/utils/misc.rs index 8703b1774b..ef04a8ada8 100644 --- a/pallets/subtensor/src/utils/misc.rs +++ b/pallets/subtensor/src/utils/misc.rs @@ -62,7 +62,7 @@ impl Pallet { if let Some(who) = maybe_who.as_ref() { for tx in limits.iter() { ensure!( - Self::passes_rate_limit_on_subnet(tx, who, netuid), + tx.passes_rate_limit_on_subnet::(who, netuid), Error::::TxRateLimitExceeded ); } @@ -83,7 +83,7 @@ impl Pallet { Self::ensure_not_in_admin_freeze_window(netuid, now)?; for tx in limits.iter() { ensure!( - Self::passes_rate_limit_on_subnet(tx, &who, netuid), + tx.passes_rate_limit_on_subnet::(&who, netuid), Error::::TxRateLimitExceeded ); } @@ -116,9 +116,9 @@ impl Pallet { Self::deposit_event(Event::AdminFreezeWindowSet(window)); } - pub fn set_owner_hyperparam_rate_limit(limit: u64) { - OwnerHyperparamRateLimit::::set(limit); - Self::deposit_event(Event::OwnerHyperparamRateLimitSet(limit)); + pub fn set_owner_hyperparam_rate_limit(epochs: u16) { + OwnerHyperparamRateLimit::::set(epochs); + Self::deposit_event(Event::OwnerHyperparamRateLimitSet(epochs)); } /// If owner is `Some`, record last-blocks for the provided `TransactionType`s. @@ -130,7 +130,7 @@ impl Pallet { if let Some(who) = maybe_owner { let now = Self::get_current_block_as_u64(); for tx in txs { - Self::set_last_transaction_block_on_subnet(&who, netuid, tx, now); + tx.set_last_block_on_subnet::(&who, netuid, now); } } } diff --git a/pallets/subtensor/src/utils/rate_limiting.rs b/pallets/subtensor/src/utils/rate_limiting.rs index a1f7e6aac6..58fcab01d0 100644 --- a/pallets/subtensor/src/utils/rate_limiting.rs +++ b/pallets/subtensor/src/utils/rate_limiting.rs @@ -4,6 +4,7 @@ use super::*; /// Enum representing different types of transactions #[derive(Copy, Clone)] +#[non_exhaustive] pub enum TransactionType { SetChildren, SetChildkeyTake, @@ -11,151 +12,193 @@ pub enum TransactionType { RegisterNetwork, SetWeightsVersionKey, SetSNOwnerHotkey, - OwnerHyperparamUpdate, + OwnerHyperparamUpdate(Hyperparameter), SubsubnetCountUpdate, SubsubnetEmission, } -/// Implement conversion from TransactionType to u16 -impl From for u16 { - fn from(tx_type: TransactionType) -> Self { - match tx_type { - TransactionType::SetChildren => 0, - TransactionType::SetChildkeyTake => 1, - TransactionType::Unknown => 2, - TransactionType::RegisterNetwork => 3, - TransactionType::SetWeightsVersionKey => 4, - TransactionType::SetSNOwnerHotkey => 5, - TransactionType::OwnerHyperparamUpdate => 6, - TransactionType::SubsubnetCountUpdate => 7, - TransactionType::SubsubnetEmission => 8, - } - } -} - -/// Implement conversion from u16 to TransactionType -impl From for TransactionType { - fn from(value: u16) -> Self { - match value { - 0 => TransactionType::SetChildren, - 1 => TransactionType::SetChildkeyTake, - 3 => TransactionType::RegisterNetwork, - 4 => TransactionType::SetWeightsVersionKey, - 5 => TransactionType::SetSNOwnerHotkey, - 6 => TransactionType::OwnerHyperparamUpdate, - 7 => TransactionType::SubsubnetCountUpdate, - 8 => TransactionType::SubsubnetEmission, - _ => TransactionType::Unknown, - } - } -} -impl Pallet { - // ======================== - // ==== Rate Limiting ===== - // ======================== +impl TransactionType { /// Get the rate limit for a specific transaction type - pub fn get_rate_limit(tx_type: &TransactionType) -> u64 { - match tx_type { - TransactionType::SetChildren => 150, // 30 minutes - TransactionType::SetChildkeyTake => TxChildkeyTakeRateLimit::::get(), - TransactionType::RegisterNetwork => NetworkRateLimit::::get(), - TransactionType::OwnerHyperparamUpdate => OwnerHyperparamRateLimit::::get(), - TransactionType::SubsubnetCountUpdate => SubsubnetCountSetRateLimit::::get(), - TransactionType::SubsubnetEmission => SubsubnetEmissionRateLimit::::get(), - - TransactionType::Unknown => 0, // Default to no limit for unknown types (no limit) + pub fn rate_limit(&self) -> u64 { + match self { + Self::SetChildren => 150, // 30 minutes + Self::SetChildkeyTake => TxChildkeyTakeRateLimit::::get(), + Self::RegisterNetwork => NetworkRateLimit::::get(), + Self::SubsubnetCountUpdate => SubsubnetCountSetRateLimit::::get(), + Self::SubsubnetEmission => SubsubnetEmissionRateLimit::::get(), + + Self::Unknown => 0, // Default to no limit for unknown types (no limit) _ => 0, } } - pub fn get_rate_limit_on_subnet(tx_type: &TransactionType, netuid: NetUid) -> u64 { + pub fn rate_limit_on_subnet(&self, netuid: NetUid) -> u64 { #[allow(clippy::match_single_binding)] - match tx_type { - TransactionType::SetWeightsVersionKey => (Tempo::::get(netuid) as u64) + match self { + Self::SetWeightsVersionKey => (Tempo::::get(netuid) as u64) .saturating_mul(WeightsVersionKeyRateLimit::::get()), - TransactionType::SetSNOwnerHotkey => DefaultSetSNOwnerHotkeyRateLimit::::get(), + // Owner hyperparameter updates are rate-limited by N tempos on the subnet (sudo configurable) + Self::OwnerHyperparamUpdate(_) => { + let epochs = OwnerHyperparamRateLimit::::get() as u64; + (Tempo::::get(netuid) as u64).saturating_mul(epochs) + } + Self::SetSNOwnerHotkey => DefaultSetSNOwnerHotkeyRateLimit::::get(), - _ => Self::get_rate_limit(tx_type), + _ => self.rate_limit::(), } } + pub fn passes_rate_limit(&self, key: &T::AccountId) -> bool { + let block = Pallet::::get_current_block_as_u64(); + let limit = self.rate_limit::(); + let last_block = self.last_block::(key); + + Self::check_passes_rate_limit(limit, block, last_block) + } + pub fn check_passes_rate_limit(limit: u64, block: u64, last_block: u64) -> bool { // Allow the first transaction (when last_block is 0) or if the rate limit has passed last_block == 0 || block.saturating_sub(last_block) >= limit } - pub fn passes_rate_limit(tx_type: &TransactionType, key: &T::AccountId) -> bool { - let block: u64 = Self::get_current_block_as_u64(); - let limit: u64 = Self::get_rate_limit(tx_type); - let last_block: u64 = Self::get_last_transaction_block(key, tx_type); - - Self::check_passes_rate_limit(limit, block, last_block) - } - /// Check if a transaction should be rate limited on a specific subnet - pub fn passes_rate_limit_on_subnet( - tx_type: &TransactionType, + pub fn passes_rate_limit_on_subnet( + &self, hotkey: &T::AccountId, netuid: NetUid, ) -> bool { - let block: u64 = Self::get_current_block_as_u64(); - let limit: u64 = Self::get_rate_limit_on_subnet(tx_type, netuid); - let last_block: u64 = Self::get_last_transaction_block_on_subnet(hotkey, netuid, tx_type); + let block = Pallet::::get_current_block_as_u64(); + let limit = self.rate_limit_on_subnet::(netuid); + let last_block = self.last_block_on_subnet::(hotkey, netuid); Self::check_passes_rate_limit(limit, block, last_block) } /// Get the block number of the last transaction for a specific key, and transaction type - pub fn get_last_transaction_block(key: &T::AccountId, tx_type: &TransactionType) -> u64 { - match tx_type { - TransactionType::RegisterNetwork => Self::get_network_last_lock_block(), - _ => Self::get_last_transaction_block_on_subnet(key, NetUid::ROOT, tx_type), + pub fn last_block(&self, key: &T::AccountId) -> u64 { + match self { + Self::RegisterNetwork => Pallet::::get_network_last_lock_block(), + _ => self.last_block_on_subnet::(key, NetUid::ROOT), } } - /// Get the block number of the last transaction for a specific hotkey, network, and transaction type - pub fn get_last_transaction_block_on_subnet( - hotkey: &T::AccountId, - netuid: NetUid, - tx_type: &TransactionType, - ) -> u64 { - match tx_type { - TransactionType::RegisterNetwork => Self::get_network_last_lock_block(), - TransactionType::SetSNOwnerHotkey => { - Self::get_rate_limited_last_block(&RateLimitKey::SetSNOwnerHotkey(netuid)) - } - TransactionType::OwnerHyperparamUpdate => { - Self::get_rate_limited_last_block(&RateLimitKey::OwnerHyperparamUpdate(netuid)) + /// Get the block number of the last transaction for a specific hotkey, network, and transaction + /// type + pub fn last_block_on_subnet(&self, hotkey: &T::AccountId, netuid: NetUid) -> u64 { + match self { + Self::RegisterNetwork => Pallet::::get_network_last_lock_block(), + Self::SetSNOwnerHotkey => { + Pallet::::get_rate_limited_last_block(&RateLimitKey::SetSNOwnerHotkey(netuid)) } + Self::OwnerHyperparamUpdate(hparam) => Pallet::::get_rate_limited_last_block( + &RateLimitKey::OwnerHyperparamUpdate(netuid, *hparam), + ), _ => { - let tx_as_u16: u16 = (*tx_type).into(); - TransactionKeyLastBlock::::get((hotkey, netuid, tx_as_u16)) + let tx_type: u16 = (*self).into(); + TransactionKeyLastBlock::::get((hotkey, netuid, tx_type)) } } } - /// Set the block number of the last transaction for a specific hotkey, network, and transaction type - pub fn set_last_transaction_block_on_subnet( + /// Set the block number of the last transaction for a specific hotkey, network, and transaction + /// type + pub fn set_last_block_on_subnet( + &self, key: &T::AccountId, netuid: NetUid, - tx_type: &TransactionType, block: u64, ) { - match tx_type { - TransactionType::RegisterNetwork => Self::set_network_last_lock_block(block), - TransactionType::SetSNOwnerHotkey => { - Self::set_rate_limited_last_block(&RateLimitKey::SetSNOwnerHotkey(netuid), block) - } - TransactionType::OwnerHyperparamUpdate => Self::set_rate_limited_last_block( - &RateLimitKey::OwnerHyperparamUpdate(netuid), + match self { + Self::RegisterNetwork => Pallet::::set_network_last_lock_block(block), + Self::SetSNOwnerHotkey => Pallet::::set_rate_limited_last_block( + &RateLimitKey::SetSNOwnerHotkey(netuid), + block, + ), + Self::OwnerHyperparamUpdate(hparam) => Pallet::::set_rate_limited_last_block( + &RateLimitKey::OwnerHyperparamUpdate(netuid, *hparam), block, ), _ => { - let tx_as_u16: u16 = (*tx_type).into(); - TransactionKeyLastBlock::::insert((key, netuid, tx_as_u16), block); + let tx_type: u16 = (*self).into(); + TransactionKeyLastBlock::::insert((key, netuid, tx_type), block); } } } +} + +/// Implement conversion from TransactionType to u16 +impl From for u16 { + fn from(tx_type: TransactionType) -> Self { + match tx_type { + TransactionType::SetChildren => 0, + TransactionType::SetChildkeyTake => 1, + TransactionType::Unknown => 2, + TransactionType::RegisterNetwork => 3, + TransactionType::SetWeightsVersionKey => 4, + TransactionType::SetSNOwnerHotkey => 5, + TransactionType::OwnerHyperparamUpdate(_) => 6, + TransactionType::SubsubnetCountUpdate => 7, + TransactionType::SubsubnetEmission => 8, + } + } +} + +/// Implement conversion from u16 to TransactionType +impl From for TransactionType { + fn from(value: u16) -> Self { + match value { + 0 => TransactionType::SetChildren, + 1 => TransactionType::SetChildkeyTake, + 3 => TransactionType::RegisterNetwork, + 4 => TransactionType::SetWeightsVersionKey, + 5 => TransactionType::SetSNOwnerHotkey, + 6 => TransactionType::OwnerHyperparamUpdate(Hyperparameter::Unknown), + 7 => TransactionType::SubsubnetCountUpdate, + 8 => TransactionType::SubsubnetEmission, + _ => TransactionType::Unknown, + } + } +} + +impl From for TransactionType { + fn from(param: Hyperparameter) -> Self { + Self::OwnerHyperparamUpdate(param) + } +} + +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, Debug, TypeInfo)] +#[non_exhaustive] +pub enum Hyperparameter { + Unknown = 0, + ServingRateLimit = 1, + MaxDifficulty = 2, + AdjustmentAlpha = 3, + MaxWeightLimit = 4, + ImmunityPeriod = 5, + MinAllowedWeights = 6, + Kappa = 7, + Rho = 8, + ActivityCutoff = 9, + PowRegistrationAllowed = 10, + MinBurn = 11, + MaxBurn = 12, + BondsMovingAverage = 13, + BondsPenalty = 14, + CommitRevealEnabled = 15, + LiquidAlphaEnabled = 16, + AlphaValues = 17, + WeightCommitInterval = 18, + TransferEnabled = 19, + AlphaSigmoidSteepness = 20, + Yuma3Enabled = 21, + BondsResetEnabled = 22, + ImmuneNeuronLimit = 23, +} + +impl Pallet { + // ======================== + // ==== Rate Limiting ===== + // ======================== pub fn remove_last_tx_block(key: &T::AccountId) { Self::remove_rate_limited_last_block(&RateLimitKey::LastTxBlock(key.clone())) diff --git a/scripts/localnet_patch.sh b/scripts/localnet_patch.sh index f5a84e8348..e3bee8c5b8 100755 --- a/scripts/localnet_patch.sh +++ b/scripts/localnet_patch.sh @@ -19,7 +19,7 @@ if ! grep -q 'pub fn DefaultPendingCooldown() -> u64 {' "$DefaultPend exit 1 fi -if ! grep -q 'TransactionType::SetChildren => 150, // 30 minutes' "$SetChildren"; then +if ! grep -q 'Self::SetChildren => 150, // 30 minutes' "$SetChildren"; then echo "Error: Target string not found in $SetChildren" exit 1 fi @@ -27,6 +27,6 @@ fi # replace perl -0777 -i -pe 's|pub const DurationOfStartCall: u64 = prod_or_fast!\(7 \* 24 \* 60 \* 60 / 12, 10\);|pub const DurationOfStartCall: u64 = prod_or_fast!(5, 10);|' "$DurationOfStartCall" perl -0777 -i -pe 's|pub fn DefaultPendingCooldown\(\) -> u64 \{\s*prod_or_fast!\(7_200, 15\)\s*\}|pub fn DefaultPendingCooldown() -> u64 {\n prod_or_fast!(15, 15)\n }|g' "$DefaultPendingCooldown" -perl -0777 -i -pe 's|TransactionType::SetChildren => 150, // 30 minutes|TransactionType::SetChildren => 15, // 3 min|' "$SetChildren" +perl -0777 -i -pe 's|Self::SetChildren => 150, // 30 minutes|Self::SetChildren => 15, // 3 min|' "$SetChildren" echo "Patch applied successfully."