diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 53266378a..2af3b2bb5 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -111,7 +111,7 @@ impl ExecuteTimings { } type BankStatusCache = StatusCache>; -#[frozen_abi(digest = "3ZaEt781qwhfQSE4DZPBHhng2S6MuimchRjkR9ZWzDFs")] +#[frozen_abi(digest = "EcB9J7sm37t1R47vLcvGuNeiRciB4Efq1EDWDWL6Bp5h")] pub type BankSlotDelta = SlotDelta>; type TransactionAccountRefCells = Vec>>; type TransactionAccountDepRefCells = Vec<(Pubkey, RefCell)>; diff --git a/sdk/program/src/instruction.rs b/sdk/program/src/instruction.rs index 4c7ee694d..8a67868a2 100644 --- a/sdk/program/src/instruction.rs +++ b/sdk/program/src/instruction.rs @@ -198,6 +198,9 @@ pub enum InstructionError { #[error("Invalid account owner")] InvalidAccountOwner, + + #[error("Program arithmetic overflowed")] + ArithmeticOverflow, } #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] diff --git a/sdk/src/genesis_config.rs b/sdk/src/genesis_config.rs index 16d51319e..06d32c8be 100644 --- a/sdk/src/genesis_config.rs +++ b/sdk/src/genesis_config.rs @@ -218,7 +218,10 @@ impl GenesisConfig { } pub fn ns_per_slot(&self) -> u128 { - self.poh_config.target_tick_duration.as_nanos() * self.ticks_per_slot() as u128 + self.poh_config + .target_tick_duration + .as_nanos() + .saturating_mul(self.ticks_per_slot() as u128) } pub fn slots_per_year(&self) -> f64 { diff --git a/sdk/src/hard_forks.rs b/sdk/src/hard_forks.rs index 5781b60a2..1714fef45 100644 --- a/sdk/src/hard_forks.rs +++ b/sdk/src/hard_forks.rs @@ -18,7 +18,7 @@ impl HardForks { .iter() .position(|(slot, _)| *slot == new_slot) { - self.hard_forks[i] = (new_slot, self.hard_forks[i].1 + 1); + self.hard_forks[i] = (new_slot, self.hard_forks[i].1.saturating_add(1)); } else { self.hard_forks.push((new_slot, 1)); } diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 8bfcddb66..f0b6db4af 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -1,6 +1,5 @@ #![cfg_attr(RUSTC_WITH_SPECIALIZATION, feature(specialization))] #![cfg_attr(RUSTC_NEEDS_PROC_MACRO_HYGIENE, feature(proc_macro_hygiene))] -#![allow(clippy::integer_arithmetic)] // Allows macro expansion of `use ::solana_sdk::*` to work within this crate extern crate self as solana_sdk; diff --git a/sdk/src/nonce_keyed_account.rs b/sdk/src/nonce_keyed_account.rs index 81e3ab7c0..fc9ae7517 100644 --- a/sdk/src/nonce_keyed_account.rs +++ b/sdk/src/nonce_keyed_account.rs @@ -153,8 +153,14 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> { return Err(InstructionError::MissingRequiredSignature); } - self.try_account_ref_mut()?.lamports -= lamports; - to.try_account_ref_mut()?.lamports += lamports; + let nonce_balance = self.try_account_ref_mut()?.lamports; + self.try_account_ref_mut()?.lamports = nonce_balance + .checked_sub(lamports) + .ok_or(InstructionError::ArithmeticOverflow)?; + let to_balance = to.try_account_ref_mut()?.lamports; + to.try_account_ref_mut()?.lamports = to_balance + .checked_add(lamports) + .ok_or(InstructionError::ArithmeticOverflow)?; Ok(()) } diff --git a/sdk/src/poh_config.rs b/sdk/src/poh_config.rs index 5c14e6d6d..12e7a583d 100644 --- a/sdk/src/poh_config.rs +++ b/sdk/src/poh_config.rs @@ -1,3 +1,4 @@ +#![allow(clippy::integer_arithmetic)] use crate::clock::DEFAULT_TICKS_PER_SECOND; use std::time::Duration; diff --git a/sdk/src/process_instruction.rs b/sdk/src/process_instruction.rs index 1659e95f6..a46fc4aa0 100644 --- a/sdk/src/process_instruction.rs +++ b/sdk/src/process_instruction.rs @@ -292,11 +292,11 @@ impl Default for MockInvokeContext { } impl InvokeContext for MockInvokeContext { fn push(&mut self, _key: &Pubkey) -> Result<(), InstructionError> { - self.invoke_depth += 1; + self.invoke_depth = self.invoke_depth.saturating_add(1); Ok(()) } fn pop(&mut self) { - self.invoke_depth -= 1; + self.invoke_depth = self.invoke_depth.saturating_sub(1); } fn invoke_depth(&self) -> usize { self.invoke_depth diff --git a/sdk/src/secp256k1_instruction.rs b/sdk/src/secp256k1_instruction.rs index e4e773c53..24d2c0d64 100644 --- a/sdk/src/secp256k1_instruction.rs +++ b/sdk/src/secp256k1_instruction.rs @@ -1,3 +1,4 @@ +#![allow(clippy::integer_arithmetic)] #![cfg(feature = "full")] use crate::instruction::Instruction; diff --git a/sdk/src/shred_version.rs b/sdk/src/shred_version.rs index de9268733..d253f30a3 100644 --- a/sdk/src/shred_version.rs +++ b/sdk/src/shred_version.rs @@ -15,6 +15,8 @@ pub fn version_from_hash(hash: &Hash) -> u16 { .for_each(|(accum, seed)| *accum ^= *seed) }); // convert accum into a u16 + // Because accum[0] is a u8, 8bit left shift of the u16 can never overflow + #[allow(clippy::integer_arithmetic)] let version = ((accum[0] as u16) << 8) | accum[1] as u16; // ensure version is never zero, to avoid looking like an uninitialized version diff --git a/sdk/src/stake_weighted_timestamp.rs b/sdk/src/stake_weighted_timestamp.rs index 620583c88..2ef8bf608 100644 --- a/sdk/src/stake_weighted_timestamp.rs +++ b/sdk/src/stake_weighted_timestamp.rs @@ -40,29 +40,29 @@ where V: Borrow<(Slot, UnixTimestamp)>, { let mut stake_per_timestamp: BTreeMap = BTreeMap::new(); - let mut total_stake = 0; + let mut total_stake: u128 = 0; for (vote_pubkey, slot_timestamp) in unique_timestamps { let (timestamp_slot, timestamp) = slot_timestamp.borrow(); let offset = slot.saturating_sub(*timestamp_slot) as u32 * slot_duration; - let estimate = timestamp + offset.as_secs() as i64; + let estimate = timestamp.saturating_add(offset.as_secs() as i64); let stake = stakes .get(vote_pubkey.borrow()) .map(|(stake, _account)| stake) .unwrap_or(&0); stake_per_timestamp .entry(estimate) - .and_modify(|stake_sum| *stake_sum += *stake as u128) + .and_modify(|stake_sum| *stake_sum = stake_sum.saturating_add(*stake as u128)) .or_insert(*stake as u128); - total_stake += *stake as u128; + total_stake = total_stake.saturating_add(*stake as u128); } if total_stake == 0 { return None; } - let mut stake_accumulator = 0; + let mut stake_accumulator: u128 = 0; let mut estimate = 0; // Populate `estimate` with stake-weighted median timestamp for (timestamp, stake) in stake_per_timestamp.into_iter() { - stake_accumulator += stake; + stake_accumulator = stake_accumulator.saturating_add(stake); if stake_accumulator > total_stake / 2 { estimate = timestamp; break; @@ -84,15 +84,16 @@ where // estimate offset since the start of the epoch is higher than // `MAX_ALLOWABLE_DRIFT_PERCENTAGE_SLOW` estimate = epoch_start_timestamp - + poh_estimate_offset.as_secs() as i64 - + max_allowable_drift_slow.as_secs() as i64; + .saturating_add(poh_estimate_offset.as_secs() as i64) + .saturating_add(max_allowable_drift_slow.as_secs() as i64); } else if estimate_offset < poh_estimate_offset && poh_estimate_offset - estimate_offset > max_allowable_drift_fast { // estimate offset since the start of the epoch is lower than // `MAX_ALLOWABLE_DRIFT_PERCENTAGE_FAST` - estimate = epoch_start_timestamp + poh_estimate_offset.as_secs() as i64 - - max_allowable_drift_fast.as_secs() as i64; + estimate = epoch_start_timestamp + .saturating_add(poh_estimate_offset.as_secs() as i64) + .saturating_sub(max_allowable_drift_fast.as_secs() as i64); } } Some(estimate) diff --git a/sdk/src/timing.rs b/sdk/src/timing.rs index 17625382e..adb0259c2 100644 --- a/sdk/src/timing.rs +++ b/sdk/src/timing.rs @@ -1,3 +1,4 @@ +#![allow(clippy::integer_arithmetic)] //! The `timing` module provides std::time utility functions. use std::time::{Duration, SystemTime, UNIX_EPOCH}; diff --git a/storage-proto/proto/solana.storage.transaction_by_addr.rs b/storage-proto/proto/solana.storage.transaction_by_addr.rs index 49ca4a9f1..ed7aebb9b 100644 --- a/storage-proto/proto/solana.storage.transaction_by_addr.rs +++ b/storage-proto/proto/solana.storage.transaction_by_addr.rs @@ -117,4 +117,5 @@ pub enum InstructionErrorType { BorshIoError = 44, AccountNotRentExempt = 45, InvalidAccountOwner = 46, + ArithmeticOverflow = 47, } diff --git a/storage-proto/src/convert.rs b/storage-proto/src/convert.rs index 9750ab1fe..708a866d5 100644 --- a/storage-proto/src/convert.rs +++ b/storage-proto/src/convert.rs @@ -509,6 +509,7 @@ impl TryFrom for TransactionError { 44 => InstructionError::BorshIoError(String::new()), 45 => InstructionError::AccountNotRentExempt, 46 => InstructionError::InvalidAccountOwner, + 47 => InstructionError::ArithmeticOverflow, _ => return Err("Invalid InstructionError"), }; @@ -735,6 +736,9 @@ impl From for tx_by_addr::TransactionError { InstructionError::InvalidAccountOwner => { tx_by_addr::InstructionErrorType::InvalidAccountOwner } + InstructionError::ArithmeticOverflow => { + tx_by_addr::InstructionErrorType::ArithmeticOverflow + } } as i32, custom: match instruction_error { InstructionError::Custom(custom) => { diff --git a/storage-proto/src/transaction_by_addr.proto b/storage-proto/src/transaction_by_addr.proto index ca46b0960..589cf384e 100644 --- a/storage-proto/src/transaction_by_addr.proto +++ b/storage-proto/src/transaction_by_addr.proto @@ -96,6 +96,7 @@ enum InstructionErrorType { BORSH_IO_ERROR = 44; ACCOUNT_NOT_RENT_EXEMPT = 45; INVALID_ACCOUNT_OWNER = 46; + ARITHMETIC_OVERFLOW = 47; } message UnixTimestamp {