Skip to content
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

Feat/record initial subnet tao in totalstake #1428

Merged
merged 10 commits into from
Mar 19, 2025
2 changes: 1 addition & 1 deletion .github/workflows/try-runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:

check-finney:
name: check finney
if: github.base_ref == 'testnet' || github.base_ref == 'devnet' || github.base_ref == 'main'
# if: github.base_ref == 'testnet' || github.base_ref == 'devnet' || github.base_ref == 'main'
runs-on: SubtensorCI
steps:
- name: Checkout sources
Expand Down
36 changes: 30 additions & 6 deletions pallets/subtensor/src/migrations/migrate_dissolve_sn73.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ pub fn migrate_dissolve_sn73<T: Config>() -> Weight {
weight = weight.saturating_add(T::DbWeight::get().reads(1));
log::debug!("Subnet TAO: {}", subnet_tao);

// Adjust total stake and total issuance
TotalStake::<T>::mutate(|total| {
*total = total.saturating_sub(subnet_tao.saturating_to_num::<u64>());
});
TotalIssuance::<T>::mutate(|total| {
*total = total.saturating_sub(subnet_tao.saturating_to_num::<u64>());
});
weight = weight.saturating_add(T::DbWeight::get().reads_writes(2, 2));

// Record for total issuance tracking
let mut total_swapped: u64 = 0;

let mut total_alpha: I96F32 = I96F32::from_num(0);
// Iterate over every hotkey and sum up the total alpha
let mut hotkeys_to_remove: Vec<T::AccountId> = Vec::new();
Expand Down Expand Up @@ -96,6 +108,7 @@ pub fn migrate_dissolve_sn73<T: Config>() -> Weight {

if as_tao > 0 {
Pallet::<T>::add_balance_to_coldkey_account(&coldkey, as_tao);
total_swapped = total_swapped.saturating_add(as_tao);
weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1));

// Emit event
Expand All @@ -115,6 +128,23 @@ pub fn migrate_dissolve_sn73<T: Config>() -> Weight {
}
}

// Update total issuance
TotalIssuance::<T>::mutate(|v| *v = v.saturating_add(total_swapped));
weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1));

// Verify total issuance change is correct
if subnet_tao
.saturating_to_num::<u64>()
.abs_diff(total_swapped)
>= 100_000
{
log::info!(
"Total issuance change is incorrect: {} != {}",
subnet_tao.saturating_to_num::<u64>(),
total_swapped
);
}

// === Clear storage entries ===
// Clear subnet owner and hotkey
SubnetOwner::<T>::remove(this_netuid);
Expand Down Expand Up @@ -154,12 +184,6 @@ pub fn migrate_dissolve_sn73<T: Config>() -> Weight {
let clear_results_1 = TaoDividendsPerSubnet::<T>::clear_prefix(this_netuid, u32::MAX, None);
weight = weight.saturating_add(T::DbWeight::get().writes(clear_results_1.unique.into()));

// Adjust total stake
TotalStake::<T>::mutate(|total| {
*total = total.saturating_sub(subnet_tao.saturating_to_num::<u64>());
});
weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1));

// Clear subnet volume
SubnetVolume::<T>::remove(this_netuid);
weight = weight.saturating_add(T::DbWeight::get().writes(1));
Expand Down
23 changes: 15 additions & 8 deletions pallets/subtensor/src/migrations/migrate_init_total_issuance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,33 @@ pub mod deprecated_loaded_emission_format {
}

