Skip to content

Commit a43217d

Browse files
authored
Merge pull request #1303 from opentensor/devnet-ready
devnet deploy 2/15/2025
2 parents de38a0b + 36e268b commit a43217d

File tree

8 files changed

+262
-5
lines changed

8 files changed

+262
-5
lines changed

pallets/admin-utils/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ pub mod pallet {
653653
netuid: u16,
654654
difficulty: u64,
655655
) -> DispatchResult {
656-
pallet_subtensor::Pallet::<T>::ensure_subnet_owner_or_root(origin, netuid)?;
656+
ensure_root(origin)?;
657657
ensure!(
658658
pallet_subtensor::Pallet::<T>::if_subnet_exist(netuid),
659659
Error::<T>::SubnetDoesNotExist

pallets/admin-utils/src/tests/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,18 @@ fn test_sudo_set_difficulty() {
643643
to_be_set
644644
));
645645
assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), to_be_set);
646+
647+
// Test that SN owner can't set difficulty
648+
pallet_subtensor::SubnetOwner::<Test>::insert(netuid, U256::from(1));
649+
assert_eq!(
650+
AdminUtils::sudo_set_difficulty(
651+
<<Test as Config>::RuntimeOrigin>::signed(U256::from(1)),
652+
netuid,
653+
init_value
654+
),
655+
Err(DispatchError::BadOrigin)
656+
);
657+
assert_eq!(SubtensorModule::get_difficulty_as_u64(netuid), to_be_set); // no change
646658
});
647659
}
648660

pallets/subtensor/src/macros/hooks.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ mod hooks {
8181
// Upgrade identities to V2
8282
.saturating_add(migrations::migrate_identities_v2::migrate_identities_to_v2::<T>())
8383
// Set the min burn across all subnets to a new minimum
84-
.saturating_add(migrations::migrate_set_min_burn::migrate_set_min_burn::<T>());
84+
.saturating_add(migrations::migrate_set_min_burn::migrate_set_min_burn::<T>())
85+
// Set the min difficulty across all subnets to a new minimum
86+
.saturating_add(migrations::migrate_set_min_difficulty::migrate_set_min_difficulty::<T>());
8587
weight
8688
}
8789

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use alloc::string::String;
2+
3+
use frame_support::IterableStorageMap;
4+
use frame_support::{traits::Get, weights::Weight};
5+
6+
use super::*;
7+
8+
pub fn migrate_set_min_difficulty<T: Config>() -> Weight {
9+
let migration_name = b"migrate_set_min_difficulty".to_vec();
10+
11+
// Initialize the weight with one read operation.
12+
let mut weight = T::DbWeight::get().reads(1);
13+
14+
// Check if the migration has already run
15+
if HasMigrationRun::<T>::get(&migration_name) {
16+
log::info!(
17+
"Migration '{:?}' has already run. Skipping.",
18+
migration_name
19+
);
20+
return weight;
21+
}
22+
log::info!(
23+
"Running migration '{}'",
24+
String::from_utf8_lossy(&migration_name)
25+
);
26+
27+
let netuids: Vec<u16> = <NetworksAdded<T> as IterableStorageMap<u16, bool>>::iter()
28+
.map(|(netuid, _)| netuid)
29+
.collect();
30+
weight = weight.saturating_add(T::DbWeight::get().reads(netuids.len() as u64));
31+
32+
for netuid in netuids.iter().clone() {
33+
if *netuid == 0 {
34+
continue;
35+
}
36+
// Set min difficulty to 10 million for all subnets
37+
Pallet::<T>::set_min_difficulty(*netuid, 10_000_000);
38+
weight = weight.saturating_add(T::DbWeight::get().writes(1));
39+
}
40+
41+
// Mark the migration as completed
42+
HasMigrationRun::<T>::insert(&migration_name, true);
43+
weight = weight.saturating_add(T::DbWeight::get().writes(1));
44+
45+
log::info!(
46+
"Migration '{:?}' completed.",
47+
String::from_utf8_lossy(&migration_name)
48+
);
49+
50+
// Return the migration weight.
51+
weight
52+
}

