Skip to content

Commit

Permalink
try state for total issuance done
Browse files Browse the repository at this point in the history
  • Loading branch information
unconst committed Jul 24, 2024
1 parent af50dd6 commit f9b6828
Show file tree
Hide file tree
Showing 11 changed files with 317 additions and 92 deletions.
11 changes: 10 additions & 1 deletion pallets/subtensor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub mod staking;
pub mod subnets;
pub mod swap;
pub mod utils;
use crate::utils::TransactionType;
use crate::utils::rate_limiting::TransactionType;
use macros::{config, dispatches, errors, events, genesis, hooks};

// apparently this is stabilized since rust 1.36
Expand Down Expand Up @@ -563,6 +563,15 @@ pub mod pallet {
/// ============================
/// ==== Staking Variables ====
/// ============================
/// The Subtensor [`TotalIssuance`] represents the total issuance of tokens on the Bittensor network.
///
/// It is comprised of three parts:
/// - The total amount of issued tokens, tracked in the TotalIssuance of the Balances pallet
/// - The total amount of tokens staked in the system, tracked in [`TotalStake`]
/// - The total amount of tokens locked up for subnet reg, tracked in [`TotalSubnetLocked`] attained by iterating over subnet lock.
///
/// Eventually, Bittensor should migrate to using Holds afterwhich time we will not require this
/// separate accounting.
#[pallet::storage] // --- ITEM ( total_issuance )
pub type TotalIssuance<T> = StorageValue<_, u64, ValueQuery, DefaultTotalIssuance<T>>;
#[pallet::storage] // --- ITEM ( total_stake )
Expand Down
6 changes: 6 additions & 0 deletions pallets/subtensor/src/macros/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,11 @@ mod hooks {
.saturating_add(migrations::migrate_fix_total_coldkey_stake::migrate_fix_total_coldkey_stake::<T>());
weight
}

#[cfg(feature = "try-runtime")]
fn try_state(_n: BlockNumberFor<T>) -> Result<(), sp_runtime::TryRuntimeError> {
Self::check_accounting_invariants()?;
Ok(())
}
}
}
83 changes: 83 additions & 0 deletions pallets/subtensor/src/migrations/migrate_init_total_issuance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use super::*;
use frame_support::pallet_prelude::OptionQuery;
use frame_support::{pallet_prelude::Identity, storage_alias};
use sp_std::vec::Vec;

// TODO: Implement comprehensive tests for this migration

/// Module containing deprecated storage format for LoadedEmission
pub mod deprecated_loaded_emission_format {
use super::*;

#[storage_alias]
pub(super) type LoadedEmission<T: Config> =
StorageMap<Pallet<T>, Identity, u16, Vec<(AccountIdOf<T>, u64)>, OptionQuery>;
}

