Skip to content

Commit

Permalink
Implement gas price updater for service (#1972)
Browse files Browse the repository at this point in the history
Part of: #1955

The updater has two ports it owns:
- `L2BlockSource`
- `MetadataStorage`

`L2BlockSource` is for getting the latest block as they are committed
and using that to update the gas price algorithm.
`MetadataStorage` is for maintaining the state of the updater in the
case the service shuts down or needs to be restarted. For now it just
naively stores the `AlgorithmUpdaterV1`, and just the most recent
version. I don't know if we need to consider storing older versions of
it for the scenario we need to roll back the chain.

I started adding the DA Record stuff, but we're not using it so we can
YAGNI it for now, otherwise it would just be implementing a bunch of
adapters that don't do anything.

This implements the service without any live adapters for the ports.

Will follow this up with another PR that actually implements the ports.

## Checklist
- [ ] Breaking changes are clearly marked as such in the PR description
and changelog
- [x] New behavior is reflected in tests
- [ ] [The specification](https://github.com/FuelLabs/fuel-specs/)
matches the implemented behavior (link update PR if changes are needed)

### Before requesting review
- [x] I have reviewed the code myself
- [ ] I have created follow-up issues caused by this PR and linked them
here

### After merging, notify other teams

[Add or remove entries as needed]

- [ ] [Rust SDK](https://github.com/FuelLabs/fuels-rs/)
- [ ] [Sway compiler](https://github.com/FuelLabs/sway/)
- [ ] [Platform
documentation](https://github.com/FuelLabs/devrel-requests/issues/new?assignees=&labels=new+request&projects=&template=NEW-REQUEST.yml&title=%5BRequest%5D%3A+)
(for out-of-organization contributors, the person merging the PR will do
this)
- [ ] Someone else?

---------

Co-authored-by: human <[email protected]>
Co-authored-by: Green Baneling <[email protected]>
  • Loading branch information
3 people authored Jun 25, 2024
1 parent f5ac3a4 commit ac65224
Show file tree
Hide file tree
Showing 8 changed files with 383 additions and 6 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

### Added
- [1972](https://github.com/FuelLabs/fuel-core/pull/1972): Implement `AlgorithmUpdater` for `GasPriceService`
- [#1948](https://github.com/FuelLabs/fuel-core/pull/1948): Add new `AlgorithmV1` and `AlgorithmUpdaterV1` for the gas price. Include tools for analysis

## [Version 0.30.0]

### Added
Expand All @@ -25,7 +29,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added
- [#1889](https://github.com/FuelLabs/fuel-core/pull/1889): Add new `FuelGasPriceProvider` that receives the gas price algorithm from a `GasPriceService`
- [#1948](https://github.com/FuelLabs/fuel-core/pull/1948): Add new `AlgorithmV1` and `AlgorithmUpdaterV1' for the gas price. Include tools for analysis

### Changed
- [#1942](https://github.com/FuelLabs/fuel-core/pull/1942): Sequential relayer's commits.
Expand Down
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion crates/fuel-gas-price-algorithm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub enum Error {
/// The DA portion also uses a moving average of the profits over the last `avg_window` blocks
/// instead of the actual profit. Setting the `avg_window` to 1 will effectively disable the
/// moving average.
#[derive(Debug, Clone, PartialEq)]
pub struct AlgorithmV1 {
/// The lowest the algorithm allows the gas price to go
min_da_gas_price: u64,
Expand Down Expand Up @@ -140,6 +141,7 @@ impl AlgorithmV1 {
///
/// This projection will inevitably lead to error in the gas price calculation. Special care should be taken
/// to account for the worst case scenario when calculating the parameters of the algorithm.
#[derive(Debug, Clone, PartialEq)]
pub struct AlgorithmUpdaterV1 {
/// The gas price to cover the execution of the next block
pub new_exec_price: u64,
Expand Down Expand Up @@ -192,7 +194,7 @@ pub struct RecordedBlock {
pub block_cost: u64,
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct BlockBytes {
pub height: u32,
pub block_bytes: u64,
Expand Down
2 changes: 2 additions & 0 deletions crates/services/gas_price_service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ anyhow = { workspace = true }
async-trait = { workspace = true }
fuel-core-services = { workspace = true }
fuel-core-types = { workspace = true }
fuel-gas-price-algorithm = { workspace = true }
futures = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }

Expand Down
137 changes: 137 additions & 0 deletions crates/services/gas_price_service/src/fuel_gas_price_updater.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
use crate::UpdateAlgorithm;
use fuel_core_types::fuel_types::BlockHeight;
use fuel_gas_price_algorithm::{
AlgorithmUpdaterV1,
AlgorithmV1,
RecordedBlock,
};

#[cfg(test)]
mod tests;

pub struct FuelGasPriceUpdater<L2, Metadata> {
inner: AlgorithmUpdaterV1,
l2_block_source: L2,
metadata_storage: Metadata,
}

#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Failed to find L2 block at height {block_height:?}: {source_error:?}")]
CouldNotFetchL2Block {
block_height: BlockHeight,
source_error: anyhow::Error,
},
#[error("Failed to find DA records: {0:?}")]
CouldNotFetchDARecord(anyhow::Error),
}

type Result<T> = std::result::Result<T, Error>;

// Info required about the l2 block for the gas price algorithm
#[derive(Debug, Clone)]
pub struct BlockInfo {
// Block height
pub height: u32,
// Fullness of block gas usage vs max block gas
pub fullness: (u64, u64),
// Block size in bytes
pub block_bytes: u64,
// Gas price of the block
pub gas_price: u64,
}
#[async_trait::async_trait]
pub trait L2BlockSource: Send + Sync {
async fn get_l2_block(&self, height: BlockHeight) -> Result<BlockInfo>;
}

#[async_trait::async_trait]
pub trait DARecordSource: Send + Sync {
async fn get_da_record(&self) -> Result<Vec<RecordedBlock>>;
}

#[derive(Debug, Clone)]
pub enum UpdaterMetadata {
V1(AlgorithmUpdaterV1),
}

impl From<UpdaterMetadata> for AlgorithmUpdaterV1 {
fn from(metadata: UpdaterMetadata) -> Self {
match metadata {
UpdaterMetadata::V1(v1) => v1,
}
}
}

impl From<AlgorithmUpdaterV1> for UpdaterMetadata {
fn from(v1: AlgorithmUpdaterV1) -> Self {
UpdaterMetadata::V1(v1)
}
}

#[async_trait::async_trait]
pub trait MetadataStorage: Send + Sync {
async fn get_metadata(&self) -> Result<Option<UpdaterMetadata>>;
async fn set_metadata(&self, metadata: UpdaterMetadata) -> Result<()>;
}

impl<L2, Metadata> FuelGasPriceUpdater<L2, Metadata>
where
Metadata: MetadataStorage,
{
pub async fn init(
init_metadata: UpdaterMetadata,
l2_block_source: L2,
metadata_storage: Metadata,
) -> Result<Self> {
let inner = metadata_storage
.get_metadata()
.await?
.unwrap_or(init_metadata)
.into();
let updater = Self {
inner,
l2_block_source,
metadata_storage,
};
Ok(updater)
}
}

#[async_trait::async_trait]
impl<L2, Metadata> UpdateAlgorithm for FuelGasPriceUpdater<L2, Metadata>
where
L2: L2BlockSource,
Metadata: MetadataStorage + Send + Sync,
{
type Algorithm = AlgorithmV1;

fn start(&self, _for_block: BlockHeight) -> Self::Algorithm {
self.inner.algorithm()
}

async fn next(&mut self) -> anyhow::Result<Self::Algorithm> {
tokio::select! {
l2_block = self.l2_block_source.get_l2_block(self.inner.l2_block_height.into()) => {
tracing::info!("Received L2 block: {:?}", l2_block);
let l2_block = l2_block?;
let BlockInfo {
height,
fullness,
block_bytes,
gas_price,
} = l2_block;
self.inner.update_l2_block_data(
height,
fullness,
block_bytes,
gas_price,
)?;
self.metadata_storage
.set_metadata(self.inner.clone().into())
.await?;
Ok(self.inner.algorithm())
}
}
}
}
Loading

0 comments on commit ac65224

Please sign in to comment.