Skip to content

Commit

Permalink
feat(solis): update katana for solis
Browse files Browse the repository at this point in the history
  • Loading branch information
kwiss committed May 9, 2024
1 parent 6f2ac9b commit 7d2e91f
Show file tree
Hide file tree
Showing 17 changed files with 1,015 additions and 35 deletions.
43 changes: 43 additions & 0 deletions bin/solis/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[package]
description = "A fast and lightweight local Starknet development sequencer."
edition.workspace = true
license-file.workspace = true
name = "solis"
repository.workspace = true
version.workspace = true

[dependencies]
alloy-primitives.workspace = true
anyhow.workspace = true
cfg-if = "1.0.0"
clap.workspace = true
clap_complete.workspace = true
common.workspace = true
console.workspace = true
dojo-metrics.workspace = true
katana-core.workspace = true
katana-executor.workspace = true
katana-primitives.workspace = true
katana-rpc-api.workspace = true
katana-rpc.workspace = true
serde_json.workspace = true
shellexpand = "3.1.0"
starknet_api.workspace = true
tokio.workspace = true
tracing-subscriber.workspace = true
tracing.workspace = true
url.workspace = true

[dev-dependencies]
assert_matches = "1.5.0"

[features]
default = [ "blockifier", "jemalloc", "messaging" ]

blockifier = [ "katana-executor/blockifier" ]
# Disable until SIR support Cairo 2.6.3
#sir = [ "katana-executor/sir" ]

jemalloc = [ "dojo-metrics/jemalloc" ]
messaging = [ "katana-core/messaging" ]
starknet-messaging = [ "katana-core/starknet-messaging", "messaging" ]
341 changes: 341 additions & 0 deletions bin/solis/src/args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,341 @@
//! Katana binary executable.
//!
//! ## Feature Flags
//!
//! - `jemalloc`: Uses [jemallocator](https://github.com/tikv/jemallocator) as the global allocator.
//! This is **not recommended on Windows**. See [here](https://rust-lang.github.io/rfcs/1974-global-allocators.html#jemalloc)
//! for more info.
//! - `jemalloc-prof`: Enables [jemallocator's](https://github.com/tikv/jemallocator) heap profiling
//! and leak detection functionality. See [jemalloc's opt.prof](https://jemalloc.net/jemalloc.3.html#opt.prof)
//! documentation for usage details. This is **not recommended on Windows**. See [here](https://rust-lang.github.io/rfcs/1974-global-allocators.html#jemalloc)
//! for more info.

use std::net::SocketAddr;
use std::path::PathBuf;

use alloy_primitives::U256;
use clap::{Args, Parser, Subcommand};
use clap_complete::Shell;
use common::parse::parse_socket_address;
use katana_core::backend::config::{Environment, StarknetConfig};
use katana_core::constants::{
DEFAULT_ETH_L1_GAS_PRICE, DEFAULT_INVOKE_MAX_STEPS, DEFAULT_SEQUENCER_ADDRESS,
DEFAULT_STRK_L1_GAS_PRICE, DEFAULT_VALIDATE_MAX_STEPS,
};
use katana_core::sequencer::SequencerConfig;
use katana_primitives::block::GasPrices;
use katana_primitives::chain::ChainId;
use katana_primitives::genesis::allocation::DevAllocationsGenerator;
use katana_primitives::genesis::constant::DEFAULT_PREFUNDED_ACCOUNT_BALANCE;
use katana_primitives::genesis::Genesis;
use katana_rpc::config::ServerConfig;
use katana_rpc_api::ApiKind;
use tracing::Subscriber;
use tracing_subscriber::{fmt, EnvFilter};
use url::Url;

