Skip to content

Commit

Permalink
Use latest block in dry run (#2615)
Browse files Browse the repository at this point in the history
## Linked Issues/PRs
<!-- List of related issues/PRs -->

## Description
<!-- List of detailed changes -->
Followup to #2612

## Checklist
- [x] New behavior is reflected in tests
  • Loading branch information
MitchTurner authored Jan 22, 2025
1 parent fbe2f87 commit 9fdbc01
Show file tree
Hide file tree
Showing 12 changed files with 116 additions and 66 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
35 changes: 24 additions & 11 deletions crates/fuel-core/src/service/adapters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,14 +210,23 @@ 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<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> 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 {
Expand Down Expand Up @@ -245,18 +254,22 @@ impl<Height: Copy, GasPrice: Copy> UniversalGasPriceProvider<Height, GasPrice> {
}
}

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

Expand Down
37 changes: 21 additions & 16 deletions crates/fuel-core/src/service/adapters/fuel_gas_price_provider.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::service::adapters::UniversalGasPriceProvider;
use fuel_core_gas_price_service::common::gas_price_algorithm::{
GasPriceAlgorithm,
SharedGasPriceAlgo,
Expand Down Expand Up @@ -26,39 +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, Height, GasPrice> FuelGasPriceProvider<A, Height, GasPrice> {
pub fn new(
algorithm: SharedGasPriceAlgo<A>,
latest_gas_price: UniversalGasPriceProvider<Height, GasPrice>,
) -> Self {
Self {
algorithm,
latest_gas_price,
}
}
}

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

#[async_trait::async_trait]
impl<A> ProducerGasPriceProvider for FuelGasPriceProvider<A>
where
A: GasPriceAlgorithm + Send + Sync,
{
async fn next_gas_price(&self) -> anyhow::Result<u64> {
Ok(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
8 changes: 6 additions & 2 deletions crates/fuel-core/src/service/sub_services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub type BlockProducerService = fuel_core_producer::block_producer::Producer<
Database,
TxPoolAdapter,
ExecutorAdapter,
FuelGasPriceProvider<AlgorithmV1>,
FuelGasPriceProvider<AlgorithmV1, u32, u64>,
ConsensusParametersProvider,
>;

Expand Down Expand Up @@ -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,
Expand Down
11 changes: 9 additions & 2 deletions crates/services/gas_price_service/src/v1/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,19 @@ use std::{
};
use tokio::sync::broadcast::Receiver;

#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct LatestGasPrice<Height, GasPrice> {
inner: Arc<parking_lot::RwLock<(Height, GasPrice)>>,
}

impl<Height, GasPrice> Clone for LatestGasPrice<Height, GasPrice> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}

impl<Height, GasPrice> LatestGasPrice<Height, GasPrice> {
pub fn new(height: Height, price: GasPrice) -> Self {
let pair = (height, price);
Expand Down Expand Up @@ -442,7 +450,6 @@ mod tests {
sync::{
atomic::AtomicU32,
Arc,
Mutex,
},
time::Duration,
};
Expand Down
15 changes: 11 additions & 4 deletions crates/services/producer/src/block_producer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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?;

Expand Down Expand Up @@ -244,9 +244,16 @@ where
Ok(result)
}

async fn calculate_gas_price(&self) -> anyhow::Result<u64> {
async fn production_gas_price(&self) -> anyhow::Result<u64> {
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<u64> {
self.gas_price_provider
.dry_run_gas_price()
.await
.map_err(|e| anyhow!("No gas price found: {e:?}"))
}
Expand Down Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion crates/services/producer/src/block_producer/gas_price.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u64>;
async fn production_gas_price(&self) -> anyhow::Result<u64>;

async fn dry_run_gas_price(&self) -> anyhow::Result<u64>;
}

/// Interface for retrieving the consensus parameters.
Expand Down
7 changes: 6 additions & 1 deletion crates/services/producer/src/block_producer/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,12 @@ impl MockProducerGasPrice {

#[async_trait::async_trait]
impl GasPriceProvider for MockProducerGasPrice {
async fn next_gas_price(&self) -> anyhow::Result<u64> {
async fn production_gas_price(&self) -> anyhow::Result<u64> {
self.gas_price
.ok_or_else(|| anyhow::anyhow!("Gas price not provided"))
}

async fn dry_run_gas_price(&self) -> anyhow::Result<u64> {
self.gas_price
.ok_or_else(|| anyhow::anyhow!("Gas price not provided"))
}
Expand Down

0 comments on commit 9fdbc01

Please sign in to comment.