From 94556b44f55b18afcac26e3057b9d848bda06a80 Mon Sep 17 00:00:00 2001 From: xgreenx Date: Mon, 30 Oct 2023 23:51:27 +0000 Subject: [PATCH 01/10] Avoid possible truncation of higher bits --- crates/services/p2p/src/p2p_service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/services/p2p/src/p2p_service.rs b/crates/services/p2p/src/p2p_service.rs index 23c2d5e0f21..2028e5b3031 100644 --- a/crates/services/p2p/src/p2p_service.rs +++ b/crates/services/p2p/src/p2p_service.rs @@ -169,7 +169,7 @@ impl FuelP2PService { // Reserved nodes do not count against the configured peer input/output limits. let total_peers = config.max_peers_connected + u32::try_from(config.reserved_nodes.len()).expect( - "The number of reserved nodes should be less than `u32::MAX`", + "The numbere of reserved nodes should be less than `u32::max`", ); total_peers * config.max_connections_per_peer From 96f764ab22ab7b7c9abcf2034e183c27e2520919 Mon Sep 17 00:00:00 2001 From: xgreenx Date: Tue, 31 Oct 2023 00:03:26 +0000 Subject: [PATCH 02/10] Update endpoitns and CHANGELOG.md --- crates/client/src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/client/src/client.rs b/crates/client/src/client.rs index 4164c4220cb..22018fb9bd1 100644 --- a/crates/client/src/client.rs +++ b/crates/client/src/client.rs @@ -466,7 +466,7 @@ impl FuelClient { self.query(query).await.map(|r| r.execute) } - pub async fn register(&self, id: &str, register: RegisterId) -> io::Result { + pub async fn register(&self, id: &str, register: u32) -> io::Result { let query = schema::Register::build(RegisterArgs { id: id.into(), register: register.into(), From 0d8e885a421636d744526ad7cff5960bca0290da Mon Sep 17 00:00:00 2001 From: xgreenx Date: Tue, 31 Oct 2023 16:36:44 +0000 Subject: [PATCH 03/10] Handling overflows by adding `clippy::arithmetic_side_effects` --- bin/fuel-core-client/src/main.rs | 2 ++ bin/fuel-core/src/main.rs | 2 ++ crates/chain-config/src/lib.rs | 1 + crates/chain-config/src/serialization.rs | 22 ++++++++----------- crates/client/src/lib.rs | 1 + crates/database/src/lib.rs | 1 + crates/fuel-core/src/coins_query.rs | 8 +++++-- crates/fuel-core/src/database/block.rs | 6 ++++- crates/fuel-core/src/database/vm_database.rs | 8 ++++++- crates/fuel-core/src/executor.rs | 1 + crates/fuel-core/src/lib.rs | 1 + crates/fuel-core/src/query/balance.rs | 7 +++--- crates/fuel-core/src/schema.rs | 4 ++-- crates/fuel-core/src/service/genesis.rs | 4 +++- crates/fuel-core/src/state/rocks_db.rs | 6 ++--- crates/keygen/src/lib.rs | 1 + crates/metrics/src/future_tracker.rs | 4 ++-- crates/metrics/src/lib.rs | 1 + .../services/consensus_module/bft/src/lib.rs | 1 + .../poa/src/deadline_clock.rs | 8 ++++++- .../services/consensus_module/poa/src/lib.rs | 1 + .../consensus_module/poa/src/service.rs | 12 +++++----- .../consensus_module/poa/src/service_test.rs | 2 ++ .../services/consensus_module/poa/src/sync.rs | 1 + crates/services/consensus_module/src/lib.rs | 1 + crates/services/executor/src/lib.rs | 1 + crates/services/importer/src/lib.rs | 1 + crates/services/p2p/src/discovery.rs | 6 +++-- crates/services/p2p/src/gossipsub/config.rs | 22 +++++++++++++++---- crates/services/p2p/src/heartbeat/handler.rs | 6 ++--- crates/services/p2p/src/lib.rs | 1 + crates/services/p2p/src/p2p_service.rs | 11 +++++----- crates/services/p2p/src/peer_manager.rs | 15 ++++++++----- .../p2p/src/peer_manager/heartbeat_data.rs | 13 ++++++----- crates/services/p2p/src/service.rs | 7 ++++-- crates/services/producer/src/lib.rs | 1 + crates/services/relayer/src/lib.rs | 1 + .../relayer/src/service/get_logs/test.rs | 1 + crates/services/relayer/src/test_helpers.rs | 1 + crates/services/src/lib.rs | 1 + crates/services/sync/src/import.rs | 13 +++++------ .../sync/src/import/back_pressure_tests.rs | 1 + .../services/sync/src/import/test_helpers.rs | 1 + crates/services/sync/src/import/tests.rs | 1 + crates/services/sync/src/lib.rs | 1 + .../txpool/src/containers/dependency.rs | 5 +++-- crates/services/txpool/src/lib.rs | 1 + crates/services/txpool/src/service.rs | 2 +- .../txpool/src/service/update_sender/tests.rs | 2 ++ crates/services/txpool/src/txpool.rs | 7 +++++- crates/storage/src/lib.rs | 1 + crates/trace/src/lib.rs | 1 + crates/types/src/blockchain/primitives.rs | 8 ------- crates/types/src/lib.rs | 1 + 54 files changed, 160 insertions(+), 79 deletions(-) diff --git a/bin/fuel-core-client/src/main.rs b/bin/fuel-core-client/src/main.rs index c1f398854b0..f6048a31937 100644 --- a/bin/fuel-core-client/src/main.rs +++ b/bin/fuel-core-client/src/main.rs @@ -1,3 +1,5 @@ +#![deny(clippy::arithmetic_side_effects)] +#![deny(clippy::cast_possible_truncation)] #![deny(unused_crate_dependencies)] #![deny(warnings)] diff --git a/bin/fuel-core/src/main.rs b/bin/fuel-core/src/main.rs index ec25651588f..e7f5c817980 100644 --- a/bin/fuel-core/src/main.rs +++ b/bin/fuel-core/src/main.rs @@ -1,3 +1,5 @@ +#![deny(clippy::arithmetic_side_effects)] +#![deny(clippy::cast_possible_truncation)] #![deny(unused_crate_dependencies)] #![deny(warnings)] diff --git a/crates/chain-config/src/lib.rs b/crates/chain-config/src/lib.rs index a3ead0bc5b5..5cd1755609d 100644 --- a/crates/chain-config/src/lib.rs +++ b/crates/chain-config/src/lib.rs @@ -1,4 +1,5 @@ #![deny(clippy::cast_possible_truncation)] +#![deny(clippy::arithmetic_side_effects)] #![deny(unused_crate_dependencies)] #![deny(warnings)] diff --git a/crates/chain-config/src/serialization.rs b/crates/chain-config/src/serialization.rs index 03419e344e6..eac42499cdf 100644 --- a/crates/chain-config/src/serialization.rs +++ b/crates/chain-config/src/serialization.rs @@ -140,21 +140,17 @@ macro_rules! impl_hex_number { { const SIZE: usize = core::mem::size_of::<$i>(); let mut bytes: Vec = serde_hex::deserialize(deserializer)?; - match bytes.len() { - len if len > SIZE => { - return Err(D::Error::custom(format!( + let pad = + SIZE.checked_sub(bytes.len()) + .ok_or(D::Error::custom(format!( "value cant exceed {WORD_SIZE} bytes" - ))) - } - len if len < SIZE => { - // pad if length < word size - bytes = (0..SIZE - len) - .map(|_| 0u8) - .chain(bytes.into_iter()) - .collect(); - } - _ => {} + )))?; + + if pad != 0 { + // pad if length < word size + bytes = (0..pad).map(|_| 0u8).chain(bytes.into_iter()).collect(); } + // We've already verified the bytes.len == WORD_SIZE, force the conversion here. Ok($i::from_be_bytes( bytes.try_into().expect("byte lengths checked"), diff --git a/crates/client/src/lib.rs b/crates/client/src/lib.rs index 75c244d59d0..f10aac15b82 100644 --- a/crates/client/src/lib.rs +++ b/crates/client/src/lib.rs @@ -1,3 +1,4 @@ +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] #![deny(unused_crate_dependencies)] #![deny(warnings)] diff --git a/crates/database/src/lib.rs b/crates/database/src/lib.rs index 2c4d856dd8d..d7417682717 100644 --- a/crates/database/src/lib.rs +++ b/crates/database/src/lib.rs @@ -4,6 +4,7 @@ //! defined here are used by services but are flexible enough to customize the //! logic when the `Database` is known. +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] #![deny(missing_docs)] #![deny(unused_crate_dependencies)] diff --git a/crates/fuel-core/src/coins_query.rs b/crates/fuel-core/src/coins_query.rs index 91cf0542b5b..254e5f1b7f3 100644 --- a/crates/fuel-core/src/coins_query.rs +++ b/crates/fuel-core/src/coins_query.rs @@ -185,9 +185,12 @@ pub fn random_improve( } // Break if adding doesn't improve the distance - let change_amount = collected_amount - target; + let change_amount = collected_amount + .checked_sub(target) + .expect("We checked it above"); let distance = target.abs_diff(change_amount); - let next_distance = target.abs_diff(change_amount + coin.amount()); + let next_distance = + target.abs_diff(change_amount.saturating_add(coin.amount())); if next_distance >= distance { break } @@ -215,6 +218,7 @@ impl From for CoinsQueryError { } } +#[allow(clippy::arithmetic_side_effects)] #[cfg(test)] mod tests { use crate::{ diff --git a/crates/fuel-core/src/database/block.rs b/crates/fuel-core/src/database/block.rs index b8584aa2abf..37c423f76d4 100644 --- a/crates/fuel-core/src/database/block.rs +++ b/crates/fuel-core/src/database/block.rs @@ -275,7 +275,10 @@ impl Database { MerkleTree::load(storage, commit_merkle_metadata.version) .map_err(|err| StorageError::Other(anyhow::anyhow!(err)))?; - let proof_index = message_merkle_metadata.version - 1; + let proof_index = message_merkle_metadata + .version + .checked_sub(1) + .ok_or(anyhow::anyhow!("The count of leafs - messages is zero"))?; let (_, proof_set) = tree .prove(proof_index) .map_err(|err| StorageError::Other(anyhow::anyhow!(err)))?; @@ -287,6 +290,7 @@ impl Database { } } +#[allow(clippy::arithmetic_side_effects)] #[cfg(test)] mod tests { use super::*; diff --git a/crates/fuel-core/src/database/vm_database.rs b/crates/fuel-core/src/database/vm_database.rs index 59200765093..7baee7e32f2 100644 --- a/crates/fuel-core/src/database/vm_database.rs +++ b/crates/fuel-core/src/database/vm_database.rs @@ -612,7 +612,13 @@ mod tests { // check stored data let results: Vec<_> = (0..remove_count) .filter_map(|i| { - let current_key = U256::from_big_endian(&start_key) + i; + let (current_key, overflow) = + U256::from_big_endian(&start_key).overflowing_add(i.into()); + + if overflow { + return None + } + let current_key = u256_to_bytes32(current_key); let result = db .merkle_contract_state(&contract_id, ¤t_key) diff --git a/crates/fuel-core/src/executor.rs b/crates/fuel-core/src/executor.rs index 4fb215e6ef4..435778d1c78 100644 --- a/crates/fuel-core/src/executor.rs +++ b/crates/fuel-core/src/executor.rs @@ -1780,6 +1780,7 @@ impl Fee for CreateCheckedMetadata { } } +#[allow(clippy::arithmetic_side_effects)] #[allow(clippy::cast_possible_truncation)] #[cfg(test)] mod tests { diff --git a/crates/fuel-core/src/lib.rs b/crates/fuel-core/src/lib.rs index 6653d97d8ae..f5e97af8da3 100644 --- a/crates/fuel-core/src/lib.rs +++ b/crates/fuel-core/src/lib.rs @@ -1,3 +1,4 @@ +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] #![deny(unused_crate_dependencies)] #![deny(warnings)] diff --git a/crates/fuel-core/src/query/balance.rs b/crates/fuel-core/src/query/balance.rs index aa25157e042..c5977422257 100644 --- a/crates/fuel-core/src/query/balance.rs +++ b/crates/fuel-core/src/query/balance.rs @@ -63,7 +63,7 @@ impl BalanceQueryData for Database { let amount = res?; // Increase the balance - balance += amount; + balance = balance.saturating_add(amount); Ok(balance) })?; @@ -87,9 +87,10 @@ impl BalanceQueryData for Database { for coin in AssetsQuery::new(&owner, None, None, self, &base_asset_id).coins() { match coin { Ok(coin) => { - *amounts_per_asset + let amount: &mut u64 = amounts_per_asset .entry(*coin.asset_id(&base_asset_id)) - .or_default() += coin.amount(); + .or_default(); + *amount = amount.saturating_add(coin.amount()); } Err(err) => { errors.push(err); diff --git a/crates/fuel-core/src/schema.rs b/crates/fuel-core/src/schema.rs index 136da0e69bd..8258980950c 100644 --- a/crates/fuel-core/src/schema.rs +++ b/crates/fuel-core/src/schema.rs @@ -154,7 +154,7 @@ where false }); - let mut count = count + 1 /* for `has_next_page` */; + let mut count = count.saturating_add(1) /* for `has_next_page` */; let entries = entries.take(count).take_while(|result| { if let Ok((key, _)) = result { if let Some(end) = end.as_ref() { @@ -164,7 +164,7 @@ where return false } } - count -= 1; + count = count.saturating_sub(1); has_next_page |= count == 0; count != 0 } else { diff --git a/crates/fuel-core/src/service/genesis.rs b/crates/fuel-core/src/service/genesis.rs index 4b8208dd992..e416f4e7e44 100644 --- a/crates/fuel-core/src/service/genesis.rs +++ b/crates/fuel-core/src/service/genesis.rs @@ -176,7 +176,9 @@ fn init_coin_state( .expect("Incorrect genesis transaction id byte length") }), coin.output_index.unwrap_or_else(|| { - generated_output_index += 1; + generated_output_index = generated_output_index + .checked_add(1) + .expect("We don't support so many UTXOs in the genesis"); (generated_output_index % 255) as u8 }), ); diff --git a/crates/fuel-core/src/state/rocks_db.rs b/crates/fuel-core/src/state/rocks_db.rs index 84a762c1bb2..09aebbba494 100644 --- a/crates/fuel-core/src/state/rocks_db.rs +++ b/crates/fuel-core/src/state/rocks_db.rs @@ -159,9 +159,9 @@ impl RocksDb { let key_as_vec = Vec::from(key); database_metrics().read_meter.inc(); - database_metrics() - .bytes_read - .observe((key_as_vec.len() + value_as_vec.len()) as f64); + database_metrics().bytes_read.observe( + (key_as_vec.len().saturating_add(value_as_vec.len())) as f64, + ); (key_as_vec, Arc::new(value_as_vec)) }) diff --git a/crates/keygen/src/lib.rs b/crates/keygen/src/lib.rs index f714510391f..e374058facf 100644 --- a/crates/keygen/src/lib.rs +++ b/crates/keygen/src/lib.rs @@ -1,5 +1,6 @@ //! Keygen crate +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] pub const BLOCK_PRODUCTION: &str = "block-production"; diff --git a/crates/metrics/src/future_tracker.rs b/crates/metrics/src/future_tracker.rs index 2bd0cad3853..a3beb43672c 100644 --- a/crates/metrics/src/future_tracker.rs +++ b/crates/metrics/src/future_tracker.rs @@ -45,7 +45,7 @@ impl<'a> Entered<'a> { impl<'a> Drop for Entered<'a> { #[inline(always)] fn drop(&mut self) { - self.span.busy += self.busy_instant.elapsed(); + self.span.busy = self.span.busy.saturating_add(self.busy_instant.elapsed()); self.span.do_exit() } } @@ -77,7 +77,7 @@ impl Span { let idle_instant = core::mem::take(&mut self.idle_instant); if let Some(idle_instant) = idle_instant { - self.idle += idle_instant.elapsed(); + self.idle = self.idle.saturating_add(idle_instant.elapsed()); } } diff --git a/crates/metrics/src/lib.rs b/crates/metrics/src/lib.rs index 808e73da553..9a7ad26f851 100644 --- a/crates/metrics/src/lib.rs +++ b/crates/metrics/src/lib.rs @@ -1,3 +1,4 @@ +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] #![deny(unused_crate_dependencies)] #![deny(warnings)] diff --git a/crates/services/consensus_module/bft/src/lib.rs b/crates/services/consensus_module/bft/src/lib.rs index facbc5b648c..63f47aa5d2e 100644 --- a/crates/services/consensus_module/bft/src/lib.rs +++ b/crates/services/consensus_module/bft/src/lib.rs @@ -1,3 +1,4 @@ +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] #![deny(unused_crate_dependencies)] #![deny(warnings)] diff --git a/crates/services/consensus_module/poa/src/deadline_clock.rs b/crates/services/consensus_module/poa/src/deadline_clock.rs index d1c0626bc02..e652e551e30 100644 --- a/crates/services/consensus_module/poa/src/deadline_clock.rs +++ b/crates/services/consensus_module/poa/src/deadline_clock.rs @@ -131,7 +131,13 @@ impl DeadlineClock { /// Sets the timeout, optionally overwriting the existing value pub async fn set_timeout(&self, after: Duration, on_conflict: OnConflict) { - self.set_deadline(Instant::now() + after, on_conflict).await; + self.set_deadline( + Instant::now() + .checked_add(after) + .expect("Setting timeout after many years doesn't make a lot of sense"), + on_conflict, + ) + .await; } /// Clears the timeout, so that now event is produced when it expires. diff --git a/crates/services/consensus_module/poa/src/lib.rs b/crates/services/consensus_module/poa/src/lib.rs index f9eedfc73e9..1be9c9ad009 100644 --- a/crates/services/consensus_module/poa/src/lib.rs +++ b/crates/services/consensus_module/poa/src/lib.rs @@ -1,3 +1,4 @@ +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] #![deny(unused_crate_dependencies)] #![deny(unused_must_use)] diff --git a/crates/services/consensus_module/poa/src/service.rs b/crates/services/consensus_module/poa/src/service.rs index 6affb419f69..46b84e14a26 100644 --- a/crates/services/consensus_module/poa/src/service.rs +++ b/crates/services/consensus_module/poa/src/service.rs @@ -201,7 +201,9 @@ where let last_timestamp = last_block.time(); let duration = Duration::from_secs(Tai64::now().0.saturating_sub(last_timestamp.0)); - let last_block_created = Instant::now() - duration; + let last_block_created = Instant::now() + .checked_sub(duration) + .unwrap_or(Instant::now()); let last_height = *last_block.height(); (last_height, last_timestamp, last_block_created) } @@ -340,13 +342,13 @@ where } (Trigger::Instant, _) => {} (Trigger::Interval { block_time }, RequestType::Trigger) => { - self.timer - .set_deadline(last_block_created + block_time, OnConflict::Min) - .await; + let deadline = last_block_created.checked_add(block_time).expect("It is impossible to overflow except in the case where we don't want to produce a block."); + self.timer.set_deadline(deadline, OnConflict::Min).await; } (Trigger::Interval { block_time }, RequestType::Manual) => { + let deadline = last_block_created.checked_add(block_time).expect("It is impossible to overflow except in the case where we don't want to produce a block."); self.timer - .set_deadline(last_block_created + block_time, OnConflict::Overwrite) + .set_deadline(deadline, OnConflict::Overwrite) .await; } } diff --git a/crates/services/consensus_module/poa/src/service_test.rs b/crates/services/consensus_module/poa/src/service_test.rs index 3819c7cf366..472d2c15e24 100644 --- a/crates/services/consensus_module/poa/src/service_test.rs +++ b/crates/services/consensus_module/poa/src/service_test.rs @@ -1,3 +1,5 @@ +#![allow(clippy::arithmetic_side_effects)] + use crate::{ new_service, ports::{ diff --git a/crates/services/consensus_module/poa/src/sync.rs b/crates/services/consensus_module/poa/src/sync.rs index 37cbb640f1d..8086493b610 100644 --- a/crates/services/consensus_module/poa/src/sync.rs +++ b/crates/services/consensus_module/poa/src/sync.rs @@ -264,6 +264,7 @@ impl InnerSyncState { } } +#[allow(clippy::arithmetic_side_effects)] #[cfg(test)] mod tests { use super::*; diff --git a/crates/services/consensus_module/src/lib.rs b/crates/services/consensus_module/src/lib.rs index 6e590b0f23a..bcc45592cc7 100644 --- a/crates/services/consensus_module/src/lib.rs +++ b/crates/services/consensus_module/src/lib.rs @@ -1,4 +1,5 @@ //! Common traits and logic for managing the lifecycle of services +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] #![deny(unused_crate_dependencies)] #![deny(missing_docs)] diff --git a/crates/services/executor/src/lib.rs b/crates/services/executor/src/lib.rs index ba5ece3c807..09f5f4e6534 100644 --- a/crates/services/executor/src/lib.rs +++ b/crates/services/executor/src/lib.rs @@ -1,3 +1,4 @@ +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] #![deny(unused_crate_dependencies)] #![deny(warnings)] diff --git a/crates/services/importer/src/lib.rs b/crates/services/importer/src/lib.rs index 4e4bafdbb0b..018264660f2 100644 --- a/crates/services/importer/src/lib.rs +++ b/crates/services/importer/src/lib.rs @@ -1,3 +1,4 @@ +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] #![deny(unused_crate_dependencies)] #![deny(warnings)] diff --git a/crates/services/p2p/src/discovery.rs b/crates/services/p2p/src/discovery.rs index b7bb0ed9266..7fe967886ce 100644 --- a/crates/services/p2p/src/discovery.rs +++ b/crates/services/p2p/src/discovery.rs @@ -149,8 +149,10 @@ impl NetworkBehaviour for DiscoveryBehaviour { Box::pin(tokio::time::sleep(self.duration_to_next_kad)); // duration to next random walk should either be exponentially bigger than the previous // or at max 60 seconds - self.duration_to_next_kad = - std::cmp::min(self.duration_to_next_kad * 2, SIXTY_SECONDS); + self.duration_to_next_kad = std::cmp::min( + self.duration_to_next_kad.saturating_mul(2), + SIXTY_SECONDS, + ); } } diff --git a/crates/services/p2p/src/gossipsub/config.rs b/crates/services/p2p/src/gossipsub/config.rs index c703ac23064..ab907964eed 100644 --- a/crates/services/p2p/src/gossipsub/config.rs +++ b/crates/services/p2p/src/gossipsub/config.rs @@ -116,7 +116,11 @@ fn initialize_topic_score_params(topic_weight: f64) -> TopicScoreParams { // The decay time for the first message delivered score, set to 100 times the epoch duration. // This means that the score given for first message deliveries will decay over this time period. - params.first_message_deliveries_decay = score_parameter_decay(EPOCH * 100); + params.first_message_deliveries_decay = score_parameter_decay( + EPOCH + .checked_mul(100) + .expect("`EPOCH` is usually not more than a year"), + ); params.first_message_deliveries_cap = 1000.0; params.first_message_deliveries_weight = 0.5; @@ -130,7 +134,11 @@ fn initialize_topic_score_params(topic_weight: f64) -> TopicScoreParams { params.mesh_failure_penalty_weight = 0.0; params.invalid_message_deliveries_weight = -10.0 / params.topic_weight; // -200 per invalid message - params.invalid_message_deliveries_decay = score_parameter_decay(EPOCH * 50); + params.invalid_message_deliveries_decay = score_parameter_decay( + EPOCH + .checked_mul(50) + .expect("`EPOCH` is usually not more than a year"), + ); params } @@ -144,11 +152,17 @@ fn initialize_peer_score_params(thresholds: &PeerScoreThresholds) -> PeerScorePa let mut params = PeerScoreParams { decay_interval: DECAY_INTERVAL, decay_to_zero: DECAY_TO_ZERO, - retain_score: EPOCH * 100, + retain_score: EPOCH + .checked_mul(100) + .expect("`EPOCH` is usually not more than a year"), app_specific_weight: 0.0, ip_colocation_factor_threshold: 8.0, // Allow up to 8 nodes per IP behaviour_penalty_threshold: 6.0, - behaviour_penalty_decay: score_parameter_decay(EPOCH * 10), + behaviour_penalty_decay: score_parameter_decay( + EPOCH + .checked_mul(10) + .expect("`EPOCH` is usually not more than a year"), + ), ..Default::default() }; diff --git a/crates/services/p2p/src/heartbeat/handler.rs b/crates/services/p2p/src/heartbeat/handler.rs index f7484e9a678..f7c27c023a9 100644 --- a/crates/services/p2p/src/heartbeat/handler.rs +++ b/crates/services/p2p/src/heartbeat/handler.rs @@ -219,7 +219,7 @@ impl ConnectionHandler for HeartbeatHandler { Poll::Pending => { if self.timer.poll_unpin(cx).is_ready() { // Time for successful send expired! - self.failure_count += 1; + self.failure_count = self.failure_count.saturating_add(1); debug!(target: "fuel-libp2p", "Sending Heartbeat timed out, this is {} time it failed with this connection", self.failure_count); } else { self.outbound = Some(OutboundState::SendingBlockHeight( @@ -236,7 +236,7 @@ impl ConnectionHandler for HeartbeatHandler { self.outbound = Some(OutboundState::Idle(stream)); } Poll::Ready(Err(_)) => { - self.failure_count += 1; + self.failure_count = self.failure_count.saturating_add(1); debug!(target: "fuel-libp2p", "Sending Heartbeat failed, {}/{} failures for this connection", self.failure_count, self.config.max_failures); } } @@ -299,7 +299,7 @@ impl ConnectionHandler for HeartbeatHandler { } ConnectionEvent::DialUpgradeError(_) => { self.outbound = None; - self.failure_count += 1; + self.failure_count = self.failure_count.saturating_add(1); } _ => {} } diff --git a/crates/services/p2p/src/lib.rs b/crates/services/p2p/src/lib.rs index b8a576eacf5..4f7753acb59 100644 --- a/crates/services/p2p/src/lib.rs +++ b/crates/services/p2p/src/lib.rs @@ -1,3 +1,4 @@ +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] pub mod behavior; diff --git a/crates/services/p2p/src/p2p_service.rs b/crates/services/p2p/src/p2p_service.rs index 2028e5b3031..c30990061ea 100644 --- a/crates/services/p2p/src/p2p_service.rs +++ b/crates/services/p2p/src/p2p_service.rs @@ -166,13 +166,14 @@ impl FuelP2PService { let behaviour = FuelBehaviour::new(&config, codec.clone()); let total_connections = { + let reserved_nodes_count = u32::try_from(config.reserved_nodes.len()) + .expect("The number of reserved nodes should be less than `u32::max`"); // Reserved nodes do not count against the configured peer input/output limits. - let total_peers = config.max_peers_connected - + u32::try_from(config.reserved_nodes.len()).expect( - "The numbere of reserved nodes should be less than `u32::max`", - ); + let total_peers = config + .max_peers_connected + .saturating_add(reserved_nodes_count); - total_peers * config.max_connections_per_peer + total_peers.saturating_mul(config.max_connections_per_peer) }; let max_established_incoming = { diff --git a/crates/services/p2p/src/peer_manager.rs b/crates/services/p2p/src/peer_manager.rs index 2a41db43473..327339f94b1 100644 --- a/crates/services/p2p/src/peer_manager.rs +++ b/crates/services/p2p/src/peer_manager.rs @@ -76,8 +76,9 @@ impl PeerManager { connection_state: Arc>, max_non_reserved_peers: usize, ) -> Self { - let (reserved_peers_updates, _) = - tokio::sync::broadcast::channel(1 + reserved_peers.len() * 2); + let (reserved_peers_updates, _) = tokio::sync::broadcast::channel( + reserved_peers.len().saturating_mul(2).saturating_add(1), + ); Self { score_config: ScoreConfig::default(), @@ -183,7 +184,9 @@ impl PeerManager { } pub fn total_peers_connected(&self) -> usize { - self.reserved_connected_peers.len() + self.non_reserved_connected_peers.len() + self.reserved_connected_peers + .len() + .saturating_add(self.non_reserved_connected_peers.len()) } pub fn get_peers_ids(&self) -> impl Iterator { @@ -220,7 +223,7 @@ impl PeerManager { if !is_reserved { // check were all the slots taken prior to this disconnect let all_slots_taken = self.max_non_reserved_peers - == self.non_reserved_connected_peers.len() + 1; + == self.non_reserved_connected_peers.len().saturating_add(1); if self.non_reserved_connected_peers.remove(&peer_id).is_some() && all_slots_taken @@ -274,7 +277,9 @@ impl PeerManager { return true } - if non_reserved_peers_connected + 1 == self.max_non_reserved_peers { + if non_reserved_peers_connected.saturating_add(1) + == self.max_non_reserved_peers + { // this is the last non-reserved peer allowed if let Ok(mut connection_state) = self.connection_state.write() { connection_state.deny_new_peers(); diff --git a/crates/services/p2p/src/peer_manager/heartbeat_data.rs b/crates/services/p2p/src/peer_manager/heartbeat_data.rs index c96e689e92d..af3043549aa 100644 --- a/crates/services/p2p/src/peer_manager/heartbeat_data.rs +++ b/crates/services/p2p/src/peer_manager/heartbeat_data.rs @@ -32,10 +32,13 @@ impl HeartbeatData { if self.durations.is_empty() { Duration::from_secs(0) } else { - self.durations.iter().sum::() - / u32::try_from(self.durations.len()).expect( - "The size of window is `u32`, so it is impossible to overflow", - ) + let len = u32::try_from(self.durations.len()) + .expect("The size of window is `u32`, so it is impossible to overflow"); + self.durations + .iter() + .sum::() + .checked_div(len) + .expect("The length is non-zero because of the check above") } } @@ -50,7 +53,7 @@ impl HeartbeatData { self.block_height = Some(block_height); let old_hearbeat = self.last_heartbeat; self.last_heartbeat = Instant::now(); - let new_duration = self.last_heartbeat - old_hearbeat; + let new_duration = self.last_heartbeat.saturating_duration_since(old_hearbeat); self.add_new_duration(new_duration); } } diff --git a/crates/services/p2p/src/service.rs b/crates/services/p2p/src/service.rs index 008107aa631..804ba901700 100644 --- a/crates/services/p2p/src/service.rs +++ b/crates/services/p2p/src/service.rs @@ -363,7 +363,10 @@ impl Task, D, SharedState> { let reserved_peers_broadcast = p2p_service.peer_manager().reserved_peers_updates(); - let next_check_time = Instant::now() + heartbeat_check_interval; + let next_check_time = + Instant::now().checked_add(heartbeat_check_interval).expect( + "The heartbeat check interval should be small enough to do frequently", + ); Self { chain_id, @@ -519,7 +522,7 @@ where // Note: this range has already been check for // validity in `SharedState::get_sealed_block_headers`. - let block_height = BlockHeight::from(block_height_range.end - 1); + let block_height = BlockHeight::from(block_height_range.end.saturating_sub(1)); let peer = self.p2p_service .get_peer_id_with_height(&block_height); let _ = self.p2p_service.send_request_msg(peer, request_msg, channel_item); diff --git a/crates/services/producer/src/lib.rs b/crates/services/producer/src/lib.rs index 1b38043294e..9a4007ba9fe 100644 --- a/crates/services/producer/src/lib.rs +++ b/crates/services/producer/src/lib.rs @@ -1,3 +1,4 @@ +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] #![deny(unused_crate_dependencies)] #![deny(unused_must_use)] diff --git a/crates/services/relayer/src/lib.rs b/crates/services/relayer/src/lib.rs index 22db36406fe..9aa70b6b553 100644 --- a/crates/services/relayer/src/lib.rs +++ b/crates/services/relayer/src/lib.rs @@ -1,5 +1,6 @@ //! # Fuel Relayer +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] #![deny(unused_crate_dependencies)] #![forbid(unsafe_code)] diff --git a/crates/services/relayer/src/service/get_logs/test.rs b/crates/services/relayer/src/service/get_logs/test.rs index 8e9582c2847..a3acd34f7f0 100644 --- a/crates/services/relayer/src/service/get_logs/test.rs +++ b/crates/services/relayer/src/service/get_logs/test.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects)] use ethers_core::types::U256; use std::{ ops::RangeInclusive, diff --git a/crates/services/relayer/src/test_helpers.rs b/crates/services/relayer/src/test_helpers.rs index 08aca6dd901..2b00477134a 100644 --- a/crates/services/relayer/src/test_helpers.rs +++ b/crates/services/relayer/src/test_helpers.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects)] #![allow(missing_docs)] use std::convert::TryFrom; diff --git a/crates/services/src/lib.rs b/crates/services/src/lib.rs index b3bdecef48a..12333c5b50d 100644 --- a/crates/services/src/lib.rs +++ b/crates/services/src/lib.rs @@ -1,4 +1,5 @@ //! Common traits and logic for managing the lifecycle of services +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] #![deny(unused_crate_dependencies)] #![deny(missing_docs)] diff --git a/crates/services/sync/src/import.rs b/crates/services/sync/src/import.rs index ee474d4dae5..c02f1d920a5 100644 --- a/crates/services/sync/src/import.rs +++ b/crates/services/sync/src/import.rs @@ -171,7 +171,7 @@ where if count < range_len { let count = u32::try_from(count) .expect("Size of the range can't be more than maximum `BlockHeight`"); - let incomplete_range = (*range.start() + count)..=*range.end(); + let incomplete_range = range.start().saturating_add(count)..=*range.end(); self.state .apply(|s| s.failed_to_process(incomplete_range.clone())); Err(anyhow::anyhow!( @@ -285,7 +285,7 @@ where // Count the number of successfully executed blocks. // Fold the stream into a count. .fold(0usize, |count, batch| async move { - count + batch.results.len() + count.checked_add(batch.results.len()).expect("It is impossible to fetch so much data to overflow `usize`") }) .await; @@ -371,12 +371,11 @@ fn range_chunks( range: RangeInclusive, chunk_size: usize, ) -> impl Iterator> { - let end = *range.end() + 1; + let end = range.end().saturating_add(1); + let chunk_size_u32 = + u32::try_from(chunk_size).expect("The size of the chunk can't exceed `u32`"); range.step_by(chunk_size).map(move |chunk_start| { - let block_end = (chunk_start - + u32::try_from(chunk_size) - .expect("The size of the chunk can't exceed `u32`")) - .min(end); + let block_end = (chunk_start.saturating_add(chunk_size_u32)).min(end); chunk_start..block_end }) } diff --git a/crates/services/sync/src/import/back_pressure_tests.rs b/crates/services/sync/src/import/back_pressure_tests.rs index c58fc97032d..9085e25efc3 100644 --- a/crates/services/sync/src/import/back_pressure_tests.rs +++ b/crates/services/sync/src/import/back_pressure_tests.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects)] use std::time::Duration; use super::*; diff --git a/crates/services/sync/src/import/test_helpers.rs b/crates/services/sync/src/import/test_helpers.rs index 125c0afd797..5a9d37ad477 100644 --- a/crates/services/sync/src/import/test_helpers.rs +++ b/crates/services/sync/src/import/test_helpers.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects)] #![allow(missing_docs)] mod counts; diff --git a/crates/services/sync/src/import/tests.rs b/crates/services/sync/src/import/tests.rs index 91d49eed44f..11e2164b374 100644 --- a/crates/services/sync/src/import/tests.rs +++ b/crates/services/sync/src/import/tests.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects)] #![allow(non_snake_case)] use crate::{ diff --git a/crates/services/sync/src/lib.rs b/crates/services/sync/src/lib.rs index e3596d5f8bc..15f1e2f67fd 100644 --- a/crates/services/sync/src/lib.rs +++ b/crates/services/sync/src/lib.rs @@ -1,3 +1,4 @@ +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] #![deny(unused_crate_dependencies)] #![deny(missing_docs)] diff --git a/crates/services/txpool/src/containers/dependency.rs b/crates/services/txpool/src/containers/dependency.rs index 64c3dbcb344..1df94b60eca 100644 --- a/crates/services/txpool/src/containers/dependency.rs +++ b/crates/services/txpool/src/containers/dependency.rs @@ -365,7 +365,8 @@ impl Dependency { // is it dependent output? if let Some(state) = self.coins.get(utxo_id) { // check depth - max_depth = core::cmp::max(state.depth + 1, max_depth); + max_depth = + core::cmp::max(state.depth.saturating_add(1), max_depth); if max_depth > self.max_depth { return Err(Error::NotInsertedMaxDepth.into()) } @@ -424,7 +425,7 @@ impl Dependency { *utxo_id, CoinState { is_spend_by: Some(tx.id() as TxId), - depth: max_depth - 1, + depth: max_depth.saturating_sub(1), }, ); // yey we got our coin diff --git a/crates/services/txpool/src/lib.rs b/crates/services/txpool/src/lib.rs index cb625e449f2..607be531308 100644 --- a/crates/services/txpool/src/lib.rs +++ b/crates/services/txpool/src/lib.rs @@ -1,3 +1,4 @@ +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] #![deny(unused_crate_dependencies)] #![deny(warnings)] diff --git a/crates/services/txpool/src/service.rs b/crates/services/txpool/src/service.rs index d93ec166e04..e247e196a77 100644 --- a/crates/services/txpool/src/service.rs +++ b/crates/services/txpool/src/service.rs @@ -460,7 +460,7 @@ where // But because of slow/malicious consumers, the subscriber can still be occupied. // We allow the subscriber to receive the event produced by TxPool's TTL. // But we still want to drop subscribers after `2 * TxPool_TTL`. - 2 * config.transaction_ttl, + config.transaction_ttl.saturating_mul(2), ), txpool, p2p, diff --git a/crates/services/txpool/src/service/update_sender/tests.rs b/crates/services/txpool/src/service/update_sender/tests.rs index 65775398e43..75e7f2266d8 100644 --- a/crates/services/txpool/src/service/update_sender/tests.rs +++ b/crates/services/txpool/src/service/update_sender/tests.rs @@ -1,5 +1,7 @@ //! Test module for validating TxUpdateStream state transitions. +#![allow(clippy::arithmetic_side_effects)] + use test_strategy::{ proptest, Arbitrary, diff --git a/crates/services/txpool/src/txpool.rs b/crates/services/txpool/src/txpool.rs index 00d56748b5b..2e1bf6283e9 100644 --- a/crates/services/txpool/src/txpool.rs +++ b/crates/services/txpool/src/txpool.rs @@ -344,7 +344,12 @@ where /// Remove all old transactions from the pool. pub fn prune_old_txs(&mut self) -> Vec { - let deadline = tokio::time::Instant::now() - self.config.transaction_ttl; + let Some(deadline) = + tokio::time::Instant::now().checked_sub(self.config.transaction_ttl) + else { + // TTL is so big that we don't need to prune any transactions + return vec![] + }; let mut result = vec![]; diff --git a/crates/storage/src/lib.rs b/crates/storage/src/lib.rs index 59691da2134..8ff7593b34a 100644 --- a/crates/storage/src/lib.rs +++ b/crates/storage/src/lib.rs @@ -4,6 +4,7 @@ //! defined here are used by services but are flexible enough to customize the //! logic when the `Database` is known. +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] #![deny(unused_crate_dependencies)] #![deny(missing_docs)] diff --git a/crates/trace/src/lib.rs b/crates/trace/src/lib.rs index 9f5c4d0429b..f2c808d1535 100644 --- a/crates/trace/src/lib.rs +++ b/crates/trace/src/lib.rs @@ -1,3 +1,4 @@ +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] use ctor::ctor; diff --git a/crates/types/src/blockchain/primitives.rs b/crates/types/src/blockchain/primitives.rs index f72cb7f60c0..468df2e2407 100644 --- a/crates/types/src/blockchain/primitives.rs +++ b/crates/types/src/blockchain/primitives.rs @@ -111,14 +111,6 @@ impl From for DaBlockHeight { } } -impl core::ops::Add for DaBlockHeight { - type Output = Self; - - fn add(self, other: u64) -> Self::Output { - Self::from(self.0 + other) - } -} - impl DaBlockHeight { /// Convert to array of big endian bytes pub fn to_bytes(self) -> [u8; 8] { diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index d4149eaeab1..5f7c4743ddc 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -2,6 +2,7 @@ //! libraries. This crate doesn't contain any business logic and is to be such primitive as that //! is possible. +#![deny(clippy::arithmetic_side_effects)] #![deny(clippy::cast_possible_truncation)] #![deny(unused_crate_dependencies)] #![deny(missing_docs)] From 2334571197cf899f35df7a29292f7969c42838cf Mon Sep 17 00:00:00 2001 From: xgreenx Date: Tue, 31 Oct 2023 16:47:44 +0000 Subject: [PATCH 04/10] Apply comments from the PR --- crates/client/src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/client/src/client.rs b/crates/client/src/client.rs index 22018fb9bd1..4164c4220cb 100644 --- a/crates/client/src/client.rs +++ b/crates/client/src/client.rs @@ -466,7 +466,7 @@ impl FuelClient { self.query(query).await.map(|r| r.execute) } - pub async fn register(&self, id: &str, register: u32) -> io::Result { + pub async fn register(&self, id: &str, register: RegisterId) -> io::Result { let query = schema::Register::build(RegisterArgs { id: id.into(), register: register.into(), From 75bc05c88b5f0c59891d479e0060e5f1574c0442 Mon Sep 17 00:00:00 2001 From: xgreenx Date: Tue, 31 Oct 2023 16:50:17 +0000 Subject: [PATCH 05/10] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e9e8c3b7ba..7ac0e4fac72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ Description of the upcoming release here. ### Changed +- [#1466](https://github.com/FuelLabs/fuel-core/pull/1466): Handling overflows during arithmetic operations. - [#1460](https://github.com/FuelLabs/fuel-core/pull/1460): Change tracking branch from main to master for releasy tests. - [#1440](https://github.com/FuelLabs/fuel-core/pull/1440): Don't report reserved nodes that send invalid transactions. - [#1439](https://github.com/FuelLabs/fuel-core/pull/1439): Reduced memory BMT consumption during creation of the header. From f37811276f7fa28a0ece1eb552124a9f6044a262 Mon Sep 17 00:00:00 2001 From: xgreenx Date: Tue, 31 Oct 2023 17:02:20 +0000 Subject: [PATCH 06/10] Make CI happy --- crates/services/p2p/src/p2p_service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/services/p2p/src/p2p_service.rs b/crates/services/p2p/src/p2p_service.rs index c30990061ea..23b52d85e81 100644 --- a/crates/services/p2p/src/p2p_service.rs +++ b/crates/services/p2p/src/p2p_service.rs @@ -812,7 +812,7 @@ mod tests { let max_peers_allowed = 3; let (bootstrap_nodes, bootstrap_multiaddrs) = - setup_bootstrap_nodes(&p2p_config, max_peers_allowed * 5).await; + setup_bootstrap_nodes(&p2p_config, max_peers_allowed.saturating_mul(5)).await; let (mut reserved_nodes, reserved_multiaddrs) = setup_bootstrap_nodes(&p2p_config, max_peers_allowed).await; From 2df9dd91b1de0303d5cf7f681e3cab90f408bf49 Mon Sep 17 00:00:00 2001 From: xgreenx Date: Tue, 31 Oct 2023 17:09:57 +0000 Subject: [PATCH 07/10] Make CI happy --- crates/services/p2p/src/p2p_service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/services/p2p/src/p2p_service.rs b/crates/services/p2p/src/p2p_service.rs index 23b52d85e81..963a374e6e6 100644 --- a/crates/services/p2p/src/p2p_service.rs +++ b/crates/services/p2p/src/p2p_service.rs @@ -809,7 +809,7 @@ mod tests { let p2p_config = Config::default_initialized("reserved_nodes_reconnect_works"); // total amount will be `max_peers_allowed` + `reserved_nodes.len()` - let max_peers_allowed = 3; + let max_peers_allowed: usize = 3; let (bootstrap_nodes, bootstrap_multiaddrs) = setup_bootstrap_nodes(&p2p_config, max_peers_allowed.saturating_mul(5)).await; From f070afe913abd2a66d72855916756b3c613ff19f Mon Sep 17 00:00:00 2001 From: Green Baneling Date: Wed, 1 Nov 2023 12:16:50 +0000 Subject: [PATCH 08/10] Update crates/fuel-core/src/service/genesis.rs Co-authored-by: Brandon Kite --- crates/fuel-core/src/service/genesis.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fuel-core/src/service/genesis.rs b/crates/fuel-core/src/service/genesis.rs index e416f4e7e44..8da0fd49637 100644 --- a/crates/fuel-core/src/service/genesis.rs +++ b/crates/fuel-core/src/service/genesis.rs @@ -178,7 +178,7 @@ fn init_coin_state( coin.output_index.unwrap_or_else(|| { generated_output_index = generated_output_index .checked_add(1) - .expect("We don't support so many UTXOs in the genesis"); + .expect("The maximum number of UTXOs supported in the genesis configuration has been exceeded."); (generated_output_index % 255) as u8 }), ); From 56dd6c60f1763d360059fe9bf70bba4ebc1c57c6 Mon Sep 17 00:00:00 2001 From: Green Baneling Date: Wed, 1 Nov 2023 12:16:57 +0000 Subject: [PATCH 09/10] Update crates/services/p2p/src/service.rs Co-authored-by: Brandon Kite --- crates/services/p2p/src/service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/services/p2p/src/service.rs b/crates/services/p2p/src/service.rs index 804ba901700..f6f624bef37 100644 --- a/crates/services/p2p/src/service.rs +++ b/crates/services/p2p/src/service.rs @@ -520,7 +520,7 @@ where let request_msg = RequestMessage::SealedHeaders(block_height_range.clone()); let channel_item = ResponseChannelItem::SealedHeaders(response); - // Note: this range has already been check for + // Note: this range has already been checked for // validity in `SharedState::get_sealed_block_headers`. let block_height = BlockHeight::from(block_height_range.end.saturating_sub(1)); let peer = self.p2p_service From 6a873a3ae9ee10af06629563cad1d9090f62919d Mon Sep 17 00:00:00 2001 From: xgreenx Date: Wed, 1 Nov 2023 12:19:49 +0000 Subject: [PATCH 10/10] Use `checked_sub` because it suits better and more clear --- crates/services/txpool/src/containers/dependency.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/services/txpool/src/containers/dependency.rs b/crates/services/txpool/src/containers/dependency.rs index 1df94b60eca..9fbf4e2e34f 100644 --- a/crates/services/txpool/src/containers/dependency.rs +++ b/crates/services/txpool/src/containers/dependency.rs @@ -425,7 +425,9 @@ impl Dependency { *utxo_id, CoinState { is_spend_by: Some(tx.id() as TxId), - depth: max_depth.saturating_sub(1), + depth: max_depth + .checked_sub(1) + .expect("The `max_depth` is always more than zero above"), }, ); // yey we got our coin