From 847da3d766b8575afd0aeeed6098e9690fefff8a Mon Sep 17 00:00:00 2001 From: Keith Date: Fri, 24 May 2024 23:47:51 +0800 Subject: [PATCH 1/2] Ban unsafe arithmetic operations --- Cargo.toml | 3 + node/src/chain_spec/finney.rs | 6 +- node/src/chain_spec/testnet.rs | 6 +- pallets/admin-utils/src/benchmarking.rs | 1 + pallets/admin-utils/tests/mock.rs | 2 + pallets/collective/src/benchmarking.rs | 3 +- pallets/collective/src/lib.rs | 29 +++-- pallets/collective/src/tests.rs | 2 +- pallets/commitments/src/benchmarking.rs | 7 +- pallets/commitments/src/lib.rs | 13 ++- pallets/commitments/src/types.rs | 7 +- pallets/registry/src/benchmarking.rs | 7 +- pallets/registry/src/lib.rs | 15 +-- pallets/registry/src/types.rs | 7 +- pallets/subtensor/src/benchmarks.rs | 2 +- pallets/subtensor/src/block_step.rs | 95 ++++++++++------ pallets/subtensor/src/delegate_info.rs | 10 +- pallets/subtensor/src/epoch.rs | 36 +++--- pallets/subtensor/src/lib.rs | 29 +++-- pallets/subtensor/src/math.rs | 145 +++++++++++++++--------- pallets/subtensor/src/migration.rs | 11 +- pallets/subtensor/src/registration.rs | 32 +++--- pallets/subtensor/src/root.rs | 56 +++++---- pallets/subtensor/src/serving.rs | 4 +- pallets/subtensor/src/staking.rs | 6 +- pallets/subtensor/src/subnet_info.rs | 2 +- pallets/subtensor/src/uids.rs | 8 +- pallets/subtensor/src/utils.rs | 4 +- pallets/subtensor/src/weights.rs | 23 ++-- pallets/subtensor/tests/block_step.rs | 3 +- pallets/subtensor/tests/difficulty.rs | 2 + pallets/subtensor/tests/epoch.rs | 6 + pallets/subtensor/tests/migration.rs | 2 + pallets/subtensor/tests/mock.rs | 8 +- pallets/subtensor/tests/registration.rs | 2 + pallets/subtensor/tests/root.rs | 2 + pallets/subtensor/tests/senate.rs | 2 + pallets/subtensor/tests/staking.rs | 2 + pallets/subtensor/tests/uids.rs | 2 + pallets/subtensor/tests/weights.rs | 2 + runtime/src/check_nonce.rs | 5 +- runtime/src/lib.rs | 13 ++- runtime/tests/metadata.rs | 2 + runtime/tests/pallet_proxy.rs | 2 + 44 files changed, 398 insertions(+), 228 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 56e40c924..51849096a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,10 @@ members = [ resolver = "2" [workspace.lints.clippy] +indexing-slicing = "deny" +arithmetic-side-effects = "deny" type_complexity = "allow" +unwrap-used = "deny" [workspace.dependencies] cargo-husky = { version = "1", default-features = false } diff --git a/node/src/chain_spec/finney.rs b/node/src/chain_spec/finney.rs index 37fa1b073..3694c3d39 100644 --- a/node/src/chain_spec/finney.rs +++ b/node/src/chain_spec/finney.rs @@ -5,7 +5,7 @@ use super::*; pub fn finney_mainnet_config() -> Result { let path: PathBuf = std::path::PathBuf::from("./snapshot.json"); - let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; + let wasm_binary = WASM_BINARY.ok_or("Development wasm not available".to_string())?; // We mmap the file into memory first, as this is *a lot* faster than using // `serde_json::from_reader`. See https://github.com/serde-rs/json/issues/160 @@ -53,7 +53,9 @@ pub fn finney_mainnet_config() -> Result { let key_account = sp_runtime::AccountId32::from(key); processed_balances.push((key_account, *amount)); - balances_issuance += *amount; + balances_issuance = balances_issuance + .checked_add(*amount) + .ok_or("Balances issuance overflowed".to_string())?; } // Give front-ends necessary data to present to users diff --git a/node/src/chain_spec/testnet.rs b/node/src/chain_spec/testnet.rs index 01c95c376..ff6c8cc39 100644 --- a/node/src/chain_spec/testnet.rs +++ b/node/src/chain_spec/testnet.rs @@ -20,7 +20,7 @@ pub fn finney_testnet_config() -> Result { }; let old_state: ColdkeyHotkeys = - json::from_slice(&bytes).map_err(|e| format!("Error parsing genesis file: {}", e))?; + json::from_slice(&bytes).map_err(|e| format!("Error parsing genesis file: {e}"))?; let mut processed_stakes: Vec<( sp_runtime::AccountId32, @@ -53,7 +53,9 @@ pub fn finney_testnet_config() -> Result { let key_account = sp_runtime::AccountId32::from(key); processed_balances.push((key_account, *amount)); - balances_issuance += *amount; + balances_issuance = balances_issuance + .checked_add(*amount) + .ok_or("Balances issuance overflowed".to_string())?; } // Give front-ends necessary data to present to users diff --git a/pallets/admin-utils/src/benchmarking.rs b/pallets/admin-utils/src/benchmarking.rs index 756864940..0158311f7 100644 --- a/pallets/admin-utils/src/benchmarking.rs +++ b/pallets/admin-utils/src/benchmarking.rs @@ -1,5 +1,6 @@ //! Benchmarking setup #![cfg(feature = "runtime-benchmarks")] +#![allow(clippy::arithmetic_side_effects)] use super::*; #[allow(unused)] diff --git a/pallets/admin-utils/tests/mock.rs b/pallets/admin-utils/tests/mock.rs index c0985b010..c6c3d7323 100644 --- a/pallets/admin-utils/tests/mock.rs +++ b/pallets/admin-utils/tests/mock.rs @@ -1,3 +1,5 @@ +#![allow(clippy::arithmetic_side_effects, clippy::unwrap_used)] + use frame_support::{ assert_ok, derive_impl, parameter_types, traits::{Everything, Hooks}, diff --git a/pallets/collective/src/benchmarking.rs b/pallets/collective/src/benchmarking.rs index cf44e9948..380a78395 100644 --- a/pallets/collective/src/benchmarking.rs +++ b/pallets/collective/src/benchmarking.rs @@ -16,6 +16,7 @@ // limitations under the License. //! Staking pallet benchmarking. +#![allow(clippy::arithmetic_side_effects, clippy::indexing_slicing)] use super::*; use crate::Pallet as Collective; @@ -70,7 +71,7 @@ benchmarks_instance_pallet! { // Proposals should be different so that different proposal hashes are generated let proposal: T::Proposal = SystemCall::::remark { remark: id_to_remark_data(i, length) }.into(); Collective::::propose( - SystemOrigin::Signed(old_members.last().unwrap().clone()).into(), + SystemOrigin::Signed(old_members.last().expect("m is greater than 0; old_members must have at least 1 element; qed").clone()).into(), Box::new(proposal.clone()), MAX_BYTES, TryInto::>::try_into(3u64).ok().expect("convert u64 to block number.") diff --git a/pallets/collective/src/lib.rs b/pallets/collective/src/lib.rs index c1bcad3e7..3be6529e0 100644 --- a/pallets/collective/src/lib.rs +++ b/pallets/collective/src/lib.rs @@ -54,7 +54,7 @@ use frame_support::{ use scale_info::TypeInfo; use sp_io::storage; use sp_runtime::traits::Dispatchable; -use sp_runtime::{traits::Hash, RuntimeDebug}; +use sp_runtime::{traits::Hash, RuntimeDebug, Saturating}; use sp_std::{marker::PhantomData, prelude::*, result}; #[cfg(test)] @@ -119,7 +119,7 @@ impl DefaultVote for MoreThanMajorityThenPrimeDefaultVote { _no_votes: MemberCount, len: MemberCount, ) -> bool { - let more_than_majority = yes_votes * 2 > len; + let more_than_majority = yes_votes.saturating_mul(2) > len; more_than_majority || prime_vote.unwrap_or(false) } } @@ -545,7 +545,9 @@ pub mod pallet { Error::::DurationLowerThanConfiguredMotionDuration ); - let threshold = (T::GetVotingMembers::get_count() / 2) + 1; + let threshold = T::GetVotingMembers::get_count() + .saturating_div(2) + .saturating_add(1); let members = Self::members(); let (proposal_len, active_proposals) = @@ -716,10 +718,15 @@ impl, I: 'static> Pallet { })?; let index = Self::proposal_count(); - >::mutate(|i| *i += 1); + >::try_mutate(|i| { + *i = i + .checked_add(1) + .ok_or(Error::::TooManyActiveProposals)?; + Ok::<(), Error>(()) + })?; >::insert(proposal_hash, proposal); let votes = { - let end = frame_system::Pallet::::block_number() + duration; + let end = frame_system::Pallet::::block_number().saturating_add(duration); Votes { index, threshold, @@ -862,10 +869,10 @@ impl, I: 'static> Pallet { // default voting strategy. let default = T::DefaultVote::default_vote(prime_vote, yes_votes, no_votes, seats); - let abstentions = seats - (yes_votes + no_votes); + let abstentions = seats.saturating_sub(yes_votes.saturating_add(no_votes)); match default { - true => yes_votes += abstentions, - false => no_votes += abstentions, + true => yes_votes = yes_votes.saturating_add(abstentions), + false => no_votes = no_votes.saturating_add(abstentions), } let approved = yes_votes >= voting.threshold; @@ -981,7 +988,7 @@ impl, I: 'static> Pallet { Voting::::remove(proposal_hash); let num_proposals = Proposals::::mutate(|proposals| { proposals.retain(|h| h != &proposal_hash); - proposals.len() + 1 // calculate weight based on original length + proposals.len().saturating_add(1) // calculate weight based on original length }); num_proposals as u32 } @@ -1154,7 +1161,7 @@ impl< type Success = (); fn try_origin(o: O) -> Result { o.into().and_then(|o| match o { - RawOrigin::Members(n, m) if n * D > N * m => Ok(()), + RawOrigin::Members(n, m) if n.saturating_mul(D) > N.saturating_mul(m) => Ok(()), r => Err(O::from(r)), }) } @@ -1179,7 +1186,7 @@ impl< type Success = (); fn try_origin(o: O) -> Result { o.into().and_then(|o| match o { - RawOrigin::Members(n, m) if n * D >= N * m => Ok(()), + RawOrigin::Members(n, m) if n.saturating_mul(D) >= N.saturating_mul(m) => Ok(()), r => Err(O::from(r)), }) } diff --git a/pallets/collective/src/tests.rs b/pallets/collective/src/tests.rs index 672556edb..91fca58d4 100644 --- a/pallets/collective/src/tests.rs +++ b/pallets/collective/src/tests.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#![allow(non_camel_case_types)] +#![allow(non_camel_case_types, clippy::indexing_slicing, clippy::unwrap_used)] use super::{Event as CollectiveEvent, *}; use crate as pallet_collective; diff --git a/pallets/commitments/src/benchmarking.rs b/pallets/commitments/src/benchmarking.rs index 1b877a8ce..54247bb9d 100644 --- a/pallets/commitments/src/benchmarking.rs +++ b/pallets/commitments/src/benchmarking.rs @@ -1,5 +1,6 @@ //! Benchmarking setup #![cfg(feature = "runtime-benchmarks")] +#![allow(clippy::arithmetic_side_effects)] use super::*; #[allow(unused)] @@ -17,7 +18,11 @@ fn assert_last_event(generic_event: ::RuntimeEvent) { // This creates an `IdentityInfo` object with `num_fields` extra fields. // All data is pre-populated with some arbitrary bytes. fn create_identity_info(_num_fields: u32) -> CommitmentInfo { - let _data = Data::Raw(vec![0; 32].try_into().unwrap()); + let _data = Data::Raw( + vec![0; 32] + .try_into() + .expect("vec length is less than 64; qed"), + ); CommitmentInfo { fields: Default::default(), diff --git a/pallets/commitments/src/lib.rs b/pallets/commitments/src/lib.rs index dec9177d2..81802b64a 100644 --- a/pallets/commitments/src/lib.rs +++ b/pallets/commitments/src/lib.rs @@ -12,7 +12,7 @@ pub use types::*; pub use weights::WeightInfo; use frame_support::traits::Currency; -use sp_runtime::traits::Zero; +use sp_runtime::{traits::Zero, Saturating}; use sp_std::boxed::Box; type BalanceOf = @@ -136,12 +136,12 @@ pub mod pallet { let cur_block = >::block_number(); if let Some(last_commit) = >::get(netuid, &who) { ensure!( - cur_block >= last_commit + T::RateLimit::get(), + cur_block >= last_commit.saturating_add(T::RateLimit::get()), Error::::CommitmentSetRateLimitExceeded ); } - let fd = >::from(extra_fields) * T::FieldDeposit::get(); + let fd = >::from(extra_fields).saturating_mul(T::FieldDeposit::get()); let mut id = match >::get(netuid, &who) { Some(mut id) => { id.info = *info; @@ -156,12 +156,13 @@ pub mod pallet { }; let old_deposit = id.deposit; - id.deposit = T::InitialDeposit::get() + fd; + id.deposit = T::InitialDeposit::get().saturating_add(fd); if id.deposit > old_deposit { - T::Currency::reserve(&who, id.deposit - old_deposit)?; + T::Currency::reserve(&who, id.deposit.saturating_sub(old_deposit))?; } if old_deposit > id.deposit { - let err_amount = T::Currency::unreserve(&who, old_deposit - id.deposit); + let err_amount = + T::Currency::unreserve(&who, old_deposit.saturating_sub(id.deposit)); debug_assert!(err_amount.is_zero()); } diff --git a/pallets/commitments/src/types.rs b/pallets/commitments/src/types.rs index 6ca9ee603..5a1d0bd64 100644 --- a/pallets/commitments/src/types.rs +++ b/pallets/commitments/src/types.rs @@ -66,7 +66,7 @@ impl Decode for Data { Ok(match b { 0 => Data::None, n @ 1..=129 => { - let mut r: BoundedVec<_, _> = vec![0u8; n as usize - 1] + let mut r: BoundedVec<_, _> = vec![0u8; (n as usize).saturating_sub(1)] .try_into() .expect("bound checked in match arm condition; qed"); input.read(&mut r[..])?; @@ -86,8 +86,8 @@ impl Encode for Data { match self { Data::None => vec![0u8; 1], Data::Raw(ref x) => { - let l = x.len().min(128); - let mut r = vec![l as u8 + 1]; + let l = x.len().min(128) as u8; + let mut r = vec![l.saturating_add(1)]; r.extend_from_slice(&x[..]); r } @@ -344,6 +344,7 @@ impl< } #[cfg(test)] +#[allow(clippy::indexing_slicing, clippy::unwrap_used)] mod tests { use super::*; diff --git a/pallets/registry/src/benchmarking.rs b/pallets/registry/src/benchmarking.rs index bb2c4ac06..ee2088478 100644 --- a/pallets/registry/src/benchmarking.rs +++ b/pallets/registry/src/benchmarking.rs @@ -1,5 +1,6 @@ //! Benchmarking setup #![cfg(feature = "runtime-benchmarks")] +#![allow(clippy::arithmetic_side_effects, clippy::unwrap_used)] use super::*; #[allow(unused)] @@ -19,7 +20,11 @@ fn assert_last_event(generic_event: ::RuntimeEvent) { // This creates an `IdentityInfo` object with `num_fields` extra fields. // All data is pre-populated with some arbitrary bytes. fn create_identity_info(_num_fields: u32) -> IdentityInfo { - let data = Data::Raw(vec![0; 32].try_into().unwrap()); + let data = Data::Raw( + vec![0; 32] + .try_into() + .expect("size does not exceed 64; qed"), + ); IdentityInfo { additional: Default::default(), diff --git a/pallets/registry/src/lib.rs b/pallets/registry/src/lib.rs index e32b1fc5f..bb1518768 100644 --- a/pallets/registry/src/lib.rs +++ b/pallets/registry/src/lib.rs @@ -15,7 +15,7 @@ use frame_support::traits::tokens::{ fungible::{self, MutateHold as _}, Precision, }; -use sp_runtime::traits::Zero; +use sp_runtime::{traits::Zero, Saturating}; use sp_std::boxed::Box; type BalanceOf = @@ -132,7 +132,7 @@ pub mod pallet { Error::::TooManyFieldsInIdentityInfo ); - let fd = >::from(extra_fields) * T::FieldDeposit::get(); + let fd = >::from(extra_fields).saturating_mul(T::FieldDeposit::get()); let mut id = match >::get(&identified) { Some(mut id) => { id.info = *info; @@ -145,23 +145,24 @@ pub mod pallet { }; let old_deposit = id.deposit; - id.deposit = T::InitialDeposit::get() + fd; + id.deposit = T::InitialDeposit::get().saturating_add(fd); if id.deposit > old_deposit { T::Currency::hold( &HoldReason::RegistryIdentity.into(), &who, - id.deposit - old_deposit, + id.deposit.saturating_sub(old_deposit), )?; } if old_deposit > id.deposit { let release_res = T::Currency::release( &HoldReason::RegistryIdentity.into(), &who, - old_deposit - id.deposit, + old_deposit.saturating_sub(id.deposit), Precision::BestEffort, ); - debug_assert!(release_res - .is_ok_and(|released_amount| released_amount == (old_deposit - id.deposit))); + debug_assert!(release_res.is_ok_and( + |released_amount| released_amount == old_deposit.saturating_sub(id.deposit) + )); } >::insert(&identified, id); diff --git a/pallets/registry/src/types.rs b/pallets/registry/src/types.rs index 0573392cd..12ee857d2 100644 --- a/pallets/registry/src/types.rs +++ b/pallets/registry/src/types.rs @@ -67,7 +67,7 @@ impl Decode for Data { Ok(match b { 0 => Data::None, n @ 1..=65 => { - let mut r: BoundedVec<_, _> = vec![0u8; n as usize - 1] + let mut r: BoundedVec<_, _> = vec![0u8; (n as usize).saturating_sub(1)] .try_into() .expect("bound checked in match arm condition; qed"); input.read(&mut r[..])?; @@ -87,8 +87,8 @@ impl Encode for Data { match self { Data::None => vec![0u8; 1], Data::Raw(ref x) => { - let l = x.len().min(64); - let mut r = vec![l as u8 + 1]; + let l = x.len().min(64) as u8; + let mut r = vec![l.saturating_add(1)]; r.extend_from_slice(&x[..]); r } @@ -403,6 +403,7 @@ impl< } #[cfg(test)] +#[allow(clippy::indexing_slicing, clippy::unwrap_used)] mod tests { use super::*; diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index a7dd29fbb..403ba413e 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -1,5 +1,5 @@ //! Subtensor pallet benchmarking. - +#![allow(clippy::arithmetic_side_effects, clippy::unwrap_used)] #![cfg(feature = "runtime-benchmarks")] use crate::Pallet as Subtensor; diff --git a/pallets/subtensor/src/block_step.rs b/pallets/subtensor/src/block_step.rs index 80733e6b7..cdd470cd0 100644 --- a/pallets/subtensor/src/block_step.rs +++ b/pallets/subtensor/src/block_step.rs @@ -1,6 +1,7 @@ use super::*; use frame_support::storage::IterableStorageDoubleMap; use frame_support::storage::IterableStorageMap; +use sp_runtime::Saturating; use substrate_fixed::types::I110F18; use substrate_fixed::types::I64F64; use substrate_fixed::types::I96F32; @@ -27,6 +28,7 @@ impl Pallet { Ok(()) } + #[allow(clippy::arithmetic_side_effects)] /// Helper function which returns the number of blocks remaining before we will run the epoch on this /// network. Networks run their epoch when (block_number + netuid + 1 ) % (tempo + 1) = 0 /// @@ -42,9 +44,13 @@ impl Pallet { if tempo == 0 { return 1000; } - tempo as u64 - (block_number + netuid as u64 + 1) % (tempo as u64 + 1) + (tempo as u64).saturating_sub( + block_number.saturating_add(netuid as u64).saturating_add(1) + % (tempo as u64).saturating_add(1), + ) } + #[allow(clippy::arithmetic_side_effects)] /// Helper function returns the number of tuples to drain on a particular step based on /// the remaining tuples to sink and the block number /// @@ -55,18 +61,20 @@ impl Pallet { n_remaining: usize, ) -> usize { let blocks_until_epoch: u64 = Self::blocks_until_next_epoch(netuid, tempo, block_number); - if blocks_until_epoch / 2 == 0 { + if blocks_until_epoch.saturating_div(2) == 0 { return n_remaining; } // drain all. - if tempo / 2 == 0 { + if tempo.saturating_div(2) == 0 { return n_remaining; } // drain all if n_remaining == 0 { return 0; } // nothing to drain at all. // Else return enough tuples to drain all within half the epoch length. - let to_sink_via_tempo: usize = n_remaining / (tempo as usize / 2); - let to_sink_via_blocks_until_epoch: usize = n_remaining / (blocks_until_epoch as usize / 2); + let to_sink_via_tempo: usize = + n_remaining.saturating_div((tempo as usize).saturating_div(2)); + let to_sink_via_blocks_until_epoch: usize = + n_remaining.saturating_div((blocks_until_epoch as usize).saturating_div(2)); if to_sink_via_tempo > to_sink_via_blocks_until_epoch { to_sink_via_tempo } else { @@ -95,7 +103,7 @@ impl Pallet { *server_amount, *validator_amount, ); - total_emitted += *server_amount + *validator_amount; + total_emitted.saturating_accrue((*server_amount).saturating_add(*validator_amount)); } LoadedEmission::::remove(netuid); TotalIssuance::::put(TotalIssuance::::get().saturating_add(total_emitted)); @@ -142,7 +150,9 @@ impl Pallet { Self::coinbase(cut.to_num::()); } // --- 5. Add remaining amount to the network's pending emission. - PendingEmission::::mutate(netuid, |queued| *queued += remaining.to_num::()); + PendingEmission::::mutate(netuid, |queued| { + queued.saturating_accrue(remaining.to_num::()) + }); log::debug!( "netuid_i: {:?} queued_emission: +{:?} ", netuid, @@ -154,7 +164,7 @@ impl Pallet { // --- 3.1 No epoch, increase blocks since last step and continue, Self::set_blocks_since_last_step( netuid, - Self::get_blocks_since_last_step(netuid) + 1, + Self::get_blocks_since_last_step(netuid).saturating_add(1), ); continue; } @@ -176,7 +186,7 @@ impl Pallet { // --- 9. Check that the emission does not exceed the allowed total. let emission_sum: u128 = emission_tuples_this_block .iter() - .map(|(_account_id, ve, se)| *ve as u128 + *se as u128) + .map(|(_account_id, ve, se)| (*ve as u128).saturating_add(*se as u128)) .sum(); if emission_sum > emission_to_drain as u128 { continue; @@ -208,7 +218,10 @@ impl Pallet { // --- 1. Check if the hotkey is a delegate. If not, we simply pass the stake through to the // coldkey - hotkey account as normal. if !Self::hotkey_is_delegate(hotkey) { - Self::increase_stake_on_hotkey_account(hotkey, server_emission + validator_emission); + Self::increase_stake_on_hotkey_account( + hotkey, + server_emission.saturating_add(validator_emission), + ); return; } // Then this is a delegate, we distribute validator_emission, then server_emission. @@ -218,7 +231,7 @@ impl Pallet { let total_hotkey_stake: u64 = Self::get_total_stake_for_hotkey(hotkey); let delegate_take: u64 = Self::calculate_delegate_proportional_take(hotkey, validator_emission); - let validator_emission_minus_take: u64 = validator_emission - delegate_take; + let validator_emission_minus_take: u64 = validator_emission.saturating_sub(delegate_take); let mut remaining_validator_emission: u64 = validator_emission_minus_take; // 3. -- The remaining emission goes to the owners in proportion to the stake delegated. @@ -244,14 +257,14 @@ impl Pallet { hotkey, stake_proportion ); - remaining_validator_emission -= stake_proportion; + remaining_validator_emission.saturating_reduce(stake_proportion); } // --- 5. Last increase final account balance of delegate after 4, since 5 will change the stake proportion of // the delegate and effect calculation in 4. Self::increase_stake_on_hotkey_account( hotkey, - delegate_take + remaining_validator_emission, + delegate_take.saturating_add(remaining_validator_emission), ); log::debug!("delkey: {:?} delegate_take: +{:?} ", hotkey, delegate_take); // Also emit the server_emission to the hotkey @@ -311,8 +324,10 @@ impl Pallet { if total_stake == 0 { return 0; }; - let stake_proportion: I64F64 = I64F64::from_num(stake) / I64F64::from_num(total_stake); - let proportional_emission: I64F64 = I64F64::from_num(emission) * stake_proportion; + let stake_proportion: I64F64 = + I64F64::from_num(stake).saturating_div(I64F64::from_num(total_stake)); + let proportional_emission: I64F64 = + I64F64::from_num(emission).saturating_mul(stake_proportion); proportional_emission.to_num::() } @@ -320,9 +335,9 @@ impl Pallet { /// pub fn calculate_delegate_proportional_take(hotkey: &T::AccountId, emission: u64) -> u64 { if Self::hotkey_is_delegate(hotkey) { - let take_proportion: I64F64 = - I64F64::from_num(Delegates::::get(hotkey)) / I64F64::from_num(u16::MAX); - let take_emission: I64F64 = take_proportion * I64F64::from_num(emission); + let take_proportion: I64F64 = I64F64::from_num(Delegates::::get(hotkey)) + .saturating_div(I64F64::from_num(u16::MAX)); + let take_emission: I64F64 = take_proportion.saturating_mul(I64F64::from_num(emission)); take_emission.to_num::() } else { 0 @@ -349,7 +364,7 @@ impl Pallet { // --- 3. Check if we are at the adjustment interval for this network. // If so, we need to adjust the registration difficulty based on target and actual registrations. - if (current_block - last_adjustment_block) >= adjustment_interval as u64 { + if current_block.saturating_sub(last_adjustment_block) >= adjustment_interval as u64 { log::debug!("interval reached."); // --- 4. Get the current counters for this network w.r.t burn and difficulty values. @@ -496,14 +511,21 @@ impl Pallet { target_registrations_per_interval: u16, ) -> u64 { let updated_difficulty: I110F18 = I110F18::from_num(current_difficulty) - * I110F18::from_num(registrations_this_interval + target_registrations_per_interval) - / I110F18::from_num( - target_registrations_per_interval + target_registrations_per_interval, + .saturating_mul(I110F18::from_num( + registrations_this_interval.saturating_add(target_registrations_per_interval), + )) + .saturating_div(I110F18::from_num( + target_registrations_per_interval.saturating_add(target_registrations_per_interval), + )); + let alpha: I110F18 = I110F18::from_num(Self::get_adjustment_alpha(netuid)) + .saturating_div(I110F18::from_num(u64::MAX)); + let next_value: I110F18 = alpha + .saturating_mul(I110F18::from_num(current_difficulty)) + .saturating_add( + I110F18::from_num(1.0) + .saturating_sub(alpha) + .saturating_mul(updated_difficulty), ); - let alpha: I110F18 = - I110F18::from_num(Self::get_adjustment_alpha(netuid)) / I110F18::from_num(u64::MAX); - let next_value: I110F18 = alpha * I110F18::from_num(current_difficulty) - + (I110F18::from_num(1.0) - alpha) * updated_difficulty; if next_value >= I110F18::from_num(Self::get_max_difficulty(netuid)) { Self::get_max_difficulty(netuid) } else if next_value <= I110F18::from_num(Self::get_min_difficulty(netuid)) { @@ -523,14 +545,21 @@ impl Pallet { target_registrations_per_interval: u16, ) -> u64 { let updated_burn: I110F18 = I110F18::from_num(current_burn) - * I110F18::from_num(registrations_this_interval + target_registrations_per_interval) - / I110F18::from_num( - target_registrations_per_interval + target_registrations_per_interval, + .saturating_mul(I110F18::from_num( + registrations_this_interval.saturating_add(target_registrations_per_interval), + )) + .saturating_div(I110F18::from_num( + target_registrations_per_interval.saturating_add(target_registrations_per_interval), + )); + let alpha: I110F18 = I110F18::from_num(Self::get_adjustment_alpha(netuid)) + .saturating_div(I110F18::from_num(u64::MAX)); + let next_value: I110F18 = alpha + .saturating_mul(I110F18::from_num(current_burn)) + .saturating_add( + I110F18::from_num(1.0) + .saturating_sub(alpha) + .saturating_mul(updated_burn), ); - let alpha: I110F18 = - I110F18::from_num(Self::get_adjustment_alpha(netuid)) / I110F18::from_num(u64::MAX); - let next_value: I110F18 = alpha * I110F18::from_num(current_burn) - + (I110F18::from_num(1.0) - alpha) * updated_burn; if next_value >= I110F18::from_num(Self::get_max_burn_as_u64(netuid)) { Self::get_max_burn_as_u64(netuid) } else if next_value <= I110F18::from_num(Self::get_min_burn_as_u64(netuid)) { diff --git a/pallets/subtensor/src/delegate_info.rs b/pallets/subtensor/src/delegate_info.rs index b33415a3b..1f8b06b69 100644 --- a/pallets/subtensor/src/delegate_info.rs +++ b/pallets/subtensor/src/delegate_info.rs @@ -52,8 +52,9 @@ impl Pallet { let emission: U64F64 = Self::get_emission_for_uid(*netuid, uid).into(); let tempo: U64F64 = Self::get_tempo(*netuid).into(); - let epochs_per_day: U64F64 = U64F64::from_num(7200) / tempo; - emissions_per_day += emission * epochs_per_day; + let epochs_per_day: U64F64 = U64F64::from_num(7200).saturating_div(tempo); + emissions_per_day = + emissions_per_day.saturating_add(emission.saturating_mul(epochs_per_day)); } } @@ -65,8 +66,9 @@ impl Pallet { let mut return_per_1000: U64F64 = U64F64::from_num(0); if total_stake > U64F64::from_num(0) { - return_per_1000 = (emissions_per_day * U64F64::from_num(0.82)) - / (total_stake / U64F64::from_num(1000)); + return_per_1000 = emissions_per_day + .saturating_mul(U64F64::from_num(0.82)) + .saturating_div(total_stake.saturating_div(U64F64::from_num(1000))); } return DelegateInfo { diff --git a/pallets/subtensor/src/epoch.rs b/pallets/subtensor/src/epoch.rs index cc146dd59..cd2666d9d 100644 --- a/pallets/subtensor/src/epoch.rs +++ b/pallets/subtensor/src/epoch.rs @@ -32,7 +32,7 @@ impl Pallet { // Inactive mask. let inactive: Vec = last_update .iter() - .map(|updated| *updated + activity_cutoff < current_block) + .map(|updated| updated.saturating_add(activity_cutoff) < current_block) .collect(); log::trace!("Inactive:\n{:?}\n", inactive.clone()); @@ -175,9 +175,10 @@ impl Pallet { // log::trace!( "ΔB:\n{:?}\n", &bonds_delta ); // Compute bonds moving average. - let bonds_moving_average: I64F64 = - I64F64::from_num(Self::get_bonds_moving_average(netuid)) / I64F64::from_num(1_000_000); - let alpha: I32F32 = I32F32::from_num(1) - I32F32::from_num(bonds_moving_average); + let bonds_moving_average: I64F64 = I64F64::from_num(Self::get_bonds_moving_average(netuid)) + .saturating_div(I64F64::from_num(1_000_000)); + let alpha: I32F32 = + I32F32::from_num(1).saturating_sub(I32F32::from_num(bonds_moving_average)); let mut ema_bonds: Vec> = mat_ema(&bonds_delta, &bonds, alpha); inplace_col_normalize(&mut ema_bonds); // sum_i b_ij = 1 // log::trace!( "emaB:\n{:?}\n", &ema_bonds ); @@ -198,7 +199,7 @@ impl Pallet { let combined_emission: Vec = incentive .iter() .zip(dividends.clone()) - .map(|(ii, di)| ii + di) + .map(|(ii, di)| ii.saturating_add(di)) .collect(); let emission_sum: I32F32 = combined_emission.iter().sum(); @@ -228,7 +229,7 @@ impl Pallet { let server_emission: Vec = normalized_server_emission .iter() - .map(|se: &I32F32| I96F32::from_num(*se) * float_rao_emission) + .map(|se: &I32F32| I96F32::from_num(*se).saturating_mul(float_rao_emission)) .collect(); let server_emission: Vec = server_emission .iter() @@ -237,7 +238,7 @@ impl Pallet { let validator_emission: Vec = normalized_validator_emission .iter() - .map(|ve: &I32F32| I96F32::from_num(*ve) * float_rao_emission) + .map(|ve: &I32F32| I96F32::from_num(*ve).saturating_mul(float_rao_emission)) .collect(); let validator_emission: Vec = validator_emission .iter() @@ -247,7 +248,7 @@ impl Pallet { // Used only to track combined emission in the storage. let combined_emission: Vec = normalized_combined_emission .iter() - .map(|ce: &I32F32| I96F32::from_num(*ce) * float_rao_emission) + .map(|ce: &I32F32| I96F32::from_num(*ce).saturating_mul(float_rao_emission)) .collect(); let combined_emission: Vec = combined_emission .iter() @@ -376,7 +377,7 @@ impl Pallet { // Inactive mask. let inactive: Vec = last_update .iter() - .map(|updated| *updated + activity_cutoff < current_block) + .map(|updated| updated.saturating_add(activity_cutoff) < current_block) .collect(); log::trace!("Inactive: {:?}", inactive.clone()); @@ -535,9 +536,10 @@ impl Pallet { // log::trace!( "ΔB (norm): {:?}", &bonds_delta ); // Compute bonds moving average. - let bonds_moving_average: I64F64 = - I64F64::from_num(Self::get_bonds_moving_average(netuid)) / I64F64::from_num(1_000_000); - let alpha: I32F32 = I32F32::from_num(1) - I32F32::from_num(bonds_moving_average); + let bonds_moving_average: I64F64 = I64F64::from_num(Self::get_bonds_moving_average(netuid)) + .saturating_div(I64F64::from_num(1_000_000)); + let alpha: I32F32 = + I32F32::from_num(1).saturating_sub(I32F32::from_num(bonds_moving_average)); let mut ema_bonds: Vec> = mat_ema_sparse(&bonds_delta, &bonds, alpha); // Normalize EMA bonds. @@ -558,7 +560,7 @@ impl Pallet { let combined_emission: Vec = incentive .iter() .zip(dividends.clone()) - .map(|(ii, di)| ii + di) + .map(|(ii, di)| ii.saturating_add(di)) .collect(); let emission_sum: I32F32 = combined_emission.iter().sum(); @@ -588,7 +590,7 @@ impl Pallet { let server_emission: Vec = normalized_server_emission .iter() - .map(|se: &I32F32| I96F32::from_num(*se) * float_rao_emission) + .map(|se: &I32F32| I96F32::from_num(*se).saturating_mul(float_rao_emission)) .collect(); let server_emission: Vec = server_emission .iter() @@ -597,7 +599,7 @@ impl Pallet { let validator_emission: Vec = normalized_validator_emission .iter() - .map(|ve: &I32F32| I96F32::from_num(*ve) * float_rao_emission) + .map(|ve: &I32F32| I96F32::from_num(*ve).saturating_mul(float_rao_emission)) .collect(); let validator_emission: Vec = validator_emission .iter() @@ -607,7 +609,7 @@ impl Pallet { // Only used to track emission in storage. let combined_emission: Vec = normalized_combined_emission .iter() - .map(|ce: &I32F32| I96F32::from_num(*ce) * float_rao_emission) + .map(|ce: &I32F32| I96F32::from_num(*ce).saturating_mul(float_rao_emission)) .collect(); let combined_emission: Vec = combined_emission .iter() @@ -704,7 +706,7 @@ impl Pallet { I32F32::from_num(Self::get_rho(netuid)) } pub fn get_float_kappa(netuid: u16) -> I32F32 { - I32F32::from_num(Self::get_kappa(netuid)) / I32F32::from_num(u16::MAX) + I32F32::from_num(Self::get_kappa(netuid)).saturating_div(I32F32::from_num(u16::MAX)) } pub fn get_normalized_stake(netuid: u16) -> Vec { diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index b590781f5..ecb02bbeb 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -1144,7 +1144,7 @@ pub mod pallet { // Set max allowed uids MaxAllowedUids::::insert(netuid, max_uids); - let mut next_uid = 0; + let mut next_uid = 0u16; for (coldkey, hotkeys) in self.stakes.iter() { for (hotkey, stake_uid) in hotkeys.iter() { @@ -1183,7 +1183,9 @@ pub mod pallet { Stake::::insert(hotkey.clone(), coldkey.clone(), stake); - next_uid += 1; + next_uid = next_uid.checked_add(1).expect( + "should not have total number of hotkey accounts larger than u16::MAX", + ); } } @@ -1191,7 +1193,11 @@ pub mod pallet { SubnetworkN::::insert(netuid, next_uid); // --- Increase total network count. - TotalNetworks::::mutate(|n| *n += 1); + TotalNetworks::::mutate(|n| { + *n = n.checked_add(1).expect( + "should not have total number of networks larger than u16::MAX in genesis", + ) + }); // Get the root network uid. let root_netuid: u16 = 0; @@ -1200,7 +1206,11 @@ pub mod pallet { NetworksAdded::::insert(root_netuid, true); // Increment the number of total networks. - TotalNetworks::::mutate(|n| *n += 1); + TotalNetworks::::mutate(|n| { + *n = n.checked_add(1).expect( + "should not have total number of networks larger than u16::MAX in genesis", + ) + }); // Set the number of validators to 1. SubnetworkN::::insert(root_netuid, 0); @@ -1213,7 +1223,7 @@ pub mod pallet { // Set the min allowed weights to zero, no weights restrictions. MinAllowedWeights::::insert(root_netuid, 0); - // Set the max weight limit to infitiy, no weight restrictions. + // Set the max weight limit to infinity, no weight restrictions. MaxWeightsLimit::::insert(root_netuid, u16::MAX); // Add default root tempo. @@ -2061,8 +2071,8 @@ pub mod pallet { let _stake = Self::get_total_stake_for_hotkey(hotkey); let current_block_number: u64 = Self::get_current_block_as_u64(); let default_priority: u64 = - current_block_number - Self::get_last_update_for_uid(netuid, uid); - return default_priority + u32::MAX as u64; + current_block_number.saturating_sub(Self::get_last_update_for_uid(netuid, uid)); + return default_priority.saturating_add(u32::MAX as u64); } 0 } @@ -2090,7 +2100,7 @@ pub mod pallet { return false; } if Self::get_registrations_this_interval(netuid) - >= Self::get_target_registrations_per_interval(netuid) * 3 + >= Self::get_target_registrations_per_interval(netuid).saturating_mul(3) { return false; } @@ -2243,7 +2253,8 @@ where Pallet::::get_registrations_this_interval(*netuid); let max_registrations_per_interval = Pallet::::get_target_registrations_per_interval(*netuid); - if registrations_this_interval >= (max_registrations_per_interval * 3) { + if registrations_this_interval >= (max_registrations_per_interval.saturating_mul(3)) + { // If the registration limit for the interval is exceeded, reject the transaction return InvalidTransaction::ExhaustsResources.into(); } diff --git a/pallets/subtensor/src/math.rs b/pallets/subtensor/src/math.rs index e10cc0001..f7784ea1c 100644 --- a/pallets/subtensor/src/math.rs +++ b/pallets/subtensor/src/math.rs @@ -1,4 +1,4 @@ -use sp_runtime::traits::CheckedAdd; +use sp_runtime::{traits::CheckedAdd, Saturating}; use sp_std::vec; use substrate_fixed::transcendental::exp; use substrate_fixed::types::{I32F32, I64F64}; @@ -44,12 +44,12 @@ pub fn u16_to_fixed(x: u16) -> I32F32 { #[allow(dead_code)] pub fn u16_proportion_to_fixed(x: u16) -> I32F32 { - I32F32::from_num(x) / I32F32::from_num(u16::MAX) + I32F32::from_num(x).saturating_div(I32F32::from_num(u16::MAX)) } #[allow(dead_code)] pub fn fixed_proportion_to_u16(x: I32F32) -> u16 { - fixed_to_u16(x * I32F32::from_num(u16::MAX)) + fixed_to_u16(x.saturating_mul(I32F32::from_num(u16::MAX))) } #[allow(dead_code)] @@ -93,25 +93,38 @@ pub fn vec_max_upscale_to_u16(vec: &[I32F32]) -> Vec { if *val == I32F32::from_num(0) { return vec .iter() - .map(|e: &I32F32| (e * u16_max).to_num::()) + .map(|e: &I32F32| e.saturating_mul(u16_max).to_num::()) .collect(); } if *val > threshold { return vec .iter() - .map(|e: &I32F32| (e * (u16_max / *val)).round().to_num::()) + .map(|e: &I32F32| { + e.saturating_mul(u16_max.saturating_div(*val)) + .round() + .to_num::() + }) .collect(); } return vec .iter() - .map(|e: &I32F32| ((e * u16_max) / *val).round().to_num::()) + .map(|e: &I32F32| { + e.saturating_mul(u16_max) + .saturating_div(*val) + .round() + .to_num::() + }) .collect(); } None => { let sum: I32F32 = vec.iter().sum(); return vec .iter() - .map(|e: &I32F32| ((e * u16_max) / sum).to_num::()) + .map(|e: &I32F32| { + e.saturating_mul(u16_max) + .saturating_div(sum) + .to_num::() + }) .collect(); } } @@ -127,7 +140,8 @@ pub fn vec_u16_max_upscale_to_u16(vec: &[u16]) -> Vec { #[allow(dead_code)] // Checks if u16 vector, when normalized, has a max value not greater than a u16 ratio max_limit. pub fn check_vec_max_limited(vec: &[u16], max_limit: u16) -> bool { - let max_limit_fixed: I32F32 = I32F32::from_num(max_limit) / I32F32::from_num(u16::MAX); + let max_limit_fixed: I32F32 = + I32F32::from_num(max_limit).saturating_div(I32F32::from_num(u16::MAX)); let mut vec_fixed: Vec = vec.iter().map(|e: &u16| I32F32::from_num(*e)).collect(); inplace_normalize(&mut vec_fixed); let max_value: Option<&I32F32> = vec_fixed.iter().max(); @@ -196,7 +210,7 @@ pub fn exp_safe(input: I32F32) -> I32F32 { pub fn sigmoid_safe(input: I32F32, rho: I32F32, kappa: I32F32) -> I32F32 { let one: I32F32 = I32F32::from_num(1); let offset: I32F32 = input.saturating_sub(kappa); // (input - kappa) - let neg_rho: I32F32 = rho.saturating_mul(-one); // -rho + let neg_rho: I32F32 = rho.saturating_mul(one.saturating_neg()); // -rho let exp_input: I32F32 = neg_rho.saturating_mul(offset); // -rho*(input-kappa) let exp_output: I32F32 = exp_safe(exp_input); // exp(-rho*(input-kappa)) let denominator: I32F32 = exp_output.saturating_add(one); // 1 + exp(-rho*(input-kappa)) @@ -214,7 +228,7 @@ pub fn is_topk(vector: &[I32F32], k: usize) -> Vec { } let mut idxs: Vec = (0..n).collect(); idxs.sort_by_key(|&idx| &vector[idx]); // ascending stable sort - for &idx in idxs.iter().take(n - k) { + for &idx in idxs.iter().take(n.saturating_sub(k)) { result[idx] = false; } result @@ -225,7 +239,7 @@ pub fn is_topk(vector: &[I32F32], k: usize) -> Vec { pub fn normalize(x: &[I32F32]) -> Vec { let x_sum: I32F32 = sum(x); if x_sum != I32F32::from_num(0.0_f32) { - return x.iter().map(|xi| xi / x_sum).collect(); + return x.iter().map(|xi| xi.saturating_div(x_sum)).collect(); } else { x.to_vec() } @@ -238,7 +252,8 @@ pub fn inplace_normalize(x: &mut [I32F32]) { if x_sum == I32F32::from_num(0.0_f32) { return; } - x.iter_mut().for_each(|value| *value /= x_sum); + x.into_iter() + .for_each(|value| *value = value.saturating_div(x_sum)); } // Normalizes (sum to 1 except 0) the input vector directly in-place, using the sum arg. @@ -247,7 +262,8 @@ pub fn inplace_normalize_using_sum(x: &mut [I32F32], x_sum: I32F32) { if x_sum == I32F32::from_num(0.0_f32) { return; } - x.iter_mut().for_each(|value| *value /= x_sum); + x.into_iter() + .for_each(|value| *value = value.saturating_div(x_sum)); } // Normalizes (sum to 1 except 0) the I64F64 input vector directly in-place. @@ -257,7 +273,8 @@ pub fn inplace_normalize_64(x: &mut [I64F64]) { if x_sum == I64F64::from_num(0) { return; } - x.iter_mut().for_each(|value| *value /= x_sum); + x.into_iter() + .for_each(|value| *value = value.saturating_div(x_sum)); } /// Normalizes (sum to 1 except 0) each row (dim=0) of a I64F64 matrix in-place. @@ -267,7 +284,7 @@ pub fn inplace_row_normalize_64(x: &mut [Vec]) { let row_sum: I64F64 = row.iter().sum(); if row_sum > I64F64::from_num(0.0_f64) { row.iter_mut() - .for_each(|x_ij: &mut I64F64| *x_ij /= row_sum); + .for_each(|x_ij: &mut I64F64| *x_ij = x_ij.saturating_div(row_sum)); } } } @@ -280,7 +297,7 @@ pub fn vecdiv(x: &[I32F32], y: &[I32F32]) -> Vec { .zip(y) .map(|(x_i, y_i)| { if *y_i != 0 { - x_i / y_i + x_i.saturating_div(*y_i) } else { I32F32::from_num(0) } @@ -294,8 +311,8 @@ pub fn inplace_row_normalize(x: &mut [Vec]) { for row in x { let row_sum: I32F32 = row.iter().sum(); if row_sum > I32F32::from_num(0.0_f32) { - row.iter_mut() - .for_each(|x_ij: &mut I32F32| *x_ij /= row_sum); + row.into_iter() + .for_each(|x_ij: &mut I32F32| *x_ij = x_ij.saturating_div(row_sum)); } } } @@ -308,7 +325,7 @@ pub fn inplace_row_normalize_sparse(sparse_matrix: &mut [Vec<(u16, I32F32)>]) { if row_sum > I32F32::from_num(0.0) { sparse_row .iter_mut() - .for_each(|(_j, value)| *value /= row_sum); + .for_each(|(_j, value)| *value = value.saturating_div(row_sum)); } } } @@ -347,7 +364,7 @@ pub fn col_sum(x: &[Vec]) -> Vec { .fold(vec![I32F32::from_num(0); cols], |acc, next_row| { acc.into_iter() .zip(next_row) - .map(|(acc_elem, next_elem)| acc_elem + next_elem) + .map(|(acc_elem, next_elem)| acc_elem.saturating_add(*next_elem)) .collect() }) } @@ -358,7 +375,7 @@ pub fn col_sum_sparse(sparse_matrix: &[Vec<(u16, I32F32)>], columns: u16) -> Vec let mut result: Vec = vec![I32F32::from_num(0); columns as usize]; for sparse_row in sparse_matrix { for (j, value) in sparse_row { - result[*j as usize] += value; + result[*j as usize] = result[*j as usize].saturating_add(*value); } } result @@ -370,7 +387,7 @@ pub fn inplace_col_normalize_sparse(sparse_matrix: &mut [Vec<(u16, I32F32)>], co let mut col_sum: Vec = vec![I32F32::from_num(0.0); columns as usize]; // assume square matrix, rows=cols for sparse_row in sparse_matrix.iter() { for (j, value) in sparse_row.iter() { - col_sum[*j as usize] += value; + col_sum[*j as usize] = col_sum[*j as usize].saturating_add(*value); } } for sparse_row in sparse_matrix { @@ -378,7 +395,7 @@ pub fn inplace_col_normalize_sparse(sparse_matrix: &mut [Vec<(u16, I32F32)>], co if col_sum[*j as usize] == I32F32::from_num(0.0_f32) { continue; } - *value /= col_sum[*j as usize]; + *value = value.saturating_div(col_sum[*j as usize]); } } } @@ -398,7 +415,7 @@ pub fn inplace_col_normalize(x: &mut [Vec]) { .fold(vec![I32F32::from_num(0.0); cols], |acc, row| { row.iter_mut() .zip(acc) - .map(|(&mut m_val, acc_val)| acc_val + m_val) + .map(|(&mut m_val, acc_val)| acc_val.saturating_add(m_val)) .collect() }); x.iter_mut().for_each(|row| { @@ -406,7 +423,7 @@ pub fn inplace_col_normalize(x: &mut [Vec]) { .zip(&col_sums) .filter(|(_, col_sum)| **col_sum != I32F32::from_num(0_f32)) .for_each(|(m_val, col_sum)| { - *m_val /= col_sum; + *m_val = m_val.saturating_div(*col_sum); }); }); } @@ -427,7 +444,7 @@ pub fn inplace_col_max_upscale_sparse(sparse_matrix: &mut [Vec<(u16, I32F32)>], if col_max[*j as usize] == I32F32::from_num(0.0_f32) { continue; } - *value /= col_max[*j as usize]; + *value = value.saturating_div(col_max[*j as usize]); } } } @@ -455,7 +472,7 @@ pub fn inplace_col_max_upscale(x: &mut [Vec]) { .zip(&col_maxes) .filter(|(_, col_max)| **col_max != I32F32::from_num(0)) .for_each(|(m_val, col_max)| { - *m_val /= col_max; + *m_val = m_val.saturating_div(*col_max); }); }); } @@ -604,7 +621,11 @@ pub fn row_hadamard(matrix: &[Vec], vector: &[I32F32]) -> Vec], vector: &[I32F32]) -> Vec { // Compute ranks: r_j = SUM(i) w_ij * s_i // Compute trust scores: t_j = SUM(i) w_ij * s_i // result_j = SUM(i) vector_i * matrix_ij - acc_val + vec_val * m_val + acc_val.saturating_add(vec_val.saturating_mul(*m_val)) }) .collect() }, @@ -674,7 +695,7 @@ pub fn matmul_64(matrix: &[Vec], vector: &[I64F64]) -> Vec { // Compute ranks: r_j = SUM(i) w_ij * s_i // Compute trust scores: t_j = SUM(i) w_ij * s_i // result_j = SUM(i) vector_i * matrix_ij - acc_val + vec_val * m_val + acc_val.saturating_add(vec_val.saturating_mul(*m_val)) }) .collect() }) @@ -699,7 +720,7 @@ pub fn matmul_transpose(matrix: &[Vec], vector: &[I32F32]) -> Vec = (0..use_stake.len()).collect(); - let minority: I32F32 = stake_sum - majority; + let minority: I32F32 = stake_sum.saturating_sub(majority); let mut use_score: Vec> = vec![vec![zero; use_stake.len()]; columns as usize]; let mut median: Vec = vec![zero; columns as usize]; let mut k: usize = 0; @@ -978,7 +1002,7 @@ pub fn weighted_median_col_sparse( for (c, val) in score[r].iter() { use_score[*c as usize][k] = *val; } - k += 1; + k.saturating_inc(); } for c in 0..columns as usize { median[c] = weighted_median( @@ -1009,7 +1033,7 @@ pub fn hadamard(mat1: &[Vec], mat2: &[Vec]) -> Vec> assert!(row1.len() == row2.len()); row1.iter() .zip(row2) - .map(|(elem1, elem2)| elem1 * elem2) + .map(|(elem1, elem2)| elem1.saturating_mul(*elem2)) .collect() }) .collect() @@ -1029,14 +1053,14 @@ pub fn hadamard_sparse( for i in 0..rows { let mut row1: Vec = vec![zero; columns as usize]; for (j, value) in mat1[i].iter() { - row1[*j as usize] += value; + row1[*j as usize] = row1[*j as usize].saturating_add(*value); } let mut row2: Vec = vec![zero; columns as usize]; for (j, value) in mat2[i].iter() { - row2[*j as usize] += value; + row2[*j as usize] = row2[*j as usize].saturating_add(*value); } for j in 0..columns as usize { - let prod: I32F32 = row1[j] * row2[j]; + let prod: I32F32 = row1[j].saturating_mul(row2[j]); if zero < prod { result[i].push((j as u16, prod)) } @@ -1056,14 +1080,18 @@ pub fn mat_ema(new: &[Vec], old: &[Vec], alpha: I32F32) -> Vec> = vec![vec![]; n]; for i in 0..new.len() { let mut row: Vec = vec![zero; n]; for (j, value) in new[i].iter() { - row[*j as usize] += alpha * value; + row[*j as usize] = row[*j as usize].saturating_add(alpha.saturating_mul(*value)); } for (j, value) in old[i].iter() { - row[*j as usize] += one_minus_alpha * value; + row[*j as usize] = + row[*j as usize].saturating_add(one_minus_alpha.saturating_mul(*value)); } for (j, value) in row.iter().enumerate() { if *value > zero { @@ -1114,7 +1143,11 @@ pub fn sparse_threshold(w: &[Vec<(u16, I32F32)>], threshold: I32F32) -> Vec(test: bool) -> Weight { weight = weight.saturating_add(T::DbWeight::get().reads(1)); // Compute the total issuance value - let total_issuance_value: u64 = stake_sum + total_balance_sum + locked_sum; + let total_issuance_value: u64 = stake_sum + .saturating_add(total_balance_sum) + .saturating_add(locked_sum); // Update the total issuance in storage TotalIssuance::::put(total_issuance_value); @@ -134,7 +137,7 @@ pub fn migrate_create_root_network() -> Weight { NetworksAdded::::insert(root_netuid, true); // Increment the number of total networks. - TotalNetworks::::mutate(|n| *n += 1); + TotalNetworks::::mutate(|n| n.saturating_inc()); // Set the maximum number to the number of senate members. MaxAllowedUids::::insert(root_netuid, 64); @@ -201,7 +204,7 @@ pub fn migrate_delete_subnet_3() -> Weight { NetworksAdded::::remove(netuid); // --- 6. Decrement the network counter. - TotalNetworks::::mutate(|n| *n -= 1); + TotalNetworks::::mutate(|n| n.saturating_dec()); // --- 7. Remove various network-related storages. NetworkRegisteredAt::::remove(netuid); @@ -285,7 +288,7 @@ pub fn migrate_delete_subnet_21() -> Weight { NetworksAdded::::remove(netuid); // --- 6. Decrement the network counter. - TotalNetworks::::mutate(|n| *n -= 1); + TotalNetworks::::mutate(|n| n.saturating_dec()); // --- 7. Remove various network-related storages. NetworkRegisteredAt::::remove(netuid); diff --git a/pallets/subtensor/src/registration.rs b/pallets/subtensor/src/registration.rs index 88730f7c3..dda00db54 100644 --- a/pallets/subtensor/src/registration.rs +++ b/pallets/subtensor/src/registration.rs @@ -2,6 +2,7 @@ use super::*; use frame_support::storage::IterableStorageDoubleMap; use sp_core::{Get, H256, U256}; use sp_io::hashing::{keccak_256, sha2_256}; +use sp_runtime::Saturating; use system::pallet_prelude::BlockNumberFor; const LOG_TARGET: &str = "runtime::subtensor::registration"; @@ -74,7 +75,7 @@ impl Pallet { // --- 4. Ensure we are not exceeding the max allowed registrations per interval. ensure!( Self::get_registrations_this_interval(netuid) - < Self::get_target_registrations_per_interval(netuid) * 3, + < Self::get_target_registrations_per_interval(netuid).saturating_mul(3), Error::::TooManyRegistrationsThisInterval ); @@ -143,9 +144,9 @@ impl Pallet { } // --- 14. Record the registration and increment block and interval counters. - BurnRegistrationsThisInterval::::mutate(netuid, |val| *val += 1); - RegistrationsThisInterval::::mutate(netuid, |val| *val += 1); - RegistrationsThisBlock::::mutate(netuid, |val| *val += 1); + BurnRegistrationsThisInterval::::mutate(netuid, |val| val.saturating_inc()); + RegistrationsThisInterval::::mutate(netuid, |val| val.saturating_inc()); + RegistrationsThisBlock::::mutate(netuid, |val| val.saturating_inc()); Self::increase_rao_recycled(netuid, Self::get_burn_as_u64(netuid)); // --- 15. Deposit successful event. @@ -259,7 +260,7 @@ impl Pallet { // --- 5. Ensure we are not exceeding the max allowed registrations per interval. ensure!( Self::get_registrations_this_interval(netuid) - < Self::get_target_registrations_per_interval(netuid) * 3, + < Self::get_target_registrations_per_interval(netuid).saturating_mul(3), Error::::TooManyRegistrationsThisInterval ); @@ -277,7 +278,7 @@ impl Pallet { Error::::InvalidWorkBlock ); ensure!( - current_block_number - block_number < 3, + current_block_number.saturating_sub(block_number) < 3, Error::::InvalidWorkBlock ); @@ -338,9 +339,9 @@ impl Pallet { } // --- 12. Record the registration and increment block and interval counters. - POWRegistrationsThisInterval::::mutate(netuid, |val| *val += 1); - RegistrationsThisInterval::::mutate(netuid, |val| *val += 1); - RegistrationsThisBlock::::mutate(netuid, |val| *val += 1); + POWRegistrationsThisInterval::::mutate(netuid, |val| val.saturating_inc()); + RegistrationsThisInterval::::mutate(netuid, |val| val.saturating_inc()); + RegistrationsThisBlock::::mutate(netuid, |val| val.saturating_inc()); // --- 13. Deposit successful event. log::info!( @@ -376,7 +377,7 @@ impl Pallet { Error::::InvalidWorkBlock ); ensure!( - current_block_number - block_number < 3, + current_block_number.saturating_sub(block_number) < 3, Error::::InvalidWorkBlock ); @@ -440,7 +441,7 @@ impl Pallet { Self::get_neuron_block_at_registration(netuid, neuron_uid_i); #[allow(clippy::comparison_chain)] if min_score == pruning_score { - if current_block - block_at_registration < immunity_period { + if current_block.saturating_sub(block_at_registration) < immunity_period { //neuron is in immunity period if min_score_in_immunity_period > pruning_score { min_score_in_immunity_period = pruning_score; @@ -452,7 +453,7 @@ impl Pallet { } // Find min pruning score. else if min_score > pruning_score { - if current_block - block_at_registration < immunity_period { + if current_block.saturating_sub(block_at_registration) < immunity_period { //neuron is in immunity period if min_score_in_immunity_period > pruning_score { min_score_in_immunity_period = pruning_score; @@ -584,7 +585,7 @@ impl Pallet { let mut nonce: u64 = start_nonce; let mut work: H256 = Self::create_seal_hash(block_number, nonce, hotkey); while !Self::hash_meets_difficulty(&work, difficulty) { - nonce += 1; + nonce.saturating_inc(); work = Self::create_seal_hash(block_number, nonce, hotkey); } let vec_work: Vec = Self::hash_to_vec(work); @@ -618,8 +619,9 @@ impl Pallet { Error::::HotKeyAlreadyRegisteredInSubNet ); - weight - .saturating_accrue(T::DbWeight::get().reads((TotalNetworks::::get() + 1u16) as u64)); + weight.saturating_accrue( + T::DbWeight::get().reads((TotalNetworks::::get().saturating_add(1)) as u64), + ); let swap_cost = 1_000_000_000u64; ensure!( diff --git a/pallets/subtensor/src/root.rs b/pallets/subtensor/src/root.rs index a09957924..9e0327fb3 100644 --- a/pallets/subtensor/src/root.rs +++ b/pallets/subtensor/src/root.rs @@ -21,6 +21,7 @@ use frame_support::dispatch::Pays; use frame_support::storage::{IterableStorageDoubleMap, IterableStorageMap}; use frame_support::traits::Get; use frame_support::weights::Weight; +use sp_runtime::Saturating; use sp_std::vec; use substrate_fixed::{ transcendental::log2, @@ -156,9 +157,19 @@ impl Pallet { // Calculate the logarithmic residual of the issuance against half the total supply. let residual: I96F32 = log2( I96F32::from_num(1.0) - / (I96F32::from_num(1.0) - - total_issuance - / (I96F32::from_num(2.0) * I96F32::from_num(10_500_000_000_000_000.0))), + .checked_div( + I96F32::from_num(1.0) + .checked_sub( + total_issuance + .checked_div( + I96F32::from_num(2.0) + .saturating_mul(I96F32::from_num(10_500_000_000_000_000.0)), + ) + .ok_or("Logarithm calculation failed")?, + ) + .ok_or("Logarithm calculation failed")?, + ) + .ok_or("Logarithm calculation failed")?, ) .map_err(|_| "Logarithm calculation failed")?; // Floor the residual to smooth out the emission rate. @@ -169,12 +180,12 @@ impl Pallet { // Multiply 2.0 by itself floored_residual times to calculate the power of 2. let mut multiplier: I96F32 = I96F32::from_num(1.0); for _ in 0..floored_residual_int { - multiplier *= I96F32::from_num(2.0); + multiplier = multiplier.saturating_mul(I96F32::from_num(2.0)); } - let block_emission_percentage: I96F32 = I96F32::from_num(1.0) / multiplier; + let block_emission_percentage: I96F32 = I96F32::from_num(1.0).saturating_div(multiplier); // Calculate the actual emission based on the emission rate - let block_emission: I96F32 = - block_emission_percentage * I96F32::from_num(DefaultBlockEmission::::get()); + let block_emission: I96F32 = block_emission_percentage + .saturating_mul(I96F32::from_num(DefaultBlockEmission::::get())); // Convert to u64 let block_emission_u64: u64 = block_emission.to_num::(); if BlockEmission::::get() != block_emission_u64 { @@ -384,10 +395,10 @@ impl Pallet { let mut trust = vec![I64F64::from_num(0); total_networks as usize]; let mut total_stake: I64F64 = I64F64::from_num(0); for (weights, hotkey_stake) in weights.iter().zip(stake_i64) { - total_stake += hotkey_stake; + total_stake = total_stake.saturating_add(hotkey_stake); for (weight, trust_score) in weights.iter().zip(&mut trust) { if *weight > 0 { - *trust_score += hotkey_stake; + *trust_score = trust_score.saturating_add(hotkey_stake); } } } @@ -411,13 +422,15 @@ impl Pallet { let one = I64F64::from_num(1); let mut consensus = vec![I64F64::from_num(0); total_networks as usize]; for (trust_score, consensus_i) in trust.iter_mut().zip(&mut consensus) { - let shifted_trust = *trust_score - I64F64::from_num(Self::get_float_kappa(0)); // Range( -kappa, 1 - kappa ) - let temperatured_trust = shifted_trust * I64F64::from_num(Self::get_rho(0)); // Range( -rho * kappa, rho ( 1 - kappa ) ) + let shifted_trust = + trust_score.saturating_sub(I64F64::from_num(Self::get_float_kappa(0))); // Range( -kappa, 1 - kappa ) + let temperatured_trust = + shifted_trust.saturating_mul(I64F64::from_num(Self::get_rho(0))); // Range( -rho * kappa, rho ( 1 - kappa ) ) let exponentiated_trust: I64F64 = - substrate_fixed::transcendental::exp(-temperatured_trust) + substrate_fixed::transcendental::exp(temperatured_trust.saturating_neg()) .expect("temperatured_trust is on range( -rho * kappa, rho ( 1 - kappa ) )"); - *consensus_i = one / (one + exponentiated_trust); + *consensus_i = one.saturating_div(one.saturating_add(exponentiated_trust)); } log::debug!("C:\n{:?}\n", &consensus); @@ -425,7 +438,7 @@ impl Pallet { for ((emission, consensus_i), rank) in weighted_emission.iter_mut().zip(&consensus).zip(&ranks) { - *emission = *consensus_i * (*rank); + *emission = consensus_i.saturating_mul(*rank); } inplace_normalize_64(&mut weighted_emission); log::debug!("Ei64:\n{:?}\n", &weighted_emission); @@ -433,7 +446,7 @@ impl Pallet { // -- 11. Converts the normalized 64-bit fixed point rank values to u64 for the final emission calculation. let emission_as_tao: Vec = weighted_emission .iter() - .map(|v: &I64F64| *v * block_emission) + .map(|v: &I64F64| v.saturating_mul(block_emission)) .collect(); // --- 12. Converts the normalized 64-bit fixed point rank values to u64 for the final emission calculation. @@ -486,7 +499,7 @@ impl Pallet { // --- 3. Ensure that the number of registrations in this interval doesn't exceed thrice the target limit. ensure!( Self::get_registrations_this_interval(root_netuid) - < Self::get_target_registrations_per_interval(root_netuid) * 3, + < Self::get_target_registrations_per_interval(root_netuid).saturating_mul(3), Error::::TooManyRegistrationsThisInterval ); @@ -584,8 +597,8 @@ impl Pallet { } // --- 14. Update the registration counters for both the block and interval. - RegistrationsThisInterval::::mutate(root_netuid, |val| *val += 1); - RegistrationsThisBlock::::mutate(root_netuid, |val| *val += 1); + RegistrationsThisInterval::::mutate(root_netuid, |val| val.saturating_inc()); + RegistrationsThisBlock::::mutate(root_netuid, |val| val.saturating_inc()); // --- 15. Log and announce the successful registration. log::info!( @@ -812,7 +825,7 @@ impl Pallet { // We subtract one because we don't want root subnet to count towards total let mut next_available_netuid = 0; loop { - next_available_netuid += 1; + next_available_netuid.saturating_inc(); if !Self::if_subnet_exist(next_available_netuid) { log::debug!("got subnet id: {:?}", next_available_netuid); break next_available_netuid; @@ -911,7 +924,7 @@ impl Pallet { NetworkModality::::insert(netuid, 0); // --- 5. Increase total network count. - TotalNetworks::::mutate(|n| *n += 1); + TotalNetworks::::mutate(|n| n.saturating_inc()); // --- 6. Set all default values **explicitly**. Self::set_network_registration_allowed(netuid, true); @@ -1003,7 +1016,7 @@ impl Pallet { NetworksAdded::::remove(netuid); // --- 6. Decrement the network counter. - TotalNetworks::::mutate(|n| *n -= 1); + TotalNetworks::::mutate(|n| n.saturating_dec()); // --- 7. Remove various network-related storages. NetworkRegisteredAt::::remove(netuid); @@ -1067,6 +1080,7 @@ impl Pallet { SubnetOwner::::remove(netuid); } + #[allow(clippy::arithmetic_side_effects)] /// This function calculates the lock cost for a network based on the last lock amount, minimum lock cost, last lock block, and current block. /// The lock cost is calculated using the formula: /// lock_cost = (last_lock * mult) - (last_lock / lock_reduction_interval) * (current_block - last_lock_block) diff --git a/pallets/subtensor/src/serving.rs b/pallets/subtensor/src/serving.rs index 116d95982..eb7fa4369 100644 --- a/pallets/subtensor/src/serving.rs +++ b/pallets/subtensor/src/serving.rs @@ -222,7 +222,7 @@ impl Pallet { ) -> bool { let rate_limit: u64 = Self::get_serving_rate_limit(netuid); let last_serve = prev_axon_info.block; - rate_limit == 0 || last_serve == 0 || current_block - last_serve >= rate_limit + rate_limit == 0 || last_serve == 0 || current_block.saturating_sub(last_serve) >= rate_limit } pub fn prometheus_passes_rate_limit( @@ -232,7 +232,7 @@ impl Pallet { ) -> bool { let rate_limit: u64 = Self::get_serving_rate_limit(netuid); let last_serve = prev_prometheus_info.block; - rate_limit == 0 || last_serve == 0 || current_block - last_serve >= rate_limit + rate_limit == 0 || last_serve == 0 || current_block.saturating_sub(last_serve) >= rate_limit } pub fn has_axon_info(netuid: u16, hotkey: &T::AccountId) -> bool { diff --git a/pallets/subtensor/src/staking.rs b/pallets/subtensor/src/staking.rs index 08b65b8a7..7c3328396 100644 --- a/pallets/subtensor/src/staking.rs +++ b/pallets/subtensor/src/staking.rs @@ -346,7 +346,7 @@ impl Pallet { Self::set_stakes_this_interval_for_coldkey_hotkey( &coldkey, &hotkey, - stakes_this_interval + 1, + stakes_this_interval.saturating_add(1), block, ); log::info!( @@ -452,7 +452,7 @@ impl Pallet { Self::set_stakes_this_interval_for_coldkey_hotkey( &coldkey, &hotkey, - unstakes_this_interval + 1, + unstakes_this_interval.saturating_add(1), block, ); log::info!( @@ -530,7 +530,7 @@ impl Pallet { TotalHotkeyColdkeyStakesThisInterval::::get(coldkey, hotkey); // Calculate the block number after which the stakes for the hotkey should be reset. - let block_to_reset_after = block_last_staked_at + stake_interval; + let block_to_reset_after = block_last_staked_at.saturating_add(stake_interval); // If the current block number is beyond the reset point, // it indicates the end of the staking interval for the hotkey. diff --git a/pallets/subtensor/src/subnet_info.rs b/pallets/subtensor/src/subnet_info.rs index cf6b66aea..ef92b2da6 100644 --- a/pallets/subtensor/src/subnet_info.rs +++ b/pallets/subtensor/src/subnet_info.rs @@ -117,7 +117,7 @@ impl Pallet { } let mut subnets_info = Vec::>>::new(); - for netuid_ in 0..(max_netuid + 1) { + for netuid_ in 0..=max_netuid { if subnet_netuids.contains(&netuid_) { subnets_info.push(Self::get_subnet_info(netuid_)); } diff --git a/pallets/subtensor/src/uids.rs b/pallets/subtensor/src/uids.rs index 4ae2c24de..fff358f1c 100644 --- a/pallets/subtensor/src/uids.rs +++ b/pallets/subtensor/src/uids.rs @@ -59,7 +59,7 @@ impl Pallet { ); // 2. Get and increase the uid count. - SubnetworkN::::insert(netuid, next_uid + 1); + SubnetworkN::::insert(netuid, next_uid.saturating_add(1)); // 3. Expand Yuma Consensus with new position. Rank::::mutate(netuid, |v| v.push(0)); @@ -126,11 +126,7 @@ impl Pallet { /// Return the total number of subnetworks available on the chain. /// pub fn get_number_of_subnets() -> u16 { - let mut number_of_subnets: u16 = 0; - for (_, _) in as IterableStorageMap>::iter() { - number_of_subnets += 1; - } - number_of_subnets + as IterableStorageMap>::iter().count() as u16 } /// Return a list of all networks a hotkey is registered on. diff --git a/pallets/subtensor/src/utils.rs b/pallets/subtensor/src/utils.rs index 54b7818c9..546875b27 100644 --- a/pallets/subtensor/src/utils.rs +++ b/pallets/subtensor/src/utils.rs @@ -291,7 +291,7 @@ impl Pallet { return false; } - current_block - prev_tx_block <= rate_limit + current_block.saturating_sub(prev_tx_block) <= rate_limit } pub fn exceeds_tx_delegate_take_rate_limit(prev_tx_block: u64, current_block: u64) -> bool { let rate_limit: u64 = Self::get_tx_delegate_take_rate_limit(); @@ -299,7 +299,7 @@ impl Pallet { return false; } - current_block - prev_tx_block <= rate_limit + current_block.saturating_sub(prev_tx_block) <= rate_limit } // ======================== diff --git a/pallets/subtensor/src/weights.rs b/pallets/subtensor/src/weights.rs index 548bc30af..1866f8e62 100644 --- a/pallets/subtensor/src/weights.rs +++ b/pallets/subtensor/src/weights.rs @@ -325,7 +325,8 @@ impl Pallet { if last_set_weights == 0 { return true; } // (Storage default) Never set weights. - return (current_block - last_set_weights) >= Self::get_weights_set_rate_limit(netuid); + return current_block.saturating_sub(last_set_weights) + >= Self::get_weights_set_rate_limit(netuid); } // --- 3. Non registered peers cant pass. false @@ -398,6 +399,7 @@ impl Pallet { false } + #[allow(clippy::arithmetic_side_effects)] /// Returns normalized the passed positive integer weights so that they sum to u16 max value. pub fn normalize_weights(mut weights: Vec) -> Vec { let sum: u64 = weights.iter().map(|x| *x as u64).sum(); @@ -405,7 +407,9 @@ impl Pallet { return weights; } weights.iter_mut().for_each(|x| { - *x = (*x as u64 * u16::MAX as u64 / sum) as u16; + *x = (*x as u64) + .saturating_mul(u16::MAX as u64) + .saturating_div(sum) as u16; }); weights } @@ -448,6 +452,7 @@ impl Pallet { uids.len() <= subnetwork_n as usize } + #[allow(clippy::arithmetic_side_effects)] 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_commit_reveal_weights_interval(netuid); @@ -456,11 +461,12 @@ impl Pallet { } 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); + let interval_start: u64 = current_block.saturating_sub(current_block % interval); + let last_commit_interval_start: u64 = + commit_block.saturating_sub(commit_block % interval); // Allow commit if we're within the interval bounds - if current_block <= interval_start + interval + if current_block <= interval_start.saturating_add(interval) && interval_start > last_commit_interval_start { return true; @@ -472,19 +478,20 @@ impl Pallet { } } + #[allow(clippy::arithmetic_side_effects)] pub fn is_reveal_block_range(netuid: u16, commit_block: u64) -> bool { let interval: u64 = Self::get_commit_reveal_weights_interval(netuid); 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 commit_interval_start: u64 = commit_block.saturating_sub(commit_block % interval); // Find the start of the interval in which the commit occurred + let reveal_interval_start: u64 = commit_interval_start.saturating_add(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 + && current_block < reveal_interval_start.saturating_add(interval) { return true; } diff --git a/pallets/subtensor/tests/block_step.rs b/pallets/subtensor/tests/block_step.rs index 5df173906..ab99363ed 100644 --- a/pallets/subtensor/tests/block_step.rs +++ b/pallets/subtensor/tests/block_step.rs @@ -1,3 +1,5 @@ +#![allow(clippy::unwrap_used)] + mod mock; use frame_support::assert_ok; use frame_system::Config; @@ -5,7 +7,6 @@ use mock::*; use sp_core::U256; #[test] -#[allow(clippy::unwrap_used)] fn test_loaded_emission() { new_test_ext(1).execute_with(|| { let n: u16 = 100; diff --git a/pallets/subtensor/tests/difficulty.rs b/pallets/subtensor/tests/difficulty.rs index 24552261d..05238bc43 100644 --- a/pallets/subtensor/tests/difficulty.rs +++ b/pallets/subtensor/tests/difficulty.rs @@ -1,3 +1,5 @@ +#![allow(clippy::unwrap_used)] + use crate::mock::*; mod mock; use sp_core::U256; diff --git a/pallets/subtensor/tests/epoch.rs b/pallets/subtensor/tests/epoch.rs index fe247fd32..635b4fc0b 100644 --- a/pallets/subtensor/tests/epoch.rs +++ b/pallets/subtensor/tests/epoch.rs @@ -1,3 +1,9 @@ +#![allow( + clippy::arithmetic_side_effects, + clippy::indexing_slicing, + clippy::unwrap_used +)] + use crate::mock::*; use frame_support::assert_ok; use frame_system::Config; diff --git a/pallets/subtensor/tests/migration.rs b/pallets/subtensor/tests/migration.rs index 2f634d7c0..c921124f4 100644 --- a/pallets/subtensor/tests/migration.rs +++ b/pallets/subtensor/tests/migration.rs @@ -1,3 +1,5 @@ +#![allow(clippy::unwrap_used)] + mod mock; use frame_support::assert_ok; use frame_system::Config; diff --git a/pallets/subtensor/tests/mock.rs b/pallets/subtensor/tests/mock.rs index 9995acf84..d772a8d47 100644 --- a/pallets/subtensor/tests/mock.rs +++ b/pallets/subtensor/tests/mock.rs @@ -1,7 +1,9 @@ -use frame_support::derive_impl; -use frame_support::dispatch::DispatchResultWithPostInfo; +#![allow(clippy::arithmetic_side_effects, clippy::unwrap_used)] + use frame_support::{ - assert_ok, parameter_types, + assert_ok, derive_impl, + dispatch::DispatchResultWithPostInfo, + parameter_types, traits::{Everything, Hooks}, weights, }; diff --git a/pallets/subtensor/tests/registration.rs b/pallets/subtensor/tests/registration.rs index 5ee941f26..0da10bc48 100644 --- a/pallets/subtensor/tests/registration.rs +++ b/pallets/subtensor/tests/registration.rs @@ -1,3 +1,5 @@ +#![allow(clippy::unwrap_used)] + use frame_support::traits::Currency; use crate::mock::*; diff --git a/pallets/subtensor/tests/root.rs b/pallets/subtensor/tests/root.rs index 7958c9c81..7c6622670 100644 --- a/pallets/subtensor/tests/root.rs +++ b/pallets/subtensor/tests/root.rs @@ -1,3 +1,5 @@ +#![allow(clippy::indexing_slicing, clippy::unwrap_used)] + use crate::mock::*; use frame_support::{assert_err, assert_ok}; use frame_system::Config; diff --git a/pallets/subtensor/tests/senate.rs b/pallets/subtensor/tests/senate.rs index a21fbce01..ac020ae04 100644 --- a/pallets/subtensor/tests/senate.rs +++ b/pallets/subtensor/tests/senate.rs @@ -1,3 +1,5 @@ +#![allow(clippy::unwrap_used)] + mod mock; use mock::*; diff --git a/pallets/subtensor/tests/staking.rs b/pallets/subtensor/tests/staking.rs index ffe9de27a..766b3a495 100644 --- a/pallets/subtensor/tests/staking.rs +++ b/pallets/subtensor/tests/staking.rs @@ -1,3 +1,5 @@ +#![allow(clippy::unwrap_used)] + use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; use frame_system::Config; mod mock; diff --git a/pallets/subtensor/tests/uids.rs b/pallets/subtensor/tests/uids.rs index b8a969943..82adc6b8a 100644 --- a/pallets/subtensor/tests/uids.rs +++ b/pallets/subtensor/tests/uids.rs @@ -1,3 +1,5 @@ +#![allow(clippy::unwrap_used)] + use crate::mock::*; use frame_support::assert_ok; use frame_system::Config; diff --git a/pallets/subtensor/tests/weights.rs b/pallets/subtensor/tests/weights.rs index 5cd3bf7c2..2344bd425 100644 --- a/pallets/subtensor/tests/weights.rs +++ b/pallets/subtensor/tests/weights.rs @@ -1,3 +1,5 @@ +#![allow(clippy::indexing_slicing)] + mod mock; use frame_support::{ assert_err, assert_ok, diff --git a/runtime/src/check_nonce.rs b/runtime/src/check_nonce.rs index d9948f9b6..b257d6a49 100644 --- a/runtime/src/check_nonce.rs +++ b/runtime/src/check_nonce.rs @@ -8,6 +8,7 @@ use sp_runtime::{ InvalidTransaction, TransactionLongevity, TransactionValidity, TransactionValidityError, ValidTransaction, }, + Saturating, }; use sp_std::vec; @@ -82,7 +83,7 @@ where } .into()); } - account.nonce += T::Nonce::one(); + account.nonce.saturating_inc(); frame_system::Account::::insert(who, account); Ok(()) } @@ -111,7 +112,7 @@ where let provides = vec![Encode::encode(&(who, self.0))]; let requires = if account.nonce < self.0 { - vec![Encode::encode(&(who, self.0 - One::one()))] + vec![Encode::encode(&(who, self.0.saturating_sub(One::one())))] } else { vec![] }; diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 2364008fd..8189f6032 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1,6 +1,8 @@ #![cfg_attr(not(feature = "std"), no_std)] // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. #![recursion_limit = "256"] +// Some arithmetic operations can't use the saturating equivalent, such as the PerThing types +#![allow(clippy::arithmetic_side_effects)] // Make the WASM binary available. #[cfg(feature = "std")] @@ -96,7 +98,9 @@ pub type Nonce = u32; pub const fn deposit(items: u32, bytes: u32) -> Balance { pub const ITEMS_FEE: Balance = 2_000 * 10_000; pub const BYTES_FEE: Balance = 100 * 10_000; - items as Balance * ITEMS_FEE + bytes as Balance * BYTES_FEE + (items as Balance) + .saturating_mul(ITEMS_FEE) + .saturating_add((bytes as Balance).saturating_mul(BYTES_FEE)) } // Opaque types. These are used by the CLI to instantiate machinery that don't need to know @@ -662,7 +666,11 @@ impl PrivilegeCmp for OriginPrivilegeCmp { r_yes_votes, r_count, )), // Equivalent to (l_yes_votes / l_count).cmp(&(r_yes_votes / r_count)) - ) => Some((l_yes_votes * r_count).cmp(&(r_yes_votes * l_count))), + ) => Some( + l_yes_votes + .saturating_mul(*r_count) + .cmp(&r_yes_votes.saturating_mul(*l_count)), + ), // For every other origin we don't care, as they are not used for `ScheduleOrigin`. _ => None, } @@ -1461,6 +1469,7 @@ impl_runtime_apis! { #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { + #[allow(clippy::unwrap_used)] fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to // have a backtrace here. If any of the pre/post migration checks fail, we shall stop diff --git a/runtime/tests/metadata.rs b/runtime/tests/metadata.rs index 692676d79..975c96227 100644 --- a/runtime/tests/metadata.rs +++ b/runtime/tests/metadata.rs @@ -1,3 +1,5 @@ +#![allow(clippy::indexing_slicing)] + use frame_metadata::RuntimeMetadata; use node_subtensor_runtime::Runtime; use scale_info::TypeDef; diff --git a/runtime/tests/pallet_proxy.rs b/runtime/tests/pallet_proxy.rs index f04fda9f2..796dfc471 100644 --- a/runtime/tests/pallet_proxy.rs +++ b/runtime/tests/pallet_proxy.rs @@ -1,3 +1,5 @@ +#![allow(clippy::unwrap_used)] + use codec::Encode; use frame_support::{assert_ok, traits::InstanceFilter, BoundedVec}; use node_subtensor_runtime::{ From 2c5b1ffbeb1331c03162930add56cc78d40962eb Mon Sep 17 00:00:00 2001 From: Keith Date: Wed, 19 Jun 2024 21:37:43 +0900 Subject: [PATCH 2/2] clippy fixes --- pallets/subtensor/src/math.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pallets/subtensor/src/math.rs b/pallets/subtensor/src/math.rs index f7784ea1c..40ee7ebe8 100644 --- a/pallets/subtensor/src/math.rs +++ b/pallets/subtensor/src/math.rs @@ -252,7 +252,7 @@ pub fn inplace_normalize(x: &mut [I32F32]) { if x_sum == I32F32::from_num(0.0_f32) { return; } - x.into_iter() + x.iter_mut() .for_each(|value| *value = value.saturating_div(x_sum)); } @@ -262,7 +262,7 @@ pub fn inplace_normalize_using_sum(x: &mut [I32F32], x_sum: I32F32) { if x_sum == I32F32::from_num(0.0_f32) { return; } - x.into_iter() + x.iter_mut() .for_each(|value| *value = value.saturating_div(x_sum)); } @@ -273,7 +273,7 @@ pub fn inplace_normalize_64(x: &mut [I64F64]) { if x_sum == I64F64::from_num(0) { return; } - x.into_iter() + x.iter_mut() .for_each(|value| *value = value.saturating_div(x_sum)); } @@ -311,7 +311,7 @@ pub fn inplace_row_normalize(x: &mut [Vec]) { for row in x { let row_sum: I32F32 = row.iter().sum(); if row_sum > I32F32::from_num(0.0_f32) { - row.into_iter() + row.iter_mut() .for_each(|x_ij: &mut I32F32| *x_ij = x_ij.saturating_div(row_sum)); } } @@ -622,7 +622,7 @@ pub fn row_hadamard(matrix: &[Vec], vector: &[I32F32]) -> Vec