diff --git a/.github/workflows/check-rust.yml b/.github/workflows/check-rust.yml index e42e369cf..b6a627314 100644 --- a/.github/workflows/check-rust.yml +++ b/.github/workflows/check-rust.yml @@ -212,16 +212,7 @@ jobs: cargo-audit: name: cargo audit runs-on: SubtensorCI - strategy: - matrix: - rust-branch: - - stable - rust-target: - - x86_64-unknown-linux-gnu - # - x86_64-apple-darwin - os: - - ubuntu-latest - # - macos-latest + if: ${{ github.event_name != 'push' && !contains(github.event.pull_request.labels.*.name, 'skip-cargo-audit') }} steps: - name: Check-out repositoroy under $GITHUB_WORKSPACE uses: actions/checkout@v4 @@ -231,17 +222,17 @@ jobs: sudo apt-get update && sudo apt-get install -y clang curl libssl-dev llvm libudev-dev protobuf-compiler - - name: Install Rust ${{ matrix.rust-branch }} + - name: Install Rust Stable uses: actions-rs/toolchain@v1.0.6 with: - toolchain: ${{ matrix.rust-branch }} + toolchain: stable components: rustfmt, clippy profile: minimal - name: Utilize Shared Rust Cache uses: Swatinem/rust-cache@v2.2.1 with: - key: ${{ matrix.os }}-${{ env.RUST_BIN_DIR }} + key: ubuntu-latest-${{ env.RUST_BIN_DIR }} - name: Install cargo-audit run: cargo install cargo-audit diff --git a/pallets/admin-utils/src/benchmarking.rs b/pallets/admin-utils/src/benchmarking.rs index 606814ff0..65ccf629e 100644 --- a/pallets/admin-utils/src/benchmarking.rs +++ b/pallets/admin-utils/src/benchmarking.rs @@ -228,14 +228,14 @@ mod benchmarks { } #[benchmark] - fn sudo_set_commit_reveal_weights_periods() { + fn sudo_set_commit_reveal_weights_interval() { pallet_subtensor::Pallet::::init_new_network( 1u16, /*netuid*/ 1u16, /*sudo_tempo*/ ); #[extrinsic_call] - _(RawOrigin::Root, 1u16/*netuid*/, 3u64/*interval*/)/*set_commit_reveal_weights_periods()*/; + _(RawOrigin::Root, 1u16/*netuid*/, 3u64/*interval*/)/*sudo_set_commit_reveal_weights_interval()*/; } #[benchmark] diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index a287bb1b4..85c7ef62c 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -1187,12 +1187,12 @@ pub mod pallet { /// /// # Weight /// Weight is handled by the `#[pallet::weight]` attribute. - #[pallet::call_index(56)] - #[pallet::weight(T::WeightInfo::sudo_set_commit_reveal_weights_periods())] - pub fn sudo_set_commit_reveal_weights_periods( + #[pallet::call_index(57)] + #[pallet::weight(T::WeightInfo::sudo_set_commit_reveal_weights_interval())] + pub fn sudo_set_commit_reveal_weights_interval( origin: OriginFor, netuid: u16, - periods: u64, + interval: u64, ) -> DispatchResult { pallet_subtensor::Pallet::::ensure_subnet_owner_or_root(origin, netuid)?; @@ -1201,11 +1201,11 @@ pub mod pallet { Error::::SubnetDoesNotExist ); - pallet_subtensor::Pallet::::set_reveal_period(netuid, periods); + pallet_subtensor::Pallet::::set_reveal_period(netuid, interval); log::debug!( - "SetWeightCommitPeriods( netuid: {:?}, periods: {:?} ) ", + "SetWeightCommitInterval( netuid: {:?}, interval: {:?} ) ", netuid, - periods + interval ); Ok(()) } diff --git a/pallets/admin-utils/src/weights.rs b/pallets/admin-utils/src/weights.rs index db8752ff7..bda9c7916 100644 --- a/pallets/admin-utils/src/weights.rs +++ b/pallets/admin-utils/src/weights.rs @@ -60,7 +60,7 @@ pub trait WeightInfo { fn sudo_set_min_burn() -> Weight; fn sudo_set_network_registration_allowed() -> Weight; fn sudo_set_tempo() -> Weight; - fn sudo_set_commit_reveal_weights_periods() -> Weight; + fn sudo_set_commit_reveal_weights_interval() -> Weight; fn sudo_set_commit_reveal_weights_enabled() -> Weight; } @@ -413,7 +413,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - fn sudo_set_commit_reveal_weights_periods() -> Weight { + fn sudo_set_commit_reveal_weights_interval() -> Weight { // Proof Size summary in bytes: // Measured: `456` // Estimated: `3921` @@ -781,7 +781,7 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - fn sudo_set_commit_reveal_weights_periods() -> Weight { + fn sudo_set_commit_reveal_weights_interval() -> Weight { // -- Extrinsic Time -- // Model: // Time ~= 19.38 diff --git a/pallets/admin-utils/tests/tests.rs b/pallets/admin-utils/tests/tests.rs index d2c36e29f..442275052 100644 --- a/pallets/admin-utils/tests/tests.rs +++ b/pallets/admin-utils/tests/tests.rs @@ -1414,7 +1414,7 @@ fn test_sudo_set_dissolve_network_schedule_duration() { } #[test] -fn sudo_set_commit_reveal_weights_periods() { +fn sudo_set_commit_reveal_weights_interval() { new_test_ext().execute_with(|| { let netuid: u16 = 1; add_network(netuid, 10); @@ -1422,7 +1422,7 @@ fn sudo_set_commit_reveal_weights_periods() { let to_be_set = 55; let init_value = SubtensorModule::get_reveal_period(netuid); - assert_ok!(AdminUtils::sudo_set_commit_reveal_weights_periods( + assert_ok!(AdminUtils::sudo_set_commit_reveal_weights_interval( <::RuntimeOrigin>::root(), netuid, to_be_set diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 723edc423..badb811fa 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -265,69 +265,65 @@ impl Pallet { // --- 1.0 Drain the hotkey emission. PendingdHotkeyEmission::::insert(hotkey, 0); - // --- 2 Retrieve the last time this hotkey's emissions were drained. - let last_emission_drain: u64 = LastHotkeyEmissionDrain::::get(hotkey); - - // --- 3 Update the block value to the current block number. + // --- 2 Update the block value to the current block number. LastHotkeyEmissionDrain::::insert(hotkey, block_number); - // --- 4 Retrieve the total stake for the hotkey from all nominations. + // --- 3 Retrieve the total stake for the hotkey from all nominations. let total_hotkey_stake: u64 = Self::get_total_stake_for_hotkey(hotkey); - // --- 5 Calculate the emission take for the hotkey. + // --- 4 Calculate the emission take for the hotkey. let take_proportion: I64F64 = I64F64::from_num(Delegates::::get(hotkey)) .saturating_div(I64F64::from_num(u16::MAX)); let hotkey_take: u64 = (take_proportion.saturating_mul(I64F64::from_num(emission))).to_num::(); - // --- 6 Compute the remaining emission after deducting the hotkey's take. + // --- 5 Compute the remaining emission after deducting the hotkey's take. let emission_minus_take: u64 = emission.saturating_sub(hotkey_take); - // --- 7 Calculate the remaining emission after the hotkey's take. + // --- 6 Calculate the remaining emission after the hotkey's take. let mut remainder: u64 = emission_minus_take; - // --- 8 Iterate over each nominator and get all viable stake. + // --- 7 Iterate over each nominator and get all viable stake. let mut total_viable_nominator_stake: u64 = total_hotkey_stake; - for (nominator, nominator_stake) in Stake::::iter_prefix(hotkey) { - if LastAddStakeIncrease::::get(hotkey, nominator) > last_emission_drain { - total_viable_nominator_stake = - total_viable_nominator_stake.saturating_sub(nominator_stake); - } + for (nominator, _) in Stake::::iter_prefix(hotkey) { + let nonviable_nomintaor_stake = Self::get_nonviable_stake(hotkey, &nominator); + + total_viable_nominator_stake = + total_viable_nominator_stake.saturating_sub(nonviable_nomintaor_stake); } - // --- 9 Iterate over each nominator. + // --- 8 Iterate over each nominator. if total_viable_nominator_stake != 0 { for (nominator, nominator_stake) in Stake::::iter_prefix(hotkey) { - // --- 10 Check if the stake was manually increased by the user since the last emission drain for this hotkey. + // --- 9 Check if the stake was manually increased by the user since the last emission drain for this hotkey. // If it was, skip this nominator as they will not receive their proportion of the emission. - if LastAddStakeIncrease::::get(hotkey, nominator.clone()) > last_emission_drain { - continue; - } + let viable_nominator_stake = + nominator_stake.saturating_sub(Self::get_nonviable_stake(hotkey, &nominator)); - // --- 11 Calculate this nominator's share of the emission. - let nominator_emission: I64F64 = I64F64::from_num(emission_minus_take) - .saturating_mul(I64F64::from_num(nominator_stake)) + // --- 10 Calculate this nominator's share of the emission. + let nominator_emission: I64F64 = I64F64::from_num(viable_nominator_stake) .checked_div(I64F64::from_num(total_viable_nominator_stake)) - .unwrap_or(I64F64::from_num(0)); + .unwrap_or(I64F64::from_num(0)) + .saturating_mul(I64F64::from_num(emission_minus_take)); - // --- 12 Increase the stake for the nominator. + // --- 11 Increase the stake for the nominator. Self::increase_stake_on_coldkey_hotkey_account( &nominator, hotkey, nominator_emission.to_num::(), ); - // --- 13* Record event and Subtract the nominator's emission from the remainder. + // --- 12* Record event and Subtract the nominator's emission from the remainder. total_new_tao = total_new_tao.saturating_add(nominator_emission.to_num::()); remainder = remainder.saturating_sub(nominator_emission.to_num::()); } } - // --- 14 Finally, add the stake to the hotkey itself, including its take and the remaining emission. + // --- 13 Finally, add the stake to the hotkey itself, including its take and the remaining emission. let hotkey_new_tao: u64 = hotkey_take.saturating_add(remainder); Self::increase_stake_on_hotkey_account(hotkey, hotkey_new_tao); - // --- 15 Record new tao creation event and return the amount created. + // --- 14 Record new tao creation event and return the amount created. total_new_tao = total_new_tao.saturating_add(hotkey_new_tao); total_new_tao } @@ -382,4 +378,18 @@ impl Pallet { let remainder = block_plus_netuid.rem_euclid(tempo_plus_one); (tempo as u64).saturating_sub(remainder) } + + /// Calculates the nonviable stake for a nominator. + /// The nonviable stake is the stake that was added by the nominator since the last emission drain. + /// This stake will not receive emission until the next emission drain. + /// Note: if the stake delta is below zero, we return zero. We don't allow more stake than the nominator has. + pub fn get_nonviable_stake(hotkey: &T::AccountId, nominator: &T::AccountId) -> u64 { + let stake_delta = StakeDeltaSinceLastEmissionDrain::::get(hotkey, nominator); + if stake_delta.is_negative() { + 0 + } else { + // Should never fail the into, but we handle it anyway. + stake_delta.try_into().unwrap_or(u64::MAX) + } + } } diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 5081d69d3..d93253cfa 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -259,6 +259,11 @@ pub mod pallet { 0 } #[pallet::type_value] + /// Default stake delta. + pub fn DefaultStakeDelta() -> i128 { + 0 + } + #[pallet::type_value] /// Default stakes per interval. pub fn DefaultStakesPerInterval() -> (u64, u64) { (0, 0) @@ -569,7 +574,7 @@ pub mod pallet { 0 } #[pallet::type_value] - /// Default minimum stake for weights. + /// Default Reveal Period Epochs pub fn DefaultRevealPeriodEpochs() -> u64 { 1 } @@ -791,16 +796,16 @@ pub mod pallet { DefaultAccumulatedEmission, >; #[pallet::storage] - /// Map ( hot, cold ) --> block_number | Last add stake increase. - pub type LastAddStakeIncrease = StorageDoubleMap< + /// Map ( hot, cold ) --> stake: i128 | Stake added/removed since last emission drain. + pub type StakeDeltaSinceLastEmissionDrain = StorageDoubleMap< _, Blake2_128Concat, T::AccountId, Identity, T::AccountId, - u64, + i128, ValueQuery, - DefaultAccountTake, + DefaultStakeDelta, >; #[pallet::storage] /// DMAP ( parent, netuid ) --> Vec<(proportion,child)> @@ -1251,14 +1256,14 @@ pub mod pallet { /// ITEM( weights_min_stake ) pub type WeightsMinStake = StorageValue<_, u64, ValueQuery, DefaultWeightsMinStake>; #[pallet::storage] - /// --- MAP (netuid, who) --> VecDeque<(hash, commit_block)> | Stores a queue of commits for an account on a given netuid. + /// --- MAP (netuid, who) --> VecDeque<(hash, commit_block, first_reveal_block, last_reveal_block)> | Stores a queue of commits for an account on a given netuid. pub type WeightCommits = StorageDoubleMap< _, Twox64Concat, u16, Twox64Concat, T::AccountId, - VecDeque<(H256, u64)>, + VecDeque<(H256, u64, u64, u64)>, OptionQuery, >; #[pallet::storage] diff --git a/pallets/subtensor/src/macros/errors.rs b/pallets/subtensor/src/macros/errors.rs index 1e4bf9ae0..aab849994 100644 --- a/pallets/subtensor/src/macros/errors.rs +++ b/pallets/subtensor/src/macros/errors.rs @@ -188,5 +188,7 @@ mod errors { RevealTooEarly, /// Attempted to batch reveal weights with mismatched vector input lenghts. InputLengthsUnequal, + /// A transactor exceeded the rate limit for setting weights. + CommittingWeightsTooFast, } } diff --git a/pallets/subtensor/src/macros/events.rs b/pallets/subtensor/src/macros/events.rs index ac6b69012..f3b03684d 100644 --- a/pallets/subtensor/src/macros/events.rs +++ b/pallets/subtensor/src/macros/events.rs @@ -204,5 +204,25 @@ mod events { ColdkeySwapScheduleDurationSet(BlockNumberFor), /// The duration of dissolve network has been set DissolveNetworkScheduleDurationSet(BlockNumberFor), + /// Weights have been successfully committed. + /// + /// - **who**: The account ID of the user committing the weights. + /// - **netuid**: The network identifier. + /// - **commit_hash**: The hash representing the committed weights. + WeightsCommitted(T::AccountId, u16, H256), + + /// Weights have been successfully revealed. + /// + /// - **who**: The account ID of the user revealing the weights. + /// - **netuid**: The network identifier. + /// - **commit_hash**: The hash of the revealed weights. + WeightsRevealed(T::AccountId, u16, H256), + + /// Weights have been successfully batch revealed. + /// + /// - **who**: The account ID of the user revealing the weights. + /// - **netuid**: The network identifier. + /// - **revealed_hashes**: A vector of hashes representing each revealed weight set. + WeightsBatchRevealed(T::AccountId, u16, Vec), } } diff --git a/pallets/subtensor/src/migrations/migrate_commit_reveal_v2.rs b/pallets/subtensor/src/migrations/migrate_commit_reveal_v2.rs index cd93842c9..b8b831b61 100644 --- a/pallets/subtensor/src/migrations/migrate_commit_reveal_v2.rs +++ b/pallets/subtensor/src/migrations/migrate_commit_reveal_v2.rs @@ -5,7 +5,7 @@ use scale_info::prelude::string::String; use sp_io::{hashing::twox_128, storage::clear_prefix, KillStorageResult}; pub fn migrate_commit_reveal_2() -> Weight { - let migration_name = b"migrate_commit_reveal_2".to_vec(); + let migration_name = b"migrate_commit_reveal_2_v2".to_vec(); let mut weight = T::DbWeight::get().reads(1); if HasMigrationRun::::get(&migration_name) { diff --git a/pallets/subtensor/src/rpc_info/subnet_info.rs b/pallets/subtensor/src/rpc_info/subnet_info.rs index 8c79db03a..bdd420821 100644 --- a/pallets/subtensor/src/rpc_info/subnet_info.rs +++ b/pallets/subtensor/src/rpc_info/subnet_info.rs @@ -51,7 +51,7 @@ pub struct SubnetInfov2 { identity: Option, } -#[freeze_struct("4ceb81dfe8a8f96d")] +#[freeze_struct("55b472510f10e76a")] #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct SubnetHyperparams { rho: Compact, @@ -76,7 +76,7 @@ pub struct SubnetHyperparams { max_validators: Compact, adjustment_alpha: Compact, difficulty: Compact, - commit_reveal_periods: Compact, + commit_reveal_weights_interval: Compact, commit_reveal_weights_enabled: bool, alpha_high: Compact, alpha_low: Compact, @@ -280,7 +280,7 @@ impl Pallet { max_validators: max_validators.into(), adjustment_alpha: adjustment_alpha.into(), difficulty: difficulty.into(), - commit_reveal_periods: commit_reveal_periods.into(), + commit_reveal_weights_interval: commit_reveal_periods.into(), commit_reveal_weights_enabled, alpha_high: alpha_high.into(), alpha_low: alpha_low.into(), diff --git a/pallets/subtensor/src/staking/add_stake.rs b/pallets/subtensor/src/staking/add_stake.rs index c9cbd7e04..72d8374bc 100644 --- a/pallets/subtensor/src/staking/add_stake.rs +++ b/pallets/subtensor/src/staking/add_stake.rs @@ -70,8 +70,10 @@ impl Pallet { Error::::StakeRateLimitExceeded ); - // Set the last time the stake increased for nominator drain protection. - LastAddStakeIncrease::::insert(&hotkey, &coldkey, Self::get_current_block_as_u64()); + // Track this addition in the stake delta. + StakeDeltaSinceLastEmissionDrain::::mutate(&hotkey, &coldkey, |stake_delta| { + *stake_delta = stake_delta.saturating_add_unsigned(stake_to_be_added as u128); + }); // If coldkey is not owner of the hotkey, it's a nomination stake. if !Self::coldkey_owns_hotkey(&coldkey, &hotkey) { diff --git a/pallets/subtensor/src/subnets/weights.rs b/pallets/subtensor/src/subnets/weights.rs index ba673afa4..87042f456 100644 --- a/pallets/subtensor/src/subnets/weights.rs +++ b/pallets/subtensor/src/subnets/weights.rs @@ -19,51 +19,88 @@ impl Pallet { /// /// # Raises: /// * `CommitRevealDisabled`: - /// - Attempting to commit when the commit-reveal mechanism is disabled. + /// - Raised if commit-reveal is disabled for the specified network. + /// + /// * `HotKeyNotRegisteredInSubNet`: + /// - Raised if the hotkey is not registered on the specified network. + /// + /// * `CommittingWeightsTooFast`: + /// - Raised if the hotkey's commit rate exceeds the permitted limit. /// /// * `TooManyUnrevealedCommits`: - /// - Attempting to commit when the user has more than the allowed limit of unrevealed commits. + /// - Raised if the hotkey has reached the maximum number of unrevealed commits. + /// + /// # Events: + /// * `WeightsCommitted`: + /// - Emitted upon successfully storing the weight hash. pub fn do_commit_weights( origin: T::RuntimeOrigin, netuid: u16, commit_hash: H256, ) -> DispatchResult { - // --- 1. Check the caller's signature (hotkey). + // 1. Verify the caller's signature (hotkey). let who = ensure_signed(origin)?; - log::debug!("do_commit_weights( hotkey:{:?} netuid:{:?})", who, netuid); + log::debug!("do_commit_weights(hotkey: {:?}, netuid: {:?})", who, netuid); - // --- 2. Ensure commit-reveal is enabled for the network. + // 2. Ensure commit-reveal is enabled. ensure!( Self::get_commit_reveal_weights_enabled(netuid), Error::::CommitRevealDisabled ); - // --- 3. Mutate the WeightCommits to retrieve existing commits for the user. + // 3. Ensure the hotkey is registered on the network. + ensure!( + Self::is_hotkey_registered_on_network(netuid, &who), + Error::::HotKeyNotRegisteredInSubNet + ); + + // 4. Check that the commit rate does not exceed the allowed frequency. + let commit_block = Self::get_current_block_as_u64(); + let neuron_uid = Self::get_uid_for_net_and_hotkey(netuid, &who)?; + ensure!( + Self::check_rate_limit(netuid, neuron_uid, commit_block), + Error::::CommittingWeightsTooFast + ); + + // 5. Calculate the reveal blocks based on network tempo and reveal period. + let (first_reveal_block, last_reveal_block) = Self::get_reveal_blocks(netuid, commit_block); + + // 6. Retrieve or initialize the VecDeque of commits for the hotkey. WeightCommits::::try_mutate(netuid, &who, |maybe_commits| -> DispatchResult { - // --- 4. Take the existing commits or create a new VecDeque. - let mut commits: VecDeque<(H256, u64)> = maybe_commits.take().unwrap_or_default(); + let mut commits: VecDeque<(H256, u64, u64, u64)> = + maybe_commits.take().unwrap_or_default(); - // --- 5. Remove any expired commits from the front of the queue. - while let Some((_, commit_block)) = commits.front() { - if Self::is_commit_expired(netuid, *commit_block) { - // Remove the expired commit + // 7. Remove any expired commits from the front of the queue. + while let Some((_, commit_block_existing, _, _)) = commits.front() { + if Self::is_commit_expired(netuid, *commit_block_existing) { commits.pop_front(); } else { break; } } - // --- 6. Check if the current number of unrevealed commits is within the allowed limit. + // 8. Verify that the number of unrevealed commits is within the allowed limit. ensure!(commits.len() < 10, Error::::TooManyUnrevealedCommits); - // --- 7. Append the new commit to the queue. - commits.push_back((commit_hash, Self::get_current_block_as_u64())); + // 9. Append the new commit with calculated reveal blocks. + commits.push_back(( + commit_hash, + commit_block, + first_reveal_block, + last_reveal_block, + )); - // --- 8. Store the updated queue back to storage. + // 10. Store the updated commits queue back to storage. *maybe_commits = Some(commits); - // --- 9. Return ok. + // 11. Emit the WeightsCommitted event + Self::deposit_event(Event::WeightsCommitted(who.clone(), netuid, commit_hash)); + + // 12. Update the last commit block for the hotkey's UID. + Self::set_last_update_for_uid(netuid, neuron_uid, commit_block); + + // 13. Return success. Ok(()) }) } @@ -131,7 +168,7 @@ impl Pallet { // --- 4. Remove any expired commits from the front of the queue, collecting their hashes. let mut expired_hashes = Vec::new(); - while let Some((hash, commit_block)) = commits.front() { + while let Some((hash, commit_block, _, _)) = commits.front() { if Self::is_commit_expired(netuid, *commit_block) { // Collect the expired commit hash expired_hashes.push(*hash); @@ -153,7 +190,6 @@ impl Pallet { // --- 6. After removing expired commits, check if any commits are left. if commits.is_empty() { - // No non-expired commits // Check if provided_hash matches any expired commits if expired_hashes.contains(&provided_hash) { return Err(Error::::ExpiredWeightCommit.into()); @@ -163,9 +199,12 @@ impl Pallet { } // --- 7. Search for the provided_hash in the non-expired commits. - if let Some(position) = commits.iter().position(|(hash, _)| *hash == provided_hash) { + if let Some(position) = commits + .iter() + .position(|(hash, _, _, _)| *hash == provided_hash) + { // --- 8. Get the commit block for the commit being revealed. - let (_, commit_block) = commits + let (_, commit_block, _, _) = commits .get(position) .ok_or(Error::::NoWeightsCommitFound)?; @@ -186,10 +225,15 @@ impl Pallet { } // --- 12. Proceed to set the revealed weights. - Self::do_set_weights(origin, netuid, uids, values, version_key) + Self::do_set_weights(origin, netuid, uids.clone(), values.clone(), version_key)?; + + // --- 13. Emit the WeightsRevealed event. + Self::deposit_event(Event::WeightsRevealed(who.clone(), netuid, provided_hash)); + + // --- 14. Return ok. + Ok(()) } else { - // --- 13. The provided_hash does not match any non-expired commits. - // Check if provided_hash matches any expired commits + // --- 15. The provided_hash does not match any non-expired commits. if expired_hashes.contains(&provided_hash) { Err(Error::::ExpiredWeightCommit.into()) } else { @@ -236,7 +280,7 @@ impl Pallet { /// * `InvalidRevealCommitHashNotMatch`: /// - The revealed hash does not match any committed hash. /// - /// * `InvalidInputLengths`: + /// * `InputLengthsUnequal`: /// - The input vectors are of mismatched lengths. pub fn do_batch_reveal_weights( origin: T::RuntimeOrigin, @@ -278,7 +322,7 @@ impl Pallet { // --- 5. Remove any expired commits from the front of the queue, collecting their hashes. let mut expired_hashes = Vec::new(); - while let Some((hash, commit_block)) = commits.front() { + while let Some((hash, commit_block, _, _)) = commits.front() { if Self::is_commit_expired(netuid, *commit_block) { // Collect the expired commit hash expired_hashes.push(*hash); @@ -288,7 +332,11 @@ impl Pallet { } } - // --- 6. Process each reveal. + // --- 6. Prepare to collect all provided hashes and their corresponding reveals. + let mut provided_hashes = Vec::new(); + let mut reveals = Vec::new(); + let mut revealed_hashes: Vec = Vec::with_capacity(num_reveals); + for ((uids, values), (salt, version_key)) in uids_list .into_iter() .zip(values_list) @@ -303,45 +351,73 @@ impl Pallet { salt.clone(), version_key, )); + provided_hashes.push(provided_hash); + reveals.push((uids, values, version_key, provided_hash)); + } - // --- 6b. Search for the provided_hash in the non-expired commits. - if let Some(position) = commits.iter().position(|(hash, _)| *hash == provided_hash) + // --- 7. Validate all reveals first to ensure atomicity. + for (_uids, _values, _version_key, provided_hash) in &reveals { + // --- 7a. Check if the provided_hash is in the non-expired commits. + if !commits + .iter() + .any(|(hash, _, _, _)| *hash == *provided_hash) { - // --- 6c. Get the commit block for the commit being revealed. - let (_, commit_block) = commits - .get(position) - .ok_or(Error::::NoWeightsCommitFound)?; - - // --- 6d. Ensure the commit is ready to be revealed in the current block range. - ensure!( - Self::is_reveal_block_range(netuid, *commit_block), - Error::::RevealTooEarly - ); - - // --- 6e. Remove all commits up to and including the one being revealed. - for _ in 0..=position { - commits.pop_front(); - } - - // --- 6f. Proceed to set the revealed weights. - Self::do_set_weights(origin.clone(), netuid, uids, values, version_key)?; - } else { - // The provided_hash does not match any non-expired commits. - // Check if it matches any expired commits - if expired_hashes.contains(&provided_hash) { + // --- 7b. If not found, check if it matches any expired commits. + if expired_hashes.contains(provided_hash) { return Err(Error::::ExpiredWeightCommit.into()); } else { return Err(Error::::InvalidRevealCommitHashNotMatch.into()); } } + + // --- 7c. Find the commit corresponding to the provided_hash. + let commit = commits + .iter() + .find(|(hash, _, _, _)| *hash == *provided_hash) + .ok_or(Error::::NoWeightsCommitFound)?; + + // --- 7d. Check if the commit is within the reveal window. + ensure!( + Self::is_reveal_block_range(netuid, commit.1), + Error::::RevealTooEarly + ); } - // --- 7. If the queue is now empty, remove the storage entry for the user. + // --- 8. All reveals are valid. Proceed to remove and process each reveal. + for (uids, values, version_key, provided_hash) in reveals { + // --- 8a. Find the position of the provided_hash. + if let Some(position) = commits + .iter() + .position(|(hash, _, _, _)| *hash == provided_hash) + { + // --- 8b. Remove the commit from the queue. + commits.remove(position); + + // --- 8c. Proceed to set the revealed weights. + Self::do_set_weights(origin.clone(), netuid, uids, values, version_key)?; + + // --- 8d. Collect the revealed hash. + revealed_hashes.push(provided_hash); + } else if expired_hashes.contains(&provided_hash) { + return Err(Error::::ExpiredWeightCommit.into()); + } else { + return Err(Error::::InvalidRevealCommitHashNotMatch.into()); + } + } + + // --- 9. If the queue is now empty, remove the storage entry for the user. if commits.is_empty() { *maybe_commits = None; } - // --- 8. Return ok. + // --- 10. Emit the WeightsBatchRevealed event with all revealed hashes. + Self::deposit_event(Event::WeightsBatchRevealed( + who.clone(), + netuid, + revealed_hashes, + )); + + // --- 11. Return ok. Ok(()) }) } @@ -464,10 +540,12 @@ impl Pallet { // --- 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), - Error::::SettingWeightsTooFast - ); + if !Self::get_commit_reveal_weights_enabled(netuid) { + ensure!( + Self::check_rate_limit(netuid, neuron_uid, current_block), + Error::::SettingWeightsTooFast + ); + } // --- 10. Check that the neuron uid is an allowed validator permitted to set non-self weights. ensure!( @@ -509,7 +587,9 @@ impl Pallet { 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); + if !Self::get_commit_reveal_weights_enabled(netuid) { + Self::set_last_update_for_uid(netuid, neuron_uid, current_block); + } // --- 19. Emit the tracking event. log::debug!( @@ -703,6 +783,23 @@ impl Pallet { current_epoch > commit_epoch.saturating_add(reveal_period) } + pub fn get_reveal_blocks(netuid: u16, commit_block: u64) -> (u64, u64) { + let reveal_period: u64 = Self::get_reveal_period(netuid); + let tempo: u64 = Self::get_tempo(netuid) as u64; + let tempo_plus_one: u64 = tempo.saturating_add(1); + let netuid_plus_one: u64 = (netuid as u64).saturating_add(1); + + let commit_epoch: u64 = Self::get_epoch_index(netuid, commit_block); + let reveal_epoch: u64 = commit_epoch.saturating_add(reveal_period); + + let first_reveal_block = reveal_epoch + .saturating_mul(tempo_plus_one) + .saturating_sub(netuid_plus_one); + let last_reveal_block = first_reveal_block.saturating_add(tempo); + + (first_reveal_block, last_reveal_block) + } + pub fn set_reveal_period(netuid: u16, reveal_period: u64) { RevealPeriodEpochs::::insert(netuid, reveal_period); } diff --git a/pallets/subtensor/src/swap/swap_hotkey.rs b/pallets/subtensor/src/swap/swap_hotkey.rs index ca3d0b5a7..efa6c53f8 100644 --- a/pallets/subtensor/src/swap/swap_hotkey.rs +++ b/pallets/subtensor/src/swap/swap_hotkey.rs @@ -206,33 +206,42 @@ impl Pallet { Delegates::::insert(new_hotkey, old_delegate_take); weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); } - // 9. Swap all subnet specific info. + + // 9. swap PendingdHotkeyEmission + if PendingdHotkeyEmission::::contains_key(old_hotkey) { + let old_pending_hotkey_emission = PendingdHotkeyEmission::::get(old_hotkey); + PendingdHotkeyEmission::::remove(old_hotkey); + PendingdHotkeyEmission::::insert(new_hotkey, old_pending_hotkey_emission); + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + } + + // 10. Swap all subnet specific info. let all_netuids: Vec = Self::get_all_subnet_netuids(); for netuid in all_netuids { - // 9.1 Remove the previous hotkey and insert the new hotkey from membership. + // 10.1 Remove the previous hotkey and insert the new hotkey from membership. // IsNetworkMember( hotkey, netuid ) -> bool -- is the hotkey a subnet member. let is_network_member: bool = IsNetworkMember::::get(old_hotkey, netuid); IsNetworkMember::::remove(old_hotkey, netuid); IsNetworkMember::::insert(new_hotkey, netuid, is_network_member); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - // 9.2 Swap Uids + Keys. + // 10.2 Swap Uids + Keys. // Keys( netuid, hotkey ) -> uid -- the uid the hotkey has in the network if it is a member. // Uids( netuid, hotkey ) -> uid -- the uids that the hotkey has. if is_network_member { - // 9.2.1 Swap the UIDS + // 10.2.1 Swap the UIDS if let Ok(old_uid) = Uids::::try_get(netuid, old_hotkey) { Uids::::remove(netuid, old_hotkey); Uids::::insert(netuid, new_hotkey, old_uid); weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2)); - // 9.2.2 Swap the keys. + // 10.2.2 Swap the keys. Keys::::insert(netuid, old_uid, new_hotkey.clone()); weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1)); } } - // 9.3 Swap Prometheus. + // 10.3 Swap Prometheus. // Prometheus( netuid, hotkey ) -> prometheus -- the prometheus data that a hotkey has in the network. if is_network_member { if let Ok(old_prometheus_info) = Prometheus::::try_get(netuid, old_hotkey) { @@ -242,7 +251,7 @@ impl Pallet { } } - // 9.4. Swap axons. + // 10.4. Swap axons. // Axons( netuid, hotkey ) -> axon -- the axon that the hotkey has. if is_network_member { if let Ok(old_axon_info) = Axons::::try_get(netuid, old_hotkey) { @@ -252,7 +261,7 @@ impl Pallet { } } - // 9.5 Swap WeightCommits + // 10.5 Swap WeightCommits // WeightCommits( hotkey ) --> Vec -- the weight commits for the hotkey. if is_network_member { if let Ok(old_weight_commits) = WeightCommits::::try_get(netuid, old_hotkey) { @@ -262,7 +271,7 @@ impl Pallet { } } - // 9.6. Swap the subnet loaded emission. + // 10.6. Swap the subnet loaded emission. // LoadedEmission( netuid ) --> Vec<(hotkey, u64)> -- the loaded emission for the subnet. if is_network_member { if let Some(mut old_loaded_emission) = LoadedEmission::::get(netuid) { @@ -277,7 +286,7 @@ impl Pallet { } } - // 9.7. Swap neuron TLS certificates. + // 10.7. Swap neuron TLS certificates. // NeuronCertificates( netuid, hotkey ) -> Vec -- the neuron certificate for the hotkey. if is_network_member { if let Ok(old_neuron_certificates) = @@ -290,7 +299,7 @@ impl Pallet { } } - // 10. Swap Stake. + // 11. Swap Stake. // Stake( hotkey, coldkey ) -> stake -- the stake that the hotkey controls on behalf of the coldkey. let stakes: Vec<(T::AccountId, u64)> = Stake::::iter_prefix(old_hotkey).collect(); // Clear the entire old prefix here. @@ -320,7 +329,7 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); } - // 11. Swap ChildKeys. + // 12. Swap ChildKeys. // ChildKeys( parent, netuid ) --> Vec<(proportion,child)> -- the child keys of the parent. for netuid in Self::get_all_subnet_netuids() { // Get the children of the old hotkey for this subnet @@ -331,7 +340,7 @@ impl Pallet { ChildKeys::::insert(new_hotkey, netuid, my_children); } - // 12. Swap ParentKeys. + // 13. Swap ParentKeys. // ParentKeys( child, netuid ) --> Vec<(proportion,parent)> -- the parent keys of the child. for netuid in Self::get_all_subnet_netuids() { // Get the parents of the old hotkey for this subnet @@ -355,6 +364,19 @@ impl Pallet { } } + // 14. Swap Stake Delta for all coldkeys. + for (coldkey, stake_delta) in StakeDeltaSinceLastEmissionDrain::::iter_prefix(old_hotkey) + { + let new_stake_delta = StakeDeltaSinceLastEmissionDrain::::get(new_hotkey, &coldkey); + StakeDeltaSinceLastEmissionDrain::::insert( + new_hotkey, + &coldkey, + new_stake_delta.saturating_add(stake_delta), + ); + StakeDeltaSinceLastEmissionDrain::::remove(old_hotkey, &coldkey); + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + } + // Return successful after swapping all the relevant terms. Ok(()) } diff --git a/pallets/subtensor/tests/migration.rs b/pallets/subtensor/tests/migration.rs index 1317bfb0f..4ddef882c 100644 --- a/pallets/subtensor/tests/migration.rs +++ b/pallets/subtensor/tests/migration.rs @@ -446,7 +446,7 @@ fn test_migrate_commit_reveal_2() { // ------------------------------ // Step 1: Simulate Old Storage Entries // ------------------------------ - const MIGRATION_NAME: &str = "migrate_commit_reveal_2"; + const MIGRATION_NAME: &str = "migrate_commit_reveal_2_v2"; let pallet_prefix = twox_128("SubtensorModule".as_bytes()); let storage_prefix_interval = twox_128("WeightCommitRevealInterval".as_bytes()); diff --git a/pallets/subtensor/tests/swap_hotkey.rs b/pallets/subtensor/tests/swap_hotkey.rs index bf5ecb301..ad4d0414c 100644 --- a/pallets/subtensor/tests/swap_hotkey.rs +++ b/pallets/subtensor/tests/swap_hotkey.rs @@ -351,8 +351,8 @@ fn test_swap_weight_commits() { let new_hotkey = U256::from(2); let coldkey = U256::from(3); let netuid = 0u16; - let mut weight_commits: VecDeque<(H256, u64)> = VecDeque::new(); - weight_commits.push_back((H256::from_low_u64_be(100), 200)); + let mut weight_commits: VecDeque<(H256, u64, u64, u64)> = VecDeque::new(); + weight_commits.push_back((H256::from_low_u64_be(100), 200, 1, 1)); let mut weight = Weight::zero(); add_network(netuid, 0, 1); diff --git a/pallets/subtensor/tests/weights.rs b/pallets/subtensor/tests/weights.rs index ddc2ccd77..7dbeba288 100644 --- a/pallets/subtensor/tests/weights.rs +++ b/pallets/subtensor/tests/weights.rs @@ -1815,7 +1815,7 @@ fn test_toggle_commit_reveal_weights_and_set_weights() { #[test] fn test_tempo_change_during_commit_reveal_process() { - new_test_ext(1).execute_with(|| { + new_test_ext(0).execute_with(|| { let netuid: u16 = 1; let uids: Vec = vec![0, 1]; let weight_values: Vec = vec![10, 10]; @@ -1832,7 +1832,7 @@ fn test_tempo_change_during_commit_reveal_process() { version_key, )); - System::set_block_number(1); + System::set_block_number(0); let tempo: u16 = 100; add_network(netuid, tempo, 0); @@ -2432,7 +2432,7 @@ fn test_expired_commits_handling_in_commit_and_reveal() { )); // 6. Verify that the number of unrevealed, non-expired commits is now 6 - let commits: VecDeque<(H256, u64)> = + let commits: VecDeque<(H256, u64, u64, u64)> = pallet_subtensor::WeightCommits::::get(netuid, hotkey) .expect("Expected a commit"); assert_eq!(commits.len(), 6); // 5 non-expired commits from epoch 1 + new commit @@ -3584,7 +3584,7 @@ fn test_batch_reveal_with_out_of_order_commits() { SubtensorModule::set_validator_permit_for_uid(netuid, 0, true); SubtensorModule::set_validator_permit_for_uid(netuid, 1, true); - // 1. Commit multiple times + // 1. Commit multiple times (A, B, C) let mut commit_info = Vec::new(); for i in 0..3 { let salt: Vec = vec![i as u16; 8]; @@ -3606,25 +3606,25 @@ fn test_batch_reveal_with_out_of_order_commits() { step_epochs(1, netuid); - // 2. Prepare batch reveal parameters out of order + // 2. Prepare batch reveal parameters for commits A and C (out of order) let salts_list: Vec> = vec![ - commit_info[2].1.clone(), // Third commit - commit_info[0].1.clone(), // First commit - commit_info[1].1.clone(), // Second commit + commit_info[2].1.clone(), // Third commit (C) + commit_info[0].1.clone(), // First commit (A) ]; let uids_list_out_of_order = vec![ - uids_list[2].clone(), - uids_list[0].clone(), - uids_list[1].clone(), + uids_list[2].clone(), // C + uids_list[0].clone(), // A ]; let weight_values_list_out_of_order = vec![ - weight_values_list[2].clone(), - weight_values_list[0].clone(), - weight_values_list[1].clone(), + weight_values_list[2].clone(), // C + weight_values_list[0].clone(), // A + ]; + let version_keys_out_of_order = vec![ + version_keys[2], // C + version_keys[0], // A ]; - let version_keys_out_of_order = vec![version_keys[2], version_keys[0], version_keys[1]]; - // 3. Attempt batch reveal out of order + // 3. Attempt batch reveal of A and C out of order let result = SubtensorModule::do_batch_reveal_weights( RuntimeOrigin::signed(hotkey), netuid, @@ -3634,44 +3634,25 @@ fn test_batch_reveal_with_out_of_order_commits() { version_keys_out_of_order, ); - // 4. Ensure the batch reveal fails with InvalidRevealCommitHashNotMatch - assert_err!(result, Error::::InvalidRevealCommitHashNotMatch); - - // 5. Reveal the first commit to proceed correctly - let first_salt = commit_info[0].1.clone(); - let first_uids = uids_list[0].clone(); - let first_weights = weight_values_list[0].clone(); - let first_version_key = version_keys[0]; - - assert_ok!(SubtensorModule::do_batch_reveal_weights( - RuntimeOrigin::signed(hotkey), - netuid, - vec![first_uids], - vec![first_weights], - vec![first_salt], - vec![first_version_key], - )); + // 4. Ensure the batch reveal succeeds + assert_ok!(result); - // 6. Now attempt to reveal the remaining commits in order - let remaining_salts = vec![ - commit_info[1].1.clone(), // Second commit - commit_info[2].1.clone(), // Third commit - ]; - let remaining_uids_list = vec![uids_list[1].clone(), uids_list[2].clone()]; - let remaining_weight_values_list = - vec![weight_values_list[1].clone(), weight_values_list[2].clone()]; - let remaining_version_keys = vec![version_keys[1], version_keys[2]]; + // 5. Prepare and reveal the remaining commit (B) + let remaining_salt = commit_info[1].1.clone(); + let remaining_uids = uids_list[1].clone(); + let remaining_weights = weight_values_list[1].clone(); + let remaining_version_key = version_keys[1]; assert_ok!(SubtensorModule::do_batch_reveal_weights( RuntimeOrigin::signed(hotkey), netuid, - remaining_uids_list, - remaining_weight_values_list, - remaining_salts, - remaining_version_keys, + vec![remaining_uids], + vec![remaining_weights], + vec![remaining_salt], + vec![remaining_version_key], )); - // 7. Ensure all commits are removed + // 6. Ensure all commits are removed let commits = pallet_subtensor::WeightCommits::::get(netuid, hotkey); assert!(commits.is_none()); }); @@ -3954,3 +3935,256 @@ fn test_highly_concurrent_commits_and_reveals_with_multiple_hotkeys() { assert_eq!(SubtensorModule::get_tempo(netuid), 200); }) } + +#[test] +fn test_get_reveal_blocks() { + new_test_ext(1).execute_with(|| { + // **1. Define Test Parameters** + let netuid: u16 = 1; + let uids: Vec = vec![0, 1]; + let weight_values: Vec = vec![10, 10]; + let salt: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8]; + let version_key: u64 = 0; + let hotkey: U256 = U256::from(1); + + // **2. Generate the Commit Hash** + let commit_hash: H256 = BlakeTwo256::hash_of(&( + hotkey, + netuid, + uids.clone(), + weight_values.clone(), + salt.clone(), + version_key, + )); + + // **3. Initialize the Block Number to 0** + System::set_block_number(0); + + // **4. Define Network Parameters** + let tempo: u16 = 5; + add_network(netuid, tempo, 0); + + // **5. Register Neurons and Configure the Network** + register_ok_neuron(netuid, U256::from(3), U256::from(4), 300_000); + register_ok_neuron(netuid, U256::from(1), U256::from(2), 100_000); + 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_commit_reveal_weights_enabled(netuid, true); + + // **6. Commit Weights at Block 0** + assert_ok!(SubtensorModule::commit_weights( + RuntimeOrigin::signed(hotkey), + netuid, + commit_hash + )); + + // **7. Retrieve the Reveal Blocks Using `get_reveal_blocks`** + let (first_reveal_block, last_reveal_block) = SubtensorModule::get_reveal_blocks(netuid, 0); + + // **8. Assert Correct Calculation of Reveal Blocks** + // With tempo=5, netuid=1, reveal_period=1: + // commit_epoch = (0 + 2) / 6 = 0 + // reveal_epoch = 0 + 1 = 1 + // first_reveal_block = 1 * 6 - 2 = 4 + // last_reveal_block = 4 + 5 = 9 + assert_eq!(first_reveal_block, 4); + assert_eq!(last_reveal_block, 9); + + // **9. Attempt to Reveal Before `first_reveal_block` (Block 3)** + step_block(3); // Advance to block 3 + let result = SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids.clone(), + weight_values.clone(), + salt.clone(), + version_key, + ); + assert_err!(result, Error::::RevealTooEarly); + + // **10. Advance to `first_reveal_block` (Block 4)** + step_block(1); // Advance to block 4 + let result = SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids.clone(), + weight_values.clone(), + salt.clone(), + version_key, + ); + assert_ok!(result); + + // **11. Attempt to Reveal Again at Block 4 (Should Fail)** + let result = SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids.clone(), + weight_values.clone(), + salt.clone(), + version_key, + ); + assert_err!(result, Error::::NoWeightsCommitFound); + + // **12. Advance to After `last_reveal_block` (Block 10)** + step_block(6); // Advance from block 4 to block 10 + + // **13. Attempt to Reveal at Block 10 (Should Fail)** + let result = SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids.clone(), + weight_values.clone(), + salt.clone(), + version_key, + ); + assert_err!(result, Error::::NoWeightsCommitFound); + + // **14. Attempt to Reveal Outside of Any Reveal Window (No Commit)** + let result = SubtensorModule::reveal_weights( + RuntimeOrigin::signed(hotkey), + netuid, + uids.clone(), + weight_values.clone(), + salt.clone(), + version_key, + ); + assert_err!(result, Error::::NoWeightsCommitFound); + + // **15. Verify that All Commits Have Been Removed from Storage** + let commits = pallet_subtensor::WeightCommits::::get(netuid, hotkey); + assert!( + commits.is_none(), + "Commits should be cleared after successful reveal" + ); + }) +} + +#[test] +fn test_commit_weights_rate_limit() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let uids: Vec = vec![0, 1]; + let weight_values: Vec = vec![10, 10]; + let salt: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8]; + 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(), + salt.clone(), + version_key, + )); + System::set_block_number(11); + + let tempo: u16 = 5; + add_network(netuid, tempo, 0); + + register_ok_neuron(netuid, U256::from(3), U256::from(4), 300_000); + register_ok_neuron(netuid, U256::from(1), U256::from(2), 100_000); + SubtensorModule::set_weights_set_rate_limit(netuid, 10); // Rate limit is 10 blocks + SubtensorModule::set_validator_permit_for_uid(netuid, 0, true); + SubtensorModule::set_validator_permit_for_uid(netuid, 1, true); + SubtensorModule::set_commit_reveal_weights_enabled(netuid, true); + + let neuron_uid = + SubtensorModule::get_uid_for_net_and_hotkey(netuid, &hotkey).expect("expected uid"); + SubtensorModule::set_last_update_for_uid(netuid, neuron_uid, 0); + + assert_ok!(SubtensorModule::commit_weights( + RuntimeOrigin::signed(hotkey), + netuid, + commit_hash + )); + + let new_salt: Vec = vec![9; 8]; + let new_commit_hash: H256 = BlakeTwo256::hash_of(&( + hotkey, + netuid, + uids.clone(), + weight_values.clone(), + new_salt.clone(), + version_key, + )); + assert_err!( + SubtensorModule::commit_weights(RuntimeOrigin::signed(hotkey), netuid, new_commit_hash), + Error::::CommittingWeightsTooFast + ); + + step_block(5); + assert_err!( + SubtensorModule::commit_weights(RuntimeOrigin::signed(hotkey), netuid, new_commit_hash), + Error::::CommittingWeightsTooFast + ); + + step_block(5); // Current block is now 21 + + assert_ok!(SubtensorModule::commit_weights( + RuntimeOrigin::signed(hotkey), + netuid, + new_commit_hash + )); + + SubtensorModule::set_commit_reveal_weights_enabled(netuid, false); + let weights_keys: Vec = vec![0]; + let weight_values: Vec = vec![1]; + + assert_err!( + SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey), + netuid, + weights_keys.clone(), + weight_values.clone(), + 0 + ), + Error::::SettingWeightsTooFast + ); + + step_block(10); + + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey), + netuid, + weights_keys.clone(), + weight_values.clone(), + 0 + )); + + assert_err!( + SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey), + netuid, + weights_keys.clone(), + weight_values.clone(), + 0 + ), + Error::::SettingWeightsTooFast + ); + + step_block(5); + + assert_err!( + SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey), + netuid, + weights_keys.clone(), + weight_values.clone(), + 0 + ), + Error::::SettingWeightsTooFast + ); + + step_block(5); + + assert_ok!(SubtensorModule::set_weights( + RuntimeOrigin::signed(hotkey), + netuid, + weights_keys.clone(), + weight_values.clone(), + 0 + )); + }); +} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 6990cb907..7d33bff03 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -146,7 +146,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: 197, + spec_version: 205, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -956,7 +956,7 @@ parameter_types! { pub const SubtensorInitialNetworkLockReductionInterval: u64 = 14 * 7200; pub const SubtensorInitialNetworkRateLimit: u64 = 7200; pub const SubtensorInitialTargetStakesPerInterval: u16 = 1; - pub const SubtensorInitialKeySwapCost: u64 = 1_000_000_000; + pub const SubtensorInitialKeySwapCost: u64 = 100_000_000; // 0.1 TAO pub const InitialAlphaHigh: u16 = 58982; // Represents 0.9 as per the production default pub const InitialAlphaLow: u16 = 45875; // Represents 0.7 as per the production default pub const InitialLiquidAlphaOn: bool = false; // Default value for LiquidAlphaOn diff --git a/scripts/localnet.sh b/scripts/localnet.sh index 51e3d05a8..793506597 100755 --- a/scripts/localnet.sh +++ b/scripts/localnet.sh @@ -72,7 +72,7 @@ alice_start=( --chain="$FULL_PATH" --alice --port 30334 - --rpc-port 9946 + --rpc-port 9944 --validator --rpc-cors=all --allow-private-ipv4