Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
1b0c63a
Merge pull request #1634 from opentensor/testnet
sam0x17 May 28, 2025
253d807
impl
camfairchild May 30, 2025
e43afcd
tests
camfairchild May 30, 2025
ec7303f
update comment
camfairchild May 30, 2025
423b3ce
fix tests
camfairchild May 30, 2025
f2d6939
Merge pull request #1706 from opentensor/fix/disabled-limit-staking-o…
sam0x17 Jun 10, 2025
619ef06
remove subnet exists check on validate_remove_stake
sam0x17 Jun 10, 2025
a69315b
whoops, wrong line
sam0x17 Jun 10, 2025
315dedc
fix test
sam0x17 Jun 10, 2025
5f552ae
clippy
sam0x17 Jun 10, 2025
4c9836f
Merge pull request #1732 from opentensor/sam-hotfix-hotfix
sam0x17 Jun 10, 2025
1b665ff
hotkey splitting emergency merge of #1559
sam0x17 Jun 14, 2025
0e914af
bump spec version
sam0x17 Jun 14, 2025
6c8df06
Merge pull request #1754 from opentensor/emergency-hotfix-6-14-2025
sam0x17 Jun 14, 2025
582ac00
move guard check for *any* sn reg
camfairchild Jun 14, 2025
0383198
add test
camfairchild Jun 14, 2025
4835953
move state change to after check
camfairchild Jun 14, 2025
248c579
fix test 1
camfairchild Jun 14, 2025
52a06bc
fix test 2
camfairchild Jun 14, 2025
55b3ea2
fix test 3
camfairchild Jun 14, 2025
f892a9c
Merge pull request #1755 from opentensor/fix/move-reg-check
sam0x17 Jun 14, 2025
5596574
add
camfairchild Jun 14, 2025
d7117b6
bump spec
camfairchild Jun 14, 2025
0e9f293
Merge pull request #1756 from opentensor/feat/add-swap-hk-proxy
sam0x17 Jun 14, 2025
4820fb2
cooldown
sam0x17 Jun 15, 2025
4b232d3
fix
sam0x17 Jun 16, 2025
3edbb98
fix: tests
distributedstatemachine Jun 16, 2025
f3c434b
fix: tests
distributedstatemachine Jun 16, 2025
a35e462
chore: clippy
distributedstatemachine Jun 16, 2025
bfeaf1c
bump spec version
sam0x17 Jun 16, 2025
586eb24
fix benchmark
open-junius Jun 16, 2025
0e99ff6
fix an error
open-junius Jun 16, 2025
17e48b2
fix benchmark
open-junius Jun 16, 2025
651b8be
fix benchmark
sam0x17 Jun 16, 2025
73094c9
Merge remote-tracking branch 'origin/hotfix-cooldown' into hotfix-coo…
sam0x17 Jun 16, 2025
18379a4
Merge pull request #1757 from opentensor/hotfix-cooldown
sam0x17 Jun 16, 2025
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
1 change: 1 addition & 0 deletions common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub enum ProxyType {
RootWeights,
ChildKeys,
SudoUncheckedSetCode,
SwapHotkey,
}

