Skip to content

Commit 5c46be0

Browse files
authored
Merge pull request #567 from opentensor/devnet_companion_refactor/hotkey_swap
[devnet companion]refactor/hotkey swap
2 parents 5c66560 + 01dca6a commit 5c46be0

File tree

14 files changed

+1518
-154
lines changed

14 files changed

+1518
-154
lines changed
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: devnet-companion Label Check
2+
on:
3+
pull_request:
4+
types: [opened, labeled, unlabeled, synchronize]
5+
branches: [devnet-ready]
6+
jobs:
7+
check-labels:
8+
runs-on: ubuntu-latest
9+
permissions:
10+
issues: write
11+
pull-requests: write
12+
steps:
13+
- uses: mheap/github-action-required-labels@v5
14+
with:
15+
mode: minimum
16+
count: 1
17+
labels: devnet-companion
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: testnet-companion Label Check
2+
on:
3+
pull_request:
4+
types: [opened, labeled, unlabeled, synchronize]
5+
branches: [testnet-ready]
6+
jobs:
7+
check-labels:
8+
runs-on: ubuntu-latest
9+
permissions:
10+
issues: write
11+
pull-requests: write
12+
steps:
13+
- uses: mheap/github-action-required-labels@v5
14+
with:
15+
mode: minimum
16+
count: 1
17+
labels: testnet-companion

CONTRIBUTING.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
add appropriate labels to your PR as shown below. Three positive reviews are required.
1616
4. Once the required passing reviews have been obtained, you are ready to request that your PR
1717
be included in the next `devnet` deploy. To do this, you should open a companion PR merging
18-
your branch into the `devnet-ready` branch. You must include a link to the parent PR in the
19-
description and preface your PR title with "(Devnet Ready)" or the PR will be
20-
closed/ignored.
18+
a copy of your branch into the `devnet-ready` branch. You must include a link to the parent
19+
PR in the description and preface your PR title with "(Devnet Ready)" or the PR will be
20+
closed/ignored. Your companion PR should have the `devnet-companion` label.
2121
5. A core team administrator will review your "(Devnet Ready)" PR, verifying that it logically
2222
matches the changes introduced in the parent PR (there will sometimes be minor differences
2323
due to merge conflicts) and will either request changes or approve the PR and merge it. Once
@@ -86,11 +86,13 @@
8686
| `runtime` | PR contains substantive changes to runtime / pallet code | none |
8787
| `breaking-change` | PR requires synchronized changes with bittensor | Triggers an automatic bot message so the relevant teams are made aware of the change well in advance |
8888
| `migration` | PR contains one or more migrations | none |
89+
| `devnet-companion` | Designates a devnet companion PR | Presence of `devnet-companion` label is checked |
8990
| `devnet-ready` | PR's branch has been merged into the `devnet-ready` branch and will be included in the next `devnet` deploy | none |
9091
| `on-devnet` | PR has been deployed to `devnet` | Removes `devnet-ready` |
9192
| `devnet-pass` | PR has passed manual testing on `devnet` | `devnet-pass` or `devnet-skip` required |
9293
| `devnet-skip` | Allows a critical hotfix PR to skip required testing on `devnet` | `devnet-pass` or `devnet-skip` required |
9394
| `devnet-fail` | PR has failed manual testing on `devnet` and requires modification | none |
95+
| `testnet-companion` | Designates a testnet companion PR | Presence of `testnet-companion` label is checked |
9496
| `on-testnet` | PR has been deployed to `testnet` | none |
9597
| `testnet-pass` | PR has passed manual testing on `testnet` | `testnet-pass` or `testnet-skip` required |
9698
| `testnet-skip` | Allows a critical hotfix PR to skip required manual testing and SOP on `testnet` | `testnet-pass` or `testnet-skip` required |

pallets/admin-utils/tests/mock.rs

