Skip to content

Commit 38828bd

Browse files
authored
Merge pull request #1314 from opentensor/fix/share-pool-precision
Prevent precision errors in share pool
2 parents eecd43a + f2d4b4f commit 38828bd

File tree

5 files changed

+422
-130
lines changed

5 files changed

+422
-130
lines changed

pallets/subtensor/src/staking/stake_utils.rs

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -544,9 +544,10 @@ impl<T: Config> Pallet<T> {
544544
coldkey: &T::AccountId,
545545
netuid: u16,
546546
amount: u64,
547-
) {
547+
) -> u64 {
548548
let mut alpha_share_pool = Self::get_alpha_share_pool(hotkey.clone(), netuid);
549-
alpha_share_pool.update_value_for_one(coldkey, amount as i64);
549+
let actual_alpha = alpha_share_pool.update_value_for_one(coldkey, amount as i64);
550+
actual_alpha.unsigned_abs()
550551
}
551552

552553
pub fn try_increase_stake_for_hotkey_and_coldkey_on_subnet(
@@ -573,13 +574,16 @@ impl<T: Config> Pallet<T> {
573574
coldkey: &T::AccountId,
574575
netuid: u16,
575576
amount: u64,
576-
) {
577+
) -> u64 {
577578
let mut alpha_share_pool = Self::get_alpha_share_pool(hotkey.clone(), netuid);
579+
let mut actual_alpha = 0;
578580
if let Ok(value) = alpha_share_pool.try_get_value(coldkey) {
579581
if value >= amount {
580-
alpha_share_pool.update_value_for_one(coldkey, (amount as i64).neg());
582+
actual_alpha =
583+
alpha_share_pool.update_value_for_one(coldkey, (amount as i64).neg());
581584
}
582585
}
586+
actual_alpha.unsigned_abs()
583587
}
584588

585589
/// Calculates Some(Alpha) returned from pool by staking operation
@@ -735,11 +739,12 @@ impl<T: Config> Pallet<T> {
735739
alpha: u64,
736740
fee: u64,
737741
) -> u64 {
738-
// Step 1: Swap the alpha for TAO.
739-
let tao: u64 = Self::swap_alpha_for_tao(netuid, alpha);
742+
// Step 1: Decrease alpha on subneet
743+
let actual_alpha_decrease =
744+
Self::decrease_stake_for_hotkey_and_coldkey_on_subnet(hotkey, coldkey, netuid, alpha);
740745

741-
// Step 2: Decrease alpha on subneet
742-
Self::decrease_stake_for_hotkey_and_coldkey_on_subnet(hotkey, coldkey, netuid, alpha);
746+
// Step 2: Swap the alpha for TAO.
747+
let tao: u64 = Self::swap_alpha_for_tao(netuid, actual_alpha_decrease);
743748

744749
// Step 3: Update StakingHotkeys if the hotkey's total alpha, across all subnets, is zero
745750
// TODO const: fix.
@@ -765,15 +770,15 @@ impl<T: Config> Pallet<T> {
765770
coldkey.clone(),
766771
hotkey.clone(),
767772
tao_unstaked,
768-
alpha,
773+
actual_alpha_decrease,
769774
netuid,
770775
));
771776
log::info!(
772777
"StakeRemoved( coldkey: {:?}, hotkey:{:?}, tao: {:?}, alpha:{:?}, netuid: {:?} )",
773778
coldkey.clone(),
774779
hotkey.clone(),
775780
tao_unstaked,
776-
alpha,
781+
actual_alpha_decrease,
777782
netuid
778783
);
779784

@@ -799,9 +804,12 @@ impl<T: Config> Pallet<T> {
799804

800805
// Step 2. Swap the tao to alpha.
801806
let alpha: u64 = Self::swap_tao_for_alpha(netuid, tao_staked);
807+
let mut actual_alpha = 0;
802808
if (tao_staked > 0) && (alpha > 0) {
803809
// Step 3: Increase the alpha on the hotkey account.
804-
Self::increase_stake_for_hotkey_and_coldkey_on_subnet(hotkey, coldkey, netuid, alpha);
810+
actual_alpha = Self::increase_stake_for_hotkey_and_coldkey_on_subnet(
811+
hotkey, coldkey, netuid, alpha,
812+
);
805813

806814
// Step 4: Update the list of hotkeys staking for this coldkey
807815
let mut staking_hotkeys = StakingHotkeys::<T>::get(coldkey);
@@ -825,20 +833,20 @@ impl<T: Config> Pallet<T> {
825833
coldkey.clone(),
826834
hotkey.clone(),
827835
tao_staked,
828-
alpha,
836+
actual_alpha,
829837
netuid,
830838
));
831839
log::info!(
832840
"StakeAdded( coldkey: {:?}, hotkey:{:?}, tao: {:?}, alpha:{:?}, netuid: {:?} )",
833841
coldkey.clone(),
834842
hotkey.clone(),
835843
tao_staked,
836-
alpha,
844+
actual_alpha,
837845
netuid
838846
);
839847

840848
// Step 7: Return the amount of alpha staked
841-
alpha
849+
actual_alpha
842850
}
843851

844852
pub fn get_alpha_share_pool(

pallets/subtensor/src/tests/move_stake.rs

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::*;
33
use approx::assert_abs_diff_eq;
44
use frame_support::{assert_err, assert_noop, assert_ok};
55
use sp_core::{Get, U256};
6-
use substrate_fixed::types::I96F32;
6+
use substrate_fixed::types::{I96F32, U64F64};
77

88
// 1. test_do_move_success
99
// Description: Test a successful move of stake between two hotkeys in the same subnet
@@ -1641,3 +1641,112 @@ fn test_stake_transfers_disabled_validate() {
16411641
assert_ok!(result3);
16421642
});
16431643
}
1644+
1645+
#[test]
1646+
// RUST_LOG=info cargo test --package pallet-subtensor --lib -- tests::staking::test_move_stake_specific_stake_into_subnet_fail --exact --show-output
1647+
fn test_move_stake_specific_stake_into_subnet_fail() {
1648+
new_test_ext(1).execute_with(|| {
1649+
let sn_owner_coldkey = U256::from(55453);
1650+
1651+
let hotkey_account_id = U256::from(533453);
1652+
let coldkey_account_id = U256::from(55454);
1653+
let hotkey_owner_account_id = U256::from(533454);
1654+
1655+
let existing_shares: U64F64 =
1656+
U64F64::from_num(161_986_254).saturating_div(U64F64::from_num(u64::MAX));
1657+
let existing_stake = 36_711_495_953;
1658+
1659+
let tao_in = 2_409_892_148_947;
1660+
let alpha_in = 15_358_708_513_716;
1661+
1662+
let tao_staked = 200_000_000;
1663+
1664+
//add network
1665+
let netuid: u16 = add_dynamic_network(&sn_owner_coldkey, &sn_owner_coldkey);
1666+
1667+
let origin_netuid: u16 = add_dynamic_network(&sn_owner_coldkey, &sn_owner_coldkey);
1668+
1669+
// Register hotkey on netuid
1670+
register_ok_neuron(netuid, hotkey_account_id, hotkey_owner_account_id, 0);
1671+
// Register hotkey on origin netuid
1672+
register_ok_neuron(origin_netuid, hotkey_account_id, hotkey_owner_account_id, 0);
1673+
1674+
// Check we have zero staked
1675+
assert_eq!(
1676+
SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id),
1677+
0
1678+
);
1679+
1680+
// Set a hotkey pool for the hotkey on destination subnet
1681+
let mut hotkey_pool = SubtensorModule::get_alpha_share_pool(hotkey_account_id, netuid);
1682+
hotkey_pool.update_value_for_one(&hotkey_owner_account_id, 1234); // Doesn't matter, will be overridden
1683+
1684+
// Adjust the total hotkey stake and shares to match the existing values
1685+
TotalHotkeyShares::<Test>::insert(hotkey_account_id, netuid, existing_shares);
1686+
TotalHotkeyAlpha::<Test>::insert(hotkey_account_id, netuid, existing_stake);
1687+
1688+
// Make the hotkey a delegate
1689+
Delegates::<Test>::insert(hotkey_account_id, 0);
1690+
1691+
// Setup Subnet pool
1692+
SubnetAlphaIn::<Test>::insert(netuid, alpha_in);
1693+
SubnetTAO::<Test>::insert(netuid, tao_in);
1694+
1695+
// Give TAO balance to coldkey
1696+
SubtensorModule::add_balance_to_coldkey_account(
1697+
&coldkey_account_id,
1698+
tao_staked + 1_000_000_000,
1699+
);
1700+
1701+
// Setup Subnet pool for origin netuid
1702+
SubnetAlphaIn::<Test>::insert(origin_netuid, alpha_in + 10_000_000);
1703+
SubnetTAO::<Test>::insert(origin_netuid, tao_in + 10_000_000);
1704+
1705+
// Add stake as new hotkey
1706+
assert_ok!(SubtensorModule::add_stake(
1707+
RuntimeOrigin::signed(coldkey_account_id),
1708+
hotkey_account_id,
1709+
origin_netuid,
1710+
tao_staked,
1711+
),);
1712+
let alpha_to_move = SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
1713+
&hotkey_account_id,
1714+
&coldkey_account_id,
1715+
origin_netuid,
1716+
);
1717+
1718+
// Move stake to destination subnet
1719+
assert_ok!(SubtensorModule::move_stake(
1720+
RuntimeOrigin::signed(coldkey_account_id),
1721+
hotkey_account_id,
1722+
hotkey_account_id,
1723+
origin_netuid,
1724+
netuid,
1725+
alpha_to_move,
1726+
));
1727+
1728+
// Check that the stake has been moved
1729+
assert_eq!(
1730+
SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
1731+
&hotkey_account_id,
1732+
&coldkey_account_id,
1733+
origin_netuid
1734+
),
1735+
0
1736+
);
1737+
let fee = DefaultStakingFee::<Test>::get();
1738+
let alpha_fee: I96F32 = I96F32::from_num(fee) / SubtensorModule::get_alpha_price(netuid);
1739+
let expected_value = I96F32::from_num(alpha_to_move)
1740+
* SubtensorModule::get_alpha_price(origin_netuid)
1741+
/ SubtensorModule::get_alpha_price(netuid);
1742+
assert_abs_diff_eq!(
1743+
SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(
1744+
&hotkey_account_id,
1745+
&coldkey_account_id,
1746+
netuid
1747+
),
1748+
(expected_value - alpha_fee).to_num::<u64>(),
1749+
epsilon = (expected_value / 1000).to_num::<u64>()
1750+
);
1751+
});
1752+
}

0 commit comments

Comments
 (0)