impl Default for ProxyType {
Expand Down
4 changes: 4 additions & 0 deletions pallets/admin-utils/src/tests/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ parameter_types! {
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 InitialKeySwapOnSubnetCost: u64 = 10_000_000;
pub const HotkeySwapOnSubnetInterval: u64 = 7 * 24 * 60 * 60 / 12; // 7 days
}

impl pallet_subtensor::Config for Test {
Expand Down Expand Up @@ -209,6 +211,8 @@ impl pallet_subtensor::Config for Test {
type InitialTaoWeight = InitialTaoWeight;
type InitialEmaPriceHalvingPeriod = InitialEmaPriceHalvingPeriod;
type DurationOfStartCall = DurationOfStartCall;
type KeySwapOnSubnetCost = InitialKeySwapOnSubnetCost;
type HotkeySwapOnSubnetInterval = HotkeySwapOnSubnetInterval;
}

#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
Expand Down
7 changes: 6 additions & 1 deletion pallets/subtensor/src/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1454,7 +1454,12 @@ mod pallet_benchmarks {
Subtensor::<T>::add_balance_to_coldkey_account(&coldkey, cost);

#[extrinsic_call]
_(RawOrigin::Signed(coldkey.clone()), old.clone(), new.clone());
_(
RawOrigin::Signed(coldkey.clone()),
old.clone(),
new.clone(),
None,
);
}

#[benchmark]
Expand Down
26 changes: 25 additions & 1 deletion pallets/subtensor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,19 @@ pub mod pallet {
OptionQuery,
>;

#[pallet::storage]
/// --- DMap ( netuid, coldkey ) --> blocknumber | last hotkey swap on network.
pub type LastHotkeySwapOnNetuid<T: Config> = StorageDoubleMap<
_,
Identity,
u16,
Blake2_128Concat,
T::AccountId,
u64,
ValueQuery,
DefaultZeroU64<T>,
>;

#[pallet::storage]
/// Ensures unique IDs for StakeJobs storage map
pub type NextStakeJobId<T> = StorageValue<_, u64, ValueQuery, DefaultZeroU64<T>>;
Expand Down Expand Up @@ -1702,6 +1715,17 @@ pub mod pallet {
#[pallet::storage] // --- Storage for migration run status
pub type HasMigrationRun<T: Config> = StorageMap<_, Identity, Vec<u8>, bool, ValueQuery>;

#[pallet::type_value]
/// Default value for pending childkey cooldown (settable by root, default 0)
pub fn DefaultPendingChildKeyCooldown<T: Config>() -> u64 {
0
}

#[pallet::storage]
/// Storage value for pending childkey cooldown, settable by root.
pub type PendingChildKeyCooldown<T: Config> =
StorageValue<_, u64, ValueQuery, DefaultPendingChildKeyCooldown<T>>;

#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
/// Stakes record in genesis.
Expand Down Expand Up @@ -1785,7 +1809,7 @@ pub mod pallet {
}

/// Ensure subtoken enalbed
pub fn ensure_subtoken_enabled(subnet: u16) -> DispatchResult {
pub fn ensure_subtoken_enabled(subnet: u16) -> Result<(), Error<T>> {
ensure!(
SubtokenEnabled::<T>::get(subnet),
Error::<T>::SubtokenDisabled
Expand Down
6 changes: 6 additions & 0 deletions pallets/subtensor/src/macros/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,5 +224,11 @@ mod config {
/// Block number after a new subnet accept the start call extrinsic.
#[pallet::constant]
type DurationOfStartCall: Get<u64>;
/// Cost of swapping a hotkey in a subnet.
#[pallet::constant]
type KeySwapOnSubnetCost: Get<u64>;
/// Block number for a coldkey swap the hotkey in specific subnet.
#[pallet::constant]
type HotkeySwapOnSubnetInterval: Get<u64>;
}
}
35 changes: 24 additions & 11 deletions pallets/subtensor/src/macros/dispatches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,11 +551,11 @@ mod dispatches {
Self::do_increase_take(origin, hotkey, take)
}

/// --- Adds stake to a hotkey. The call is made from the
/// coldkey account linked in the hotkey.
/// Only the associated coldkey is allowed to make staking and
/// unstaking requests. This protects the neuron against
/// attacks on its hotkey running in production code.
/// --- Adds stake to a hotkey. The call is made from a coldkey account.
/// This delegates stake to the hotkey.
///
/// Note: the coldkey account may own the hotkey, in which case they are
/// delegating to themselves.
///
/// # Args:
/// * 'origin': (<T as frame_system::Config>Origin):
Expand Down Expand Up @@ -935,17 +935,18 @@ mod dispatches {
Self::do_burned_registration(origin, netuid, hotkey)
}

/// The extrinsic for user to change its hotkey
/// The extrinsic for user to change its hotkey in subnet or all subnets.
#[pallet::call_index(70)]
#[pallet::weight((Weight::from_parts(240_600_000, 0)
.saturating_add(T::DbWeight::get().reads(31))
.saturating_add(T::DbWeight::get().writes(23)), DispatchClass::Operational, Pays::No))]
#[pallet::weight((Weight::from_parts(285_900_000, 0)
.saturating_add(T::DbWeight::get().reads(47))
.saturating_add(T::DbWeight::get().writes(37)), DispatchClass::Operational, Pays::No))]
pub fn swap_hotkey(
origin: OriginFor<T>,
hotkey: T::AccountId,
new_hotkey: T::AccountId,
netuid: Option<u16>,
) -> DispatchResultWithPostInfo {
Self::do_swap_hotkey(origin, &hotkey, &new_hotkey)
Self::do_swap_hotkey(origin, &hotkey, &new_hotkey, netuid)
}

