Skip to content

[devnet companion]refactor/hotkey swap #567

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
2b10e12
refactor: hotkey swap + tests
Jun 17, 2024
7eb29f9
chore: lints
Jun 17, 2024
6ddcfe2
chore: clippy
Jun 17, 2024
45e828d
chore: give 1k on faucet for easier to create networks locally
Jun 17, 2024
c12ec37
Correct the expected weights on the register extrinsic
keithtensor Jun 17, 2024
5eaa088
Update pallets/subtensor/src/swap.rs
distributedstatemachine Jun 17, 2024
969a4f8
chore: updates from using real weights in tests
Jun 17, 2024
6b68263
chore: review comments , make swap cost a constant
Jun 17, 2024
ec27e77
chore: runtime consts
Jun 17, 2024
fc82551
chore: clear prefix for removing old value from stake map
Jun 17, 2024
5057472
chore: pr comments assert keys
Jun 17, 2024
dd9672b
chore: pr comments: remove last tx block
Jun 17, 2024
60019a9
chore: fmt
Jun 17, 2024
2cd90dd
Use concrete numbers for weight expectations
keithtensor Jun 18, 2024
5743ae7
Update pallets/subtensor/src/swap.rs
distributedstatemachine Jun 18, 2024
f358847
chore: add test_swap_hotkey_tx_rate_limit_exceeded
Jun 18, 2024
768e8e4
chore: fmt
Jun 18, 2024
cb078a2
chore: review comments
Jun 18, 2024
814447f
fix: pr comments
Jun 21, 2024
680e4ad
chore: lint
Jun 21, 2024
f7b567a
fix: remove unused function
Jun 21, 2024
78663d8
add requirement for `devnet-companion` label for `devnet-ready` PRs
sam0x17 Jun 19, 2024
76d9439
add testnet-ready labels check
sam0x17 Jun 19, 2024
6bd2e42
update CONTRIBUTING.md with additional info
sam0x17 Jun 19, 2024
ad85c27
update docs
sam0x17 Jun 19, 2024
66c87af
clippy fix
sam0x17 Jun 21, 2024
01dca6a
make clippy happy
Jun 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/devnet-ready-labels.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: devnet-companion Label Check
on:
pull_request:
types: [opened, labeled, unlabeled, synchronize]
branches: [devnet-ready]
jobs:
check-labels:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: mheap/github-action-required-labels@v5
with:
mode: minimum
count: 1
labels: devnet-companion
17 changes: 17 additions & 0 deletions .github/workflows/testnet-ready-labels.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: testnet-companion Label Check
on:
pull_request:
types: [opened, labeled, unlabeled, synchronize]
branches: [testnet-ready]
jobs:
check-labels:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: mheap/github-action-required-labels@v5
with:
mode: minimum
count: 1
labels: testnet-companion
8 changes: 5 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
add appropriate labels to your PR as shown below. Three positive reviews are required.
4. Once the required passing reviews have been obtained, you are ready to request that your PR
be included in the next `devnet` deploy. To do this, you should open a companion PR merging
your branch into the `devnet-ready` branch. You must include a link to the parent PR in the
description and preface your PR title with "(Devnet Ready)" or the PR will be
closed/ignored.
a copy of your branch into the `devnet-ready` branch. You must include a link to the parent
PR in the description and preface your PR title with "(Devnet Ready)" or the PR will be
closed/ignored. Your companion PR should have the `devnet-companion` label.
5. A core team administrator will review your "(Devnet Ready)" PR, verifying that it logically
matches the changes introduced in the parent PR (there will sometimes be minor differences
due to merge conflicts) and will either request changes or approve the PR and merge it. Once
Expand Down Expand Up @@ -86,11 +86,13 @@
| `runtime` | PR contains substantive changes to runtime / pallet code | none |
| `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 |
| `migration` | PR contains one or more migrations | none |
| `devnet-companion` | Designates a devnet companion PR | Presence of `devnet-companion` label is checked |
| `devnet-ready` | PR's branch has been merged into the `devnet-ready` branch and will be included in the next `devnet` deploy | none |
| `on-devnet` | PR has been deployed to `devnet` | Removes `devnet-ready` |
| `devnet-pass` | PR has passed manual testing on `devnet` | `devnet-pass` or `devnet-skip` required |
| `devnet-skip` | Allows a critical hotfix PR to skip required testing on `devnet` | `devnet-pass` or `devnet-skip` required |
| `devnet-fail` | PR has failed manual testing on `devnet` and requires modification | none |
| `testnet-companion` | Designates a testnet companion PR | Presence of `testnet-companion` label is checked |
| `on-testnet` | PR has been deployed to `testnet` | none |
| `testnet-pass` | PR has passed manual testing on `testnet` | `testnet-pass` or `testnet-skip` required |
| `testnet-skip` | Allows a critical hotfix PR to skip required manual testing and SOP on `testnet` | `testnet-pass` or `testnet-skip` required |
Expand Down
2 changes: 2 additions & 0 deletions pallets/admin-utils/tests/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ parameter_types! {
pub const InitialSubnetLimit: u16 = 10; // Max 10 subnets.
pub const InitialNetworkRateLimit: u64 = 0;
pub const InitialTargetStakesPerInterval: u16 = 1;
pub const InitialHotkeySwapCost: u64 = 1_000_000_000;
pub const InitialAlphaHigh: u16 = 58982; // Represents 0.9 as per the production default
pub const InitialAlphaLow: u16 = 45875; // Represents 0.7 as per the production default
pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn
Expand Down Expand Up @@ -164,6 +165,7 @@ impl pallet_subtensor::Config for Test {
type InitialSubnetLimit = InitialSubnetLimit;
type InitialNetworkRateLimit = InitialNetworkRateLimit;
type InitialTargetStakesPerInterval = InitialTargetStakesPerInterval;
type HotkeySwapCost = InitialHotkeySwapCost;
type AlphaHigh = InitialAlphaHigh;
type AlphaLow = InitialAlphaLow;
type LiquidAlphaOn = InitialLiquidAlphaOn;
Expand Down
16 changes: 10 additions & 6 deletions pallets/subtensor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ mod registration;
mod root;
mod serving;
mod staking;
mod swap;
mod uids;
mod utils;
mod weights;
Expand Down Expand Up @@ -240,6 +241,9 @@ pub mod pallet {
/// Initial target stakes per interval issuance.
#[pallet::constant]
type InitialTargetStakesPerInterval: Get<u64>;
/// Cost of swapping a hotkey.
#[pallet::constant]
type HotkeySwapCost: Get<u64>;
/// The upper bound for the alpha parameter. Used for Liquid Alpha.
#[pallet::constant]
type AlphaHigh: Get<u16>;
Expand Down Expand Up @@ -744,7 +748,7 @@ pub mod pallet {
pub(super) type TxDelegateTakeRateLimit<T> =
StorageValue<_, u64, ValueQuery, DefaultTxDelegateTakeRateLimit<T>>;
#[pallet::storage] // --- MAP ( key ) --> last_block
pub(super) type LastTxBlock<T: Config> =
pub type LastTxBlock<T: Config> =
StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock<T>>;
#[pallet::storage] // --- MAP ( key ) --> last_block
pub(super) type LastTxBlockDelegateTake<T: Config> =
Expand All @@ -760,10 +764,10 @@ pub mod pallet {
pub type ServingRateLimit<T> =
StorageMap<_, Identity, u16, u64, ValueQuery, DefaultServingRateLimit<T>>;
#[pallet::storage] // --- MAP ( netuid, hotkey ) --> axon_info
pub(super) type Axons<T: Config> =
pub type Axons<T: Config> =
StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, AxonInfoOf, OptionQuery>;
#[pallet::storage] // --- MAP ( netuid, hotkey ) --> prometheus_info
pub(super) type Prometheus<T: Config> = StorageDoubleMap<
pub type Prometheus<T: Config> = StorageDoubleMap<
_,
Identity,
u16,
Expand Down Expand Up @@ -1017,13 +1021,13 @@ pub mod pallet {
}

#[pallet::storage] // --- DMAP ( netuid, hotkey ) --> uid
pub(super) type Uids<T: Config> =
pub type Uids<T: Config> =
StorageDoubleMap<_, Identity, u16, Blake2_128Concat, T::AccountId, u16, OptionQuery>;
#[pallet::storage] // --- DMAP ( netuid, uid ) --> hotkey
pub(super) type Keys<T: Config> =
pub type Keys<T: Config> =
StorageDoubleMap<_, Identity, u16, Identity, u16, T::AccountId, ValueQuery, DefaultKey<T>>;
#[pallet::storage] // --- DMAP ( netuid ) --> (hotkey, se, ve)
pub(super) type LoadedEmission<T: Config> =
pub type LoadedEmission<T: Config> =
StorageMap<_, Identity, u16, Vec<(T::AccountId, u64, u64)>, OptionQuery>;

#[pallet::storage] // --- DMAP ( netuid ) --> active
Expand Down
141 changes: 2 additions & 139 deletions pallets/subtensor/src/registration.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use super::*;
use frame_support::storage::IterableStorageDoubleMap;
use sp_core::{Get, H256, U256};
use sp_core::{H256, U256};
use sp_io::hashing::{keccak_256, sha2_256};
use sp_runtime::Saturating;
use system::pallet_prelude::BlockNumberFor;
Expand Down Expand Up @@ -395,7 +394,7 @@ impl<T: Config> Pallet<T> {
UsedWork::<T>::insert(work.clone(), current_block_number);

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

Self::add_balance_to_coldkey_account(&coldkey, balance_to_add);
Expand Down Expand Up @@ -591,140 +590,4 @@ impl<T: Config> Pallet<T> {
let vec_work: Vec<u8> = Self::hash_to_vec(work);
(nonce, vec_work)
}

pub fn do_swap_hotkey(
origin: T::RuntimeOrigin,
old_hotkey: &T::AccountId,
new_hotkey: &T::AccountId,
) -> DispatchResultWithPostInfo {
let coldkey = ensure_signed(origin)?;

let mut weight = T::DbWeight::get().reads_writes(2, 0);
ensure!(
Self::coldkey_owns_hotkey(&coldkey, old_hotkey),
Error::<T>::NonAssociatedColdKey
);

let block: u64 = Self::get_current_block_as_u64();
ensure!(
!Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&coldkey), block),
Error::<T>::HotKeySetTxRateLimitExceeded
);

weight.saturating_accrue(T::DbWeight::get().reads(2));

ensure!(old_hotkey != new_hotkey, Error::<T>::NewHotKeyIsSameWithOld);
ensure!(
!Self::is_hotkey_registered_on_any_network(new_hotkey),
Error::<T>::HotKeyAlreadyRegisteredInSubNet
);

weight.saturating_accrue(
T::DbWeight::get().reads((TotalNetworks::<T>::get().saturating_add(1)) as u64),
);

let swap_cost = 1_000_000_000u64;
ensure!(
Self::can_remove_balance_from_coldkey_account(&coldkey, swap_cost),
Error::<T>::NotEnoughBalanceToPaySwapHotKey
);
let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?;
Self::burn_tokens(actual_burn_amount);

Owner::<T>::remove(old_hotkey);
Owner::<T>::insert(new_hotkey, coldkey.clone());
weight.saturating_accrue(T::DbWeight::get().writes(2));

if let Ok(total_hotkey_stake) = TotalHotkeyStake::<T>::try_get(old_hotkey) {
TotalHotkeyStake::<T>::remove(old_hotkey);
TotalHotkeyStake::<T>::insert(new_hotkey, total_hotkey_stake);

weight.saturating_accrue(T::DbWeight::get().writes(2));
}

if let Ok(delegate_take) = Delegates::<T>::try_get(old_hotkey) {
Delegates::<T>::remove(old_hotkey);
Delegates::<T>::insert(new_hotkey, delegate_take);

weight.saturating_accrue(T::DbWeight::get().writes(2));
}

if let Ok(last_tx) = LastTxBlock::<T>::try_get(old_hotkey) {
LastTxBlock::<T>::remove(old_hotkey);
LastTxBlock::<T>::insert(new_hotkey, last_tx);

weight.saturating_accrue(T::DbWeight::get().writes(2));
}

let mut coldkey_stake: Vec<(T::AccountId, u64)> = vec![];
for (coldkey, stake_amount) in Stake::<T>::iter_prefix(old_hotkey) {
coldkey_stake.push((coldkey.clone(), stake_amount));
}

let _ = Stake::<T>::clear_prefix(old_hotkey, coldkey_stake.len() as u32, None);
weight.saturating_accrue(T::DbWeight::get().writes(coldkey_stake.len() as u64));

for (coldkey, stake_amount) in coldkey_stake {
Stake::<T>::insert(new_hotkey, coldkey, stake_amount);
weight.saturating_accrue(T::DbWeight::get().writes(1));
}

let mut netuid_is_member: Vec<u16> = vec![];
for netuid in <IsNetworkMember<T> as IterableStorageDoubleMap<T::AccountId, u16, bool>>::iter_key_prefix(old_hotkey) {
netuid_is_member.push(netuid);
}

let _ = IsNetworkMember::<T>::clear_prefix(old_hotkey, netuid_is_member.len() as u32, None);
weight.saturating_accrue(T::DbWeight::get().writes(netuid_is_member.len() as u64));

for netuid in netuid_is_member.iter() {
IsNetworkMember::<T>::insert(new_hotkey, netuid, true);
weight.saturating_accrue(T::DbWeight::get().writes(1));
}

for netuid in netuid_is_member.iter() {
if let Ok(axon_info) = Axons::<T>::try_get(netuid, old_hotkey) {
Axons::<T>::remove(netuid, old_hotkey);
Axons::<T>::insert(netuid, new_hotkey, axon_info);

weight.saturating_accrue(T::DbWeight::get().writes(2));
}
}

for netuid in netuid_is_member.iter() {
if let Ok(uid) = Uids::<T>::try_get(netuid, old_hotkey) {
Uids::<T>::remove(netuid, old_hotkey);
Uids::<T>::insert(netuid, new_hotkey, uid);

weight.saturating_accrue(T::DbWeight::get().writes(2));

Keys::<T>::insert(netuid, uid, new_hotkey);

weight.saturating_accrue(T::DbWeight::get().writes(1));

LoadedEmission::<T>::mutate(netuid, |emission_exists| match emission_exists {
Some(emissions) => {
if let Some(emission) = emissions.get_mut(uid as usize) {
let (_, se, ve) = emission;
*emission = (new_hotkey.clone(), *se, *ve);
}
}
None => {}
});

weight.saturating_accrue(T::DbWeight::get().writes(1));
}
}

Self::set_last_tx_block(&coldkey, block);
weight.saturating_accrue(T::DbWeight::get().writes(1));

Self::deposit_event(Event::HotkeySwapped {
coldkey,
old_hotkey: old_hotkey.clone(),
new_hotkey: new_hotkey.clone(),
});

Ok(Some(weight).into())
}
}
Loading
Loading