Skip to content

Commit 2f41708

Browse files
authored
Merge pull request #2041 from opentensor/auto-hotkey-per-subnet
set auto hotkey per subnet
2 parents a3cc69c + 1dc5e0e commit 2f41708

File tree

17 files changed

+410
-16
lines changed

17 files changed

+410
-16
lines changed

pallets/subtensor/rpc/src/lib.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ pub trait SubtensorCustomApi<BlockHash> {
9292
metagraph_index: Vec<u16>,
9393
at: Option<BlockHash>,
9494
) -> RpcResult<Vec<u8>>;
95+
#[method(name = "subnetInfo_getColdkeyAutoStakeHotkey")]
96+
fn get_coldkey_auto_stake_hotkey(
97+
&self,
98+
coldkey: AccountId32,
99+
netuid: NetUid,
100+
at: Option<BlockHash>,
101+
) -> RpcResult<Vec<u8>>;
95102
#[method(name = "subnetInfo_getSelectiveMechagraph")]
96103
fn get_selective_mechagraph(
97104
&self,
@@ -474,6 +481,24 @@ where
474481
}
475482
}
476483

484+
fn get_coldkey_auto_stake_hotkey(
485+
&self,
486+
coldkey: AccountId32,
487+
netuid: NetUid,
488+
at: Option<<Block as BlockT>::Hash>,
489+
) -> RpcResult<Vec<u8>> {
490+
let api = self.client.runtime_api();
491+
let at = at.unwrap_or_else(|| self.client.info().best_hash);
492+
493+
match api.get_coldkey_auto_stake_hotkey(at, coldkey, netuid) {
494+
Ok(result) => Ok(result.encode()),
495+
Err(e) => Err(Error::RuntimeError(format!(
496+
"Unable to get coldkey auto stake hotkey: {e:?}"
497+
))
498+
.into()),
499+
}
500+
}
501+
477502
fn get_selective_mechagraph(
478503
&self,
479504
netuid: NetUid,

pallets/subtensor/runtime-api/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ sp_api::decl_runtime_apis! {
4545
fn get_dynamic_info(netuid: NetUid) -> Option<DynamicInfo<AccountId32>>;
4646
fn get_subnet_state(netuid: NetUid) -> Option<SubnetState<AccountId32>>;
4747
fn get_selective_metagraph(netuid: NetUid, metagraph_indexes: Vec<u16>) -> Option<SelectiveMetagraph<AccountId32>>;
48+
fn get_coldkey_auto_stake_hotkey(coldkey: AccountId32, netuid: NetUid) -> Option<AccountId32>;
4849
fn get_selective_mechagraph(netuid: NetUid, subid: MechId, metagraph_indexes: Vec<u16>) -> Option<SelectiveMetagraph<AccountId32>>;
4950
fn get_subnet_to_prune() -> Option<NetUid>;
5051
}

pallets/subtensor/src/benchmarks.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1560,9 +1560,21 @@ mod pallet_benchmarks {
15601560
#[benchmark]
15611561
fn set_coldkey_auto_stake_hotkey() {
15621562
let coldkey: T::AccountId = whitelisted_caller();
1563-
let hot: T::AccountId = account("A", 0, 1);
1563+
let netuid = NetUid::from(1);
1564+
let hotkey: T::AccountId = account("A", 0, 1);
1565+
SubtokenEnabled::<T>::insert(netuid, true);
1566+
Subtensor::<T>::init_new_network(netuid, 1);
1567+
let amount = 900_000_000_000;
1568+
1569+
Subtensor::<T>::add_balance_to_coldkey_account(&coldkey.clone(), amount);
1570+
1571+
assert_ok!(Subtensor::<T>::burned_register(
1572+
RawOrigin::Signed(coldkey.clone()).into(),
1573+
netuid,
1574+
hotkey.clone()
1575+
));
15641576

15651577
#[extrinsic_call]
1566-
_(RawOrigin::Signed(coldkey.clone()), hot.clone());
1578+
_(RawOrigin::Signed(coldkey.clone()), netuid, hotkey.clone());
15671579
}
15681580
}

pallets/subtensor/src/coinbase/run_coinbase.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ impl<T: Config> Pallet<T> {
514514
}
515515

516516
let owner: T::AccountId = Owner::<T>::get(&hotkey);
517-
let maybe_dest = AutoStakeDestination::<T>::get(&owner);
517+
let maybe_dest = AutoStakeDestination::<T>::get(&owner, netuid);
518518

519519
// Always stake but only emit event if autostake is set.
520520
let destination = maybe_dest.clone().unwrap_or(hotkey.clone());

pallets/subtensor/src/lib.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,9 +1140,16 @@ pub mod pallet {
11401140
#[pallet::storage] // --- MAP ( cold ) --> Vec<hot> | Returns the vector of hotkeys controlled by this coldkey.
11411141
pub type OwnedHotkeys<T: Config> =
11421142
StorageMap<_, Blake2_128Concat, T::AccountId, Vec<T::AccountId>, ValueQuery>;
1143-
#[pallet::storage] // --- MAP ( cold ) --> hot | Returns the hotkey a coldkey will autostake to with mining rewards.
1144-
pub type AutoStakeDestination<T: Config> =
1145-
StorageMap<_, Blake2_128Concat, T::AccountId, T::AccountId, OptionQuery>;
1143+
#[pallet::storage] // --- DMAP ( cold, netuid )--> hot | Returns the hotkey a coldkey will autostake to with mining rewards.
1144+
pub type AutoStakeDestination<T: Config> = StorageDoubleMap<
1145+
_,
1146+
Blake2_128Concat,
1147+
T::AccountId,
1148+
Identity,
1149+
NetUid,
1150+
T::AccountId,
1151+
OptionQuery,
1152+
>;
11461153

11471154
#[pallet::storage] // --- DMAP ( cold ) --> (block_expected, new_coldkey) | Maps coldkey to the block to swap at and new coldkey.
11481155
pub type ColdkeySwapScheduled<T: Config> = StorageMap<

pallets/subtensor/src/macros/dispatches.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,7 +1086,7 @@ mod dispatches {
10861086
/// Weight is calculated based on the number of database reads and writes.
10871087
#[pallet::call_index(71)]
10881088
#[pallet::weight((Weight::from_parts(161_700_000, 0)
1089-
.saturating_add(T::DbWeight::get().reads(15_u64))
1089+
.saturating_add(T::DbWeight::get().reads(16_u64))
10901090
.saturating_add(T::DbWeight::get().writes(9)), DispatchClass::Operational, Pays::No))]
10911091
pub fn swap_coldkey(
10921092
origin: OriginFor<T>,
@@ -2292,16 +2292,36 @@ mod dispatches {
22922292
/// * `hotkey` (T::AccountId):
22932293
/// - The hotkey account to designate as the autostake destination.
22942294
#[pallet::call_index(114)]
2295-
#[pallet::weight((Weight::from_parts(5_170_000, 0)
2296-
.saturating_add(T::DbWeight::get().reads(0_u64))
2295+
#[pallet::weight((Weight::from_parts(29_930_000, 0)
2296+
.saturating_add(T::DbWeight::get().reads(3_u64))
22972297
.saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Normal, Pays::No))]
22982298
pub fn set_coldkey_auto_stake_hotkey(
22992299
origin: T::RuntimeOrigin,
2300+
netuid: NetUid,
23002301
hotkey: T::AccountId,
23012302
) -> DispatchResult {
23022303
let coldkey = ensure_signed(origin)?;
2304+
ensure!(Self::if_subnet_exist(netuid), Error::<T>::SubnetNotExists);
2305+
ensure!(
2306+
Uids::<T>::contains_key(netuid, &hotkey),
2307+
Error::<T>::HotKeyNotRegisteredInSubNet
2308+
);
2309+
2310+
let current_hotkey = AutoStakeDestination::<T>::get(coldkey.clone(), netuid);
2311+
if let Some(current_hotkey) = current_hotkey {
2312+
ensure!(
2313+
current_hotkey != hotkey,
2314+
Error::<T>::SameAutoStakeHotkeyAlreadySet
2315+
);
2316+
}
2317+
2318+
AutoStakeDestination::<T>::insert(coldkey.clone(), netuid, hotkey.clone());
23032319

2304-
AutoStakeDestination::<T>::insert(coldkey, hotkey.clone());
2320+
Self::deposit_event(Event::AutoStakeDestinationSet {
2321+
coldkey,
2322+
netuid,
2323+
hotkey,
2324+
});
23052325

23062326
Ok(())
23072327
}

