Skip to content

Commit 054e680

Browse files
authored
Merge pull request #361 from opentensor/hotfix/min-nom-stake
hotfix: minimum nominator stake
2 parents 76aabe5 + bfd67c8 commit 054e680

File tree

10 files changed

+681
-45
lines changed

10 files changed

+681
-45
lines changed

pallets/admin-utils/src/lib.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ pub mod pallet {
5353
}
5454

5555
#[pallet::event]
56-
#[pallet::generate_deposit(pub(super) fn deposit_event)]
5756
pub enum Event<T: Config> {}
5857

5958
// Errors inform users that something went wrong.
@@ -765,6 +764,27 @@ pub mod pallet {
765764
T::Subtensor::set_weights_min_stake(min_stake);
766765
Ok(())
767766
}
767+
768+
/// Sets the minimum stake required for nominators, and clears small nominations
769+
/// that are below the minimum required stake.
770+
#[pallet::call_index(43)]
771+
#[pallet::weight((0, DispatchClass::Operational, Pays::No))]
772+
pub fn sudo_set_nominator_min_required_stake(
773+
origin: OriginFor<T>,
774+
// The minimum stake required for nominators.
775+
min_stake: u64,
776+
) -> DispatchResult {
777+
ensure_root(origin)?;
778+
let prev_min_stake = T::Subtensor::get_nominator_min_required_stake();
779+
log::trace!("Setting minimum stake to: {}", min_stake);
780+
T::Subtensor::set_nominator_min_required_stake(min_stake);
781+
if min_stake > prev_min_stake {
782+
log::trace!("Clearing small nominations");
783+
T::Subtensor::clear_small_nominations();
784+
log::trace!("Small nominations cleared");
785+
}
786+
Ok(())
787+
}
768788
}
769789
}
770790

@@ -853,4 +873,7 @@ pub trait SubtensorInterface<AccountId, Balance, RuntimeOrigin> {
853873
fn set_weights_set_rate_limit(netuid: u16, weights_set_rate_limit: u64);
854874
fn init_new_network(netuid: u16, tempo: u16);
855875
fn set_weights_min_stake(min_stake: u64);
876+
fn get_nominator_min_required_stake() -> u64;
877+
fn set_nominator_min_required_stake(min_stake: u64);
878+
fn clear_small_nominations();
856879
}

pallets/admin-utils/tests/mock.rs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use frame_support::{
2-
parameter_types,
2+
assert_ok, parameter_types,
33
traits::{Everything, Hooks, StorageMapShim},
44
weights,
55
};
@@ -436,6 +436,18 @@ impl pallet_admin_utils::SubtensorInterface<AccountId, Balance, RuntimeOrigin> f
436436
fn set_weights_min_stake(min_stake: u64) {
437437
SubtensorModule::set_weights_min_stake(min_stake);
438438
}
439+
440+
fn set_nominator_min_required_stake(min_stake: u64) {
441+
SubtensorModule::set_nominator_min_required_stake(min_stake);
442+
}
443+
444+
fn get_nominator_min_required_stake() -> u64 {
445+
SubtensorModule::get_nominator_min_required_stake()
446+
}
447+
448+
fn clear_small_nominations() {
449+
SubtensorModule::clear_small_nominations();
450+
}
439451
}
440452

441453
impl pallet_admin_utils::Config for Test {
@@ -467,3 +479,42 @@ pub(crate) fn run_to_block(n: u64) {
467479
SubtensorModule::on_initialize(System::block_number());
468480
}
469481
}
482+
483+
#[allow(dead_code)]
484+
pub fn register_ok_neuron(
485+
netuid: u16,
486+
hotkey_account_id: U256,
487+
coldkey_account_id: U256,
488+
start_nonce: u64,
489+
) {
490+
let block_number: u64 = SubtensorModule::get_current_block_as_u64();
491+
let (nonce, work): (u64, Vec<u8>) = SubtensorModule::create_work_for_block_number(
492+
netuid,
493+
block_number,
494+
start_nonce,
495+
&hotkey_account_id,
496+
);
497+
let result = SubtensorModule::register(
498+
<<Test as frame_system::Config>::RuntimeOrigin>::signed(hotkey_account_id),
499+
netuid,
500+
block_number,
501+
nonce,
502+
work,
503+
hotkey_account_id,
504+
coldkey_account_id,
505+
);
506+
assert_ok!(result);
507+
log::info!(
508+
"Register ok neuron: netuid: {:?}, coldkey: {:?}, hotkey: {:?}",
509+
netuid,
510+
hotkey_account_id,
511+
coldkey_account_id
512+
);
513+
}
514+
515+
#[allow(dead_code)]
516+
pub fn add_network(netuid: u16, tempo: u16, _modality: u16) {
517+
SubtensorModule::init_new_network(netuid, tempo);
518+
SubtensorModule::set_network_registration_allowed(netuid, true);
519+
SubtensorModule::set_network_pow_registration_allowed(netuid, true);
520+
}

pallets/admin-utils/tests/tests.rs

