From 4fac11ea5bc57633120f178e5f85120d00fecc51 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 15 Apr 2024 16:31:13 -0700 Subject: [PATCH 1/7] add test set_root_weights --- pallets/subtensor/src/lib.rs | 90 ++++++++++++++++++++++ pallets/subtensor/src/root.rs | 129 ++++++++++++++++++++++++++++++++ pallets/subtensor/tests/root.rs | 59 +++++++++++++-- 3 files changed, 270 insertions(+), 8 deletions(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index f9c05eba35..07e5904e29 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -968,6 +968,7 @@ pub mod pallet { StakeTooLowForRoot, // --- Thrown when a hotkey attempts to join the root subnet with too little stake AllNetworksInImmunity, // --- Thrown when all subnets are in the immunity period NotEnoughBalance, + NotRootSubnet, } // ================== @@ -1277,6 +1278,83 @@ pub mod pallet { Self::do_set_weights(origin, netuid, dests, weights, version_key) } + // # Args: + // * `origin`: (Origin): + // - The caller, a hotkey who wishes to set their weights. + // + // * `netuid` (u16): + // - The network uid we are setting these weights on. + // + // * `hotkey` (T::AccountId): + // - The hotkey associated with the operation and the calling coldkey. + // + // * `dests` (Vec): + // - The edge endpoint for the weight, i.e. j for w_ij. + // + // * 'weights' (Vec): + // - The u16 integer encoded weights. Interpreted as rational + // values in the range [0,1]. They must sum to in32::MAX. + // + // * 'version_key' ( u64 ): + // - The network version key to check if the validator is up to date. + // + // # Event: + // * 'WeightVecNotEqualSize': + // - Attempting to set weights with uids not of same length. + // + // * WeightsSet; + // - On successfully setting the weights on chain. + // + // # Raises: + // + // * NonAssociatedColdKey; + // - Attempting to set weights on a non-associated cold key. + // + // * 'NetworkDoesNotExist': + // - Attempting to set weights on a non-existent network. + // + // * 'NotRootSubnet': + // - Attempting to set weights on a subnet that is not the root network. + // + // * 'WeightVecNotEqualSize': + // - Attempting to set weights with uids not of same length. + // + // * 'InvalidUid': + // - Attempting to set weights with invalid uids. + // + // * 'NotRegistered': + // - Attempting to set weights from a non registered account. + // + // * 'NotSettingEnoughWeights': + // - Attempting to set weights with fewer weights than min. + // + // * 'IncorrectNetworkVersionKey': + // - Attempting to set weights with the incorrect network version key. + // + // * 'SettingWeightsTooFast': + // - Attempting to set weights too fast. + // + // * 'NotSettingEnoughWeights': + // - Attempting to set weights with fewer weights than min. + // + // * 'MaxWeightExceeded': + // - Attempting to set weights with max value exceeding limit. + // + #[pallet::call_index(8)] + #[pallet::weight((Weight::from_parts(10_151_000_000, 0) + .saturating_add(T::DbWeight::get().reads(4104)) + .saturating_add(T::DbWeight::get().writes(2)), DispatchClass::Normal, Pays::No))] + pub fn set_root_weights( + origin: OriginFor, + netuid: u16, + hotkey: T::AccountId, + dests: Vec, + weights: Vec, + version_key: u64, + ) -> DispatchResult { + Self::do_set_root_weights(origin, netuid, hotkey, dests, weights, version_key) + } + // --- Sets the key as a delegate. // // # Args: @@ -1845,6 +1923,18 @@ where return Err(InvalidTransaction::Call.into()); } } + Some(Call::set_root_weights { netuid, .. }) => { + if Self::check_weights_min_stake(who) { + let priority: u64 = Self::get_priority_set_weights(who, *netuid); + Ok(ValidTransaction { + priority: priority, + longevity: 1, + ..Default::default() + }) + } else { + return Err(InvalidTransaction::Call.into()); + } + } Some(Call::add_stake { hotkey, .. }) => { let stakes_this_interval = Pallet::::get_stakes_this_interval_for_hotkey(hotkey); let max_stakes_per_interval = Pallet::::get_target_stakes_per_interval(); diff --git a/pallets/subtensor/src/root.rs b/pallets/subtensor/src/root.rs index 6393fce63e..f850af7c6a 100644 --- a/pallets/subtensor/src/root.rs +++ b/pallets/subtensor/src/root.rs @@ -577,6 +577,135 @@ impl Pallet { Ok(()) } + pub fn do_set_root_weights( + origin: T::RuntimeOrigin, + netuid: u16, + hotkey: T::AccountId, + uids: Vec, + values: Vec, + version_key: u64, + ) -> dispatch::DispatchResult { + // --- 1. Check the caller's signature. This is the coldkey of a registered account. + let coldkey = ensure_signed(origin)?; + log::info!( + "do_set_root_weights( origin:{:?} netuid:{:?}, uids:{:?}, values:{:?})", + coldkey, + netuid, + uids, + values + ); + + // --- 2. Check that the signer coldkey owns the hotkey + ensure!( + Self::coldkey_owns_hotkey(&coldkey, &hotkey) + && Self::get_owning_coldkey_for_hotkey(&hotkey) == coldkey, + Error::::NonAssociatedColdKey + ); + + // --- 3. Check to see if this is a valid network. + ensure!( + Self::if_subnet_exist(netuid), + Error::::NetworkDoesNotExist + ); + + // --- 4. Check that this is the root network. + ensure!( + netuid == Self::get_root_netuid(), + Error::::NotRootSubnet + ); + + // --- 5. Check that the length of uid list and value list are equal for this network. + ensure!( + Self::uids_match_values(&uids, &values), + Error::::WeightVecNotEqualSize + ); + + // --- 6. Check to see if the number of uids is within the max allowed uids for this network. + // For the root network this number is the number of subnets. + ensure!( + !Self::contains_invalid_root_uids(&uids), + Error::::InvalidUid + ); + + // --- 7. Check to see if the hotkey is registered to the passed network. + ensure!( + Self::is_hotkey_registered_on_network(netuid, &hotkey), + Error::::NotRegistered + ); + + // --- 8. Check to see if the hotkey has enough stake to set weights. + ensure!( + Self::get_total_stake_for_hotkey(&hotkey) >= Self::get_weights_min_stake(), + Error::::NotEnoughStakeToSetWeights + ); + + // --- 9. Ensure version_key is up-to-date. + ensure!( + Self::check_version_key(netuid, version_key), + Error::::IncorrectNetworkVersionKey + ); + + // --- 10. Get the neuron uid of associated hotkey on network netuid. + let neuron_uid; + let net_neuron_uid = Self::get_uid_for_net_and_hotkey(netuid, &hotkey); + ensure!( + net_neuron_uid.is_ok(), + net_neuron_uid + .err() + .unwrap_or(Error::::NotRegistered.into()) + ); + + neuron_uid = net_neuron_uid.unwrap(); + + // --- 11. Ensure the uid is not setting weights faster than the weights_set_rate_limit. + let current_block: u64 = Self::get_current_block_as_u64(); + ensure!( + Self::check_rate_limit(netuid, neuron_uid, current_block), + Error::::SettingWeightsTooFast + ); + + // --- 12. Ensure the passed uids contain no duplicates. + ensure!(!Self::has_duplicate_uids(&uids), Error::::DuplicateUids); + + // --- 13. Ensure that the weights have the required length. + ensure!( + Self::check_length(netuid, neuron_uid, &uids, &values), + Error::::NotSettingEnoughWeights + ); + + // --- 14. Max-upscale the weights. + let max_upscaled_weights: Vec = vec_u16_max_upscale_to_u16(&values); + + // --- 15. Ensure the weights are max weight limited + ensure!( + Self::max_weight_limited(netuid, neuron_uid, &uids, &max_upscaled_weights), + Error::::MaxWeightExceeded + ); + + // --- 16. Zip weights for sinking to storage map. + let mut zipped_weights: Vec<(u16, u16)> = vec![]; + for (uid, val) in uids.iter().zip(max_upscaled_weights.iter()) { + zipped_weights.push((*uid, *val)) + } + + // --- 17. Set weights under netuid, uid double map entry. + Weights::::insert(netuid, neuron_uid, zipped_weights); + + // --- 18. Set the activity for the weights on this network. + Self::set_last_update_for_uid(netuid, neuron_uid, current_block); + + // --- 19. Emit the tracking event. + log::info!( + "RootWeightsSet( netuid:{:?}, neuron_uid:{:?} )", + netuid, + neuron_uid + ); + Self::deposit_event(Event::WeightsSet(netuid, neuron_uid)); + + // --- 20. Return ok. + Ok(()) + } + pub fn do_vote_root( origin: T::RuntimeOrigin, hotkey: &T::AccountId, diff --git a/pallets/subtensor/tests/root.rs b/pallets/subtensor/tests/root.rs index c5fa9d84a4..d3320afe33 100644 --- a/pallets/subtensor/tests/root.rs +++ b/pallets/subtensor/tests/root.rs @@ -1,5 +1,5 @@ use crate::mock::*; -use frame_support::assert_ok; +use frame_support::{assert_err, assert_ok}; use frame_system::Config; use frame_system::{EventRecord, Phase}; use pallet_subtensor::migration; @@ -175,7 +175,7 @@ fn test_root_set_weights() { SubtensorModule::set_max_allowed_uids(root_netuid, n as u16); for i in 0..n { let hotkey_account_id: U256 = U256::from(i); - let coldkey_account_id: U256 = U256::from(i); + let coldkey_account_id: U256 = U256::from(i + 456); SubtensorModule::add_balance_to_coldkey_account( &coldkey_account_id, 1_000_000_000_000_000, @@ -201,17 +201,57 @@ fn test_root_set_weights() { for netuid in 1..n { log::debug!("Adding network with netuid: {}", netuid); assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(U256::from(netuid)) + <::RuntimeOrigin>::signed(U256::from(netuid + 456)) )); } + // Test that signing with hotkey will fail. + for i in 0..n { + let hotkey = U256::from(i); + let uids: Vec = vec![i as u16]; + let values: Vec = vec![1]; + assert_err!( + SubtensorModule::set_root_weights( + <::RuntimeOrigin>::signed(hotkey), + root_netuid, + hotkey, + uids, + values, + 0, + ), + Error::::NonAssociatedColdKey + ); + } + + // Test that signing an unassociated coldkey will fail. + let unassociated_coldkey = U256::from(612); + for i in 0..n { + let hotkey = U256::from(i); + let uids: Vec = vec![i as u16]; + let values: Vec = vec![1]; + assert_err!( + SubtensorModule::set_root_weights( + <::RuntimeOrigin>::signed(unassociated_coldkey), + root_netuid, + hotkey, + uids, + values, + 0, + ), + Error::::NonAssociatedColdKey + ); + } + // Set weights into diagonal matrix. for i in 0..n { + let hotkey = U256::from(i); + let coldkey = U256::from(i + 456); let uids: Vec = vec![i as u16]; let values: Vec = vec![1]; - assert_ok!(SubtensorModule::set_weights( - <::RuntimeOrigin>::signed(U256::from(i)), + assert_ok!(SubtensorModule::set_root_weights( + <::RuntimeOrigin>::signed(coldkey), root_netuid, + hotkey, uids, values, 0, @@ -322,11 +362,14 @@ fn test_root_set_weights_out_of_order_netuids() { // Set weights into diagonal matrix. for (i, netuid) in subnets.iter().enumerate() { let uids: Vec = vec![*netuid]; - let values: Vec = vec![1]; - assert_ok!(SubtensorModule::set_weights( - <::RuntimeOrigin>::signed(U256::from(i)), + + let coldkey = U256::from(i); + let hotkey = U256::from(i); + assert_ok!(SubtensorModule::set_root_weights( + <::RuntimeOrigin>::signed(coldkey), root_netuid, + hotkey, uids, values, 0, From 15c671ab1191916859c76afc5dd24a79c5f5fdd1 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:31:05 -0700 Subject: [PATCH 2/7] cargo fmt --- pallets/subtensor/src/lib.rs | 1 - pallets/subtensor/src/root.rs | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 6f74633896..262296b919 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -987,7 +987,6 @@ pub mod pallet { NoNeuronIdAvailable, // -- Thrown when no neuron id is available /// Thrown a stake would be below the minimum threshold for nominator validations NomStakeBelowMinimumThreshold, - } // ================== diff --git a/pallets/subtensor/src/root.rs b/pallets/subtensor/src/root.rs index bd7f8c32c1..ebd716c82c 100644 --- a/pallets/subtensor/src/root.rs +++ b/pallets/subtensor/src/root.rs @@ -605,10 +605,7 @@ impl Pallet { ); // --- 4. Check that this is the root network. - ensure!( - netuid == Self::get_root_netuid(), - Error::::NotRootSubnet - ); + ensure!(netuid == Self::get_root_netuid(), Error::::NotRootSubnet); // --- 5. Check that the length of uid list and value list are equal for this network. ensure!( From a49315d4170dbf9819597560c6ce0875c38675af Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:47:17 -0700 Subject: [PATCH 3/7] fix comment --- pallets/subtensor/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 262296b919..6544415507 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1317,8 +1317,6 @@ pub mod pallet { // - The network version key to check if the validator is up to date. // // # Event: - // * 'WeightVecNotEqualSize': - // - Attempting to set weights with uids not of same length. // // * WeightsSet; // - On successfully setting the weights on chain. From 00508fd7dd2fd84ca4207489cec5ca82d6507a07 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Tue, 30 Apr 2024 10:33:23 -0700 Subject: [PATCH 4/7] reject root from set_weights --- pallets/subtensor/src/lib.rs | 1 + pallets/subtensor/src/weights.rs | 39 ++++++++++++-------------------- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 6544415507..61d5d785d9 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -984,6 +984,7 @@ pub mod pallet { AllNetworksInImmunity, // --- Thrown when all subnets are in the immunity period NotEnoughBalance, NotRootSubnet, + IsRoot, NoNeuronIdAvailable, // -- Thrown when no neuron id is available /// Thrown a stake would be below the minimum threshold for nominator validations NomStakeBelowMinimumThreshold, diff --git a/pallets/subtensor/src/weights.rs b/pallets/subtensor/src/weights.rs index 6969a3a674..524ee75da0 100644 --- a/pallets/subtensor/src/weights.rs +++ b/pallets/subtensor/src/weights.rs @@ -76,6 +76,8 @@ impl Pallet { values ); + ensure!(netuid != Self::get_root_netuid(), Error::::IsRoot); + // --- 2. Check that the length of uid list and value list are equal for this network. ensure!( Self::uids_match_values(&uids, &values), @@ -89,19 +91,10 @@ impl Pallet { ); // --- 4. Check to see if the number of uids is within the max allowed uids for this network. - // For the root network this number is the number of subnets. - if netuid == Self::get_root_netuid() { - // --- 4.a. Ensure that the passed uids are valid for the network. - ensure!( - !Self::contains_invalid_root_uids(&uids), - Error::::InvalidUid - ); - } else { - ensure!( - Self::check_len_uids_within_allowed(netuid, &uids), - Error::::TooManyUids - ); - } + ensure!( + Self::check_len_uids_within_allowed(netuid, &uids), + Error::::TooManyUids + ); // --- 5. Check to see if the hotkey is registered to the passed network. ensure!( @@ -141,23 +134,19 @@ impl Pallet { ); // --- 10. Check that the neuron uid is an allowed validator permitted to set non-self weights. - if netuid != Self::get_root_netuid() { - ensure!( - Self::check_validator_permit(netuid, neuron_uid, &uids, &values), - Error::::NoValidatorPermit - ); - } + ensure!( + Self::check_validator_permit(netuid, neuron_uid, &uids, &values), + Error::::NoValidatorPermit + ); // --- 11. Ensure the passed uids contain no duplicates. ensure!(!Self::has_duplicate_uids(&uids), Error::::DuplicateUids); // --- 12. Ensure that the passed uids are valid for the network. - if netuid != Self::get_root_netuid() { - ensure!( - !Self::contains_invalid_uids(netuid, &uids), - Error::::InvalidUid - ); - } + ensure!( + !Self::contains_invalid_uids(netuid, &uids), + Error::::InvalidUid + ); // --- 13. Ensure that the weights have the required length. ensure!( From 12a8941d9e5a5b0d44aaba8dbed4422ed930c0b0 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Tue, 30 Apr 2024 10:33:33 -0700 Subject: [PATCH 5/7] add tests --- pallets/subtensor/tests/root.rs | 38 ++++++++++++++++++++++++++---- pallets/subtensor/tests/weights.rs | 25 +++++++++++++++++++- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/pallets/subtensor/tests/root.rs b/pallets/subtensor/tests/root.rs index 82ce2d03dc..02b0458929 100644 --- a/pallets/subtensor/tests/root.rs +++ b/pallets/subtensor/tests/root.rs @@ -30,6 +30,34 @@ fn test_root_register_network_exist() { }); } +#[test] +fn test_set_weights_not_root_error() { + new_test_ext(0).execute_with(|| { + let netuid: u16 = 1; + + let dests = vec![0]; + let weights = vec![1]; + let version_key: u64 = 0; + let hotkey = U256::from(1); + let coldkey = U256::from(2); + + add_network(netuid, 0, 0); + register_ok_neuron(netuid, hotkey, coldkey, 2143124); + + assert_err!( + SubtensorModule::set_root_weights( + RuntimeOrigin::signed(coldkey), + netuid, + hotkey, + dests.clone(), + weights.clone(), + version_key, + ), + Error::::NotRootSubnet + ); + }); +} + #[test] fn test_root_register_normal_on_root_fails() { new_test_ext(1).execute_with(|| { @@ -546,9 +574,10 @@ fn test_network_pruning() { &hot )); assert!(SubtensorModule::get_uid_for_net_and_hotkey(root_netuid, &hot).is_ok()); - assert_ok!(SubtensorModule::set_weights( - <::RuntimeOrigin>::signed(hot), + assert_ok!(SubtensorModule::set_root_weights( + <::RuntimeOrigin>::signed(cold), root_netuid, + hot, uids, values, 0 @@ -679,9 +708,10 @@ fn test_weights_after_network_pruning() { log::info!("uids set: {:?}", uids); log::info!("values set: {:?}", values); log::info!("In netuid: {:?}", root_netuid); - assert_ok!(SubtensorModule::set_weights( - <::RuntimeOrigin>::signed(hot), + assert_ok!(SubtensorModule::set_root_weights( + <::RuntimeOrigin>::signed(cold), root_netuid, + hot, uids, values, 0 diff --git a/pallets/subtensor/tests/weights.rs b/pallets/subtensor/tests/weights.rs index c1467abda4..3d7673982e 100644 --- a/pallets/subtensor/tests/weights.rs +++ b/pallets/subtensor/tests/weights.rs @@ -1,6 +1,6 @@ mod mock; use frame_support::{ - assert_ok, + assert_err, assert_ok, dispatch::{DispatchClass, GetDispatchInfo, Pays}, }; use mock::*; @@ -35,6 +35,29 @@ fn test_set_weights_dispatch_info_ok() { }); } +#[test] +fn test_set_weights_is_root_error() { + new_test_ext(0).execute_with(|| { + let root_netuid: u16 = 0; + + let dests = vec![0]; + let weights = vec![1]; + let version_key: u64 = 0; + let hotkey = U256::from(1); + + assert_err!( + SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey), + root_netuid, + dests.clone(), + weights.clone(), + version_key, + ), + Error::::IsRoot + ); + }); +} + // Test ensures that uid has validator permit to set non-self weights. #[test] fn test_weights_err_no_validator_permit() { From dd1a596bb72b07ffb5714eb7b01409a762f4137a Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Tue, 30 Apr 2024 10:54:10 -0700 Subject: [PATCH 6/7] add comment --- pallets/subtensor/src/weights.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/pallets/subtensor/src/weights.rs b/pallets/subtensor/src/weights.rs index 524ee75da0..a14e8dad15 100644 --- a/pallets/subtensor/src/weights.rs +++ b/pallets/subtensor/src/weights.rs @@ -76,6 +76,7 @@ impl Pallet { values ); + // --- Check that the netuid is not the root network. ensure!(netuid != Self::get_root_netuid(), Error::::IsRoot); // --- 2. Check that the length of uid list and value list are equal for this network. From 3b9e53e0c882ca388a2d325048f6fb7f121d8781 Mon Sep 17 00:00:00 2001 From: John Reed <87283488+JohnReedV@users.noreply.github.com> Date: Tue, 30 Apr 2024 12:03:31 -0700 Subject: [PATCH 7/7] resolve merge conflict correctly --- pallets/subtensor/src/root.rs | 11 +---------- pallets/subtensor/src/weights.rs | 13 +------------ 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/pallets/subtensor/src/root.rs b/pallets/subtensor/src/root.rs index ebd716c82c..1c308d9c60 100644 --- a/pallets/subtensor/src/root.rs +++ b/pallets/subtensor/src/root.rs @@ -639,16 +639,7 @@ impl Pallet { ); // --- 10. Get the neuron uid of associated hotkey on network netuid. - let neuron_uid; - let net_neuron_uid = Self::get_uid_for_net_and_hotkey(netuid, &hotkey); - ensure!( - net_neuron_uid.is_ok(), - net_neuron_uid - .err() - .unwrap_or(Error::::NotRegistered.into()) - ); - - neuron_uid = net_neuron_uid.unwrap(); + let neuron_uid = Self::get_uid_for_net_and_hotkey(netuid, &hotkey)?; // --- 11. Ensure the uid is not setting weights faster than the weights_set_rate_limit. let current_block: u64 = Self::get_current_block_as_u64(); diff --git a/pallets/subtensor/src/weights.rs b/pallets/subtensor/src/weights.rs index a14e8dad15..6bf91dcc8a 100644 --- a/pallets/subtensor/src/weights.rs +++ b/pallets/subtensor/src/weights.rs @@ -115,19 +115,8 @@ impl Pallet { Error::::IncorrectNetworkVersionKey ); - // --- 9. Get the neuron uid of associated hotkey on network netuid. - - let net_neuron_uid = Self::get_uid_for_net_and_hotkey(netuid, &hotkey); - ensure!( - net_neuron_uid.is_ok(), - net_neuron_uid - .err() - .unwrap_or(Error::::NotRegistered.into()) - ); - - let neuron_uid = net_neuron_uid.unwrap(); - // --- 9. Ensure the uid is not setting weights faster than the weights_set_rate_limit. + let neuron_uid = Self::get_uid_for_net_and_hotkey(netuid, &hotkey)?; let current_block: u64 = Self::get_current_block_as_u64(); ensure!( Self::check_rate_limit(netuid, neuron_uid, current_block),