pallets/subtensor/src/macros/errors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ mod errors {
256256
CannotAffordLockCost,
257257
/// exceeded the rate limit for associating an EVM key.
258258
EvmKeyAssociateRateLimitExceeded,
259+
/// Same auto stake hotkey already set
260+
SameAutoStakeHotkeyAlreadySet,
259261
/// The UID map for the subnet could not be cleared
260262
UidMapCouldNotBeCleared,
261263
/// Trimming would exceed the max immune neurons percentage

pallets/subtensor/src/macros/events.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,5 +442,19 @@ mod events {
442442

443443
/// The minimum allowed UIDs for a subnet have been set.
444444
MinAllowedUidsSet(NetUid, u16),
445+
446+
/// The auto stake destination has been set.
447+
///
448+
/// - **coldkey**: The account ID of the coldkey.
449+
/// - **netuid**: The network identifier.
450+
/// - **hotkey**: The account ID of the hotkey.
451+
AutoStakeDestinationSet {
452+
/// The account ID of the coldkey.
453+
coldkey: T::AccountId,
454+
/// The network identifier.
455+
netuid: NetUid,
456+
/// The account ID of the hotkey.
457+
hotkey: T::AccountId,
458+
},
445459
}
446460
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use super::*;
2+
use crate::AccountIdOf;
3+
use frame_support::{
4+
IterableStorageMap,
5+
pallet_prelude::{Blake2_128Concat, OptionQuery},
6+
storage_alias,
7+
traits::Get,
8+
weights::Weight,
9+
};
10+
use scale_info::prelude::string::String;
11+
12+
/// Module containing deprecated storage format for AutoStakeDestination
13+
pub mod deprecated_auto_stake_destination_format {
14+
use super::*;
15+
16+
#[storage_alias]
17+
pub(super) type AutoStakeDestination<T: Config> =
18+
StorageMap<Pallet<T>, Blake2_128Concat, AccountIdOf<T>, AccountIdOf<T>, OptionQuery>;
19+
}
20+
21+
/// Migrate the AutoStakeDestination map from single map to double map format
22+
pub fn migrate_auto_stake_destination<T: Config>() -> Weight {
23+
use deprecated_auto_stake_destination_format as old;
24+
25+
let migration_name = b"migrate_auto_stake_destination".to_vec();
26+
let mut weight = T::DbWeight::get().reads(1);
27+
28+
if HasMigrationRun::<T>::get(&migration_name) {
29+
log::info!(
30+
"Migration '{:?}' has already run. Skipping.",
31+
String::from_utf8_lossy(&migration_name)
32+
);
33+
return weight;
34+
}
35+
36+
log::info!(
37+
"Running migration '{}'",
38+
String::from_utf8_lossy(&migration_name)
39+
);
40+
41+
// ------------------------------
42+
// Step 1: Migrate AutoStakeDestination entries
43+
// ------------------------------
44+
45+
let curr_keys: Vec<AccountIdOf<T>> = old::AutoStakeDestination::<T>::iter_keys().collect();
46+
let root_netuid = NetUid::ROOT;
47+
let netuids: Vec<NetUid> = <NetworksAdded<T> as IterableStorageMap<NetUid, bool>>::iter()
48+
.map(|(netuid, _)| netuid)
49+
.collect();
50+
51+
for coldkey in &curr_keys {
52+
weight.saturating_accrue(T::DbWeight::get().reads(1));
53+
54+
if let Some(hotkey) = old::AutoStakeDestination::<T>::get(coldkey) {
55+
for netuid in netuids.iter() {
56+
if *netuid == root_netuid {
57+
continue;
58+
}
59+
AutoStakeDestination::<T>::insert(coldkey, netuid, hotkey.clone());
60+
}
61+
62+
old::AutoStakeDestination::<T>::remove(coldkey);
63+
64+
weight.saturating_accrue(T::DbWeight::get().writes(netuids.len() as u64));
65+
}
66+
}
67+
68+
// ------------------------------
69+
// Step 2: Mark Migration as Completed
70+
// ------------------------------
71+
72+
HasMigrationRun::<T>::insert(&migration_name, true);
73+
weight = weight.saturating_add(T::DbWeight::get().writes(1));
74+
75+
log::info!(
76+
"Migration '{:?}' completed successfully. {} entries migrated.",
77+
String::from_utf8_lossy(&migration_name),
78+
curr_keys.len()
79+
);
80+
81+
weight
82+
}

pallets/subtensor/src/migrations/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use frame_support::pallet_prelude::Weight;
44
use sp_io::KillStorageResult;
55
use sp_io::hashing::twox_128;
66
use sp_io::storage::clear_prefix;
7+
pub mod migrate_auto_stake_destination;
78
pub mod migrate_chain_identity;
89
pub mod migrate_coldkey_swap_scheduled;
910
pub mod migrate_commit_reveal_settings;

0 commit comments

Comments
 (0)