Skip to content

Commit

Permalink
feat(starknet_l1_provider): add baselayer interface to query ethereum…
Browse files Browse the repository at this point in the history
… gas price
  • Loading branch information
guy-starkware committed Jan 29, 2025
1 parent 993f242 commit 7be5ae4
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 2 deletions.
76 changes: 74 additions & 2 deletions crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ use alloy_json_rpc::RpcError;
use alloy_primitives::Address as EthereumContractAddress;
use alloy_provider::network::Ethereum;
use alloy_provider::{Provider, ProviderBuilder, RootProvider};
use alloy_rpc_types_eth::{BlockId, BlockTransactionsKind, Filter as EthEventFilter};
use alloy_rpc_types_eth::{
BlockId,
BlockNumberOrTag,
BlockTransactionsKind,
Filter as EthEventFilter,
};
use alloy_sol_types::{sol, sol_data};
use alloy_transport::TransportErrorKind;
use alloy_transport_http::{Client, Http};
Expand All @@ -21,7 +26,7 @@ use starknet_api::StarknetApiError;
use url::Url;
use validator::Validate;

use crate::{BaseLayerContract, L1BlockNumber, L1BlockReference, L1Event};
use crate::{BaseLayerContract, L1BlockNumber, L1BlockReference, L1Event, PriceSample};

pub type EthereumBaseLayerResult<T> = Result<T, EthereumBaseLayerError>;

Expand Down Expand Up @@ -131,6 +136,73 @@ impl BaseLayerContract for EthereumBaseLayerContract {
hash: block.header.hash.0,
}))
}

async fn get_block_timestamp(&self, block_number: u64) -> EthereumBaseLayerResult<Option<u64>> {
let block = self
.contract
.provider()
.get_block(
BlockId::Number(BlockNumberOrTag::Number(block_number)),
BlockTransactionsKind::Hashes,
)
.await?;
Ok(block.map(|block| block.header.timestamp))
}

async fn get_block_gas_price(
&self,
block_number: u64,
) -> EthereumBaseLayerResult<Option<u128>> {
let block = self
.contract
.provider()
.get_block(
BlockId::Number(BlockNumberOrTag::Number(block_number)),
BlockTransactionsKind::Hashes,
)
.await?;
Ok(block.and_then(|block| block.header.base_fee_per_gas))
}

async fn get_block_data_gas_price(
&self,
block_number: u64,
) -> EthereumBaseLayerResult<Option<u128>> {
let block = self
.contract
.provider()
.get_block(
BlockId::Number(BlockNumberOrTag::Number(block_number)),
BlockTransactionsKind::Hashes,
)
.await?;
Ok(block.and_then(|block| block.header.blob_fee()))
}

// Combine the above three functions into one call, which is more efficient.
async fn get_price_sample(
&self,
block_number: u64,
) -> EthereumBaseLayerResult<Option<PriceSample>> {
let block = self
.contract
.provider()
.get_block(
BlockId::Number(BlockNumberOrTag::Number(block_number)),
BlockTransactionsKind::Hashes,
)
.await?;
if let Some(block) = block {
match (block.header.timestamp, block.header.base_fee_per_gas, block.header.blob_fee()) {
(timestamp, Some(base_fee_per_gas), Some(blob_fee)) => {
Ok(Some(PriceSample { timestamp, base_fee_per_gas, blob_fee }))
}
_ => Ok(None),
}
} else {
Ok(None)
}
}
}

#[derive(thiserror::Error, Debug)]
Expand Down
26 changes: 26 additions & 0 deletions crates/papyrus_base_layer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,32 @@ pub trait BaseLayerContract {
block_range: RangeInclusive<L1BlockNumber>,
event_identifiers: &[&str],
) -> Result<Vec<L1Event>, Self::Error>;

async fn get_block_timestamp(&self, block_number: u64) -> Result<Option<u64>, Self::Error>;
async fn get_block_gas_price(&self, block_number: u64) -> Result<Option<u128>, Self::Error>;
async fn get_block_data_gas_price(
&self,
block_number: u64,
) -> Result<Option<u128>, Self::Error>;
async fn get_price_sample(&self, block_number: u64)
-> Result<Option<PriceSample>, Self::Error>;
}

/// A struct the holds together the data on the baselayer's gas prices, for a given timestamp.
pub struct PriceSample {
timestamp: u64,
base_fee_per_gas: u128,
blob_fee: u128,
}

impl Display for PriceSample {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"PriceSample {{ timestamp: {}, base_fee_per_gas: {}, blob_fee: {} }}",
self.timestamp, self.base_fee_per_gas, self.blob_fee
)
}
}

/// Reference to an L1 block, extend as needed.
Expand Down
36 changes: 36 additions & 0 deletions crates/starknet_l1_provider/src/l1_gas_price_provider.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use std::collections::BTreeMap;

use papyrus_config::dumping::{ser_param, SerializeConfig};
use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam};
use serde::{Deserialize, Serialize};
use starknet_api::block::{BlockNumber, BlockTimestamp};
use thiserror::Error;
use validator::Validate;

// TODO(guyn): both these constants need to go into VersionedConstants.
pub const MEAN_NUMBER_OF_BLOCKS: u64 = 300;
pub const LAG_MARGIN_SECONDS: u32 = 60;

// TODO(guyn, Gilda): consider moving this to starknet_l1_provider_types/lib.rs?
// This is an interface that allows sharing the provider with the scraper across threads.
pub trait L1GasPriceProviderClient: Send + Sync {
fn add_price_info(
&self,
height: BlockNumber,
timestamp: BlockTimestamp,
gas_price: u128,
data_gas_price: u128,
) -> Result<(), L1GasPriceProviderError>;

fn get_price_info(&self, timestamp: BlockTimestamp) -> Result<u64, L1GasPriceProviderError>;
}

#[derive(Clone, Debug, Error)]
pub enum L1GasPriceProviderError {
#[error("Failed to add price info: {0}")]
AddPriceInfoError(String),
#[error("Failed to get price info: {0}")]
GetPriceInfoError(String),
}

// TODO(guyn): add the concrete implementation of the gas price provider client here.

0 comments on commit 7be5ae4

Please sign in to comment.