pallets/subtensor/src/migrations/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub mod migrate_populate_owned_hotkeys;
1212
pub mod migrate_populate_staking_hotkeys;
1313
pub mod migrate_rao;
1414
pub mod migrate_set_min_burn;
15+
pub mod migrate_set_min_difficulty;
1516
pub mod migrate_stake_threshold;
1617
pub mod migrate_subnet_volume;
1718
pub mod migrate_to_v1_separate_emission;

pallets/subtensor/src/subnets/registration.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::*;
22
use sp_core::{H256, U256};
33
use sp_io::hashing::{keccak_256, sha2_256};
44
use sp_runtime::Saturating;
5+
use substrate_fixed::types::I64F64;
56
use system::pallet_prelude::BlockNumberFor;
67

78
const LOG_TARGET: &str = "runtime::subtensor::registration";
@@ -424,13 +425,32 @@ impl<T: Config> Pallet<T> {
424425
return 0; // If there are no neurons in this network.
425426
}
426427

428+
// Get SN owner top stake hotkey
429+
let mut top_stake_sn_owner_hotkey: Option<T::AccountId> = None;
430+
let mut max_stake_weight: I64F64 = I64F64::from_num(-1);
427431
for neuron_uid in 0..neurons_n {
428-
// Do not deregister the owner
429432
if let Ok(hotkey) = Self::get_hotkey_for_net_and_uid(netuid, neuron_uid) {
430433
let coldkey = Self::get_owning_coldkey_for_hotkey(&hotkey);
431-
if Self::get_subnet_owner(netuid) == coldkey {
434+
if Self::get_subnet_owner(netuid) != coldkey {
432435
continue;
433436
}
437+
438+
let stake_weights = Self::get_stake_weights_for_hotkey_on_subnet(&hotkey, netuid);
439+
if stake_weights.0 > max_stake_weight {
440+
max_stake_weight = stake_weights.0;
441+
top_stake_sn_owner_hotkey = Some(hotkey);
442+
}
443+
}
444+
}
445+
446+
for neuron_uid in 0..neurons_n {
447+
// Do not deregister the owner's top-stake hotkey
448+
if let Ok(hotkey) = Self::get_hotkey_for_net_and_uid(netuid, neuron_uid) {
449+
if let Some(ref top_sn_owner_hotkey) = top_stake_sn_owner_hotkey {
450+
if top_sn_owner_hotkey == &hotkey {
451+
continue;
452+
}
453+
}
434454
}
435455

436456
let pruning_score: u16 = Self::get_pruning_score_for_uid(netuid, neuron_uid);

pallets/subtensor/src/tests/uids.rs

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::*;
55
use frame_support::{assert_err, assert_ok};
66
use frame_system::Config;
77
use sp_core::U256;
8+
use substrate_fixed::types::I64F64;
89

910
/********************************************
1011
tests for uids.rs file
@@ -335,3 +336,172 @@ fn test_get_neuron_to_prune_owner_not_pruned() {
335336
);
336337
});
337338
}
339+
340+
#[test]
341+
fn test_get_neuron_to_prune_owner_pruned_if_not_top_stake_owner_hotkey() {
342+
new_test_ext(1).execute_with(|| {
343+
let owner_hotkey = U256::from(123);
344+
let owner_coldkey = U256::from(999);
345+
let other_owner_hotkey = U256::from(456);
346+
347+
let netuid = add_dynamic_network(&owner_hotkey, &owner_coldkey);
348+
349+
SubtensorModule::set_max_registrations_per_block(netuid, 100);
350+
SubtensorModule::set_target_registrations_per_interval(netuid, 100);
351+
SubnetOwner::<Test>::insert(netuid, owner_coldkey);
352+
353+
let owner_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &owner_hotkey)
354+
.expect("Owner neuron should already be registered by add_dynamic_network");
355+
356+
// Register another hotkey for the owner
357+
register_ok_neuron(netuid, other_owner_hotkey, owner_coldkey, 0);
358+
let other_owner_uid =
359+
SubtensorModule::get_uid_for_net_and_hotkey(netuid, &other_owner_hotkey)
360+
.expect("Should be registered");
361+
362+
let additional_hotkey_1 = U256::from(1000);
363+
let additional_coldkey_1 = U256::from(2000);
364+
365+
let additional_hotkey_2 = U256::from(1001);
366+
let additional_coldkey_2 = U256::from(2001);
367+
368+
register_ok_neuron(netuid, additional_hotkey_1, additional_coldkey_1, 1);
369+
let uid_2 = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &additional_hotkey_1)
370+
.expect("Should be registered");
371+
372+
register_ok_neuron(netuid, additional_hotkey_2, additional_coldkey_2, 2);
373+
let uid_3 = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &additional_hotkey_2)
374+
.expect("Should be registered");
375+
376+
SubtensorModule::set_pruning_score_for_uid(netuid, owner_uid, 0);
377+
// Other owner key has pruning score not worse than the owner's first hotkey, but worse than the additional hotkeys
378+
SubtensorModule::set_pruning_score_for_uid(netuid, other_owner_uid, 1);
379+
SubtensorModule::set_pruning_score_for_uid(netuid, uid_2, 2);
380+
SubtensorModule::set_pruning_score_for_uid(netuid, uid_3, 3);
381+
382+
let pruned_uid = SubtensorModule::get_neuron_to_prune(netuid);
383+
assert_eq!(pruned_uid, other_owner_uid, "Should prune the owner");
384+
385+
// Give the owner's other hotkey some stake
386+
SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
387+
&other_owner_hotkey,
388+
&owner_coldkey,
389+
netuid,
390+
1000,
391+
);
392+
393+
// Reset pruning scores
394+
SubtensorModule::set_pruning_score_for_uid(netuid, owner_uid, 0);
395+
SubtensorModule::set_pruning_score_for_uid(netuid, other_owner_uid, 1);
396+
SubtensorModule::set_pruning_score_for_uid(netuid, uid_2, 2);
397+
SubtensorModule::set_pruning_score_for_uid(netuid, uid_3, 3);
398+
399+
let pruned_uid = SubtensorModule::get_neuron_to_prune(netuid);
400+
401+
// - The pruned UID must be `uid_1` (score=1).
402+
// - The owner's UID remains unpruned.
403+
assert_eq!(
404+
pruned_uid, owner_uid,
405+
"Should prune the owner, not the top-stake owner hotkey and not the additional hotkeys"
406+
);
407+
});
408+
}
409+
410+
#[test]
411+
fn test_get_neuron_to_prune_owner_pruned_if_not_top_stake_owner_hotkey_chk() {
412+
new_test_ext(1).execute_with(|| {
413+
let owner_hotkey = U256::from(123);
414+
let owner_coldkey = U256::from(999);
415+
let other_owner_hotkey = U256::from(456);
416+
let parent_hotkey = U256::from(4567);
417+
let parent_coldkey = U256::from(4568);
418+
419+
let netuid = add_dynamic_network(&owner_hotkey, &owner_coldkey);
420+
421+
SubtensorModule::set_max_registrations_per_block(netuid, 100);
422+
SubtensorModule::set_target_registrations_per_interval(netuid, 100);
423+
SubnetOwner::<Test>::insert(netuid, owner_coldkey);
424+
425+
let owner_uid = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &owner_hotkey)
426+
.expect("Owner neuron should already be registered by add_dynamic_network");
427+
428+
// Register another hotkey for the owner
429+
register_ok_neuron(netuid, other_owner_hotkey, owner_coldkey, 0);
430+
let other_owner_uid =
431+
SubtensorModule::get_uid_for_net_and_hotkey(netuid, &other_owner_hotkey)
432+
.expect("Should be registered");
433+
434+
let additional_hotkey_1 = U256::from(1000);
435+
let additional_coldkey_1 = U256::from(2000);
436+
437+
let additional_hotkey_2 = U256::from(1001);
438+
let additional_coldkey_2 = U256::from(2001);
439+
440+
register_ok_neuron(netuid, additional_hotkey_1, additional_coldkey_1, 1);
441+
let uid_2 = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &additional_hotkey_1)
442+
.expect("Should be registered");
443+
444+
register_ok_neuron(netuid, additional_hotkey_2, additional_coldkey_2, 2);
445+
let uid_3 = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &additional_hotkey_2)
446+
.expect("Should be registered");
447+
448+
register_ok_neuron(netuid, parent_hotkey, parent_coldkey, 3);
449+
let uid_4: u16 = SubtensorModule::get_uid_for_net_and_hotkey(netuid, &parent_hotkey)
450+
.expect("Should be registered");
451+
452+
// Give parent key some stake
453+
SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
454+
&parent_hotkey,
455+
&parent_coldkey,
456+
netuid,
457+
10_000_000,
458+
);
459+
460+
SubtensorModule::set_pruning_score_for_uid(netuid, owner_uid, 0);
461+
// Other owner key has pruning score not worse than the owner's first hotkey, but worse than the additional hotkeys
462+
SubtensorModule::set_pruning_score_for_uid(netuid, other_owner_uid, 1);
463+
SubtensorModule::set_pruning_score_for_uid(netuid, uid_2, 2);
464+
SubtensorModule::set_pruning_score_for_uid(netuid, uid_3, 3);
465+
466+
// Ensure parent key is not pruned
467+
SubtensorModule::set_pruning_score_for_uid(netuid, uid_4, 10_000);
468+
469+
let pruned_uid = SubtensorModule::get_neuron_to_prune(netuid);
470+
assert_eq!(
471+
pruned_uid, other_owner_uid,
472+
"Should prune the owner's other hotkey"
473+
);
474+
475+
// Give the owner's other hotkey some CHK stake; Doesn't need to be much
476+
mock_set_children_no_epochs(
477+
netuid,
478+
&parent_hotkey,
479+
&[(
480+
I64F64::saturating_from_num(0.1)
481+
.saturating_mul(I64F64::saturating_from_num(u64::MAX))
482+
.saturating_to_num::<u64>(),
483+
other_owner_hotkey,
484+
)],
485+
);
486+
// Check stake weight of other_owner_hotkey
487+
let stake_weight =
488+
SubtensorModule::get_stake_weights_for_hotkey_on_subnet(&other_owner_hotkey, netuid);
489+
assert!(stake_weight.0 > 0);
490+
491+
// Reset pruning scores
492+
SubtensorModule::set_pruning_score_for_uid(netuid, owner_uid, 0);
493+
SubtensorModule::set_pruning_score_for_uid(netuid, other_owner_uid, 1);
494+
SubtensorModule::set_pruning_score_for_uid(netuid, uid_2, 2);
495+
SubtensorModule::set_pruning_score_for_uid(netuid, uid_3, 3);
496+
SubtensorModule::set_pruning_score_for_uid(netuid, uid_4, 10_000);
497+
498+
let pruned_uid = SubtensorModule::get_neuron_to_prune(netuid);
499+
500+
// - The pruned UID must be `uid_1` (score=1).
501+
// - The owner's UID remains unpruned.
502+
assert_eq!(
503+
pruned_uid, owner_uid,
504+
"Should prune the owner, not the top-stake owner hotkey and not the additional hotkeys"
505+
);
506+
});
507+
}

runtime/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
229229
// `spec_version`, and `authoring_version` are the same between Wasm and native.
230230
// This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
231231
// the compatible custom types.
232-
spec_version: 236,
232+
spec_version: 237,
233233
impl_version: 1,
234234
apis: RUNTIME_API_VERSIONS,
235235
transaction_version: 1,

0 commit comments

Comments
 (0)