diff --git a/.github/workflows/try-runtime.yml b/.github/workflows/try-runtime.yml index c3b54a3514..1241ca94d0 100644 --- a/.github/workflows/try-runtime.yml +++ b/.github/workflows/try-runtime.yml @@ -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 diff --git a/pallets/subtensor/src/migrations/migrate_dissolve_sn73.rs b/pallets/subtensor/src/migrations/migrate_dissolve_sn73.rs index 9839d2d93d..996e74f720 100644 --- a/pallets/subtensor/src/migrations/migrate_dissolve_sn73.rs +++ b/pallets/subtensor/src/migrations/migrate_dissolve_sn73.rs @@ -36,6 +36,18 @@ pub fn migrate_dissolve_sn73() -> Weight { weight = weight.saturating_add(T::DbWeight::get().reads(1)); log::debug!("Subnet TAO: {}", subnet_tao); + // Adjust total stake and total issuance + TotalStake::::mutate(|total| { + *total = total.saturating_sub(subnet_tao.saturating_to_num::()); + }); + TotalIssuance::::mutate(|total| { + *total = total.saturating_sub(subnet_tao.saturating_to_num::()); + }); + 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 = Vec::new(); @@ -96,6 +108,7 @@ pub fn migrate_dissolve_sn73() -> Weight { if as_tao > 0 { Pallet::::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 @@ -115,6 +128,23 @@ pub fn migrate_dissolve_sn73() -> Weight { } } + // Update total issuance + TotalIssuance::::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::() + .abs_diff(total_swapped) + >= 100_000 + { + log::info!( + "Total issuance change is incorrect: {} != {}", + subnet_tao.saturating_to_num::(), + total_swapped + ); + } + // === Clear storage entries === // Clear subnet owner and hotkey SubnetOwner::::remove(this_netuid); @@ -154,12 +184,6 @@ pub fn migrate_dissolve_sn73() -> Weight { let clear_results_1 = TaoDividendsPerSubnet::::clear_prefix(this_netuid, u32::MAX, None); weight = weight.saturating_add(T::DbWeight::get().writes(clear_results_1.unique.into())); - // Adjust total stake - TotalStake::::mutate(|total| { - *total = total.saturating_sub(subnet_tao.saturating_to_num::()); - }); - weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); - // Clear subnet volume SubnetVolume::::remove(this_netuid); weight = weight.saturating_add(T::DbWeight::get().writes(1)); diff --git a/pallets/subtensor/src/migrations/migrate_init_total_issuance.rs b/pallets/subtensor/src/migrations/migrate_init_total_issuance.rs index ba9d85badc..5bccfff9a0 100644 --- a/pallets/subtensor/src/migrations/migrate_init_total_issuance.rs +++ b/pallets/subtensor/src/migrations/migrate_init_total_issuance.rs @@ -15,10 +15,7 @@ pub mod deprecated_loaded_emission_format { } pub(crate) fn migrate_init_total_issuance() -> Weight { - // Calculate the total locked tokens across all subnets let subnets_len = crate::SubnetLocked::::iter().count() as u64; - let total_subnet_locked: u64 = - crate::SubnetLocked::::iter().fold(0, |acc, (_, v)| acc.saturating_add(v)); // Retrieve the total balance of all accounts let total_account_balances = <::Currency as fungible::Inspect< @@ -26,15 +23,25 @@ pub(crate) fn migrate_init_total_issuance() -> Weight { >>::total_issuance(); // Get the total stake from the system - let total_stake = crate::TotalStake::::get(); + let prev_total_stake = crate::TotalStake::::get(); + // Calculate new total stake using the sum of all subnet TAO + let total_subnet_tao: u64 = + crate::SubnetTAO::::iter().fold(0, |acc, (_, v)| acc.saturating_add(v)); + + let total_stake = total_subnet_tao; + // Update the total stake in storage + crate::TotalStake::::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::::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::::put(new_total_issuance); @@ -48,7 +55,7 @@ pub(crate) fn migrate_init_total_issuance() -> Weight { // Return the weight of the operation // We performed subnets_len + 5 reads and 1 write - ::DbWeight::get().reads_writes(subnets_len.saturating_add(5), 1) + ::DbWeight::get().reads_writes(subnets_len.saturating_add(5), 2) } pub mod initialise_total_issuance { diff --git a/pallets/subtensor/src/subnets/subnet.rs b/pallets/subtensor/src/subnets/subnet.rs index 87704c558a..bf1806da14 100644 --- a/pallets/subtensor/src/subnets/subnet.rs +++ b/pallets/subtensor/src/subnets/subnet.rs @@ -217,6 +217,11 @@ impl Pallet { 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!( diff --git a/pallets/subtensor/src/tests/migration.rs b/pallets/subtensor/src/tests/migration.rs index be0d563576..5b636c1397 100644 --- a/pallets/subtensor/src/tests/migration.rs +++ b/pallets/subtensor/src/tests/migration.rs @@ -34,20 +34,21 @@ fn test_initialise_ti() { use frame_support::traits::OnRuntimeUpgrade; new_test_ext(1).execute_with(|| { - crate::SubnetLocked::::insert(1, 100); - crate::SubnetLocked::::insert(2, 5); pallet_balances::TotalIssuance::::put(1000); - crate::TotalStake::::put(25); + crate::SubnetTAO::::insert(1, 100); + crate::SubnetTAO::::insert(2, 5); // Ensure values are NOT initialized prior to running migration assert!(crate::TotalIssuance::::get() == 0); + assert!(crate::TotalStake::::get() == 0); crate::migrations::migrate_init_total_issuance::initialise_total_issuance::Migration::::on_runtime_upgrade(); // Ensure values were initialized correctly + assert!(crate::TotalStake::::get() == 105); assert!( crate::TotalIssuance::::get() - == 105u64.saturating_add(1000).saturating_add(25) + == 105u64.saturating_add(1000) ); }); } diff --git a/pallets/subtensor/src/tests/staking.rs b/pallets/subtensor/src/tests/staking.rs index 38c440fe71..33d686a604 100644 --- a/pallets/subtensor/src/tests/staking.rs +++ b/pallets/subtensor/src/tests/staking.rs @@ -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( @@ -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() + ); }); } @@ -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::::get() * 10; - let fee = DefaultStakingFee::::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 @@ -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::::mutate(netuid, |v| *v += amount_tao.saturating_to_num::()); + TotalStake::::mutate(|v| *v += amount_tao.saturating_to_num::()); // Do the magic assert_ok!(SubtensorModule::remove_stake( @@ -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 + ); }); } @@ -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 @@ -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::::get() * 10; - let fee = DefaultStakingFee::::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 @@ -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::::mutate(netuid, |v| *v += amount_tao.saturating_to_num::()); + TotalStake::::mutate(|v| *v += amount_tao.saturating_to_num::()); + // Do the magic assert_ok!(SubtensorModule::remove_stake( RuntimeOrigin::signed(coldkey_account_id), @@ -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, @@ -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); @@ -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 @@ -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 ); @@ -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, @@ -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 + ); }); } diff --git a/pallets/subtensor/src/utils/try_state.rs b/pallets/subtensor/src/utils/try_state.rs index ffa5869110..1fb75fd4bb 100644 --- a/pallets/subtensor/src/utils/try_state.rs +++ b/pallets/subtensor/src/utils/try_state.rs @@ -6,16 +6,11 @@ impl Pallet { /// 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::::get()) - .saturating_add(total_subnet_locked); + let expected_total_issuance = currency_issuance.saturating_add(TotalStake::::get()); // Verify the diff between calculated TI and actual TI is less than delta // diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 0f362ada54..86a689aadc 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -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,