use crate::utils::{parse_genesis, parse_seed};

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
#[command(propagate_version = true)]
pub struct KatanaArgs {
#[arg(long)]
#[arg(help = "Don't print anything on startup.")]
pub silent: bool,

#[arg(long)]
#[arg(conflicts_with = "block_time")]
#[arg(help = "Disable auto and interval mining, and mine on demand instead via an endpoint.")]
pub no_mining: bool,

#[arg(short, long)]
#[arg(value_name = "MILLISECONDS")]
#[arg(help = "Block time in milliseconds for interval mining.")]
pub block_time: Option<u64>,

#[arg(long)]
#[arg(value_name = "PATH")]
#[arg(help = "Directory path of the database to initialize from.")]
#[arg(long_help = "Directory path of the database to initialize from. The path must either \
be an empty directory or a directory which already contains a previously \
initialized Katana database.")]
pub db_dir: Option<PathBuf>,

#[arg(long)]
#[arg(value_name = "URL")]
#[arg(help = "The Starknet RPC provider to fork the network from.")]
pub rpc_url: Option<Url>,

#[arg(long)]
pub dev: bool,

#[arg(long)]
#[arg(help = "Output logs in JSON format.")]
pub json_log: bool,

/// Enable Prometheus metrics.
///
/// The metrics will be served at the given interface and port.
#[arg(long, value_name = "SOCKET", value_parser = parse_socket_address, help_heading = "Metrics")]
pub metrics: Option<SocketAddr>,

#[arg(long)]
#[arg(requires = "rpc_url")]
#[arg(value_name = "BLOCK_NUMBER")]
#[arg(help = "Fork the network at a specific block.")]
pub fork_block_number: Option<u64>,

#[cfg(feature = "messaging")]
#[arg(long)]
#[arg(value_name = "PATH")]
#[arg(value_parser = katana_core::service::messaging::MessagingConfig::parse)]
#[arg(help = "Configure the messaging with an other chain.")]
#[arg(long_help = "Configure the messaging to allow Katana listening/sending messages on a \
settlement chain that can be Ethereum or an other Starknet sequencer. \
The configuration file details and examples can be found here: https://book.dojoengine.org/toolchain/katana/reference#messaging")]
pub messaging: Option<katana_core::service::messaging::MessagingConfig>,

#[command(flatten)]
#[command(next_help_heading = "Server options")]
pub server: ServerOptions,

#[command(flatten)]
#[command(next_help_heading = "Starknet options")]
pub starknet: StarknetOptions,

#[command(subcommand)]
pub command: Option<Commands>,
}

#[derive(Debug, Subcommand)]
pub enum Commands {
#[command(about = "Generate shell completion file for specified shell")]
Completions { shell: Shell },
}

#[derive(Debug, Args, Clone)]
pub struct ServerOptions {
#[arg(short, long)]
#[arg(default_value = "5050")]
#[arg(help = "Port number to listen on.")]
pub port: u16,

#[arg(long)]
#[arg(help = "The IP address the server will listen on.")]
pub host: Option<String>,

#[arg(long)]
#[arg(default_value = "100")]
#[arg(help = "Maximum number of concurrent connections allowed.")]
pub max_connections: u32,

#[arg(long)]
#[arg(value_delimiter = ',')]
#[arg(help = "Enables the CORS layer and sets the allowed origins, separated by commas.")]
pub allowed_origins: Option<Vec<String>>,
}

#[derive(Debug, Args, Clone)]
pub struct StarknetOptions {
#[arg(long)]
#[arg(default_value = "0")]
#[arg(help = "Specify the seed for randomness of accounts to be predeployed.")]
pub seed: String,

#[arg(long = "accounts")]
#[arg(value_name = "NUM")]
#[arg(default_value = "10")]
#[arg(help = "Number of pre-funded accounts to generate.")]
pub total_accounts: u16,

#[arg(long)]
#[arg(help = "Disable charging fee when executing transactions.")]
pub disable_fee: bool,

#[arg(long)]
#[arg(help = "Disable validation when executing transactions.")]
pub disable_validate: bool,

#[command(flatten)]
#[command(next_help_heading = "Environment options")]
pub environment: EnvironmentOptions,

#[arg(long)]
#[arg(value_parser = parse_genesis)]
#[arg(conflicts_with_all(["rpc_url", "seed", "total_accounts"]))]
pub genesis: Option<Genesis>,
}

#[derive(Debug, Args, Clone)]
pub struct EnvironmentOptions {
#[arg(long)]
#[arg(help = "The chain ID.")]
#[arg(long_help = "The chain ID. If a raw hex string (`0x` prefix) is provided, then it'd \
used as the actual chain ID. Otherwise, it's represented as the raw \
ASCII values. It must be a valid Cairo short string.")]
#[arg(default_value = "KATANA")]
#[arg(value_parser = ChainId::parse)]
pub chain_id: ChainId,

#[arg(long)]
#[arg(help = "The maximum number of steps available for the account validation logic.")]
#[arg(default_value_t = DEFAULT_VALIDATE_MAX_STEPS)]
pub validate_max_steps: u32,

#[arg(long)]
#[arg(help = "The maximum number of steps available for the account execution logic.")]
#[arg(default_value_t = DEFAULT_INVOKE_MAX_STEPS)]
pub invoke_max_steps: u32,

#[arg(long = "eth-gas-price")]
#[arg(conflicts_with = "genesis")]
#[arg(help = "The L1 ETH gas price. (denominated in wei)")]
#[arg(default_value_t = DEFAULT_ETH_L1_GAS_PRICE)]
pub l1_eth_gas_price: u128,

#[arg(long = "strk-gas-price")]
#[arg(conflicts_with = "genesis")]
#[arg(help = "The L1 STRK gas price. (denominated in fri)")]
#[arg(default_value_t = DEFAULT_STRK_L1_GAS_PRICE)]
pub l1_strk_gas_price: u128,
}