pub(crate) fn migrate_init_total_issuance<T: Config>() -> Weight {
// Calculate the total locked tokens across all subnets
let subnets_len = crate::SubnetLocked::<T>::iter().count() as u64;
let total_subnet_locked: u64 =
crate::SubnetLocked::<T>::iter().fold(0, |acc, (_, v)| acc.saturating_add(v));

// Retrieve the total balance of all accounts
let total_account_balances = <<T as crate::Config>::Currency as fungible::Inspect<
<T as frame_system::Config>::AccountId,
>>::total_issuance();

// Get the total stake from the system
let total_stake = crate::TotalStake::<T>::get();
let prev_total_stake = crate::TotalStake::<T>::get();

// Calculate new total stake using the sum of all subnet TAO
let total_subnet_tao: u64 =
crate::SubnetTAO::<T>::iter().fold(0, |acc, (_, v)| acc.saturating_add(v));

let total_stake = total_subnet_tao;
// Update the total stake in storage
crate::TotalStake::<T>::put(total_stake);
log::info!(
"Subtensor Pallet Total Stake Updated: previous: {:?}, new: {:?}",
prev_total_stake,
total_stake
);
// Retrieve the previous total issuance for logging purposes
let prev_total_issuance = crate::TotalIssuance::<T>::get();

// Calculate the new total issuance
let new_total_issuance = total_account_balances
.saturating_add(total_stake)
.saturating_add(total_subnet_locked);
let new_total_issuance = total_account_balances.saturating_add(total_stake);

// Update the total issuance in storage
crate::TotalIssuance::<T>::put(new_total_issuance);
Expand All @@ -48,7 +55,7 @@ pub(crate) fn migrate_init_total_issuance<T: Config>() -> Weight {

// Return the weight of the operation
// We performed subnets_len + 5 reads and 1 write
<T as frame_system::Config>::DbWeight::get().reads_writes(subnets_len.saturating_add(5), 1)
<T as frame_system::Config>::DbWeight::get().reads_writes(subnets_len.saturating_add(5), 2)
}

pub mod initialise_total_issuance {
Expand Down
5 changes: 5 additions & 0 deletions pallets/subtensor/src/subnets/subnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@ impl<T: Config> Pallet<T> {
Self::burn_tokens(actual_tao_lock_amount_less_pool_tao);
}

if actual_tao_lock_amount > 0 && pool_initial_tao > 0 {
// Record in TotalStake the initial TAO in the pool.
Self::increase_total_stake(pool_initial_tao);
}

// --- 15. Add the identity if it exists
if let Some(identity_value) = identity {
ensure!(
Expand Down
9 changes: 5 additions & 4 deletions pallets/subtensor/src/tests/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,21 @@ fn test_initialise_ti() {
use frame_support::traits::OnRuntimeUpgrade;

new_test_ext(1).execute_with(|| {
crate::SubnetLocked::<Test>::insert(1, 100);
crate::SubnetLocked::<Test>::insert(2, 5);
pallet_balances::TotalIssuance::<Test>::put(1000);
crate::TotalStake::<Test>::put(25);
crate::SubnetTAO::<Test>::insert(1, 100);
crate::SubnetTAO::<Test>::insert(2, 5);

// Ensure values are NOT initialized prior to running migration
assert!(crate::TotalIssuance::<Test>::get() == 0);
assert!(crate::TotalStake::<Test>::get() == 0);

crate::migrations::migrate_init_total_issuance::initialise_total_issuance::Migration::<Test>::on_runtime_upgrade();

// Ensure values were initialized correctly
assert!(crate::TotalStake::<Test>::get() == 105);
assert!(
crate::TotalIssuance::<Test>::get()
== 105u64.saturating_add(1000).saturating_add(25)
== 105u64.saturating_add(1000)
);
});
}
Expand Down
90 changes: 75 additions & 15 deletions pallets/subtensor/src/tests/staking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,11 @@ fn test_add_stake_ok_no_emission() {
0
);

// Also total stake should be zero
assert_eq!(SubtensorModule::get_total_stake(), 0);
// Also total stake should be equal to the network initial lock
assert_eq!(
SubtensorModule::get_total_stake(),
SubtensorModule::get_network_min_lock()
);

// Transfer to hotkey account, and check if the result is ok
assert_ok!(SubtensorModule::add_stake(
Expand All @@ -79,7 +82,10 @@ fn test_add_stake_ok_no_emission() {
assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), 1);

// Check if total stake has increased accordingly.
assert_eq!(SubtensorModule::get_total_stake(), amount);
assert_eq!(
SubtensorModule::get_total_stake(),
amount + SubtensorModule::get_network_min_lock()
);
});
}

Expand Down Expand Up @@ -353,12 +359,14 @@ fn test_remove_stake_ok_no_emission() {
let coldkey_account_id = U256::from(4343);
let hotkey_account_id = U256::from(4968585);
let amount = DefaultMinStake::<Test>::get() * 10;
let fee = DefaultStakingFee::<Test>::get();
let netuid: u16 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, 192213123);

// Some basic assertions
assert_eq!(SubtensorModule::get_total_stake(), 0);
assert_eq!(
SubtensorModule::get_total_stake(),
SubtensorModule::get_network_min_lock()
);
assert_eq!(
SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id),
0
Expand All @@ -372,6 +380,16 @@ fn test_remove_stake_ok_no_emission() {
netuid,
amount,
);
assert_eq!(
SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id),
amount
);

// Add subnet TAO for the equivalent amount added at price
let amount_tao =
I96F32::saturating_from_num(amount) * SubtensorModule::get_alpha_price(netuid);
SubnetTAO::<Test>::mutate(netuid, |v| *v += amount_tao.saturating_to_num::<u64>());
TotalStake::<Test>::mutate(|v| *v += amount_tao.saturating_to_num::<u64>());

// Do the magic
assert_ok!(SubtensorModule::remove_stake(
Expand All @@ -381,13 +399,24 @@ fn test_remove_stake_ok_no_emission() {
amount
));

let fee = SubtensorModule::calculate_staking_fee(
Some((&hotkey_account_id, netuid)),
&coldkey_account_id,
None,
&coldkey_account_id,
I96F32::saturating_from_num(amount),
);

// we do not expect the exact amount due to slippage
assert!(SubtensorModule::get_coldkey_balance(&coldkey_account_id) > amount / 10 * 9 - fee);
assert_eq!(
SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id),
0
);
assert_eq!(SubtensorModule::get_total_stake(), fee);
assert_eq!(
SubtensorModule::get_total_stake(),
SubtensorModule::get_network_min_lock() + fee
);
});
}

Expand All @@ -403,7 +432,10 @@ fn test_remove_stake_amount_too_low() {
register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, 192213123);

