From c179c8e23550c4da447d284c6d22458c173ee9a7 Mon Sep 17 00:00:00 2001 From: opendansor Date: Fri, 7 Jun 2024 13:25:16 -0700 Subject: [PATCH 01/31] Update localnet.sh to include a flag for fast_blocks for E2E testing --- scripts/localnet.sh | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/scripts/localnet.sh b/scripts/localnet.sh index ab564871b..65ca5c0a9 100755 --- a/scripts/localnet.sh +++ b/scripts/localnet.sh @@ -6,9 +6,24 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" # The base directory of the subtensor project BASE_DIR="$SCRIPT_DIR/.." -: "${CHAIN:=local}" -: "${BUILD_BINARY:=1}" -: "${FEATURES:="pow-faucet runtime-benchmarks fast-blocks"}" +# get parameters +# Get the value of fast_blocks from the first argument +fast_blocks=${1:-"True"} + +# Check the value of fast_blocks +if [ "$fast_blocks" == "False" ]; then + # Block of code to execute if fast_blocks is False + echo "fast_blocks is Off" + : "${CHAIN:=local}" + : "${BUILD_BINARY:=1}" + : "${FEATURES:="pow-faucet runtime-benchmarks"}" +else + # Block of code to execute if fast_blocks is not False + echo "fast_blocks is On" + : "${CHAIN:=local}" + : "${BUILD_BINARY:=1}" + : "${FEATURES:="pow-faucet runtime-benchmarks fast-blocks"}" +fi SPEC_PATH="${SCRIPT_DIR}/specs/" FULL_PATH="$SPEC_PATH$CHAIN.json" From 59d9cbdc6b2034778fd238fa5c250d8801a4eda3 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 23 Jul 2024 02:06:56 +0400 Subject: [PATCH 02/31] chore: update spec version --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index a4abd124f..4079860b6 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -139,7 +139,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: 165, + spec_version: 190, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 62c152755a9feca61f37ec200603007dba3eac28 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Fri, 26 Jul 2024 21:01:28 +0400 Subject: [PATCH 03/31] clippy --- pallets/collective/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/collective/src/lib.rs b/pallets/collective/src/lib.rs index 96040f99c..c6552b036 100644 --- a/pallets/collective/src/lib.rs +++ b/pallets/collective/src/lib.rs @@ -951,8 +951,8 @@ impl, I: 'static> Pallet { /// /// If not `approved`: /// - one event deposited. - /// Two removals, one mutation. - /// Computation and i/o `O(P)` where: + /// Two removals, one mutation. + /// Computation and i/o `O(P)` where: /// - `P` is number of active proposals fn do_approve_proposal( seats: MemberCount, From cd23ac287c9dc5dc02999f3751cd255ad8a5e143 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Mon, 29 Jul 2024 21:10:48 +0400 Subject: [PATCH 04/31] chore: clippy --- pallets/collective/src/lib.rs | 6 +++--- pallets/subtensor/tests/children.rs | 1 - pallets/subtensor/tests/coinbase.rs | 4 ---- pallets/subtensor/tests/difficulty.rs | 1 - pallets/subtensor/tests/epoch.rs | 1 - pallets/subtensor/tests/mock.rs | 4 ++++ pallets/subtensor/tests/neuron_info.rs | 1 - pallets/subtensor/tests/registration.rs | 1 - pallets/subtensor/tests/serving.rs | 2 -- pallets/subtensor/tests/staking.rs | 2 -- pallets/subtensor/tests/weights.rs | 3 --- runtime/src/lib.rs | 2 ++ 12 files changed, 9 insertions(+), 19 deletions(-) diff --git a/pallets/collective/src/lib.rs b/pallets/collective/src/lib.rs index c6552b036..6aae3c85e 100644 --- a/pallets/collective/src/lib.rs +++ b/pallets/collective/src/lib.rs @@ -951,9 +951,9 @@ impl, I: 'static> Pallet { /// /// If not `approved`: /// - one event deposited. - /// Two removals, one mutation. - /// Computation and i/o `O(P)` where: - /// - `P` is number of active proposals + /// - two removals, one mutation. + /// - computation and i/o `O(P)` where: + /// - `P` is number of active proposals fn do_approve_proposal( seats: MemberCount, yes_votes: MemberCount, diff --git a/pallets/subtensor/tests/children.rs b/pallets/subtensor/tests/children.rs index 9ad07e1e7..e834baa85 100644 --- a/pallets/subtensor/tests/children.rs +++ b/pallets/subtensor/tests/children.rs @@ -297,7 +297,6 @@ fn test_do_set_child_singular_multiple_children() { // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_add_singular_child --exact --nocapture #[test] -#[cfg(not(tarpaulin))] fn test_add_singular_child() { new_test_ext(1).execute_with(|| { let netuid: u16 = 1; diff --git a/pallets/subtensor/tests/coinbase.rs b/pallets/subtensor/tests/coinbase.rs index 8fd963dff..d6e48bbcc 100644 --- a/pallets/subtensor/tests/coinbase.rs +++ b/pallets/subtensor/tests/coinbase.rs @@ -6,7 +6,6 @@ use sp_core::U256; // Test the ability to hash all sorts of hotkeys. #[test] -#[cfg(not(tarpaulin))] fn test_hotkey_hashing() { new_test_ext(1).execute_with(|| { for i in 0..10000 { @@ -18,7 +17,6 @@ fn test_hotkey_hashing() { // Test drain tempo on hotkeys. // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test coinbase test_hotkey_drain_time -- --nocapture #[test] -#[cfg(not(tarpaulin))] fn test_hotkey_drain_time() { new_test_ext(1).execute_with(|| { // Block 0 @@ -46,7 +44,6 @@ fn test_hotkey_drain_time() { // To run this test specifically, use the following command: // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test coinbase test_coinbase_basic -- --nocapture #[test] -#[cfg(not(tarpaulin))] fn test_coinbase_basic() { new_test_ext(1).execute_with(|| { // Define network ID @@ -138,7 +135,6 @@ fn test_coinbase_basic() { // Test getting and setting hotkey emission tempo // SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test coinbase test_set_and_get_hotkey_emission_tempo -- --nocapture #[test] -#[cfg(not(tarpaulin))] fn test_set_and_get_hotkey_emission_tempo() { new_test_ext(1).execute_with(|| { // Get the default hotkey emission tempo diff --git a/pallets/subtensor/tests/difficulty.rs b/pallets/subtensor/tests/difficulty.rs index 05238bc43..c3023b829 100644 --- a/pallets/subtensor/tests/difficulty.rs +++ b/pallets/subtensor/tests/difficulty.rs @@ -5,7 +5,6 @@ mod mock; use sp_core::U256; #[test] -#[cfg(not(tarpaulin))] fn test_registration_difficulty_adjustment() { new_test_ext(1).execute_with(|| { // Create Net 1 diff --git a/pallets/subtensor/tests/epoch.rs b/pallets/subtensor/tests/epoch.rs index 526a58b4e..b639a4ac4 100644 --- a/pallets/subtensor/tests/epoch.rs +++ b/pallets/subtensor/tests/epoch.rs @@ -2107,7 +2107,6 @@ fn test_zero_weights() { // Test that epoch assigns validator permits to highest stake uids, varies uid interleaving and stake values. #[test] -#[cfg(not(tarpaulin))] fn test_validator_permits() { let netuid: u16 = 1; let tempo: u16 = u16::MAX - 1; // high tempo to skip automatic epochs in on_initialize, use manual epochs instead diff --git a/pallets/subtensor/tests/mock.rs b/pallets/subtensor/tests/mock.rs index 27d11eb13..d8d677006 100644 --- a/pallets/subtensor/tests/mock.rs +++ b/pallets/subtensor/tests/mock.rs @@ -264,6 +264,7 @@ impl CollectiveInterface for TriumvirateVotes { } // We call pallet_collective TriumvirateCollective +#[allow(dead_code)] type TriumvirateCollective = pallet_collective::Instance1; impl pallet_collective::Config for Test { type RuntimeOrigin = RuntimeOrigin; @@ -281,6 +282,7 @@ impl pallet_collective::Config for Test { } // We call council members Triumvirate +#[allow(dead_code)] type TriumvirateMembership = pallet_membership::Instance1; impl pallet_membership::Config for Test { type RuntimeEvent = RuntimeEvent; @@ -297,6 +299,7 @@ impl pallet_membership::Config for Test { // This is a dummy collective instance for managing senate members // Probably not the best solution, but fastest implementation +#[allow(dead_code)] type SenateCollective = pallet_collective::Instance2; impl pallet_collective::Config for Test { type RuntimeOrigin = RuntimeOrigin; @@ -314,6 +317,7 @@ impl pallet_collective::Config for Test { } // We call our top K delegates membership Senate +#[allow(dead_code)] type SenateMembership = pallet_membership::Instance2; impl pallet_membership::Config for Test { type RuntimeEvent = RuntimeEvent; diff --git a/pallets/subtensor/tests/neuron_info.rs b/pallets/subtensor/tests/neuron_info.rs index 10df1c07d..3494fdc5f 100644 --- a/pallets/subtensor/tests/neuron_info.rs +++ b/pallets/subtensor/tests/neuron_info.rs @@ -15,7 +15,6 @@ fn test_get_neuron_none() { } #[test] -#[cfg(not(tarpaulin))] fn test_get_neuron_some() { new_test_ext(1).execute_with(|| { let netuid: u16 = 1; diff --git a/pallets/subtensor/tests/registration.rs b/pallets/subtensor/tests/registration.rs index bd95ae3b1..7d6e8ea65 100644 --- a/pallets/subtensor/tests/registration.rs +++ b/pallets/subtensor/tests/registration.rs @@ -539,7 +539,6 @@ fn test_burn_adjustment() { } #[test] -#[cfg(not(tarpaulin))] fn test_registration_too_many_registrations_per_block() { new_test_ext(1).execute_with(|| { let netuid: u16 = 1; diff --git a/pallets/subtensor/tests/serving.rs b/pallets/subtensor/tests/serving.rs index 41e9888cc..b87b7fd10 100644 --- a/pallets/subtensor/tests/serving.rs +++ b/pallets/subtensor/tests/serving.rs @@ -161,7 +161,6 @@ fn test_serving_set_metadata_update() { } #[test] -#[cfg(not(tarpaulin))] fn test_axon_serving_rate_limit_exceeded() { new_test_ext(1).execute_with(|| { let hotkey_account_id = U256::from(1); @@ -379,7 +378,6 @@ fn test_prometheus_serving_set_metadata_update() { } #[test] -#[cfg(not(tarpaulin))] fn test_prometheus_serving_rate_limit_exceeded() { new_test_ext(1).execute_with(|| { let hotkey_account_id = U256::from(1); diff --git a/pallets/subtensor/tests/staking.rs b/pallets/subtensor/tests/staking.rs index 2952426a9..5bf95841a 100644 --- a/pallets/subtensor/tests/staking.rs +++ b/pallets/subtensor/tests/staking.rs @@ -15,7 +15,6 @@ use sp_core::{H256, U256}; ************************************************************/ #[test] -#[cfg(not(tarpaulin))] fn test_add_stake_dispatch_info_ok() { new_test_ext(1).execute_with(|| { let hotkey = U256::from(0); @@ -521,7 +520,6 @@ fn test_remove_stake_rate_limit_exceeded() { } #[test] -#[cfg(not(tarpaulin))] fn test_remove_stake_dispatch_info_ok() { new_test_ext(1).execute_with(|| { let hotkey = U256::from(0); diff --git a/pallets/subtensor/tests/weights.rs b/pallets/subtensor/tests/weights.rs index 2344bd425..020eb1f6b 100644 --- a/pallets/subtensor/tests/weights.rs +++ b/pallets/subtensor/tests/weights.rs @@ -21,7 +21,6 @@ use substrate_fixed::types::I32F32; // Test the call passes through the subtensor module. #[test] -#[cfg(not(tarpaulin))] fn test_set_weights_dispatch_info_ok() { new_test_ext(0).execute_with(|| { let dests = vec![1, 1]; @@ -41,7 +40,6 @@ fn test_set_weights_dispatch_info_ok() { }); } #[test] -#[cfg(not(tarpaulin))] fn test_set_rootweights_dispatch_info_ok() { new_test_ext(0).execute_with(|| { let dests = vec![1, 1]; @@ -404,7 +402,6 @@ fn test_weights_err_no_validator_permit() { // To execute this test: cargo test --package pallet-subtensor --test weights test_set_weights_min_stake_failed -- --nocapture` #[test] -#[cfg(not(tarpaulin))] fn test_set_weights_min_stake_failed() { new_test_ext(0).execute_with(|| { let dests = vec![0]; diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 2d1716337..66951b7fc 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -516,6 +516,7 @@ impl pallet_collective::Config for Runtime { } // We call council members Triumvirate +#[allow(dead_code)] type TriumvirateMembership = pallet_membership::Instance1; impl pallet_membership::Config for Runtime { type RuntimeEvent = RuntimeEvent; @@ -531,6 +532,7 @@ impl pallet_membership::Config for Runtime { } // We call our top K delegates membership Senate +#[allow(dead_code)] type SenateMembership = pallet_membership::Instance2; impl pallet_membership::Config for Runtime { type RuntimeEvent = RuntimeEvent; From 8ce0d690b37fdd0635267fe1f6f78fe5d3e1078f Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 30 Jul 2024 19:20:21 +0400 Subject: [PATCH 05/31] feat: child key takes --- pallets/admin-utils/tests/mock.rs | 13 +- pallets/admin-utils/tests/tests.rs | 6 +- .../subtensor/src/coinbase/run_coinbase.rs | 2 +- pallets/subtensor/src/lib.rs | 55 ++++-- pallets/subtensor/src/macros/config.rs | 13 +- pallets/subtensor/src/macros/dispatches.rs | 80 +++++++- pallets/subtensor/src/macros/errors.rs | 4 + pallets/subtensor/src/macros/events.rs | 8 + .../subtensor/src/staking/become_delegate.rs | 6 +- .../subtensor/src/staking/decrease_take.rs | 4 +- pallets/subtensor/src/staking/helpers.rs | 7 + .../subtensor/src/staking/increase_take.rs | 4 +- pallets/subtensor/src/staking/set_children.rs | 98 ++++++++++ pallets/subtensor/src/utils.rs | 70 +++++-- pallets/subtensor/tests/children.rs | 183 +++++++++++++++++- pallets/subtensor/tests/mock.rs | 13 +- pallets/subtensor/tests/staking.rs | 70 +++---- runtime/src/lib.rs | 12 +- scripts/test_specific.sh | 2 +- 19 files changed, 558 insertions(+), 92 deletions(-) diff --git a/pallets/admin-utils/tests/mock.rs b/pallets/admin-utils/tests/mock.rs index 7ae11b6fb..0142a435a 100644 --- a/pallets/admin-utils/tests/mock.rs +++ b/pallets/admin-utils/tests/mock.rs @@ -77,12 +77,16 @@ parameter_types! { pub const InitialBondsMovingAverage: u64 = 900_000; pub const InitialStakePruningMin: u16 = 0; pub const InitialFoundationDistribution: u64 = 0; - pub const InitialDefaultTake: u16 = 11_796; // 18% honest number. + pub const InitialDefaultDelegateTake: u16 = 11_796; // 18% honest number. + pub const InitialMinDelegateTake: u16 = 5_898; // 9%; + pub const InitialDefaultChildKeyTake: u16 = 11_796; // 18% honest number. + pub const InitialMinChildKeyTake: u16 = 5_898; // 9%; pub const InitialMinTake: u16 = 5_898; // 9%; pub const InitialWeightsVersionKey: u16 = 0; pub const InitialServingRateLimit: u64 = 0; // No limit. pub const InitialTxRateLimit: u64 = 0; // Disable rate limit for testing pub const InitialTxDelegateTakeRateLimit: u64 = 0; // Disable rate limit for testing + pub const InitialTxChildKeyTakeRateLimit: u64 = 0; // Disable rate limit for testing pub const InitialBurn: u64 = 0; pub const InitialMinBurn: u64 = 0; pub const InitialMaxBurn: u64 = 1_000_000_000; @@ -146,14 +150,17 @@ impl pallet_subtensor::Config for Test { type InitialPruningScore = InitialPruningScore; type InitialBondsMovingAverage = InitialBondsMovingAverage; type InitialMaxAllowedValidators = InitialMaxAllowedValidators; - type InitialDefaultTake = InitialDefaultTake; - type InitialMinTake = InitialMinTake; + type InitialDefaultDelegateTake = InitialDefaultDelegateTake; + type InitialMinDelegateTake = InitialMinDelegateTake; + type InitialDefaultChildKeyTake = InitialDefaultChildKeyTake; + type InitialMinChildKeyTake = InitialMinChildKeyTake; type InitialWeightsVersionKey = InitialWeightsVersionKey; type InitialMaxDifficulty = InitialMaxDifficulty; type InitialMinDifficulty = InitialMinDifficulty; type InitialServingRateLimit = InitialServingRateLimit; type InitialTxRateLimit = InitialTxRateLimit; type InitialTxDelegateTakeRateLimit = InitialTxDelegateTakeRateLimit; + type InitialTxChildKeyTakeRateLimit = InitialTxChildKeyTakeRateLimit; type InitialBurn = InitialBurn; type InitialMaxBurn = InitialMaxBurn; type InitialMinBurn = InitialMinBurn; diff --git a/pallets/admin-utils/tests/tests.rs b/pallets/admin-utils/tests/tests.rs index 6e78a1ed6..af3bf66d7 100644 --- a/pallets/admin-utils/tests/tests.rs +++ b/pallets/admin-utils/tests/tests.rs @@ -16,7 +16,7 @@ use mock::*; fn test_sudo_set_default_take() { new_test_ext().execute_with(|| { let to_be_set: u16 = 10; - let init_value: u16 = SubtensorModule::get_default_take(); + let init_value: u16 = SubtensorModule::get_default_delegate_take(); assert_eq!( AdminUtils::sudo_set_default_take( <::RuntimeOrigin>::signed(U256::from(0)), @@ -24,12 +24,12 @@ fn test_sudo_set_default_take() { ), Err(DispatchError::BadOrigin) ); - assert_eq!(SubtensorModule::get_default_take(), init_value); + assert_eq!(SubtensorModule::get_default_delegate_take(), init_value); assert_ok!(AdminUtils::sudo_set_default_take( <::RuntimeOrigin>::root(), to_be_set )); - assert_eq!(SubtensorModule::get_default_take(), to_be_set); + assert_eq!(SubtensorModule::get_default_delegate_take(), to_be_set); }); } diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index fcf76728f..442a9f085 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -186,7 +186,7 @@ impl Pallet { mining_emission: u64, ) { // --- 1. First, calculate the hotkey's share of the emission. - let take_proportion: I64F64 = I64F64::from_num(Delegates::::get(hotkey)) + let take_proportion: I64F64 = I64F64::from_num(Self::get_childkey_take(hotkey, netuid)) .saturating_div(I64F64::from_num(u16::MAX)); let hotkey_take: u64 = take_proportion .saturating_mul(I64F64::from_num(validating_emission)) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index abf6a8613..c58c6a0c6 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -143,15 +143,27 @@ pub mod pallet { 21_000_000_000_000_000 } #[pallet::type_value] - /// Default total stake. - pub fn DefaultDefaultTake() -> u16 { - T::InitialDefaultTake::get() + /// Default Delegate Take. + pub fn DefaultDelegateTake() -> u16 { + T::InitialDefaultDelegateTake::get() + } + + #[pallet::type_value] + /// Default childkey take. + pub fn DefaultChildKeyTake() -> u16 { + T::InitialDefaultChildKeyTake::get() } #[pallet::type_value] - /// Default minimum take. - pub fn DefaultMinTake() -> u16 { - T::InitialMinTake::get() + /// Default minimum delegate take. + pub fn DefaultMinDelegateTake() -> u16 { + T::InitialMinDelegateTake::get() } + #[pallet::type_value] + /// Default minimum childkey take. + pub fn DefaultMinChildKeyTake() -> u16 { + T::InitialMinChildKeyTake::get() + } + #[pallet::type_value] /// Default account take. pub fn DefaultAccountTake() -> u64 { @@ -516,6 +528,11 @@ pub mod pallet { T::InitialTxDelegateTakeRateLimit::get() } #[pallet::type_value] + /// Default value for chidlkey take rate limiting + pub fn DefaultTxChildKeyTakeRateLimit() -> u64 { + T::InitialTxChildKeyTakeRateLimit::get() + } + #[pallet::type_value] /// Default value for last extrinsic block. pub fn DefaultLastTxBlock() -> u64 { 0 @@ -567,10 +584,15 @@ pub mod pallet { pub type TotalIssuance = StorageValue<_, u64, ValueQuery, DefaultTotalIssuance>; #[pallet::storage] // --- ITEM ( total_stake ) pub type TotalStake = StorageValue<_, u64, ValueQuery>; - #[pallet::storage] // --- ITEM ( default_take ) - pub type MaxTake = StorageValue<_, u16, ValueQuery, DefaultDefaultTake>; - #[pallet::storage] // --- ITEM ( min_take ) - pub type MinTake = StorageValue<_, u16, ValueQuery, DefaultMinTake>; + #[pallet::storage] // --- ITEM ( default_delegate_take ) + pub type MaxDelegateTake = StorageValue<_, u16, ValueQuery, DefaultDelegateTake>; + #[pallet::storage] // --- ITEM ( min_delegate_take ) + pub type MinDelegateTake = StorageValue<_, u16, ValueQuery, DefaultMinDelegateTake>; + #[pallet::storage] // --- ITEM ( default_childkey_take ) + pub type MaxChildkeyTake = StorageValue<_, u16, ValueQuery, DefaultChildKeyTake>; + #[pallet::storage] // --- ITEM ( min_childkey_take ) + pub type MinChildkeyTake = StorageValue<_, u16, ValueQuery, DefaultMinChildKeyTake>; + #[pallet::storage] // --- ITEM ( global_block_emission ) pub type BlockEmission = StorageValue<_, u64, ValueQuery, DefaultBlockEmission>; #[pallet::storage] // --- ITEM (target_stakes_per_interval) @@ -603,7 +625,12 @@ pub mod pallet { #[pallet::storage] /// MAP ( hot ) --> take | Returns the hotkey delegation take. And signals that this key is open for delegation. pub type Delegates = - StorageMap<_, Blake2_128Concat, T::AccountId, u16, ValueQuery, DefaultDefaultTake>; + StorageMap<_, Blake2_128Concat, T::AccountId, u16, ValueQuery, DefaultDelegateTake>; + #[pallet::storage] + /// DMAP ( hot, netuid ) --> take | Returns the hotkey childkey take for a specific subnet + pub type ChildkeyTake = + StorageMap<_, Blake2_128Concat, (T::AccountId, u16), u16, ValueQuery>; + #[pallet::storage] /// DMAP ( hot, cold ) --> stake | Returns the stake under a coldkey prefixed by hotkey. pub type Stake = StorageDoubleMap< @@ -921,10 +948,14 @@ pub mod pallet { /// --- ITEM ( tx_rate_limit ) pub type TxRateLimit = StorageValue<_, u64, ValueQuery, DefaultTxRateLimit>; #[pallet::storage] - /// --- ITEM ( tx_rate_limit ) + /// --- ITEM ( tx_delegate_take_rate_limit ) pub type TxDelegateTakeRateLimit = StorageValue<_, u64, ValueQuery, DefaultTxDelegateTakeRateLimit>; #[pallet::storage] + /// --- ITEM ( tx_childkey_take_rate_limit ) + pub type TxChildkeyTakeRateLimit = + StorageValue<_, u64, ValueQuery, DefaultTxChildKeyTakeRateLimit>; + #[pallet::storage] /// --- MAP ( netuid ) --> Whether or not Liquid Alpha is enabled pub type LiquidAlphaOn = StorageMap<_, Blake2_128Concat, u16, bool, ValueQuery, DefaultLiquidAlpha>; diff --git a/pallets/subtensor/src/macros/config.rs b/pallets/subtensor/src/macros/config.rs index e59eac5ca..2a6d8db00 100644 --- a/pallets/subtensor/src/macros/config.rs +++ b/pallets/subtensor/src/macros/config.rs @@ -112,10 +112,16 @@ mod config { type InitialMaxAllowedValidators: Get; /// Initial default delegation take. #[pallet::constant] - type InitialDefaultTake: Get; + type InitialDefaultDelegateTake: Get; /// Initial minimum delegation take. #[pallet::constant] - type InitialMinTake: Get; + type InitialMinDelegateTake: Get; + /// Initial default childkey take. + #[pallet::constant] + type InitialDefaultChildKeyTake: Get; + /// Initial minimum childkey take. + #[pallet::constant] + type InitialMinChildKeyTake: Get; /// Initial weights version key. #[pallet::constant] type InitialWeightsVersionKey: Get; @@ -128,6 +134,9 @@ mod config { /// Initial delegate take transaction rate limit. #[pallet::constant] type InitialTxDelegateTakeRateLimit: Get; + /// Initial childkey take transaction rate limit. + #[pallet::constant] + type InitialTxChildKeyTakeRateLimit: Get; /// Initial percentage of total stake required to join senate. #[pallet::constant] type InitialSenateRequiredStakePercentage: Get; diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 293dc0238..7954e77c1 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -262,7 +262,7 @@ mod dispatches { .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)), DispatchClass::Normal, Pays::No))] pub fn become_delegate(origin: OriginFor, hotkey: T::AccountId) -> DispatchResult { - Self::do_become_delegate(origin, hotkey, Self::get_default_take()) + Self::do_become_delegate(origin, hotkey, Self::get_default_delegate_take()) } /// --- Allows delegates to decrease its take value. @@ -708,6 +708,84 @@ mod dispatches { Ok(()) } + /// Sets the childkey take for a given hotkey. + /// + /// This function allows a coldkey to set the childkey take for a given hotkey. + /// The childkey take determines the proportion of stake that the hotkey keeps for itself + /// when distributing stake to its children. + /// + /// # Arguments: + /// * `origin` (::RuntimeOrigin): + /// - The signature of the calling coldkey. Setting childkey take can only be done by the coldkey. + /// + /// * `hotkey` (T::AccountId): + /// - The hotkey for which the childkey take will be set. + /// + /// * `take` (u16): + /// - The new childkey take value. This is a percentage represented as a value between 0 and 10000, + /// where 10000 represents 100%. + /// + /// # Events: + /// * `ChildkeyTakeSet`: + /// - On successfully setting the childkey take for a hotkey. + /// + /// # Errors: + /// * `NonAssociatedColdKey`: + /// - The coldkey does not own the hotkey. + /// * `InvalidChildkeyTake`: + /// - The provided take value is invalid (greater than the maximum allowed take). + /// * `TxChildkeyTakeRateLimitExceeded`: + /// - The rate limit for changing childkey take has been exceeded. + /// + #[pallet::call_index(68)] + #[pallet::weight(( + Weight::from_parts(10_000_000, 0) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)), + DispatchClass::Normal, + Pays::Yes +))] + pub fn set_childkey_take( + origin: OriginFor, + hotkey: T::AccountId, + netuid: u16, + take: u16, + ) -> DispatchResult { + let coldkey = ensure_signed(origin)?; + + // Call the utility function to set the childkey take + Self::do_set_childkey_take(coldkey, hotkey, netuid, take) + } + + /// Sets the transaction rate limit for changing childkey take. + /// + /// This function can only be called by the root origin. + /// + /// # Arguments: + /// * `origin` - The origin of the call, must be root. + /// * `tx_rate_limit` - The new rate limit in blocks. + /// + /// # Errors: + /// * `BadOrigin` - If the origin is not root. + /// + // TODO: Benchmark this call + #[pallet::call_index(69)] + #[pallet::weight(( + Weight::from_parts(10_000_000, 0) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)), + DispatchClass::Operational, + Pays::No +))] + pub fn sudo_set_tx_childkey_take_rate_limit( + origin: OriginFor, + tx_rate_limit: u64, + ) -> DispatchResult { + ensure_root(origin)?; + Self::set_tx_childkey_take_rate_limit(tx_rate_limit); + Ok(()) + } + // ---- SUDO ONLY FUNCTIONS ------------------------------------------------------------ // ================================== diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index 156cbea56..4c5103fa2 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -168,5 +168,9 @@ mod errors { TooManyChildren, /// Default transaction rate limit exceeded. TxRateLimitExceeded, + /// Childkey take is invalid. + InvalidChildkeyTake, + /// Childkey take rate limit exceeded. + TxChildkeyTakeRateLimitExceeded, } } diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index b93b8296b..c9fbb0b44 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -83,6 +83,14 @@ mod events { TxRateLimitSet(u64), /// setting the delegate take transaction rate limit. TxDelegateTakeRateLimitSet(u64), + /// setting the childkey take transaction rate limit. + TxChildKeyTakeRateLimitSet(u64), + /// minimum childkey take set + MinChildKeyTakeSet(u16), + /// maximum childkey take set + MaxChildKeyTakeSet(u16), + /// childkey take set + ChildKeyTakeSet(T::AccountId, u16), /// a sudo call is done. Sudid(DispatchResult), /// registration is allowed/disallowed for a subnet. diff --git a/pallets/subtensor/src/staking/become_delegate.rs b/pallets/subtensor/src/staking/become_delegate.rs index 064f47c12..ccbdc44a2 100644 --- a/pallets/subtensor/src/staking/become_delegate.rs +++ b/pallets/subtensor/src/staking/become_delegate.rs @@ -58,9 +58,9 @@ impl Pallet { Error::::DelegateTxRateLimitExceeded ); - // --- 5.1 Ensure take is within the min ..= InitialDefaultTake (18%) range - let min_take = MinTake::::get(); - let max_take = MaxTake::::get(); + // --- 5.1 Ensure take is within the min ..= InitialDefaultDelegateTake (18%) range + let min_take = MinDelegateTake::::get(); + let max_take = MaxDelegateTake::::get(); ensure!(take >= min_take, Error::::DelegateTakeTooLow); ensure!(take <= max_take, Error::::DelegateTakeTooHigh); diff --git a/pallets/subtensor/src/staking/decrease_take.rs b/pallets/subtensor/src/staking/decrease_take.rs index 9e48bac91..6da669ca2 100644 --- a/pallets/subtensor/src/staking/decrease_take.rs +++ b/pallets/subtensor/src/staking/decrease_take.rs @@ -50,8 +50,8 @@ impl Pallet { ensure!(take < current_take, Error::::DelegateTakeTooLow); } - // --- 3.1 Ensure take is within the min ..= InitialDefaultTake (18%) range - let min_take = MinTake::::get(); + // --- 3.1 Ensure take is within the min ..= InitialDefaultDelegateTake (18%) range + let min_take = MinDelegateTake::::get(); ensure!(take >= min_take, Error::::DelegateTakeTooLow); // --- 4. Set the new take value. diff --git a/pallets/subtensor/src/staking/helpers.rs b/pallets/subtensor/src/staking/helpers.rs index 486577712..7445bd154 100644 --- a/pallets/subtensor/src/staking/helpers.rs +++ b/pallets/subtensor/src/staking/helpers.rs @@ -218,6 +218,13 @@ impl Pallet { hotkey: &T::AccountId, increment: u64, ) { + log::debug!( + "Increasing stake: coldkey: {:?}, hotkey: {:?}, amount: {}", + coldkey, + hotkey, + increment + ); + TotalColdkeyStake::::insert( coldkey, TotalColdkeyStake::::get(coldkey).saturating_add(increment), diff --git a/pallets/subtensor/src/staking/increase_take.rs b/pallets/subtensor/src/staking/increase_take.rs index aa6dd443c..bc72bda4e 100644 --- a/pallets/subtensor/src/staking/increase_take.rs +++ b/pallets/subtensor/src/staking/increase_take.rs @@ -53,8 +53,8 @@ impl Pallet { ensure!(take > current_take, Error::::DelegateTakeTooLow); } - // --- 4. Ensure take is within the min ..= InitialDefaultTake (18%) range - let max_take = MaxTake::::get(); + // --- 4. Ensure take is within the min ..= InitialDefaultDelegateTake (18%) range + let max_take = MaxDelegateTake::::get(); ensure!(take <= max_take, Error::::DelegateTakeTooHigh); // --- 5. Enforce the rate limit (independently on do_add_stake rate limits) diff --git a/pallets/subtensor/src/staking/set_children.rs b/pallets/subtensor/src/staking/set_children.rs index f413db23f..bfe5d1c1e 100644 --- a/pallets/subtensor/src/staking/set_children.rs +++ b/pallets/subtensor/src/staking/set_children.rs @@ -190,4 +190,102 @@ impl Pallet { pub fn get_parents(child: &T::AccountId, netuid: u16) -> Vec<(u64, T::AccountId)> { ParentKeys::::get(child, netuid) } + + /// Sets the childkey take for a given hotkey. + /// + /// This function allows a coldkey to set the childkey take for a given hotkey. + /// The childkey take determines the proportion of stake that the hotkey keeps for itself + /// when distributing stake to its children. + /// + /// # Arguments: + /// * `coldkey` (T::AccountId): + /// - The coldkey that owns the hotkey. + /// + /// * `hotkey` (T::AccountId): + /// - The hotkey for which the childkey take will be set. + /// + /// * `take` (u16): + /// - The new childkey take value. This is a percentage represented as a value between 0 and 10000, + /// where 10000 represents 100%. + /// + /// # Returns: + /// * `DispatchResult` - The result of the operation. + /// + /// # Errors: + /// * `NonAssociatedColdKey`: + /// - The coldkey does not own the hotkey. + /// * `InvalidChildkeyTake`: + /// - The provided take value is invalid (greater than the maximum allowed take). + /// * `TxChildkeyTakeRateLimitExceeded`: + /// - The rate limit for changing childkey take has been exceeded. + pub fn do_set_childkey_take( + coldkey: T::AccountId, + hotkey: T::AccountId, + netuid: u16, + take: u16, + ) -> DispatchResult { + // Ensure the coldkey owns the hotkey + ensure!( + Self::coldkey_owns_hotkey(&coldkey, &hotkey), + Error::::NonAssociatedColdKey + ); + + // Ensure the take value is valid + ensure!( + take <= Self::get_max_childkey_take(), + Error::::InvalidChildkeyTake + ); + + // Ensure the hotkey passes the rate limit + ensure!( + Self::passes_rate_limit_on_subnet(&TransactionType::SetChildkeyTake, &hotkey, netuid), + Error::::TxChildkeyTakeRateLimitExceeded + ); + + // Set the new childkey take value for the given hotkey and network + ChildkeyTake::::insert((hotkey.clone(), netuid), take); + + // TODO: Consider adding a check to ensure the hotkey is registered on the specified network (netuid) + // before setting the childkey take. This could prevent setting takes for non-existent or + // unregistered hotkeys. + + // NOTE: The childkey take is now associated with both the hotkey and the network ID. + // This allows for different take values across different networks for the same hotkey. + + // Update the last transaction block + let current_block: u64 = >::block_number() + .try_into() + .unwrap_or_else(|_| 0); + Self::set_last_transaction_block( + &hotkey, + netuid, + &TransactionType::SetChildkeyTake, + current_block, + ); + + // Emit the event + Self::deposit_event(Event::ChildKeyTakeSet(hotkey.clone(), take)); + log::debug!( + "Childkey take set for hotkey: {:?} and take: {:?}", + hotkey, + take + ); + Ok(()) + } + + /// Gets the childkey take for a given hotkey. + /// + /// This function retrieves the current childkey take value for a specified hotkey. + /// If no specific take value has been set, it returns the default childkey take. + /// + /// # Arguments: + /// * `hotkey` (&T::AccountId): + /// - The hotkey for which to retrieve the childkey take. + /// + /// # Returns: + /// * `u16` - The childkey take value. This is a percentage represented as a value between 0 and 10000, + /// where 10000 represents 100%. + pub fn get_childkey_take(hotkey: &T::AccountId, netuid: u16) -> u16 { + ChildkeyTake::::get((hotkey, netuid)) + } } diff --git a/pallets/subtensor/src/utils.rs b/pallets/subtensor/src/utils.rs index 2cd49e198..edbe02a36 100644 --- a/pallets/subtensor/src/utils.rs +++ b/pallets/subtensor/src/utils.rs @@ -11,6 +11,7 @@ use substrate_fixed::types::I32F32; #[derive(Copy, Clone)] pub enum TransactionType { SetChildren, + SetChildkeyTake, Unknown, } @@ -19,7 +20,8 @@ impl From for u16 { fn from(tx_type: TransactionType) -> Self { match tx_type { TransactionType::SetChildren => 0, - TransactionType::Unknown => 1, + TransactionType::SetChildkeyTake => 1, + TransactionType::Unknown => 2, } } } @@ -29,6 +31,7 @@ impl From for TransactionType { fn from(value: u16) -> Self { match value { 0 => TransactionType::SetChildren, + 1 => TransactionType::SetChildkeyTake, _ => TransactionType::Unknown, } } @@ -309,6 +312,7 @@ impl Pallet { pub fn get_rate_limit(tx_type: &TransactionType) -> u64 { match tx_type { TransactionType::SetChildren => (DefaultTempo::::get().saturating_mul(2)).into(), // Cannot set children twice within the default tempo period. + TransactionType::SetChildkeyTake => (TxChildkeyTakeRateLimit::::get()).into(), TransactionType::Unknown => 0, // Default to no limit for unknown types (no limit) } } @@ -319,10 +323,22 @@ impl Pallet { hotkey: &T::AccountId, netuid: u16, ) -> bool { - let block: u64 = Self::get_current_block_as_u64(); + let current_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 + + log::info!( + "Rate limit check: current_block: {}, last_block: {}, limit: {}", + current_block, + last_block, + limit + ); + + if last_block == 0 { + true + } else { + current_block.saturating_sub(last_block) > limit + } } /// Check if a transaction should be rate limited globally @@ -393,17 +409,6 @@ impl Pallet { pub fn coinbase(amount: u64) { TotalIssuance::::put(TotalIssuance::::get().saturating_add(amount)); } - pub fn get_default_take() -> u16 { - // Default to maximum - MaxTake::::get() - } - pub fn set_max_take(default_take: u16) { - MaxTake::::put(default_take); - Self::deposit_event(Event::DefaultTakeSet(default_take)); - } - pub fn get_min_take() -> u16 { - MinTake::::get() - } pub fn set_subnet_locked_balance(netuid: u16, amount: u64) { SubnetLocked::::insert(netuid, amount); @@ -425,6 +430,11 @@ impl Pallet { TxRateLimit::::put(tx_rate_limit); Self::deposit_event(Event::TxRateLimitSet(tx_rate_limit)); } + + pub fn get_default_delegate_take() -> u16 { + // Default to maximum + MaxDelegateTake::::get() + } pub fn get_tx_delegate_take_rate_limit() -> u64 { TxDelegateTakeRateLimit::::get() } @@ -433,18 +443,42 @@ impl Pallet { Self::deposit_event(Event::TxDelegateTakeRateLimitSet(tx_rate_limit)); } pub fn set_min_delegate_take(take: u16) { - MinTake::::put(take); + MinDelegateTake::::put(take); Self::deposit_event(Event::MinDelegateTakeSet(take)); } pub fn set_max_delegate_take(take: u16) { - MaxTake::::put(take); + MaxDelegateTake::::put(take); Self::deposit_event(Event::MaxDelegateTakeSet(take)); } pub fn get_min_delegate_take() -> u16 { - MinTake::::get() + MinDelegateTake::::get() } pub fn get_max_delegate_take() -> u16 { - MaxTake::::get() + MaxDelegateTake::::get() + } + pub fn set_tx_childkey_take_rate_limit(tx_rate_limit: u64) { + TxChildkeyTakeRateLimit::::put(tx_rate_limit); + Self::deposit_event(Event::TxChildKeyTakeRateLimitSet(tx_rate_limit)); + } + + pub fn set_min_childkey_take(take: u16) { + MinChildkeyTake::::put(take); + Self::deposit_event(Event::MinChildKeyTakeSet(take)); + } + pub fn set_max_childkey_take(take: u16) { + MaxChildkeyTake::::put(take); + Self::deposit_event(Event::MaxChildKeyTakeSet(take)); + } + pub fn get_min_childkey_take() -> u16 { + MinChildkeyTake::::get() + } + pub fn get_max_childkey_take() -> u16 { + MaxChildkeyTake::::get() + } + + pub fn get_default_childkey_take() -> u16 { + // Default to maximum + MaxChildkeyTake::::get() } pub fn get_serving_rate_limit(netuid: u16) -> u64 { diff --git a/pallets/subtensor/tests/children.rs b/pallets/subtensor/tests/children.rs index e834baa85..c38005a53 100644 --- a/pallets/subtensor/tests/children.rs +++ b/pallets/subtensor/tests/children.rs @@ -1,7 +1,7 @@ use crate::mock::*; -use frame_support::{assert_err, assert_ok}; +use frame_support::{assert_err, assert_noop, assert_ok}; mod mock; -use pallet_subtensor::*; +use pallet_subtensor::{utils::TransactionType, *}; use sp_core::U256; // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_success --exact --nocapture @@ -791,7 +791,184 @@ fn test_do_set_children_multiple_overwrite_existing() { }); } -// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_empty_list --exact --nocapture +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_childkey_take_functionality --exact --nocapture +#[test] +fn test_childkey_take_functionality() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let netuid: u16 = 1; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Test default and max childkey take + let default_take = SubtensorModule::get_default_childkey_take(); + let max_take = SubtensorModule::get_max_childkey_take(); + log::info!("Default take: {}, Max take: {}", default_take, max_take); + + // Check if default take and max take are the same + assert_eq!( + default_take, max_take, + "Default take should be equal to max take" + ); + + // Log the actual value of MaxChildkeyTake + log::info!( + "MaxChildkeyTake value: {:?}", + MaxChildkeyTake::::get() + ); + + // Test setting childkey take + let new_take: u16 = max_take / 2; // 50% of max_take + assert_ok!(SubtensorModule::set_childkey_take( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + new_take + )); + + // Verify childkey take was set correctly + let stored_take = SubtensorModule::get_childkey_take(&hotkey, netuid); + log::info!("Stored take: {}", stored_take); + assert_eq!(stored_take, new_take); + + // Test setting childkey take outside of allowed range + let invalid_take: u16 = max_take + 1; + assert_noop!( + SubtensorModule::set_childkey_take( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + invalid_take + ), + Error::::InvalidChildkeyTake + ); + + // Test setting childkey take with non-associated coldkey + let non_associated_coldkey = U256::from(999); + assert_noop!( + SubtensorModule::set_childkey_take( + RuntimeOrigin::signed(non_associated_coldkey), + hotkey, + netuid, + new_take + ), + Error::::NonAssociatedColdKey + ); + }); +} + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_childkey_take_rate_limiting --exact --nocapture +#[test] +fn test_childkey_take_rate_limiting() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let netuid: u16 = 1; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set a rate limit for childkey take changes + let rate_limit: u64 = 100; + SubtensorModule::set_tx_childkey_take_rate_limit(rate_limit.into()); + + log::info!( + "TxChildkeyTakeRateLimit: {:?}", + TxChildkeyTakeRateLimit::::get() + ); + + // First transaction (should succeed) + assert_ok!(SubtensorModule::set_childkey_take( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + 500 + )); + + let current_block = SubtensorModule::get_current_block_as_u64(); + let last_block = SubtensorModule::get_last_transaction_block( + &hotkey, + netuid, + &TransactionType::SetChildkeyTake, + ); + log::info!( + "After first transaction: current_block: {}, last_block: {}", + current_block, + last_block + ); + + // Second transaction (should fail due to rate limit) + let result = + SubtensorModule::set_childkey_take(RuntimeOrigin::signed(coldkey), hotkey, netuid, 600); + log::info!("Second transaction result: {:?}", result); + let current_block = SubtensorModule::get_current_block_as_u64(); + let last_block = SubtensorModule::get_last_transaction_block( + &hotkey, + netuid, + &TransactionType::SetChildkeyTake, + ); + log::info!( + "After second transaction attempt: current_block: {}, last_block: {}", + current_block, + last_block + ); + + assert_noop!(result, Error::::TxChildkeyTakeRateLimitExceeded); + + // Advance the block number to just before the rate limit + run_to_block(rate_limit); + + // Third transaction (should still fail) + let result = + SubtensorModule::set_childkey_take(RuntimeOrigin::signed(coldkey), hotkey, netuid, 650); + log::info!("Third transaction result: {:?}", result); + let current_block = SubtensorModule::get_current_block_as_u64(); + let last_block = SubtensorModule::get_last_transaction_block( + &hotkey, + netuid, + &TransactionType::SetChildkeyTake, + ); + log::info!( + "After third transaction attempt: current_block: {}, last_block: {}", + current_block, + last_block + ); + + assert_noop!(result, Error::::TxChildkeyTakeRateLimitExceeded); + + // Advance the block number to just after the rate limit + run_to_block(rate_limit * 2); + + // Fourth transaction (should succeed) + assert_ok!(SubtensorModule::set_childkey_take( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + 700 + )); + + let current_block = SubtensorModule::get_current_block_as_u64(); + let last_block = SubtensorModule::get_last_transaction_block( + &hotkey, + netuid, + &TransactionType::SetChildkeyTake, + ); + log::info!( + "After fourth transaction: current_block: {}, last_block: {}", + current_block, + last_block + ); + + // Verify the final take was set + let stored_take = SubtensorModule::get_childkey_take(&hotkey, netuid); + assert_eq!(stored_take, 700); + }); +} + #[test] fn test_do_set_children_multiple_empty_list() { new_test_ext(1).execute_with(|| { diff --git a/pallets/subtensor/tests/mock.rs b/pallets/subtensor/tests/mock.rs index d8d677006..4de74f4ab 100644 --- a/pallets/subtensor/tests/mock.rs +++ b/pallets/subtensor/tests/mock.rs @@ -131,12 +131,16 @@ parameter_types! { pub const InitialBondsMovingAverage: u64 = 900_000; pub const InitialStakePruningMin: u16 = 0; pub const InitialFoundationDistribution: u64 = 0; - pub const InitialDefaultTake: u16 = 11_796; // 18%, same as in production + pub const InitialDefaultDelegateTake: u16 = 11_796; // 18%, same as in production + pub const InitialMinDelegateTake: u16 = 5_898; // 9%; + pub const InitialDefaultChildKeyTake: u16 = 11_796; // 18%, same as in production + pub const InitialMinChildKeyTake: u16 = 5_898; // 9%; pub const InitialMinTake: u16 =5_898; // 9%; pub const InitialWeightsVersionKey: u16 = 0; pub const InitialServingRateLimit: u64 = 0; // No limit. pub const InitialTxRateLimit: u64 = 0; // Disable rate limit for testing pub const InitialTxDelegateTakeRateLimit: u64 = 1; // 1 block take rate limit for testing + pub const InitialTxChildKeyTakeRateLimit: u64 = 1; // 1 block take rate limit for testing pub const InitialBurn: u64 = 0; pub const InitialMinBurn: u64 = 0; pub const InitialMaxBurn: u64 = 1_000_000_000; @@ -360,8 +364,11 @@ impl pallet_subtensor::Config for Test { type InitialPruningScore = InitialPruningScore; type InitialBondsMovingAverage = InitialBondsMovingAverage; type InitialMaxAllowedValidators = InitialMaxAllowedValidators; - type InitialDefaultTake = InitialDefaultTake; - type InitialMinTake = InitialMinTake; + type InitialDefaultDelegateTake = InitialDefaultDelegateTake; + type InitialMinDelegateTake = InitialMinDelegateTake; + type InitialDefaultChildKeyTake = InitialDefaultChildKeyTake; + type InitialMinChildKeyTake = InitialMinChildKeyTake; + type InitialTxChildKeyTakeRateLimit = InitialTxChildKeyTakeRateLimit; type InitialWeightsVersionKey = InitialWeightsVersionKey; type InitialMaxDifficulty = InitialMaxDifficulty; type InitialMinDifficulty = InitialMinDifficulty; diff --git a/pallets/subtensor/tests/staking.rs b/pallets/subtensor/tests/staking.rs index 5bf95841a..f053c7ca6 100644 --- a/pallets/subtensor/tests/staking.rs +++ b/pallets/subtensor/tests/staking.rs @@ -1395,7 +1395,7 @@ fn test_clear_small_nominations() { assert_ok!(SubtensorModule::do_become_delegate( <::RuntimeOrigin>::signed(cold1), hot1, - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() )); assert_eq!(SubtensorModule::get_owning_coldkey_for_hotkey(&hot1), cold1); @@ -1404,7 +1404,7 @@ fn test_clear_small_nominations() { assert_ok!(SubtensorModule::do_become_delegate( <::RuntimeOrigin>::signed(cold2), hot2, - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() )); assert_eq!(SubtensorModule::get_owning_coldkey_for_hotkey(&hot2), cold2); @@ -1697,11 +1697,11 @@ fn test_delegate_take_can_be_decreased() { assert_ok!(SubtensorModule::do_become_delegate( <::RuntimeOrigin>::signed(coldkey0), hotkey0, - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() )); assert_eq!( SubtensorModule::get_hotkey_take(&hotkey0), - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() ); // Coldkey / hotkey 0 decreases take to 5%. This should fail as the minimum take is 9% @@ -1743,11 +1743,11 @@ fn test_can_set_min_take_ok() { assert_ok!(SubtensorModule::do_decrease_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() )); assert_eq!( SubtensorModule::get_hotkey_take(&hotkey0), - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() ); }); } @@ -1772,11 +1772,11 @@ fn test_delegate_take_can_not_be_increased_with_decrease_take() { assert_ok!(SubtensorModule::do_become_delegate( <::RuntimeOrigin>::signed(coldkey0), hotkey0, - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() )); assert_eq!( SubtensorModule::get_hotkey_take(&hotkey0), - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() ); // Coldkey / hotkey 0 tries to increase take to 12.5% @@ -1790,7 +1790,7 @@ fn test_delegate_take_can_not_be_increased_with_decrease_take() { ); assert_eq!( SubtensorModule::get_hotkey_take(&hotkey0), - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() ); }); } @@ -1815,11 +1815,11 @@ fn test_delegate_take_can_be_increased() { assert_ok!(SubtensorModule::do_become_delegate( <::RuntimeOrigin>::signed(coldkey0), hotkey0, - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() )); assert_eq!( SubtensorModule::get_hotkey_take(&hotkey0), - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() ); step_block(1 + InitialTxDelegateTakeRateLimit::get() as u16); @@ -1854,11 +1854,11 @@ fn test_delegate_take_can_not_be_decreased_with_increase_take() { assert_ok!(SubtensorModule::do_become_delegate( <::RuntimeOrigin>::signed(coldkey0), hotkey0, - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() )); assert_eq!( SubtensorModule::get_hotkey_take(&hotkey0), - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() ); // Coldkey / hotkey 0 tries to decrease take to 5% @@ -1872,12 +1872,12 @@ fn test_delegate_take_can_not_be_decreased_with_increase_take() { ); assert_eq!( SubtensorModule::get_hotkey_take(&hotkey0), - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() ); }); } -// Verify delegate take can be increased up to InitialDefaultTake (18%) +// Verify delegate take can be increased up to InitialDefaultDelegateTake (18%) #[test] fn test_delegate_take_can_be_increased_to_limit() { new_test_ext(1).execute_with(|| { @@ -1897,29 +1897,29 @@ fn test_delegate_take_can_be_increased_to_limit() { assert_ok!(SubtensorModule::do_become_delegate( <::RuntimeOrigin>::signed(coldkey0), hotkey0, - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() )); assert_eq!( SubtensorModule::get_hotkey_take(&hotkey0), - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() ); step_block(1 + InitialTxDelegateTakeRateLimit::get() as u16); - // Coldkey / hotkey 0 tries to increase take to InitialDefaultTake+1 + // Coldkey / hotkey 0 tries to increase take to InitialDefaultDelegateTake+1 assert_ok!(SubtensorModule::do_increase_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, - InitialDefaultTake::get() + InitialDefaultDelegateTake::get() )); assert_eq!( SubtensorModule::get_hotkey_take(&hotkey0), - InitialDefaultTake::get() + InitialDefaultDelegateTake::get() ); }); } -// Verify delegate take can not be set above InitialDefaultTake +// Verify delegate take can not be set above InitialDefaultDelegateTake #[test] fn test_delegate_take_can_not_be_set_beyond_limit() { new_test_ext(1).execute_with(|| { @@ -1937,13 +1937,13 @@ fn test_delegate_take_can_not_be_set_beyond_limit() { let before = SubtensorModule::get_hotkey_take(&hotkey0); // Coldkey / hotkey 0 attempt to become delegates with take above maximum - // (Disable this check if InitialDefaultTake is u16::MAX) - if InitialDefaultTake::get() != u16::MAX { + // (Disable this check if InitialDefaultDelegateTake is u16::MAX) + if InitialDefaultDelegateTake::get() != u16::MAX { assert_eq!( SubtensorModule::do_become_delegate( <::RuntimeOrigin>::signed(coldkey0), hotkey0, - InitialDefaultTake::get() + 1 + InitialDefaultDelegateTake::get() + 1 ), Err(Error::::DelegateTakeTooHigh.into()) ); @@ -1952,7 +1952,7 @@ fn test_delegate_take_can_not_be_set_beyond_limit() { }); } -// Verify delegate take can not be increased above InitialDefaultTake (18%) +// Verify delegate take can not be increased above InitialDefaultDelegateTake (18%) #[test] fn test_delegate_take_can_not_be_increased_beyond_limit() { new_test_ext(1).execute_with(|| { @@ -1972,28 +1972,28 @@ fn test_delegate_take_can_not_be_increased_beyond_limit() { assert_ok!(SubtensorModule::do_become_delegate( <::RuntimeOrigin>::signed(coldkey0), hotkey0, - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() )); assert_eq!( SubtensorModule::get_hotkey_take(&hotkey0), - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() ); - // Coldkey / hotkey 0 tries to increase take to InitialDefaultTake+1 - // (Disable this check if InitialDefaultTake is u16::MAX) - if InitialDefaultTake::get() != u16::MAX { + // Coldkey / hotkey 0 tries to increase take to InitialDefaultDelegateTake+1 + // (Disable this check if InitialDefaultDelegateTake is u16::MAX) + if InitialDefaultDelegateTake::get() != u16::MAX { assert_eq!( SubtensorModule::do_increase_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, - InitialDefaultTake::get() + 1 + InitialDefaultDelegateTake::get() + 1 ), Err(Error::::DelegateTakeTooHigh.into()) ); } assert_eq!( SubtensorModule::get_hotkey_take(&hotkey0), - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() ); }); } @@ -2018,11 +2018,11 @@ fn test_rate_limits_enforced_on_increase_take() { assert_ok!(SubtensorModule::do_become_delegate( <::RuntimeOrigin>::signed(coldkey0), hotkey0, - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() )); assert_eq!( SubtensorModule::get_hotkey_take(&hotkey0), - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() ); // Coldkey / hotkey 0 increases take to 12.5% @@ -2036,7 +2036,7 @@ fn test_rate_limits_enforced_on_increase_take() { ); assert_eq!( SubtensorModule::get_hotkey_take(&hotkey0), - SubtensorModule::get_min_take() + SubtensorModule::get_min_delegate_take() ); step_block(1 + InitialTxDelegateTakeRateLimit::get() as u16); diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 66951b7fc..1fecf7dbc 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -858,7 +858,9 @@ parameter_types! { pub const SubtensorInitialPruningScore : u16 = u16::MAX; pub const SubtensorInitialBondsMovingAverage: u64 = 900_000; pub const SubtensorInitialDefaultTake: u16 = 11_796; // 18% honest number. - pub const SubtensorInitialMinTake: u16 = 5_898; // 9% + pub const SubtensorInitialMinDelegateTake: u16 = 5_898; // 9% + pub const SubtensorInitialDefaultChildKeyTake: u16 = 11_796; // 18% honest number. + pub const SubtensorInitialMinChildKeyTake: u16 = 5_898; // 9% pub const SubtensorInitialWeightsVersionKey: u64 = 0; pub const SubtensorInitialMinDifficulty: u64 = 10_000_000; pub const SubtensorInitialMaxDifficulty: u64 = u64::MAX / 4; @@ -868,6 +870,7 @@ parameter_types! { pub const SubtensorInitialMaxBurn: u64 = 100_000_000_000; // 100 tao pub const SubtensorInitialTxRateLimit: u64 = 1000; pub const SubtensorInitialTxDelegateTakeRateLimit: u64 = 216000; // 30 days at 12 seconds per block + pub const SubtensorInitialTxChildKeyTakeRateLimit: u64 = 216000; // 30 days at 12 seconds per block pub const SubtensorInitialRAORecycledForRegistration: u64 = 0; // 0 rao pub const SubtensorInitialSenateRequiredStakePercentage: u64 = 1; // 1 percent of total stake pub const SubtensorInitialNetworkImmunity: u64 = 7 * 7200; @@ -914,8 +917,10 @@ impl pallet_subtensor::Config for Runtime { type InitialMaxRegistrationsPerBlock = SubtensorInitialMaxRegistrationsPerBlock; type InitialPruningScore = SubtensorInitialPruningScore; type InitialMaxAllowedValidators = SubtensorInitialMaxAllowedValidators; - type InitialDefaultTake = SubtensorInitialDefaultTake; - type InitialMinTake = SubtensorInitialMinTake; + type InitialDefaultDelegateTake = SubtensorInitialDefaultTake; + type InitialDefaultChildKeyTake = SubtensorInitialDefaultChildKeyTake; + type InitialMinDelegateTake = SubtensorInitialMinDelegateTake; + type InitialMinChildKeyTake = SubtensorInitialMinChildKeyTake; type InitialWeightsVersionKey = SubtensorInitialWeightsVersionKey; type InitialMaxDifficulty = SubtensorInitialMaxDifficulty; type InitialMinDifficulty = SubtensorInitialMinDifficulty; @@ -925,6 +930,7 @@ impl pallet_subtensor::Config for Runtime { type InitialMinBurn = SubtensorInitialMinBurn; type InitialTxRateLimit = SubtensorInitialTxRateLimit; type InitialTxDelegateTakeRateLimit = SubtensorInitialTxDelegateTakeRateLimit; + type InitialTxChildKeyTakeRateLimit = SubtensorInitialTxChildKeyTakeRateLimit; type InitialRAORecycledForRegistration = SubtensorInitialRAORecycledForRegistration; type InitialSenateRequiredStakePercentage = SubtensorInitialSenateRequiredStakePercentage; type InitialNetworkImmunityPeriod = SubtensorInitialNetworkImmunity; diff --git a/scripts/test_specific.sh b/scripts/test_specific.sh index 018872d33..c5b940f0f 100755 --- a/scripts/test_specific.sh +++ b/scripts/test_specific.sh @@ -3,4 +3,4 @@ features="${4:-pow-faucet}" # RUST_LOG="pallet_subtensor=info" cargo test --release --features=$features -p $pallet --test $1 -- $2 --nocapture --exact -RUST_LOG=INFO cargo test --release --features=$features -p $pallet --test $1 -- $2 --nocapture --exact \ No newline at end of file +RUST_LOG=DEBUG cargo test --release --features=$features -p $pallet --test $1 -- $2 --nocapture --exact \ No newline at end of file From 9917c03357f5632ca1e9ff9510a6ccdcf28772cb Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 30 Jul 2024 19:22:23 +0400 Subject: [PATCH 06/31] chore: lints --- pallets/subtensor/src/staking/set_children.rs | 2 +- pallets/subtensor/src/utils.rs | 2 +- pallets/subtensor/tests/children.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pallets/subtensor/src/staking/set_children.rs b/pallets/subtensor/src/staking/set_children.rs index bfe5d1c1e..c62d8f130 100644 --- a/pallets/subtensor/src/staking/set_children.rs +++ b/pallets/subtensor/src/staking/set_children.rs @@ -255,7 +255,7 @@ impl Pallet { // Update the last transaction block let current_block: u64 = >::block_number() .try_into() - .unwrap_or_else(|_| 0); + .unwrap_or(0); Self::set_last_transaction_block( &hotkey, netuid, diff --git a/pallets/subtensor/src/utils.rs b/pallets/subtensor/src/utils.rs index edbe02a36..7f70de0fe 100644 --- a/pallets/subtensor/src/utils.rs +++ b/pallets/subtensor/src/utils.rs @@ -312,7 +312,7 @@ impl Pallet { pub fn get_rate_limit(tx_type: &TransactionType) -> u64 { match tx_type { TransactionType::SetChildren => (DefaultTempo::::get().saturating_mul(2)).into(), // Cannot set children twice within the default tempo period. - TransactionType::SetChildkeyTake => (TxChildkeyTakeRateLimit::::get()).into(), + TransactionType::SetChildkeyTake => TxChildkeyTakeRateLimit::::get(), TransactionType::Unknown => 0, // Default to no limit for unknown types (no limit) } } diff --git a/pallets/subtensor/tests/children.rs b/pallets/subtensor/tests/children.rs index c38005a53..8dfeedc29 100644 --- a/pallets/subtensor/tests/children.rs +++ b/pallets/subtensor/tests/children.rs @@ -874,7 +874,7 @@ fn test_childkey_take_rate_limiting() { // Set a rate limit for childkey take changes let rate_limit: u64 = 100; - SubtensorModule::set_tx_childkey_take_rate_limit(rate_limit.into()); + SubtensorModule::set_tx_childkey_take_rate_limit(rate_limit); log::info!( "TxChildkeyTakeRateLimit: {:?}", From b656a583b563bb55f24d6536f4377f27669c0159 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 30 Jul 2024 20:16:02 +0400 Subject: [PATCH 07/31] feat: benchmarks --- pallets/subtensor/src/benchmarks.rs | 30 +++++++++++++++++++++- pallets/subtensor/src/macros/dispatches.rs | 13 +++++----- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 03e087a92..25176dab7 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -159,7 +159,7 @@ benchmarks! { Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), wallet_bal); assert_ok!(Subtensor::::do_burned_registration(RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone())); - assert_ok!(Subtensor::::do_become_delegate(RawOrigin::Signed(coldkey.clone()).into(), hotkey.clone(), Subtensor::::get_default_take())); + assert_ok!(Subtensor::::do_become_delegate(RawOrigin::Signed(coldkey.clone()).into(), hotkey.clone(), Subtensor::::get_default_delegate_take())); // Stake 10% of our current total staked TAO let u64_staked_amt = 100_000_000_000; @@ -429,4 +429,32 @@ reveal_weights { }: reveal_weights(RawOrigin::Signed(hotkey.clone()), netuid, uids, weight_values, salt, version_key) + benchmark_sudo_set_tx_childkey_take_rate_limit { + // We don't need to set up any initial state for this benchmark + // as it's a simple setter function that only requires root origin + let new_rate_limit: u64 = 100; +}: sudo_set_tx_childkey_take_rate_limit(RawOrigin::Root, new_rate_limit) + +benchmark_set_childkey_take { + // Setup + let netuid: u16 = 1; + let tempo: u16 = 1; + let seed: u32 = 1; + let coldkey: T::AccountId = account("Cold", 0, seed); + let hotkey: T::AccountId = account("Hot", 0, seed); + let take: u16 = 1000; // 10% in basis points + + // Initialize the network + Subtensor::::init_new_network(netuid, tempo); + + // Register the hotkey + Subtensor::::set_burn(netuid, 1); + let amount_to_be_staked = 1_000_000u32.into(); + Subtensor::::add_balance_to_coldkey_account(&coldkey, amount_to_be_staked); + assert_ok!(Subtensor::::do_burned_registration(RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone())); + + // Ensure the coldkey owns the hotkey + // Subtensor::::set_coldkey_ownership(coldkey.clone(), hotkey.clone(), true); + +}: set_childkey_take(RawOrigin::Signed(coldkey), hotkey, netuid, take) } diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 7954e77c1..26cba6abd 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -739,9 +739,9 @@ mod dispatches { /// #[pallet::call_index(68)] #[pallet::weight(( - Weight::from_parts(10_000_000, 0) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)), + Weight::from_parts(34_000, 0) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(2)), DispatchClass::Normal, Pays::Yes ))] @@ -757,6 +757,8 @@ mod dispatches { Self::do_set_childkey_take(coldkey, hotkey, netuid, take) } + // ---- SUDO ONLY FUNCTIONS ------------------------------------------------------------ + /// Sets the transaction rate limit for changing childkey take. /// /// This function can only be called by the root origin. @@ -771,8 +773,7 @@ mod dispatches { // TODO: Benchmark this call #[pallet::call_index(69)] #[pallet::weight(( - Weight::from_parts(10_000_000, 0) - .saturating_add(T::DbWeight::get().reads(1)) + Weight::from_parts(6_000, 0) .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Operational, Pays::No @@ -786,8 +787,6 @@ mod dispatches { Ok(()) } - // ---- SUDO ONLY FUNCTIONS ------------------------------------------------------------ - // ================================== // ==== Parameter Sudo calls ======== // ================================== From ee8aa6b52cafb3b0d51899e767f9612a37767029 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 30 Jul 2024 20:16:19 +0400 Subject: [PATCH 08/31] chore: remove todos --- pallets/subtensor/src/macros/dispatches.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index 26cba6abd..95dec13d3 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -770,7 +770,6 @@ mod dispatches { /// # Errors: /// * `BadOrigin` - If the origin is not root. /// - // TODO: Benchmark this call #[pallet::call_index(69)] #[pallet::weight(( Weight::from_parts(6_000, 0) From c1dbc59c3f0e6d8fea4555a4fc5590edc091a821 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 30 Jul 2024 20:17:13 +0400 Subject: [PATCH 09/31] chore: remove more comments --- pallets/subtensor/src/benchmarks.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 25176dab7..0a251894e 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -452,9 +452,5 @@ benchmark_set_childkey_take { let amount_to_be_staked = 1_000_000u32.into(); Subtensor::::add_balance_to_coldkey_account(&coldkey, amount_to_be_staked); assert_ok!(Subtensor::::do_burned_registration(RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone())); - - // Ensure the coldkey owns the hotkey - // Subtensor::::set_coldkey_ownership(coldkey.clone(), hotkey.clone(), true); - }: set_childkey_take(RawOrigin::Signed(coldkey), hotkey, netuid, take) } From 01cabbdc033f9455aa30ae14ccba2fa507327cd7 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 30 Jul 2024 20:25:27 +0400 Subject: [PATCH 10/31] chore: multiple network child key takes --- pallets/subtensor/tests/children.rs | 52 +++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/pallets/subtensor/tests/children.rs b/pallets/subtensor/tests/children.rs index 8dfeedc29..68e13e56e 100644 --- a/pallets/subtensor/tests/children.rs +++ b/pallets/subtensor/tests/children.rs @@ -969,6 +969,58 @@ fn test_childkey_take_rate_limiting() { }); } +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_multiple_networks_childkey_take --exact --nocapture +#[test] +fn test_multiple_networks_childkey_take() { + new_test_ext(1).execute_with(|| { + const NUM_NETWORKS: u16 = 10; + let coldkey = U256::from(1); + let hotkey = U256::from(2); + + // Create 10 networks and set up neurons (skip network 0) + for netuid in 1..NUM_NETWORKS { + // Add network + add_network(netuid, 13, 0); + + // Register neuron + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set a unique childkey take value for each network + let take_value = (netuid as u16 + 1) * 1000; // Values will be 1000, 2000, ..., 10000 + assert_ok!(SubtensorModule::set_childkey_take( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + take_value + )); + + // Verify the childkey take was set correctly + let stored_take = SubtensorModule::get_childkey_take(&hotkey, netuid); + assert_eq!( + stored_take, take_value, + "Childkey take not set correctly for network {}", + netuid + ); + + // Log the set value + log::info!("Network {}: Childkey take set to {}", netuid, take_value); + } + + // Verify all networks have different childkey take values + for i in 1..NUM_NETWORKS { + for j in (i + 1)..NUM_NETWORKS { + let take_i = SubtensorModule::get_childkey_take(&hotkey, i); + let take_j = SubtensorModule::get_childkey_take(&hotkey, j); + assert_ne!( + take_i, take_j, + "Childkey take values should be different for networks {} and {}", + i, j + ); + } + } + }); +} + #[test] fn test_do_set_children_multiple_empty_list() { new_test_ext(1).execute_with(|| { From f7f243cef46dc6245eaa6d60e99a8a59ccedeee1 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Tue, 30 Jul 2024 20:30:26 +0400 Subject: [PATCH 11/31] chore: clippy --- pallets/subtensor/tests/children.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/subtensor/tests/children.rs b/pallets/subtensor/tests/children.rs index 68e13e56e..147a8edae 100644 --- a/pallets/subtensor/tests/children.rs +++ b/pallets/subtensor/tests/children.rs @@ -986,7 +986,7 @@ fn test_multiple_networks_childkey_take() { register_ok_neuron(netuid, hotkey, coldkey, 0); // Set a unique childkey take value for each network - let take_value = (netuid as u16 + 1) * 1000; // Values will be 1000, 2000, ..., 10000 + let take_value = (netuid + 1) * 1000; // Values will be 1000, 2000, ..., 10000 assert_ok!(SubtensorModule::set_childkey_take( RuntimeOrigin::signed(coldkey), hotkey, From 06f1b9d44504a501492f6a4c30d8d148ab4edf94 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Wed, 31 Jul 2024 00:17:30 +0400 Subject: [PATCH 12/31] bump spec version --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 1fecf7dbc..4f10474c8 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -139,7 +139,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: 191, + spec_version: 192, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From d8acb8bc10fa6148f188c15d76a88fdf7a7f32f2 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Wed, 31 Jul 2024 01:40:10 +0400 Subject: [PATCH 13/31] feat: isabella question --- pallets/subtensor/tests/children.rs | 96 +++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/pallets/subtensor/tests/children.rs b/pallets/subtensor/tests/children.rs index 147a8edae..9db206c06 100644 --- a/pallets/subtensor/tests/children.rs +++ b/pallets/subtensor/tests/children.rs @@ -1487,3 +1487,99 @@ fn test_children_stake_values() { ); }); } + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_get_parents_chain --exact --nocapture +#[test] +fn test_get_parents_chain() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let coldkey = U256::from(1); + let num_keys: usize = 5; + let proportion = u64::MAX / 2; // 50% stake allocation + + log::info!("Test setup: netuid={}, coldkey={}, num_keys={}, proportion={}", netuid, coldkey, num_keys, proportion); + + // Create a vector of hotkeys + let hotkeys: Vec = (0..num_keys).map(|i| U256::from(i as u64 + 2)).collect(); + log::info!("Created hotkeys: {:?}", hotkeys); + + // Add network + add_network(netuid, 13, 0); + SubtensorModule::set_max_registrations_per_block(netuid, 1000); + SubtensorModule::set_target_registrations_per_interval(netuid, 1000); + log::info!("Network added and parameters set: netuid={}", netuid); + + // Register all neurons + for hotkey in &hotkeys { + register_ok_neuron(netuid, *hotkey, coldkey, 0); + log::info!("Registered neuron: hotkey={}, coldkey={}, netuid={}", hotkey, coldkey, netuid); + } + + // Set up parent-child relationships + for i in 0..num_keys - 1 { + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkeys[i], + netuid, + vec![(proportion, hotkeys[i + 1])] + )); + log::info!("Set parent-child relationship: parent={}, child={}, proportion={}", hotkeys[i], hotkeys[i + 1], proportion); + } + + // Test get_parents for each hotkey + for i in 1..num_keys { + let parents = SubtensorModule::get_parents(&hotkeys[i], netuid); + log::info!("Testing get_parents for hotkey {}: {:?}", hotkeys[i], parents); + assert_eq!( + parents.len(), + 1, + "Hotkey {} should have exactly one parent", + i + ); + assert_eq!( + parents[0], + (proportion, hotkeys[i - 1]), + "Incorrect parent for hotkey {}", + i + ); + } + + // Test get_parents for the root (should be empty) + let root_parents = SubtensorModule::get_parents(&hotkeys[0], netuid); + log::info!("Testing get_parents for root hotkey {}: {:?}", hotkeys[0], root_parents); + assert!( + root_parents.is_empty(), + "Root hotkey should have no parents" + ); + + // Test multiple parents + let last_hotkey = hotkeys[num_keys - 1]; + let new_parent = U256::from(num_keys as u64 + 2); + register_ok_neuron(netuid, new_parent, coldkey, 0); + log::info!("Registered new parent neuron: new_parent={}, coldkey={}, netuid={}", new_parent, coldkey, netuid); + + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + new_parent, + netuid, + vec![(proportion / 2, last_hotkey)] + )); + log::info!("Set additional parent-child relationship: parent={}, child={}, proportion={}", new_parent, last_hotkey, proportion / 2); + + let last_hotkey_parents = SubtensorModule::get_parents(&last_hotkey, netuid); + log::info!("Testing get_parents for last hotkey {} with multiple parents: {:?}", last_hotkey, last_hotkey_parents); + assert_eq!( + last_hotkey_parents.len(), + 2, + "Last hotkey should have two parents" + ); + assert!( + last_hotkey_parents.contains(&(proportion, hotkeys[num_keys - 2])), + "Last hotkey should still have its original parent" + ); + assert!( + last_hotkey_parents.contains(&(proportion / 2, new_parent)), + "Last hotkey should have the new parent" + ); + }); +} From 5d48fae1b40c919db94ee7e5ce38080c300cf959 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Wed, 31 Jul 2024 12:03:16 +0400 Subject: [PATCH 14/31] chore: PR review comments --- pallets/subtensor/src/lib.rs | 11 +- pallets/subtensor/src/staking/set_children.rs | 9 +- pallets/subtensor/tests/children.rs | 106 ++++++++++++++++-- runtime/src/lib.rs | 4 +- scripts/test_specific.sh | 4 +- 5 files changed, 117 insertions(+), 17 deletions(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index c58c6a0c6..89aa76bb7 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -628,8 +628,15 @@ pub mod pallet { StorageMap<_, Blake2_128Concat, T::AccountId, u16, ValueQuery, DefaultDelegateTake>; #[pallet::storage] /// DMAP ( hot, netuid ) --> take | Returns the hotkey childkey take for a specific subnet - pub type ChildkeyTake = - StorageMap<_, Blake2_128Concat, (T::AccountId, u16), u16, ValueQuery>; + pub type ChildkeyTake = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, // First key: hotkey + Identity, + u16, // Second key: netuid + u16, // Value: take + ValueQuery, + >; #[pallet::storage] /// DMAP ( hot, cold ) --> stake | Returns the stake under a coldkey prefixed by hotkey. diff --git a/pallets/subtensor/src/staking/set_children.rs b/pallets/subtensor/src/staking/set_children.rs index c62d8f130..f60298d57 100644 --- a/pallets/subtensor/src/staking/set_children.rs +++ b/pallets/subtensor/src/staking/set_children.rs @@ -130,6 +130,11 @@ impl Pallet { // --- 7.1. Insert my new children + proportion list into the map. ChildKeys::::insert(hotkey.clone(), netuid, children.clone()); + if children.is_empty() { + // If there are no children, remove the ChildkeyTake value + ChildkeyTake::::remove(hotkey.clone(), netuid); + } + // --- 7.2. Update the parents list for my new children. for (proportion, new_child_i) in children.clone().iter() { // --- 8.2.1. Get the child's parents on this network. @@ -243,7 +248,7 @@ impl Pallet { ); // Set the new childkey take value for the given hotkey and network - ChildkeyTake::::insert((hotkey.clone(), netuid), take); + ChildkeyTake::::insert(hotkey.clone(), netuid, take); // TODO: Consider adding a check to ensure the hotkey is registered on the specified network (netuid) // before setting the childkey take. This could prevent setting takes for non-existent or @@ -286,6 +291,6 @@ impl Pallet { /// * `u16` - The childkey take value. This is a percentage represented as a value between 0 and 10000, /// where 10000 represents 100%. pub fn get_childkey_take(hotkey: &T::AccountId, netuid: u16) -> u16 { - ChildkeyTake::::get((hotkey, netuid)) + ChildkeyTake::::get(hotkey, netuid) } } diff --git a/pallets/subtensor/tests/children.rs b/pallets/subtensor/tests/children.rs index 9db206c06..0025dd24a 100644 --- a/pallets/subtensor/tests/children.rs +++ b/pallets/subtensor/tests/children.rs @@ -1497,7 +1497,13 @@ fn test_get_parents_chain() { let num_keys: usize = 5; let proportion = u64::MAX / 2; // 50% stake allocation - log::info!("Test setup: netuid={}, coldkey={}, num_keys={}, proportion={}", netuid, coldkey, num_keys, proportion); + log::info!( + "Test setup: netuid={}, coldkey={}, num_keys={}, proportion={}", + netuid, + coldkey, + num_keys, + proportion + ); // Create a vector of hotkeys let hotkeys: Vec = (0..num_keys).map(|i| U256::from(i as u64 + 2)).collect(); @@ -1512,7 +1518,12 @@ fn test_get_parents_chain() { // Register all neurons for hotkey in &hotkeys { register_ok_neuron(netuid, *hotkey, coldkey, 0); - log::info!("Registered neuron: hotkey={}, coldkey={}, netuid={}", hotkey, coldkey, netuid); + log::info!( + "Registered neuron: hotkey={}, coldkey={}, netuid={}", + hotkey, + coldkey, + netuid + ); } // Set up parent-child relationships @@ -1523,13 +1534,22 @@ fn test_get_parents_chain() { netuid, vec![(proportion, hotkeys[i + 1])] )); - log::info!("Set parent-child relationship: parent={}, child={}, proportion={}", hotkeys[i], hotkeys[i + 1], proportion); + log::info!( + "Set parent-child relationship: parent={}, child={}, proportion={}", + hotkeys[i], + hotkeys[i + 1], + proportion + ); } // Test get_parents for each hotkey for i in 1..num_keys { let parents = SubtensorModule::get_parents(&hotkeys[i], netuid); - log::info!("Testing get_parents for hotkey {}: {:?}", hotkeys[i], parents); + log::info!( + "Testing get_parents for hotkey {}: {:?}", + hotkeys[i], + parents + ); assert_eq!( parents.len(), 1, @@ -1546,7 +1566,11 @@ fn test_get_parents_chain() { // Test get_parents for the root (should be empty) let root_parents = SubtensorModule::get_parents(&hotkeys[0], netuid); - log::info!("Testing get_parents for root hotkey {}: {:?}", hotkeys[0], root_parents); + log::info!( + "Testing get_parents for root hotkey {}: {:?}", + hotkeys[0], + root_parents + ); assert!( root_parents.is_empty(), "Root hotkey should have no parents" @@ -1556,7 +1580,12 @@ fn test_get_parents_chain() { let last_hotkey = hotkeys[num_keys - 1]; let new_parent = U256::from(num_keys as u64 + 2); register_ok_neuron(netuid, new_parent, coldkey, 0); - log::info!("Registered new parent neuron: new_parent={}, coldkey={}, netuid={}", new_parent, coldkey, netuid); + log::info!( + "Registered new parent neuron: new_parent={}, coldkey={}, netuid={}", + new_parent, + coldkey, + netuid + ); assert_ok!(SubtensorModule::do_set_children( RuntimeOrigin::signed(coldkey), @@ -1564,10 +1593,19 @@ fn test_get_parents_chain() { netuid, vec![(proportion / 2, last_hotkey)] )); - log::info!("Set additional parent-child relationship: parent={}, child={}, proportion={}", new_parent, last_hotkey, proportion / 2); + log::info!( + "Set additional parent-child relationship: parent={}, child={}, proportion={}", + new_parent, + last_hotkey, + proportion / 2 + ); let last_hotkey_parents = SubtensorModule::get_parents(&last_hotkey, netuid); - log::info!("Testing get_parents for last hotkey {} with multiple parents: {:?}", last_hotkey, last_hotkey_parents); + log::info!( + "Testing get_parents for last hotkey {} with multiple parents: {:?}", + last_hotkey, + last_hotkey_parents + ); assert_eq!( last_hotkey_parents.len(), 2, @@ -1583,3 +1621,55 @@ fn test_get_parents_chain() { ); }); } + +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_childkey_take_removal_on_empty_children --exact --nocapture +#[test] +fn test_childkey_take_removal_on_empty_children() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(2); + let child = U256::from(3); + let netuid: u16 = 1; + let proportion: u64 = 1000; + + // Add network and register hotkey + add_network(netuid, 13, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + // Set a child and childkey take + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![(proportion, child)] + )); + + let take: u16 = u16::MAX / 10; // 10% take + assert_ok!(SubtensorModule::set_childkey_take( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + take + )); + + // Verify childkey take is set + assert_eq!(SubtensorModule::get_childkey_take(&hotkey, netuid), take); + + // Remove all children + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + hotkey, + netuid, + vec![] + )); + + // Verify children are removed + let children = SubtensorModule::get_children(&hotkey, netuid); + assert!(children.is_empty()); + + // Verify childkey take is removed + assert_eq!(SubtensorModule::get_childkey_take(&hotkey, netuid), 0); + // Verify childkey take storage is empty + assert_eq!(ChildkeyTake::::get(hotkey, netuid), 0); + }); +} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 4f10474c8..20d337d64 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -858,8 +858,8 @@ parameter_types! { pub const SubtensorInitialPruningScore : u16 = u16::MAX; pub const SubtensorInitialBondsMovingAverage: u64 = 900_000; pub const SubtensorInitialDefaultTake: u16 = 11_796; // 18% honest number. - pub const SubtensorInitialMinDelegateTake: u16 = 5_898; // 9% - pub const SubtensorInitialDefaultChildKeyTake: u16 = 11_796; // 18% honest number. + pub const SubtensorInitialMinDelegateTake: u16 = 0; // Allow 0% delegate take + pub const SubtensorInitialDefaultChildKeyTake: u16 = 0; // Allow 0% childkey take pub const SubtensorInitialMinChildKeyTake: u16 = 5_898; // 9% pub const SubtensorInitialWeightsVersionKey: u64 = 0; pub const SubtensorInitialMinDifficulty: u64 = 10_000_000; diff --git a/scripts/test_specific.sh b/scripts/test_specific.sh index c5b940f0f..85f3ebe30 100755 --- a/scripts/test_specific.sh +++ b/scripts/test_specific.sh @@ -1,6 +1,4 @@ pallet="${3:-pallet-subtensor}" features="${4:-pow-faucet}" -# RUST_LOG="pallet_subtensor=info" cargo test --release --features=$features -p $pallet --test $1 -- $2 --nocapture --exact - -RUST_LOG=DEBUG cargo test --release --features=$features -p $pallet --test $1 -- $2 --nocapture --exact \ No newline at end of file +SKIP_WASM_BUILD=1 RUST_LOG=DEBUG cargo test --release --features=$features -p $pallet --test $1 -- $2 --nocapture --exact \ No newline at end of file From b1037ab0ff7566ccaea79679d482b19a1def8a18 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Wed, 31 Jul 2024 12:09:40 +0400 Subject: [PATCH 15/31] chore: clippy --- pallets/subtensor/tests/children.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/pallets/subtensor/tests/children.rs b/pallets/subtensor/tests/children.rs index 0025dd24a..2a15d05d6 100644 --- a/pallets/subtensor/tests/children.rs +++ b/pallets/subtensor/tests/children.rs @@ -1,3 +1,4 @@ +#![allow(clippy::indexing_slicing)] use crate::mock::*; use frame_support::{assert_err, assert_noop, assert_ok}; mod mock; From 531417a2788947fbdfc7773e7ae92fda8d211362 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Wed, 31 Jul 2024 12:11:44 +0400 Subject: [PATCH 16/31] chore: bump spec --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 20d337d64..c7187e0f4 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -139,7 +139,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: 192, + spec_version: 193, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From 06013f87ea9eb3884f4300c8bc0d151623266a38 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Fri, 2 Aug 2024 14:38:52 +0400 Subject: [PATCH 17/31] chore: remove childkey take removal --- pallets/admin-utils/tests/mock.rs | 5 +- pallets/subtensor/src/staking/set_children.rs | 5 -- pallets/subtensor/tests/children.rs | 52 ------------------- 3 files changed, 2 insertions(+), 60 deletions(-) diff --git a/pallets/admin-utils/tests/mock.rs b/pallets/admin-utils/tests/mock.rs index 0142a435a..acb9c8a4a 100644 --- a/pallets/admin-utils/tests/mock.rs +++ b/pallets/admin-utils/tests/mock.rs @@ -79,9 +79,8 @@ parameter_types! { pub const InitialFoundationDistribution: u64 = 0; pub const InitialDefaultDelegateTake: u16 = 11_796; // 18% honest number. pub const InitialMinDelegateTake: u16 = 5_898; // 9%; - pub const InitialDefaultChildKeyTake: u16 = 11_796; // 18% honest number. - pub const InitialMinChildKeyTake: u16 = 5_898; // 9%; - pub const InitialMinTake: u16 = 5_898; // 9%; + pub const InitialDefaultChildKeyTake: u16 = 0; // Allow 0 % + pub const InitialMinChildKeyTake: u16 = 0; // Allow 0 % pub const InitialWeightsVersionKey: u16 = 0; pub const InitialServingRateLimit: u64 = 0; // No limit. pub const InitialTxRateLimit: u64 = 0; // Disable rate limit for testing diff --git a/pallets/subtensor/src/staking/set_children.rs b/pallets/subtensor/src/staking/set_children.rs index f60298d57..fda0ae27b 100644 --- a/pallets/subtensor/src/staking/set_children.rs +++ b/pallets/subtensor/src/staking/set_children.rs @@ -130,11 +130,6 @@ impl Pallet { // --- 7.1. Insert my new children + proportion list into the map. ChildKeys::::insert(hotkey.clone(), netuid, children.clone()); - if children.is_empty() { - // If there are no children, remove the ChildkeyTake value - ChildkeyTake::::remove(hotkey.clone(), netuid); - } - // --- 7.2. Update the parents list for my new children. for (proportion, new_child_i) in children.clone().iter() { // --- 8.2.1. Get the child's parents on this network. diff --git a/pallets/subtensor/tests/children.rs b/pallets/subtensor/tests/children.rs index 2a15d05d6..6a37b5bea 100644 --- a/pallets/subtensor/tests/children.rs +++ b/pallets/subtensor/tests/children.rs @@ -1622,55 +1622,3 @@ fn test_get_parents_chain() { ); }); } - -// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_childkey_take_removal_on_empty_children --exact --nocapture -#[test] -fn test_childkey_take_removal_on_empty_children() { - new_test_ext(1).execute_with(|| { - let coldkey = U256::from(1); - let hotkey = U256::from(2); - let child = U256::from(3); - let netuid: u16 = 1; - let proportion: u64 = 1000; - - // Add network and register hotkey - add_network(netuid, 13, 0); - register_ok_neuron(netuid, hotkey, coldkey, 0); - - // Set a child and childkey take - assert_ok!(SubtensorModule::do_set_children( - RuntimeOrigin::signed(coldkey), - hotkey, - netuid, - vec![(proportion, child)] - )); - - let take: u16 = u16::MAX / 10; // 10% take - assert_ok!(SubtensorModule::set_childkey_take( - RuntimeOrigin::signed(coldkey), - hotkey, - netuid, - take - )); - - // Verify childkey take is set - assert_eq!(SubtensorModule::get_childkey_take(&hotkey, netuid), take); - - // Remove all children - assert_ok!(SubtensorModule::do_set_children( - RuntimeOrigin::signed(coldkey), - hotkey, - netuid, - vec![] - )); - - // Verify children are removed - let children = SubtensorModule::get_children(&hotkey, netuid); - assert!(children.is_empty()); - - // Verify childkey take is removed - assert_eq!(SubtensorModule::get_childkey_take(&hotkey, netuid), 0); - // Verify childkey take storage is empty - assert_eq!(ChildkeyTake::::get(hotkey, netuid), 0); - }); -} From 9b557c43e484cb8feda2a4ccbc95561630fa7a41 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Mon, 5 Aug 2024 16:54:45 +0400 Subject: [PATCH 18/31] feat: fix child take tests --- pallets/subtensor/src/lib.rs | 6 +- pallets/subtensor/src/macros/dispatches.rs | 2 +- pallets/subtensor/src/staking/set_children.rs | 30 ++-- pallets/subtensor/src/utils/misc.rs | 78 +++++------ pallets/subtensor/src/utils/rate_limiting.rs | 17 ++- pallets/subtensor/tests/children.rs | 132 +++++++++--------- pallets/subtensor/tests/mock.rs | 3 +- runtime/src/lib.rs | 2 +- 8 files changed, 143 insertions(+), 127 deletions(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 93fa6a6f2..edc9040ac 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1137,7 +1137,11 @@ pub mod pallet { pub type LastTxBlock = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; #[pallet::storage] - /// --- MAP ( key ) --> last_block + /// --- MAP ( key ) --> last_tx_block_childkey_take + pub type LastTxBlockChildKeyTake = + StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; + #[pallet::storage] + /// --- MAP ( key ) --> last_tx_block_delegate_take pub type LastTxBlockDelegateTake = StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultLastTxBlock>; #[pallet::storage] diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index f62efd94c..a776cfc4f 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -737,7 +737,7 @@ mod dispatches { /// * `TxChildkeyTakeRateLimitExceeded`: /// - The rate limit for changing childkey take has been exceeded. /// - #[pallet::call_index(68)] + #[pallet::call_index(75)] #[pallet::weight(( Weight::from_parts(34_000, 0) .saturating_add(T::DbWeight::get().reads(4)) diff --git a/pallets/subtensor/src/staking/set_children.rs b/pallets/subtensor/src/staking/set_children.rs index fda0ae27b..402e9fd2a 100644 --- a/pallets/subtensor/src/staking/set_children.rs +++ b/pallets/subtensor/src/staking/set_children.rs @@ -236,26 +236,28 @@ impl Pallet { Error::::InvalidChildkeyTake ); - // Ensure the hotkey passes the rate limit - ensure!( - Self::passes_rate_limit_on_subnet(&TransactionType::SetChildkeyTake, &hotkey, netuid), - Error::::TxChildkeyTakeRateLimitExceeded + // Check if the rate limit has been exceeded + let current_block = Self::get_current_block_as_u64(); + let last_tx_block = + Self::get_last_transaction_block(&hotkey, netuid, &TransactionType::SetChildkeyTake); + let rate_limit = TxChildkeyTakeRateLimit::::get(); + let passes = + Self::passes_rate_limit_on_subnet(&TransactionType::SetChildkeyTake, &hotkey, netuid); + + log::info!( + "Rate limit check: current_block: {}, last_tx_block: {}, rate_limit: {}, passes: {}", + current_block, + last_tx_block, + rate_limit, + passes ); + ensure!(passes, Error::::TxChildkeyTakeRateLimitExceeded); + // Set the new childkey take value for the given hotkey and network ChildkeyTake::::insert(hotkey.clone(), netuid, take); - // TODO: Consider adding a check to ensure the hotkey is registered on the specified network (netuid) - // before setting the childkey take. This could prevent setting takes for non-existent or - // unregistered hotkeys. - - // NOTE: The childkey take is now associated with both the hotkey and the network ID. - // This allows for different take values across different networks for the same hotkey. - // Update the last transaction block - let current_block: u64 = >::block_number() - .try_into() - .unwrap_or(0); Self::set_last_transaction_block( &hotkey, netuid, diff --git a/pallets/subtensor/src/utils/misc.rs b/pallets/subtensor/src/utils/misc.rs index 9155357c0..c75ce1a8d 100644 --- a/pallets/subtensor/src/utils/misc.rs +++ b/pallets/subtensor/src/utils/misc.rs @@ -8,33 +8,6 @@ use sp_core::U256; use sp_runtime::Saturating; use substrate_fixed::types::I32F32; -/// Enum representing different types of transactions -#[derive(Copy, Clone)] -pub enum TransactionType { - SetChildren, - Unknown, -} - -/// Implement conversion from TransactionType to u16 -impl From 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 for TransactionType { - fn from(value: u16) -> Self { - match value { - 0 => TransactionType::SetChildren, - _ => TransactionType::Unknown, - } - } -} - impl Pallet { pub fn ensure_subnet_owner_or_root( o: T::RuntimeOrigin, @@ -312,17 +285,7 @@ impl Pallet { pub fn coinbase(amount: u64) { TotalIssuance::::put(TotalIssuance::::get().saturating_add(amount)); } - pub fn get_default_take() -> u16 { - // Default to maximum - MaxTake::::get() - } - pub fn set_max_take(default_take: u16) { - MaxTake::::put(default_take); - Self::deposit_event(Event::DefaultTakeSet(default_take)); - } - pub fn get_min_take() -> u16 { - MinTake::::get() - } + pub fn set_subnet_locked_balance(netuid: u16, amount: u64) { SubnetLocked::::insert(netuid, amount); } @@ -357,18 +320,49 @@ impl Pallet { Self::deposit_event(Event::TxDelegateTakeRateLimitSet(tx_rate_limit)); } pub fn set_min_delegate_take(take: u16) { - MinTake::::put(take); + MinDelegateTake::::put(take); Self::deposit_event(Event::MinDelegateTakeSet(take)); } pub fn set_max_delegate_take(take: u16) { - MaxTake::::put(take); + MaxDelegateTake::::put(take); Self::deposit_event(Event::MaxDelegateTakeSet(take)); } pub fn get_min_delegate_take() -> u16 { - MinTake::::get() + MinDelegateTake::::get() } pub fn get_max_delegate_take() -> u16 { - MaxTake::::get() + MaxDelegateTake::::get() + } + pub fn get_default_delegate_take() -> u16 { + // Default to maximum + MaxDelegateTake::::get() + } + // get_default_childkey_take + pub fn get_default_childkey_take() -> u16 { + // Default to maximum + MinChildkeyTake::::get() + } + pub fn get_tx_childkey_take_rate_limit() -> u64 { + TxChildkeyTakeRateLimit::::get() + } + pub fn set_tx_childkey_take_rate_limit(tx_rate_limit: u64) { + TxChildkeyTakeRateLimit::::put(tx_rate_limit); + Self::deposit_event(Event::TxChildKeyTakeRateLimitSet(tx_rate_limit)); + } + pub fn set_min_childkey_take(take: u16) { + MinChildkeyTake::::put(take); + Self::deposit_event(Event::MinChildKeyTakeSet(take)); + } + pub fn set_max_childkey_take(take: u16) { + MaxChildkeyTake::::put(take); + Self::deposit_event(Event::MaxChildKeyTakeSet(take)); + } + pub fn get_min_childkey_take() -> u16 { + MinChildkeyTake::::get() + } + + pub fn get_max_childkey_take() -> u16 { + MaxChildkeyTake::::get() } pub fn get_serving_rate_limit(netuid: u16) -> u64 { diff --git a/pallets/subtensor/src/utils/rate_limiting.rs b/pallets/subtensor/src/utils/rate_limiting.rs index ffd17ca93..b02ad9855 100644 --- a/pallets/subtensor/src/utils/rate_limiting.rs +++ b/pallets/subtensor/src/utils/rate_limiting.rs @@ -5,6 +5,7 @@ use sp_core::Get; #[derive(Copy, Clone)] pub enum TransactionType { SetChildren, + SetChildkeyTake, Unknown, } @@ -13,7 +14,8 @@ impl From for u16 { fn from(tx_type: TransactionType) -> Self { match tx_type { TransactionType::SetChildren => 0, - TransactionType::Unknown => 1, + TransactionType::SetChildkeyTake => 1, + TransactionType::Unknown => 2, } } } @@ -23,6 +25,7 @@ impl From for TransactionType { fn from(value: u16) -> Self { match value { 0 => TransactionType::SetChildren, + 1 => TransactionType::SetChildkeyTake, _ => TransactionType::Unknown, } } @@ -35,6 +38,7 @@ impl Pallet { pub fn get_rate_limit(tx_type: &TransactionType) -> u64 { match tx_type { TransactionType::SetChildren => (DefaultTempo::::get().saturating_mul(2)).into(), // Cannot set children twice within the default tempo period. + TransactionType::SetChildkeyTake => TxChildkeyTakeRateLimit::::get(), TransactionType::Unknown => 0, // Default to no limit for unknown types (no limit) } } @@ -48,7 +52,9 @@ impl Pallet { 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 + + // Allow the first transaction (when last_block is 0) or if the rate limit has passed + last_block == 0 || block.saturating_sub(last_block) >= limit } /// Check if a transaction should be rate limited globally @@ -93,6 +99,13 @@ impl Pallet { pub fn get_last_tx_block_delegate_take(key: &T::AccountId) -> u64 { LastTxBlockDelegateTake::::get(key) } + + pub fn set_last_tx_block_childkey_take(key: &T::AccountId, block: u64) { + LastTxBlockChildKeyTake::::insert(key, block) + } + pub fn get_last_tx_block_childkey_take(key: &T::AccountId) -> u64 { + LastTxBlockChildKeyTake::::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 { diff --git a/pallets/subtensor/tests/children.rs b/pallets/subtensor/tests/children.rs index 6a37b5bea..b675ff8e9 100644 --- a/pallets/subtensor/tests/children.rs +++ b/pallets/subtensor/tests/children.rs @@ -2,7 +2,7 @@ use crate::mock::*; use frame_support::{assert_err, assert_noop, assert_ok}; mod mock; -use pallet_subtensor::{utils::TransactionType, *}; +use pallet_subtensor::{utils::rate_limiting::TransactionType, *}; use sp_core::U256; // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_success --exact --nocapture @@ -806,12 +806,12 @@ fn test_childkey_take_functionality() { // Test default and max childkey take let default_take = SubtensorModule::get_default_childkey_take(); - let max_take = SubtensorModule::get_max_childkey_take(); - log::info!("Default take: {}, Max take: {}", default_take, max_take); + let min_take = SubtensorModule::get_min_childkey_take(); + log::info!("Default take: {}, Max take: {}", default_take, min_take); // Check if default take and max take are the same assert_eq!( - default_take, max_take, + default_take, min_take, "Default take should be equal to max take" ); @@ -822,7 +822,7 @@ fn test_childkey_take_functionality() { ); // Test setting childkey take - let new_take: u16 = max_take / 2; // 50% of max_take + let new_take: u16 = SubtensorModule::get_max_childkey_take() / 2; // 50% of max_take assert_ok!(SubtensorModule::set_childkey_take( RuntimeOrigin::signed(coldkey), hotkey, @@ -836,7 +836,7 @@ fn test_childkey_take_functionality() { assert_eq!(stored_take, new_take); // Test setting childkey take outside of allowed range - let invalid_take: u16 = max_take + 1; + let invalid_take: u16 = SubtensorModule::get_max_childkey_take() + 1; assert_noop!( SubtensorModule::set_childkey_take( RuntimeOrigin::signed(coldkey), @@ -878,91 +878,75 @@ fn test_childkey_take_rate_limiting() { SubtensorModule::set_tx_childkey_take_rate_limit(rate_limit); log::info!( - "TxChildkeyTakeRateLimit: {:?}", + "Set TxChildkeyTakeRateLimit: {:?}", TxChildkeyTakeRateLimit::::get() ); + // Helper function to log rate limit information + let log_rate_limit_info = || { + let current_block = SubtensorModule::get_current_block_as_u64(); + let last_block = SubtensorModule::get_last_transaction_block( + &hotkey, + netuid, + &TransactionType::SetChildkeyTake, + ); + let passes = SubtensorModule::passes_rate_limit_on_subnet( + &TransactionType::SetChildkeyTake, + &hotkey, + netuid, + ); + let limit = SubtensorModule::get_rate_limit(&TransactionType::SetChildkeyTake); + log::info!( + "Rate limit info: current_block: {}, last_block: {}, limit: {}, passes: {}, diff: {}", + current_block, + last_block, + limit, + passes, + current_block.saturating_sub(last_block) + ); + }; + // First transaction (should succeed) + log_rate_limit_info(); assert_ok!(SubtensorModule::set_childkey_take( RuntimeOrigin::signed(coldkey), hotkey, netuid, 500 )); - - let current_block = SubtensorModule::get_current_block_as_u64(); - let last_block = SubtensorModule::get_last_transaction_block( - &hotkey, - netuid, - &TransactionType::SetChildkeyTake, - ); - log::info!( - "After first transaction: current_block: {}, last_block: {}", - current_block, - last_block - ); + log_rate_limit_info(); // Second transaction (should fail due to rate limit) - let result = - SubtensorModule::set_childkey_take(RuntimeOrigin::signed(coldkey), hotkey, netuid, 600); - log::info!("Second transaction result: {:?}", result); - let current_block = SubtensorModule::get_current_block_as_u64(); - let last_block = SubtensorModule::get_last_transaction_block( - &hotkey, - netuid, - &TransactionType::SetChildkeyTake, - ); - log::info!( - "After second transaction attempt: current_block: {}, last_block: {}", - current_block, - last_block + log_rate_limit_info(); + assert_noop!( + SubtensorModule::set_childkey_take(RuntimeOrigin::signed(coldkey), hotkey, netuid, 600), + Error::::TxChildkeyTakeRateLimitExceeded ); - - assert_noop!(result, Error::::TxChildkeyTakeRateLimitExceeded); + log_rate_limit_info(); // Advance the block number to just before the rate limit - run_to_block(rate_limit); + run_to_block(rate_limit - 1); // Third transaction (should still fail) - let result = - SubtensorModule::set_childkey_take(RuntimeOrigin::signed(coldkey), hotkey, netuid, 650); - log::info!("Third transaction result: {:?}", result); - let current_block = SubtensorModule::get_current_block_as_u64(); - let last_block = SubtensorModule::get_last_transaction_block( - &hotkey, - netuid, - &TransactionType::SetChildkeyTake, - ); - log::info!( - "After third transaction attempt: current_block: {}, last_block: {}", - current_block, - last_block + log_rate_limit_info(); + assert_noop!( + SubtensorModule::set_childkey_take(RuntimeOrigin::signed(coldkey), hotkey, netuid, 650), + Error::::TxChildkeyTakeRateLimitExceeded ); - - assert_noop!(result, Error::::TxChildkeyTakeRateLimitExceeded); + log_rate_limit_info(); // Advance the block number to just after the rate limit - run_to_block(rate_limit * 2); + run_to_block(rate_limit + 1); // Fourth transaction (should succeed) + log_rate_limit_info(); assert_ok!(SubtensorModule::set_childkey_take( RuntimeOrigin::signed(coldkey), hotkey, netuid, 700 )); - - let current_block = SubtensorModule::get_current_block_as_u64(); - let last_block = SubtensorModule::get_last_transaction_block( - &hotkey, - netuid, - &TransactionType::SetChildkeyTake, - ); - log::info!( - "After fourth transaction: current_block: {}, last_block: {}", - current_block, - last_block - ); + log_rate_limit_info(); // Verify the final take was set let stored_take = SubtensorModule::get_childkey_take(&hotkey, netuid); @@ -987,7 +971,7 @@ fn test_multiple_networks_childkey_take() { register_ok_neuron(netuid, hotkey, coldkey, 0); // Set a unique childkey take value for each network - let take_value = (netuid + 1) * 1000; // Values will be 1000, 2000, ..., 10000 + let take_value = (netuid + 1) * 100; // Values will be 200, 300, ..., 1000 assert_ok!(SubtensorModule::set_childkey_take( RuntimeOrigin::signed(coldkey), hotkey, @@ -1019,6 +1003,26 @@ fn test_multiple_networks_childkey_take() { ); } } + + // Attempt to set childkey take again (should fail due to rate limit) + let result = + SubtensorModule::set_childkey_take(RuntimeOrigin::signed(coldkey), hotkey, 1, 1100); + assert_noop!(result, Error::::TxChildkeyTakeRateLimitExceeded); + + // Advance blocks to bypass rate limit + run_to_block(SubtensorModule::get_tx_childkey_take_rate_limit() + 1); + + // Now setting childkey take should succeed + assert_ok!(SubtensorModule::set_childkey_take( + RuntimeOrigin::signed(coldkey), + hotkey, + 1, + 1100 + )); + + // Verify the new take value + let new_take = SubtensorModule::get_childkey_take(&hotkey, 1); + assert_eq!(new_take, 1100, "Childkey take not updated after rate limit"); }); } diff --git a/pallets/subtensor/tests/mock.rs b/pallets/subtensor/tests/mock.rs index 4de74f4ab..4039054e0 100644 --- a/pallets/subtensor/tests/mock.rs +++ b/pallets/subtensor/tests/mock.rs @@ -134,8 +134,7 @@ parameter_types! { pub const InitialDefaultDelegateTake: u16 = 11_796; // 18%, same as in production pub const InitialMinDelegateTake: u16 = 5_898; // 9%; pub const InitialDefaultChildKeyTake: u16 = 11_796; // 18%, same as in production - pub const InitialMinChildKeyTake: u16 = 5_898; // 9%; - pub const InitialMinTake: u16 =5_898; // 9%; + pub const InitialMinChildKeyTake: u16 = 0; // 0 %; pub const InitialWeightsVersionKey: u16 = 0; pub const InitialServingRateLimit: u64 = 0; // No limit. pub const InitialTxRateLimit: u64 = 0; // Disable rate limit for testing diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 4dc0e5d72..dec65f60f 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -873,7 +873,7 @@ parameter_types! { pub const SubtensorInitialDefaultTake: u16 = 11_796; // 18% honest number. pub const SubtensorInitialMinDelegateTake: u16 = 0; // Allow 0% delegate take pub const SubtensorInitialDefaultChildKeyTake: u16 = 0; // Allow 0% childkey take - pub const SubtensorInitialMinChildKeyTake: u16 = 5_898; // 9% + pub const SubtensorInitialMinChildKeyTake: u16 = 0; // 0 % pub const SubtensorInitialWeightsVersionKey: u64 = 0; pub const SubtensorInitialMinDifficulty: u64 = 10_000_000; pub const SubtensorInitialMaxDifficulty: u64 = u64::MAX / 4; From 676463328de5d87663332adaaa9cb5cf1997352f Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Wed, 7 Aug 2024 18:16:26 +0400 Subject: [PATCH 19/31] feat: add more childkey tests --- pallets/subtensor/src/epoch/run_epoch.rs | 4 +- pallets/subtensor/src/lib.rs | 2 - pallets/subtensor/tests/children.rs | 1715 +++++++++++++++++++++- pallets/subtensor/tests/mock.rs | 18 + 4 files changed, 1682 insertions(+), 57 deletions(-) diff --git a/pallets/subtensor/src/epoch/run_epoch.rs b/pallets/subtensor/src/epoch/run_epoch.rs index 1cb2c3448..9196bee4b 100644 --- a/pallets/subtensor/src/epoch/run_epoch.rs +++ b/pallets/subtensor/src/epoch/run_epoch.rs @@ -31,12 +31,10 @@ impl Pallet { /// This function does not explicitly panic, but underlying arithmetic operations /// use saturating arithmetic to prevent overflows. /// - /// TODO: check for self loops. - /// TODO: (@distributedstatemachine): check if we should return error , otherwise self loop - /// detection is impossible to test. pub fn get_stake_for_hotkey_on_subnet(hotkey: &T::AccountId, netuid: u16) -> u64 { // Retrieve the initial total stake for the hotkey without any child/parent adjustments. let initial_stake: u64 = Self::get_total_stake_for_hotkey(hotkey); + log::debug!("Initial stake: {:?}", initial_stake); let mut stake_to_children: u64 = 0; let mut stake_from_parents: u64 = 0; diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index edc9040ac..b0fbc9140 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -372,8 +372,6 @@ pub mod pallet { } T::InitialNetworkRateLimit::get() } - // #[pallet::type_value] /// Default value for network max stake. - // pub fn DefaultNetworkMaxStake() -> u64 { T::InitialNetworkMaxStake::get() } #[pallet::type_value] /// Default value for emission values. pub fn DefaultEmissionValues() -> u64 { diff --git a/pallets/subtensor/tests/children.rs b/pallets/subtensor/tests/children.rs index b675ff8e9..f491e8b64 100644 --- a/pallets/subtensor/tests/children.rs +++ b/pallets/subtensor/tests/children.rs @@ -5,6 +5,7 @@ mod mock; use pallet_subtensor::{utils::rate_limiting::TransactionType, *}; use sp_core::U256; +// 1: Successful setting of a single child // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_success --exact --nocapture #[test] fn test_do_set_child_singular_success() { @@ -33,6 +34,7 @@ fn test_do_set_child_singular_success() { }); } +// 2: Attempt to set child in non-existent network // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_network_does_not_exist --exact --nocapture #[test] fn test_do_set_child_singular_network_does_not_exist() { @@ -56,6 +58,7 @@ fn test_do_set_child_singular_network_does_not_exist() { }); } +// 3: Attempt to set invalid child (same as hotkey) // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_invalid_child --exact --nocapture #[test] fn test_do_set_child_singular_invalid_child() { @@ -84,6 +87,7 @@ fn test_do_set_child_singular_invalid_child() { }); } +// 4: Attempt to set child with non-associated coldkey // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_non_associated_coldkey --exact --nocapture #[test] fn test_do_set_child_singular_non_associated_coldkey() { @@ -111,6 +115,7 @@ fn test_do_set_child_singular_non_associated_coldkey() { }); } +// 5: Attempt to set child in root network // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_root_network --exact --nocapture #[test] fn test_do_set_child_singular_root_network() { @@ -137,6 +142,13 @@ fn test_do_set_child_singular_root_network() { }); } +// 6: Cleanup of old children when setting new ones +// This test verifies that when new children are set, the old ones are properly removed. +// It checks: +// - Setting an initial child +// - Replacing it with a new child +// - Ensuring the old child is no longer associated +// - Confirming the new child is correctly assigned // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_old_children_cleanup --exact --nocapture #[test] fn test_do_set_child_singular_old_children_cleanup() { @@ -178,7 +190,13 @@ fn test_do_set_child_singular_old_children_cleanup() { }); } -// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_old_children_cleanup --exact --nocapture +// 7: Verify new children assignment +// This test checks if new children are correctly assigned to a parent. +// It verifies: +// - Setting a child for a parent +// - Confirming the child is correctly listed under the parent +// - Ensuring the parent is correctly listed for the child +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_new_children_assignment --exact --nocapture #[test] fn test_do_set_child_singular_new_children_assignment() { new_test_ext(1).execute_with(|| { @@ -210,6 +228,12 @@ fn test_do_set_child_singular_new_children_assignment() { }); } +// 8: Test edge cases for proportion values +// This test verifies that the system correctly handles minimum and maximum proportion values. +// It checks: +// - Setting a child with the minimum possible proportion (0) +// - Setting a child with the maximum possible proportion (u64::MAX) +// - Confirming both assignments are processed correctly // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_proportion_edge_cases --exact --nocapture #[test] fn test_do_set_child_singular_proportion_edge_cases() { @@ -251,6 +275,13 @@ fn test_do_set_child_singular_proportion_edge_cases() { }); } +// 9: Test setting multiple children +// This test verifies that when multiple children are set, only the last one remains. +// It checks: +// - Setting an initial child +// - Setting a second child +// - Confirming only the second child remains associated +// - Verifying the first child is no longer associated // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_child_singular_multiple_children --exact --nocapture #[test] fn test_do_set_child_singular_multiple_children() { @@ -296,6 +327,12 @@ fn test_do_set_child_singular_multiple_children() { }); } +// 10: Test adding a singular child with various error conditions +// This test checks different scenarios when adding a child, including: +// - Attempting to set a child in a non-existent network +// - Trying to set a child with an unassociated coldkey +// - Setting an invalid child +// - Successfully setting a valid child // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_add_singular_child --exact --nocapture #[test] fn test_add_singular_child() { @@ -343,73 +380,67 @@ fn test_add_singular_child() { }) } +// 11: Test getting stake for a hotkey on a subnet +// This test verifies the correct calculation of stake for a parent and child neuron: +// - Sets up a network with a parent and child neuron +// - Stakes tokens to both parent and child from different coldkeys +// - Establishes a parent-child relationship with 100% stake allocation +// - Checks that the parent's stake is correctly transferred to the child +// - Ensures the total stake is preserved in the system // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_get_stake_for_hotkey_on_subnet --exact --nocapture #[test] fn test_get_stake_for_hotkey_on_subnet() { new_test_ext(1).execute_with(|| { let netuid: u16 = 1; - let hotkey0 = U256::from(1); - let hotkey1 = U256::from(2); - let coldkey0 = U256::from(3); - let coldkey1 = U256::from(4); + let parent = U256::from(1); + let child = U256::from(2); + let coldkey1 = U256::from(3); + let coldkey2 = U256::from(4); add_network(netuid, 0, 0); - - let max_stake: u64 = 3000; - SubtensorModule::set_network_max_stake(netuid, max_stake); - - SubtensorModule::create_account_if_non_existent(&coldkey0, &hotkey0); - SubtensorModule::create_account_if_non_existent(&coldkey1, &hotkey1); - - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey0, &hotkey0, 1000); - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey0, &hotkey1, 1000); - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey1, &hotkey0, 1000); - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey1, &hotkey1, 1000); - - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 2000); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 2000); - - assert_eq!( - SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey0, netuid), - 2000 - ); - assert_eq!( - SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey1, netuid), - 2000 - ); - - // Set child relationship + register_ok_neuron(netuid, parent, coldkey1, 0); + register_ok_neuron(netuid, child, coldkey2, 0); + + // Stake 1000 to parent from coldkey1 + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey1, &parent, 1000); + // Stake 1000 to parent from coldkey2 + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey2, &parent, 1000); + // Stake 1000 to child from coldkey1 + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey1, &child, 1000); + // Stake 1000 to child from coldkey2 + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey2, &child, 1000); + + // Set parent-child relationship with 100% stake allocation assert_ok!(SubtensorModule::do_set_children( - RuntimeOrigin::signed(coldkey0), - hotkey0, + RuntimeOrigin::signed(coldkey1), + parent, netuid, - vec![(u64::MAX, hotkey1)] + vec![(u64::MAX, child)] )); - // Check stakes after setting child - let stake0 = SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey0, netuid); - let stake1 = SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey1, netuid); + let parent_stake = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); + let child_stake = SubtensorModule::get_stake_for_hotkey_on_subnet(&child, netuid); - assert_eq!(stake0, 0); - assert_eq!(stake1, max_stake); - - // Change child relationship to 50% - assert_ok!(SubtensorModule::do_set_children( - RuntimeOrigin::signed(coldkey0), - hotkey0, - netuid, - vec![(u64::MAX / 2, hotkey1)] - )); + println!("Parent stake: {}", parent_stake); + println!("Child stake: {}", child_stake); - // Check stakes after changing child relationship - let stake0 = SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey0, netuid); - let stake1 = SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey1, netuid); + // The parent should have 0 stake as it's all allocated to the child + assert_eq!(parent_stake, 0); + // The child should have its original stake (2000) plus the parent's stake (2000) + assert_eq!(child_stake, 4000); - assert_eq!(stake0, 1001); - assert!(stake1 >= max_stake - 1 && stake1 <= max_stake); + // Ensure total stake is preserved + assert_eq!(parent_stake + child_stake, 4000); }); } +// 12: Test revoking a singular child successfully +// This test checks the process of revoking a child neuron: +// - Sets up a network with a parent and child neuron +// - Establishes a parent-child relationship +// - Revokes the child relationship +// - Verifies that the child is removed from the parent's children list +// - Ensures the parent is removed from the child's parents list // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_child_singular_success --exact --nocapture #[test] fn test_do_revoke_child_singular_success() { @@ -454,6 +485,10 @@ fn test_do_revoke_child_singular_success() { }); } +// 13: Test revoking a child in a non-existent network +// This test verifies that attempting to revoke a child in a non-existent network results in an error: +// - Attempts to revoke a child in a network that doesn't exist +// - Checks that the appropriate error is returned // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_child_singular_network_does_not_exist --exact --nocapture #[test] fn test_do_revoke_child_singular_network_does_not_exist() { @@ -475,6 +510,11 @@ fn test_do_revoke_child_singular_network_does_not_exist() { }); } +// 14: Test revoking a child with a non-associated coldkey +// This test ensures that attempting to revoke a child using an unassociated coldkey results in an error: +// - Sets up a network with a hotkey registered to a different coldkey +// - Attempts to revoke a child using an unassociated coldkey +// - Verifies that the appropriate error is returned // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_child_singular_non_associated_coldkey --exact --nocapture #[test] fn test_do_revoke_child_singular_non_associated_coldkey() { @@ -500,6 +540,11 @@ fn test_do_revoke_child_singular_non_associated_coldkey() { }); } +// 15: Test revoking a non-associated child +// This test verifies that attempting to revoke a child that is not associated with the parent results in an error: +// - Sets up a network and registers a hotkey +// - Attempts to revoke a child that was never associated with the parent +// - Checks that the appropriate error is returned // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_child_singular_child_not_associated --exact --nocapture #[test] fn test_do_revoke_child_singular_child_not_associated() { @@ -524,6 +569,12 @@ fn test_do_revoke_child_singular_child_not_associated() { }); } +// 16: Test setting multiple children successfully +// This test verifies that multiple children can be set for a parent successfully: +// - Sets up a network and registers a hotkey +// - Sets multiple children with different proportions +// - Verifies that the children are correctly assigned to the parent +// - Checks that the parent is correctly assigned to each child // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_success --exact --nocapture #[test] fn test_do_set_children_multiple_success() { @@ -561,6 +612,10 @@ fn test_do_set_children_multiple_success() { }); } +// 17: Test setting multiple children in a non-existent network +// This test ensures that attempting to set multiple children in a non-existent network results in an error: +// - Attempts to set children in a network that doesn't exist +// - Verifies that the appropriate error is returned // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_network_does_not_exist --exact --nocapture #[test] fn test_do_set_children_multiple_network_does_not_exist() { @@ -584,6 +639,11 @@ fn test_do_set_children_multiple_network_does_not_exist() { }); } +// 18: Test setting multiple children with an invalid child +// This test verifies that attempting to set multiple children with an invalid child (same as parent) results in an error: +// - Sets up a network and registers a hotkey +// - Attempts to set a child that is the same as the parent hotkey +// - Checks that the appropriate error is returned // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_invalid_child --exact --nocapture #[test] fn test_do_set_children_multiple_invalid_child() { @@ -610,6 +670,11 @@ fn test_do_set_children_multiple_invalid_child() { }); } +// 19: Test setting multiple children with a non-associated coldkey +// This test ensures that attempting to set multiple children using an unassociated coldkey results in an error: +// - Sets up a network with a hotkey registered to a different coldkey +// - Attempts to set children using an unassociated coldkey +// - Verifies that the appropriate error is returned // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_non_associated_coldkey --exact --nocapture #[test] fn test_do_set_children_multiple_non_associated_coldkey() { @@ -637,6 +702,11 @@ fn test_do_set_children_multiple_non_associated_coldkey() { }); } +// 20: Test setting multiple children in root network +// This test verifies that attempting to set children in the root network results in an error: +// - Sets up the root network +// - Attempts to set children in the root network +// - Checks that the appropriate error is returned // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_root_network --exact --nocapture #[test] fn test_do_set_children_multiple_root_network() { @@ -663,6 +733,13 @@ fn test_do_set_children_multiple_root_network() { }); } +// 21: Test cleanup of old children when setting multiple new ones +// This test ensures that when new children are set, the old ones are properly removed: +// - Sets up a network and registers a hotkey +// - Sets an initial child +// - Replaces it with multiple new children +// - Verifies that the old child is no longer associated +// - Confirms the new children are correctly assigned // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_old_children_cleanup --exact --nocapture #[test] fn test_do_set_children_multiple_old_children_cleanup() { @@ -708,6 +785,11 @@ fn test_do_set_children_multiple_old_children_cleanup() { }); } +// 22: Test setting multiple children with edge case proportions +// This test verifies the behavior when setting multiple children with minimum and maximum proportions: +// - Sets up a network and registers a hotkey +// - Sets two children with minimum and maximum proportions respectively +// - Verifies that the children are correctly assigned with their respective proportions // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_proportion_edge_cases --exact --nocapture #[test] fn test_do_set_children_multiple_proportion_edge_cases() { @@ -741,6 +823,13 @@ fn test_do_set_children_multiple_proportion_edge_cases() { }); } +// 23: Test overwriting existing children with new ones +// This test ensures that when new children are set, they correctly overwrite the existing ones: +// - Sets up a network and registers a hotkey +// - Sets initial children +// - Overwrites with new children +// - Verifies that the final children assignment is correct +// - Checks that old children are properly removed and new ones are correctly assigned // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_overwrite_existing --exact --nocapture #[test] fn test_do_set_children_multiple_overwrite_existing() { @@ -792,6 +881,14 @@ fn test_do_set_children_multiple_overwrite_existing() { }); } +// 24: Test childkey take functionality +// This test verifies the functionality of setting and getting childkey take: +// - Sets up a network and registers a hotkey +// - Checks default and maximum childkey take values +// - Sets a new childkey take value +// - Verifies the new take value is stored correctly +// - Attempts to set an invalid take value and checks for appropriate error +// - Tries to set take with a non-associated coldkey and verifies the error // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_childkey_take_functionality --exact --nocapture #[test] fn test_childkey_take_functionality() { @@ -861,6 +958,13 @@ fn test_childkey_take_functionality() { }); } +// 25: Test childkey take rate limiting +// This test verifies the rate limiting functionality for setting childkey take: +// - Sets up a network and registers a hotkey +// - Sets a rate limit for childkey take changes +// - Performs multiple attempts to set childkey take +// - Verifies that rate limiting prevents frequent changes +// - Advances blocks to bypass rate limit and confirms successful change // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_childkey_take_rate_limiting --exact --nocapture #[test] fn test_childkey_take_rate_limiting() { @@ -954,6 +1058,13 @@ fn test_childkey_take_rate_limiting() { }); } +// 26: Test childkey take functionality across multiple networks +// This test verifies the childkey take functionality across multiple networks: +// - Creates multiple networks and sets up neurons +// - Sets unique childkey take values for each network +// - Verifies that each network has a different childkey take value +// - Attempts to set childkey take again (should fail due to rate limit) +// - Advances blocks to bypass rate limit and successfully updates take value // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_multiple_networks_childkey_take --exact --nocapture #[test] fn test_multiple_networks_childkey_take() { @@ -1026,6 +1137,12 @@ fn test_multiple_networks_childkey_take() { }); } +// 27: Test setting children with an empty list +// This test verifies the behavior of setting an empty children list: +// - Adds a network and registers a hotkey +// - Sets an empty children list for the hotkey +// - Verifies that the children assignment is empty +// SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_set_children_multiple_empty_list --exact --nocapture #[test] fn test_do_set_children_multiple_empty_list() { new_test_ext(1).execute_with(|| { @@ -1051,6 +1168,13 @@ fn test_do_set_children_multiple_empty_list() { }); } +// 28: Test revoking multiple children successfully +// This test verifies the successful revocation of multiple children: +// - Adds a network and registers a hotkey +// - Sets multiple children for the hotkey +// - Revokes all children by setting an empty list +// - Verifies that the children list is empty +// - Verifies that the parent-child relationships are removed for both children // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_children_multiple_success --exact --nocapture #[test] fn test_do_revoke_children_multiple_success() { @@ -1096,6 +1220,10 @@ fn test_do_revoke_children_multiple_success() { }); } +// 29: Test revoking children when network does not exist +// This test verifies the behavior when attempting to revoke children on a non-existent network: +// - Attempts to revoke children on a network that doesn't exist +// - Verifies that the operation fails with the correct error // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_children_multiple_network_does_not_exist --exact --nocapture #[test] fn test_do_revoke_children_multiple_network_does_not_exist() { @@ -1118,6 +1246,11 @@ fn test_do_revoke_children_multiple_network_does_not_exist() { }); } +// 30: Test revoking children with non-associated coldkey +// This test verifies the behavior when attempting to revoke children using a non-associated coldkey: +// - Adds a network and registers a hotkey with a different coldkey +// - Attempts to revoke children using an unassociated coldkey +// - Verifies that the operation fails with the correct error // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_children_multiple_non_associated_coldkey --exact --nocapture #[test] fn test_do_revoke_children_multiple_non_associated_coldkey() { @@ -1145,6 +1278,13 @@ fn test_do_revoke_children_multiple_non_associated_coldkey() { }); } +// 31: Test partial revocation of children +// This test verifies the behavior when partially revoking children: +// - Adds a network and registers a hotkey +// - Sets multiple children for the hotkey +// - Revokes one of the children +// - Verifies that the correct children remain and the revoked child is removed +// - Checks the parent-child relationships after partial revocation // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_children_multiple_partial_revocation --exact --nocapture #[test] fn test_do_revoke_children_multiple_partial_revocation() { @@ -1195,8 +1335,14 @@ fn test_do_revoke_children_multiple_partial_revocation() { }); } +// 32: Test revoking non-existent children +// This test verifies the behavior when attempting to revoke non-existent children: +// - Adds a network and registers a hotkey +// - Sets one child for the hotkey +// - Attempts to revoke all children (including non-existent ones) +// - Verifies that all children are removed, including the existing one +// - Checks that the parent-child relationship is properly updated // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_children_multiple_non_existent_children --exact --nocapture - #[test] fn test_do_revoke_children_multiple_non_existent_children() { new_test_ext(1).execute_with(|| { @@ -1236,6 +1382,11 @@ fn test_do_revoke_children_multiple_non_existent_children() { }); } +// 33: Test revoking children with an empty list +// This test verifies the behavior when attempting to revoke children using an empty list: +// - Adds a network and registers a hotkey +// - Attempts to revoke children with an empty list +// - Verifies that no changes occur in the children list // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_children_multiple_empty_list --exact --nocapture #[test] fn test_do_revoke_children_multiple_empty_list() { @@ -1262,6 +1413,13 @@ fn test_do_revoke_children_multiple_empty_list() { }); } +// 34: Test complex scenario for revoking multiple children +// This test verifies a complex scenario involving setting and revoking multiple children: +// - Adds a network and registers a hotkey +// - Sets multiple children with different proportions +// - Revokes one child and verifies the remaining children +// - Revokes all remaining children +// - Verifies that all parent-child relationships are properly updated // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_do_revoke_children_multiple_complex_scenario --exact --nocapture #[test] fn test_do_revoke_children_multiple_complex_scenario() { @@ -1328,6 +1486,11 @@ fn test_do_revoke_children_multiple_complex_scenario() { }); } +// 35: Test getting network max stake +// This test verifies the functionality of getting the network max stake: +// - Checks the default max stake value +// - Sets a new max stake value +// - Verifies that the new value is retrieved correctly // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_get_network_max_stake --exact --nocapture #[test] fn test_get_network_max_stake() { @@ -1350,6 +1513,12 @@ fn test_get_network_max_stake() { }); } +// 36: Test setting network max stake +// This test verifies the functionality of setting the network max stake: +// - Checks the initial max stake value +// - Sets a new max stake value +// - Verifies that the new value is set correctly +// - Checks that the appropriate event is emitted // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_set_network_max_stake --exact --nocapture #[test] fn test_set_network_max_stake() { @@ -1376,6 +1545,11 @@ fn test_set_network_max_stake() { }); } +// 37: Test setting network max stake for multiple networks +// This test verifies the functionality of setting different max stake values for multiple networks: +// - Sets different max stake values for two networks +// - Verifies that the values are set correctly for each network +// - Checks that the values are different between networks // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_set_network_max_stake_multiple_networks --exact --nocapture #[test] fn test_set_network_max_stake_multiple_networks() { @@ -1399,6 +1573,12 @@ fn test_set_network_max_stake_multiple_networks() { }); } +// 38: Test updating network max stake +// This test verifies the functionality of updating an existing network max stake value: +// - Sets an initial max stake value +// - Updates the max stake value +// - Verifies that the value is updated correctly +// - Checks that the appropriate event is emitted for the update // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_set_network_max_stake_update --exact --nocapture #[test] fn test_set_network_max_stake_update() { @@ -1428,6 +1608,13 @@ fn test_set_network_max_stake_update() { }); } +// 39: Test children stake values +// This test verifies the correct distribution of stake among parent and child neurons: +// - Sets up a network with a parent neuron and multiple child neurons +// - Assigns stake to the parent neuron +// - Sets child neurons with specific proportions +// - Verifies that the stake is correctly distributed among parent and child neurons +// - Checks that the total stake remains constant across all neurons // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_children_stake_values --exact --nocapture #[test] fn test_children_stake_values() { @@ -1493,6 +1680,13 @@ fn test_children_stake_values() { }); } +// 40: Test getting parents chain +// This test verifies the correct implementation of parent-child relationships and the get_parents function: +// - Sets up a network with multiple neurons in a chain of parent-child relationships +// - Verifies that each neuron has the correct parent +// - Tests the root neuron has no parents +// - Tests a neuron with multiple parents +// - Verifies correct behavior when adding a new parent to an existing child // SKIP_WASM_BUILD=1 RUST_LOG=info cargo test --test children -- test_get_parents_chain --exact --nocapture #[test] fn test_get_parents_chain() { @@ -1626,3 +1820,1420 @@ fn test_get_parents_chain() { ); }); } + +// 41: Test emission distribution between a childkey and a single parent +// This test verifies the correct distribution of emissions between a child and a single parent: +// - Sets up a network with a parent, child, and weight setter +// - Establishes a parent-child relationship +// - Sets weights on the child +// - Runs an epoch with a hardcoded emission value +// - Checks the emission distribution among parent, child, and weight setter +// - Verifies that all parties received emissions and the weight setter received the most +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test children test_childkey_single_parent_emission -- --nocapture +#[test] +fn test_childkey_single_parent_emission() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + add_network(netuid, 1, 0); + + // Define hotkeys + let parent: U256 = U256::from(1); + let child: U256 = U256::from(2); + let weight_setter: U256 = U256::from(3); + + // Define coldkeys with more readable names + let coldkey_parent: U256 = U256::from(100); + let coldkey_child: U256 = U256::from(101); + let coldkey_weight_setter: U256 = U256::from(102); + + // Register parent with minimal stake and child with high stake + SubtensorModule::add_balance_to_coldkey_account(&coldkey_parent, 1); + SubtensorModule::add_balance_to_coldkey_account(&coldkey_child, 109_999); + SubtensorModule::add_balance_to_coldkey_account(&coldkey_weight_setter, 1_000_000); + + // Add neurons for parent, child and weight_setter + register_ok_neuron(netuid, parent, coldkey_parent, 1); + register_ok_neuron(netuid, child, coldkey_child, 1); + register_ok_neuron(netuid, weight_setter, coldkey_weight_setter, 1); + + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &coldkey_parent, + &parent, + 109_999, + ); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &coldkey_weight_setter, + &weight_setter, + 1_000_000, + ); + + SubtensorModule::set_weights_set_rate_limit(netuid, 0); + + // Set parent-child relationship + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey_parent), + parent, + netuid, + vec![(u64::MAX, child)] + )); + step_block(7200 + 1); + // Set weights on the child using the weight_setter account + let origin = RuntimeOrigin::signed(weight_setter); + let uids: Vec = vec![1]; // Only set weight for the child (UID 1) + let values: Vec = vec![u16::MAX]; // Use maximum value for u16 + let version_key = SubtensorModule::get_weights_version_key(netuid); + assert_ok!(SubtensorModule::set_weights( + origin, + netuid, + uids, + values, + version_key + )); + + // Run epoch with a hardcoded emission value + let hardcoded_emission: u64 = 1_000_000_000; // 1 TAO + let hotkey_emission: Vec<(U256, u64, u64)> = + SubtensorModule::epoch(netuid, hardcoded_emission); + + // Process the hotkey emission results + for (hotkey, mining_emission, validator_emission) in hotkey_emission { + SubtensorModule::accumulate_hotkey_emission( + &hotkey, + netuid, + validator_emission, + mining_emission, + ); + log::debug!( + "Accumulated emissions on hotkey {:?} for netuid {:?}: mining {:?}, validator {:?}", + hotkey, + netuid, + mining_emission, + validator_emission + ); + } + step_block(7200 + 1); + // Check emission distribution + let parent_stake: u64 = + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey_parent, &parent); + let parent_stake_on_subnet: u64 = + SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); + + log::debug!( + "Parent stake: {:?}, Parent stake on subnet: {:?}", + parent_stake, + parent_stake_on_subnet + ); + + let child_stake: u64 = + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey_child, &child); + let child_stake_on_subnet: u64 = + SubtensorModule::get_stake_for_hotkey_on_subnet(&child, netuid); + + log::debug!( + "Child stake: {:?}, Child stake on subnet: {:?}", + child_stake, + child_stake_on_subnet + ); + + let weight_setter_stake: u64 = SubtensorModule::get_stake_for_coldkey_and_hotkey( + &coldkey_weight_setter, + &weight_setter, + ); + let weight_setter_stake_on_subnet: u64 = + SubtensorModule::get_stake_for_hotkey_on_subnet(&weight_setter, netuid); + + log::debug!( + "Weight setter stake: {:?}, Weight setter stake on subnet: {:?}", + weight_setter_stake, + weight_setter_stake_on_subnet + ); + + assert!(parent_stake > 1, "Parent should have received emission"); + assert!(child_stake > 109_999, "Child should have received emission"); + assert!( + weight_setter_stake > 1_000_000, + "Weight setter should have received emission" + ); + + // Additional assertion to verify that the weight setter received the most emission + assert!( + weight_setter_stake > parent_stake && weight_setter_stake > child_stake, + "Weight setter should have received the most emission" + ); + }); +} + +// 43: Test emission distribution between a childkey and multiple parents +// This test verifies the correct distribution of emissions between a child and multiple parents: +// - Sets up a network with two parents, a child, and a weight setter +// - Establishes parent-child relationships with different stake proportions +// - Sets weights on the child and one parent +// - Runs an epoch with a hardcoded emission value +// - Checks the emission distribution among parents, child, and weight setter +// - Verifies that all parties received emissions and the total stake increased correctly +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test coinbase test_childkey_multiple_parents_emission -- --nocapture +#[test] +fn test_childkey_multiple_parents_emission() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + add_network(netuid, 1, 0); + + // Set registration parameters and emission tempo + SubtensorModule::set_max_registrations_per_block(netuid, 1000); + SubtensorModule::set_target_registrations_per_interval(netuid, 1000); + SubtensorModule::set_hotkey_emission_tempo(10); + + // Define hotkeys and coldkeys + let parent1: U256 = U256::from(1); + let parent2: U256 = U256::from(2); + let child: U256 = U256::from(3); + let weight_setter: U256 = U256::from(4); + let coldkey_parent1: U256 = U256::from(100); + let coldkey_parent2: U256 = U256::from(101); + let coldkey_child: U256 = U256::from(102); + let coldkey_weight_setter: U256 = U256::from(103); + + // Register neurons and add initial stakes + let initial_stakes: Vec<(U256, U256, u64)> = vec![ + (coldkey_parent1, parent1, 200_000), + (coldkey_parent2, parent2, 150_000), + (coldkey_child, child, 20_000), + (coldkey_weight_setter, weight_setter, 100_000), + ]; + + for (coldkey, hotkey, stake) in initial_stakes.iter() { + SubtensorModule::add_balance_to_coldkey_account(coldkey, *stake); + register_ok_neuron(netuid, *hotkey, *coldkey, 0); + SubtensorModule::increase_stake_on_coldkey_hotkey_account(coldkey, hotkey, *stake); + } + + SubtensorModule::set_weights_set_rate_limit(netuid, 0); + step_block(2); + + // Set parent-child relationships + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey_parent1), + parent1, + netuid, + vec![(100_000, child)] + )); + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey_parent2), + parent2, + netuid, + vec![(75_000, child)] + )); + + // Set weights + let uids: Vec = vec![0, 1, 2]; + let values: Vec = vec![0, 65354, 65354]; + let version_key = SubtensorModule::get_weights_version_key(netuid); + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(weight_setter), + netuid, + uids, + values, + version_key + )); + + // Run epoch with a hardcoded emission value + let hardcoded_emission: u64 = 1_000_000_000; // 1 billion + let hotkey_emission: Vec<(U256, u64, u64)> = + SubtensorModule::epoch(netuid, hardcoded_emission); + + // Process the hotkey emission results + for (hotkey, mining_emission, validator_emission) in hotkey_emission { + SubtensorModule::accumulate_hotkey_emission( + &hotkey, + netuid, + validator_emission, + mining_emission, + ); + log::debug!( + "Accumulated emissions on hotkey {:?} for netuid {:?}: mining {:?}, validator {:?}", + hotkey, + netuid, + mining_emission, + validator_emission + ); + } + + step_block(11); + + // Check emission distribution + let stakes: Vec<(U256, U256, &str)> = vec![ + (coldkey_parent1, parent1, "Parent1"), + (coldkey_parent2, parent2, "Parent2"), + (coldkey_child, child, "Child"), + (coldkey_weight_setter, weight_setter, "Weight setter"), + ]; + + for (coldkey, hotkey, name) in stakes.iter() { + let stake = SubtensorModule::get_stake_for_coldkey_and_hotkey(coldkey, hotkey); + let stake_on_subnet = SubtensorModule::get_stake_for_hotkey_on_subnet(hotkey, netuid); + log::debug!( + "{} stake: {:?}, {} stake on subnet: {:?}", + name, + stake, + name, + stake_on_subnet + ); + } + + let parent1_stake = + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey_parent1, &parent1); + let parent2_stake = + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey_parent2, &parent2); + let child_stake = SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey_child, &child); + let weight_setter_stake = SubtensorModule::get_stake_for_coldkey_and_hotkey( + &coldkey_weight_setter, + &weight_setter, + ); + + assert!( + parent1_stake > 200_000, + "Parent1 should have received emission" + ); + assert!( + parent2_stake > 150_000, + "Parent2 should have received emission" + ); + assert!(child_stake > 20_000, "Child should have received emission"); + assert!( + weight_setter_stake > 100_000, + "Weight setter should have received emission" + ); + + // Check individual stake increases + let parent1_stake_increase = parent1_stake - 200_000; + let parent2_stake_increase = parent2_stake - 150_000; + let child_stake_increase = child_stake - 20_000; + + log::debug!( + "Stake increases - Parent1: {}, Parent2: {}, Child: {}", + parent1_stake_increase, + parent2_stake_increase, + child_stake_increase + ); + + // Assert that all neurons received some emission + assert!( + parent1_stake_increase > 0, + "Parent1 should have received some emission" + ); + assert!( + parent2_stake_increase > 0, + "Parent2 should have received some emission" + ); + assert!( + child_stake_increase > 0, + "Child should have received some emission" + ); + + // Check that the total stake has increased by the hardcoded emission amount + let total_stake = parent1_stake + parent2_stake + child_stake + weight_setter_stake; + let initial_total_stake: u64 = initial_stakes.iter().map(|(_, _, stake)| stake).sum(); + assert_eq!( + total_stake, + initial_total_stake + hardcoded_emission - 2, // U64::MAX normalization rounding error + "Total stake should have increased by the hardcoded emission amount" + ); + }); +} + +// 44: Test with a chain of parent-child relationships (e.g., A -> B -> C) +// This test verifies the correct distribution of emissions in a chain of parent-child relationships: +// - Sets up a network with three neurons A, B, and C in a chain (A -> B -> C) +// - Establishes parent-child relationships with different stake proportions +// - Sets weights for all neurons +// - Runs an epoch with a hardcoded emission value +// - Checks the emission distribution among A, B, and C +// - Verifies that all parties received emissions and the total stake increased correctly +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test coinbase test_parent_child_chain_emission -- --nocapture +#[test] +fn test_parent_child_chain_emission() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + add_network(netuid, 1, 0); + + // Define hotkeys and coldkeys + let hotkey_a: U256 = U256::from(1); + let hotkey_b: U256 = U256::from(2); + let hotkey_c: U256 = U256::from(3); + let coldkey_a: U256 = U256::from(100); + let coldkey_b: U256 = U256::from(101); + let coldkey_c: U256 = U256::from(102); + + // Register neurons with decreasing stakes + register_ok_neuron(netuid, hotkey_a, coldkey_a, 0); + register_ok_neuron(netuid, hotkey_b, coldkey_b, 0); + register_ok_neuron(netuid, hotkey_c, coldkey_c, 0); + + // Add initial stakes + SubtensorModule::add_balance_to_coldkey_account(&coldkey_a, 300_000); + SubtensorModule::add_balance_to_coldkey_account(&coldkey_b, 100_000); + SubtensorModule::add_balance_to_coldkey_account(&coldkey_c, 50_000); + + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey_a, &hotkey_a, 300_000); + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey_b, &hotkey_b, 100_000); + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey_c, &hotkey_c, 50_000); + + // Set parent-child relationships + // A -> B (50% of A's stake) + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey_a), + hotkey_a, + netuid, + vec![(u64::MAX / 2, hotkey_b)] + )); + // B -> C (50% of B's stake) + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey_b), + hotkey_b, + netuid, + vec![(u64::MAX / 2, hotkey_c)] + )); + + step_block(2); + + // Set weights + let origin = RuntimeOrigin::signed(hotkey_a); + let uids: Vec = vec![0, 1, 2]; // UIDs for hotkey_a, hotkey_b, hotkey_c + let values: Vec = vec![65535, 65535, 65535]; // Set equal weights for all hotkeys + let version_key = SubtensorModule::get_weights_version_key(netuid); + + // Ensure we can set weights without rate limiting + SubtensorModule::set_weights_set_rate_limit(netuid, 0); + + assert_ok!(SubtensorModule::set_weights( + origin, + netuid, + uids, + values, + version_key + )); + + // Run epoch with a hardcoded emission value + let hardcoded_emission: u64 = 1_000_000; // 1 million (adjust as needed) + let hotkey_emission: Vec<(U256, u64, u64)> = + SubtensorModule::epoch(netuid, hardcoded_emission); + + // Process the hotkey emission results + for (hotkey, mining_emission, validator_emission) in hotkey_emission { + SubtensorModule::accumulate_hotkey_emission( + &hotkey, + netuid, + validator_emission, + mining_emission, + ); + } + + // Log PendingEmission Tuple for a, b, c + let pending_emission_a = SubtensorModule::get_pending_hotkey_emission(&hotkey_a); + let pending_emission_b = SubtensorModule::get_pending_hotkey_emission(&hotkey_b); + let pending_emission_c = SubtensorModule::get_pending_hotkey_emission(&hotkey_c); + + println!("Pending Emission for A: {:?}", pending_emission_a); + println!("Pending Emission for B: {:?}", pending_emission_b); + println!("Pending Emission for C: {:?}", pending_emission_c); + + // Assert that pending emissions are non-zero + // A's pending emission: 2/3 of total emission (due to having 2/3 of total stake) + assert!( + pending_emission_a == 666667, + "A should have pending emission of 2/3 of total emission" + ); + // B's pending emission: 2/9 of total emission (1/3 of A's emission + 1/3 of total emission) + assert!( + pending_emission_b == 222222, + "B should have pending emission of 2/9 of total emission" + ); + // C's pending emission: 1/9 of total emission (1/2 of B's emission) + assert!( + pending_emission_c == 111109, + "C should have pending emission of 1/9 of total emission" + ); + + SubtensorModule::set_hotkey_emission_tempo(10); + + step_block(10 + 1); + // Retrieve the current stake for each hotkey on the subnet + let stake_a: u64 = SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey_a, netuid); + let stake_b: u64 = SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey_b, netuid); + let stake_c: u64 = SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey_c, netuid); + + // Log the current stakes for debugging purposes + log::info!("Stake for hotkey A: {:?}", stake_a); + log::info!("Stake for hotkey B: {:?}", stake_b); + log::info!("Stake for hotkey C: {:?}", stake_c); + + // Assert that the stakes have been updated correctly after emission distribution + assert_eq!( + stake_a, 483334, + "A's stake should be 483334 (initial 300_000 + 666667 emission - 483333 given to B)" + ); + assert_eq!( + stake_b, 644445, + "B's stake should be 644445 (initial 100_000 + 222222 emission + 483333 from A - 161110 given to C)" + ); + assert_eq!( + stake_c, 322219, + "C's stake should be 322219 (initial 50_000 + 111109 emission + 161110 from B)" + ); + + // Check that the total stake has increased by the hardcoded emission amount + let total_stake = stake_a + stake_b + stake_c; + let initial_total_stake = 300_000 + 100_000 + 50_000; + let hardcoded_emission = 1_000_000; // Define the hardcoded emission value + assert_eq!( + total_stake, + initial_total_stake + hardcoded_emission - 2, // U64::MAX normalization rounding error + "Total stake should have increased by the hardcoded emission amount" + ); + }); +} + +// 46: Test emission distribution when adding/removing parent-child relationships mid-epoch +// This test verifies the correct distribution of emissions when parent-child relationships change: +// - Sets up a network with three neurons: parent, child1, and child2 +// - Establishes initial parent-child relationship between parent and child1 +// - Runs first epoch and distributes emissions +// - Changes parent-child relationships to include both child1 and child2 +// - Runs second epoch and distributes emissions +// - Checks final emission distribution and stake updates +// - Verifies correct parent-child relationships and stake proportions +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test children -- test_dynamic_parent_child_relationships --exact --nocapture +#[test] +fn test_dynamic_parent_child_relationships() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + add_network(netuid, 1, 0); + + // Define hotkeys and coldkeys + let parent: U256 = U256::from(1); + let child1: U256 = U256::from(2); + let child2: U256 = U256::from(3); + let coldkey_parent: U256 = U256::from(100); + let coldkey_child1: U256 = U256::from(101); + let coldkey_child2: U256 = U256::from(102); + + // Register neurons with varying stakes + register_ok_neuron(netuid, parent, coldkey_parent, 0); + register_ok_neuron(netuid, child1, coldkey_child1, 0); + register_ok_neuron(netuid, child2, coldkey_child2, 0); + + // Add initial stakes + SubtensorModule::add_balance_to_coldkey_account(&coldkey_parent, 500_000); + SubtensorModule::add_balance_to_coldkey_account(&coldkey_child1, 50_000); + SubtensorModule::add_balance_to_coldkey_account(&coldkey_child2, 30_000); + + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey_parent, &parent, 500_000); + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey_child1, &child1, 50_000); + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey_child2, &child2, 30_000); + + // Set initial parent-child relationship + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey_parent), + parent, + netuid, + vec![(u64::MAX / 2, child1)] + )); + + step_block(2); + + // Set weights + let origin = RuntimeOrigin::signed(parent); + let uids: Vec = vec![0, 1, 2]; // UIDs for parent, child1, child2 + let values: Vec = vec![65535, 65535, 65535]; // Set equal weights for all hotkeys + let version_key = SubtensorModule::get_weights_version_key(netuid); + + // Ensure we can set weights without rate limiting + SubtensorModule::set_weights_set_rate_limit(netuid, 0); + + assert_ok!(SubtensorModule::set_weights( + origin, + netuid, + uids, + values, + version_key + )); + + // Set hotkey emission tempo + SubtensorModule::set_hotkey_emission_tempo(10); + + // Run first epoch + let hardcoded_emission: u64 = 1_000_000; // 1 million (adjust as needed) + let hotkey_emission: Vec<(U256, u64, u64)> = SubtensorModule::epoch(netuid, hardcoded_emission); + + // Process the hotkey emission results + for (hotkey, mining_emission, validator_emission) in hotkey_emission { + SubtensorModule::accumulate_hotkey_emission(&hotkey, netuid, validator_emission, mining_emission); + } + + // Step blocks to allow for emission distribution + step_block(11); + + // Change parent-child relationships + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey_parent), + parent, + netuid, + vec![(u64::MAX / 4, child1), (u64::MAX / 3, child2)] + )); + + // Run second epoch + let hotkey_emission: Vec<(U256, u64, u64)> = SubtensorModule::epoch(netuid, hardcoded_emission); + + // Process the hotkey emission results + for (hotkey, mining_emission, validator_emission) in hotkey_emission { + SubtensorModule::accumulate_hotkey_emission(&hotkey, netuid, validator_emission, mining_emission); + } + + // Step blocks again to allow for emission distribution + step_block(11); + + // Check final emission distribution + let parent_stake: u64 = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); + let child1_stake: u64 = SubtensorModule::get_stake_for_hotkey_on_subnet(&child1, netuid); + let child2_stake: u64 = SubtensorModule::get_stake_for_hotkey_on_subnet(&child2, netuid); + + println!("Final stakes:"); + println!("Parent stake: {}", parent_stake); + println!("Child1 stake: {}", child1_stake); + println!("Child2 stake: {}", child2_stake); + + const TOLERANCE: u64 = 5; // Allow for a small discrepancy due to potential rounding + + // Precise assertions with tolerance + assert!( + (parent_stake as i64 - 926725).abs() <= TOLERANCE as i64, + "Parent stake should be close to 926,725, but was {}", + parent_stake + ); + // Parent stake calculation: + // Initial stake: 500,000 + // First epoch: ~862,500 (500,000 + 725,000 * 1/2) + // Second epoch: ~926,725 (862,500 + 725,000 * 5/12) + + assert!( + (child1_stake as i64 - 778446).abs() <= TOLERANCE as i64, + "Child1 stake should be close to 778,446, but was {}", + child1_stake + ); + // Child1 stake calculation: + // Initial stake: 50,000 + // First epoch: ~412,500 (50,000 + 725,000 * 1/2) + // Second epoch: ~778,446 (412,500 + 725,000 * 1/2 * 1/4 + 137,500) + + assert!( + (child2_stake as i64 - 874826).abs() <= TOLERANCE as i64, + "Child2 stake should be close to 874,826, but was {}", + child2_stake + ); + // Child2 stake calculation: + // Initial stake: 30,000 + // First epoch: ~167,500 (30,000 + 137,500) + // Second epoch: ~874,826 (167,500 + 725,000 * 1/2 * 1/3 + 137,500) + + // Check that the total stake has increased by approximately twice the hardcoded emission amount + let total_stake: u64 = parent_stake + child1_stake + child2_stake; + let initial_total_stake: u64 = 500_000 + 50_000 + 30_000; + let total_emission: u64 = 2 * hardcoded_emission; + assert!( + (total_stake as i64 - (initial_total_stake + total_emission) as i64).abs() <= TOLERANCE as i64, + "Total stake should have increased by approximately twice the hardcoded emission amount" + ); + // Total stake calculation: + // Initial total stake: 500,000 + 50,000 + 30,000 = 580,000 + // Total emission: 2 * 1,000,000 = 2,000,000 + // Expected total stake: 580,000 + 2,000,000 = 2,580,000 + + // Additional checks for parent-child relationships + let parent_children: Vec<(u64, U256)> = SubtensorModule::get_children(&parent, netuid); + assert_eq!( + parent_children, + vec![(u64::MAX / 4, child1), (u64::MAX / 3, child2)], + "Parent should have both children with correct proportions" + ); + // Parent-child relationship: + // child1: 1/4 of parent's stake + // child2: 1/3 of parent's stake + + let child1_parents: Vec<(u64, U256)> = SubtensorModule::get_parents(&child1, netuid); + assert_eq!( + child1_parents, + vec![(u64::MAX / 4, parent)], + "Child1 should have parent as its parent with correct proportion" + ); + // Child1-parent relationship: + // parent: 1/4 of child1's stake + + let child2_parents: Vec<(u64, U256)> = SubtensorModule::get_parents(&child2, netuid); + assert_eq!( + child2_parents, + vec![(u64::MAX / 3, parent)], + "Child2 should have parent as its parent with correct proportion" + ); + // Child2-parent relationship: + // parent: 1/3 of child2's stake + + // Check that child2 has received more stake than child1 + assert!( + child2_stake > child1_stake, + "Child2 should have received more emission than Child1 due to higher proportion" + ); + // Child2 stake (874,826) > Child1 stake (778,446) + + // Check the approximate difference between child2 and child1 stakes + let stake_difference: u64 = child2_stake - child1_stake; + assert!( + (stake_difference as i64 - 96_380).abs() <= TOLERANCE as i64, + "The difference between Child2 and Child1 stakes should be close to 96,380, but was {}", + stake_difference + ); + // Stake difference calculation: + // Child2 stake: 874,826 + // Child1 stake: 778,446 + // Difference: 874,826 - 778,446 = 96,380 + }); +} + +// 47: Test basic stake retrieval for a single hotkey on a subnet +/// This test verifies the basic functionality of retrieving stake for a single hotkey on a subnet: +/// - Sets up a network with one neuron +/// - Increases stake for the neuron +/// - Checks if the retrieved stake matches the increased amount +/// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test children -- test_get_stake_for_hotkey_on_subnet_basic --exact --nocapture +#[test] +fn test_get_stake_for_hotkey_on_subnet_basic() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let hotkey = U256::from(1); + let coldkey = U256::from(2); + + add_network(netuid, 0, 0); + register_ok_neuron(netuid, hotkey, coldkey, 0); + + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey, &hotkey, 1000); + + assert_eq!( + SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey, netuid), + 1000 + ); + }); +} + +// 48: Test stake retrieval for a hotkey with multiple coldkeys on a subnet +/// This test verifies the functionality of retrieving stake for a hotkey with multiple coldkeys on a subnet: +/// - Sets up a network with one neuron and two coldkeys +/// - Increases stake from both coldkeys +/// - Checks if the retrieved stake matches the total increased amount +/// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test children -- test_get_stake_for_hotkey_on_subnet_multiple_coldkeys --exact --nocapture +#[test] +fn test_get_stake_for_hotkey_on_subnet_multiple_coldkeys() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let hotkey = U256::from(1); + let coldkey1 = U256::from(2); + let coldkey2 = U256::from(3); + + add_network(netuid, 0, 0); + register_ok_neuron(netuid, hotkey, coldkey1, 0); + + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey1, &hotkey, 1000); + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey2, &hotkey, 2000); + + assert_eq!( + SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey, netuid), + 3000 + ); + }); +} + +// 49: Test stake retrieval for a single parent-child relationship on a subnet +/// This test verifies the functionality of retrieving stake for a single parent-child relationship on a subnet: +/// - Sets up a network with a parent and child neuron +/// - Increases stake for the parent +/// - Sets the child as the parent's only child with 100% stake allocation +/// - Checks if the retrieved stake for both parent and child is correct +/// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test children -- test_get_stake_for_hotkey_on_subnet_single_parent_child --exact --nocapture +#[test] +fn test_get_stake_for_hotkey_on_subnet_single_parent_child() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let parent = U256::from(1); + let child = U256::from(2); + let coldkey = U256::from(3); + + add_network(netuid, 0, 0); + register_ok_neuron(netuid, parent, coldkey, 0); + register_ok_neuron(netuid, child, coldkey, 0); + + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey, &parent, 1000); + + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + parent, + netuid, + vec![(u64::MAX, child)] + )); + + assert_eq!( + SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid), + 0 + ); + assert_eq!( + SubtensorModule::get_stake_for_hotkey_on_subnet(&child, netuid), + 1000 + ); + }); +} + +// 50: Test stake retrieval for multiple parents and a single child on a subnet +/// This test verifies the functionality of retrieving stake for multiple parents and a single child on a subnet: +/// - Sets up a network with two parents and one child neuron +/// - Increases stake for both parents +/// - Sets the child as a 50% stake recipient for both parents +/// - Checks if the retrieved stake for parents and child is correct +/// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test children -- test_get_stake_for_hotkey_on_subnet_multiple_parents_single_child --exact --nocapture +#[test] +fn test_get_stake_for_hotkey_on_subnet_multiple_parents_single_child() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let parent1 = U256::from(1); + let parent2 = U256::from(2); + let child = U256::from(3); + let coldkey = U256::from(4); + + add_network(netuid, 0, 0); + register_ok_neuron(netuid, parent1, coldkey, 0); + register_ok_neuron(netuid, parent2, coldkey, 0); + register_ok_neuron(netuid, child, coldkey, 0); + + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey, &parent1, 1000); + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey, &parent2, 2000); + + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + parent1, + netuid, + vec![(u64::MAX / 2, child)] + )); + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + parent2, + netuid, + vec![(u64::MAX / 2, child)] + )); + + assert_eq!( + SubtensorModule::get_stake_for_hotkey_on_subnet(&parent1, netuid), + 501 + ); + assert_eq!( + SubtensorModule::get_stake_for_hotkey_on_subnet(&parent2, netuid), + 1001 + ); + assert_eq!( + SubtensorModule::get_stake_for_hotkey_on_subnet(&child, netuid), + 1498 + ); + }); +} + +// 51: Test stake retrieval for a single parent with multiple children on a subnet +/// This test verifies the functionality of retrieving stake for a single parent with multiple children on a subnet: +/// - Sets up a network with one parent and two child neurons +/// - Increases stake for the parent +/// - Sets both children as 1/3 stake recipients of the parent +/// - Checks if the retrieved stake for parent and children is correct and preserves total stake +/// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test children -- test_get_stake_for_hotkey_on_subnet_single_parent_multiple_children --exact --nocapture +#[test] +fn test_get_stake_for_hotkey_on_subnet_single_parent_multiple_children() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let parent = U256::from(1); + let child1 = U256::from(2); + let child2 = U256::from(3); + let coldkey = U256::from(4); + + add_network(netuid, 0, 0); + register_ok_neuron(netuid, parent, coldkey, 0); + register_ok_neuron(netuid, child1, coldkey, 0); + register_ok_neuron(netuid, child2, coldkey, 0); + + let total_stake = 3000; + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey, &parent, total_stake); + + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + parent, + netuid, + vec![(u64::MAX / 3, child1), (u64::MAX / 3, child2)] + )); + + let parent_stake = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); + let child1_stake = SubtensorModule::get_stake_for_hotkey_on_subnet(&child1, netuid); + let child2_stake = SubtensorModule::get_stake_for_hotkey_on_subnet(&child2, netuid); + + // Check that the total stake is preserved + assert_eq!(parent_stake + child1_stake + child2_stake, total_stake); + + // Check that the parent stake is slightly higher due to rounding + assert_eq!(parent_stake, 1002); + + // Check that each child gets an equal share of the remaining stake + assert_eq!(child1_stake, 999); + assert_eq!(child2_stake, 999); + + // Log the actual stake values + println!("Parent stake: {}", parent_stake); + println!("Child1 stake: {}", child1_stake); + println!("Child2 stake: {}", child2_stake); + }); +} + +// 52: Test stake retrieval for edge cases on a subnet +/// This test verifies the functionality of retrieving stake for edge cases on a subnet: +/// - Sets up a network with one parent and two child neurons +/// - Increases stake to the network maximum +/// - Sets children with 0% and 100% stake allocation +/// - Checks if the retrieved stake for parent and children is correct and preserves total stake +/// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test children -- test_get_stake_for_hotkey_on_subnet_edge_cases --exact --nocapture +#[test] +fn test_get_stake_for_hotkey_on_subnet_edge_cases() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let parent = U256::from(1); + let child1 = U256::from(2); + let child2 = U256::from(3); + let coldkey = U256::from(4); + + add_network(netuid, 0, 0); + register_ok_neuron(netuid, parent, coldkey, 0); + register_ok_neuron(netuid, child1, coldkey, 0); + register_ok_neuron(netuid, child2, coldkey, 0); + + // Set network max stake + let network_max_stake: u64 = 500_000_000_000_000; // 500_000 TAO + SubtensorModule::set_network_max_stake(netuid, network_max_stake); + + // Increase stake to the network max + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &coldkey, + &parent, + network_max_stake, + ); + + // Test with 0% and 100% stake allocation + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey), + parent, + netuid, + vec![(0, child1), (u64::MAX, child2)] + )); + + let parent_stake = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); + let child1_stake = SubtensorModule::get_stake_for_hotkey_on_subnet(&child1, netuid); + let child2_stake = SubtensorModule::get_stake_for_hotkey_on_subnet(&child2, netuid); + + println!("Parent stake: {}", parent_stake); + println!("Child1 stake: {}", child1_stake); + println!("Child2 stake: {}", child2_stake); + + assert_eq!(parent_stake, 0, "Parent should have 0 stake"); + assert_eq!(child1_stake, 0, "Child1 should have 0 stake"); + assert_eq!( + child2_stake, network_max_stake, + "Child2 should have all the stake" + ); + + // Check that the total stake is preserved and equal to the network max stake + assert_eq!( + parent_stake + child1_stake + child2_stake, + network_max_stake, + "Total stake should equal the network max stake" + ); + }); +} + +// 53: Test stake distribution in a complex hierarchy of parent-child relationships +// This test verifies the correct distribution of stake in a multi-level parent-child hierarchy: +// - Sets up a network with four neurons: parent, child1, child2, and grandchild +// - Establishes parent-child relationships between parent and its children, and child1 and grandchild +// - Adds initial stake to the parent +// - Checks stake distribution after setting up the first level of relationships +// - Checks stake distribution after setting up the second level of relationships +// - Verifies correct stake calculations, parent-child relationships, and preservation of total stake +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test children -- test_get_stake_for_hotkey_on_subnet_complex_hierarchy --exact --nocapture + +#[test] +fn test_get_stake_for_hotkey_on_subnet_complex_hierarchy() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let parent = U256::from(1); + let child1 = U256::from(2); + let child2 = U256::from(3); + let grandchild = U256::from(4); + let coldkey_parent = U256::from(5); + let coldkey_child1 = U256::from(6); + let coldkey_child2 = U256::from(7); + let coldkey_grandchild = U256::from(8); + + add_network(netuid, 0, 0); + SubtensorModule::set_max_registrations_per_block(netuid, 1000); + SubtensorModule::set_target_registrations_per_interval(netuid, 1000); + register_ok_neuron(netuid, parent, coldkey_parent, 0); + register_ok_neuron(netuid, child1, coldkey_child1, 0); + register_ok_neuron(netuid, child2, coldkey_child2, 0); + register_ok_neuron(netuid, grandchild, coldkey_grandchild, 0); + + let total_stake = 1000; + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &coldkey_parent, + &parent, + total_stake, + ); + + println!("Initial stakes:"); + println!( + "Parent stake: {}", + SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid) + ); + println!( + "Child1 stake: {}", + SubtensorModule::get_stake_for_hotkey_on_subnet(&child1, netuid) + ); + println!( + "Child2 stake: {}", + SubtensorModule::get_stake_for_hotkey_on_subnet(&child2, netuid) + ); + println!( + "Grandchild stake: {}", + SubtensorModule::get_stake_for_hotkey_on_subnet(&grandchild, netuid) + ); + + // Step 1: Set children for parent + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey_parent), + parent, + netuid, + vec![(u64::MAX / 2, child1), (u64::MAX / 2, child2)] + )); + + println!("After setting parent's children:"); + println!( + "Parent's children: {:?}", + SubtensorModule::get_children(&parent, netuid) + ); + println!( + "Child1's parents: {:?}", + SubtensorModule::get_parents(&child1, netuid) + ); + println!( + "Child2's parents: {:?}", + SubtensorModule::get_parents(&child2, netuid) + ); + + let parent_stake_1 = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); + let child1_stake_1 = SubtensorModule::get_stake_for_hotkey_on_subnet(&child1, netuid); + let child2_stake_1 = SubtensorModule::get_stake_for_hotkey_on_subnet(&child2, netuid); + + println!("Parent stake: {}", parent_stake_1); + println!("Child1 stake: {}", child1_stake_1); + println!("Child2 stake: {}", child2_stake_1); + + assert_eq!( + parent_stake_1, 2, + "Parent should have 2 stake due to rounding" + ); + assert_eq!(child1_stake_1, 499, "Child1 should have 499 stake"); + assert_eq!(child2_stake_1, 499, "Child2 should have 499 stake"); + + // Step 2: Set children for child1 + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(coldkey_child1), + child1, + netuid, + vec![(u64::MAX, grandchild)] + )); + + println!("After setting child1's children:"); + println!( + "Child1's children: {:?}", + SubtensorModule::get_children(&child1, netuid) + ); + println!( + "Grandchild's parents: {:?}", + SubtensorModule::get_parents(&grandchild, netuid) + ); + + let parent_stake_2 = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); + let child1_stake_2 = SubtensorModule::get_stake_for_hotkey_on_subnet(&child1, netuid); + let child2_stake_2 = SubtensorModule::get_stake_for_hotkey_on_subnet(&child2, netuid); + let grandchild_stake = SubtensorModule::get_stake_for_hotkey_on_subnet(&grandchild, netuid); + + println!("Parent stake: {}", parent_stake_2); + println!("Child1 stake: {}", child1_stake_2); + println!("Child2 stake: {}", child2_stake_2); + println!("Grandchild stake: {}", grandchild_stake); + + assert_eq!(parent_stake_2, 2, "Parent stake should remain 2"); + assert_eq!( + child1_stake_2, 499, + "Child1 stake should be be the same , as it doesnt have owned stake" + ); + assert_eq!(child2_stake_2, 499, "Child2 should still have 499 stake"); + assert_eq!( + grandchild_stake, 0, + "Grandchild should have 0 , as child1 doesnt have any owned stake" + ); + + // Check that the total stake is preserved + assert_eq!( + parent_stake_2 + child1_stake_2 + child2_stake_2 + grandchild_stake, + total_stake, + "Total stake should equal the initial stake" + ); + + // Additional checks + println!("Final parent-child relationships:"); + println!( + "Parent's children: {:?}", + SubtensorModule::get_children(&parent, netuid) + ); + println!( + "Child1's parents: {:?}", + SubtensorModule::get_parents(&child1, netuid) + ); + println!( + "Child2's parents: {:?}", + SubtensorModule::get_parents(&child2, netuid) + ); + println!( + "Child1's children: {:?}", + SubtensorModule::get_children(&child1, netuid) + ); + println!( + "Grandchild's parents: {:?}", + SubtensorModule::get_parents(&grandchild, netuid) + ); + + // Check if the parent-child relationships are correct + assert_eq!( + SubtensorModule::get_children(&parent, netuid), + vec![(u64::MAX / 2, child1), (u64::MAX / 2, child2)], + "Parent should have both children" + ); + assert_eq!( + SubtensorModule::get_parents(&child1, netuid), + vec![(u64::MAX / 2, parent)], + "Child1 should have parent as its parent" + ); + assert_eq!( + SubtensorModule::get_parents(&child2, netuid), + vec![(u64::MAX / 2, parent)], + "Child2 should have parent as its parent" + ); + assert_eq!( + SubtensorModule::get_children(&child1, netuid), + vec![(u64::MAX, grandchild)], + "Child1 should have grandchild as its child" + ); + assert_eq!( + SubtensorModule::get_parents(&grandchild, netuid), + vec![(u64::MAX, child1)], + "Grandchild should have child1 as its parent" + ); + }); +} + +// 54: Test stake distribution across multiple networks +// This test verifies the correct distribution of stake for a single neuron across multiple networks: +// - Sets up two networks with a single neuron registered on both +// - Adds initial stake to the neuron +// - Checks that the stake is correctly reflected on both networks +// - Verifies that changes in stake are consistently applied across all networks +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test children -- test_get_stake_for_hotkey_on_subnet_multiple_networks --exact --nocapture + +#[test] +fn test_get_stake_for_hotkey_on_subnet_multiple_networks() { + new_test_ext(1).execute_with(|| { + let netuid1: u16 = 1; + let netuid2: u16 = 2; + let hotkey = U256::from(1); + let coldkey = U256::from(2); + + add_network(netuid1, 0, 0); + add_network(netuid2, 0, 0); + register_ok_neuron(netuid1, hotkey, coldkey, 0); + register_ok_neuron(netuid2, hotkey, coldkey, 0); + + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey, &hotkey, 1000); + + assert_eq!( + SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey, netuid1), + 1000 + ); + assert_eq!( + SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey, netuid2), + 1000 + ); + }); +} + +/// 55: Test rank, trust, and incentive calculation with parent-child relationships +/// +/// This test verifies the correct calculation and distribution of rank, trust, incentive, and dividends +/// in a network with parent-child relationships: +/// - Sets up a network with validators (including a parent-child pair) and miners +/// - Establishes initial stakes and weights for all validators +/// - Runs a first epoch to establish baseline metrics +/// - Sets up a parent-child relationship +/// - Runs a second epoch to observe changes in metrics +/// - Verifies that the child's metrics improve relative to its initial state and other validators +/// +/// # Test Steps: +/// 1. Initialize test environment with validators (including parent and child) and miners +/// 2. Set up network parameters and register all neurons +/// 3. Set initial stakes for validators +/// 4. Set initial weights for all validators +/// 5. Run first epoch and process emissions +/// 6. Record initial metrics for the child +/// 7. Establish parent-child relationship +/// 8. Run second epoch and process emissions +/// 9. Record final metrics for the child +/// 10. Compare child's initial and final metrics +/// 11. Compare child's final metrics with other validators +/// +/// # Expected Results: +/// - Child's rank should improve (decrease) +/// - Child's trust should increase or remain the same +/// - Child's dividends should increase +/// - Child's final metrics should be better than or equal to other validators' +/// +/// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test children -- test_rank_trust_incentive_calculation_with_parent_child --exact --nocapture +#[test] +fn test_rank_trust_incentive_calculation_with_parent_child() { + new_test_ext(1).execute_with(|| { + // Initialize test environment + let netuid: u16 = 1; + let parent_hotkey: U256 = U256::from(1); + let parent_coldkey: U256 = U256::from(101); + let child_hotkey: U256 = U256::from(2); + let child_coldkey: U256 = U256::from(102); + let other_validators: Vec<(U256, U256)> = (3..6) + .map(|i| (U256::from(i), U256::from(100 + i))) + .collect(); + let miners: Vec<(U256, U256)> = (6..16) + .map(|i| (U256::from(i), U256::from(100 + i))) + .collect(); // 10 miners + + // Setup network and set registration parameters + add_network(netuid, 1, 0); + SubtensorModule::set_max_registrations_per_block(netuid, 1000); + SubtensorModule::set_target_registrations_per_interval(netuid, 1000); + SubtensorModule::set_weights_set_rate_limit(netuid, 0); + SubtensorModule::set_hotkey_emission_tempo(10); + + // Register neurons (validators and miners) + register_ok_neuron(netuid, parent_hotkey, parent_coldkey, 0); + register_ok_neuron(netuid, child_hotkey, child_coldkey, 0); + for (hotkey, coldkey) in &other_validators { + register_ok_neuron(netuid, *hotkey, *coldkey, 0); + } + for (hotkey, coldkey) in &miners { + register_ok_neuron(netuid, *hotkey, *coldkey, 0); + } + + step_block(2); + + // Set initial stakes for validators only + let initial_stake: u64 = 1_000_000_000; // 1000 TAO + SubtensorModule::add_balance_to_coldkey_account(&parent_coldkey, initial_stake); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &parent_coldkey, + &parent_hotkey, + initial_stake, + ); + SubtensorModule::add_balance_to_coldkey_account(&child_coldkey, initial_stake); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + &child_coldkey, + &child_hotkey, + initial_stake, + ); + for (hotkey, coldkey) in &other_validators { + SubtensorModule::add_balance_to_coldkey_account(coldkey, initial_stake); + SubtensorModule::increase_stake_on_coldkey_hotkey_account( + coldkey, + hotkey, + initial_stake, + ); + } + + step_block(2); + + // Set initial weights for all validators + let all_uids: Vec = (0..15).collect(); // 0-4 are validators, 5-14 are miners + let validator_weights: Vec = vec![u16::MAX / 5; 5] // Equal weights for validators + .into_iter() + .chain(vec![u16::MAX / 10; 10]) // Equal weights for miners + .collect(); + + for hotkey in std::iter::once(&parent_hotkey) + .chain(other_validators.iter().map(|(h, _)| h)) + .chain(std::iter::once(&child_hotkey)) + { + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(*hotkey), + netuid, + all_uids.clone(), + validator_weights.clone(), + 0 + )); + } + + step_block(10); + + // Run first epoch + let rao_emission: u64 = 1_000_000_000; + let initial_emission = SubtensorModule::epoch(netuid, rao_emission); + + // Process initial emission + for (hotkey, mining_emission, validator_emission) in initial_emission { + SubtensorModule::accumulate_hotkey_emission( + &hotkey, + netuid, + validator_emission, + mining_emission, + ); + } + + step_block(11); + + // Get initial rank, trust, incentive, and dividends for the child + let initial_child_rank: u16 = SubtensorModule::get_rank_for_uid(netuid, 1); + let initial_child_trust: u16 = SubtensorModule::get_trust_for_uid(netuid, 1); + let initial_child_incentive: u16 = SubtensorModule::get_incentive_for_uid(netuid, 1); + let initial_child_dividends: u16 = SubtensorModule::get_dividends_for_uid(netuid, 1); + + log::debug!("Initial child rank: {:?}", initial_child_rank); + log::debug!("Initial child trust: {:?}", initial_child_trust); + log::debug!("Initial child incentive: {:?}", initial_child_incentive); + log::debug!("Initial child dividends: {:?}", initial_child_dividends); + + // Parent sets the child with 100% of its weight + assert_ok!(SubtensorModule::do_set_children( + RuntimeOrigin::signed(parent_coldkey), + parent_hotkey, + netuid, + vec![(u64::MAX, child_hotkey)] + )); + + // Child now sets weights as a validator + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(child_hotkey), + netuid, + all_uids.clone(), + validator_weights.clone(), + 1 + )); + + step_block(10); + + // Run second epoch + let final_emission = SubtensorModule::epoch(netuid, rao_emission); + + // Process final emission + for (hotkey, mining_emission, validator_emission) in final_emission { + SubtensorModule::accumulate_hotkey_emission( + &hotkey, + netuid, + validator_emission, + mining_emission, + ); + } + + step_block(11); + + // Get final rank, trust, incentive, and dividends for the child + let final_child_rank: u16 = SubtensorModule::get_rank_for_uid(netuid, 1); + let final_child_trust: u16 = SubtensorModule::get_trust_for_uid(netuid, 1); + let final_child_incentive: u16 = SubtensorModule::get_incentive_for_uid(netuid, 1); + let final_child_dividends: u16 = SubtensorModule::get_dividends_for_uid(netuid, 1); + + log::debug!("Final child rank: {:?}", final_child_rank); + log::debug!("Final child trust: {:?}", final_child_trust); + log::debug!("Final child incentive: {:?}", final_child_incentive); + log::debug!("Final child dividends: {:?}", final_child_dividends); + + // Print ranks for all validators + for i in 0..5 { + log::debug!( + "Validator {} rank: {:?}", + i, + SubtensorModule::get_rank_for_uid(netuid, i) + ); + } + + // Assert that rank has improved (decreased) for the child + assert!( + final_child_rank < initial_child_rank, + "Child rank should have improved (decreased). Initial: {}, Final: {}", + initial_child_rank, + final_child_rank + ); + + // Assert that trust has increased or remained the same for the child + assert!( + final_child_trust >= initial_child_trust, + "Child trust should have increased or remained the same. Initial: {}, Final: {}", + initial_child_trust, + final_child_trust + ); + + + // Assert that dividends have increased for the child + assert!( + final_child_dividends > initial_child_dividends, + "Child dividends should have increased. Initial: {}, Final: {}", + initial_child_dividends, + final_child_dividends + ); + + // Compare child's final values with other validators + for i in 2..5 { + let other_rank: u16 = SubtensorModule::get_rank_for_uid(netuid, i); + let other_trust: u16 = SubtensorModule::get_trust_for_uid(netuid, i); + let other_incentive: u16 = SubtensorModule::get_incentive_for_uid(netuid, i); + let other_dividends: u16 = SubtensorModule::get_dividends_for_uid(netuid, i); + + log::debug!( + "Validator {} - Rank: {}, Trust: {}, Incentive: {}, Dividends: {}", + i, other_rank, other_trust, other_incentive, other_dividends + ); + + assert!( + final_child_rank <= other_rank, + "Child rank should be better than or equal to other validators. Child: {}, Other: {}", + final_child_rank, + other_rank + ); + + assert!( + final_child_trust >= other_trust, + "Child trust should be greater than or equal to other validators. Child: {}, Other: {}", + final_child_trust, + other_trust + ); + + assert!( + final_child_dividends >= other_dividends, + "Child dividends should be greater than or equal to other validators. Child: {}, Other: {}", + final_child_dividends, + other_dividends + ); + } + + }); +} diff --git a/pallets/subtensor/tests/mock.rs b/pallets/subtensor/tests/mock.rs index 4039054e0..022849c56 100644 --- a/pallets/subtensor/tests/mock.rs +++ b/pallets/subtensor/tests/mock.rs @@ -507,3 +507,21 @@ pub fn add_network(netuid: u16, tempo: u16, _modality: u16) { SubtensorModule::set_network_registration_allowed(netuid, true); SubtensorModule::set_network_pow_registration_allowed(netuid, true); } + +// Helper function to set up a neuron with stake +#[allow(dead_code)] +pub fn setup_neuron_with_stake(netuid: u16, hotkey: U256, coldkey: U256, stake: u64) { + register_ok_neuron(netuid, hotkey, coldkey, stake); + SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey, &hotkey, stake); +} + +// Helper function to check if a value is within tolerance of an expected value +#[allow(dead_code)] +pub fn is_within_tolerance(actual: u64, expected: u64, tolerance: u64) -> bool { + let difference = if actual > expected { + actual - expected + } else { + expected - actual + }; + difference <= tolerance +} From 3de5b038307d3553e7999b47e960deab2bcc9a39 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Wed, 7 Aug 2024 07:56:25 -0700 Subject: [PATCH 20/31] Update run_coinbase.rs --- pallets/subtensor/src/coinbase/run_coinbase.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 442a9f085..f7fa3b2a2 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -131,6 +131,11 @@ impl Pallet { log::debug!("Accumulated emissions on hotkey {:?} for netuid {:?}: mining {:?}, validator {:?}", hotkey, *netuid, mining_emission, validator_emission); } } else { + // No epoch, increase blocks since last step and continue, + Self::set_blocks_since_last_step( + *netuid, + Self::get_blocks_since_last_step(*netuid).saturating_add(1), + ); log::debug!("Tempo not reached for subnet: {:?}", *netuid); } } From 037b76db2637d2e47970f3909ea1e4ab5256bf19 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Wed, 7 Aug 2024 09:13:58 -0700 Subject: [PATCH 21/31] add test_blocks_since_last_step --- .../subtensor/src/coinbase/run_coinbase.rs | 2 +- pallets/subtensor/tests/epoch.rs | 47 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index f7fa3b2a2..723edc423 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -131,7 +131,7 @@ impl Pallet { log::debug!("Accumulated emissions on hotkey {:?} for netuid {:?}: mining {:?}, validator {:?}", hotkey, *netuid, mining_emission, validator_emission); } } else { - // No epoch, increase blocks since last step and continue, + // No epoch, increase blocks since last step and continue Self::set_blocks_since_last_step( *netuid, Self::get_blocks_since_last_step(*netuid).saturating_add(1), diff --git a/pallets/subtensor/tests/epoch.rs b/pallets/subtensor/tests/epoch.rs index b639a4ac4..9c4bf87cc 100644 --- a/pallets/subtensor/tests/epoch.rs +++ b/pallets/subtensor/tests/epoch.rs @@ -2703,6 +2703,53 @@ fn test_get_set_alpha() { }); } +#[test] +fn test_blocks_since_last_step() { + new_test_ext(1).execute_with(|| { + System::set_block_number(0); + + let netuid: u16 = 1; + let tempo: u16 = 7200; + add_network(netuid, tempo, 0); + + let original_blocks: u64 = SubtensorModule::get_blocks_since_last_step(netuid); + + step_block(5); + + let new_blocks: u64 = SubtensorModule::get_blocks_since_last_step(netuid); + + assert!(new_blocks > original_blocks); + assert_eq!(new_blocks, 5); + + let blocks_to_step: u16 = SubtensorModule::blocks_until_next_epoch( + netuid, + tempo, + SubtensorModule::get_current_block_as_u64(), + ) as u16 + + 10; + step_block(blocks_to_step); + + let post_blocks: u64 = SubtensorModule::get_blocks_since_last_step(netuid); + + assert_eq!(post_blocks, 10); + + let blocks_to_step: u16 = SubtensorModule::blocks_until_next_epoch( + netuid, + tempo, + SubtensorModule::get_current_block_as_u64(), + ) as u16 + + 20; + step_block(blocks_to_step); + + let new_post_blocks: u64 = SubtensorModule::get_blocks_since_last_step(netuid); + + assert_eq!(new_post_blocks, 20); + + step_block(7); + + assert_eq!(SubtensorModule::get_blocks_since_last_step(netuid), 27); + }); +} // // Map the retention graph for consensus guarantees with an single epoch on a graph with 512 nodes, of which the first 64 are validators, the graph is split into a major and minor set, each setting specific weight on itself and the complement on the other. // // // // ```import torch From a6d13f62adec87aff6b7598a65103c7a19f19f1d Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Thu, 8 Aug 2024 13:55:28 -0400 Subject: [PATCH 22/31] Add short default tempo to fast-blocks feature --- runtime/src/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index dec65f60f..f5db5d1ed 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -848,6 +848,12 @@ impl pallet_commitments::Config for Runtime { type RateLimit = CommitmentRateLimit; } +#[cfg(not(feature = "fast-blocks"))] +pub const INITIAL_SUBNET_TEMPO: u16 = 99; + +#[cfg(feature = "fast-blocks")] +pub const INITIAL_SUBNET_TEMPO: u16 = 10; + // Configure the pallet subtensor. parameter_types! { pub const SubtensorInitialRho: u16 = 10; @@ -860,7 +866,7 @@ parameter_types! { pub const SubtensorInitialValidatorPruneLen: u64 = 1; pub const SubtensorInitialScalingLawPower: u16 = 50; // 0.5 pub const SubtensorInitialMaxAllowedValidators: u16 = 128; - pub const SubtensorInitialTempo: u16 = 99; + pub const SubtensorInitialTempo: u16 = INITIAL_SUBNET_TEMPO; pub const SubtensorInitialDifficulty: u64 = 10_000_000; pub const SubtensorInitialAdjustmentInterval: u16 = 100; pub const SubtensorInitialAdjustmentAlpha: u64 = 0; // no weight to previous value. From 10114250d90bd385d9b5ee480a3524169b00490b Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Thu, 8 Aug 2024 18:15:33 -0400 Subject: [PATCH 23/31] Add short InitialTxChildkeyTakeRateLimit to fast-blocks feature --- runtime/src/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index f5db5d1ed..45ebee849 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -854,6 +854,12 @@ pub const INITIAL_SUBNET_TEMPO: u16 = 99; #[cfg(feature = "fast-blocks")] pub const INITIAL_SUBNET_TEMPO: u16 = 10; +#[cfg(not(feature = "fast-blocks"))] +pub const INITIAL_CHILDKEY_TAKE_RATELIMIT: u64 = 216000; // 30 days at 12 seconds per block + +#[cfg(feature = "fast-blocks")] +pub const INITIAL_CHILDKEY_TAKE_RATELIMIT: u64 = 5; + // Configure the pallet subtensor. parameter_types! { pub const SubtensorInitialRho: u16 = 10; @@ -889,7 +895,7 @@ parameter_types! { pub const SubtensorInitialMaxBurn: u64 = 100_000_000_000; // 100 tao pub const SubtensorInitialTxRateLimit: u64 = 1000; pub const SubtensorInitialTxDelegateTakeRateLimit: u64 = 216000; // 30 days at 12 seconds per block - pub const SubtensorInitialTxChildKeyTakeRateLimit: u64 = 216000; // 30 days at 12 seconds per block + pub const SubtensorInitialTxChildKeyTakeRateLimit: u64 = INITIAL_CHILDKEY_TAKE_RATELIMIT; pub const SubtensorInitialRAORecycledForRegistration: u64 = 0; // 0 rao pub const SubtensorInitialSenateRequiredStakePercentage: u64 = 1; // 1 percent of total stake pub const SubtensorInitialNetworkImmunity: u64 = 7 * 7200; From 68ec4c66ae263f1ee343b6b8f752ada467bff9fb Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Fri, 9 Aug 2024 16:13:14 +0400 Subject: [PATCH 24/31] feat: bump network max stake --- pallets/admin-utils/tests/mock.rs | 2 +- runtime/src/lib.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pallets/admin-utils/tests/mock.rs b/pallets/admin-utils/tests/mock.rs index acb9c8a4a..5575bd560 100644 --- a/pallets/admin-utils/tests/mock.rs +++ b/pallets/admin-utils/tests/mock.rs @@ -118,7 +118,7 @@ parameter_types! { pub const InitialAlphaLow: u16 = 45875; // Represents 0.7 as per the production default pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn pub const InitialHotkeyEmissionTempo: u64 = 1; - pub const InitialNetworkMaxStake: u64 = 500_000_000_000_000; // 500_000 TAO + pub const InitialNetworkMaxStake: u64 = u64::MAX; // Maximum possible value for u64, this make the make stake infinity } impl pallet_subtensor::Config for Test { diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index dec65f60f..80818f7e4 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -899,7 +899,8 @@ parameter_types! { pub const InitialAlphaLow: u16 = 45875; // Represents 0.7 as per the production default pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn pub const SubtensorInitialHotkeyEmissionTempo: u64 = 7200; // Drain every day. - pub const SubtensorInitialNetworkMaxStake: u64 = 500_000_000_000_000; // 500_000 TAO + pub const SubtensorInitialNetworkMaxStake: u64 = u64::MAX; // Maximum possible value for u64, this make the make stake infinity + } impl pallet_subtensor::Config for Runtime { From ae40d0f64e8773f1c1c750e1ff2bdaff3ba38df6 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Fri, 9 Aug 2024 18:57:47 +0400 Subject: [PATCH 25/31] chore: add sudo calls for setting min/max childkey takes --- pallets/subtensor/src/macros/dispatches.rs | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/pallets/subtensor/src/macros/dispatches.rs b/pallets/subtensor/src/macros/dispatches.rs index a776cfc4f..2d6c5bde0 100644 --- a/pallets/subtensor/src/macros/dispatches.rs +++ b/pallets/subtensor/src/macros/dispatches.rs @@ -786,6 +786,53 @@ mod dispatches { Ok(()) } + /// Sets the minimum allowed childkey take. + /// + /// This function can only be called by the root origin. + /// + /// # Arguments: + /// * `origin` - The origin of the call, must be root. + /// * `take` - The new minimum childkey take value. + /// + /// # Errors: + /// * `BadOrigin` - If the origin is not root. + /// + #[pallet::call_index(76)] + #[pallet::weight(( + Weight::from_parts(6_000, 0) + .saturating_add(T::DbWeight::get().writes(1)), + DispatchClass::Operational, + Pays::No + ))] + pub fn sudo_set_min_childkey_take(origin: OriginFor, take: u16) -> DispatchResult { + ensure_root(origin)?; + Self::set_min_childkey_take(take); + Ok(()) + } + + /// Sets the maximum allowed childkey take. + /// + /// This function can only be called by the root origin. + /// + /// # Arguments: + /// * `origin` - The origin of the call, must be root. + /// * `take` - The new maximum childkey take value. + /// + /// # Errors: + /// * `BadOrigin` - If the origin is not root. + /// + #[pallet::call_index(77)] + #[pallet::weight(( + Weight::from_parts(6_000, 0) + .saturating_add(T::DbWeight::get().writes(1)), + DispatchClass::Operational, + Pays::No + ))] + pub fn sudo_set_max_childkey_take(origin: OriginFor, take: u16) -> DispatchResult { + ensure_root(origin)?; + Self::set_max_childkey_take(take); + Ok(()) + } // ================================== // ==== Parameter Sudo calls ======== // ================================== From ce0dfa7ec2c7d2480c9f0ab254e9c020c91ff846 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Wed, 14 Aug 2024 10:12:21 -0400 Subject: [PATCH 26/31] Fix rate limit for setting children --- pallets/subtensor/src/staking/set_children.rs | 12 +++++++++++- pallets/subtensor/src/utils/rate_limiting.rs | 7 +++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/pallets/subtensor/src/staking/set_children.rs b/pallets/subtensor/src/staking/set_children.rs index 402e9fd2a..ebd8db6bf 100644 --- a/pallets/subtensor/src/staking/set_children.rs +++ b/pallets/subtensor/src/staking/set_children.rs @@ -61,12 +61,22 @@ impl Pallet { // Ensure the hotkey passes the rate limit. ensure!( Self::passes_rate_limit_globally( - &TransactionType::SetChildren, // Set children. &hotkey, // Specific to a hotkey. + netuid, // Specific to a subnet. + &TransactionType::SetChildren, // Set children. ), Error::::TxRateLimitExceeded ); + // Set last transaction block + let current_block = Self::get_current_block_as_u64(); + Self::set_last_transaction_block( + &hotkey, + netuid, + &TransactionType::SetChildren, + current_block + ); + // --- 2. Check that this delegation is not on the root network. Child hotkeys are not valid on root. ensure!( netuid != Self::get_root_netuid(), diff --git a/pallets/subtensor/src/utils/rate_limiting.rs b/pallets/subtensor/src/utils/rate_limiting.rs index b02ad9855..1b75de7d5 100644 --- a/pallets/subtensor/src/utils/rate_limiting.rs +++ b/pallets/subtensor/src/utils/rate_limiting.rs @@ -58,8 +58,11 @@ impl Pallet { } /// 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; + pub fn passes_rate_limit_globally( + hotkey: &T::AccountId, + netuid: u16, + tx_type: &TransactionType, + ) -> 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); From d6790a3972d3fe90fa5351e3c2483ba6da75ac70 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Fri, 16 Aug 2024 12:03:03 -0400 Subject: [PATCH 27/31] Use passes_rate_limit_on_subnet for setting children --- pallets/subtensor/src/staking/set_children.rs | 4 ++-- pallets/subtensor/src/utils/rate_limiting.rs | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/pallets/subtensor/src/staking/set_children.rs b/pallets/subtensor/src/staking/set_children.rs index ebd8db6bf..31bf96f52 100644 --- a/pallets/subtensor/src/staking/set_children.rs +++ b/pallets/subtensor/src/staking/set_children.rs @@ -60,10 +60,10 @@ impl Pallet { // Ensure the hotkey passes the rate limit. ensure!( - Self::passes_rate_limit_globally( + Self::passes_rate_limit_on_subnet( + &TransactionType::SetChildren, // Set children. &hotkey, // Specific to a hotkey. netuid, // Specific to a subnet. - &TransactionType::SetChildren, // Set children. ), Error::::TxRateLimitExceeded ); diff --git a/pallets/subtensor/src/utils/rate_limiting.rs b/pallets/subtensor/src/utils/rate_limiting.rs index 1b75de7d5..b02ad9855 100644 --- a/pallets/subtensor/src/utils/rate_limiting.rs +++ b/pallets/subtensor/src/utils/rate_limiting.rs @@ -58,11 +58,8 @@ impl Pallet { } /// Check if a transaction should be rate limited globally - pub fn passes_rate_limit_globally( - hotkey: &T::AccountId, - netuid: u16, - tx_type: &TransactionType, - ) -> bool { + 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); From f1866df8e497717c7e551944e1e3ded25ce0785e Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Fri, 9 Aug 2024 19:58:43 +0400 Subject: [PATCH 28/31] draft take tests --- pallets/subtensor/tests/children.rs | 303 ++++++++++++++++++++++++---- 1 file changed, 263 insertions(+), 40 deletions(-) diff --git a/pallets/subtensor/tests/children.rs b/pallets/subtensor/tests/children.rs index f491e8b64..f66c88441 100644 --- a/pallets/subtensor/tests/children.rs +++ b/pallets/subtensor/tests/children.rs @@ -421,8 +421,8 @@ fn test_get_stake_for_hotkey_on_subnet() { let parent_stake = SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid); let child_stake = SubtensorModule::get_stake_for_hotkey_on_subnet(&child, netuid); - println!("Parent stake: {}", parent_stake); - println!("Child stake: {}", child_stake); + log::info!("Parent stake: {}", parent_stake); + log::info!("Child stake: {}", child_stake); // The parent should have 0 stake as it's all allocated to the child assert_eq!(parent_stake, 0); @@ -2233,9 +2233,9 @@ fn test_parent_child_chain_emission() { let pending_emission_b = SubtensorModule::get_pending_hotkey_emission(&hotkey_b); let pending_emission_c = SubtensorModule::get_pending_hotkey_emission(&hotkey_c); - println!("Pending Emission for A: {:?}", pending_emission_a); - println!("Pending Emission for B: {:?}", pending_emission_b); - println!("Pending Emission for C: {:?}", pending_emission_c); + log::info!("Pending Emission for A: {:?}", pending_emission_a); + log::info!("Pending Emission for B: {:?}", pending_emission_b); + log::info!("Pending Emission for C: {:?}", pending_emission_c); // Assert that pending emissions are non-zero // A's pending emission: 2/3 of total emission (due to having 2/3 of total stake) @@ -2397,10 +2397,10 @@ fn test_dynamic_parent_child_relationships() { let child1_stake: u64 = SubtensorModule::get_stake_for_hotkey_on_subnet(&child1, netuid); let child2_stake: u64 = SubtensorModule::get_stake_for_hotkey_on_subnet(&child2, netuid); - println!("Final stakes:"); - println!("Parent stake: {}", parent_stake); - println!("Child1 stake: {}", child1_stake); - println!("Child2 stake: {}", child2_stake); + log::info!("Final stakes:"); + log::info!("Parent stake: {}", parent_stake); + log::info!("Child1 stake: {}", child1_stake); + log::info!("Child2 stake: {}", child2_stake); const TOLERANCE: u64 = 5; // Allow for a small discrepancy due to potential rounding @@ -2687,9 +2687,9 @@ fn test_get_stake_for_hotkey_on_subnet_single_parent_multiple_children() { assert_eq!(child2_stake, 999); // Log the actual stake values - println!("Parent stake: {}", parent_stake); - println!("Child1 stake: {}", child1_stake); - println!("Child2 stake: {}", child2_stake); + log::info!("Parent stake: {}", parent_stake); + log::info!("Child1 stake: {}", child1_stake); + log::info!("Child2 stake: {}", child2_stake); }); } @@ -2737,9 +2737,9 @@ fn test_get_stake_for_hotkey_on_subnet_edge_cases() { let child1_stake = SubtensorModule::get_stake_for_hotkey_on_subnet(&child1, netuid); let child2_stake = SubtensorModule::get_stake_for_hotkey_on_subnet(&child2, netuid); - println!("Parent stake: {}", parent_stake); - println!("Child1 stake: {}", child1_stake); - println!("Child2 stake: {}", child2_stake); + log::info!("Parent stake: {}", parent_stake); + log::info!("Child1 stake: {}", child1_stake); + log::info!("Child2 stake: {}", child2_stake); assert_eq!(parent_stake, 0, "Parent should have 0 stake"); assert_eq!(child1_stake, 0, "Child1 should have 0 stake"); @@ -2795,20 +2795,20 @@ fn test_get_stake_for_hotkey_on_subnet_complex_hierarchy() { total_stake, ); - println!("Initial stakes:"); - println!( + log::info!("Initial stakes:"); + log::info!( "Parent stake: {}", SubtensorModule::get_stake_for_hotkey_on_subnet(&parent, netuid) ); - println!( + log::info!( "Child1 stake: {}", SubtensorModule::get_stake_for_hotkey_on_subnet(&child1, netuid) ); - println!( + log::info!( "Child2 stake: {}", SubtensorModule::get_stake_for_hotkey_on_subnet(&child2, netuid) ); - println!( + log::info!( "Grandchild stake: {}", SubtensorModule::get_stake_for_hotkey_on_subnet(&grandchild, netuid) ); @@ -2821,16 +2821,16 @@ fn test_get_stake_for_hotkey_on_subnet_complex_hierarchy() { vec![(u64::MAX / 2, child1), (u64::MAX / 2, child2)] )); - println!("After setting parent's children:"); - println!( + log::info!("After setting parent's children:"); + log::info!( "Parent's children: {:?}", SubtensorModule::get_children(&parent, netuid) ); - println!( + log::info!( "Child1's parents: {:?}", SubtensorModule::get_parents(&child1, netuid) ); - println!( + log::info!( "Child2's parents: {:?}", SubtensorModule::get_parents(&child2, netuid) ); @@ -2839,9 +2839,9 @@ fn test_get_stake_for_hotkey_on_subnet_complex_hierarchy() { let child1_stake_1 = SubtensorModule::get_stake_for_hotkey_on_subnet(&child1, netuid); let child2_stake_1 = SubtensorModule::get_stake_for_hotkey_on_subnet(&child2, netuid); - println!("Parent stake: {}", parent_stake_1); - println!("Child1 stake: {}", child1_stake_1); - println!("Child2 stake: {}", child2_stake_1); + log::info!("Parent stake: {}", parent_stake_1); + log::info!("Child1 stake: {}", child1_stake_1); + log::info!("Child2 stake: {}", child2_stake_1); assert_eq!( parent_stake_1, 2, @@ -2858,12 +2858,12 @@ fn test_get_stake_for_hotkey_on_subnet_complex_hierarchy() { vec![(u64::MAX, grandchild)] )); - println!("After setting child1's children:"); - println!( + log::info!("After setting child1's children:"); + log::info!( "Child1's children: {:?}", SubtensorModule::get_children(&child1, netuid) ); - println!( + log::info!( "Grandchild's parents: {:?}", SubtensorModule::get_parents(&grandchild, netuid) ); @@ -2873,10 +2873,10 @@ fn test_get_stake_for_hotkey_on_subnet_complex_hierarchy() { let child2_stake_2 = SubtensorModule::get_stake_for_hotkey_on_subnet(&child2, netuid); let grandchild_stake = SubtensorModule::get_stake_for_hotkey_on_subnet(&grandchild, netuid); - println!("Parent stake: {}", parent_stake_2); - println!("Child1 stake: {}", child1_stake_2); - println!("Child2 stake: {}", child2_stake_2); - println!("Grandchild stake: {}", grandchild_stake); + log::info!("Parent stake: {}", parent_stake_2); + log::info!("Child1 stake: {}", child1_stake_2); + log::info!("Child2 stake: {}", child2_stake_2); + log::info!("Grandchild stake: {}", grandchild_stake); assert_eq!(parent_stake_2, 2, "Parent stake should remain 2"); assert_eq!( @@ -2897,24 +2897,24 @@ fn test_get_stake_for_hotkey_on_subnet_complex_hierarchy() { ); // Additional checks - println!("Final parent-child relationships:"); - println!( + log::info!("Final parent-child relationships:"); + log::info!( "Parent's children: {:?}", SubtensorModule::get_children(&parent, netuid) ); - println!( + log::info!( "Child1's parents: {:?}", SubtensorModule::get_parents(&child1, netuid) ); - println!( + log::info!( "Child2's parents: {:?}", SubtensorModule::get_parents(&child2, netuid) ); - println!( + log::info!( "Child1's children: {:?}", SubtensorModule::get_children(&child1, netuid) ); - println!( + log::info!( "Grandchild's parents: {:?}", SubtensorModule::get_parents(&grandchild, netuid) ); @@ -3237,3 +3237,226 @@ fn test_rank_trust_incentive_calculation_with_parent_child() { }); } + +/// Test normal operation of childkey take +/// +/// This test verifies the correct distribution of rewards between child and parents. +/// +/// # Test Steps: +/// 1. Initialize test environment with a child and multiple parents +/// 2. Set childkey take to 9% (4915 when normalized to u16::MAX) +/// 3. Set up network parameters and register all neurons +/// 4. Set initial stakes for all neurons +/// 5. Run an epoch and process emissions +/// 6. Calculate expected reward distribution +/// 7. Compare actual distribution with expected distribution +/// +/// # Expected Results: +/// - Child should keep 9% of the rewards +/// - Remaining 91% should be distributed among parents proportional to their stake +/// - Total distributed rewards should equal total emissions + +/// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test children -- test_normal_childkey_take_operation --exact --nocapture + +// #[test] +// fn test_normal_childkey_take_operation() { +// new_test_ext(1).execute_with(|| { +// let netuid: u16 = 1; +// let num_neurons: u16 = 5; + +// // Create hotkeys and coldkeys +// let child_coldkey = U256::from(100); +// let child_hotkey = U256::from(0); +// let parent_coldkey = U256::from(101); +// let parent_hotkey = U256::from(1); +// let validator_coldkeys: Vec = (102..105).map(U256::from).collect(); +// let validator_hotkeys: Vec = (2..5).map(U256::from).collect(); + +// // Set childkey take to 9% (4915 when normalized to u16::MAX) +// let childkey_take: u16 = 4915; + +// // Set up network parameters and register neurons +// add_network(netuid, num_neurons, 0); +// SubtensorModule::set_max_registrations_per_block(netuid, 1000); +// SubtensorModule::set_target_registrations_per_interval(netuid, 1000); +// SubtensorModule::set_weights_set_rate_limit(netuid, 0); +// SubtensorModule::set_hotkey_emission_tempo(10); + +// register_ok_neuron(netuid, child_hotkey, child_coldkey, 0); +// register_ok_neuron(netuid, parent_hotkey, parent_coldkey, 0); +// for (&hotkey, &coldkey) in validator_hotkeys.iter().zip(validator_coldkeys.iter()) { +// register_ok_neuron(netuid, hotkey, coldkey, 0); +// } + +// // Set initial stakes +// let child_stake: u64 = 1_000_000; +// let parent_stake: u64 = 2_000_000; +// let validator_stakes: Vec = vec![3_000_000, 4_000_000, 5_000_000]; + +// SubtensorModule::add_balance_to_coldkey_account(&child_coldkey, child_stake); +// SubtensorModule::increase_stake_on_coldkey_hotkey_account( +// &child_coldkey, +// &child_hotkey, +// child_stake, +// ); + +// SubtensorModule::add_balance_to_coldkey_account(&parent_coldkey, parent_stake); +// SubtensorModule::increase_stake_on_coldkey_hotkey_account( +// &parent_coldkey, +// &parent_hotkey, +// parent_stake, +// ); + +// for (i, (&hotkey, &coldkey)) in validator_hotkeys +// .iter() +// .zip(validator_coldkeys.iter()) +// .enumerate() +// { +// SubtensorModule::add_balance_to_coldkey_account(&coldkey, validator_stakes[i]); +// SubtensorModule::increase_stake_on_coldkey_hotkey_account( +// &coldkey, +// &hotkey, +// validator_stakes[i], +// ); +// } + +// // Set up parent-child relationship +// assert_ok!(SubtensorModule::do_set_children( +// RuntimeOrigin::signed(parent_coldkey), +// parent_hotkey, +// netuid, +// vec![(u64::MAX, child_hotkey)] +// )); + +// // Set childkey take +// assert_ok!(SubtensorModule::do_set_childkey_take( +// child_coldkey, +// child_hotkey, +// childkey_take, +// netuid +// )); + +// // Set weights +// let all_uids: Vec = (0..num_neurons).collect(); +// let weights: Vec = vec![u16::MAX / num_neurons; num_neurons as usize]; + +// step_block(2); // Step to ensure weights are set + +// for &hotkey in std::iter::once(&parent_hotkey).chain(validator_hotkeys.iter()) { +// assert_ok!(SubtensorModule::set_weights( +// RuntimeOrigin::signed(hotkey), +// netuid, +// all_uids.clone(), +// weights.clone(), +// 0 +// )); +// } + +// // Run epoch and process emissions +// let rao_emission: u64 = 1_000_000_000; +// let emission = SubtensorModule::epoch(netuid, rao_emission); + +// // Store initial stakes +// let initial_stakes: Vec = [child_hotkey, parent_hotkey] +// .iter() +// .chain(validator_hotkeys.iter()) +// .map(|&hotkey| SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey, netuid)) +// .collect(); + +// log::info!("Initial stakes:"); +// log::info!("Child: {}", initial_stakes[0]); +// log::info!("Parent: {}", initial_stakes[1]); +// for (i, &stake) in initial_stakes.iter().skip(2).enumerate() { +// log::info!("Validator {}: {}", i, stake); +// } + +// // Accumulate emissions +// for (hotkey, mining_emission, validator_emission) in emission { +// SubtensorModule::accumulate_hotkey_emission( +// &hotkey, +// netuid, +// validator_emission, +// mining_emission, +// ); +// } + +// // Check pending emissions before distribution +// log::info!("\nPending emissions before distribution:"); +// let pending_emissions: Vec = [child_hotkey, parent_hotkey] +// .iter() +// .chain(validator_hotkeys.iter()) +// .map(|&hotkey| SubtensorModule::get_pending_hotkey_emission(&hotkey)) +// .collect(); + +// log::info!("Child: {}", pending_emissions[0]); +// log::info!("Parent: {}", pending_emissions[1]); +// for (i, &emission) in pending_emissions.iter().skip(2).enumerate() { +// log::info!("Validator {}: {}", i, emission); +// } + +// let total_pending_emission: u64 = pending_emissions.iter().sum(); +// log::info!("Total pending emission: {}", total_pending_emission); + +// log::info!("\nChildkey take: {}", childkey_take); + +// // Step block to trigger emission distribution +// step_block(11); + +// // Calculate actual rewards +// let final_stakes: Vec = [child_hotkey, parent_hotkey] +// .iter() +// .chain(validator_hotkeys.iter()) +// .map(|&hotkey| SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey, netuid)) +// .collect(); + +// let rewards: Vec = final_stakes +// .iter() +// .zip(initial_stakes.iter()) +// .map(|(&final_stake, &initial_stake)| final_stake - initial_stake) +// .collect(); + +// log::info!("\nRewards:"); +// log::info!("Child reward: {}", rewards[0]); +// log::info!("Parent reward: {}", rewards[1]); +// for (i, &reward) in rewards.iter().skip(2).enumerate() { +// log::info!("Validator {} reward: {}", i, reward); +// } + +// // Verify total distributed rewards +// let total_distributed: u64 = rewards.iter().sum(); +// log::info!("\nTotal distributed: {}", total_distributed); +// log::info!("Total emission: {}", total_pending_emission); + +// assert!( +// (total_distributed as i64 - total_pending_emission as i64).abs() <= 10, +// "Total distributed rewards mismatch: distributed {} vs emission {}", +// total_distributed, +// total_pending_emission +// ); + +// // Check that PendingdHotkeyEmission is cleared after distribution +// for &hotkey in [child_hotkey, parent_hotkey] +// .iter() +// .chain(validator_hotkeys.iter()) +// { +// assert_eq!( +// SubtensorModule::get_pending_hotkey_emission(&hotkey), +// 0, +// "Pending emission not cleared for hotkey {:?}", +// hotkey +// ); +// } + +// // Verify childkey take +// let child_reward = rewards[0]; +// let expected_child_reward = +// (total_pending_emission as u128 * childkey_take as u128 / u16::MAX as u128) as u64; +// log::info!("\nExpected child reward: {}", expected_child_reward); +// assert!( +// (child_reward as i64 - expected_child_reward as i64).abs() <= 1, +// "Child reward mismatch: actual {} vs expected {}", +// child_reward, +// expected_child_reward +// ); +// }); +// } From aa1920127852a3966b0041e590126a6c39973adf Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Mon, 19 Aug 2024 07:22:56 +0400 Subject: [PATCH 29/31] chore: make rate limit prettier --- pallets/subtensor/src/staking/set_children.rs | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/pallets/subtensor/src/staking/set_children.rs b/pallets/subtensor/src/staking/set_children.rs index 31bf96f52..ab69c3438 100644 --- a/pallets/subtensor/src/staking/set_children.rs +++ b/pallets/subtensor/src/staking/set_children.rs @@ -246,23 +246,24 @@ impl Pallet { Error::::InvalidChildkeyTake ); - // Check if the rate limit has been exceeded - let current_block = Self::get_current_block_as_u64(); - let last_tx_block = - Self::get_last_transaction_block(&hotkey, netuid, &TransactionType::SetChildkeyTake); - let rate_limit = TxChildkeyTakeRateLimit::::get(); - let passes = - Self::passes_rate_limit_on_subnet(&TransactionType::SetChildkeyTake, &hotkey, netuid); - - log::info!( - "Rate limit check: current_block: {}, last_tx_block: {}, rate_limit: {}, passes: {}", - current_block, - last_tx_block, - rate_limit, - passes + // Ensure the hotkey passes the rate limit. + ensure!( + Self::passes_rate_limit_on_subnet( + &TransactionType::SetChildkeyTake, // Set childkey take. + &hotkey, // Specific to a hotkey. + netuid, // Specific to a subnet. + ), + Error::::TxChildkeyTakeRateLimitExceeded ); - ensure!(passes, Error::::TxChildkeyTakeRateLimitExceeded); + // Set last transaction block + let current_block = Self::get_current_block_as_u64(); + Self::set_last_transaction_block( + &hotkey, + netuid, + &TransactionType::SetChildkeyTake, + current_block + ); // Set the new childkey take value for the given hotkey and network ChildkeyTake::::insert(hotkey.clone(), netuid, take); From c68f4e466e19a2d44d43d72f919f10157f5a5b18 Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Mon, 19 Aug 2024 07:23:07 +0400 Subject: [PATCH 30/31] chore: remove commented test --- pallets/subtensor/tests/children.rs | 222 ---------------------------- 1 file changed, 222 deletions(-) diff --git a/pallets/subtensor/tests/children.rs b/pallets/subtensor/tests/children.rs index f66c88441..e5b5d080c 100644 --- a/pallets/subtensor/tests/children.rs +++ b/pallets/subtensor/tests/children.rs @@ -3238,225 +3238,3 @@ fn test_rank_trust_incentive_calculation_with_parent_child() { }); } -/// Test normal operation of childkey take -/// -/// This test verifies the correct distribution of rewards between child and parents. -/// -/// # Test Steps: -/// 1. Initialize test environment with a child and multiple parents -/// 2. Set childkey take to 9% (4915 when normalized to u16::MAX) -/// 3. Set up network parameters and register all neurons -/// 4. Set initial stakes for all neurons -/// 5. Run an epoch and process emissions -/// 6. Calculate expected reward distribution -/// 7. Compare actual distribution with expected distribution -/// -/// # Expected Results: -/// - Child should keep 9% of the rewards -/// - Remaining 91% should be distributed among parents proportional to their stake -/// - Total distributed rewards should equal total emissions - -/// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --test children -- test_normal_childkey_take_operation --exact --nocapture - -// #[test] -// fn test_normal_childkey_take_operation() { -// new_test_ext(1).execute_with(|| { -// let netuid: u16 = 1; -// let num_neurons: u16 = 5; - -// // Create hotkeys and coldkeys -// let child_coldkey = U256::from(100); -// let child_hotkey = U256::from(0); -// let parent_coldkey = U256::from(101); -// let parent_hotkey = U256::from(1); -// let validator_coldkeys: Vec = (102..105).map(U256::from).collect(); -// let validator_hotkeys: Vec = (2..5).map(U256::from).collect(); - -// // Set childkey take to 9% (4915 when normalized to u16::MAX) -// let childkey_take: u16 = 4915; - -// // Set up network parameters and register neurons -// add_network(netuid, num_neurons, 0); -// SubtensorModule::set_max_registrations_per_block(netuid, 1000); -// SubtensorModule::set_target_registrations_per_interval(netuid, 1000); -// SubtensorModule::set_weights_set_rate_limit(netuid, 0); -// SubtensorModule::set_hotkey_emission_tempo(10); - -// register_ok_neuron(netuid, child_hotkey, child_coldkey, 0); -// register_ok_neuron(netuid, parent_hotkey, parent_coldkey, 0); -// for (&hotkey, &coldkey) in validator_hotkeys.iter().zip(validator_coldkeys.iter()) { -// register_ok_neuron(netuid, hotkey, coldkey, 0); -// } - -// // Set initial stakes -// let child_stake: u64 = 1_000_000; -// let parent_stake: u64 = 2_000_000; -// let validator_stakes: Vec = vec![3_000_000, 4_000_000, 5_000_000]; - -// SubtensorModule::add_balance_to_coldkey_account(&child_coldkey, child_stake); -// SubtensorModule::increase_stake_on_coldkey_hotkey_account( -// &child_coldkey, -// &child_hotkey, -// child_stake, -// ); - -// SubtensorModule::add_balance_to_coldkey_account(&parent_coldkey, parent_stake); -// SubtensorModule::increase_stake_on_coldkey_hotkey_account( -// &parent_coldkey, -// &parent_hotkey, -// parent_stake, -// ); - -// for (i, (&hotkey, &coldkey)) in validator_hotkeys -// .iter() -// .zip(validator_coldkeys.iter()) -// .enumerate() -// { -// SubtensorModule::add_balance_to_coldkey_account(&coldkey, validator_stakes[i]); -// SubtensorModule::increase_stake_on_coldkey_hotkey_account( -// &coldkey, -// &hotkey, -// validator_stakes[i], -// ); -// } - -// // Set up parent-child relationship -// assert_ok!(SubtensorModule::do_set_children( -// RuntimeOrigin::signed(parent_coldkey), -// parent_hotkey, -// netuid, -// vec![(u64::MAX, child_hotkey)] -// )); - -// // Set childkey take -// assert_ok!(SubtensorModule::do_set_childkey_take( -// child_coldkey, -// child_hotkey, -// childkey_take, -// netuid -// )); - -// // Set weights -// let all_uids: Vec = (0..num_neurons).collect(); -// let weights: Vec = vec![u16::MAX / num_neurons; num_neurons as usize]; - -// step_block(2); // Step to ensure weights are set - -// for &hotkey in std::iter::once(&parent_hotkey).chain(validator_hotkeys.iter()) { -// assert_ok!(SubtensorModule::set_weights( -// RuntimeOrigin::signed(hotkey), -// netuid, -// all_uids.clone(), -// weights.clone(), -// 0 -// )); -// } - -// // Run epoch and process emissions -// let rao_emission: u64 = 1_000_000_000; -// let emission = SubtensorModule::epoch(netuid, rao_emission); - -// // Store initial stakes -// let initial_stakes: Vec = [child_hotkey, parent_hotkey] -// .iter() -// .chain(validator_hotkeys.iter()) -// .map(|&hotkey| SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey, netuid)) -// .collect(); - -// log::info!("Initial stakes:"); -// log::info!("Child: {}", initial_stakes[0]); -// log::info!("Parent: {}", initial_stakes[1]); -// for (i, &stake) in initial_stakes.iter().skip(2).enumerate() { -// log::info!("Validator {}: {}", i, stake); -// } - -// // Accumulate emissions -// for (hotkey, mining_emission, validator_emission) in emission { -// SubtensorModule::accumulate_hotkey_emission( -// &hotkey, -// netuid, -// validator_emission, -// mining_emission, -// ); -// } - -// // Check pending emissions before distribution -// log::info!("\nPending emissions before distribution:"); -// let pending_emissions: Vec = [child_hotkey, parent_hotkey] -// .iter() -// .chain(validator_hotkeys.iter()) -// .map(|&hotkey| SubtensorModule::get_pending_hotkey_emission(&hotkey)) -// .collect(); - -// log::info!("Child: {}", pending_emissions[0]); -// log::info!("Parent: {}", pending_emissions[1]); -// for (i, &emission) in pending_emissions.iter().skip(2).enumerate() { -// log::info!("Validator {}: {}", i, emission); -// } - -// let total_pending_emission: u64 = pending_emissions.iter().sum(); -// log::info!("Total pending emission: {}", total_pending_emission); - -// log::info!("\nChildkey take: {}", childkey_take); - -// // Step block to trigger emission distribution -// step_block(11); - -// // Calculate actual rewards -// let final_stakes: Vec = [child_hotkey, parent_hotkey] -// .iter() -// .chain(validator_hotkeys.iter()) -// .map(|&hotkey| SubtensorModule::get_stake_for_hotkey_on_subnet(&hotkey, netuid)) -// .collect(); - -// let rewards: Vec = final_stakes -// .iter() -// .zip(initial_stakes.iter()) -// .map(|(&final_stake, &initial_stake)| final_stake - initial_stake) -// .collect(); - -// log::info!("\nRewards:"); -// log::info!("Child reward: {}", rewards[0]); -// log::info!("Parent reward: {}", rewards[1]); -// for (i, &reward) in rewards.iter().skip(2).enumerate() { -// log::info!("Validator {} reward: {}", i, reward); -// } - -// // Verify total distributed rewards -// let total_distributed: u64 = rewards.iter().sum(); -// log::info!("\nTotal distributed: {}", total_distributed); -// log::info!("Total emission: {}", total_pending_emission); - -// assert!( -// (total_distributed as i64 - total_pending_emission as i64).abs() <= 10, -// "Total distributed rewards mismatch: distributed {} vs emission {}", -// total_distributed, -// total_pending_emission -// ); - -// // Check that PendingdHotkeyEmission is cleared after distribution -// for &hotkey in [child_hotkey, parent_hotkey] -// .iter() -// .chain(validator_hotkeys.iter()) -// { -// assert_eq!( -// SubtensorModule::get_pending_hotkey_emission(&hotkey), -// 0, -// "Pending emission not cleared for hotkey {:?}", -// hotkey -// ); -// } - -// // Verify childkey take -// let child_reward = rewards[0]; -// let expected_child_reward = -// (total_pending_emission as u128 * childkey_take as u128 / u16::MAX as u128) as u64; -// log::info!("\nExpected child reward: {}", expected_child_reward); -// assert!( -// (child_reward as i64 - expected_child_reward as i64).abs() <= 1, -// "Child reward mismatch: actual {} vs expected {}", -// child_reward, -// expected_child_reward -// ); -// }); -// } From dc67f8fbfd0d4fb7035adc1d1e80408283d44d9e Mon Sep 17 00:00:00 2001 From: Samuel Dare Date: Mon, 19 Aug 2024 07:28:41 +0400 Subject: [PATCH 31/31] chore: fmt --- pallets/subtensor/src/staking/set_children.rs | 4 ++-- pallets/subtensor/tests/children.rs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/pallets/subtensor/src/staking/set_children.rs b/pallets/subtensor/src/staking/set_children.rs index ab69c3438..9029d58ca 100644 --- a/pallets/subtensor/src/staking/set_children.rs +++ b/pallets/subtensor/src/staking/set_children.rs @@ -74,7 +74,7 @@ impl Pallet { &hotkey, netuid, &TransactionType::SetChildren, - current_block + current_block, ); // --- 2. Check that this delegation is not on the root network. Child hotkeys are not valid on root. @@ -262,7 +262,7 @@ impl Pallet { &hotkey, netuid, &TransactionType::SetChildkeyTake, - current_block + current_block, ); // Set the new childkey take value for the given hotkey and network diff --git a/pallets/subtensor/tests/children.rs b/pallets/subtensor/tests/children.rs index e5b5d080c..f36c21521 100644 --- a/pallets/subtensor/tests/children.rs +++ b/pallets/subtensor/tests/children.rs @@ -3237,4 +3237,3 @@ fn test_rank_trust_incentive_calculation_with_parent_child() { }); } -