impl KatanaArgs {
pub fn init_logging(&self) -> Result<(), Box<dyn std::error::Error>> {
const DEFAULT_LOG_FILTER: &str = "info,executor=trace,forked_backend=trace,server=debug,\
katana_core=trace,blockifier=off,jsonrpsee_server=off,\
hyper=off,messaging=debug,node=error";

let builder = fmt::Subscriber::builder().with_env_filter(
EnvFilter::try_from_default_env().or(EnvFilter::try_new(DEFAULT_LOG_FILTER))?,
);

let subscriber: Box<dyn Subscriber + Send + Sync> = if self.json_log {
Box::new(builder.json().finish())
} else {
Box::new(builder.finish())
};

Ok(tracing::subscriber::set_global_default(subscriber)?)
}

pub fn sequencer_config(&self) -> SequencerConfig {
SequencerConfig {
block_time: self.block_time,
no_mining: self.no_mining,
#[cfg(feature = "messaging")]
messaging: self.messaging.clone(),
}
}

pub fn server_config(&self) -> ServerConfig {
let mut apis = vec![ApiKind::Starknet, ApiKind::Katana, ApiKind::Torii, ApiKind::Saya];
// only enable `katana` API in dev mode
if self.dev {
apis.push(ApiKind::Dev);
}

ServerConfig {
apis,
port: self.server.port,
host: self.server.host.clone().unwrap_or("0.0.0.0".into()),
max_connections: self.server.max_connections,
allowed_origins: self.server.allowed_origins.clone(),
}
}

pub fn starknet_config(&self) -> StarknetConfig {
let genesis = match self.starknet.genesis.clone() {
Some(genesis) => genesis,
None => {
let gas_prices = GasPrices {
eth: self.starknet.environment.l1_eth_gas_price,
strk: self.starknet.environment.l1_strk_gas_price,
};

let accounts = DevAllocationsGenerator::new(self.starknet.total_accounts)
.with_seed(parse_seed(&self.starknet.seed))
.with_balance(U256::from(DEFAULT_PREFUNDED_ACCOUNT_BALANCE))
.generate();

let mut genesis = Genesis {
gas_prices,
sequencer_address: *DEFAULT_SEQUENCER_ADDRESS,
..Default::default()
};

genesis.extend_allocations(accounts.into_iter().map(|(k, v)| (k, v.into())));
genesis
}
};

StarknetConfig {
disable_fee: self.starknet.disable_fee,
disable_validate: self.starknet.disable_validate,
fork_rpc_url: self.rpc_url.clone(),
fork_block_number: self.fork_block_number,
env: Environment {
chain_id: self.starknet.environment.chain_id,
invoke_max_steps: self.starknet.environment.invoke_max_steps,
validate_max_steps: self.starknet.environment.validate_max_steps,
},
db_dir: self.db_dir.clone(),
genesis,
}
}
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_starknet_config_default() {
let args = KatanaArgs::parse_from(["katana"]);
let config = args.starknet_config();

assert!(!config.disable_fee);
assert!(!config.disable_validate);
assert_eq!(config.fork_rpc_url, None);
assert_eq!(config.fork_block_number, None);
assert_eq!(config.env.chain_id, ChainId::parse("KATANA").unwrap());
assert_eq!(config.env.invoke_max_steps, DEFAULT_INVOKE_MAX_STEPS);
assert_eq!(config.env.validate_max_steps, DEFAULT_VALIDATE_MAX_STEPS);
assert_eq!(config.db_dir, None);
assert_eq!(config.genesis.gas_prices.eth, DEFAULT_ETH_L1_GAS_PRICE);
assert_eq!(config.genesis.gas_prices.strk, DEFAULT_STRK_L1_GAS_PRICE);
assert_eq!(config.genesis.sequencer_address, *DEFAULT_SEQUENCER_ADDRESS);
}

#[test]
fn test_starknet_config_custom() {
let args = KatanaArgs::parse_from([
"katana",
"--disable-fee",
"--disable-validate",
"--chain-id",
"SN_GOERLI",
"--invoke-max-steps",
"200",
"--validate-max-steps",
"100",
"--db-dir",
"/path/to/db",
"--eth-gas-price",
"10",
"--strk-gas-price",
"20",
]);
let config = args.starknet_config();

assert!(config.disable_fee);
assert!(config.disable_validate);
assert_eq!(config.env.chain_id, ChainId::GOERLI);
assert_eq!(config.env.invoke_max_steps, 200);
assert_eq!(config.env.validate_max_steps, 100);
assert_eq!(config.db_dir, Some(PathBuf::from("/path/to/db")));
assert_eq!(config.genesis.gas_prices.eth, 10);
assert_eq!(config.genesis.gas_prices.strk, 20);
}
}
Loading

0 comments on commit 7d2e91f

Please sign in to comment.