diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d8efebffc0..4962954f354 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - [2603](https://github.com/FuelLabs/fuel-core/pull/2603): Sets the latest recorded height on initialization, not just when DA costs are received ### Fixed +- [2612](https://github.com/FuelLabs/fuel-core/pull/2612): Use latest gas price to estimate next block gas price during dry runs - [2612](https://github.com/FuelLabs/fuel-core/pull/2612): Use latest gas price to estimate next block gas price in tx pool instead of using algorithm directly - [2609](https://github.com/FuelLabs/fuel-core/pull/2609): Check response before trying to deserialize, return error instead - [2599](https://github.com/FuelLabs/fuel-core/pull/2599): Use the proper `url` apis to construct full url path in `BlockCommitterHttpApi` client diff --git a/crates/fuel-core/src/service/adapters.rs b/crates/fuel-core/src/service/adapters.rs index 3e66ad7618b..2db8de292e2 100644 --- a/crates/fuel-core/src/service/adapters.rs +++ b/crates/fuel-core/src/service/adapters.rs @@ -210,7 +210,7 @@ mod universal_gas_price_provider_tests { /// Allows communication from other service with more recent gas price data /// `Height` refers to the height of the block at which the gas price was last updated /// `GasPrice` refers to the gas price at the last updated block -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct UniversalGasPriceProvider { /// Shared state of latest gas price data latest_gas_price: LatestGasPrice, @@ -218,6 +218,15 @@ pub struct UniversalGasPriceProvider { percentage: u16, } +impl Clone for UniversalGasPriceProvider { + fn clone(&self) -> Self { + Self { + latest_gas_price: self.latest_gas_price.clone(), + percentage: self.percentage, + } + } +} + impl UniversalGasPriceProvider { #[cfg(test)] pub fn new(height: Height, price: GasPrice, percentage: u16) -> Self { @@ -245,18 +254,22 @@ impl UniversalGasPriceProvider { } } -impl TxPoolGasPriceProvider for UniversalGasPriceProvider { - fn next_gas_price(&self) -> fuel_core_txpool::GasPrice { - let (best_height, best_gas_price) = self.get_height_and_gas_price(); - let next_block = best_height.saturating_add(1); +impl UniversalGasPriceProvider { + pub fn inner_next_gas_price(&self) -> u64 { + let (_, latest_price) = self.get_height_and_gas_price(); let percentage = self.percentage; - cumulative_percentage_change( - best_gas_price, - best_height, - percentage as u64, - next_block, - ) + let change = latest_price + .saturating_mul(percentage as u64) + .saturating_div(100); + + latest_price.saturating_add(change) + } +} + +impl TxPoolGasPriceProvider for UniversalGasPriceProvider { + fn next_gas_price(&self) -> fuel_core_txpool::GasPrice { + self.inner_next_gas_price() } } diff --git a/crates/fuel-core/src/service/adapters/fuel_gas_price_provider.rs b/crates/fuel-core/src/service/adapters/fuel_gas_price_provider.rs index df26ae53f50..3401e100d4e 100644 --- a/crates/fuel-core/src/service/adapters/fuel_gas_price_provider.rs +++ b/crates/fuel-core/src/service/adapters/fuel_gas_price_provider.rs @@ -1,3 +1,4 @@ +use crate::service::adapters::UniversalGasPriceProvider; use fuel_core_gas_price_service::common::gas_price_algorithm::{ GasPriceAlgorithm, SharedGasPriceAlgo, @@ -26,39 +27,43 @@ mod tests; #[derive(Debug)] /// Receives the next gas price algorithm via a shared `BlockGasPriceAlgo` instance -pub struct FuelGasPriceProvider { +pub struct FuelGasPriceProvider { algorithm: SharedGasPriceAlgo, + latest_gas_price: UniversalGasPriceProvider, } -impl Clone for FuelGasPriceProvider { +impl Clone for FuelGasPriceProvider { fn clone(&self) -> Self { Self { algorithm: self.algorithm.clone(), + latest_gas_price: self.latest_gas_price.clone(), } } } -impl FuelGasPriceProvider { - pub fn new(algorithm: SharedGasPriceAlgo) -> Self { - Self { algorithm } +impl FuelGasPriceProvider { + pub fn new( + algorithm: SharedGasPriceAlgo, + latest_gas_price: UniversalGasPriceProvider, + ) -> Self { + Self { + algorithm, + latest_gas_price, + } } } -impl FuelGasPriceProvider +#[async_trait::async_trait] +impl ProducerGasPriceProvider for FuelGasPriceProvider where A: GasPriceAlgorithm + Send + Sync, { - fn next_gas_price(&self) -> u64 { - self.algorithm.next_gas_price() + async fn production_gas_price(&self) -> anyhow::Result { + Ok(self.algorithm.next_gas_price()) } -} -#[async_trait::async_trait] -impl ProducerGasPriceProvider for FuelGasPriceProvider -where - A: GasPriceAlgorithm + Send + Sync, -{ - async fn next_gas_price(&self) -> anyhow::Result { - Ok(self.next_gas_price()) + async fn dry_run_gas_price(&self) -> anyhow::Result { + let price = self.latest_gas_price.inner_next_gas_price(); + Ok(price) } } 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 e4e9b9b325f..56ef2fd7ddf 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 @@ -5,15 +5,18 @@ use super::*; #[cfg(test)] mod producer_gas_price_tests; -#[cfg(test)] -mod tx_pool_gas_price_tests; - -fn build_provider(algorithm: A) -> FuelGasPriceProvider +fn build_provider( + algorithm: A, + height: u32, + price: u64, + percentage: u16, +) -> FuelGasPriceProvider where A: Send + Sync, { let algorithm = SharedGasPriceAlgo::new_with_algorithm(algorithm); - FuelGasPriceProvider::new(algorithm) + let latest_gas_price = UniversalGasPriceProvider::new(height, price, percentage); + FuelGasPriceProvider::new(algorithm, latest_gas_price) } #[ignore] 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 d8929cb4fdf..6d9bc797002 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 @@ -3,18 +3,37 @@ use fuel_core_gas_price_service::{ common::gas_price_algorithm::GasPriceAlgorithm, static_updater::StaticAlgorithm, }; +use fuel_core_producer::block_producer::gas_price::GasPriceProvider; #[tokio::test] -async fn gas_price__if_requested_block_height_is_latest_return_gas_price() { +async 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()); + let gas_price_provider = build_provider(algo.clone(), 0, price, 10); // when let expected_price = algo.next_gas_price(); - let actual_price = gas_price_provider.next_gas_price(); + let actual_price = gas_price_provider.production_gas_price().await.unwrap(); // then assert_eq!(expected_price, actual_price); } + +#[tokio::test] +async fn _dry_run_gas_price__calculates_correctly_based_on_percentage() { + // given + let height = 123; + let price = 33; + let percentage = 10; + let algo = StaticAlgorithm::new(price); + let gas_price_provider = build_provider(algo.clone(), height, price, percentage); + + // when + let actual = gas_price_provider.dry_run_gas_price().await.unwrap(); + + // then + 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/fuel_gas_price_provider/tests/tx_pool_gas_price_tests.rs b/crates/fuel-core/src/service/adapters/fuel_gas_price_provider/tests/tx_pool_gas_price_tests.rs deleted file mode 100644 index d8929cb4fdf..00000000000 --- a/crates/fuel-core/src/service/adapters/fuel_gas_price_provider/tests/tx_pool_gas_price_tests.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::service::adapters::fuel_gas_price_provider::tests::build_provider; -use fuel_core_gas_price_service::{ - common::gas_price_algorithm::GasPriceAlgorithm, - static_updater::StaticAlgorithm, -}; - -#[tokio::test] -async fn 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()); - - // when - let expected_price = algo.next_gas_price(); - let actual_price = gas_price_provider.next_gas_price(); - - // then - assert_eq!(expected_price, actual_price); -} diff --git a/crates/fuel-core/src/service/adapters/producer.rs b/crates/fuel-core/src/service/adapters/producer.rs index 7a977f69228..a16b0d74227 100644 --- a/crates/fuel-core/src/service/adapters/producer.rs +++ b/crates/fuel-core/src/service/adapters/producer.rs @@ -250,7 +250,11 @@ impl fuel_core_producer::ports::BlockProducerDatabase for OnChainIterableKeyValu #[async_trait::async_trait] impl GasPriceProvider for StaticGasPrice { - async fn next_gas_price(&self) -> anyhow::Result { + async fn production_gas_price(&self) -> anyhow::Result { + Ok(self.gas_price) + } + + async fn dry_run_gas_price(&self) -> anyhow::Result { Ok(self.gas_price) } } diff --git a/crates/fuel-core/src/service/sub_services.rs b/crates/fuel-core/src/service/sub_services.rs index f8978c4700d..4be58304b37 100644 --- a/crates/fuel-core/src/service/sub_services.rs +++ b/crates/fuel-core/src/service/sub_services.rs @@ -74,7 +74,7 @@ pub type BlockProducerService = fuel_core_producer::block_producer::Producer< Database, TxPoolAdapter, ExecutorAdapter, - FuelGasPriceProvider, + FuelGasPriceProvider, ConsensusParametersProvider, >; @@ -207,7 +207,11 @@ pub fn init_sub_services( latest_gas_price, DEFAULT_GAS_PRICE_CHANGE_PERCENT, ); - let producer_gas_price_provider = FuelGasPriceProvider::new(gas_price_algo.clone()); + + let producer_gas_price_provider = FuelGasPriceProvider::new( + gas_price_algo.clone(), + universal_gas_price_provider.clone(), + ); let txpool = fuel_core_txpool::new_service( chain_id, diff --git a/crates/services/gas_price_service/src/v1/service.rs b/crates/services/gas_price_service/src/v1/service.rs index 9512f13e251..3664488204d 100644 --- a/crates/services/gas_price_service/src/v1/service.rs +++ b/crates/services/gas_price_service/src/v1/service.rs @@ -71,11 +71,19 @@ use std::{ }; use tokio::sync::broadcast::Receiver; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct LatestGasPrice { inner: Arc>, } +impl Clone for LatestGasPrice { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + } + } +} + impl LatestGasPrice { pub fn new(height: Height, price: GasPrice) -> Self { let pair = (height, price); @@ -442,7 +450,6 @@ mod tests { sync::{ atomic::AtomicU32, Arc, - Mutex, }, time::Duration, }; diff --git a/crates/services/producer/src/block_producer.rs b/crates/services/producer/src/block_producer.rs index f5ad44be901..4a8972a187b 100644 --- a/crates/services/producer/src/block_producer.rs +++ b/crates/services/producer/src/block_producer.rs @@ -204,7 +204,7 @@ where anyhow!("Failed to acquire the production lock, block production is already in progress") })?; - let gas_price = self.calculate_gas_price().await?; + let gas_price = self.production_gas_price().await?; let source = tx_source(gas_price, height).await?; @@ -244,9 +244,16 @@ where Ok(result) } - async fn calculate_gas_price(&self) -> anyhow::Result { + async fn production_gas_price(&self) -> anyhow::Result { self.gas_price_provider - .next_gas_price() + .production_gas_price() + .await + .map_err(|e| anyhow!("No gas price found: {e:?}")) + } + + async fn dry_run_gas_price(&self) -> anyhow::Result { + self.gas_price_provider + .dry_run_gas_price() .await .map_err(|e| anyhow!("No gas price found: {e:?}")) } @@ -338,7 +345,7 @@ where let gas_price = if let Some(inner) = gas_price { inner } else { - self.calculate_gas_price().await? + self.dry_run_gas_price().await? }; // The dry run execution should use the state of the blockchain based on the diff --git a/crates/services/producer/src/block_producer/gas_price.rs b/crates/services/producer/src/block_producer/gas_price.rs index 12e08cfa2c7..d4026b59bc6 100644 --- a/crates/services/producer/src/block_producer/gas_price.rs +++ b/crates/services/producer/src/block_producer/gas_price.rs @@ -5,7 +5,9 @@ use std::sync::Arc; /// Interface for retrieving the gas price for a block pub trait GasPriceProvider { /// The gas price for all transactions in the block. - async fn next_gas_price(&self) -> anyhow::Result; + async fn production_gas_price(&self) -> anyhow::Result; + + async fn dry_run_gas_price(&self) -> anyhow::Result; } /// Interface for retrieving the consensus parameters. diff --git a/crates/services/producer/src/block_producer/tests.rs b/crates/services/producer/src/block_producer/tests.rs index f8b18b549d5..84dde81cc73 100644 --- a/crates/services/producer/src/block_producer/tests.rs +++ b/crates/services/producer/src/block_producer/tests.rs @@ -72,7 +72,12 @@ impl MockProducerGasPrice { #[async_trait::async_trait] impl GasPriceProvider for MockProducerGasPrice { - async fn next_gas_price(&self) -> anyhow::Result { + async fn production_gas_price(&self) -> anyhow::Result { + self.gas_price + .ok_or_else(|| anyhow::anyhow!("Gas price not provided")) + } + + async fn dry_run_gas_price(&self) -> anyhow::Result { self.gas_price .ok_or_else(|| anyhow::anyhow!("Gas price not provided")) }