// Some basic assertions
assert_eq!(SubtensorModule::get_total_stake(), 0);
assert_eq!(
SubtensorModule::get_total_stake(),
SubtensorModule::get_network_min_lock()
);
assert_eq!(
SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id),
0
Expand Down Expand Up @@ -510,12 +542,14 @@ fn test_remove_stake_total_balance_no_change() {
let hotkey_account_id = U256::from(571337);
let coldkey_account_id = U256::from(71337);
let amount = DefaultMinStake::<Test>::get() * 10;
let fee = DefaultStakingFee::<Test>::get();
let netuid: u16 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, 192213123);

// Some basic assertions
assert_eq!(SubtensorModule::get_total_stake(), 0);
assert_eq!(
SubtensorModule::get_total_stake(),
SubtensorModule::get_network_min_lock()
);
assert_eq!(
SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id),
0
Expand All @@ -532,6 +566,12 @@ fn test_remove_stake_total_balance_no_change() {
amount,
);

// Add subnet TAO for the equivalent amount added at price
let amount_tao =
I96F32::saturating_from_num(amount) * SubtensorModule::get_alpha_price(netuid);
SubnetTAO::<Test>::mutate(netuid, |v| *v += amount_tao.saturating_to_num::<u64>());
TotalStake::<Test>::mutate(|v| *v += amount_tao.saturating_to_num::<u64>());

// Do the magic
assert_ok!(SubtensorModule::remove_stake(
RuntimeOrigin::signed(coldkey_account_id),
Expand All @@ -540,6 +580,13 @@ fn test_remove_stake_total_balance_no_change() {
amount
));

let fee = SubtensorModule::calculate_staking_fee(
Some((&hotkey_account_id, netuid)),
&coldkey_account_id,
None,
&coldkey_account_id,
I96F32::saturating_from_num(amount),
);
assert_abs_diff_eq!(
SubtensorModule::get_coldkey_balance(&coldkey_account_id),
amount - fee,
Expand All @@ -549,7 +596,10 @@ fn test_remove_stake_total_balance_no_change() {
SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id),
0
);
assert_eq!(SubtensorModule::get_total_stake(), fee);
assert_eq!(
SubtensorModule::get_total_stake(),
SubtensorModule::get_network_min_lock() + fee
);

// Check total balance is equal to the added stake. Even after remove stake (no fee, includes reserved/locked balance)
let total_balance = Balances::total_balance(&coldkey_account_id);
Expand Down Expand Up @@ -648,7 +698,10 @@ fn test_remove_stake_total_issuance_no_change() {
SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, amount);

// Some basic assertions
assert_eq!(SubtensorModule::get_total_stake(), 0);
assert_eq!(
SubtensorModule::get_total_stake(),
SubtensorModule::get_network_min_lock()
);
assert_eq!(
SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id),
0
Expand Down Expand Up @@ -697,7 +750,7 @@ fn test_remove_stake_total_issuance_no_change() {
);
assert_abs_diff_eq!(
SubtensorModule::get_total_stake(),
fee * 2,
fee * 2 + SubtensorModule::get_network_min_lock(),
epsilon = fee / 1000
);

Expand Down Expand Up @@ -762,8 +815,11 @@ fn test_add_stake_to_hotkey_account_ok() {
let netuid: u16 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey);
register_ok_neuron(netuid, hotkey_id, coldkey_id, 192213123);

// There is not stake in the system at first, so result should be 0;
assert_eq!(SubtensorModule::get_total_stake(), 0);
// There is no stake in the system at first, other than the network initial lock so result;
assert_eq!(
SubtensorModule::get_total_stake(),
SubtensorModule::get_network_min_lock()
);

SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
&hotkey_id,
Expand Down Expand Up @@ -2497,7 +2553,11 @@ fn test_stake_overflow() {
);

// Check if total stake has increased accordingly.
assert_abs_diff_eq!(SubtensorModule::get_total_stake(), amount, epsilon = 10);
assert_abs_diff_eq!(
SubtensorModule::get_total_stake(),
amount + SubtensorModule::get_network_min_lock(),
epsilon = 10
);
});
}

Expand Down
7 changes: 1 addition & 6 deletions pallets/subtensor/src/utils/try_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,11 @@ impl<T: Config> Pallet<T> {
/// Checks [`TotalIssuance`] equals the sum of currency issuance, total stake, and total subnet
/// locked.
pub(crate) fn check_total_issuance() -> Result<(), sp_runtime::TryRuntimeError> {
// Get the total subnet locked amount
let total_subnet_locked = Self::get_total_subnet_locked();

// Get the total currency issuance
let currency_issuance = T::Currency::total_issuance();

// Calculate the expected total issuance
let expected_total_issuance = currency_issuance
.saturating_add(TotalStake::<T>::get())
.saturating_add(total_subnet_locked);
let expected_total_issuance = currency_issuance.saturating_add(TotalStake::<T>::get());

// Verify the diff between calculated TI and actual TI is less than delta
//
Expand Down
2 changes: 1 addition & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// `spec_version`, and `authoring_version` are the same between Wasm and native.
// This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
// the compatible custom types.
spec_version: 250,
spec_version: 251,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
Expand Down
Loading