+2
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ parameter_types! {
110110
pub const InitialSubnetLimit: u16 = 10; // Max 10 subnets.
111111
pub const InitialNetworkRateLimit: u64 = 0;
112112
pub const InitialTargetStakesPerInterval: u16 = 1;
113+
pub const InitialHotkeySwapCost: u64 = 1_000_000_000;
113114
pub const InitialAlphaHigh: u16 = 58982; // Represents 0.9 as per the production default
114115
pub const InitialAlphaLow: u16 = 45875; // Represents 0.7 as per the production default
115116
pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn
@@ -164,6 +165,7 @@ impl pallet_subtensor::Config for Test {
164165
type InitialSubnetLimit = InitialSubnetLimit;
165166
type InitialNetworkRateLimit = InitialNetworkRateLimit;
166167
type InitialTargetStakesPerInterval = InitialTargetStakesPerInterval;
168+
type HotkeySwapCost = InitialHotkeySwapCost;
167169
type AlphaHigh = InitialAlphaHigh;
168170
type AlphaLow = InitialAlphaLow;
169171
type LiquidAlphaOn = InitialLiquidAlphaOn;

pallets/subtensor/src/lib.rs

+10-6
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ mod registration;
4343
mod root;
4444
mod serving;
4545
mod staking;
46+
mod swap;
4647
mod uids;
4748
mod utils;
4849
mod weights;
@@ -240,6 +241,9 @@ pub mod pallet {
240241
/// Initial target stakes per interval issuance.
241242
#[pallet::constant]
242243
type InitialTargetStakesPerInterval: Get<u64>;
244+
/// Cost of swapping a hotkey.
245+
#[pallet::constant]
246+
type HotkeySwapCost: Get<u64>;
243247
/// The upper bound for the alpha parameter. Used for Liquid Alpha.
244248
#[pallet::constant]
245249
type AlphaHigh: Get<u16>;
@@ -744,7 +748,7 @@ pub mod pallet {
744748
pub(super) type TxDelegateTakeRateLimit<T> =
745749
StorageValue<_, u64, ValueQuery, DefaultTxDelegateTakeRateLimit<T>>;
746750
#[pallet::storage] // --- MAP ( key ) --> last_block
747-
pub(super) type LastTxBlock<T: Config> =
751+
pub type LastTxBlock<T: Config> =
748752
StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock<T>>;
749753
#[pallet::storage] // --- MAP ( key ) --> last_block
750754
pub(super) type LastTxBlockDelegateTake<T: Config> =
@@ -760,10 +764,10 @@ pub mod pallet {
760764
pub type ServingRateLimit<T> =
761765
StorageMap<_, Identity, u16, u64, ValueQuery, DefaultServingRateLimit<T>>;
762766
#[pallet::storage] // --- MAP ( netuid, hotkey ) --> axon_info
763-
pub(super) type Axons<T: Config> =
767+
pub type Axons<T: Config> =
764768
StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, AxonInfoOf, OptionQuery>;
765769
#[pallet::storage] // --- MAP ( netuid, hotkey ) --> prometheus_info
766-
pub(super) type Prometheus<T: Config> = StorageDoubleMap<
770+
pub type Prometheus<T: Config> = StorageDoubleMap<
767771
_,
768772
Identity,
769773
u16,
@@ -1017,13 +1021,13 @@ pub mod pallet {
10171021
}
10181022

10191023
#[pallet::storage] // --- DMAP ( netuid, hotkey ) --> uid
1020-
pub(super) type Uids<T: Config> =
1024+
pub type Uids<T: Config> =
10211025
StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, u16, OptionQuery>;
10221026
#[pallet::storage] // --- DMAP ( netuid, uid ) --> hotkey
1023-
pub(super) type Keys<T: Config> =
1027+
pub type Keys<T: Config> =
10241028
StorageDoubleMap<_, Identity, u16, Identity, u16, T::AccountId, ValueQuery, DefaultKey<T>>;
10251029
#[pallet::storage] // --- DMAP ( netuid ) --> (hotkey, se, ve)
1026-
pub(super) type LoadedEmission<T: Config> =
1030+
pub type LoadedEmission<T: Config> =
10271031
StorageMap<_, Identity, u16, Vec<(T::AccountId, u64, u64)>, OptionQuery>;
10281032

10291033
#[pallet::storage] // --- DMAP ( netuid ) --> active

pallets/subtensor/src/registration.rs

+2-139
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use super::*;
2-
use frame_support::storage::IterableStorageDoubleMap;
3-
use sp_core::{Get, H256, U256};
2+
use sp_core::{H256, U256};
43
use sp_io::hashing::{keccak_256, sha2_256};
54
use sp_runtime::Saturating;
65
use system::pallet_prelude::BlockNumberFor;
@@ -395,7 +394,7 @@ impl<T: Config> Pallet<T> {
395394
UsedWork::<T>::insert(work.clone(), current_block_number);
396395

397396
// --- 5. Add Balance via faucet.
398-
let balance_to_add: u64 = 100_000_000_000;
397+
let balance_to_add: u64 = 1_000_000_000_000;
399398
Self::coinbase(100_000_000_000); // We are creating tokens here from the coinbase.
400399

401400
Self::add_balance_to_coldkey_account(&coldkey, balance_to_add);
@@ -591,140 +590,4 @@ impl<T: Config> Pallet<T> {
591590
let vec_work: Vec<u8> = Self::hash_to_vec(work);
592591
(nonce, vec_work)
593592
}
594-
595-
pub fn do_swap_hotkey(
596-
origin: T::RuntimeOrigin,
597-
old_hotkey: &T::AccountId,
598-
new_hotkey: &T::AccountId,
599-
) -> DispatchResultWithPostInfo {
600-
let coldkey = ensure_signed(origin)?;
601-
602-
let mut weight = T::DbWeight::get().reads_writes(2, 0);
603-
ensure!(
604-
Self::coldkey_owns_hotkey(&coldkey, old_hotkey),
605-
Error::<T>::NonAssociatedColdKey
606-
);
607-
608-
let block: u64 = Self::get_current_block_as_u64();
609-
ensure!(
610-
!Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&coldkey), block),
611-
Error::<T>::HotKeySetTxRateLimitExceeded
612-
);
613-
614-
weight.saturating_accrue(T::DbWeight::get().reads(2));
615-
616-
ensure!(old_hotkey != new_hotkey, Error::<T>::NewHotKeyIsSameWithOld);
617-
ensure!(
618-
!Self::is_hotkey_registered_on_any_network(new_hotkey),
619-
Error::<T>::HotKeyAlreadyRegisteredInSubNet
620-
);
621-
622-
weight.saturating_accrue(
623-
T::DbWeight::get().reads((TotalNetworks::<T>::get().saturating_add(1)) as u64),
624-
);
625-
626-
let swap_cost = 1_000_000_000u64;
627-
ensure!(
628-
Self::can_remove_balance_from_coldkey_account(&coldkey, swap_cost),
629-
Error::<T>::NotEnoughBalanceToPaySwapHotKey
630-
);
631-
let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?;
632-
Self::burn_tokens(actual_burn_amount);
633-
634-
Owner::<T>::remove(old_hotkey);
635-
Owner::<T>::insert(new_hotkey, coldkey.clone());
636-
weight.saturating_accrue(T::DbWeight::get().writes(2));
637-
638-
if let Ok(total_hotkey_stake) = TotalHotkeyStake::<T>::try_get(old_hotkey) {
639-
TotalHotkeyStake::<T>::remove(old_hotkey);
640-
TotalHotkeyStake::<T>::insert(new_hotkey, total_hotkey_stake);
641-
642-
weight.saturating_accrue(T::DbWeight::get().writes(2));
643-
}
644-
645-
if let Ok(delegate_take) = Delegates::<T>::try_get(old_hotkey) {
646-
Delegates::<T>::remove(old_hotkey);
647-
Delegates::<T>::insert(new_hotkey, delegate_take);
648-
649-
weight.saturating_accrue(T::DbWeight::get().writes(2));
650-
}
651-
652-
if let Ok(last_tx) = LastTxBlock::<T>::try_get(old_hotkey) {
653-
LastTxBlock::<T>::remove(old_hotkey);
654-
LastTxBlock::<T>::insert(new_hotkey, last_tx);
655-
656-
weight.saturating_accrue(T::DbWeight::get().writes(2));
657-
}
658-
659-
let mut coldkey_stake: Vec<(T::AccountId, u64)> = vec![];
660-
for (coldkey, stake_amount) in Stake::<T>::iter_prefix(old_hotkey) {
661-
coldkey_stake.push((coldkey.clone(), stake_amount));
662-
}
663-
664-
let _ = Stake::<T>::clear_prefix(old_hotkey, coldkey_stake.len() as u32, None);
665-
weight.saturating_accrue(T::DbWeight::get().writes(coldkey_stake.len() as u64));
666-
667-
for (coldkey, stake_amount) in coldkey_stake {
668-
Stake::<T>::insert(new_hotkey, coldkey, stake_amount);
669-
weight.saturating_accrue(T::DbWeight::get().writes(1));
670-
}
671-
672-
let mut netuid_is_member: Vec<u16> = vec![];
673-
for netuid in <IsNetworkMember<T> as IterableStorageDoubleMap<T::AccountId, u16, bool>>::iter_key_prefix(old_hotkey) {
674-
netuid_is_member.push(netuid);
675-
}
676-
677-
let _ = IsNetworkMember::<T>::clear_prefix(old_hotkey, netuid_is_member.len() as u32, None);
678-
weight.saturating_accrue(T::DbWeight::get().writes(netuid_is_member.len() as u64));
679-
680-
for netuid in netuid_is_member.iter() {
681-
IsNetworkMember::<T>::insert(new_hotkey, netuid, true);
682-
weight.saturating_accrue(T::DbWeight::get().writes(1));
683-
}
684-
685-
for netuid in netuid_is_member.iter() {
686-
if let Ok(axon_info) = Axons::<T>::try_get(netuid, old_hotkey) {
687-
Axons::<T>::remove(netuid, old_hotkey);
688-
Axons::<T>::insert(netuid, new_hotkey, axon_info);
689-
690-
weight.saturating_accrue(T::DbWeight::get().writes(2));
691-
}
692-
}
693-
694-
for netuid in netuid_is_member.iter() {
695-
if let Ok(uid) = Uids::<T>::try_get(netuid, old_hotkey) {
696-
Uids::<T>::remove(netuid, old_hotkey);
697-
Uids::<T>::insert(netuid, new_hotkey, uid);
698-
699-
weight.saturating_accrue(T::DbWeight::get().writes(2));
700-
701-
Keys::<T>::insert(netuid, uid, new_hotkey);
702-
703-
weight.saturating_accrue(T::DbWeight::get().writes(1));
704-
705-
LoadedEmission::<T>::mutate(netuid, |emission_exists| match emission_exists {
706-
Some(emissions) => {
707-
if let Some(emission) = emissions.get_mut(uid as usize) {
708-
let (_, se, ve) = emission;
709-
*emission = (new_hotkey.clone(), *se, *ve);
710-
}
711-
}
712-
None => {}
713-
});
714-
715-
weight.saturating_accrue(T::DbWeight::get().writes(1));
716-
}
717-
}
718-
719-
Self::set_last_tx_block(&coldkey, block);
720-
weight.saturating_accrue(T::DbWeight::get().writes(1));
721-
722-
Self::deposit_event(Event::HotkeySwapped {
723-
coldkey,
724-
old_hotkey: old_hotkey.clone(),
725-
new_hotkey: new_hotkey.clone(),
726-
});
727-
728-
Ok(Some(weight).into())
729-
}
730593
}

0 commit comments

Comments
 (0)