Skip to content

Commit 1c3f4c9

Browse files
committed
Merge remote-tracking branch 'origin/hotfix/add-call-filter-for-nested-batches' into hotfix/add-call-filter-for-nested-batches
2 parents 3ba9333 + 54bf122 commit 1c3f4c9

File tree

3 files changed

+101
-0
lines changed

3 files changed

+101
-0
lines changed

pallets/subtensor/src/lib.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2045,6 +2045,20 @@ where
20452045
Self::get_priority_staking(who, hotkey, *amount_unstaked),
20462046
)
20472047
}
2048+
Some(Call::unstake_all { hotkey }) => {
2049+
// Fully validate the user input
2050+
Self::result_to_validity(
2051+
Pallet::<T>::validate_unstake_all(who, hotkey, false),
2052+
Self::get_priority_vanilla(),
2053+
)
2054+
}
2055+
Some(Call::unstake_all_alpha { hotkey }) => {
2056+
// Fully validate the user input
2057+
Self::result_to_validity(
2058+
Pallet::<T>::validate_unstake_all(who, hotkey, true),
2059+
Self::get_priority_vanilla(),
2060+
)
2061+
}
20482062
Some(Call::move_stake {
20492063
origin_hotkey,
20502064
destination_hotkey,

pallets/subtensor/src/staking/stake_utils.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,42 @@ impl<T: Config> Pallet<T> {
987987
Ok(())
988988
}
989989

990+
/// Validate if unstake_all can be executed
991+
///
992+
pub fn validate_unstake_all(
993+
coldkey: &T::AccountId,
994+
hotkey: &T::AccountId,
995+
only_alpha: bool,
996+
) -> Result<(), Error<T>> {
997+
// Get all netuids (filter out root)
998+
let subnets: Vec<u16> = Self::get_all_subnet_netuids();
999+
1000+
// Ensure that the hotkey account exists this is only possible through registration.
1001+
ensure!(
1002+
Self::hotkey_account_exists(hotkey),
1003+
Error::<T>::HotKeyAccountNotExists
1004+
);
1005+
1006+
let mut unstaking_any = false;
1007+
for netuid in subnets.iter() {
1008+
if only_alpha && (*netuid == Self::get_root_netuid()) {
1009+
continue;
1010+
}
1011+
1012+
// Get user's stake in this subnet
1013+
let alpha = Self::get_stake_for_hotkey_and_coldkey_on_subnet(hotkey, coldkey, *netuid);
1014+
1015+
if Self::validate_remove_stake(coldkey, hotkey, *netuid, alpha, alpha, false).is_ok() {
1016+
unstaking_any = true;
1017+
}
1018+
}
1019+
1020+
// If no unstaking happens, return error
1021+
ensure!(unstaking_any, Error::<T>::AmountTooLow);
1022+
1023+
Ok(())
1024+
}
1025+
9901026
/// Validate stake transition user input
9911027
/// That works for move_stake, transfer_stake, and swap_stake
9921028
///

pallets/subtensor/src/tests/staking.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2836,6 +2836,57 @@ fn test_unstake_low_liquidity_validate() {
28362836
});
28372837
}
28382838

2839+
#[test]
2840+
fn test_unstake_all_validate() {
2841+
// Testing the signed extension validate function
2842+
// correctly filters the `unstake_all` transaction.
2843+
2844+
new_test_ext(0).execute_with(|| {
2845+
let subnet_owner_coldkey = U256::from(1001);
2846+
let subnet_owner_hotkey = U256::from(1002);
2847+
let hotkey = U256::from(2);
2848+
let coldkey = U256::from(3);
2849+
let amount_staked = DefaultMinStake::<Test>::get() * 10 + DefaultStakingFee::<Test>::get();
2850+
2851+
let netuid = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
2852+
SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey);
2853+
SubtensorModule::add_balance_to_coldkey_account(&coldkey, amount_staked);
2854+
2855+
// Simulate stake for hotkey
2856+
SubnetTAO::<Test>::insert(netuid, u64::MAX / 1000);
2857+
SubnetAlphaIn::<Test>::insert(netuid, u64::MAX / 1000);
2858+
SubtensorModule::stake_into_subnet(&hotkey, &coldkey, netuid, amount_staked, 0);
2859+
2860+
// Set the liquidity at lowest possible value so that all staking requests fail
2861+
SubnetTAO::<Test>::insert(
2862+
netuid,
2863+
DefaultMinimumPoolLiquidity::<Test>::get().to_num::<u64>(),
2864+
);
2865+
SubnetAlphaIn::<Test>::insert(
2866+
netuid,
2867+
DefaultMinimumPoolLiquidity::<Test>::get().to_num::<u64>(),
2868+
);
2869+
2870+
// unstake_all call
2871+
let call = RuntimeCall::SubtensorModule(SubtensorCall::unstake_all { hotkey });
2872+
2873+
let info: DispatchInfo =
2874+
DispatchInfoOf::<<Test as frame_system::Config>::RuntimeCall>::default();
2875+
2876+
let extension = SubtensorSignedExtension::<Test>::new();
2877+
// Submit to the signed extension validate function
2878+
let result_no_stake = extension.validate(&coldkey, &call.clone(), &info, 10);
2879+
2880+
// Should fail due to insufficient stake
2881+
assert_err!(
2882+
result_no_stake,
2883+
TransactionValidityError::Invalid(InvalidTransaction::Custom(
2884+
CustomTransactionError::StakeAmountTooLow.into()
2885+
))
2886+
);
2887+
});
2888+
}
2889+
28392890
#[test]
28402891
fn test_max_amount_add_root() {
28412892
new_test_ext(0).execute_with(|| {

0 commit comments

Comments
 (0)