/// The extrinsic for user to change the coldkey associated with their account.
Expand Down Expand Up @@ -1785,7 +1786,7 @@ mod dispatches {
///
#[pallet::call_index(88)]
#[pallet::weight((Weight::from_parts(159_200_000, 0)
.saturating_add(T::DbWeight::get().reads(13))
.saturating_add(T::DbWeight::get().reads(14))
.saturating_add(T::DbWeight::get().writes(10)), DispatchClass::Normal, Pays::No))]
pub fn add_stake_limit(
origin: OriginFor<T>,
Expand Down Expand Up @@ -2056,6 +2057,18 @@ mod dispatches {
Self::do_burn_alpha(origin, hotkey, amount, netuid)
}

/// Sets the pending childkey cooldown (in blocks). Root only.
#[pallet::call_index(109)]
#[pallet::weight((Weight::from_parts(10_000, 0), DispatchClass::Operational, Pays::No))]
pub fn set_pending_childkey_cooldown(
origin: OriginFor<T>,
cooldown: u64,
) -> DispatchResult {
ensure_root(origin)?;
PendingChildKeyCooldown::<T>::put(cooldown);
Ok(())
}

// /// --- Adds stake to a hotkey on a subnet with a price limit.
// /// This extrinsic allows to specify the limit price for alpha token
// /// at which or better (lower) the staking should execute.
Expand Down
2 changes: 2 additions & 0 deletions pallets/subtensor/src/macros/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ mod errors {
InvalidRecoveredPublicKey,
/// SubToken disabled now
SubtokenDisabled,
/// Too frequent hotkey swap on subnet
HotKeySwapOnSubnetIntervalNotPassed,
/// Zero max stake amount
ZeroMaxStakeAmount,
/// Invalid netuid duplication
Expand Down
12 changes: 12 additions & 0 deletions pallets/subtensor/src/macros/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,5 +351,17 @@ mod events {
/// - **netuid**: The network identifier.
/// - **Enabled**: Is Commit-Reveal enabled.
CommitRevealEnabled(u16, bool),

/// the hotkey is swapped
HotkeySwappedOnSubnet {
/// the account ID of coldkey
coldkey: T::AccountId,
/// the account ID of old hotkey
old_hotkey: T::AccountId,
/// the account ID of new hotkey
new_hotkey: T::AccountId,
/// the subnet ID
netuid: u16,
},
}
}
44 changes: 43 additions & 1 deletion pallets/subtensor/src/macros/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ mod hooks {
// # Args:
// * 'n': (BlockNumberFor<T>):
// - The number of the block we are initializing.
fn on_initialize(_block_number: BlockNumberFor<T>) -> Weight {
fn on_initialize(block_number: BlockNumberFor<T>) -> Weight {
let hotkey_swap_clean_up_weight = Self::clean_up_hotkey_swap_records(block_number);

let block_step_result = Self::block_step();
match block_step_result {
Ok(_) => {
Expand All @@ -23,13 +25,15 @@ mod hooks {
Weight::from_parts(110_634_229_000_u64, 0)
.saturating_add(T::DbWeight::get().reads(8304_u64))
.saturating_add(T::DbWeight::get().writes(110_u64))
.saturating_add(hotkey_swap_clean_up_weight)
}
Err(e) => {
// --- If the block step was unsuccessful, return the weight anyway.
log::error!("Error while stepping block: {:?}", e);
Weight::from_parts(110_634_229_000_u64, 0)
.saturating_add(T::DbWeight::get().reads(8304_u64))
.saturating_add(T::DbWeight::get().writes(110_u64))
.saturating_add(hotkey_swap_clean_up_weight)
}
}
}
Expand Down Expand Up @@ -127,4 +131,42 @@ mod hooks {
Ok(())
}
}

impl<T: Config> Pallet<T> {
// This function is to clean up the old hotkey swap records
// It just clean up for one subnet at a time, according to the block number
fn clean_up_hotkey_swap_records(block_number: BlockNumberFor<T>) -> Weight {
let mut weight = Weight::from_parts(0, 0);
let hotkey_swap_on_subnet_interval = T::HotkeySwapOnSubnetInterval::get();
let block_number: u64 = TryInto::try_into(block_number)
.ok()
.expect("blockchain will not exceed 2^64 blocks; QED.");
weight.saturating_accrue(T::DbWeight::get().reads(2_u64));

let netuids = Self::get_all_subnet_netuids();
weight.saturating_accrue(T::DbWeight::get().reads(netuids.len() as u64));

if let Some(slot) = block_number.checked_rem(hotkey_swap_on_subnet_interval) {
// only handle the subnet with the same residue as current block number by HotkeySwapOnSubnetInterval
for netuid in netuids.iter().filter(|netuid| {
(**netuid as u64).checked_rem(hotkey_swap_on_subnet_interval) == Some(slot)
}) {
// Iterate over all the coldkeys in the subnet
for (coldkey, swap_block_number) in
LastHotkeySwapOnNetuid::<T>::iter_prefix(netuid)
{
// Clean up out of date swap records
if swap_block_number.saturating_add(hotkey_swap_on_subnet_interval)
< block_number
{
LastHotkeySwapOnNetuid::<T>::remove(netuid, coldkey);
weight.saturating_accrue(T::DbWeight::get().writes(1_u64));
}
weight.saturating_accrue(T::DbWeight::get().reads(1_u64));
}
}
}
weight
}
}
}
3 changes: 1 addition & 2 deletions pallets/subtensor/src/staking/set_children.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use super::*;
use sp_core::Get;

impl<T: Config> Pallet<T> {
/// ---- The implementation for the extrinsic do_set_child_singular: Sets a single child.
Expand Down Expand Up @@ -123,7 +122,7 @@ impl<T: Config> Pallet<T> {

// Calculate cool-down block
let cooldown_block =
Self::get_current_block_as_u64().saturating_add(DefaultPendingCooldown::<T>::get());
Self::get_current_block_as_u64().saturating_add(PendingChildKeyCooldown::<T>::get());

// Insert or update PendingChildKeys
PendingChildKeys::<T>::insert(netuid, hotkey.clone(), (children.clone(), cooldown_block));
Expand Down
6 changes: 6 additions & 0 deletions pallets/subtensor/src/staking/stake_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,9 @@ impl<T: Config> Pallet<T> {
// Ensure that the subnet exists.
ensure!(Self::if_subnet_exist(netuid), Error::<T>::SubnetNotExists);

// Ensure that the subnet is enabled.
Self::ensure_subtoken_enabled(netuid)?;

// Get the minimum balance (and amount) that satisfies the transaction
let min_amount = DefaultMinStake::<T>::get().saturating_add(DefaultStakingFee::<T>::get());

Expand Down Expand Up @@ -964,6 +967,9 @@ impl<T: Config> Pallet<T> {
// Ensure that the subnet exists.
ensure!(Self::if_subnet_exist(netuid), Error::<T>::SubnetNotExists);

// Ensure that the subnet is enabled.
// Self::ensure_subtoken_enabled(netuid)?;

// Ensure that the stake amount to be removed is above the minimum in tao equivalent.
if let Some(tao_equivalent) = Self::sim_swap_alpha_for_tao(netuid, alpha_unstaked) {
ensure!(
Expand Down
6 changes: 6 additions & 0 deletions pallets/subtensor/src/subnets/uids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,4 +187,10 @@ impl<T: Config> Pallet<T> {
}
false
}

/// Return true if a hotkey is registered on specific network.
///
pub fn is_hotkey_registered_on_specific_network(hotkey: &T::AccountId, netuid: u16) -> bool {
IsNetworkMember::<T>::contains_key(hotkey, netuid)
}
}
Loading
Loading