pub mod initialise_total_issuance {
use frame_support::pallet_prelude::Weight;
use frame_support::traits::{fungible, OnRuntimeUpgrade};
use sp_core::Get;

use crate::*;

pub struct Migration<T: Config>(PhantomData<T>);

impl<T: Config> OnRuntimeUpgrade for Migration<T> {
/// Performs the migration to initialize and update the total issuance.
///
/// This function does the following:
/// 1. Calculates the total locked tokens across all subnets
/// 2. Retrieves the total account balances and total stake
/// 3. Computes and updates the new total issuance
///
/// Returns the weight of the migration operation.
fn on_runtime_upgrade() -> 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();

// 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);

// Update the total issuance in storage
crate::TotalIssuance::<T>::put(new_total_issuance);

// Log the change in total issuance
log::info!(
"Subtensor Pallet Total Issuance Updated: previous: {:?}, new: {:?}",
prev_total_issuance,
new_total_issuance
);

// 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)
}

/// Performs post-upgrade checks to ensure the migration was successful.
///
/// This function is only compiled when the "try-runtime" feature is enabled.
#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
// Verify that all accounting invariants are satisfied after the migration
crate::Pallet::<T>::check_accounting_invariants()?;
Ok(())
}
}
}
1 change: 1 addition & 0 deletions pallets/subtensor/src/migrations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub mod migrate_create_root_network;
pub mod migrate_delete_subnet_21;
pub mod migrate_delete_subnet_3;
pub mod migrate_fix_total_coldkey_stake;
pub mod migrate_init_total_issuance;
pub mod migrate_populate_owned_hotkeys;
pub mod migrate_populate_staking_hotkeys;
pub mod migrate_to_v1_separate_emission;
Expand Down
1 change: 0 additions & 1 deletion pallets/subtensor/src/staking/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,6 @@ impl<T: Config> Pallet<T> {
TotalHotkeyStake::<T>::mutate(hotkey, |stake| *stake = stake.saturating_sub(current_stake));
Stake::<T>::remove(hotkey, coldkey);
TotalStake::<T>::mutate(|stake| *stake = stake.saturating_sub(current_stake));
TotalIssuance::<T>::mutate(|issuance| *issuance = issuance.saturating_sub(current_stake));

// Update StakingHotkeys map
let mut staking_hotkeys = StakingHotkeys::<T>::get(coldkey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::{
};
use sp_core::Get;
use sp_core::U256;
use sp_runtime::Saturating;
use substrate_fixed::types::I32F32;

/// Enum representing different types of transactions
Expand Down Expand Up @@ -302,88 +303,6 @@ impl<T: Config> Pallet<T> {
Ok(())
}

// ========================
// ==== Rate Limiting =====
// ========================
/// Get the rate limit for a specific transaction type
pub fn get_rate_limit(tx_type: &TransactionType) -> u64 {
match tx_type {
TransactionType::SetChildren => (DefaultTempo::<T>::get().saturating_mul(2)).into(), // Cannot set children twice within the default tempo period.
TransactionType::Unknown => 0, // Default to no limit for unknown types (no limit)
}
}

/// Check if a transaction should be rate limited on a specific subnet
pub fn passes_rate_limit_on_subnet(
tx_type: &TransactionType,
hotkey: &T::AccountId,
netuid: u16,
) -> bool {
let block: u64 = Self::get_current_block_as_u64();
let limit: u64 = Self::get_rate_limit(tx_type);
let last_block: u64 = Self::get_last_transaction_block(hotkey, netuid, tx_type);
block.saturating_sub(last_block) < limit
}

/// Check if a transaction should be rate limited globally
pub fn passes_rate_limit_globally(tx_type: &TransactionType, hotkey: &T::AccountId) -> bool {
let netuid: u16 = u16::MAX;
let block: u64 = Self::get_current_block_as_u64();
let limit: u64 = Self::get_rate_limit(tx_type);
let last_block: u64 = Self::get_last_transaction_block(hotkey, netuid, tx_type);
block.saturating_sub(last_block) >= limit
}

/// Get the block number of the last transaction for a specific hotkey, network, and transaction type
pub fn get_last_transaction_block(
hotkey: &T::AccountId,
netuid: u16,
tx_type: &TransactionType,
) -> u64 {
let tx_as_u16: u16 = (*tx_type).into();
TransactionKeyLastBlock::<T>::get((hotkey, netuid, tx_as_u16))
}

/// Set the block number of the last transaction for a specific hotkey, network, and transaction type
pub fn set_last_transaction_block(
hotkey: &T::AccountId,
netuid: u16,
tx_type: &TransactionType,
block: u64,
) {
let tx_as_u16: u16 = (*tx_type).into();
TransactionKeyLastBlock::<T>::insert((hotkey, netuid, tx_as_u16), block);
}

pub fn set_last_tx_block(key: &T::AccountId, block: u64) {
LastTxBlock::<T>::insert(key, block)
}
pub fn get_last_tx_block(key: &T::AccountId) -> u64 {
LastTxBlock::<T>::get(key)
}
pub fn set_last_tx_block_delegate_take(key: &T::AccountId, block: u64) {
LastTxBlockDelegateTake::<T>::insert(key, block)
}
pub fn get_last_tx_block_delegate_take(key: &T::AccountId) -> u64 {
LastTxBlockDelegateTake::<T>::get(key)
}
pub fn exceeds_tx_rate_limit(prev_tx_block: u64, current_block: u64) -> bool {
let rate_limit: u64 = Self::get_tx_rate_limit();
if rate_limit == 0 || prev_tx_block == 0 {
return false;
}

current_block.saturating_sub(prev_tx_block) <= rate_limit
}
pub fn exceeds_tx_delegate_take_rate_limit(prev_tx_block: u64, current_block: u64) -> bool {
let rate_limit: u64 = Self::get_tx_delegate_take_rate_limit();
if rate_limit == 0 || prev_tx_block == 0 {
return false;
}

current_block.saturating_sub(prev_tx_block) <= rate_limit
}

// ========================
// === Token Management ===
// ========================
Expand All @@ -404,14 +323,19 @@ impl<T: Config> Pallet<T> {
pub fn get_min_take() -> u16 {
MinTake::<T>::get()
}

pub fn set_subnet_locked_balance(netuid: u16, amount: u64) {
SubnetLocked::<T>::insert(netuid, amount);
}

pub fn get_subnet_locked_balance(netuid: u16) -> u64 {
SubnetLocked::<T>::get(netuid)
}
pub fn get_total_subnet_locked() -> u64 {
let mut total_subnet_locked: u64 = 0;
for (_, locked) in SubnetLocked::<T>::iter() {
total_subnet_locked.saturating_accrue(locked);
}
total_subnet_locked
}

// ========================
// ========= Sudo =========
Expand Down
4 changes: 4 additions & 0 deletions pallets/subtensor/src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
use super::*;
pub mod misc;
pub mod rate_limiting;
pub mod try_state;
112 changes: 112 additions & 0 deletions pallets/subtensor/src/utils/rate_limiting.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
use super::*;
use sp_core::Get;

/// Enum representing different types of transactions
#[derive(Copy, Clone)]
pub enum TransactionType {
SetChildren,
Unknown,
}

/// Implement conversion from TransactionType to u16
impl From<TransactionType> for u16 {
fn from(tx_type: TransactionType) -> Self {
match tx_type {
TransactionType::SetChildren => 0,
TransactionType::Unknown => 1,
}
}
}

/// Implement conversion from u16 to TransactionType
impl From<u16> for TransactionType {
fn from(value: u16) -> Self {
match value {
0 => TransactionType::SetChildren,
_ => TransactionType::Unknown,
}
}
}
impl<T: Config> Pallet<T> {
// ========================
// ==== Rate Limiting =====
// ========================
/// Get the rate limit for a specific transaction type
pub fn get_rate_limit(tx_type: &TransactionType) -> u64 {
match tx_type {
TransactionType::SetChildren => (DefaultTempo::<T>::get().saturating_mul(2)).into(), // Cannot set children twice within the default tempo period.
TransactionType::Unknown => 0, // Default to no limit for unknown types (no limit)
}
}

/// Check if a transaction should be rate limited on a specific subnet
pub fn passes_rate_limit_on_subnet(
tx_type: &TransactionType,
hotkey: &T::AccountId,
netuid: u16,
) -> bool {
let block: u64 = Self::get_current_block_as_u64();
let limit: u64 = Self::get_rate_limit(tx_type);
let last_block: u64 = Self::get_last_transaction_block(hotkey, netuid, tx_type);
block.saturating_sub(last_block) < limit
}

/// Check if a transaction should be rate limited globally
pub fn passes_rate_limit_globally(tx_type: &TransactionType, hotkey: &T::AccountId) -> bool {
let netuid: u16 = u16::MAX;
let block: u64 = Self::get_current_block_as_u64();
let limit: u64 = Self::get_rate_limit(tx_type);
let last_block: u64 = Self::get_last_transaction_block(hotkey, netuid, tx_type);
block.saturating_sub(last_block) >= limit
}

/// Get the block number of the last transaction for a specific hotkey, network, and transaction type
pub fn get_last_transaction_block(
hotkey: &T::AccountId,
netuid: u16,
tx_type: &TransactionType,
) -> u64 {
let tx_as_u16: u16 = (*tx_type).into();
TransactionKeyLastBlock::<T>::get((hotkey, netuid, tx_as_u16))
}

/// Set the block number of the last transaction for a specific hotkey, network, and transaction type
pub fn set_last_transaction_block(
hotkey: &T::AccountId,
netuid: u16,
tx_type: &TransactionType,
block: u64,
) {
let tx_as_u16: u16 = (*tx_type).into();
TransactionKeyLastBlock::<T>::insert((hotkey, netuid, tx_as_u16), block);
}

pub fn set_last_tx_block(key: &T::AccountId, block: u64) {
LastTxBlock::<T>::insert(key, block)
}
pub fn get_last_tx_block(key: &T::AccountId) -> u64 {
LastTxBlock::<T>::get(key)
}
pub fn set_last_tx_block_delegate_take(key: &T::AccountId, block: u64) {
LastTxBlockDelegateTake::<T>::insert(key, block)
}
pub fn get_last_tx_block_delegate_take(key: &T::AccountId) -> u64 {
LastTxBlockDelegateTake::<T>::get(key)
}
pub fn exceeds_tx_rate_limit(prev_tx_block: u64, current_block: u64) -> bool {
let rate_limit: u64 = Self::get_tx_rate_limit();
if rate_limit == 0 || prev_tx_block == 0 {
return false;
}

current_block.saturating_sub(prev_tx_block) <= rate_limit
}
pub fn exceeds_tx_delegate_take_rate_limit(prev_tx_block: u64, current_block: u64) -> bool {
let rate_limit: u64 = Self::get_tx_delegate_take_rate_limit();
if rate_limit == 0 || prev_tx_block == 0 {
return false;
}

current_block.saturating_sub(prev_tx_block) <= rate_limit
}
}
Loading

0 comments on commit f9b6828

Please sign in to comment.