diff --git a/chain-extensions/src/mock.rs b/chain-extensions/src/mock.rs index 98ea096199..660aa0c77c 100644 --- a/chain-extensions/src/mock.rs +++ b/chain-extensions/src/mock.rs @@ -331,7 +331,7 @@ parameter_types! { pub const InitialDissolveNetworkScheduleDuration: u64 = 5 * 24 * 60 * 60 / 12; // Default as 5 days pub const InitialTaoWeight: u64 = 0; // 100% global weight. pub const InitialEmaPriceHalvingPeriod: u64 = 201_600_u64; // 4 weeks - pub const DurationOfStartCall: u64 = 7 * 24 * 60 * 60 / 12; // Default as 7 days + pub const InitialStartCallDelay: u64 = 7 * 24 * 60 * 60 / 12; // Default as 7 days pub const InitialKeySwapOnSubnetCost: u64 = 10_000_000; pub const HotkeySwapOnSubnetInterval: u64 = 15; // 15 block, should be bigger than subnet number, then trigger clean up for all subnets pub const MaxContributorsPerLeaseToRemove: u32 = 3; @@ -402,7 +402,7 @@ impl pallet_subtensor::Config for Test { type InitialDissolveNetworkScheduleDuration = InitialDissolveNetworkScheduleDuration; type InitialTaoWeight = InitialTaoWeight; type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod; - type DurationOfStartCall = DurationOfStartCall; + type InitialStartCallDelay = InitialStartCallDelay; type SwapInterface = pallet_subtensor_swap::Pallet; type KeySwapOnSubnetCost = InitialKeySwapOnSubnetCost; type HotkeySwapOnSubnetInterval = HotkeySwapOnSubnetInterval; diff --git a/contract-tests/src/subtensor.ts b/contract-tests/src/subtensor.ts index 12d652a9a3..fab9e8cc10 100644 --- a/contract-tests/src/subtensor.ts +++ b/contract-tests/src/subtensor.ts @@ -296,7 +296,7 @@ export async function setSubtokenEnable(api: TypedApi, netuid: nu export async function startCall(api: TypedApi, netuid: number, keypair: KeyPair) { const registerBlock = Number(await api.query.SubtensorModule.NetworkRegisteredAt.getValue(netuid)) let currentBlock = await api.query.System.Number.getValue() - const duration = Number(await api.constants.SubtensorModule.DurationOfStartCall) + const duration = Number(await api.constants.SubtensorModule.InitialStartCallDelay) while (currentBlock - registerBlock <= duration) { await new Promise((resolve) => setTimeout(resolve, 2000)); diff --git a/node/src/chain_spec/localnet.rs b/node/src/chain_spec/localnet.rs index 02ea8896b5..b20372e4b9 100644 --- a/node/src/chain_spec/localnet.rs +++ b/node/src/chain_spec/localnet.rs @@ -124,5 +124,8 @@ fn localnet_genesis( "evmChainId": { "chainId": 42, }, + "subtensorModule": { + "startCallDelay": 10, + }, }) } diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index c3999312b3..c910fe8ad1 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -2240,6 +2240,21 @@ pub mod pallet { pallet_subtensor::Pallet::::set_min_non_immune_uids(netuid, min); Ok(()) } + + /// Sets the delay before a subnet can call start + #[pallet::call_index(85)] + #[pallet::weight(( + Weight::from_parts(14_000_000, 0) + .saturating_add(::DbWeight::get().writes(1)), + DispatchClass::Operational, + Pays::Yes + ))] + pub fn sudo_set_start_call_delay(origin: OriginFor, delay: u64) -> DispatchResult { + ensure_root(origin)?; + pallet_subtensor::Pallet::::set_start_call_delay(delay); + log::debug!("StartCallDelay( delay: {delay:?} ) "); + Ok(()) + } } } diff --git a/pallets/admin-utils/src/tests/mock.rs b/pallets/admin-utils/src/tests/mock.rs index 0140808baa..e1ab02d911 100644 --- a/pallets/admin-utils/src/tests/mock.rs +++ b/pallets/admin-utils/src/tests/mock.rs @@ -145,7 +145,7 @@ parameter_types! { pub const InitialDissolveNetworkScheduleDuration: u64 = 5 * 24 * 60 * 60 / 12; // 5 days pub const InitialTaoWeight: u64 = u64::MAX/10; // 10% global weight. pub const InitialEmaPriceHalvingPeriod: u64 = 201_600_u64; // 4 weeks - pub const DurationOfStartCall: u64 = 7 * 24 * 60 * 60 / 12; // 7 days + pub const InitialStartCallDelay: u64 = 7 * 24 * 60 * 60 / 12; // 7 days pub const InitialKeySwapOnSubnetCost: u64 = 10_000_000; pub const HotkeySwapOnSubnetInterval: u64 = 7 * 24 * 60 * 60 / 12; // 7 days pub const LeaseDividendsDistributionInterval: u32 = 100; // 100 blocks @@ -215,7 +215,7 @@ impl pallet_subtensor::Config for Test { type InitialDissolveNetworkScheduleDuration = InitialDissolveNetworkScheduleDuration; type InitialTaoWeight = InitialTaoWeight; type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod; - type DurationOfStartCall = DurationOfStartCall; + type InitialStartCallDelay = InitialStartCallDelay; type SwapInterface = Swap; type KeySwapOnSubnetCost = InitialKeySwapOnSubnetCost; type HotkeySwapOnSubnetInterval = HotkeySwapOnSubnetInterval; diff --git a/pallets/admin-utils/src/tests/mod.rs b/pallets/admin-utils/src/tests/mod.rs index 024871e60f..970c24498e 100644 --- a/pallets/admin-utils/src/tests/mod.rs +++ b/pallets/admin-utils/src/tests/mod.rs @@ -2887,3 +2887,101 @@ fn test_sudo_set_min_non_immune_uids() { assert_eq!(SubtensorModule::get_min_non_immune_uids(netuid), to_be_set); }); } + +#[test] +fn test_sudo_set_start_call_delay_permissions_and_zero_delay() { + new_test_ext().execute_with(|| { + let netuid = NetUid::from(1); + let tempo: u16 = 13; + let coldkey_account_id = U256::from(0); + let non_root_account = U256::from(1); + + // Get initial delay value (should be non-zero) + let initial_delay = pallet_subtensor::StartCallDelay::::get(); + assert!( + initial_delay > 0, + "Initial delay should be greater than zero" + ); + + // Test 1: Non-root account should fail to set delay + assert_err!( + AdminUtils::sudo_set_start_call_delay( + <::RuntimeOrigin>::signed(non_root_account), + 0 + ), + DispatchError::BadOrigin + ); + assert_eq!( + pallet_subtensor::StartCallDelay::::get(), + initial_delay, + "Delay should not have changed" + ); + + // Test 2: Create a subnet + add_network(netuid, tempo); + assert_eq!( + pallet_subtensor::FirstEmissionBlockNumber::::get(netuid), + None, + "Emission block should not be set yet" + ); + assert_eq!( + pallet_subtensor::SubnetOwner::::get(netuid), + coldkey_account_id, + "Default owner should be account 0" + ); + + // Test 3: Try to start the subnet immediately - should FAIL (delay not passed) + assert_err!( + pallet_subtensor::Pallet::::start_call( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid + ), + pallet_subtensor::Error::::NeedWaitingMoreBlocksToStarCall + ); + + // Verify emission has not been set + assert_eq!( + pallet_subtensor::FirstEmissionBlockNumber::::get(netuid), + None, + "Emission should not be set yet" + ); + + // Test 4: Root sets delay to zero + assert_ok!(AdminUtils::sudo_set_start_call_delay( + <::RuntimeOrigin>::root(), + 0 + )); + assert_eq!( + pallet_subtensor::StartCallDelay::::get(), + 0, + "Delay should now be zero" + ); + + // Verify event was emitted + frame_system::Pallet::::assert_last_event(RuntimeEvent::SubtensorModule( + pallet_subtensor::Event::StartCallDelaySet(0), + )); + + // Test 5: Try to start the subnet again - should SUCCEED (delay is now zero) + let current_block = frame_system::Pallet::::block_number(); + assert_ok!(pallet_subtensor::Pallet::::start_call( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid + )); + + assert_eq!( + pallet_subtensor::FirstEmissionBlockNumber::::get(netuid), + Some(current_block + 1), + "Emission should start at next block" + ); + + // Test 6: Try to start it a third time - should FAIL (already started) + assert_err!( + pallet_subtensor::Pallet::::start_call( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid + ), + pallet_subtensor::Error::::FirstEmissionBlockNumberAlreadySet + ); + }); +} diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 476be905e9..f61c35aede 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -648,7 +648,7 @@ mod pallet_benchmarks { assert_eq!(FirstEmissionBlockNumber::::get(netuid), None); let current_block: u64 = Subtensor::::get_current_block_as_u64(); - let duration = ::DurationOfStartCall::get(); + let duration = StartCallDelay::::get(); let block: BlockNumberFor = (current_block + duration) .try_into() .ok() diff --git a/pallets/subtensor/src/coinbase/root.rs b/pallets/subtensor/src/coinbase/root.rs index 328ce3805c..a5c7296424 100644 --- a/pallets/subtensor/src/coinbase/root.rs +++ b/pallets/subtensor/src/coinbase/root.rs @@ -542,6 +542,13 @@ impl Pallet { NetworkImmunityPeriod::::set(net_immunity_period); Self::deposit_event(Event::NetworkImmunityPeriodSet(net_immunity_period)); } + pub fn get_start_call_delay() -> u64 { + StartCallDelay::::get() + } + pub fn set_start_call_delay(delay: u64) { + StartCallDelay::::set(delay); + Self::deposit_event(Event::StartCallDelaySet(delay)); + } pub fn set_network_min_lock(net_min_lock: TaoCurrency) { NetworkMinLockCost::::set(net_min_lock); Self::deposit_event(Event::NetworkMinLockCostSet(net_min_lock)); diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index ef2d44e68b..b08d8d8b0b 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -640,6 +640,12 @@ pub mod pallet { T::InitialSubnetOwnerCut::get() } + /// Default value for start call delay. + #[pallet::type_value] + pub fn DefaultStartCallDelay() -> u64 { + T::InitialStartCallDelay::get() + } + /// Default value for recycle or burn. #[pallet::type_value] pub fn DefaultRecycleOrBurn() -> RecycleOrBurnEnum { @@ -1514,6 +1520,10 @@ pub mod pallet { pub type NetworkImmunityPeriod = StorageValue<_, u64, ValueQuery, DefaultNetworkImmunityPeriod>; + /// ITEM( start_call_delay ) + #[pallet::storage] + pub type StartCallDelay = StorageValue<_, u64, ValueQuery, DefaultStartCallDelay>; + /// ITEM( min_network_lock_cost ) #[pallet::storage] pub type NetworkMinLockCost = diff --git a/pallets/subtensor/src/macros/config.rs b/pallets/subtensor/src/macros/config.rs index a735bde1e1..ce6dfd57c2 100644 --- a/pallets/subtensor/src/macros/config.rs +++ b/pallets/subtensor/src/macros/config.rs @@ -233,9 +233,9 @@ mod config { /// Initial EMA price halving period #[pallet::constant] type InitialEmaPriceHalvingPeriod: Get; - /// Block number after a new subnet accept the start call extrinsic. + /// Initial block number after a new subnet accept the start call extrinsic. #[pallet::constant] - type DurationOfStartCall: Get; + type InitialStartCallDelay: Get; /// Cost of swapping a hotkey in a subnet. #[pallet::constant] type KeySwapOnSubnetCost: Get; diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index a06e035d86..c86cc1a1e5 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -147,6 +147,8 @@ mod events { NetworkRateLimitSet(u64), /// the network immunity period is set. NetworkImmunityPeriodSet(u64), + /// the start call delay is set. + StartCallDelaySet(u64), /// the network minimum locking cost is set. NetworkMinLockCostSet(TaoCurrency), /// the maximum number of subnets is set diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index 4185aee624..0de55e61bd 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -358,7 +358,7 @@ impl Pallet { ensure!( current_block_number - >= registration_block_number.saturating_add(T::DurationOfStartCall::get()), + >= registration_block_number.saturating_add(StartCallDelay::::get()), Error::::NeedWaitingMoreBlocksToStarCall ); let next_block_number = current_block_number.saturating_add(1); diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index f6c92c8079..a79f4b713a 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -2701,7 +2701,7 @@ fn test_run_coinbase_not_started_start_after() { // We expect that the epoch ran. assert_eq!(BlocksSinceLastStep::::get(netuid), 0); - let block_number = DurationOfStartCall::get(); + let block_number = StartCallDelay::::get(); run_to_block_no_epoch(netuid, block_number); let current_block = System::block_number(); diff --git a/pallets/subtensor/src/tests/mock.rs b/pallets/subtensor/src/tests/mock.rs index 090fcf8f75..c33be9068c 100644 --- a/pallets/subtensor/src/tests/mock.rs +++ b/pallets/subtensor/src/tests/mock.rs @@ -218,7 +218,7 @@ parameter_types! { pub const InitialDissolveNetworkScheduleDuration: u64 = 5 * 24 * 60 * 60 / 12; // Default as 5 days pub const InitialTaoWeight: u64 = 0; // 100% global weight. pub const InitialEmaPriceHalvingPeriod: u64 = 201_600_u64; // 4 weeks - pub const DurationOfStartCall: u64 = 7 * 24 * 60 * 60 / 12; // Default as 7 days + pub const InitialStartCallDelay: u64 = 7 * 24 * 60 * 60 / 12; // Default as 7 days pub const InitialKeySwapOnSubnetCost: u64 = 10_000_000; pub const HotkeySwapOnSubnetInterval: u64 = 15; // 15 block, should be bigger than subnet number, then trigger clean up for all subnets pub const MaxContributorsPerLeaseToRemove: u32 = 3; @@ -289,7 +289,7 @@ impl crate::Config for Test { type InitialDissolveNetworkScheduleDuration = InitialDissolveNetworkScheduleDuration; type InitialTaoWeight = InitialTaoWeight; type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod; - type DurationOfStartCall = DurationOfStartCall; + type InitialStartCallDelay = InitialStartCallDelay; type SwapInterface = pallet_subtensor_swap::Pallet; type KeySwapOnSubnetCost = InitialKeySwapOnSubnetCost; type HotkeySwapOnSubnetInterval = HotkeySwapOnSubnetInterval; diff --git a/pallets/subtensor/src/tests/subnet.rs b/pallets/subtensor/src/tests/subnet.rs index d2a73a919d..456c33ce65 100644 --- a/pallets/subtensor/src/tests/subnet.rs +++ b/pallets/subtensor/src/tests/subnet.rs @@ -27,7 +27,7 @@ fn test_do_start_call_ok() { // account 0 is the default owner for any subnet assert_eq!(SubnetOwner::::get(netuid), coldkey_account_id); - let block_number = System::block_number() + DurationOfStartCall::get(); + let block_number = System::block_number() + StartCallDelay::::get(); System::set_block_number(block_number); assert_ok!(SubtensorModule::start_call( @@ -76,7 +76,7 @@ fn test_do_start_call_fail_not_owner() { assert_eq!(SubnetOwner::::get(netuid), coldkey_account_id); - System::set_block_number(System::block_number() + DurationOfStartCall::get()); + System::set_block_number(System::block_number() + StartCallDelay::::get()); assert_noop!( SubtensorModule::start_call( @@ -143,7 +143,7 @@ fn test_do_start_call_fail_for_set_again() { assert_eq!(SubnetOwner::::get(netuid), coldkey_account_id); - let block_number = System::block_number() + DurationOfStartCall::get(); + let block_number = System::block_number() + StartCallDelay::::get(); System::set_block_number(block_number); assert_ok!(SubtensorModule::start_call( @@ -174,7 +174,7 @@ fn test_do_start_call_ok_with_same_block_number_after_coinbase() { assert_eq!(SubnetOwner::::get(netuid), coldkey_account_id); - let block_number = System::block_number() + DurationOfStartCall::get(); + let block_number = System::block_number() + StartCallDelay::::get(); System::set_block_number(block_number); assert_ok!(SubtensorModule::start_call( @@ -368,7 +368,7 @@ fn test_subtoken_enable() { add_network_disable_subtoken(netuid, 10, 0); assert!(!SubtokenEnabled::::get(netuid)); - let block_number = System::block_number() + DurationOfStartCall::get(); + let block_number = System::block_number() + StartCallDelay::::get(); System::set_block_number(block_number); assert_ok!(SubtensorModule::start_call( diff --git a/pallets/transaction-fee/src/tests/mock.rs b/pallets/transaction-fee/src/tests/mock.rs index ee5b1693ba..75e90346b4 100644 --- a/pallets/transaction-fee/src/tests/mock.rs +++ b/pallets/transaction-fee/src/tests/mock.rs @@ -210,7 +210,7 @@ parameter_types! { pub const InitialDissolveNetworkScheduleDuration: u64 = 5 * 24 * 60 * 60 / 12; // 5 days pub const InitialTaoWeight: u64 = u64::MAX/10; // 10% global weight. pub const InitialEmaPriceHalvingPeriod: u64 = 201_600_u64; // 4 weeks - pub const DurationOfStartCall: u64 = 7 * 24 * 60 * 60 / 12; // 7 days + pub const InitialStartCallDelay: u64 = 7 * 24 * 60 * 60 / 12; // 7 days pub const InitialKeySwapOnSubnetCost: u64 = 10_000_000; pub const HotkeySwapOnSubnetInterval: u64 = 7 * 24 * 60 * 60 / 12; // 7 days pub const LeaseDividendsDistributionInterval: u32 = 100; // 100 blocks @@ -280,7 +280,7 @@ impl pallet_subtensor::Config for Test { type InitialDissolveNetworkScheduleDuration = InitialDissolveNetworkScheduleDuration; type InitialTaoWeight = InitialTaoWeight; type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod; - type DurationOfStartCall = DurationOfStartCall; + type InitialStartCallDelay = InitialStartCallDelay; type SwapInterface = Swap; type KeySwapOnSubnetCost = InitialKeySwapOnSubnetCost; type HotkeySwapOnSubnetInterval = HotkeySwapOnSubnetInterval; diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 52746675f9..49ebd26e6e 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1058,7 +1058,7 @@ parameter_types! { pub const SubtensorInitialTaoWeight: u64 = 971_718_665_099_567_868; // 0.05267697438728329% tao weight. pub const InitialEmaPriceHalvingPeriod: u64 = 201_600_u64; // 4 weeks // 7 * 24 * 60 * 60 / 12 = 7 days - pub const DurationOfStartCall: u64 = prod_or_fast!(7 * 24 * 60 * 60 / 12, 10); + pub const InitialStartCallDelay: u64 = prod_or_fast!(7 * 24 * 60 * 60 / 12, 10); pub const SubtensorInitialKeySwapOnSubnetCost: u64 = 1_000_000; // 0.001 TAO pub const HotkeySwapOnSubnetInterval : BlockNumber = 5 * 24 * 60 * 60 / 12; // 5 days pub const LeaseDividendsDistributionInterval: BlockNumber = 100; // 100 blocks @@ -1128,7 +1128,7 @@ impl pallet_subtensor::Config for Runtime { type InitialColdkeySwapRescheduleDuration = InitialColdkeySwapRescheduleDuration; type InitialDissolveNetworkScheduleDuration = InitialDissolveNetworkScheduleDuration; type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod; - type DurationOfStartCall = DurationOfStartCall; + type InitialStartCallDelay = InitialStartCallDelay; type SwapInterface = Swap; type KeySwapOnSubnetCost = SubtensorInitialKeySwapOnSubnetCost; type HotkeySwapOnSubnetInterval = HotkeySwapOnSubnetInterval; diff --git a/scripts/localnet_patch.sh b/scripts/localnet_patch.sh index e3bee8c5b8..f36c912512 100755 --- a/scripts/localnet_patch.sh +++ b/scripts/localnet_patch.sh @@ -4,29 +4,51 @@ set -e -DurationOfStartCall="runtime/src/lib.rs" -DefaultPendingCooldown="pallets/subtensor/src/lib.rs" -SetChildren="pallets/subtensor/src/utils/rate_limiting.rs" - -# Checkers -if ! grep -q 'pub const DurationOfStartCall: u64' "$DurationOfStartCall"; then - echo "Error: Target string not found in $DurationOfStartCall" - exit 1 -fi - -if ! grep -q 'pub fn DefaultPendingCooldown() -> u64 {' "$DefaultPendingCooldown"; then - echo "Error: Target function not found in $DefaultPendingCooldown" - exit 1 -fi - -if ! grep -q 'Self::SetChildren => 150, // 30 minutes' "$SetChildren"; then - echo "Error: Target string not found in $SetChildren" - exit 1 -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|Self::SetChildren => 150, // 30 minutes|Self::SetChildren => 15, // 3 min|' "$SetChildren" - -echo "Patch applied successfully." +# Function to check for a pattern and apply a replacement +# Args: file_path, search_pattern, replacement_pattern, description +patch_file() { + local file_path="$1" + local search_pattern="$2" + local replacement_pattern="$3" + local description="$4" + + # Check if the search pattern exists + if ! grep -qF "$search_pattern" "$file_path" 2>/dev/null && ! grep -qP "$search_pattern" "$file_path" 2>/dev/null; then + echo "Error: Target pattern '$search_pattern' not found in $file_path" + echo "Description: $description" + echo "This may indicate the codebase has changed. Please verify the target code exists." + exit 1 + fi + + # Apply the replacement + if ! perl -0777 -i -pe "$replacement_pattern" "$file_path"; then + echo "Error: Failed to apply replacement in $file_path" + echo "Description: $description" + exit 1 + fi +} + +echo "Applying patches..." + +# Patch 1: InitialStartCallDelay +patch_file \ + "runtime/src/lib.rs" \ + "pub const InitialStartCallDelay: u64" \ + 's|pub const InitialStartCallDelay: u64 = prod_or_fast!\(7 \* 24 \* 60 \* 60 / 12, 10\);|pub const InitialStartCallDelay: u64 = prod_or_fast!(5, 10);|' \ + "Reduce InitialStartCallDelay for local testing" + +# Patch 2: DefaultPendingCooldown +patch_file \ + "pallets/subtensor/src/lib.rs" \ + "pub fn DefaultPendingCooldown() -> u64 {" \ + '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' \ + "Reduce DefaultPendingCooldown for local testing" + +# Patch 3: SetChildren rate limit +patch_file \ + "pallets/subtensor/src/utils/rate_limiting.rs" \ + "Self::SetChildren => 150, // 30 minutes" \ + 's|Self::SetChildren => 150, // 30 minutes|Self::SetChildren => 15, // 3 min|' \ + "Reduce SetChildren rate limit for local testing" + +echo "✓ All patches applied successfully."