Lines changed: 184 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,6 @@ use sp_core::U256;
88
mod mock;
99
use mock::*;
1010

11-
#[allow(dead_code)]
12-
pub fn add_network(netuid: u16, tempo: u16, modality: u16) {
13-
SubtensorModule::init_new_network(netuid, tempo);
14-
SubtensorModule::set_network_registration_allowed(netuid, true);
15-
SubtensorModule::set_network_pow_registration_allowed(netuid, true);
16-
}
17-
1811
#[test]
1912
fn test_sudo_set_default_take() {
2013
new_test_ext().execute_with(|| {
@@ -884,3 +877,187 @@ fn test_sudo_set_network_pow_registration_allowed() {
884877
);
885878
});
886879
}
880+
881+
mod sudo_set_nominator_min_required_stake {
882+
use super::*;
883+
884+
#[test]
885+
fn can_only_be_called_by_admin() {
886+
new_test_ext().execute_with(|| {
887+
let to_be_set: u64 = SubtensorModule::get_nominator_min_required_stake() + 5 as u64;
888+
assert_eq!(
889+
AdminUtils::sudo_set_nominator_min_required_stake(
890+
<<Test as Config>::RuntimeOrigin>::signed(U256::from(0)),
891+
to_be_set
892+
),
893+
Err(DispatchError::BadOrigin.into())
894+
);
895+
});
896+
}
897+
898+
#[test]
899+
fn sets_a_lower_value() {
900+
new_test_ext().execute_with(|| {
901+
let to_be_set: u64 = SubtensorModule::get_nominator_min_required_stake() - 5 as u64;
902+
assert_ok!(AdminUtils::sudo_set_nominator_min_required_stake(
903+
<<Test as Config>::RuntimeOrigin>::root(),
904+
to_be_set
905+
));
906+
assert_eq!(
907+
SubtensorModule::get_nominator_min_required_stake(),
908+
to_be_set
909+
);
910+
});
911+
}
912+
913+
#[test]
914+
fn sets_a_higher_value() {
915+
new_test_ext().execute_with(|| {
916+
let to_be_set: u64 = SubtensorModule::get_nominator_min_required_stake() + 5 as u64;
917+
assert_ok!(AdminUtils::sudo_set_nominator_min_required_stake(
918+
<<Test as Config>::RuntimeOrigin>::root(),
919+
to_be_set
920+
));
921+
assert_eq!(
922+
SubtensorModule::get_nominator_min_required_stake(),
923+
to_be_set
924+
);
925+
});
926+
}
927+
928+
#[test]
929+
fn clears_staker_nominations_below_min() {
930+
new_test_ext().execute_with(|| {
931+
System::set_block_number(1);
932+
933+
// Create accounts.
934+
let netuid = 1;
935+
let hot1 = U256::from(1);
936+
let hot2 = U256::from(2);
937+
let cold1 = U256::from(3);
938+
let cold2 = U256::from(4);
939+
940+
SubtensorModule::set_target_stakes_per_interval(10);
941+
// Register network.
942+
add_network(netuid, 0, 0);
943+
944+
// Register hot1.
945+
register_ok_neuron(netuid, hot1, cold1, 0);
946+
assert_ok!(SubtensorModule::do_become_delegate(
947+
<<Test as Config>::RuntimeOrigin>::signed(cold1),
948+
hot1,
949+
0
950+
));
951+
assert_eq!(SubtensorModule::get_owning_coldkey_for_hotkey(&hot1), cold1);
952+
953+
// Register hot2.
954+
register_ok_neuron(netuid, hot2, cold2, 0);
955+
assert_ok!(SubtensorModule::do_become_delegate(
956+
<<Test as Config>::RuntimeOrigin>::signed(cold2),
957+
hot2,
958+
0
959+
));
960+
assert_eq!(SubtensorModule::get_owning_coldkey_for_hotkey(&hot2), cold2);
961+
962+
// Add stake cold1 --> hot1 (non delegation.)
963+
SubtensorModule::add_balance_to_coldkey_account(&cold1, 5);
964+
assert_ok!(SubtensorModule::add_stake(
965+
<<Test as Config>::RuntimeOrigin>::signed(cold1),
966+
hot1,
967+
1
968+
));
969+
assert_eq!(
970+
SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot1),
971+
1
972+
);
973+
assert_eq!(Balances::free_balance(cold1), 4);
974+
975+
// Add stake cold2 --> hot1 (is delegation.)
976+
SubtensorModule::add_balance_to_coldkey_account(&cold2, 5);
977+
assert_ok!(SubtensorModule::add_stake(
978+
<<Test as Config>::RuntimeOrigin>::signed(cold2),
979+
hot1,
980+
1
981+
));
982+
assert_eq!(
983+
SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot1),
984+
1
985+
);
986+
assert_eq!(Balances::free_balance(cold2), 4);
987+
988+
// Add stake cold1 --> hot2 (non delegation.)
989+
SubtensorModule::add_balance_to_coldkey_account(&cold1, 5);
990+
assert_ok!(SubtensorModule::add_stake(
991+
<<Test as Config>::RuntimeOrigin>::signed(cold1),
992+
hot2,
993+
1
994+
));
995+
assert_eq!(
996+
SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot2),
997+
1
998+
);
999+
assert_eq!(Balances::free_balance(cold1), 8);
1000+
1001+
// Add stake cold2 --> hot2 (is delegation.)
1002+
SubtensorModule::add_balance_to_coldkey_account(&cold2, 5);
1003+
assert_ok!(SubtensorModule::add_stake(
1004+
<<Test as Config>::RuntimeOrigin>::signed(cold2),
1005+
hot2,
1006+
1
1007+
));
1008+
assert_eq!(
1009+
SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot2),
1010+
1
1011+
);
1012+
assert_eq!(Balances::free_balance(cold2), 8);
1013+
1014+
// Set min stake to 0 (noop)
1015+
assert_ok!(AdminUtils::sudo_set_nominator_min_required_stake(
1016+
<<Test as Config>::RuntimeOrigin>::root(),
1017+
0u64
1018+
));
1019+
assert_eq!(
1020+
SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot1),
1021+
1
1022+
);
1023+
assert_eq!(
1024+
SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot2),
1025+
1
1026+
);
1027+
assert_eq!(
1028+
SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot1),
1029+
1
1030+
);
1031+
assert_eq!(
1032+
SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot2),
1033+
1
1034+
);
1035+
1036+
// Set min nomination to 10: should clear (cold2, hot1) and (cold1, hot2).
1037+
assert_ok!(AdminUtils::sudo_set_nominator_min_required_stake(
1038+
<<Test as Config>::RuntimeOrigin>::root(),
1039+
10u64
1040+
));
1041+
assert_eq!(
1042+
SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot1),
1043+
1
1044+
);
1045+
assert_eq!(
1046+
SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot2),
1047+
0
1048+
);
1049+
assert_eq!(
1050+
SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot1),
1051+
0
1052+
);
1053+
assert_eq!(
1054+
SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot2),
1055+
1
1056+
);
1057+
1058+
// Balances have been added back into accounts.
1059+
assert_eq!(Balances::free_balance(cold1), 9);
1060+
assert_eq!(Balances::free_balance(cold2), 9);
1061+
});
1062+
}
1063+
}

