diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index 1cec11514..b45eefde5 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -8,6 +8,8 @@ use frame_benchmarking::{account, benchmarks, whitelisted_caller}; use frame_support::assert_ok; use frame_system::RawOrigin; pub use pallet::*; +use sp_core::H256; +use sp_runtime::traits::{BlakeTwo256, Hash}; use sp_std::vec; benchmarks! { @@ -333,4 +335,89 @@ benchmarks! { assert_ok!(Subtensor::::add_stake(RawOrigin::Signed(coldkey).into(), old_hotkey.clone(), 1_000_000_000)); } }: _(RawOrigin::Signed(coldkey), old_hotkey, new_hotkey) + + commit_weights { + let tempo: u16 = 1; + let netuid: u16 = 1; + let version_key: u64 = 0; + let uids: Vec = vec![0]; + let weight_values: Vec = vec![10]; + let hotkey: T::AccountId = account("hot", 0, 1); + let coldkey: T::AccountId = account("cold", 0, 2); + let start_nonce = 300000; + + let commit_hash: H256 = BlakeTwo256::hash_of(&( + hotkey.clone(), + netuid, + uids.clone(), + weight_values.clone(), + version_key, + )); + + Subtensor::::init_new_network(netuid, tempo); + + let block_number: u64 = Subtensor::::get_current_block_as_u64(); + let (nonce, work): (u64, Vec) = Subtensor::::create_work_for_block_number( + netuid, + block_number, + start_nonce, + &hotkey, + ); + let result = Subtensor::::register( + ::RuntimeOrigin::from(RawOrigin::Signed(hotkey.clone())), + netuid, + block_number, + nonce, + work, + hotkey.clone(), + coldkey, + ); + Subtensor::::set_validator_permit_for_uid(netuid, 0, true); + +}: commit_weights(RawOrigin::Signed(hotkey.clone()), netuid, commit_hash) + +reveal_weights { + let tempo: u16 = 0; + let netuid: u16 = 1; + let version_key: u64 = 0; + let uids: Vec = vec![0]; + let weight_values: Vec = vec![10]; + let hotkey: T::AccountId = account("hot", 0, 1); + let coldkey: T::AccountId = account("cold", 1, 2); + + Subtensor::::init_new_network(netuid, tempo); + Subtensor::::set_network_registration_allowed(netuid, true); + Subtensor::::set_network_pow_registration_allowed(netuid, true); + + let block_number: u64 = Subtensor::::get_current_block_as_u64(); + let (nonce, work): (u64, Vec) = Subtensor::::create_work_for_block_number( + netuid, + block_number, + 3, + &hotkey, + ); + + let _ = Subtensor::::register( + ::RuntimeOrigin::from(RawOrigin::Signed(hotkey.clone())), + netuid, + block_number, + nonce, + work.clone(), + hotkey.clone(), + coldkey.clone(), + ); + + Subtensor::::set_validator_permit_for_uid(netuid, 0, true); + Subtensor::::set_weight_commit_interval(0); + + let commit_hash: H256 = BlakeTwo256::hash_of(&( + hotkey.clone(), + netuid, + uids.clone(), + weight_values.clone(), + version_key, + )); + let _ = Subtensor::::commit_weights(::RuntimeOrigin::from(RawOrigin::Signed(hotkey.clone())), netuid, commit_hash); + + }: reveal_weights(RawOrigin::Signed(hotkey.clone()), netuid, uids, weight_values, version_key) } diff --git a/pallets/subtensor/src/errors.rs b/pallets/subtensor/src/errors.rs index 9b703255b..57b190b93 100644 --- a/pallets/subtensor/src/errors.rs +++ b/pallets/subtensor/src/errors.rs @@ -132,5 +132,13 @@ mod errors { NomStakeBelowMinimumThreshold, /// delegate take is being set out of bounds InvalidTake, + /// Not allowed to commit weights + CommitNotAllowed, + /// No commit found for provided hotkey+netuid when attempting to reveal weights + NoCommitFound, + /// Not the correct block/range to reveal weights + InvalidRevealTempo, + /// Committed hash does not equal the hashed reveal data + InvalidReveal, } } diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 3df94368a..c5be7a8a7 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -68,6 +68,7 @@ pub mod pallet { traits::{tokens::fungible, UnfilteredDispatchable}, }; use frame_system::pallet_prelude::*; + use sp_core::H256; use sp_runtime::traits::TrailingZeroInput; use sp_std::vec; use sp_std::vec::Vec; @@ -786,6 +787,27 @@ pub mod pallet { pub type AdjustmentAlpha = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultAdjustmentAlpha>; + // --- MAP (netuid, who) --> (hash, weight) | Returns the hash and weight committed by an account for a given netuid. + #[pallet::storage] + pub type WeightCommits = StorageDoubleMap< + _, + Twox64Concat, + u16, + Twox64Concat, + T::AccountId, + (H256, u64), + OptionQuery, + >; + + #[pallet::type_value] + pub fn DefaultWeightCommitRevealInterval() -> u64 { + 1000 + } + + #[pallet::storage] + pub type WeightCommitRevealInterval = + StorageValue<_, u64, ValueQuery, DefaultWeightCommitRevealInterval>; + // ======================================= // ==== Subnetwork Consensus Storage ==== // ======================================= @@ -1184,8 +1206,8 @@ pub mod pallet { // - Attempting to set weights with max value exceeding limit. #[pallet::call_index(0)] #[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))] + .saturating_add(T::DbWeight::get().reads(4104)) + .saturating_add(T::DbWeight::get().writes(2)), DispatchClass::Normal, Pays::No))] pub fn set_weights( origin: OriginFor, netuid: u16, @@ -1196,6 +1218,76 @@ pub mod pallet { Self::do_set_weights(origin, netuid, dests, weights, version_key) } + /// ---- Used to commit a hash of your weight values to later be revealed. + /// + /// # Args: + /// * `origin`: (`::RuntimeOrigin`): + /// - The signature of the committing hotkey. + /// + /// * `netuid` (`u16`): + /// - The u16 network identifier. + /// + /// * `commit_hash` (`H256`): + /// - The hash representing the committed weights. + /// + /// # Raises: + /// * `CommitNotAllowed`: + /// - Attempting to commit when it is not allowed. + /// + #[pallet::call_index(96)] + #[pallet::weight((Weight::from_parts(46_000_000, 0) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Normal, Pays::No))] + pub fn commit_weights( + origin: T::RuntimeOrigin, + netuid: u16, + commit_hash: H256, + ) -> DispatchResult { + Self::do_commit_weights(origin, netuid, commit_hash) + } + + /// ---- Used to reveal the weights for a previously committed hash. + /// + /// # Args: + /// * `origin`: (`::RuntimeOrigin`): + /// - The signature of the revealing hotkey. + /// + /// * `netuid` (`u16`): + /// - The u16 network identifier. + /// + /// * `uids` (`Vec`): + /// - The uids for the weights being revealed. + /// + /// * `values` (`Vec`): + /// - The values of the weights being revealed. + /// + /// * `version_key` (`u64`): + /// - The network version key. + /// + /// # Raises: + /// * `NoCommitFound`: + /// - Attempting to reveal weights without an existing commit. + /// + /// * `InvalidRevealTempo`: + /// - Attempting to reveal weights outside the valid tempo. + /// + /// * `InvalidReveal`: + /// - The revealed hash does not match the committed hash. + /// + #[pallet::call_index(97)] + #[pallet::weight((Weight::from_parts(103_000_000, 0) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(3)), DispatchClass::Normal, Pays::No))] + pub fn reveal_weights( + origin: T::RuntimeOrigin, + netuid: u16, + uids: Vec, + values: Vec, + version_key: u64, + ) -> DispatchResult { + Self::do_reveal_weights(origin, netuid, uids, values, version_key) + } + // # Args: // * `origin`: (Origin): // - The caller, a hotkey who wishes to set their weights. @@ -1756,7 +1848,7 @@ pub mod pallet { #[pallet::call_index(60)] #[pallet::weight((Weight::from_parts(91_000_000, 0) - .saturating_add(T::DbWeight::get().reads(27)) + .saturating_add(T::DbWeight::get().reads(27)) .saturating_add(T::DbWeight::get().writes(22)), DispatchClass::Normal, Pays::No))] pub fn faucet( origin: OriginFor, @@ -1908,6 +2000,30 @@ where _len: usize, ) -> TransactionValidity { match call.is_sub_type() { + Some(Call::commit_weights { netuid, .. }) => { + if Self::check_weights_min_stake(who) { + let priority: u64 = Self::get_priority_set_weights(who, *netuid); + Ok(ValidTransaction { + priority, + longevity: 1, + ..Default::default() + }) + } else { + Err(InvalidTransaction::Call.into()) + } + } + Some(Call::reveal_weights { netuid, .. }) => { + if Self::check_weights_min_stake(who) { + let priority: u64 = Self::get_priority_set_weights(who, *netuid); + Ok(ValidTransaction { + priority, + longevity: 1, + ..Default::default() + }) + } else { + Err(InvalidTransaction::Call.into()) + } + } Some(Call::set_weights { netuid, .. }) => { if Self::check_weights_min_stake(who) { let priority: u64 = Self::get_priority_set_weights(who, *netuid); @@ -1986,6 +2102,14 @@ where let transaction_fee = 0; Ok((CallType::SetWeights, transaction_fee, who.clone())) } + Some(Call::commit_weights { .. }) => { + let transaction_fee = 0; + Ok((CallType::SetWeights, transaction_fee, who.clone())) + } + Some(Call::reveal_weights { .. }) => { + let transaction_fee = 0; + Ok((CallType::SetWeights, transaction_fee, who.clone())) + } Some(Call::register { .. }) => { let transaction_fee = 0; Ok((CallType::Register, transaction_fee, who.clone())) diff --git a/pallets/subtensor/src/weights.rs b/pallets/subtensor/src/weights.rs index 1bbb39491..2e3ace77b 100644 --- a/pallets/subtensor/src/weights.rs +++ b/pallets/subtensor/src/weights.rs @@ -1,8 +1,106 @@ use super::*; use crate::math::*; +use sp_core::H256; +use sp_runtime::traits::{BlakeTwo256, Hash}; use sp_std::vec; impl Pallet { + /// ---- The implementation for committing weight hashes. + /// + /// # Args: + /// * `origin`: (`::RuntimeOrigin`): + /// - The signature of the committing hotkey. + /// + /// * `netuid` (`u16`): + /// - The u16 network identifier. + /// + /// * `commit_hash` (`H256`): + /// - The hash representing the committed weights. + /// + /// # Raises: + /// * `CommitNotAllowed`: + /// - Attempting to commit when it is not allowed. + /// + pub fn do_commit_weights( + origin: T::RuntimeOrigin, + netuid: u16, + commit_hash: H256, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + log::info!("do_commit_weights( hotkey:{:?} netuid:{:?})", who, netuid); + + ensure!(Self::can_commit(netuid, &who), Error::::CommitNotAllowed); + + WeightCommits::::insert( + netuid, + &who, + (commit_hash, Self::get_current_block_as_u64()), + ); + Ok(()) + } + + /// ---- The implementation for revealing committed weights. + /// + /// # Args: + /// * `origin`: (`::RuntimeOrigin`): + /// - The signature of the revealing hotkey. + /// + /// * `netuid` (`u16`): + /// - The u16 network identifier. + /// + /// * `uids` (`Vec`): + /// - The uids for the weights being revealed. + /// + /// * `values` (`Vec`): + /// - The values of the weights being revealed. + /// + /// * `version_key` (`u64`): + /// - The network version key. + /// + /// # Raises: + /// * `NoCommitFound`: + /// - Attempting to reveal weights without an existing commit. + /// + /// * `InvalidRevealTempo`: + /// - Attempting to reveal weights outside the valid tempo. + /// + /// * `InvalidReveal`: + /// - The revealed hash does not match the committed hash. + /// + pub fn do_reveal_weights( + origin: T::RuntimeOrigin, + netuid: u16, + uids: Vec, + values: Vec, + version_key: u64, + ) -> DispatchResult { + let who = ensure_signed(origin.clone())?; + + log::info!("do_reveal_weights( hotkey:{:?} netuid:{:?})", who, netuid); + + WeightCommits::::try_mutate_exists(netuid, &who, |maybe_commit| -> DispatchResult { + let (commit_hash, commit_block) = + maybe_commit.take().ok_or(Error::::NoCommitFound)?; + + ensure!( + Self::is_reveal_block_range(commit_block), + Error::::InvalidRevealTempo + ); + + let provided_hash: H256 = BlakeTwo256::hash_of(&( + who.clone(), + netuid, + uids.clone(), + values.clone(), + version_key, + )); + ensure!(provided_hash == commit_hash, Error::::InvalidReveal); + + Self::do_set_weights(origin, netuid, uids, values, version_key) + }) + } + // ---- The implementation for the extrinsic set_weights. // // # Args: @@ -324,4 +422,56 @@ impl Pallet { // we should expect at most subnetwork_n uids. uids.len() <= subnetwork_n as usize } + + pub fn can_commit(netuid: u16, who: &T::AccountId) -> bool { + if let Some((_hash, commit_block)) = WeightCommits::::get(netuid, who) { + let interval: u64 = Self::get_weight_commit_interval(); + if interval == 0 { + return true; //prevent division by 0 + } + + let current_block: u64 = Self::get_current_block_as_u64(); + let interval_start: u64 = current_block - (current_block % interval); + let last_commit_interval_start: u64 = commit_block - (commit_block % interval); + + // Allow commit if we're within the interval bounds + if current_block <= interval_start + interval + && interval_start > last_commit_interval_start + { + return true; + } + + false + } else { + true + } + } + + pub fn is_reveal_block_range(commit_block: u64) -> bool { + let interval: u64 = Self::get_weight_commit_interval(); + if interval == 0 { + return true; //prevent division by 0 + } + + let commit_interval_start: u64 = commit_block - (commit_block % interval); // Find the start of the interval in which the commit occurred + let reveal_interval_start: u64 = commit_interval_start + interval; // Start of the next interval after the commit interval + let current_block: u64 = Self::get_current_block_as_u64(); + + // Allow reveal if the current block is within the interval following the commit's interval + if current_block >= reveal_interval_start + && current_block < reveal_interval_start + interval + { + return true; + } + + false + } + + pub fn get_weight_commit_interval() -> u64 { + WeightCommitRevealInterval::::get() + } + + pub fn set_weight_commit_interval(interval: u64) { + WeightCommitRevealInterval::::set(interval) + } } diff --git a/pallets/subtensor/tests/weights.rs b/pallets/subtensor/tests/weights.rs index 3d7673982..5badaafad 100644 --- a/pallets/subtensor/tests/weights.rs +++ b/pallets/subtensor/tests/weights.rs @@ -1,12 +1,15 @@ mod mock; use frame_support::{ assert_err, assert_ok, - dispatch::{DispatchClass, GetDispatchInfo, Pays}, + dispatch::{DispatchClass, DispatchResult, GetDispatchInfo, Pays}, }; use mock::*; use pallet_subtensor::Error; -use sp_core::U256; -use sp_runtime::DispatchError; +use sp_core::{H256, U256}; +use sp_runtime::{ + traits::{BlakeTwo256, Hash}, + DispatchError, +}; use substrate_fixed::types::I32F32; /*************************** @@ -35,24 +38,62 @@ fn test_set_weights_dispatch_info_ok() { }); } +#[test] +fn test_commit_weights_dispatch_info_ok() { + new_test_ext(0).execute_with(|| { + let dests = vec![1, 1]; + let weights = vec![1, 1]; + let netuid: u16 = 1; + let version_key: u64 = 0; + let hotkey: U256 = U256::from(1); + + let commit_hash: H256 = + BlakeTwo256::hash_of(&(hotkey, netuid, dests, weights, version_key)); + + let call = RuntimeCall::SubtensorModule(SubtensorCall::commit_weights { + netuid, + commit_hash, + }); + let dispatch_info = call.get_dispatch_info(); + + assert_eq!(dispatch_info.class, DispatchClass::Normal); + assert_eq!(dispatch_info.pays_fee, Pays::No); + }); +} + +#[test] +fn test_reveal_weights_dispatch_info_ok() { + new_test_ext(0).execute_with(|| { + let dests = vec![1, 1]; + let weights = vec![1, 1]; + let netuid: u16 = 1; + let version_key: u64 = 0; + + let call = RuntimeCall::SubtensorModule(SubtensorCall::reveal_weights { + netuid, + uids: dests, + values: weights, + version_key, + }); + let dispatch_info = call.get_dispatch_info(); + + assert_eq!(dispatch_info.class, DispatchClass::Normal); + assert_eq!(dispatch_info.pays_fee, Pays::No); + }); +} + #[test] fn test_set_weights_is_root_error() { new_test_ext(0).execute_with(|| { let root_netuid: u16 = 0; - let dests = vec![0]; + let uids = 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, - ), + commit_reveal_set_weights(hotkey, root_netuid, uids, weights, version_key), Error::::IsRoot ); }); @@ -75,13 +116,9 @@ fn test_weights_err_no_validator_permit() { let weights_keys: Vec = vec![1, 2]; let weight_values: Vec = vec![1, 2]; - let result = SubtensorModule::set_weights( - RuntimeOrigin::signed(hotkey_account_id), - netuid, - weights_keys, - weight_values, - 0, - ); + + let result = + commit_reveal_set_weights(hotkey_account_id, netuid, weights_keys, weight_values, 0); assert_eq!(result, Err(Error::::NoValidatorPermit.into())); let weights_keys: Vec = vec![1, 2]; @@ -90,13 +127,8 @@ fn test_weights_err_no_validator_permit() { SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey_account_id) .expect("Not registered."); SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); - let result = SubtensorModule::set_weights( - RuntimeOrigin::signed(hotkey_account_id), - netuid, - weights_keys, - weight_values, - 0, - ); + let result = + commit_reveal_set_weights(hotkey_account_id, netuid, weights_keys, weight_values, 0); assert_ok!(result); }); } @@ -127,24 +159,18 @@ fn test_set_weights_min_stake_failed() { // Check that it fails at the pallet level. SubtensorModule::set_weights_min_stake(100_000_000_000_000); assert_eq!( - SubtensorModule::set_weights( - RuntimeOrigin::signed(hotkey), - netuid, - dests.clone(), - weights.clone(), - version_key, - ), + commit_reveal_set_weights(hotkey, netuid, dests.clone(), weights.clone(), version_key), Err(Error::::NotEnoughStakeToSetWeights.into()) ); // Now passes SubtensorModule::increase_stake_on_hotkey_account(&hotkey, 100_000_000_000_000); - assert_ok!(SubtensorModule::set_weights( - RuntimeOrigin::signed(hotkey), + assert_ok!(commit_reveal_set_weights( + hotkey, netuid, dests.clone(), weights.clone(), - version_key, - ),); + version_key + )); }); } @@ -163,15 +189,15 @@ fn test_weights_version_key() { let weights_keys: Vec = vec![0]; let weight_values: Vec = vec![1]; - assert_ok!(SubtensorModule::set_weights( - RuntimeOrigin::signed(hotkey), + assert_ok!(commit_reveal_set_weights( + hotkey, netuid0, weights_keys.clone(), weight_values.clone(), 0 )); - assert_ok!(SubtensorModule::set_weights( - RuntimeOrigin::signed(hotkey), + assert_ok!(commit_reveal_set_weights( + hotkey, netuid1, weights_keys.clone(), weight_values.clone(), @@ -185,15 +211,15 @@ fn test_weights_version_key() { SubtensorModule::set_weights_version_key(netuid1, key1); // Setting works with version key. - assert_ok!(SubtensorModule::set_weights( - RuntimeOrigin::signed(hotkey), + assert_ok!(commit_reveal_set_weights( + hotkey, netuid0, weights_keys.clone(), weight_values.clone(), key0 )); - assert_ok!(SubtensorModule::set_weights( - RuntimeOrigin::signed(hotkey), + assert_ok!(commit_reveal_set_weights( + hotkey, netuid1, weights_keys.clone(), weight_values.clone(), @@ -201,8 +227,8 @@ fn test_weights_version_key() { )); // validator:20313 >= network:12312 (accepted: validator newer) - assert_ok!(SubtensorModule::set_weights( - RuntimeOrigin::signed(hotkey), + assert_ok!(commit_reveal_set_weights( + hotkey, netuid0, weights_keys.clone(), weight_values.clone(), @@ -212,8 +238,8 @@ fn test_weights_version_key() { // Setting fails with incorrect keys. // validator:12312 < network:20313 (rejected: validator not updated) assert_eq!( - SubtensorModule::set_weights( - RuntimeOrigin::signed(hotkey), + commit_reveal_set_weights( + hotkey, netuid1, weights_keys.clone(), weight_values.clone(), @@ -294,11 +320,11 @@ fn test_weights_err_weights_vec_not_equal_size() { SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); let weights_keys: Vec = vec![1, 2, 3, 4, 5, 6]; let weight_values: Vec = vec![1, 2, 3, 4, 5]; // Uneven sizes - let result = SubtensorModule::set_weights( - RuntimeOrigin::signed(hotkey_account_id), + let result = commit_reveal_set_weights( + hotkey_account_id, 1, - weights_keys, - weight_values, + weights_keys.clone(), + weight_values.clone(), 0, ); assert_eq!(result, Err(Error::::WeightVecNotEqualSize.into())); @@ -343,11 +369,11 @@ fn test_weights_err_has_duplicate_ids() { let weights_keys: Vec = vec![1, 1, 1]; // Contains duplicates let weight_values: Vec = vec![1, 2, 3]; - let result = SubtensorModule::set_weights( - RuntimeOrigin::signed(hotkey_account_id), + let result = commit_reveal_set_weights( + hotkey_account_id, netuid, - weights_keys, - weight_values, + weights_keys.clone(), + weight_values.clone(), 0, ); assert_eq!(result, Err(Error::::DuplicateUids.into())); @@ -422,20 +448,13 @@ fn test_weights_err_max_weight_limit() { // Non self-weight fails. let uids: Vec = vec![1, 2, 3, 4]; let values: Vec = vec![u16::MAX / 4, u16::MAX / 4, u16::MAX / 54, u16::MAX / 4]; - let result = - SubtensorModule::set_weights(RuntimeOrigin::signed(U256::from(0)), 1, uids, values, 0); + let result = commit_reveal_set_weights(U256::from(0), 1, uids, values, 0); assert_eq!(result, Err(Error::::MaxWeightExceeded.into())); // Self-weight is a success. let uids: Vec = vec![0]; // Self. let values: Vec = vec![u16::MAX]; // normalizes to u32::MAX - assert_ok!(SubtensorModule::set_weights( - RuntimeOrigin::signed(U256::from(0)), - 1, - uids, - values, - 0 - )); + assert_ok!(commit_reveal_set_weights(U256::from(0), 1, uids, values, 0)); }); } @@ -466,13 +485,7 @@ fn test_set_weights_err_not_active() { let weights_keys: Vec = vec![0]; // Uid 0 is valid. let weight_values: Vec = vec![1]; // This hotkey is NOT registered. - let result = SubtensorModule::set_weights( - RuntimeOrigin::signed(U256::from(1)), - 1, - weights_keys, - weight_values, - 0, - ); + let result = commit_reveal_set_weights(U256::from(1), 1, weights_keys, weight_values, 0); assert_eq!(result, Err(Error::::NotRegistered.into())); }); } @@ -492,13 +505,7 @@ fn test_set_weights_err_invalid_uid() { SubtensorModule::set_validator_permit_for_uid(netuid, neuron_uid, true); let weight_keys: Vec = vec![9999]; // Does not exist let weight_values: Vec = vec![88]; // random value - let result = SubtensorModule::set_weights( - RuntimeOrigin::signed(hotkey_account_id), - 1, - weight_keys, - weight_values, - 0, - ); + let result = commit_reveal_set_weights(hotkey_account_id, 1, weight_keys, weight_values, 0); assert_eq!(result, Err(Error::::InvalidUid.into())); }); } @@ -524,20 +531,14 @@ fn test_set_weight_not_enough_values() { // Should fail because we are only setting a single value and its not the self weight. let weight_keys: Vec = vec![1]; // not weight. let weight_values: Vec = vec![88]; // random value. - let result = SubtensorModule::set_weights( - RuntimeOrigin::signed(account_id), - 1, - weight_keys, - weight_values, - 0, - ); + let result = commit_reveal_set_weights(account_id, 1, weight_keys, weight_values, 0); assert_eq!(result, Err(Error::::NotSettingEnoughWeights.into())); // Shouldnt fail because we setting a single value but it is the self weight. let weight_keys: Vec = vec![0]; // self weight. let weight_values: Vec = vec![88]; // random value. - assert_ok!(SubtensorModule::set_weights( - RuntimeOrigin::signed(account_id), + assert_ok!(commit_reveal_set_weights( + account_id, 1, weight_keys, weight_values, @@ -548,8 +549,8 @@ fn test_set_weight_not_enough_values() { let weight_keys: Vec = vec![0, 1]; // self weight. let weight_values: Vec = vec![10, 10]; // random value. SubtensorModule::set_min_allowed_weights(netuid, 1); - assert_ok!(SubtensorModule::set_weights( - RuntimeOrigin::signed(account_id), + assert_ok!(commit_reveal_set_weights( + account_id, 1, weight_keys, weight_values, @@ -578,20 +579,14 @@ fn test_set_weight_too_many_uids() { // Should fail because we are setting more weights than there are neurons. let weight_keys: Vec = vec![0, 1, 2, 3, 4]; // more uids than neurons in subnet. let weight_values: Vec = vec![88, 102, 303, 1212, 11]; // random value. - let result = SubtensorModule::set_weights( - RuntimeOrigin::signed(U256::from(1)), - 1, - weight_keys, - weight_values, - 0, - ); + let result = commit_reveal_set_weights(U256::from(1), 1, weight_keys, weight_values, 0); assert_eq!(result, Err(Error::::TooManyUids.into())); // Shouldnt fail because we are setting less weights than there are neurons. let weight_keys: Vec = vec![0, 1]; // Only on neurons that exist. let weight_values: Vec = vec![10, 10]; // random value. - assert_ok!(SubtensorModule::set_weights( - RuntimeOrigin::signed(U256::from(1)), + assert_ok!(commit_reveal_set_weights( + U256::from(1), 1, weight_keys, weight_values, @@ -623,13 +618,7 @@ fn test_set_weights_sum_larger_than_u16_max() { // sum of weights is larger than u16 max. assert!(weight_values.iter().map(|x| *x as u64).sum::() > (u16::MAX as u64)); - let result = SubtensorModule::set_weights( - RuntimeOrigin::signed(U256::from(1)), - 1, - weight_keys, - weight_values, - 0, - ); + let result = commit_reveal_set_weights(U256::from(1), 1, weight_keys, weight_values, 0); assert_ok!(result); // Get max-upscaled unnormalized weights. @@ -965,3 +954,324 @@ fn test_check_len_uids_within_allowed_not_within_network_pool() { ); }); } + +#[test] +fn test_commit_reveal_weights_ok() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let uids: Vec = vec![0, 1]; + let weight_values: Vec = vec![10, 10]; + let version_key: u64 = 0; + let hotkey: U256 = U256::from(1); + + let commit_hash: H256 = BlakeTwo256::hash_of(&( + hotkey, + netuid, + uids.clone(), + weight_values.clone(), + version_key, + )); + + add_network(netuid, 0, 0); + register_ok_neuron(netuid, U256::from(3), U256::from(4), 300000); + register_ok_neuron(netuid, U256::from(1), U256::from(2), 100000); + SubtensorModule::set_weights_set_rate_limit(netuid, 5); + SubtensorModule::set_validator_permit_for_uid(netuid, 0, true); + SubtensorModule::set_validator_permit_for_uid(netuid, 1, true); + + SubtensorModule::set_weight_commit_interval(5); + + assert_ok!(SubtensorModule::commit_weights( + RuntimeOrigin::signed(hotkey), + netuid, + commit_hash + )); + + step_block(5); + + assert_ok!(SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids, + weight_values, + version_key, + )); + }); +} + +#[test] +fn test_commit_reveal_interval() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let uids: Vec = vec![0, 1]; + let weight_values: Vec = vec![10, 10]; + let version_key: u64 = 0; + let hotkey: U256 = U256::from(1); + + let commit_hash: H256 = BlakeTwo256::hash_of(&( + hotkey, + netuid, + uids.clone(), + weight_values.clone(), + version_key, + )); + + add_network(netuid, 0, 0); + register_ok_neuron(netuid, U256::from(3), U256::from(4), 300000); + register_ok_neuron(netuid, U256::from(1), U256::from(2), 100000); + SubtensorModule::set_weights_set_rate_limit(netuid, 5); + SubtensorModule::set_validator_permit_for_uid(netuid, 0, true); + SubtensorModule::set_validator_permit_for_uid(netuid, 1, true); + + SubtensorModule::set_weight_commit_interval(100); + System::set_block_number(0); + + assert_ok!(SubtensorModule::commit_weights( + RuntimeOrigin::signed(hotkey), + netuid, + commit_hash + )); + assert_err!( + SubtensorModule::commit_weights(RuntimeOrigin::signed(hotkey), netuid, commit_hash), + Error::::CommitNotAllowed + ); + assert_err!( + SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids.clone(), + weight_values.clone(), + version_key, + ), + Error::::InvalidRevealTempo + ); + step_block(99); + assert_err!( + SubtensorModule::commit_weights(RuntimeOrigin::signed(hotkey), netuid, commit_hash), + Error::::CommitNotAllowed + ); + assert_err!( + SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids.clone(), + weight_values.clone(), + version_key, + ), + Error::::InvalidRevealTempo + ); + step_block(1); + assert_ok!(SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids.clone(), + weight_values.clone(), + version_key, + )); + + // After the previous reveal the associated mapping entry was removed. + // Therefore we expect NoCommitFound + assert_err!( + SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids.clone(), + weight_values.clone(), + version_key, + ), + Error::::NoCommitFound + ); + assert_ok!(SubtensorModule::commit_weights( + RuntimeOrigin::signed(hotkey), + netuid, + commit_hash + )); + assert_err!( + SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids.clone(), + weight_values.clone(), + version_key, + ), + Error::::InvalidRevealTempo + ); + step_block(100); + assert_ok!(SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids.clone(), + weight_values.clone(), + version_key, + )); + + // Testing that if you miss the next tempo you cannot reveal it. + assert_ok!(SubtensorModule::commit_weights( + RuntimeOrigin::signed(hotkey), + netuid, + commit_hash + )); + step_block(205); + assert_err!( + SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids.clone(), + weight_values.clone(), + version_key, + ), + Error::::InvalidRevealTempo + ); + + // Testing when you commit but do not reveal until later intervals + assert_ok!(SubtensorModule::commit_weights( + RuntimeOrigin::signed(hotkey), + netuid, + commit_hash + )); + step_block(425); + let commit_hash_2: H256 = BlakeTwo256::hash_of(&( + hotkey, + netuid, + uids.clone(), + weight_values.clone(), + version_key + 1, + )); + assert_ok!(SubtensorModule::commit_weights( + RuntimeOrigin::signed(hotkey), + netuid, + commit_hash_2 + )); + step_block(100); + assert_err!( + SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids.clone(), + weight_values.clone(), + version_key, + ), + Error::::InvalidReveal + ); + assert_ok!(SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids.clone(), + weight_values.clone(), + version_key + 1, + )); + }); +} + +#[test] +fn test_commit_reveal_hash() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let uids: Vec = vec![0, 1]; + let weight_values: Vec = vec![10, 10]; + let version_key: u64 = 0; + let hotkey: U256 = U256::from(1); + + add_network(netuid, 0, 0); + register_ok_neuron(netuid, U256::from(3), U256::from(4), 300000); + register_ok_neuron(netuid, U256::from(1), U256::from(2), 100000); + SubtensorModule::set_weights_set_rate_limit(netuid, 5); + SubtensorModule::set_validator_permit_for_uid(netuid, 0, true); + SubtensorModule::set_validator_permit_for_uid(netuid, 1, true); + + SubtensorModule::set_weight_commit_interval(5); + + let commit_hash: H256 = BlakeTwo256::hash_of(&( + hotkey, + netuid, + uids.clone(), + weight_values.clone(), + version_key, + )); + + assert_ok!(SubtensorModule::commit_weights( + RuntimeOrigin::signed(hotkey), + netuid, + commit_hash + )); + + step_block(5); + + assert_err!( + SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + vec![0, 2], + weight_values.clone(), + version_key + ), + Error::::InvalidReveal + ); + assert_err!( + SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids.clone(), + weight_values.clone(), + 7, + ), + Error::::InvalidReveal + ); + assert_err!( + SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids.clone(), + vec![10, 9], + version_key, + ), + Error::::InvalidReveal + ); + assert_err!( + SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + vec![0, 1, 2], + vec![10, 10, 33], + 9, + ), + Error::::InvalidReveal + ); + + assert_ok!(SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids, + weight_values, + version_key, + )); + }); +} + +fn commit_reveal_set_weights( + hotkey: U256, + netuid: u16, + uids: Vec, + weights: Vec, + version_key: u64, +) -> DispatchResult { + SubtensorModule::set_weight_commit_interval(5); + SubtensorModule::set_weights_set_rate_limit(netuid, 5); + + let commit_hash: H256 = + BlakeTwo256::hash_of(&(hotkey, netuid, uids.clone(), weights.clone(), version_key)); + + SubtensorModule::commit_weights(RuntimeOrigin::signed(hotkey), netuid, commit_hash)?; + + step_block(5); + + SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids, + weights, + version_key, + )?; + + Ok(()) +}