Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use latest gas price to estimate next block gas price during dry runs #2615

Merged
merged 9 commits into from
Jan 22, 2025
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- [2551](https://github.com/FuelLabs/fuel-core/pull/2551): Enhanced the DA compressed block header to include block id.

### Fixed
- [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

Expand Down
86 changes: 77 additions & 9 deletions crates/fuel-core/src/service/adapters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ use fuel_core_importer::ImporterResult;
use fuel_core_poa::ports::BlockSigner;
use fuel_core_services::stream::BoxStream;
use fuel_core_storage::transactional::Changes;
use fuel_core_txpool::BorrowedTxPool;
use fuel_core_txpool::{
ports::GasPriceProvider as TxPoolGasPriceProvider,
BorrowedTxPool,
};
#[cfg(feature = "p2p")]
use fuel_core_types::services::p2p::peer_reputation::AppScore;
use fuel_core_types::{
Expand Down Expand Up @@ -91,7 +94,7 @@ impl StaticGasPrice {
}

#[cfg(test)]
mod arc_gas_price_estimate_tests {
mod universal_gas_price_provider_tests {
#![allow(non_snake_case)]

use super::*;
Expand All @@ -104,7 +107,8 @@ mod arc_gas_price_estimate_tests {
percentage: u16,
) {
// given
let subject = ArcGasPriceEstimate::new(starting_height, gas_price, percentage);
let subject =
UniversalGasPriceProvider::new(starting_height, gas_price, percentage);

// when
let target_height = starting_height.saturating_add(block_horizon);
Expand Down Expand Up @@ -154,7 +158,7 @@ mod arc_gas_price_estimate_tests {
let rt = tokio::runtime::Runtime::new().unwrap();

// given
let subject = ArcGasPriceEstimate::new(starting_height, gas_price, percentage);
let subject = UniversalGasPriceProvider::new(starting_height, gas_price, percentage);

// when
let target_height = starting_height.saturating_add(block_horizon);
Expand All @@ -165,20 +169,65 @@ mod arc_gas_price_estimate_tests {
// doesn't panic with an overflow
}
}

fn _next_gas_price__correctly_calculates_value(
gas_price: u64,
starting_height: u32,
percentage: u16,
) {
// given
let subject =
UniversalGasPriceProvider::new(starting_height, gas_price, percentage);

// when
let estimated = subject.next_gas_price();

// then
let change_amount = gas_price
.saturating_mul(percentage as u64)
.saturating_div(100);
let actual = gas_price.saturating_add(change_amount);

assert!(estimated >= actual);
}

proptest! {
#[test]
fn next_gas_price__correctly_calculates_value(
gas_price: u64,
starting_height: u32,
percentage: u16,
) {
_next_gas_price__correctly_calculates_value(
gas_price,
starting_height,
percentage,
)
}
}
}

/// 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
#[allow(dead_code)]
pub struct ArcGasPriceEstimate<Height, GasPrice> {
#[derive(Debug)]
pub struct UniversalGasPriceProvider<Height, GasPrice> {
/// Shared state of latest gas price data
latest_gas_price: LatestGasPrice<Height, GasPrice>,
/// The max percentage the gas price can increase per block
percentage: u16,
}

impl<Height, GasPrice> ArcGasPriceEstimate<Height, GasPrice> {
impl<Height, GasPrice> Clone for UniversalGasPriceProvider<Height, GasPrice> {
fn clone(&self) -> Self {
Self {
latest_gas_price: self.latest_gas_price.clone(),
percentage: self.percentage,
}
}
}

impl<Height, GasPrice> UniversalGasPriceProvider<Height, GasPrice> {
#[cfg(test)]
pub fn new(height: Height, price: GasPrice, percentage: u16) -> Self {
let latest_gas_price = LatestGasPrice::new(height, price);
Expand All @@ -199,14 +248,33 @@ impl<Height, GasPrice> ArcGasPriceEstimate<Height, GasPrice> {
}
}

impl<Height: Copy, GasPrice: Copy> ArcGasPriceEstimate<Height, GasPrice> {
impl<Height: Copy, GasPrice: Copy> UniversalGasPriceProvider<Height, GasPrice> {
fn get_height_and_gas_price(&self) -> (Height, GasPrice) {
self.latest_gas_price.get()
}
}

impl UniversalGasPriceProvider<u32, u64> {
pub fn inner_next_gas_price(&self) -> u64 {
let (_, latest_price) = self.get_height_and_gas_price();
let percentage = self.percentage;

let change = latest_price
.saturating_mul(percentage as u64)
.saturating_div(100);

latest_price.saturating_add(change)
}
}

impl TxPoolGasPriceProvider for UniversalGasPriceProvider<u32, u64> {
fn next_gas_price(&self) -> fuel_core_txpool::GasPrice {
self.inner_next_gas_price()
}
}

#[async_trait::async_trait]
impl GasPriceEstimate for ArcGasPriceEstimate<u32, u64> {
impl GasPriceEstimate for UniversalGasPriceProvider<u32, u64> {
async fn worst_case_gas_price(&self, height: BlockHeight) -> Option<u64> {
let (best_height, best_gas_price) = self.get_height_and_gas_price();
let percentage = self.percentage;
Expand Down
45 changes: 20 additions & 25 deletions crates/fuel-core/src/service/adapters/fuel_gas_price_provider.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::service::adapters::UniversalGasPriceProvider;
use fuel_core_gas_price_service::common::gas_price_algorithm::{
GasPriceAlgorithm,
SharedGasPriceAlgo,
};
use fuel_core_producer::block_producer::gas_price::GasPriceProvider as ProducerGasPriceProvider;
use fuel_core_txpool::ports::GasPriceProvider as TxPoolGasPriceProvider;
use fuel_core_types::fuel_types::BlockHeight;

pub type Result<T, E = Error> = std::result::Result<T, E>;
Expand All @@ -27,48 +27,43 @@ mod tests;

#[derive(Debug)]
/// Receives the next gas price algorithm via a shared `BlockGasPriceAlgo` instance
pub struct FuelGasPriceProvider<A> {
pub struct FuelGasPriceProvider<A, Height, GasPrice> {
algorithm: SharedGasPriceAlgo<A>,
latest_gas_price: UniversalGasPriceProvider<Height, GasPrice>,
}

impl<A> Clone for FuelGasPriceProvider<A> {
impl<A, Height, GasPrice> Clone for FuelGasPriceProvider<A, Height, GasPrice> {
fn clone(&self) -> Self {
Self {
algorithm: self.algorithm.clone(),
latest_gas_price: self.latest_gas_price.clone(),
}
}
}

impl<A> FuelGasPriceProvider<A> {
pub fn new(algorithm: SharedGasPriceAlgo<A>) -> Self {
Self { algorithm }
}
}

impl<A> FuelGasPriceProvider<A>
where
A: GasPriceAlgorithm + Send + Sync,
{
fn next_gas_price(&self) -> u64 {
self.algorithm.next_gas_price()
impl<A, Height, GasPrice> FuelGasPriceProvider<A, Height, GasPrice> {
pub fn new(
algorithm: SharedGasPriceAlgo<A>,
latest_gas_price: UniversalGasPriceProvider<Height, GasPrice>,
) -> Self {
Self {
algorithm,
latest_gas_price,
}
}
}

#[async_trait::async_trait]
impl<A> ProducerGasPriceProvider for FuelGasPriceProvider<A>
impl<A> ProducerGasPriceProvider for FuelGasPriceProvider<A, u32, u64>
where
A: GasPriceAlgorithm + Send + Sync,
{
async fn next_gas_price(&self) -> anyhow::Result<u64> {
Ok(self.next_gas_price())
async fn production_gas_price(&self) -> anyhow::Result<u64> {
Ok(self.algorithm.next_gas_price())
}
}

impl<A> TxPoolGasPriceProvider for FuelGasPriceProvider<A>
where
A: GasPriceAlgorithm + Send + Sync + 'static,
{
fn next_gas_price(&self) -> u64 {
self.next_gas_price()
async fn dry_run_gas_price(&self) -> anyhow::Result<u64> {
let price = self.latest_gas_price.inner_next_gas_price();
Ok(price)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@ use super::*;
#[cfg(test)]
mod producer_gas_price_tests;

#[cfg(test)]
mod tx_pool_gas_price_tests;

fn build_provider<A>(algorithm: A) -> FuelGasPriceProvider<A>
fn build_provider<A>(
algorithm: A,
height: u32,
price: u64,
percentage: u16,
) -> FuelGasPriceProvider<A, u32, u64>
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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

This file was deleted.

6 changes: 5 additions & 1 deletion crates/fuel-core/src/service/adapters/producer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u64> {
async fn production_gas_price(&self) -> anyhow::Result<u64> {
Ok(self.gas_price)
}

async fn dry_run_gas_price(&self) -> anyhow::Result<u64> {
Ok(self.gas_price)
}
}
Expand Down
Loading
Loading