pallets/subtensor/src/lib.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,10 @@ pub mod pallet {
404404
0
405405
}
406406
#[pallet::type_value]
407+
pub fn DefaultNominatorMinRequiredStake<T: Config>() -> u64 {
408+
0
409+
}
410+
#[pallet::type_value]
407411
pub fn DefaultNetworkMinAllowedUids<T: Config>() -> u16 {
408412
T::InitialNetworkMinAllowedUids::get()
409413
}
@@ -484,6 +488,9 @@ pub mod pallet {
484488
pub type SubnetOwnerCut<T> = StorageValue<_, u16, ValueQuery, DefaultSubnetOwnerCut<T>>;
485489
#[pallet::storage] // ITEM( network_rate_limit )
486490
pub type NetworkRateLimit<T> = StorageValue<_, u64, ValueQuery, DefaultNetworkRateLimit<T>>;
491+
#[pallet::storage] // ITEM( nominator_min_required_stake )
492+
pub type NominatorMinRequiredStake<T> =
493+
StorageValue<_, u64, ValueQuery, DefaultNominatorMinRequiredStake<T>>;
487494

488495
// ==============================
489496
// ==== Subnetwork Features =====
@@ -974,6 +981,8 @@ pub mod pallet {
974981
StakeTooLowForRoot, // --- Thrown when a hotkey attempts to join the root subnet with too little stake
975982
AllNetworksInImmunity, // --- Thrown when all subnets are in the immunity period
976983
NotEnoughBalance,
984+
/// Thrown a stake would be below the minimum threshold for nominator validations
985+
NomStakeBelowMinimumThreshold,
977986
}
978987

979988
// ==================
@@ -1000,8 +1009,6 @@ pub mod pallet {
10001009
#[pallet::genesis_build]
10011010
impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
10021011
fn build(&self) {
1003-
use crate::MemberManagement;
1004-
10051012
// Set initial total issuance from balances
10061013
TotalIssuance::<T>::put(self.balances_issuance);
10071014

@@ -1714,7 +1721,7 @@ pub mod pallet {
17141721
pub fn get_priority_set_weights(hotkey: &T::AccountId, netuid: u16) -> u64 {
17151722
if Uids::<T>::contains_key(netuid, &hotkey) {
17161723
let uid = Self::get_uid_for_net_and_hotkey(netuid, &hotkey.clone()).unwrap();
1717-
let stake = Self::get_total_stake_for_hotkey(&hotkey);
1724+
let _stake = Self::get_total_stake_for_hotkey(&hotkey);
17181725
let current_block_number: u64 = Self::get_current_block_as_u64();
17191726
let default_priority: u64 =
17201727
current_block_number - Self::get_last_update_for_uid(netuid, uid as u16);

0 commit comments

Comments
 (0)