From 3e15172df259b59012483e41d5cc24e0b561b692 Mon Sep 17 00:00:00 2001 From: Guy Nir Date: Sun, 26 Jan 2025 16:45:53 +0200 Subject: [PATCH] feat(starknet_l1_provider): add baselayer interface to query ethereum gas price --- .../src/ethereum_base_layer_contract.rs | 76 ++++++++++++++++++- crates/papyrus_base_layer/src/lib.rs | 26 +++++++ 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs index 0fa9e91d253..15fbcbacb4d 100644 --- a/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs +++ b/crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs @@ -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}; @@ -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 = Result; @@ -131,6 +136,73 @@ impl BaseLayerContract for EthereumBaseLayerContract { hash: block.header.hash.0, })) } + + async fn get_block_timestamp(&self, block_number: u64) -> EthereumBaseLayerResult> { + 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> { + 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> { + 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> { + 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)] diff --git a/crates/papyrus_base_layer/src/lib.rs b/crates/papyrus_base_layer/src/lib.rs index a3ac9e30702..3822b2156a1 100644 --- a/crates/papyrus_base_layer/src/lib.rs +++ b/crates/papyrus_base_layer/src/lib.rs @@ -60,6 +60,32 @@ pub trait BaseLayerContract { block_range: RangeInclusive, event_identifiers: &[&str], ) -> Result, Self::Error>; + + async fn get_block_timestamp(&self, block_number: u64) -> Result, Self::Error>; + async fn get_block_gas_price(&self, block_number: u64) -> Result, Self::Error>; + async fn get_block_data_gas_price( + &self, + block_number: u64, + ) -> Result, Self::Error>; + async fn get_price_sample(&self, block_number: u64) + -> Result, 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.