From 224e1e0a37c7223e94f9f58cfbca5b610fbdda01 Mon Sep 17 00:00:00 2001 From: Charan <123436521+charans29@users.noreply.github.com> Date: Wed, 26 Mar 2025 12:05:26 -0400 Subject: [PATCH] Refactor: Move ClampedPercentage type to common folder (#2786) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description: • Moved ClampedPercentage from `fuel-gas-price-algorithm` to `crates/types/src/` for better modularity and reuse. • Updated references in `fuel_gas_price_provider` and `genesis` adapters. • No functional changes, just refactoring. ## Testing: Ran `cargo test --all-targets`, and all tests passed. ## Linked Issue: • ref #2773 Let me know if any further adjustments are needed! --- Cargo.lock | 1 + bin/fuel-core/src/cli/run/gas_price.rs | 7 ++- bin/fuel-core/src/cli/run/tx_pool.rs | 3 +- crates/fuel-core/src/service/adapters.rs | 30 ++++++--- .../adapters/fuel_gas_price_provider/tests.rs | 3 +- .../tests/producer_gas_price_tests.rs | 8 ++- .../service/adapters/gas_price_adapters.rs | 6 +- crates/fuel-core/src/service/config.rs | 17 ++++-- crates/fuel-core/src/service/sub_services.rs | 14 +++-- crates/fuel-gas-price-algorithm/Cargo.toml | 1 + crates/fuel-gas-price-algorithm/src/v0.rs | 26 +++++--- .../fuel-gas-price-algorithm/src/v0/tests.rs | 12 ++-- .../src/v0/tests/algorithm_v0_tests.rs | 14 +++-- crates/fuel-gas-price-algorithm/src/v1.rs | 31 +--------- .../src/common/fuel_core_storage_adapter.rs | 5 +- .../metadata_tests.rs | 4 +- .../gas_price_service/src/v0/metadata.rs | 12 ++-- .../gas_price_service/src/v0/service.rs | 9 ++- .../gas_price_service/src/v0/tests.rs | 9 +-- .../src/v0/uninitialized_task.rs | 4 +- crates/services/importer/src/ports.rs | 5 +- crates/services/txpool_v2/src/config.rs | 5 +- crates/services/txpool_v2/src/pool_worker.rs | 6 +- .../txpool_v2/src/tests/tests_pending_pool.rs | 2 +- crates/storage/src/codec/postcard.rs | 5 +- crates/storage/src/codec/raw.rs | 5 +- crates/types/src/clamped_percentage.rs | 61 +++++++++++++++++++ crates/types/src/lib.rs | 2 + tests/tests/coins.rs | 12 +--- tests/tests/gas_price.rs | 28 ++++----- tests/tests/lib.rs | 1 + .../required_fuel_block_height_extension.rs | 3 +- tests/tests/storage.rs | 8 +-- 33 files changed, 210 insertions(+), 149 deletions(-) create mode 100644 crates/types/src/clamped_percentage.rs diff --git a/Cargo.lock b/Cargo.lock index 1a7bb4533bc..4eb5c0e4714 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4201,6 +4201,7 @@ dependencies = [ name = "fuel-gas-price-algorithm" version = "0.42.0" dependencies = [ + "fuel-core-types 0.42.0", "proptest", "rand 0.8.5", "serde", diff --git a/bin/fuel-core/src/cli/run/gas_price.rs b/bin/fuel-core/src/cli/run/gas_price.rs index 3a0be194b4a..95affb81183 100644 --- a/bin/fuel-core/src/cli/run/gas_price.rs +++ b/bin/fuel-core/src/cli/run/gas_price.rs @@ -1,6 +1,7 @@ use clap::Args; #[cfg(feature = "production")] use fuel_core::service::sub_services::DEFAULT_GAS_PRICE_CHANGE_PERCENT; +use fuel_core_types::clamped_percentage::ClampedPercentage; use url::Url; #[derive(Debug, Clone, Args)] @@ -19,13 +20,13 @@ pub struct GasPriceArgs { /// The percentage change in gas price per block #[cfg_attr( feature = "production", - arg(long = "gas-price-change-percent", default_value_t = DEFAULT_GAS_PRICE_CHANGE_PERCENT, env) + arg(long = "gas-price-change-percent", default_value_t = ClampedPercentage::new(DEFAULT_GAS_PRICE_CHANGE_PERCENT.try_into().unwrap()), env) )] #[cfg_attr( not(feature = "production"), arg(long = "gas-price-change-percent", default_value = "0", env) )] - pub gas_price_change_percent: u16, + pub gas_price_change_percent: ClampedPercentage, /// The minimum allowed gas price #[arg(long = "min-gas-price", default_value = "0", env)] @@ -33,7 +34,7 @@ pub struct GasPriceArgs { /// The percentage threshold for gas price increase #[arg(long = "gas-price-threshold-percent", default_value = "50", env)] - pub gas_price_threshold_percent: u8, + pub gas_price_threshold_percent: ClampedPercentage, /// Minimum DA gas price #[cfg_attr( diff --git a/bin/fuel-core/src/cli/run/tx_pool.rs b/bin/fuel-core/src/cli/run/tx_pool.rs index ce78b6ffeb8..8d2ad5a9867 100644 --- a/bin/fuel-core/src/cli/run/tx_pool.rs +++ b/bin/fuel-core/src/cli/run/tx_pool.rs @@ -1,6 +1,7 @@ //! Clap configuration related to TxPool service. use fuel_core_types::{ + clamped_percentage::ClampedPercentage, fuel_tx::{ Address, ContractId, @@ -88,7 +89,7 @@ pub struct TxPoolArgs { /// The max percentage of the `TxPool` that can be used by the `PendingPool`. #[clap(long = "tx-pending-pool-size-percentage", default_value = "50", env)] - pub tx_pending_pool_size_percentage: u16, + pub tx_pending_pool_size_percentage: ClampedPercentage, } #[cfg(test)] diff --git a/crates/fuel-core/src/service/adapters.rs b/crates/fuel-core/src/service/adapters.rs index 02de422f3c2..0eb8bff991a 100644 --- a/crates/fuel-core/src/service/adapters.rs +++ b/crates/fuel-core/src/service/adapters.rs @@ -33,6 +33,7 @@ use fuel_core_types::{ Consensus, }, }, + clamped_percentage::ClampedPercentage, fuel_tx::{ Bytes32, Transaction, @@ -119,6 +120,7 @@ impl StaticGasPrice { mod universal_gas_price_provider_tests { #![allow(non_snake_case)] + use fuel_core_types::clamped_percentage::ClampedPercentage; use proptest::proptest; use super::*; @@ -127,7 +129,7 @@ mod universal_gas_price_provider_tests { gas_price: u64, starting_height: u32, block_horizon: u32, - percentage: u16, + percentage: ClampedPercentage, ) { // given let subject = @@ -141,8 +143,9 @@ mod universal_gas_price_provider_tests { let mut actual = gas_price; for _ in 0..block_horizon { - let change_amount = - actual.saturating_mul(percentage as u64).saturating_div(100); + let change_amount = actual + .saturating_mul(*percentage as u64) + .saturating_div(100); actual = actual.saturating_add(change_amount); } @@ -157,6 +160,8 @@ mod universal_gas_price_provider_tests { block_horizon in 0..10_000u32, percentage: u16, ) { + #[allow(clippy::cast_possible_truncation)] + let percentage = ClampedPercentage::new(percentage as u8); _worst_case__correctly_calculates_value( gas_price, starting_height, @@ -174,6 +179,9 @@ mod universal_gas_price_provider_tests { block_horizon in 0..10_000u32, percentage: u16 ) { + // Convert u16 to ClampedPercentage + #[allow(clippy::cast_possible_truncation)] + let percentage = ClampedPercentage::new(percentage as u8); // given let subject = UniversalGasPriceProvider::new(starting_height, gas_price, percentage); @@ -190,7 +198,7 @@ mod universal_gas_price_provider_tests { fn _next_gas_price__correctly_calculates_value( gas_price: u64, starting_height: u32, - percentage: u16, + percentage: ClampedPercentage, ) { // given let subject = @@ -201,7 +209,7 @@ mod universal_gas_price_provider_tests { // then let change_amount = gas_price - .saturating_mul(percentage as u64) + .saturating_mul(*percentage as u64) .saturating_div(100); let actual = gas_price.saturating_add(change_amount); @@ -215,6 +223,8 @@ mod universal_gas_price_provider_tests { starting_height: u32, percentage: u16, ) { + #[allow(clippy::cast_possible_truncation)] + let percentage = ClampedPercentage::new(percentage as u8); _next_gas_price__correctly_calculates_value( gas_price, starting_height, @@ -232,7 +242,7 @@ pub struct UniversalGasPriceProvider { /// Shared state of latest gas price data latest_gas_price: LatestGasPrice, /// The max percentage the gas price can increase per block - percentage: u16, + percentage: ClampedPercentage, } impl Clone for UniversalGasPriceProvider { @@ -246,7 +256,7 @@ impl Clone for UniversalGasPriceProvider { impl UniversalGasPriceProvider { #[cfg(test)] - pub fn new(height: Height, price: GasPrice, percentage: u16) -> Self { + pub fn new(height: Height, price: GasPrice, percentage: ClampedPercentage) -> Self { let latest_gas_price = LatestGasPrice::new(height, price); Self { latest_gas_price, @@ -256,7 +266,7 @@ impl UniversalGasPriceProvider { pub fn new_from_inner( inner: LatestGasPrice, - percentage: u16, + percentage: ClampedPercentage, ) -> Self { Self { latest_gas_price: inner, @@ -277,7 +287,7 @@ impl UniversalGasPriceProvider { let percentage = self.percentage; let change = latest_price - .saturating_mul(percentage as u64) + .saturating_mul(*percentage as u64) .saturating_div(100); latest_price.saturating_add(change) @@ -298,7 +308,7 @@ impl GasPriceEstimate for UniversalGasPriceProvider { let worst = cumulative_percentage_change( best_gas_price, best_height, - percentage as u64, + *percentage as u64, height.into(), ); Some(worst) diff --git a/crates/fuel-core/src/service/adapters/fuel_gas_price_provider/tests.rs b/crates/fuel-core/src/service/adapters/fuel_gas_price_provider/tests.rs index 56ef2fd7ddf..b25f610e790 100644 --- a/crates/fuel-core/src/service/adapters/fuel_gas_price_provider/tests.rs +++ b/crates/fuel-core/src/service/adapters/fuel_gas_price_provider/tests.rs @@ -1,6 +1,7 @@ #![allow(non_snake_case)] use super::*; +use fuel_core_types::clamped_percentage::ClampedPercentage; #[cfg(test)] mod producer_gas_price_tests; @@ -9,7 +10,7 @@ fn build_provider( algorithm: A, height: u32, price: u64, - percentage: u16, + percentage: ClampedPercentage, ) -> FuelGasPriceProvider where A: Send + Sync, diff --git a/crates/fuel-core/src/service/adapters/fuel_gas_price_provider/tests/producer_gas_price_tests.rs b/crates/fuel-core/src/service/adapters/fuel_gas_price_provider/tests/producer_gas_price_tests.rs index f84fea71416..2e40c8f791b 100644 --- a/crates/fuel-core/src/service/adapters/fuel_gas_price_provider/tests/producer_gas_price_tests.rs +++ b/crates/fuel-core/src/service/adapters/fuel_gas_price_provider/tests/producer_gas_price_tests.rs @@ -4,13 +4,15 @@ use fuel_core_gas_price_service::{ static_updater::StaticAlgorithm, }; use fuel_core_producer::block_producer::gas_price::GasPriceProvider; +use fuel_core_types::clamped_percentage::ClampedPercentage; #[test] fn production_gas_price__if_requested_block_height_is_latest_return_gas_price() { // given let price = 33; let algo = StaticAlgorithm::new(price); - let gas_price_provider = build_provider(algo.clone(), 0, price, 10); + let gas_price_provider = + build_provider(algo.clone(), 0, price, ClampedPercentage::new(10)); // when let expected_price = algo.next_gas_price(); @@ -25,7 +27,7 @@ fn dry_run_gas_price__calculates_correctly_based_on_percentage() { // given let height = 123; let price = 33; - let percentage = 10; + let percentage = ClampedPercentage::new(10); let algo = StaticAlgorithm::new(price); let gas_price_provider = build_provider(algo.clone(), height, price, percentage); @@ -33,7 +35,7 @@ fn dry_run_gas_price__calculates_correctly_based_on_percentage() { let actual = gas_price_provider.dry_run_gas_price().unwrap(); // then - let change_amount = price.saturating_mul(percentage as u64).saturating_div(100); + let change_amount = price.saturating_mul(*percentage as u64).saturating_div(100); let expected = price + change_amount; assert_eq!(expected, actual); } diff --git a/crates/fuel-core/src/service/adapters/gas_price_adapters.rs b/crates/fuel-core/src/service/adapters/gas_price_adapters.rs index 5504389ec4b..299be998742 100644 --- a/crates/fuel-core/src/service/adapters/gas_price_adapters.rs +++ b/crates/fuel-core/src/service/adapters/gas_price_adapters.rs @@ -90,11 +90,11 @@ impl From for V1AlgorithmConfig { V1AlgorithmConfig { new_exec_gas_price: starting_exec_gas_price.max(min_exec_gas_price), min_exec_gas_price, - exec_gas_price_change_percent, - l2_block_fullness_threshold_percent: exec_gas_price_threshold_percent, + exec_gas_price_change_percent: *exec_gas_price_change_percent as u16, + l2_block_fullness_threshold_percent: *exec_gas_price_threshold_percent, min_da_gas_price, max_da_gas_price, - max_da_gas_price_change_percent, + max_da_gas_price_change_percent: *max_da_gas_price_change_percent as u16, da_p_component: da_gas_price_p_component, da_d_component: da_gas_price_d_component, normal_range_size: activity_normal_range_size, diff --git a/crates/fuel-core/src/service/config.rs b/crates/fuel-core/src/service/config.rs index 3575fc9fa08..1ff22ea6753 100644 --- a/crates/fuel-core/src/service/config.rs +++ b/crates/fuel-core/src/service/config.rs @@ -30,6 +30,7 @@ use fuel_core_tx_status_manager::config::Config as TxStatusManagerConfig; use fuel_core_txpool::config::Config as TxPoolConfig; use fuel_core_types::{ blockchain::header::StateTransitionBytecodeVersion, + clamped_percentage::ClampedPercentage, signer::SignMode, }; @@ -305,16 +306,16 @@ pub enum DbType { #[derive(Clone, Debug)] pub struct GasPriceConfig { pub starting_exec_gas_price: u64, - pub exec_gas_price_change_percent: u16, + pub exec_gas_price_change_percent: ClampedPercentage, pub min_exec_gas_price: u64, - pub exec_gas_price_threshold_percent: u8, + pub exec_gas_price_threshold_percent: ClampedPercentage, pub da_committer_url: Option, pub da_poll_interval: Option, pub da_gas_price_factor: NonZeroU64, pub starting_recorded_height: Option, pub min_da_gas_price: u64, pub max_da_gas_price: u64, - pub max_da_gas_price_change_percent: u16, + pub max_da_gas_price_change_percent: ClampedPercentage, pub da_gas_price_p_component: i64, pub da_gas_price_d_component: i64, pub gas_price_metrics: bool, @@ -335,14 +336,18 @@ impl GasPriceConfig { GasPriceConfig { starting_exec_gas_price: starting_gas_price, - exec_gas_price_change_percent: gas_price_change_percent, + exec_gas_price_change_percent: ClampedPercentage::new( + gas_price_change_percent, + ), min_exec_gas_price: min_gas_price, - exec_gas_price_threshold_percent: gas_price_threshold_percent, + exec_gas_price_threshold_percent: ClampedPercentage::new( + gas_price_threshold_percent, + ), da_gas_price_factor: NonZeroU64::new(100).expect("100 is not zero"), starting_recorded_height: None, min_da_gas_price: 0, max_da_gas_price: 1, - max_da_gas_price_change_percent: 0, + max_da_gas_price_change_percent: ClampedPercentage::new(0), da_gas_price_p_component: 0, da_gas_price_d_component: 0, gas_price_metrics, diff --git a/crates/fuel-core/src/service/sub_services.rs b/crates/fuel-core/src/service/sub_services.rs index 778249b483a..d5536f968ac 100644 --- a/crates/fuel-core/src/service/sub_services.rs +++ b/crates/fuel-core/src/service/sub_services.rs @@ -21,7 +21,10 @@ use fuel_core_storage::{ }; #[cfg(feature = "relayer")] use fuel_core_types::blockchain::primitives::DaBlockHeight; -use fuel_core_types::signer::SignMode; +use fuel_core_types::{ + clamped_percentage::ClampedPercentage, + signer::SignMode, +}; use fuel_core_compression_service::service::new_service as new_compression_service; @@ -262,10 +265,11 @@ pub fn init_sub_services( database.on_chain().clone(), )?; let (gas_price_algo, latest_gas_price) = gas_price_service_v1.shared.clone(); - let universal_gas_price_provider = UniversalGasPriceProvider::new_from_inner( - latest_gas_price, - DEFAULT_GAS_PRICE_CHANGE_PERCENT, - ); + #[allow(clippy::cast_possible_truncation)] + let clamped_percentage = + ClampedPercentage::new(DEFAULT_GAS_PRICE_CHANGE_PERCENT as u8); + let universal_gas_price_provider = + UniversalGasPriceProvider::new_from_inner(latest_gas_price, clamped_percentage); let producer_gas_price_provider = FuelGasPriceProvider::new( gas_price_algo.clone(), diff --git a/crates/fuel-gas-price-algorithm/Cargo.toml b/crates/fuel-gas-price-algorithm/Cargo.toml index 24cb619585c..5a467fc76a2 100644 --- a/crates/fuel-gas-price-algorithm/Cargo.toml +++ b/crates/fuel-gas-price-algorithm/Cargo.toml @@ -15,6 +15,7 @@ name = "fuel_gas_price_algorithm" path = "src/lib.rs" [dependencies] +fuel-core-types = { path = "../types", features = ["serde"] } serde = { workspace = true, features = ["derive"] } thiserror = { workspace = true } tracing = { workspace = true } diff --git a/crates/fuel-gas-price-algorithm/src/v0.rs b/crates/fuel-gas-price-algorithm/src/v0.rs index 126d70a3669..ae3a86b3eb1 100644 --- a/crates/fuel-gas-price-algorithm/src/v0.rs +++ b/crates/fuel-gas-price-algorithm/src/v0.rs @@ -3,6 +3,8 @@ use std::{ num::NonZeroU64, }; +use fuel_core_types::clamped_percentage::ClampedPercentage; + use crate::utils::cumulative_percentage_change; #[cfg(test)] @@ -21,7 +23,7 @@ pub struct AlgorithmV0 { /// The block height of the next L2 block for_height: u32, /// The change percentage per block - percentage: u64, + percentage: ClampedPercentage, } impl AlgorithmV0 { @@ -33,7 +35,7 @@ impl AlgorithmV0 { cumulative_percentage_change( self.new_exec_price, self.for_height, - self.percentage, + *self.percentage as u64, height, ) } @@ -58,12 +60,12 @@ pub struct AlgorithmUpdaterV0 { pub min_exec_gas_price: u64, /// The Percentage the execution gas price will change in a single block, either increase or decrease /// based on the fullness of the last L2 block - pub exec_gas_price_change_percent: u64, + pub exec_gas_price_change_percent: ClampedPercentage, /// The height of the next L2 block pub l2_block_height: u32, /// The threshold of gas usage above and below which the gas price will increase or decrease /// This is a percentage of the total capacity of the L2 block - pub l2_block_fullness_threshold_percent: u64, + pub l2_block_fullness_threshold_percent: ClampedPercentage, } impl AlgorithmUpdaterV0 { @@ -78,9 +80,15 @@ impl AlgorithmUpdaterV0 { Self { new_exec_price: new_exec_price_corrected, min_exec_gas_price, - exec_gas_price_change_percent, + #[allow(clippy::cast_possible_truncation)] + exec_gas_price_change_percent: ClampedPercentage::new( + exec_gas_price_change_percent as u8, + ), l2_block_height, - l2_block_fullness_threshold_percent, + #[allow(clippy::cast_possible_truncation)] + l2_block_fullness_threshold_percent: ClampedPercentage::new( + l2_block_fullness_threshold_percent as u8, + ), } } @@ -108,9 +116,9 @@ impl AlgorithmUpdaterV0 { let fullness_percent = used .saturating_mul(100) .checked_div(capacity.into()) - .unwrap_or(self.l2_block_fullness_threshold_percent); + .unwrap_or(*self.l2_block_fullness_threshold_percent as u64); - match fullness_percent.cmp(&self.l2_block_fullness_threshold_percent) { + match fullness_percent.cmp(&(*self.l2_block_fullness_threshold_percent as u64)) { std::cmp::Ordering::Greater | std::cmp::Ordering::Equal => { let change_amount = self.change_amount(exec_gas_price); exec_gas_price = exec_gas_price.saturating_add(change_amount); @@ -125,7 +133,7 @@ impl AlgorithmUpdaterV0 { fn change_amount(&self, principle: u64) -> u64 { principle - .saturating_mul(self.exec_gas_price_change_percent) + .saturating_mul(*self.exec_gas_price_change_percent as u64) .saturating_div(100) } diff --git a/crates/fuel-gas-price-algorithm/src/v0/tests.rs b/crates/fuel-gas-price-algorithm/src/v0/tests.rs index 49c5bf49ac7..22ff1cee7e2 100644 --- a/crates/fuel-gas-price-algorithm/src/v0/tests.rs +++ b/crates/fuel-gas-price-algorithm/src/v0/tests.rs @@ -2,6 +2,8 @@ #![allow(clippy::arithmetic_side_effects)] #![allow(clippy::cast_possible_truncation)] +use fuel_core_types::clamped_percentage::ClampedPercentage; + use super::AlgorithmUpdaterV0; #[cfg(test)] @@ -12,7 +14,7 @@ mod update_l2_block_data_tests; pub struct UpdaterBuilder { min_exec_gas_price: u64, starting_exec_gas_price: u64, - exec_gas_price_change_percent: u64, + exec_gas_price_change_percent: ClampedPercentage, l2_block_height: u32, l2_block_capacity_threshold: u64, } @@ -22,7 +24,7 @@ impl UpdaterBuilder { Self { min_exec_gas_price: 0, starting_exec_gas_price: 0, - exec_gas_price_change_percent: 0, + exec_gas_price_change_percent: ClampedPercentage::new(0), l2_block_height: 0, l2_block_capacity_threshold: 50, } @@ -39,7 +41,7 @@ impl UpdaterBuilder { } fn with_exec_gas_price_change_percent(mut self, percent: u64) -> Self { - self.exec_gas_price_change_percent = percent; + self.exec_gas_price_change_percent = ClampedPercentage::new(percent as u8); self } @@ -62,7 +64,9 @@ impl UpdaterBuilder { new_exec_price: self.starting_exec_gas_price, exec_gas_price_change_percent: self.exec_gas_price_change_percent, l2_block_height: self.l2_block_height, - l2_block_fullness_threshold_percent: self.l2_block_capacity_threshold, + l2_block_fullness_threshold_percent: ClampedPercentage::new( + self.l2_block_capacity_threshold as u8, + ), } } } diff --git a/crates/fuel-gas-price-algorithm/src/v0/tests/algorithm_v0_tests.rs b/crates/fuel-gas-price-algorithm/src/v0/tests/algorithm_v0_tests.rs index a903a8efe6b..199942c72c0 100644 --- a/crates/fuel-gas-price-algorithm/src/v0/tests/algorithm_v0_tests.rs +++ b/crates/fuel-gas-price-algorithm/src/v0/tests/algorithm_v0_tests.rs @@ -1,4 +1,5 @@ use crate::v0::AlgorithmV0; +use fuel_core_types::clamped_percentage::ClampedPercentage; use proptest::prelude::*; #[test] @@ -8,7 +9,7 @@ fn calculate__gives_static_value() { let algorithm = AlgorithmV0 { new_exec_price: value, for_height: 0, - percentage: 0, + percentage: ClampedPercentage::new(0), }; // when @@ -23,7 +24,7 @@ fn _worst_case__correctly_calculates_value( price: u64, starting_height: u32, block_horizon: u32, - percentage: u64, + percentage: ClampedPercentage, ) { // given let algorithm = AlgorithmV0 { @@ -39,7 +40,9 @@ fn _worst_case__correctly_calculates_value( // then let mut expected = price; for _ in 0..block_horizon { - let change_amount = expected.saturating_mul(percentage).saturating_div(100); + let change_amount = expected + .saturating_mul(*percentage as u64) + .saturating_div(100); expected = expected.saturating_add(change_amount); } assert!(actual >= expected); @@ -53,6 +56,7 @@ proptest! { block_horizon in 0..10_000u32, percentage: u64 ) { + let percentage = ClampedPercentage::new(percentage as u8); _worst_case__correctly_calculates_value(price, starting_height, block_horizon, percentage); } } @@ -69,7 +73,7 @@ proptest! { let algorithm = AlgorithmV0 { new_exec_price: price, for_height: starting_height, - percentage, + percentage: ClampedPercentage::new(percentage as u8), }; // when @@ -86,7 +90,7 @@ fn worst_case__same_block_gives_the_same_value_as_calculate() { // given let new_exec_price = 1000; let for_height = 10; - let percentage = 10; + let percentage = ClampedPercentage::new(10); let algorithm = AlgorithmV0 { new_exec_price, for_height, diff --git a/crates/fuel-gas-price-algorithm/src/v1.rs b/crates/fuel-gas-price-algorithm/src/v1.rs index 7d76ddb70a4..68788119d29 100644 --- a/crates/fuel-gas-price-algorithm/src/v1.rs +++ b/crates/fuel-gas-price-algorithm/src/v1.rs @@ -1,4 +1,5 @@ use crate::utils::cumulative_percentage_change; +use fuel_core_types::clamped_percentage::ClampedPercentage; use std::{ cmp::{ max, @@ -321,36 +322,6 @@ impl L2ActivityTracker { } } -/// A value that represents a value between 0 and 100. Higher values are clamped to 100 -#[derive( - serde::Serialize, serde::Deserialize, Debug, Copy, Clone, PartialEq, PartialOrd, -)] -pub struct ClampedPercentage { - value: u8, -} - -impl ClampedPercentage { - pub fn new(maybe_value: u8) -> Self { - Self { - value: maybe_value.min(100), - } - } -} - -impl From for ClampedPercentage { - fn from(value: u8) -> Self { - Self::new(value) - } -} - -impl core::ops::Deref for ClampedPercentage { - type Target = u8; - - fn deref(&self) -> &Self::Target { - &self.value - } -} - impl AlgorithmUpdaterV1 { pub fn update_da_record_data( &mut self, diff --git a/crates/services/gas_price_service/src/common/fuel_core_storage_adapter.rs b/crates/services/gas_price_service/src/common/fuel_core_storage_adapter.rs index f53e8431866..d28933f9256 100644 --- a/crates/services/gas_price_service/src/common/fuel_core_storage_adapter.rs +++ b/crates/services/gas_price_service/src/common/fuel_core_storage_adapter.rs @@ -124,10 +124,7 @@ where + Sync + 'static, { - type Transaction<'a> - = StorageTransaction<&'a mut Storage> - where - Self: 'a; + type Transaction<'a> = StorageTransaction<&'a mut Storage> where Self: 'a; fn begin_transaction(&mut self) -> GasPriceResult> { let tx = self.write_transaction(); diff --git a/crates/services/gas_price_service/src/common/fuel_core_storage_adapter/metadata_tests.rs b/crates/services/gas_price_service/src/common/fuel_core_storage_adapter/metadata_tests.rs index 86a3c458f5e..6ae02f83fb1 100644 --- a/crates/services/gas_price_service/src/common/fuel_core_storage_adapter/metadata_tests.rs +++ b/crates/services/gas_price_service/src/common/fuel_core_storage_adapter/metadata_tests.rs @@ -19,9 +19,9 @@ fn arb_metadata_with_l2_height(l2_height: BlockHeight) -> UpdaterMetadata { let inner = AlgorithmUpdaterV0 { new_exec_price: 100, min_exec_gas_price: 12, - exec_gas_price_change_percent: 2, + exec_gas_price_change_percent: 2.into(), l2_block_height: l2_height.into(), - l2_block_fullness_threshold_percent: 0, + l2_block_fullness_threshold_percent: 0.into(), }; inner.into() } diff --git a/crates/services/gas_price_service/src/v0/metadata.rs b/crates/services/gas_price_service/src/v0/metadata.rs index d16f0c078ae..f55aba1c3e8 100644 --- a/crates/services/gas_price_service/src/v0/metadata.rs +++ b/crates/services/gas_price_service/src/v0/metadata.rs @@ -1,3 +1,4 @@ +use fuel_core_types::clamped_percentage::ClampedPercentage; use fuel_gas_price_algorithm::v0::AlgorithmUpdaterV0; /// DO NOT TOUCH! DEPLOYED TO MAINNET @@ -23,8 +24,8 @@ pub struct V0Metadata { pub struct V0AlgorithmConfig { pub starting_gas_price: u64, pub min_gas_price: u64, - pub gas_price_change_percent: u64, - pub gas_price_threshold_percent: u64, + pub gas_price_change_percent: ClampedPercentage, + pub gas_price_threshold_percent: ClampedPercentage, } impl From for V0Metadata { @@ -33,9 +34,10 @@ impl From for V0Metadata { new_exec_price: updater.new_exec_price, l2_block_height: updater.l2_block_height, _min_exec_gas_price: updater.min_exec_gas_price, - _exec_gas_price_change_percent: updater.exec_gas_price_change_percent, - _l2_block_fullness_threshold_percent: updater - .l2_block_fullness_threshold_percent, + _exec_gas_price_change_percent: *updater.exec_gas_price_change_percent as u64, + _l2_block_fullness_threshold_percent: *updater + .l2_block_fullness_threshold_percent + as u64, } } } diff --git a/crates/services/gas_price_service/src/v0/service.rs b/crates/services/gas_price_service/src/v0/service.rs index 98ddcb6983d..7c16a3e1780 100644 --- a/crates/services/gas_price_service/src/v0/service.rs +++ b/crates/services/gas_price_service/src/v0/service.rs @@ -193,7 +193,10 @@ mod tests { RunnableTask, StateWatcher, }; - use fuel_core_types::fuel_types::BlockHeight; + use fuel_core_types::{ + clamped_percentage::ClampedPercentage, + fuel_types::BlockHeight, + }; use std::sync::Arc; use tokio::sync::mpsc; @@ -260,8 +263,8 @@ mod tests { let config = V0AlgorithmConfig { starting_gas_price: 100, min_gas_price: 10, - gas_price_change_percent: 10, - gas_price_threshold_percent: 0, + gas_price_change_percent: ClampedPercentage::new(10), + gas_price_threshold_percent: ClampedPercentage::new(0), }; let (algo_updater, shared_algo) = initialize_algorithm(&config, l2_block_height, &metadata_storage).unwrap(); diff --git a/crates/services/gas_price_service/src/v0/tests.rs b/crates/services/gas_price_service/src/v0/tests.rs index 51b9b49c415..b847ae008a9 100644 --- a/crates/services/gas_price_service/src/v0/tests.rs +++ b/crates/services/gas_price_service/src/v0/tests.rs @@ -50,6 +50,7 @@ use fuel_core_types::{ block::Block, header::ConsensusParametersVersion, }, + clamped_percentage::ClampedPercentage, fuel_tx::Transaction, fuel_types::BlockHeight, services::block_importer::{ @@ -123,8 +124,8 @@ fn arbitrary_config() -> V0AlgorithmConfig { V0AlgorithmConfig { starting_gas_price: 100, min_gas_price: 0, - gas_price_change_percent: 10, - gas_price_threshold_percent: 0, + gas_price_change_percent: ClampedPercentage::new(10), + gas_price_threshold_percent: ClampedPercentage::new(0), } } @@ -142,8 +143,8 @@ fn different_arb_config() -> V0AlgorithmConfig { V0AlgorithmConfig { starting_gas_price: 200, min_gas_price: 0, - gas_price_change_percent: 20, - gas_price_threshold_percent: 0, + gas_price_change_percent: ClampedPercentage::new(20), + gas_price_threshold_percent: ClampedPercentage::new(0), } } diff --git a/crates/services/gas_price_service/src/v0/uninitialized_task.rs b/crates/services/gas_price_service/src/v0/uninitialized_task.rs index d0cb57c28ef..0753cb7ed40 100644 --- a/crates/services/gas_price_service/src/v0/uninitialized_task.rs +++ b/crates/services/gas_price_service/src/v0/uninitialized_task.rs @@ -196,8 +196,8 @@ where Metadata: GetMetadataStorage + SetMetadataStorage, { let min_exec_gas_price = config.min_gas_price; - let exec_gas_price_change_percent = config.gas_price_change_percent; - let l2_block_fullness_threshold_percent = config.gas_price_threshold_percent; + let exec_gas_price_change_percent = *config.gas_price_change_percent as u64; + let l2_block_fullness_threshold_percent = *config.gas_price_threshold_percent as u64; let algorithm_updater; if let Some(updater_metadata) = metadata_storage diff --git a/crates/services/importer/src/ports.rs b/crates/services/importer/src/ports.rs index 3a30387eec5..6031bf75565 100644 --- a/crates/services/importer/src/ports.rs +++ b/crates/services/importer/src/ports.rs @@ -114,10 +114,7 @@ impl Transactional for S where S: KeyValueInspect, { - type Transaction<'a> - = StorageTransaction<&'a S> - where - Self: 'a; + type Transaction<'a> = StorageTransaction<&'a S> where Self: 'a; fn storage_transaction(&self, changes: Changes) -> Self::Transaction<'_> { self.read_transaction() diff --git a/crates/services/txpool_v2/src/config.rs b/crates/services/txpool_v2/src/config.rs index a28f3243756..7ce12d6da7e 100644 --- a/crates/services/txpool_v2/src/config.rs +++ b/crates/services/txpool_v2/src/config.rs @@ -4,6 +4,7 @@ use std::{ }; use fuel_core_types::{ + clamped_percentage::ClampedPercentage, fuel_tx::{ input::{ coin::{ @@ -141,7 +142,7 @@ pub struct Config { /// TTL for transactions inside the pending pool. pub pending_pool_tx_ttl: Duration, /// Maximum percentage of the pool size to be used for the pending pool. - pub max_pending_pool_size_percentage: u16, + pub max_pending_pool_size_percentage: ClampedPercentage, /// Enable metrics when set to true pub metrics: bool, } @@ -203,7 +204,7 @@ impl Default for Config { max_pending_read_pool_requests: 1000, }, pending_pool_tx_ttl: Duration::from_secs(3), - max_pending_pool_size_percentage: 50, + max_pending_pool_size_percentage: 50.into(), metrics: false, } } diff --git a/crates/services/txpool_v2/src/pool_worker.rs b/crates/services/txpool_v2/src/pool_worker.rs index 28c2b977580..02ebb0688c1 100644 --- a/crates/services/txpool_v2/src/pool_worker.rs +++ b/crates/services/txpool_v2/src/pool_worker.rs @@ -628,21 +628,21 @@ where .config .pool_limits .max_gas - .saturating_mul(self.pool.config.max_pending_pool_size_percentage as u64) + .saturating_mul(*self.pool.config.max_pending_pool_size_percentage as u64) .saturating_div(100); let max_bytes = self .pool .config .pool_limits .max_bytes_size - .saturating_mul(self.pool.config.max_pending_pool_size_percentage as usize) + .saturating_mul(*self.pool.config.max_pending_pool_size_percentage as usize) .saturating_div(100); let max_txs = self .pool .config .pool_limits .max_txs - .saturating_mul(self.pool.config.max_pending_pool_size_percentage as usize) + .saturating_mul(*self.pool.config.max_pending_pool_size_percentage as usize) .saturating_div(100); if gas_used > max_gas || bytes_used > max_bytes || txs_used > max_txs { diff --git a/crates/services/txpool_v2/src/tests/tests_pending_pool.rs b/crates/services/txpool_v2/src/tests/tests_pending_pool.rs index f5ca849cac7..5ed7b5ab76c 100644 --- a/crates/services/txpool_v2/src/tests/tests_pending_pool.rs +++ b/crates/services/txpool_v2/src/tests/tests_pending_pool.rs @@ -94,7 +94,7 @@ async fn test_tx__return_error_expired() { async fn test_tx__directly_removed_not_enough_space() { let mut universe = TestPoolUniverse::default(); universe.config.utxo_validation = true; - universe.config.max_pending_pool_size_percentage = 1; + universe.config.max_pending_pool_size_percentage = 1.into(); universe.config.pool_limits.max_txs = 1; let (_, unset_input) = universe.create_output_and_input(); diff --git a/crates/storage/src/codec/postcard.rs b/crates/storage/src/codec/postcard.rs index 426713803ae..f19f6707408 100644 --- a/crates/storage/src/codec/postcard.rs +++ b/crates/storage/src/codec/postcard.rs @@ -22,10 +22,7 @@ impl Encode for Postcard where T: ?Sized + serde::Serialize, { - type Encoder<'a> - = Cow<'a, [u8]> - where - T: 'a; + type Encoder<'a> = Cow<'a, [u8]> where T: 'a; fn encode(value: &T) -> Self::Encoder<'_> { Cow::Owned(postcard::to_allocvec(value).expect( diff --git a/crates/storage/src/codec/raw.rs b/crates/storage/src/codec/raw.rs index c0ed7e378e2..f398dbbf42f 100644 --- a/crates/storage/src/codec/raw.rs +++ b/crates/storage/src/codec/raw.rs @@ -20,10 +20,7 @@ impl Encode for Raw where T: ?Sized + AsRef<[u8]>, { - type Encoder<'a> - = Cow<'a, [u8]> - where - T: 'a; + type Encoder<'a> = Cow<'a, [u8]> where T: 'a; fn encode(t: &T) -> Self::Encoder<'_> { Cow::Borrowed(t.as_ref()) diff --git a/crates/types/src/clamped_percentage.rs b/crates/types/src/clamped_percentage.rs new file mode 100644 index 00000000000..a21bc20a36b --- /dev/null +++ b/crates/types/src/clamped_percentage.rs @@ -0,0 +1,61 @@ +/// A value that represents a value between 0 and 100. Higher values are clamped to 100 +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] +pub struct ClampedPercentage { + value: u8, +} + +impl ClampedPercentage { + /// Creates a new `ClampedPercentage` by clamping the given value to the range [0, 100]. + pub fn new(maybe_value: u8) -> Self { + Self { + value: maybe_value.min(100), + } + } +} + +impl From for ClampedPercentage { + fn from(value: u8) -> Self { + Self::new(value) + } +} + +impl core::ops::Deref for ClampedPercentage { + type Target = u8; + + fn deref(&self) -> &Self::Target { + &self.value + } +} + +#[cfg(feature = "std")] +use std::str::FromStr; + +#[cfg(feature = "std")] +impl FromStr for ClampedPercentage { + type Err = std::num::ParseIntError; + + fn from_str(s: &str) -> Result { + let value = s.parse::()?; + Ok(ClampedPercentage::new(value)) + } +} + +#[cfg(feature = "std")] +impl std::fmt::Display for ClampedPercentage { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.value) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_clamping() { + assert_eq!(*ClampedPercentage::new(50), 50); + assert_eq!(*ClampedPercentage::new(150), 100); + assert_eq!(*ClampedPercentage::new(0), 0); + } +} diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index e021bd278c2..b5a616ff89e 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -31,6 +31,8 @@ pub use secrecy; pub use tai64; pub mod blockchain; +/// A module that provides functionality for working with clamped percentages. +pub mod clamped_percentage; pub mod entities; pub mod services; pub mod signer; diff --git a/tests/tests/coins.rs b/tests/tests/coins.rs index 12dccf15cb5..9ec332ebe94 100644 --- a/tests/tests/coins.rs +++ b/tests/tests/coins.rs @@ -282,10 +282,7 @@ mod coin { .client .coins_to_spend( &owner, - vec![ - (asset_id_a, 300, Some(MAX as u16)), - (asset_id_b, 300, Some(MAX as u16)), - ], + vec![(asset_id_a, 300, Some(MAX)), (asset_id_b, 300, Some(MAX))], None, ) .await; @@ -495,7 +492,7 @@ mod message_coin { // not enough inputs let coins_per_asset = context .client - .coins_to_spend(&owner, vec![(base_asset_id, 300, Some(MAX as u16))], None) + .coins_to_spend(&owner, vec![(base_asset_id, 300, Some(MAX))], None) .await; assert!(coins_per_asset.is_err()); assert_eq!( @@ -719,10 +716,7 @@ mod all_coins { .client .coins_to_spend( &owner, - vec![ - (asset_id_a, 300, Some(MAX as u16)), - (asset_id_b, 300, Some(MAX as u16)), - ], + vec![(asset_id_a, 300, Some(MAX)), (asset_id_b, 300, Some(MAX))], None, ) .await; diff --git a/tests/tests/gas_price.rs b/tests/tests/gas_price.rs index 23144691eee..20f22c63b8b 100644 --- a/tests/tests/gas_price.rs +++ b/tests/tests/gas_price.rs @@ -91,7 +91,7 @@ fn infinite_loop_tx( rng: &mut R, asset_id: Option, ) -> Transaction { - let script = vec![op::jmp(RegId::ZERO)]; + let script = [op::jmp(RegId::ZERO)]; let script_bytes = script.iter().flat_map(|op| op.to_bytes()).collect(); let mut builder = TransactionBuilder::script(script_bytes, vec![]); let asset_id = asset_id.unwrap_or_else(|| *builder.get_params().base_asset_id()); @@ -214,14 +214,14 @@ async fn produce_block__raises_gas_price() { let threshold = 50; node_config.block_producer.coinbase_recipient = Some([5; 32].into()); node_config.gas_price_config.starting_exec_gas_price = starting_gas_price; - node_config.gas_price_config.exec_gas_price_change_percent = percent; + node_config.gas_price_config.exec_gas_price_change_percent = percent.into(); node_config .gas_price_config - .exec_gas_price_threshold_percent = threshold; + .exec_gas_price_threshold_percent = threshold.into(); node_config.block_production = Trigger::Never; node_config.gas_price_config.da_gas_price_p_component = 0; node_config.gas_price_config.da_gas_price_d_component = 0; - node_config.gas_price_config.max_da_gas_price_change_percent = 0; + node_config.gas_price_config.max_da_gas_price_change_percent = 0.into(); node_config.gas_price_config.min_da_gas_price = 0; node_config.gas_price_config.max_da_gas_price = 1; @@ -266,14 +266,14 @@ async fn produce_block__lowers_gas_price() { let threshold = 50; node_config.block_producer.coinbase_recipient = Some([5; 32].into()); node_config.gas_price_config.starting_exec_gas_price = starting_gas_price; - node_config.gas_price_config.exec_gas_price_change_percent = percent; + node_config.gas_price_config.exec_gas_price_change_percent = percent.into(); node_config .gas_price_config - .exec_gas_price_threshold_percent = threshold; + .exec_gas_price_threshold_percent = threshold.into(); node_config.block_production = Trigger::Never; node_config.gas_price_config.da_gas_price_p_component = 0; node_config.gas_price_config.da_gas_price_d_component = 0; - node_config.gas_price_config.max_da_gas_price_change_percent = 0; + node_config.gas_price_config.max_da_gas_price_change_percent = 0.into(); node_config.gas_price_config.min_da_gas_price = 0; node_config.gas_price_config.max_da_gas_price = 1; @@ -351,11 +351,11 @@ async fn estimate_gas_price__is_greater_than_actual_price_at_desired_height() { let starting_gas_price = 1000; let percent = 10; node_config.gas_price_config.starting_exec_gas_price = starting_gas_price; - node_config.gas_price_config.exec_gas_price_change_percent = percent; + node_config.gas_price_config.exec_gas_price_change_percent = percent.into(); // Always increase node_config .gas_price_config - .exec_gas_price_threshold_percent = 0; + .exec_gas_price_threshold_percent = 0.into(); let srv = FuelService::new_node(node_config.clone()).await.unwrap(); let client = FuelClient::from(srv.bound_address); @@ -729,7 +729,7 @@ fn node_config_with_da_committer_url(url: url::Url) -> Config { node_config.block_producer.coinbase_recipient = Some([5; 32].into()); node_config.gas_price_config.min_da_gas_price = starting_gas_price; node_config.gas_price_config.max_da_gas_price = u64::MAX; - node_config.gas_price_config.max_da_gas_price_change_percent = 15; + node_config.gas_price_config.max_da_gas_price_change_percent = 15.into(); node_config.block_production = Trigger::Never; node_config.gas_price_config.da_committer_url = Some(url); node_config.gas_price_config.da_poll_interval = Some(Duration::from_millis(100)); @@ -776,9 +776,9 @@ fn produce_block__algorithm_recovers_from_divergent_profit() { let half_of_blocks = block_delay as u32 / 2; let count = half_of_blocks; let block_bytes = 1000; - let total_size_bytes = block_bytes * count as u32; + let total_size_bytes = block_bytes * count; let gas = 16 * total_size_bytes as u128; - let cost_gwei = gas * 1; // blob gas price 1 gwei + let cost_gwei = gas; // blob gas price 1 gwei let cost = cost_gwei * 1_000_000_000; // Wei mock.add_response(RawDaBlockCosts { id: 1, @@ -830,7 +830,7 @@ fn produce_block__algorithm_recovers_from_divergent_profit() { gas_prices.push(metadata.new_scaled_da_gas_price / metadata.gas_price_factor); if profit > 0 && !success { success = true; - success_iteration = i as i32; + success_iteration = i; } } }); @@ -933,7 +933,7 @@ fn produce_block__costs_from_da_are_properly_recorded_in_metadata() { #[tokio::test] async fn sentry__gas_price_estimate__uses_gas_price_from_produced_block() { - let mut rng = StdRng::seed_from_u64(1234 as u64); + let mut rng = StdRng::seed_from_u64(1234_u64); // given let unexpected_high_min_gas_limit = u64::MAX; diff --git a/tests/tests/lib.rs b/tests/tests/lib.rs index 8f738aa718f..4ead63e04fb 100644 --- a/tests/tests/lib.rs +++ b/tests/tests/lib.rs @@ -1,6 +1,7 @@ #![allow(non_snake_case)] #![deny(unused_must_use)] #![deny(warnings)] +#![allow(clippy::len_zero)] #[cfg(not(feature = "only-p2p"))] mod assemble_tx; diff --git a/tests/tests/required_fuel_block_height_extension.rs b/tests/tests/required_fuel_block_height_extension.rs index f1b4b940084..07b04937dad 100644 --- a/tests/tests/required_fuel_block_height_extension.rs +++ b/tests/tests/required_fuel_block_height_extension.rs @@ -171,8 +171,7 @@ async fn request_with_required_block_height_extension_waits_when_within_threshol // Issue a request while the precondition on the required fuel block height is not met. let request_task = tokio::spawn(async move { client.with_required_fuel_block_height(Some(100u32.into())); - let result = client.balance(&owner, Some(&asset_id)).await; - result + client.balance(&owner, Some(&asset_id)).await }); // Produce 5 blocks in parallel with the main test, to meet the precondition // on required fuel block height. diff --git a/tests/tests/storage.rs b/tests/tests/storage.rs index 87dc651b365..4049647217e 100644 --- a/tests/tests/storage.rs +++ b/tests/tests/storage.rs @@ -101,17 +101,13 @@ async fn contract_storage_values_create_tx() { let slots_before = client .contract_slots_values( &contract_id, - Some(height_before.into()), + Some(height_before), storage_to_request.clone(), ) .await .unwrap(); let slots_after = client - .contract_slots_values( - &contract_id, - Some(height_after.into()), - storage_to_request, - ) + .contract_slots_values(&contract_id, Some(height_after), storage_to_request) .await .unwrap();