diff --git a/pallets/subtensor/src/coinbase/block_step.rs b/pallets/subtensor/src/coinbase/block_step.rs index 21f7866459..b8004f6e5c 100644 --- a/pallets/subtensor/src/coinbase/block_step.rs +++ b/pallets/subtensor/src/coinbase/block_step.rs @@ -25,11 +25,13 @@ impl Pallet { Self::run_coinbase(block_emission); // --- 5. Update moving prices AFTER using them for emissions. Self::update_moving_prices(); - // --- 6. Set pending children on the epoch; but only after the coinbase has been run. + // --- 6. Update roop prop AFTER using them for emissions. + Self::update_root_prop(); + // --- 7. Set pending children on the epoch; but only after the coinbase has been run. Self::try_set_pending_children(block_number); - // --- 7. Run auto-claim root divs. + // --- 8. Run auto-claim root divs. Self::run_auto_claim_root_divs(last_block_hash); - // --- 8. Populate root coldkey maps. + // --- 9. Populate root coldkey maps. Self::populate_root_coldkey_staking_maps(); // Return ok. @@ -277,6 +279,29 @@ impl Pallet { } } + pub fn update_root_prop() { + let subnets_to_emit_to: Vec = + Self::get_subnets_to_emit_to(&Self::get_all_subnet_netuids()); + // Only root_prop for subnets that we emit to. + for netuid_i in subnets_to_emit_to.iter() { + let root_prop = Self::root_proportion(*netuid_i); + + RootProp::::insert(netuid_i, root_prop); + } + } + + pub fn root_proportion(netuid: NetUid) -> U96F32 { + let alpha_issuance = U96F32::from_num(Self::get_alpha_issuance(netuid)); + let root_tao: U96F32 = U96F32::from_num(SubnetTAO::::get(NetUid::ROOT)); + let tao_weight: U96F32 = root_tao.saturating_mul(Self::get_tao_weight()); + + let root_proportion: U96F32 = tao_weight + .checked_div(tao_weight.saturating_add(alpha_issuance)) + .unwrap_or(U96F32::from_num(0.0)); + + root_proportion + } + pub fn reveal_crv3_commits() { let netuids: Vec = Self::get_all_subnet_netuids(); for netuid in netuids.into_iter().filter(|netuid| *netuid != NetUid::ROOT) { diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 3b82ec86d5..13808d2361 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -178,13 +178,6 @@ impl Pallet { // --- 3. Inject ALPHA for participants. let cut_percent: U96F32 = Self::get_float_subnet_owner_cut(); - // Get total TAO on root. - let root_tao: U96F32 = asfloat!(SubnetTAO::::get(NetUid::ROOT)); - log::debug!("root_tao: {root_tao:?}"); - // Get tao_weight - let tao_weight: U96F32 = root_tao.saturating_mul(Self::get_tao_weight()); - log::debug!("tao_weight: {tao_weight:?}"); - for netuid_i in subnets_to_emit_to.iter() { // Get alpha_out for this block. let mut alpha_out_i: U96F32 = *alpha_out.get(netuid_i).unwrap_or(&asfloat!(0)); @@ -205,14 +198,8 @@ impl Pallet { *total = total.saturating_add(tou64!(owner_cut_i).into()); }); - // Get ALPHA issuance. - let alpha_issuance: U96F32 = asfloat!(Self::get_alpha_issuance(*netuid_i)); - log::debug!("alpha_issuance: {alpha_issuance:?}"); - // Get root proportional dividends. - let root_proportion: U96F32 = tao_weight - .checked_div(tao_weight.saturating_add(alpha_issuance)) - .unwrap_or(asfloat!(0.0)); + let root_proportion = Self::root_proportion(*netuid_i); log::debug!("root_proportion: {root_proportion:?}"); // Get root alpha from root prop. diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 6d61baadf3..1f6b000e7a 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -95,7 +95,7 @@ pub mod pallet { use sp_std::collections::vec_deque::VecDeque; use sp_std::vec; use sp_std::vec::Vec; - use substrate_fixed::types::{I64F64, I96F32, U64F64}; + use substrate_fixed::types::{I64F64, I96F32, U64F64, U96F32}; use subtensor_macros::freeze_struct; use subtensor_runtime_common::{ AlphaCurrency, Currency, MechId, NetUid, NetUidStorageIndex, TaoCurrency, @@ -994,6 +994,12 @@ pub mod pallet { I96F32::saturating_from_num(0.0) } + /// Default subnet root proportion. + #[pallet::type_value] + pub fn DefaultRootProp() -> U96F32 { + U96F32::saturating_from_num(0.0) + } + /// Default subnet root claimable #[pallet::type_value] pub fn DefaultRootClaimable() -> BTreeMap { @@ -1279,6 +1285,11 @@ pub mod pallet { pub type SubnetMovingPrice = StorageMap<_, Identity, NetUid, I96F32, ValueQuery, DefaultMovingPrice>; + /// --- MAP ( netuid ) --> root_prop | The subnet root proportion. + #[pallet::storage] + pub type RootProp = + StorageMap<_, Identity, NetUid, U96F32, ValueQuery, DefaultRootProp>; + /// --- MAP ( netuid ) --> total_volume | The total amount of TAO bought and sold since the start of the network. #[pallet::storage] pub type SubnetVolume = diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index ef36b17921..a4c01b440f 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -712,7 +712,7 @@ mod dispatches { /// #[pallet::call_index(2)] #[pallet::weight((Weight::from_parts(340_800_000, 0) - .saturating_add(T::DbWeight::get().reads(27_u64)) + .saturating_add(T::DbWeight::get().reads(25_u64)) .saturating_add(T::DbWeight::get().writes(16_u64)), DispatchClass::Normal, Pays::Yes))] pub fn add_stake( origin: OriginFor, @@ -1587,7 +1587,7 @@ mod dispatches { /// - Thrown if key has hit transaction rate limit #[pallet::call_index(84)] #[pallet::weight((Weight::from_parts(358_500_000, 0) - .saturating_add(T::DbWeight::get().reads(44_u64)) + .saturating_add(T::DbWeight::get().reads(41_u64)) .saturating_add(T::DbWeight::get().writes(26_u64)), DispatchClass::Normal, Pays::Yes))] pub fn unstake_all_alpha(origin: OriginFor, hotkey: T::AccountId) -> DispatchResult { Self::do_unstake_all_alpha(origin, hotkey) @@ -1701,7 +1701,7 @@ mod dispatches { #[pallet::call_index(87)] #[pallet::weight(( Weight::from_parts(351_300_000, 0) - .saturating_add(T::DbWeight::get().reads(40_u64)) + .saturating_add(T::DbWeight::get().reads(37_u64)) .saturating_add(T::DbWeight::get().writes(24_u64)), DispatchClass::Normal, Pays::Yes @@ -1766,7 +1766,7 @@ mod dispatches { /// #[pallet::call_index(88)] #[pallet::weight((Weight::from_parts(402_900_000, 0) - .saturating_add(T::DbWeight::get().reads(27_u64)) + .saturating_add(T::DbWeight::get().reads(25_u64)) .saturating_add(T::DbWeight::get().writes(16_u64)), DispatchClass::Normal, Pays::Yes))] pub fn add_stake_limit( origin: OriginFor, @@ -1830,7 +1830,7 @@ mod dispatches { /// #[pallet::call_index(89)] #[pallet::weight((Weight::from_parts(377_400_000, 0) - .saturating_add(T::DbWeight::get().reads(31_u64)) + .saturating_add(T::DbWeight::get().reads(29_u64)) .saturating_add(T::DbWeight::get().writes(15_u64)), DispatchClass::Normal, Pays::Yes))] pub fn remove_stake_limit( origin: OriginFor, @@ -1874,7 +1874,7 @@ mod dispatches { #[pallet::call_index(90)] #[pallet::weight(( Weight::from_parts(411_500_000, 0) - .saturating_add(T::DbWeight::get().reads(40_u64)) + .saturating_add(T::DbWeight::get().reads(37_u64)) .saturating_add(T::DbWeight::get().writes(24_u64)), DispatchClass::Normal, Pays::Yes @@ -2052,7 +2052,7 @@ mod dispatches { /// Without limit_price it remove all the stake similar to `remove_stake` extrinsic #[pallet::call_index(103)] #[pallet::weight((Weight::from_parts(395_300_000, 10142) - .saturating_add(T::DbWeight::get().reads(31_u64)) + .saturating_add(T::DbWeight::get().reads(29_u64)) .saturating_add(T::DbWeight::get().writes(15_u64)), DispatchClass::Normal, Pays::Yes))] pub fn remove_stake_full_limit( origin: T::RuntimeOrigin, diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index c7ad008c04..6cb4ebe3d5 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -3919,3 +3919,64 @@ fn test_pending_emission_start_call_not_done() { ); }); } + +#[test] +fn test_root_prop_filled_on_block_step() { + new_test_ext(1).execute_with(|| { + let hotkey = U256::from(10); + let coldkey = U256::from(11); + let netuid1 = add_dynamic_network(&hotkey, &coldkey); + let netuid2 = add_dynamic_network(&hotkey, &coldkey); + + SubnetTAO::::insert(NetUid::ROOT, TaoCurrency::from(1_000_000_000_000u64)); + SubtensorModule::set_tao_weight(u64::MAX); // Set TAO weight to 1.0 + + let tao_reserve = TaoCurrency::from(50_000_000_000); + let alpha_in = AlphaCurrency::from(100_000_000_000); + SubnetTAO::::insert(netuid1, tao_reserve); + SubnetAlphaIn::::insert(netuid1, alpha_in); + SubnetTAO::::insert(netuid2, tao_reserve); + SubnetAlphaIn::::insert(netuid2, alpha_in); + + assert!(!RootProp::::contains_key(netuid1)); + assert!(!RootProp::::contains_key(netuid2)); + + run_to_block(2); + + assert!(RootProp::::get(netuid1) > U96F32::from_num(0)); + assert!(RootProp::::get(netuid2) > U96F32::from_num(0)); + }); +} + +#[test] +fn test_root_proportion() { + new_test_ext(1).execute_with(|| { + let hotkey = U256::from(10); + let coldkey = U256::from(11); + let netuid = add_dynamic_network(&hotkey, &coldkey); + + let root_tao_reserve = 1_000_000_000_000u64; + SubnetTAO::::insert(NetUid::ROOT, TaoCurrency::from(root_tao_reserve)); + + let tao_weight = 3_320_413_933_267_719_290u64; + SubtensorModule::set_tao_weight(tao_weight); + + let alpha_in = 100_000_000_000u64; + SubnetAlphaIn::::insert(netuid, AlphaCurrency::from(alpha_in)); + + let actual_root_proportion = SubtensorModule::root_proportion(netuid); + let expected_root_prop = { + let tao_weight = SubtensorModule::get_tao_weight(); + let root_tao = U96F32::from_num(root_tao_reserve); + let alpha_in = { + let alpha: u64 = SubtensorModule::get_alpha_issuance(netuid).into(); + + U96F32::from_num(alpha) + }; + + tao_weight * root_tao / (tao_weight * root_tao + alpha_in) + }; + + assert_eq!(actual_root_proportion, expected_root_prop); + }); +}