Skip to content

Commit

Permalink
feat(katana): starknet gas oracle placeholder (#2874)
Browse files Browse the repository at this point in the history
Starknet doesn't yet provide a way to query the L2 gas prices from the current RPC specs (but soon will be in [RPC v0.80 ](https://github.com/starkware-libs/starknet-specs/blob/c94df2c5866e11c866abd3d234b0d5df681073c3/api/starknet_api_openrpc.json#L1603-L1607)), so this is merely a placeholder to make sure that we can run the node with Starknet as the settlement layer when specified in the `ChainSpec`. Reference: #2870
  • Loading branch information
kariy committed Jan 8, 2025
1 parent 7bc8c58 commit d4a757d
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 39 deletions.
14 changes: 6 additions & 8 deletions crates/katana/chain-spec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use katana_primitives::chain::ChainId;
use katana_primitives::class::ClassHash;
use katana_primitives::contract::ContractAddress;
use katana_primitives::da::L1DataAvailabilityMode;
use katana_primitives::eth::{self, Address as EthAddress};
use katana_primitives::genesis::allocation::{DevAllocationsGenerator, GenesisAllocation};
use katana_primitives::genesis::constant::{
get_fee_token_balance_base_storage_address, DEFAULT_ACCOUNT_CLASS_PUBKEY_STORAGE_SLOT,
Expand All @@ -24,7 +23,7 @@ use katana_primitives::genesis::Genesis;
use katana_primitives::state::StateUpdatesWithClasses;
use katana_primitives::utils::split_u256;
use katana_primitives::version::{ProtocolVersion, CURRENT_STARKNET_VERSION};
use katana_primitives::Felt;
use katana_primitives::{eth, Felt};
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use starknet::core::utils::cairo_short_string_to_felt;
Expand Down Expand Up @@ -63,7 +62,7 @@ pub struct FeeContracts {
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum SettlementLayer {
Ethereum {
// The id of the settlement chain.
Expand All @@ -72,11 +71,11 @@ pub enum SettlementLayer {
// url for ethereum rpc provider
rpc_url: Url,

account: EthAddress,
/// account on the ethereum network
account: eth::Address,

// - The core appchain contract used to settlement
// - This is deployed on the L1
core_contract: EthAddress,
core_contract: eth::Address,
},

Starknet {
Expand All @@ -86,11 +85,10 @@ pub enum SettlementLayer {
// url for starknet rpc provider
rpc_url: Url,

// the account address that was used to initialized the l1 deployments
/// account on the starknet network
account: ContractAddress,

// - The core appchain contract used to settlement
// - This is deployed on the L1
core_contract: ContractAddress,
},
}
Expand Down
50 changes: 29 additions & 21 deletions crates/katana/core/src/backend/gas_oracle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,22 @@ const BUFFER_SIZE: usize = 60;
const INTERVAL: Duration = Duration::from_secs(60);
const ONE_GWEI: u128 = 1_000_000_000;

// TODO: implement a proper gas oracle function - sample the l1 gas and data gas prices
// currently this just return the hardcoded value set from the cli or if not set, the default value.
#[derive(Debug)]
pub enum L1GasOracle {
Fixed(FixedL1GasOracle),
Sampled(SampledL1GasOracle),
pub enum GasOracle {
Fixed(FixedGasOracle),
Sampled(EthereumSampledGasOracle),
}

#[derive(Debug)]
pub struct FixedL1GasOracle {
pub struct FixedGasOracle {
gas_prices: GasPrices,
data_gas_prices: GasPrices,
}

#[derive(Debug, Clone)]
pub struct SampledL1GasOracle {
pub struct EthereumSampledGasOracle {
prices: Arc<Mutex<SampledPrices>>,
l1_provider: Url,
provider: Url,
}

#[derive(Debug, Default)]
Expand All @@ -50,29 +48,39 @@ pub struct GasOracleWorker {
pub data_gas_price_buffer: GasPriceBuffer,
}

impl L1GasOracle {
impl GasOracle {
pub fn fixed(gas_prices: GasPrices, data_gas_prices: GasPrices) -> Self {
L1GasOracle::Fixed(FixedL1GasOracle { gas_prices, data_gas_prices })
GasOracle::Fixed(FixedGasOracle { gas_prices, data_gas_prices })
}

pub fn sampled(l1_provider: Url) -> Self {
/// Creates a new gas oracle that samples the gas prices from an Ethereum chain.
pub fn sampled_ethereum(eth_provider: Url) -> Self {
let prices: Arc<Mutex<SampledPrices>> = Arc::new(Mutex::new(SampledPrices::default()));
L1GasOracle::Sampled(SampledL1GasOracle { prices, l1_provider })
GasOracle::Sampled(EthereumSampledGasOracle { prices, provider: eth_provider })
}

/// This is just placeholder for now, as Starknet doesn't provide a way to get the L2 gas
/// prices, we just return a fixed gas price values of 0. This is equivalent to calling
/// [`GasOracle::fixed`] with 0 values for both gas and data prices.
///
/// The result of this is the same as running the node with fee disabled.
pub fn sampled_starknet() -> Self {
Self::fixed(GasPrices { eth: 0, strk: 0 }, GasPrices { eth: 0, strk: 0 })
}

/// Returns the current gas prices.
pub fn current_gas_prices(&self) -> GasPrices {
match self {
L1GasOracle::Fixed(fixed) => fixed.current_gas_prices(),
L1GasOracle::Sampled(sampled) => sampled.prices.lock().gas_prices.clone(),
GasOracle::Fixed(fixed) => fixed.current_gas_prices(),
GasOracle::Sampled(sampled) => sampled.prices.lock().gas_prices.clone(),
}
}

/// Returns the current data gas prices.
pub fn current_data_gas_prices(&self) -> GasPrices {
match self {
L1GasOracle::Fixed(fixed) => fixed.current_data_gas_prices(),
L1GasOracle::Sampled(sampled) => sampled.prices.lock().data_gas_prices.clone(),
GasOracle::Fixed(fixed) => fixed.current_data_gas_prices(),
GasOracle::Sampled(sampled) => sampled.prices.lock().data_gas_prices.clone(),
}
}

Expand All @@ -81,7 +89,7 @@ impl L1GasOracle {
Self::Fixed(..) => {}
Self::Sampled(oracle) => {
let prices = oracle.prices.clone();
let l1_provider = oracle.l1_provider.clone();
let l1_provider = oracle.provider.clone();

task_spawner.build_task().critical().name("L1 Gas Oracle Worker").spawn(
async move {
Expand All @@ -97,7 +105,7 @@ impl L1GasOracle {
}
}

impl SampledL1GasOracle {
impl EthereumSampledGasOracle {
pub fn current_data_gas_prices(&self) -> GasPrices {
self.prices.lock().data_gas_prices.clone()
}
Expand All @@ -107,7 +115,7 @@ impl SampledL1GasOracle {
}
}

impl FixedL1GasOracle {
impl FixedGasOracle {
pub fn current_data_gas_prices(&self) -> GasPrices {
self.data_gas_prices.clone()
}
Expand Down Expand Up @@ -289,10 +297,10 @@ mod tests {
#[ignore = "Requires external assumption"]
async fn test_gas_oracle() {
let url = Url::parse("https://eth.merkle.io/").expect("Invalid URL");
let oracle = L1GasOracle::sampled(url.clone());
let oracle = GasOracle::sampled_ethereum(url.clone());

let shared_prices = match &oracle {
L1GasOracle::Sampled(sampled) => sampled.prices.clone(),
GasOracle::Sampled(sampled) => sampled.prices.clone(),
_ => panic!("Expected sampled oracle"),
};

Expand Down
4 changes: 2 additions & 2 deletions crates/katana/core/src/backend/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::sync::Arc;

use gas_oracle::L1GasOracle;
use gas_oracle::GasOracle;
use katana_chain_spec::ChainSpec;
use katana_executor::{ExecutionOutput, ExecutionResult, ExecutorFactory};
use katana_primitives::block::{
Expand Down Expand Up @@ -41,7 +41,7 @@ pub struct Backend<EF: ExecutorFactory> {

pub executor_factory: Arc<EF>,

pub gas_oracle: L1GasOracle,
pub gas_oracle: GasOracle,
}

impl<EF: ExecutorFactory> Backend<EF> {
Expand Down
13 changes: 5 additions & 8 deletions crates/katana/node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use dojo_metrics::{Report, Server as MetricsServer};
use hyper::Method;
use jsonrpsee::RpcModule;
use katana_chain_spec::SettlementLayer;
use katana_core::backend::gas_oracle::L1GasOracle;
use katana_core::backend::gas_oracle::GasOracle;
use katana_core::backend::storage::Blockchain;
use katana_core::backend::Backend;
use katana_core::env::BlockContextGenerator;
Expand Down Expand Up @@ -202,20 +202,17 @@ pub async fn build(mut config: Config) -> Result<Node> {
// Check if the user specify a fixed gas price in the dev config.
let gas_oracle = if let Some(fixed_prices) = &config.dev.fixed_gas_prices {
// Use fixed gas prices if provided in the configuration
L1GasOracle::fixed(fixed_prices.gas_price.clone(), fixed_prices.data_gas_price.clone())
GasOracle::fixed(fixed_prices.gas_price.clone(), fixed_prices.data_gas_price.clone())
} else if let Some(settlement) = &config.chain.settlement {
match settlement {
SettlementLayer::Starknet { .. } => GasOracle::sampled_starknet(),
SettlementLayer::Ethereum { rpc_url, .. } => {
// Default to a sampled gas oracle using the given provider
L1GasOracle::sampled(rpc_url.clone())
}
SettlementLayer::Starknet { .. } => {
todo!("starknet gas oracle")
GasOracle::sampled_ethereum(rpc_url.clone())
}
}
} else {
// Use default fixed gas prices if no url and if no fixed prices are provided
L1GasOracle::fixed(
GasOracle::fixed(
GasPrices { eth: DEFAULT_ETH_L1_GAS_PRICE, strk: DEFAULT_STRK_L1_GAS_PRICE },
GasPrices { eth: DEFAULT_ETH_L1_DATA_GAS_PRICE, strk: DEFAULT_STRK_L1_DATA_GAS_PRICE },
)
Expand Down

0 comments on commit d4a757d

Please sign in to comment.