diff --git a/Cargo.lock b/Cargo.lock index f9e754902f61..0a84a976bfa6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11267,6 +11267,7 @@ dependencies = [ "serde", "serde_json", "tracing", + "url", "zksync_basic_types", "zksync_concurrency", "zksync_consensus_utils", diff --git a/core/lib/config/Cargo.toml b/core/lib/config/Cargo.toml index 46c0b27d4b03..474377dc6363 100644 --- a/core/lib/config/Cargo.toml +++ b/core/lib/config/Cargo.toml @@ -22,6 +22,7 @@ anyhow.workspace = true rand.workspace = true secrecy.workspace = true serde = { workspace = true, features = ["derive"] } +url.workspace = true [dev-dependencies] serde_json.workspace = true diff --git a/core/lib/config/src/configs/general.rs b/core/lib/config/src/configs/general.rs index dfb81af1cf8c..614e48dda42e 100644 --- a/core/lib/config/src/configs/general.rs +++ b/core/lib/config/src/configs/general.rs @@ -1,3 +1,5 @@ +use url::Url; + use crate::{ configs::{ base_token_adjuster::BaseTokenAdjusterConfig, @@ -61,3 +63,25 @@ pub struct GeneralConfig { pub prover_job_monitor_config: Option, pub timestamp_asserter_config: Option, } + +impl GeneralConfig { + pub fn prometheus_host(&self) -> Option { + self.api_config + .as_ref() + .and_then(|api| api.prometheus.pushgateway_url.as_ref()) + .and_then(|url| Url::parse(url).ok()) + .and_then(|url| url.host_str().map(String::from)) + } + + pub fn set_prometheus_host(&mut self, host: &str) -> anyhow::Result<()> { + if let Some(api) = self.api_config.as_mut() { + if let Some(url) = api.prometheus.pushgateway_url.as_mut() { + let mut new_url = Url::parse(url)?; + new_url.set_host(Some(host))?; + *url = new_url.to_string(); + } + } + + Ok(()) + } +} diff --git a/core/lib/config/src/configs/secrets.rs b/core/lib/config/src/configs/secrets.rs index 8285d81e4bd2..960d14c0c102 100644 --- a/core/lib/config/src/configs/secrets.rs +++ b/core/lib/config/src/configs/secrets.rs @@ -34,6 +34,65 @@ pub struct Secrets { pub data_availability: Option, } +impl Secrets { + pub fn prover_url_host(&self) -> Option { + self.database + .as_ref() + .and_then(|database| database.prover_url.as_ref()) + .and_then(|url| url.expose_url().host_str()) + .map(String::from) + } + + pub fn set_prover_url_host(&mut self, host: &str) -> anyhow::Result<()> { + if let Some(database) = self.database.as_mut() { + if let Some(url) = database.prover_url.as_mut() { + let mut new_url = url.expose_url().clone(); + new_url.set_host(Some(host))?; + *url = SensitiveUrl::from(new_url); + } + } + + Ok(()) + } + + pub fn server_url_host(&self) -> Option { + self.database + .as_ref() + .and_then(|database| database.server_url.as_ref()) + .and_then(|url| url.expose_url().host_str()) + .map(String::from) + } + + pub fn set_server_url_host(&mut self, host: &str) -> anyhow::Result<()> { + if let Some(database) = self.database.as_mut() { + if let Some(url) = database.server_url.as_mut() { + let mut new_url = url.expose_url().clone(); + new_url.set_host(Some(host))?; + *url = SensitiveUrl::from(new_url); + } + } + + Ok(()) + } + + pub fn l1_rpc_url_host(&self) -> Option { + self.l1 + .as_ref() + .and_then(|l1| l1.l1_rpc_url.expose_url().host_str()) + .map(String::from) + } + + pub fn set_l1_rpc_url_host(&mut self, host: &str) -> anyhow::Result<()> { + if let Some(l1) = &mut self.l1 { + let mut new_url = l1.l1_rpc_url.expose_url().clone(); + new_url.set_host(Some(host))?; + l1.l1_rpc_url = SensitiveUrl::from(new_url); + } + + Ok(()) + } +} + impl DatabaseSecrets { /// Returns a copy of the master database URL as a `Result` to simplify error propagation. pub fn master_url(&self) -> anyhow::Result { diff --git a/prover/Cargo.lock b/prover/Cargo.lock index 453a768c0678..eefbec3b98eb 100644 --- a/prover/Cargo.lock +++ b/prover/Cargo.lock @@ -8235,6 +8235,7 @@ dependencies = [ "secrecy 0.8.0", "serde", "tracing", + "url", "zksync_basic_types", "zksync_concurrency", "zksync_consensus_utils", diff --git a/zkstack_cli/Cargo.lock b/zkstack_cli/Cargo.lock index 900ac677fd61..e14b01745ba1 100644 --- a/zkstack_cli/Cargo.lock +++ b/zkstack_cli/Cargo.lock @@ -713,6 +713,8 @@ dependencies = [ "futures", "git_version_macro", "once_cell", + "reqwest 0.12.9", + "semver", "serde", "serde_json", "serde_yaml", @@ -6796,6 +6798,7 @@ dependencies = [ "rand", "secrecy", "serde", + "url", "zksync_basic_types", "zksync_concurrency", "zksync_consensus_utils", diff --git a/zkstack_cli/Cargo.toml b/zkstack_cli/Cargo.toml index 1734673aefba..482d55effcfe 100644 --- a/zkstack_cli/Cargo.toml +++ b/zkstack_cli/Cargo.toml @@ -53,6 +53,8 @@ lazy_static = "1.4.0" once_cell = "1.19.0" prost = "0.12.1" rand = "0.8.5" +reqwest = { version = "0.12.8", features = ["json"] } +semver = "1.0.23" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_yaml = "0.9" diff --git a/zkstack_cli/crates/common/Cargo.toml b/zkstack_cli/crates/common/Cargo.toml index 5fdf481bea6f..8abcfcc626b1 100644 --- a/zkstack_cli/crates/common/Cargo.toml +++ b/zkstack_cli/crates/common/Cargo.toml @@ -30,3 +30,5 @@ xshell.workspace = true thiserror.workspace = true strum.workspace = true git_version_macro.workspace = true +reqwest.workspace = true +semver.workspace = true diff --git a/zkstack_cli/crates/common/src/github.rs b/zkstack_cli/crates/common/src/github.rs new file mode 100644 index 000000000000..28244dd9c0bb --- /dev/null +++ b/zkstack_cli/crates/common/src/github.rs @@ -0,0 +1,112 @@ +use anyhow::{Context, Result}; +use reqwest::{ + header::{HeaderMap, HeaderValue}, + Client, +}; +use semver::Version; +use serde::{Deserialize, Serialize}; + +const GITHUB_API_REPO_URL: &str = "https://api.github.com/repos/matter-labs/zksync-era"; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Tag { + pub name: String, + pub commit: Commit, + pub zipball_url: String, + pub tarball_url: String, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Commit { + pub sha: String, + pub url: String, +} + +/// Fetches and sorts GitHub repository tags by semantic version +pub struct GitHubTagFetcher { + client: Client, + auth_token: Option, +} + +impl GitHubTagFetcher { + pub fn new(auth_token: Option) -> Result { + let client = Client::new(); + Ok(Self { client, auth_token }) + } + + pub async fn get_newest_core_tags(&self, limit: Option) -> Result> { + let mut all_tags = Vec::new(); + let mut page = 1; + + // Set up headers + let mut headers = HeaderMap::new(); + headers.insert( + "Accept", + HeaderValue::from_static("application/vnd.github+json"), + ); + headers.insert("User-Agent", HeaderValue::from_static("zkstack")); + headers.insert( + "X-GitHub-Api-Version", + HeaderValue::from_static("2022-11-28"), + ); + + if let Some(token) = &self.auth_token { + headers.insert( + "Authorization", + HeaderValue::from_str(&format!("Bearer {}", token)) + .context("Invalid authorization header")?, + ); + } + + // Fetch all pages + loop { + let url = format!("{}/tags?page={}&per_page=100", GITHUB_API_REPO_URL, page); + + let response = self + .client + .get(&url) + .headers(headers.clone()) + .send() + .await?; + + if !response.status().is_success() { + return Err(anyhow::anyhow!( + "GitHub API request failed with status: {}", + response.status() + )); + } + + let page_tags: Vec = response.json().await?; + if page_tags.is_empty() { + break; + } + + all_tags.extend(page_tags); + page += 1; + } + + // filter tag names containing "core" + all_tags.retain(|t| t.name.contains("core")); + + // Sort tags by semantic version + all_tags.sort_by(|a, b| { + let version_a = clean_version(&a.name); + let version_b = clean_version(&b.name); + version_b.cmp(&version_a) // Reverse order (newest first) + }); + + // Apply limit if specified + Ok(if let Some(limit) = limit { + all_tags.into_iter().take(limit).collect() + } else { + all_tags + }) + } +} + +/// Cleans and parses version strings into semver::Version +fn clean_version(tag_name: &str) -> Version { + // Remove "core-v" prefix and parse the version string + let cleaned = tag_name.trim_start_matches("core-v"); + Version::parse(cleaned).unwrap_or_else(|_| Version::new(0, 0, 0)) +} diff --git a/zkstack_cli/crates/common/src/lib.rs b/zkstack_cli/crates/common/src/lib.rs index 9680bdd8df39..838d360b7337 100644 --- a/zkstack_cli/crates/common/src/lib.rs +++ b/zkstack_cli/crates/common/src/lib.rs @@ -12,6 +12,7 @@ pub mod external_node; pub mod files; pub mod forge; pub mod git; +pub mod github; pub mod server; pub mod version; pub mod wallets; diff --git a/zkstack_cli/crates/common/src/server.rs b/zkstack_cli/crates/common/src/server.rs index 40da1cf80325..7b355f97d341 100644 --- a/zkstack_cli/crates/common/src/server.rs +++ b/zkstack_cli/crates/common/src/server.rs @@ -1,5 +1,6 @@ use std::{ffi::OsStr, path::PathBuf}; +use anyhow::Context; use xshell::{cmd, Shell}; use crate::cmd::Cmd; @@ -19,6 +20,17 @@ pub enum ServerMode { Genesis, } +/// Possible execution modes. +#[derive(Clone, Debug, Default)] +pub enum ExecutionMode { + #[default] + Release, + Debug, + Docker { + tag: String, + }, +} + impl Server { /// Creates a new instance of the server. pub fn new(components: Option>, code_path: PathBuf, uring: bool) -> Self { @@ -31,9 +43,10 @@ impl Server { /// Runs the server. #[allow(clippy::too_many_arguments)] - pub fn run

( + pub async fn run

( &self, shell: &Shell, + execution_mode: ExecutionMode, server_mode: ServerMode, genesis_path: P, wallets_path: P, @@ -41,6 +54,7 @@ impl Server { secrets_path: P, contracts_path: P, mut additional_args: Vec, + ports: Vec, ) -> anyhow::Result<()> where P: AsRef, @@ -56,28 +70,20 @@ impl Server { let uring = self.uring.then_some("--features=rocksdb/io-uring"); - let mut cmd = Cmd::new( - cmd!( - shell, - "cargo run --release --bin zksync_server {uring...} -- - --genesis-path {genesis_path} - --wallets-path {wallets_path} - --config-path {general_path} - --secrets-path {secrets_path} - --contracts-config-path {contracts_path} - " - ) - .args(additional_args) - .env_remove("RUSTUP_TOOLCHAIN"), - ); - - // If we are running server in normal mode - // we need to get the output to the console - if let ServerMode::Normal = server_mode { - cmd = cmd.with_force_run(); - } - - cmd.run()?; + run_server( + shell, + uring, + genesis_path, + wallets_path, + general_path, + secrets_path, + contracts_path, + additional_args, + execution_mode, + server_mode, + ports, + ) + .await?; Ok(()) } @@ -99,3 +105,169 @@ impl Server { }) } } + +#[allow(clippy::too_many_arguments)] +async fn run_server

( + shell: &Shell, + uring: Option<&str>, + genesis_path: P, + wallets_path: P, + general_path: P, + secrets_path: P, + contracts_path: P, + additional_args: Vec, + execution_mode: ExecutionMode, + server_mode: ServerMode, + ports: Vec, +) -> anyhow::Result<()> +where + P: AsRef, +{ + let mut cmd = match execution_mode { + ExecutionMode::Release => cargo_run( + shell, + true, + uring, + genesis_path, + wallets_path, + general_path, + secrets_path, + contracts_path, + additional_args, + ), + ExecutionMode::Debug => cargo_run( + shell, + false, + uring, + genesis_path, + wallets_path, + general_path, + secrets_path, + contracts_path, + additional_args, + ), + ExecutionMode::Docker { tag } => docker_run( + shell, + genesis_path, + wallets_path, + general_path, + secrets_path, + contracts_path, + additional_args, + tag, + ports, + ), + }; + + // If we are running server in normal mode + // we need to get the output to the console + if let ServerMode::Normal = server_mode { + cmd = cmd.with_force_run(); + } + + cmd.run().context("Failed to run server") +} + +#[allow(clippy::too_many_arguments)] +fn cargo_run<'a, P>( + shell: &'a Shell, + release: bool, + uring: Option<&str>, + genesis_path: P, + wallets_path: P, + general_path: P, + secrets_path: P, + contracts_path: P, + additional_args: Vec, +) -> Cmd<'a> +where + P: AsRef, +{ + let mut cmd = cmd!(shell, "cargo run"); + + if release { + cmd = cmd.arg("--release"); + } + + cmd = cmd + .arg("--bin") + .arg("zksync_server") + .args(uring) + .arg("--") + .arg("--genesis-path") + .arg(genesis_path) + .arg("--wallets-path") + .arg(wallets_path) + .arg("--config-path") + .arg(general_path) + .arg("--secrets-path") + .arg(secrets_path) + .arg("--contracts-config-path") + .arg(contracts_path) + .args(additional_args) + .env_remove("RUSTUP_TOOLCHAIN"); + + Cmd::new(cmd) +} + +#[allow(clippy::too_many_arguments)] +fn docker_run

( + shell: &Shell, + genesis_path: P, + wallets_path: P, + general_path: P, + secrets_path: P, + contracts_path: P, + additional_args: Vec, + tag: String, + ports: Vec, +) -> Cmd<'_> +where + P: AsRef, +{ + let genesis_path = genesis_path.as_ref().to_string_lossy(); + let wallets_path = wallets_path.as_ref().to_string_lossy(); + let general_path = general_path.as_ref().to_string_lossy(); + let secrets_path = secrets_path.as_ref().to_string_lossy(); + let contracts_path = contracts_path.as_ref().to_string_lossy(); + + // do not expose postgres and reth ports + let ports = ports + .into_iter() + .filter(|p| *p != 5432 && *p != 8545) + .collect::>(); + + let mut cmd = cmd!(shell, "docker run") + .arg("--platform") + .arg("linux/amd64") + .arg("-v") + .arg(format!("{genesis_path}:/config/genesis.yaml")) + .arg("-v") + .arg(format!("{wallets_path}:/config/wallets.yaml")) + .arg("-v") + .arg(format!("{general_path}:/config/general.yaml")) + .arg("-v") + .arg(format!("{secrets_path}:/config/secrets.yaml")) + .arg("-v") + .arg(format!("{contracts_path}:/config/contracts.yaml")); + + for p in ports { + cmd = cmd.arg("-p").arg(format!("{p}:{p}")); + } + + cmd = cmd + .arg(format!("matterlabs/server-v2:{tag}")) + .arg("--genesis-path") + .arg("/config/genesis.yaml") + .arg("--wallets-path") + .arg("/config/wallets.yaml") + .arg("--config-path") + .arg("/config/general.yaml") + .arg("--secrets-path") + .arg("/config/secrets.yaml") + .arg("--contracts-config-path") + .arg("/config/contracts.yaml") + .args(additional_args); + + Cmd::new(cmd) +} diff --git a/zkstack_cli/crates/zkstack/Cargo.toml b/zkstack_cli/crates/zkstack/Cargo.toml index 85ab8081eaa4..c3dc80c073ae 100644 --- a/zkstack_cli/crates/zkstack/Cargo.toml +++ b/zkstack_cli/crates/zkstack/Cargo.toml @@ -44,7 +44,7 @@ zksync_consensus_crypto.workspace = true zksync_protobuf.workspace = true zksync_protobuf_config.workspace = true prost.workspace = true -reqwest = "0.12.8" +reqwest.workspace = true [dev-dependencies] rand.workspace = true diff --git a/zkstack_cli/crates/zkstack/completion/_zkstack.zsh b/zkstack_cli/crates/zkstack/completion/_zkstack.zsh index fc6f29851e66..4e10f23883b7 100644 --- a/zkstack_cli/crates/zkstack/completion/_zkstack.zsh +++ b/zkstack_cli/crates/zkstack/completion/_zkstack.zsh @@ -126,6 +126,8 @@ _arguments "${_arguments_options[@]}" : \ '*-a+[List of additional arguments that can be passed through the CLI]:ADDITIONAL_ARGS:_default' \ '*--additional-args=[List of additional arguments that can be passed through the CLI]:ADDITIONAL_ARGS:_default' \ '--deploy-paymaster=[Deploy Paymaster contract]' \ +'--mode=[]:MODE:(release debug docker)' \ +'--tag=[Select a specific Docker image tag]:TAG:_default' \ '--server-db-url=[Server database url without database name]:SERVER_DB_URL:_default' \ '--server-db-name=[Server database name]:SERVER_DB_NAME:_default' \ '-o+[Enable Grafana]' \ @@ -280,6 +282,8 @@ _arguments "${_arguments_options[@]}" : \ '--verifier-api-key=[Verifier API key]:VERIFIER_API_KEY:_default' \ '*-a+[List of additional arguments that can be passed through the CLI]:ADDITIONAL_ARGS:_default' \ '*--additional-args=[List of additional arguments that can be passed through the CLI]:ADDITIONAL_ARGS:_default' \ +'--mode=[]:MODE:(release debug docker)' \ +'--tag=[Select a specific Docker image tag]:TAG:_default' \ '--server-db-url=[Server database url without database name]:SERVER_DB_URL:_default' \ '--server-db-name=[Server database name]:SERVER_DB_NAME:_default' \ '--deploy-paymaster=[]' \ @@ -307,6 +311,8 @@ _arguments "${_arguments_options[@]}" : \ case $line[1] in (configs) _arguments "${_arguments_options[@]}" : \ +'--mode=[]:MODE:(release debug docker)' \ +'--tag=[Select a specific Docker image tag]:TAG:_default' \ '--server-db-url=[Server database url without database name]:SERVER_DB_URL:_default' \ '--server-db-name=[Server database name]:SERVER_DB_NAME:_default' \ '--l1-rpc-url=[L1 RPC URL]:L1_RPC_URL:_default' \ @@ -353,6 +359,8 @@ esac ;; (genesis) _arguments "${_arguments_options[@]}" : \ +'--mode=[]:MODE:(release debug docker)' \ +'--tag=[Select a specific Docker image tag]:TAG:_default' \ '--server-db-url=[Server database url without database name]:SERVER_DB_URL:_default' \ '--server-db-name=[Server database name]:SERVER_DB_NAME:_default' \ '--chain=[Chain to use]:CHAIN:_default' \ @@ -377,6 +385,8 @@ _arguments "${_arguments_options[@]}" : \ case $line[1] in (init-database) _arguments "${_arguments_options[@]}" : \ +'--mode=[]:MODE:(release debug docker)' \ +'--tag=[Select a specific Docker image tag]:TAG:_default' \ '--server-db-url=[Server database url without database name]:SERVER_DB_URL:_default' \ '--server-db-name=[Server database name]:SERVER_DB_NAME:_default' \ '--chain=[Chain to use]:CHAIN:_default' \ @@ -393,6 +403,8 @@ _arguments "${_arguments_options[@]}" : \ ;; (server) _arguments "${_arguments_options[@]}" : \ +'--mode=[]:MODE:(release debug docker)' \ +'--tag=[Select a specific Docker image tag]:TAG:_default' \ '--chain=[Chain to use]:CHAIN:_default' \ '-v[Verbose mode]' \ '--verbose[Verbose mode]' \ @@ -1928,7 +1940,7 @@ _arguments "${_arguments_options[@]}" : \ '-m+[]:MAX_ALLOCATION:_default' \ '--max-allocation=[]:MAX_ALLOCATION:_default' \ '--docker=[]:DOCKER:(true false)' \ -'--tag=[]:TAG:_default' \ +'--tag=[Select a specific Docker image tag]:TAG:_default' \ '--chain=[Chain to use]:CHAIN:_default' \ '-v[Verbose mode]' \ '--verbose[Verbose mode]' \ @@ -2006,6 +2018,8 @@ esac ;; (server) _arguments "${_arguments_options[@]}" : \ +'--mode=[]:MODE:(release debug docker)' \ +'--tag=[Select a specific Docker image tag]:TAG:_default' \ '*--components=[Components of server to run]:COMPONENTS:_default' \ '*-a+[Additional arguments that can be passed through the CLI]:ADDITIONAL_ARGS:_default' \ '*--additional-args=[Additional arguments that can be passed through the CLI]:ADDITIONAL_ARGS:_default' \ @@ -2039,6 +2053,8 @@ _arguments "${_arguments_options[@]}" : \ ;; (run) _arguments "${_arguments_options[@]}" : \ +'--mode=[]:MODE:(release debug docker)' \ +'--tag=[Select a specific Docker image tag]:TAG:_default' \ '*--components=[Components of server to run]:COMPONENTS:_default' \ '*-a+[Additional arguments that can be passed through the CLI]:ADDITIONAL_ARGS:_default' \ '*--additional-args=[Additional arguments that can be passed through the CLI]:ADDITIONAL_ARGS:_default' \ diff --git a/zkstack_cli/crates/zkstack/completion/zkstack.fish b/zkstack_cli/crates/zkstack/completion/zkstack.fish index 8a5b338fcda2..b5a086fad7aa 100644 --- a/zkstack_cli/crates/zkstack/completion/zkstack.fish +++ b/zkstack_cli/crates/zkstack/completion/zkstack.fish @@ -103,6 +103,8 @@ complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_se complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from init" -l verifier-api-key -d 'Verifier API key' -r complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from init" -s a -l additional-args -d 'List of additional arguments that can be passed through the CLI' -r complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from init" -l deploy-paymaster -d 'Deploy Paymaster contract' -r -f -a "{true\t'',false\t''}" +complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from init" -l mode -r -f -a "{release\t'',debug\t'',docker\t''}" +complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from init" -l tag -d 'Select a specific Docker image tag' -r complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from init" -l server-db-url -d 'Server database url without database name' -r complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from init" -l server-db-name -d 'Server database name' -r complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from init" -s o -l observability -d 'Enable Grafana' -r -f -a "{true\t'',false\t''}" @@ -181,6 +183,8 @@ complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_s complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -l verifier-url -d 'Verifier URL, if using a custom provider' -r complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -l verifier-api-key -d 'Verifier API key' -r complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -s a -l additional-args -d 'List of additional arguments that can be passed through the CLI' -r +complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -l mode -r -f -a "{release\t'',debug\t'',docker\t''}" +complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -l tag -d 'Select a specific Docker image tag' -r complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -l server-db-url -d 'Server database url without database name' -r complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -l server-db-name -d 'Server database name' -r complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -l deploy-paymaster -r -f -a "{true\t'',false\t''}" @@ -195,6 +199,8 @@ complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_s complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -s h -l help -d 'Print help (see more with \'--help\')' complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -f -a "configs" -d 'Initialize chain configs' complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from genesis" -l mode -r -f -a "{release\t'',debug\t'',docker\t''}" +complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from genesis" -l tag -d 'Select a specific Docker image tag' -r complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from genesis" -l server-db-url -d 'Server database url without database name' -r complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from genesis" -l server-db-name -d 'Server database name' -r complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from genesis" -l chain -d 'Chain to use' -r @@ -503,7 +509,7 @@ complete -c zkstack -n "__fish_zkstack_using_subcommand prover; and __fish_seen_ complete -c zkstack -n "__fish_zkstack_using_subcommand prover; and __fish_seen_subcommand_from run" -s h -l heavy-wvg-count -r complete -c zkstack -n "__fish_zkstack_using_subcommand prover; and __fish_seen_subcommand_from run" -s m -l max-allocation -r complete -c zkstack -n "__fish_zkstack_using_subcommand prover; and __fish_seen_subcommand_from run" -l docker -r -f -a "{true\t'',false\t''}" -complete -c zkstack -n "__fish_zkstack_using_subcommand prover; and __fish_seen_subcommand_from run" -l tag -r +complete -c zkstack -n "__fish_zkstack_using_subcommand prover; and __fish_seen_subcommand_from run" -l tag -d 'Select a specific Docker image tag' -r complete -c zkstack -n "__fish_zkstack_using_subcommand prover; and __fish_seen_subcommand_from run" -l chain -d 'Chain to use' -r complete -c zkstack -n "__fish_zkstack_using_subcommand prover; and __fish_seen_subcommand_from run" -s v -l verbose -d 'Verbose mode' complete -c zkstack -n "__fish_zkstack_using_subcommand prover; and __fish_seen_subcommand_from run" -l ignore-prerequisites -d 'Ignores prerequisites checks' @@ -525,6 +531,8 @@ complete -c zkstack -n "__fish_zkstack_using_subcommand prover; and __fish_seen_ complete -c zkstack -n "__fish_zkstack_using_subcommand prover; and __fish_seen_subcommand_from help" -f -a "init-bellman-cuda" -d 'Initialize bellman-cuda' complete -c zkstack -n "__fish_zkstack_using_subcommand prover; and __fish_seen_subcommand_from help" -f -a "compressor-keys" -d 'Download compressor keys' complete -c zkstack -n "__fish_zkstack_using_subcommand prover; and __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c zkstack -n "__fish_zkstack_using_subcommand server; and not __fish_seen_subcommand_from build run wait help" -l mode -r -f -a "{release\t'',debug\t'',docker\t''}" +complete -c zkstack -n "__fish_zkstack_using_subcommand server; and not __fish_seen_subcommand_from build run wait help" -l tag -d 'Select a specific Docker image tag' -r complete -c zkstack -n "__fish_zkstack_using_subcommand server; and not __fish_seen_subcommand_from build run wait help" -l components -d 'Components of server to run' -r complete -c zkstack -n "__fish_zkstack_using_subcommand server; and not __fish_seen_subcommand_from build run wait help" -s a -l additional-args -d 'Additional arguments that can be passed through the CLI' -r complete -c zkstack -n "__fish_zkstack_using_subcommand server; and not __fish_seen_subcommand_from build run wait help" -l chain -d 'Chain to use' -r @@ -541,6 +549,8 @@ complete -c zkstack -n "__fish_zkstack_using_subcommand server; and __fish_seen_ complete -c zkstack -n "__fish_zkstack_using_subcommand server; and __fish_seen_subcommand_from build" -s v -l verbose -d 'Verbose mode' complete -c zkstack -n "__fish_zkstack_using_subcommand server; and __fish_seen_subcommand_from build" -l ignore-prerequisites -d 'Ignores prerequisites checks' complete -c zkstack -n "__fish_zkstack_using_subcommand server; and __fish_seen_subcommand_from build" -s h -l help -d 'Print help' +complete -c zkstack -n "__fish_zkstack_using_subcommand server; and __fish_seen_subcommand_from run" -l mode -r -f -a "{release\t'',debug\t'',docker\t''}" +complete -c zkstack -n "__fish_zkstack_using_subcommand server; and __fish_seen_subcommand_from run" -l tag -d 'Select a specific Docker image tag' -r complete -c zkstack -n "__fish_zkstack_using_subcommand server; and __fish_seen_subcommand_from run" -l components -d 'Components of server to run' -r complete -c zkstack -n "__fish_zkstack_using_subcommand server; and __fish_seen_subcommand_from run" -s a -l additional-args -d 'Additional arguments that can be passed through the CLI' -r complete -c zkstack -n "__fish_zkstack_using_subcommand server; and __fish_seen_subcommand_from run" -l chain -d 'Chain to use' -r diff --git a/zkstack_cli/crates/zkstack/completion/zkstack.sh b/zkstack_cli/crates/zkstack/completion/zkstack.sh index bb373c3f63eb..7eb3cdaa2c3d 100644 --- a/zkstack_cli/crates/zkstack/completion/zkstack.sh +++ b/zkstack_cli/crates/zkstack/completion/zkstack.sh @@ -1574,12 +1574,20 @@ _zkstack() { return 0 ;; zkstack__chain__genesis) - opts="-d -d -v -h --server-db-url --server-db-name --dev --dont-drop --verbose --chain --ignore-prerequisites --help init-database server help" + opts="-d -d -v -h --mode --tag --server-db-url --server-db-name --dev --dont-drop --verbose --chain --ignore-prerequisites --help init-database server help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in + --mode) + COMPREPLY=($(compgen -W "release debug docker" -- "${cur}")) + return 0 + ;; + --tag) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --server-db-url) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1656,12 +1664,20 @@ _zkstack() { return 0 ;; zkstack__chain__genesis__init__database) - opts="-d -d -v -h --server-db-url --server-db-name --dev --dont-drop --verbose --chain --ignore-prerequisites --help" + opts="-d -d -v -h --mode --tag --server-db-url --server-db-name --dev --dont-drop --verbose --chain --ignore-prerequisites --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in + --mode) + COMPREPLY=($(compgen -W "release debug docker" -- "${cur}")) + return 0 + ;; + --tag) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --server-db-url) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1682,12 +1698,20 @@ _zkstack() { return 0 ;; zkstack__chain__genesis__server) - opts="-v -h --verbose --chain --ignore-prerequisites --help" + opts="-v -h --mode --tag --verbose --chain --ignore-prerequisites --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in + --mode) + COMPREPLY=($(compgen -W "release debug docker" -- "${cur}")) + return 0 + ;; + --tag) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --chain) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -1966,7 +1990,7 @@ _zkstack() { return 0 ;; zkstack__chain__init) - opts="-a -d -v -h --verify --verifier --verifier-url --verifier-api-key --resume --additional-args --server-db-url --server-db-name --dont-drop --deploy-paymaster --l1-rpc-url --no-port-reallocation --dev --verbose --chain --ignore-prerequisites --help configs help" + opts="-a -d -v -h --verify --verifier --verifier-url --verifier-api-key --resume --additional-args --mode --tag --server-db-url --server-db-name --dont-drop --deploy-paymaster --l1-rpc-url --no-port-reallocation --dev --verbose --chain --ignore-prerequisites --help configs help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1996,6 +2020,14 @@ _zkstack() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --mode) + COMPREPLY=($(compgen -W "release debug docker" -- "${cur}")) + return 0 + ;; + --tag) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --server-db-url) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -2024,12 +2056,20 @@ _zkstack() { return 0 ;; zkstack__chain__init__configs) - opts="-d -d -v -h --server-db-url --server-db-name --dev --dont-drop --l1-rpc-url --no-port-reallocation --verbose --chain --ignore-prerequisites --help" + opts="-d -d -v -h --mode --tag --server-db-url --server-db-name --dev --dont-drop --l1-rpc-url --no-port-reallocation --verbose --chain --ignore-prerequisites --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in + --mode) + COMPREPLY=($(compgen -W "release debug docker" -- "${cur}")) + return 0 + ;; + --tag) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --server-db-url) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -5096,7 +5136,7 @@ _zkstack() { return 0 ;; zkstack__ecosystem__init) - opts="-a -d -o -v -h --deploy-erc20 --deploy-ecosystem --ecosystem-contracts-path --l1-rpc-url --verify --verifier --verifier-url --verifier-api-key --resume --additional-args --deploy-paymaster --server-db-url --server-db-name --dont-drop --ecosystem-only --dev --observability --no-port-reallocation --verbose --chain --ignore-prerequisites --help" + opts="-a -d -o -v -h --deploy-erc20 --deploy-ecosystem --ecosystem-contracts-path --l1-rpc-url --verify --verifier --verifier-url --verifier-api-key --resume --additional-args --deploy-paymaster --mode --tag --server-db-url --server-db-name --dont-drop --ecosystem-only --dev --observability --no-port-reallocation --verbose --chain --ignore-prerequisites --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -5146,6 +5186,14 @@ _zkstack() { COMPREPLY=($(compgen -W "true false" -- "${cur}")) return 0 ;; + --mode) + COMPREPLY=($(compgen -W "release debug docker" -- "${cur}")) + return 0 + ;; + --tag) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --server-db-url) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -7426,12 +7474,20 @@ _zkstack() { return 0 ;; zkstack__server) - opts="-a -v -h --components --genesis --additional-args --uring --verbose --chain --ignore-prerequisites --help build run wait help" + opts="-a -v -h --mode --tag --components --genesis --additional-args --uring --verbose --chain --ignore-prerequisites --help build run wait help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in + --mode) + COMPREPLY=($(compgen -W "release debug docker" -- "${cur}")) + return 0 + ;; + --tag) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --components) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -7544,12 +7600,20 @@ _zkstack() { return 0 ;; zkstack__server__run) - opts="-a -v -h --components --genesis --additional-args --uring --verbose --chain --ignore-prerequisites --help" + opts="-a -v -h --mode --tag --components --genesis --additional-args --uring --verbose --chain --ignore-prerequisites --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in + --mode) + COMPREPLY=($(compgen -W "release debug docker" -- "${cur}")) + return 0 + ;; + --tag) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --components) COMPREPLY=($(compgen -f "${cur}")) return 0 diff --git a/zkstack_cli/crates/zkstack/src/commands/args/mod.rs b/zkstack_cli/crates/zkstack/src/commands/args/mod.rs index 477f3a6ae9af..0f82984ddff3 100644 --- a/zkstack_cli/crates/zkstack/src/commands/args/mod.rs +++ b/zkstack_cli/crates/zkstack/src/commands/args/mod.rs @@ -1,7 +1,7 @@ -pub use self::{autocomplete::*, containers::*, run_server::*, update::*, wait::*}; +pub use self::{autocomplete::*, containers::*, server::*, update::*, wait::*}; mod autocomplete; mod containers; -mod run_server; +mod server; mod update; mod wait; diff --git a/zkstack_cli/crates/zkstack/src/commands/args/run_server.rs b/zkstack_cli/crates/zkstack/src/commands/args/run_server.rs deleted file mode 100644 index 40344c90ad05..000000000000 --- a/zkstack_cli/crates/zkstack/src/commands/args/run_server.rs +++ /dev/null @@ -1,53 +0,0 @@ -use clap::{Parser, Subcommand}; -use serde::{Deserialize, Serialize}; - -use crate::{ - commands::args::WaitArgs, - messages::{ - MSG_SERVER_ADDITIONAL_ARGS_HELP, MSG_SERVER_COMPONENTS_HELP, MSG_SERVER_GENESIS_HELP, - MSG_SERVER_URING_HELP, - }, -}; - -#[derive(Debug, Parser)] -#[command(args_conflicts_with_subcommands = true, flatten_help = true)] -pub struct ServerArgs { - #[command(subcommand)] - command: Option, - #[command(flatten)] - run: RunServerArgs, -} - -#[derive(Debug, Subcommand)] -pub enum ServerCommand { - /// Builds server - Build, - /// Runs server - Run(RunServerArgs), - /// Waits for server to start - Wait(WaitArgs), -} - -impl From for ServerCommand { - fn from(args: ServerArgs) -> Self { - args.command.unwrap_or(ServerCommand::Run(args.run)) - } -} - -#[derive(Debug, Serialize, Deserialize, Parser)] -pub struct RunServerArgs { - #[arg(long, help = MSG_SERVER_COMPONENTS_HELP)] - pub components: Option>, - #[arg(long, help = MSG_SERVER_GENESIS_HELP)] - pub genesis: bool, - #[arg( - long, short, - trailing_var_arg = true, - allow_hyphen_values = true, - hide = false, - help = MSG_SERVER_ADDITIONAL_ARGS_HELP - )] - additional_args: Vec, - #[clap(help = MSG_SERVER_URING_HELP, long, default_missing_value = "true")] - pub uring: bool, -} diff --git a/zkstack_cli/crates/zkstack/src/commands/args/server/mod.rs b/zkstack_cli/crates/zkstack/src/commands/args/server/mod.rs new file mode 100644 index 000000000000..34e2ad5ec0c3 --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/commands/args/server/mod.rs @@ -0,0 +1,31 @@ +use clap::{Parser, Subcommand}; +use run::RunServerArgs; + +use crate::commands::args::WaitArgs; + +pub mod run; + +#[derive(Debug, Parser)] +#[command(args_conflicts_with_subcommands = true, flatten_help = true)] +pub struct ServerArgs { + #[command(subcommand)] + command: Option, + #[command(flatten)] + run: RunServerArgs, +} + +#[derive(Debug, Subcommand)] +pub enum ServerCommand { + /// Builds server + Build, + /// Runs server + Run(RunServerArgs), + /// Waits for server to start + Wait(WaitArgs), +} + +impl From for ServerCommand { + fn from(args: ServerArgs) -> Self { + args.command.unwrap_or(ServerCommand::Run(args.run)) + } +} diff --git a/zkstack_cli/crates/zkstack/src/commands/args/server/run.rs b/zkstack_cli/crates/zkstack/src/commands/args/server/run.rs new file mode 100644 index 000000000000..1c56bf9a73e1 --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/commands/args/server/run.rs @@ -0,0 +1,79 @@ +use clap::{Parser, ValueEnum}; +use common::server::ExecutionMode; +use serde::{Deserialize, Serialize}; + +use crate::{ + messages::{ + MSG_DOCKER_IMAGE_TAG_OPTION, MSG_SERVER_ADDITIONAL_ARGS_HELP, MSG_SERVER_COMPONENTS_HELP, + MSG_SERVER_GENESIS_HELP, MSG_SERVER_URING_HELP, + }, + utils::docker::select_tag, +}; + +#[derive(Clone, Debug, Default, Serialize, Deserialize, ValueEnum)] +pub enum Mode { + #[default] + Release, + Debug, + Docker, +} + +impl Mode { + pub fn as_execution_mode(&self, tag: Option) -> ExecutionMode { + match self { + Mode::Debug => ExecutionMode::Debug, + Mode::Release => ExecutionMode::Release, + Mode::Docker => ExecutionMode::Docker { + tag: tag.unwrap_or("latest".to_string()), + }, + } + } +} + +#[derive(Debug, Serialize, Deserialize, Parser)] +pub struct RunServerArgs { + #[arg(long, default_value = "release")] + pub mode: Mode, + #[arg(long, help = MSG_DOCKER_IMAGE_TAG_OPTION)] + pub tag: Option, + #[arg(long, help = MSG_SERVER_COMPONENTS_HELP)] + pub components: Option>, + #[arg(long, help = MSG_SERVER_GENESIS_HELP)] + pub genesis: bool, + #[arg( + long, short, + trailing_var_arg = true, + allow_hyphen_values = true, + hide = false, + help = MSG_SERVER_ADDITIONAL_ARGS_HELP + )] + additional_args: Vec, + #[clap(help = MSG_SERVER_URING_HELP, long, default_missing_value = "true")] + pub uring: bool, +} + +impl RunServerArgs { + pub async fn fill_values_with_prompt(self) -> RunServerArgsFinal { + let tag = if let Mode::Docker = self.mode { + self.tag + .or(select_tag().await.ok().or(Some("latest".to_string()))) + } else { + None + }; + + RunServerArgsFinal { + mode: self.mode.as_execution_mode(tag), + components: self.components, + genesis: self.genesis, + uring: self.uring, + } + } +} + +#[derive(Debug)] +pub struct RunServerArgsFinal { + pub mode: ExecutionMode, + pub components: Option>, + pub genesis: bool, + pub uring: bool, +} diff --git a/zkstack_cli/crates/zkstack/src/commands/args/wait.rs b/zkstack_cli/crates/zkstack/src/commands/args/wait.rs index a3a7e32ae8b4..8784d36f5782 100644 --- a/zkstack_cli/crates/zkstack/src/commands/args/wait.rs +++ b/zkstack_cli/crates/zkstack/src/commands/args/wait.rs @@ -1,6 +1,6 @@ use std::{fmt, future::Future, time::Duration}; -use anyhow::Context as _; +use anyhow::Context; use clap::Parser; use common::logger; use reqwest::StatusCode; diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/args/genesis.rs b/zkstack_cli/crates/zkstack/src/commands/chain/args/genesis/mod.rs similarity index 74% rename from zkstack_cli/crates/zkstack/src/commands/chain/args/genesis.rs rename to zkstack_cli/crates/zkstack/src/commands/chain/args/genesis/mod.rs index f990cbfd77da..98dd2540faee 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/args/genesis.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/args/genesis/mod.rs @@ -1,21 +1,29 @@ use anyhow::Context; use clap::Parser; -use common::{db::DatabaseConfig, Prompt}; +use common::{db::DatabaseConfig, server::ExecutionMode, Prompt}; use config::ChainConfig; use serde::{Deserialize, Serialize}; use slugify_rs::slugify; use url::Url; use crate::{ + commands::args::run::Mode, defaults::{generate_db_names, DBNames, DATABASE_SERVER_URL}, messages::{ - msg_server_db_name_prompt, msg_server_db_url_prompt, MSG_SERVER_DB_NAME_HELP, - MSG_SERVER_DB_URL_HELP, MSG_USE_DEFAULT_DATABASES_HELP, + msg_server_db_name_prompt, msg_server_db_url_prompt, MSG_DOCKER_IMAGE_TAG_OPTION, + MSG_SERVER_DB_NAME_HELP, MSG_SERVER_DB_URL_HELP, MSG_USE_DEFAULT_DATABASES_HELP, }, + utils::docker::select_tag, }; +pub mod server; + #[derive(Debug, Clone, Serialize, Deserialize, Parser, Default)] pub struct GenesisArgs { + #[arg(long, default_value = "release")] + pub mode: Mode, + #[arg(long, help = MSG_DOCKER_IMAGE_TAG_OPTION)] + pub tag: Option, #[clap(long, help = MSG_SERVER_DB_URL_HELP)] pub server_db_url: Option, #[clap(long, help = MSG_SERVER_DB_NAME_HELP)] @@ -27,13 +35,21 @@ pub struct GenesisArgs { } impl GenesisArgs { - pub fn fill_values_with_prompt(self, config: &ChainConfig) -> GenesisArgsFinal { + pub async fn fill_values_with_prompt(self, config: &ChainConfig) -> GenesisArgsFinal { + let tag = if let Mode::Docker = self.mode { + self.tag + .or(select_tag().await.ok().or(Some("latest".to_string()))) + } else { + None + }; + let DBNames { server_name, .. } = generate_db_names(config); let chain_name = config.name.clone(); if self.dev { GenesisArgsFinal { server_db: DatabaseConfig::new(DATABASE_SERVER_URL.clone(), server_name), dont_drop: self.dont_drop, + mode: self.mode.as_execution_mode(tag), } } else { let server_db_url = self.server_db_url.unwrap_or_else(|| { @@ -49,14 +65,16 @@ impl GenesisArgs { }), separator = "_" ); + GenesisArgsFinal { server_db: DatabaseConfig::new(server_db_url, server_db_name), dont_drop: self.dont_drop, + mode: self.mode.as_execution_mode(tag), } } } - pub fn fill_values_with_secrets( + pub async fn fill_values_with_secrets( mut self, chain_config: &ChainConfig, ) -> anyhow::Result { @@ -76,7 +94,7 @@ impl GenesisArgs { self.server_db_url = self.server_db_url.or(server_db_url); self.server_db_name = self.server_db_name.or(server_db_name); - Ok(self.fill_values_with_prompt(chain_config)) + Ok(self.fill_values_with_prompt(chain_config).await) } pub fn reset_db_names(&mut self) { @@ -85,8 +103,9 @@ impl GenesisArgs { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone)] pub struct GenesisArgsFinal { pub server_db: DatabaseConfig, pub dont_drop: bool, + pub mode: ExecutionMode, } diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/args/genesis/server.rs b/zkstack_cli/crates/zkstack/src/commands/chain/args/genesis/server.rs new file mode 100644 index 000000000000..85ddb9eec234 --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/commands/chain/args/genesis/server.rs @@ -0,0 +1,34 @@ +use clap::Parser; +use common::server::ExecutionMode; +use serde::{Deserialize, Serialize}; + +use super::MSG_DOCKER_IMAGE_TAG_OPTION; +use crate::{commands::args::run::Mode, utils::docker::select_tag}; + +#[derive(Clone, Debug, Serialize, Deserialize, Parser)] +pub struct GenesisServerArgs { + #[arg(long, default_value = "release")] + pub mode: Mode, + #[arg(long, help = MSG_DOCKER_IMAGE_TAG_OPTION)] + pub tag: Option, +} + +impl GenesisServerArgs { + pub async fn fill_values_with_prompt(self) -> GenesisServerArgsFinal { + let tag = if let Mode::Docker = self.mode { + self.tag + .or(select_tag().await.ok().or(Some("latest".to_string()))) + } else { + None + }; + + GenesisServerArgsFinal { + mode: self.mode.as_execution_mode(tag), + } + } +} + +#[derive(Debug)] +pub struct GenesisServerArgsFinal { + pub mode: ExecutionMode, +} diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/args/init/configs.rs b/zkstack_cli/crates/zkstack/src/commands/chain/args/init/configs.rs index b34809643cf5..566d327b0c18 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/args/init/configs.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/args/init/configs.rs @@ -28,7 +28,7 @@ pub struct InitConfigsArgs { pub no_port_reallocation: bool, } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Clone)] pub struct InitConfigsArgsFinal { pub genesis_args: GenesisArgsFinal, pub l1_rpc_url: String, @@ -36,7 +36,7 @@ pub struct InitConfigsArgsFinal { } impl InitConfigsArgs { - pub fn fill_values_with_prompt(self, config: &ChainConfig) -> InitConfigsArgsFinal { + pub async fn fill_values_with_prompt(self, config: &ChainConfig) -> InitConfigsArgsFinal { let l1_rpc_url = self.l1_rpc_url.unwrap_or_else(|| { let mut prompt = Prompt::new(MSG_L1_RPC_URL_PROMPT); if config.l1_network == L1Network::Localhost { @@ -52,7 +52,7 @@ impl InitConfigsArgs { }); InitConfigsArgsFinal { - genesis_args: self.genesis_args.fill_values_with_prompt(config), + genesis_args: self.genesis_args.fill_values_with_prompt(config).await, l1_rpc_url, no_port_reallocation: self.no_port_reallocation, } diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/args/init/mod.rs b/zkstack_cli/crates/zkstack/src/commands/chain/args/init/mod.rs index a5c7a6890ca1..1d4c08de9435 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/args/init/mod.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/args/init/mod.rs @@ -6,12 +6,15 @@ use types::L1Network; use url::Url; use crate::{ - commands::chain::args::genesis::{GenesisArgs, GenesisArgsFinal}, + commands::{ + args::run::Mode, + chain::args::genesis::{GenesisArgs, GenesisArgsFinal}, + }, defaults::LOCAL_RPC_URL, messages::{ - MSG_DEPLOY_PAYMASTER_PROMPT, MSG_DEV_ARG_HELP, MSG_L1_RPC_URL_HELP, - MSG_L1_RPC_URL_INVALID_ERR, MSG_L1_RPC_URL_PROMPT, MSG_NO_PORT_REALLOCATION_HELP, - MSG_SERVER_DB_NAME_HELP, MSG_SERVER_DB_URL_HELP, + MSG_DEPLOY_PAYMASTER_PROMPT, MSG_DEV_ARG_HELP, MSG_DOCKER_IMAGE_TAG_OPTION, + MSG_L1_RPC_URL_HELP, MSG_L1_RPC_URL_INVALID_ERR, MSG_L1_RPC_URL_PROMPT, + MSG_NO_PORT_REALLOCATION_HELP, MSG_SERVER_DB_NAME_HELP, MSG_SERVER_DB_URL_HELP, }, }; @@ -23,6 +26,10 @@ pub struct InitArgs { #[clap(flatten)] #[serde(flatten)] pub forge_args: ForgeScriptArgs, + #[arg(long, default_value = "release")] + pub mode: Mode, + #[arg(long, help = MSG_DOCKER_IMAGE_TAG_OPTION)] + pub tag: Option, #[clap(long, help = MSG_SERVER_DB_URL_HELP)] pub server_db_url: Option, #[clap(long, help = MSG_SERVER_DB_NAME_HELP)] @@ -42,6 +49,8 @@ pub struct InitArgs { impl InitArgs { pub fn get_genesis_args(&self) -> GenesisArgs { GenesisArgs { + mode: self.mode.clone(), + tag: self.tag.clone(), server_db_url: self.server_db_url.clone(), server_db_name: self.server_db_name.clone(), dev: self.dev, @@ -49,7 +58,7 @@ impl InitArgs { } } - pub fn fill_values_with_prompt(self, config: &ChainConfig) -> InitArgsFinal { + pub async fn fill_values_with_prompt(self, config: &ChainConfig) -> InitArgsFinal { let genesis = self.get_genesis_args(); let deploy_paymaster = if self.dev { @@ -82,21 +91,19 @@ impl InitArgs { InitArgsFinal { forge_args: self.forge_args, - genesis_args: genesis.fill_values_with_prompt(config), + genesis_args: genesis.fill_values_with_prompt(config).await, deploy_paymaster, l1_rpc_url, no_port_reallocation: self.no_port_reallocation, - dev: self.dev, } } } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Clone)] pub struct InitArgsFinal { pub forge_args: ForgeScriptArgs, pub genesis_args: GenesisArgsFinal, pub deploy_paymaster: bool, pub l1_rpc_url: String, pub no_port_reallocation: bool, - pub dev: bool, } diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/genesis/database.rs b/zkstack_cli/crates/zkstack/src/commands/chain/genesis/database.rs index edf480946be1..df13ab9c18d5 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/genesis/database.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/genesis/database.rs @@ -35,7 +35,7 @@ pub async fn run(args: GenesisArgs, shell: &Shell) -> anyhow::Result<()> { .context(MSG_CHAIN_NOT_INITIALIZED)?; let mut secrets = chain_config.get_secrets_config()?; - let args = args.fill_values_with_secrets(&chain_config)?; + let args = args.fill_values_with_secrets(&chain_config).await?; set_server_database(&mut secrets, &args.server_db)?; secrets.save_with_base_path(shell, &chain_config.configs)?; diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/genesis/mod.rs b/zkstack_cli/crates/zkstack/src/commands/chain/genesis/mod.rs index c1cc03174aeb..991255194aa3 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/genesis/mod.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/genesis/mod.rs @@ -4,6 +4,7 @@ use common::{logger, spinner::Spinner}; use config::{ChainConfig, EcosystemConfig}; use xshell::Shell; +use super::args::genesis::server::GenesisServerArgs; use crate::{ commands::chain::{ args::genesis::{GenesisArgs, GenesisArgsFinal}, @@ -25,7 +26,7 @@ pub enum GenesisSubcommands { #[command(alias = "database")] InitDatabase(Box), /// Runs server genesis - Server, + Server(GenesisServerArgs), } #[derive(Parser, Debug)] @@ -40,7 +41,7 @@ pub struct GenesisCommand { pub(crate) async fn run(args: GenesisCommand, shell: &Shell) -> anyhow::Result<()> { match args.command { Some(GenesisSubcommands::InitDatabase(args)) => database::run(*args, shell).await, - Some(GenesisSubcommands::Server) => server::run(shell).await, + Some(GenesisSubcommands::Server(args)) => server::run(args, shell).await, None => run_genesis(args.args, shell).await, } } @@ -50,7 +51,7 @@ pub async fn run_genesis(args: GenesisArgs, shell: &Shell) -> anyhow::Result<()> let chain_config = ecosystem_config .load_current_chain() .context(MSG_CHAIN_NOT_INITIALIZED)?; - let args = args.fill_values_with_prompt(&chain_config); + let args = args.fill_values_with_prompt(&chain_config).await; genesis(args, shell, &chain_config).await?; logger::outro(MSG_GENESIS_COMPLETED); @@ -85,7 +86,7 @@ pub async fn genesis( spinner.finish(); let spinner = Spinner::new(MSG_STARTING_GENESIS_SPINNER); - run_server_genesis(config, shell)?; + run_server_genesis(config, shell, args.mode).await?; spinner.finish(); Ok(()) diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/genesis/server.rs b/zkstack_cli/crates/zkstack/src/commands/chain/genesis/server.rs index 50a74b7ea9e4..837d99296370 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/genesis/server.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/genesis/server.rs @@ -1,7 +1,7 @@ use anyhow::Context; use common::{ logger, - server::{Server, ServerMode}, + server::{ExecutionMode, Server, ServerMode}, spinner::Spinner, }; use config::{ @@ -10,30 +10,45 @@ use config::{ }; use xshell::Shell; -use crate::messages::{ - MSG_CHAIN_NOT_INITIALIZED, MSG_FAILED_TO_RUN_SERVER_ERR, MSG_GENESIS_COMPLETED, - MSG_STARTING_GENESIS_SPINNER, +use crate::{ + commands::chain::args::genesis::server::GenesisServerArgs, + messages::{ + MSG_CHAIN_NOT_INITIALIZED, MSG_FAILED_TO_RUN_SERVER_ERR, MSG_GENESIS_COMPLETED, + MSG_STARTING_GENESIS_SPINNER, + }, + utils::{docker::adjust_host_to_execution_mode, ports::EcosystemPortsScanner}, }; -pub async fn run(shell: &Shell) -> anyhow::Result<()> { +pub async fn run(args: GenesisServerArgs, shell: &Shell) -> anyhow::Result<()> { + let args = args.fill_values_with_prompt().await; + let ecosystem_config = EcosystemConfig::from_file(shell)?; let chain_config = ecosystem_config .load_current_chain() .context(MSG_CHAIN_NOT_INITIALIZED)?; let spinner = Spinner::new(MSG_STARTING_GENESIS_SPINNER); - run_server_genesis(&chain_config, shell)?; + run_server_genesis(&chain_config, shell, args.mode).await?; spinner.finish(); logger::outro(MSG_GENESIS_COMPLETED); Ok(()) } -pub fn run_server_genesis(chain_config: &ChainConfig, shell: &Shell) -> anyhow::Result<()> { +pub async fn run_server_genesis( + chain_config: &ChainConfig, + shell: &Shell, + execution_mode: ExecutionMode, +) -> anyhow::Result<()> { + let ports = EcosystemPortsScanner::scan(shell)?; let server = Server::new(None, chain_config.link_to_code.clone(), false); + + adjust_host_to_execution_mode(shell, &execution_mode, chain_config)?; + server .run( shell, + execution_mode, ServerMode::Genesis, GenesisConfig::get_path_with_base_path(&chain_config.configs), WalletsConfig::get_path_with_base_path(&chain_config.configs), @@ -41,6 +56,8 @@ pub fn run_server_genesis(chain_config: &ChainConfig, shell: &Shell) -> anyhow:: SecretsConfig::get_path_with_base_path(&chain_config.configs), ContractsConfig::get_path_with_base_path(&chain_config.configs), vec![], + ports.ports.keys().map(|p| p.to_owned()).collect(), ) + .await .context(MSG_FAILED_TO_RUN_SERVER_ERR) } diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/init/configs.rs b/zkstack_cli/crates/zkstack/src/commands/chain/init/configs.rs index 31c5c681e7d3..5671b66c5839 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/init/configs.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/init/configs.rs @@ -30,7 +30,7 @@ pub async fn run(args: InitConfigsArgs, shell: &Shell) -> anyhow::Result<()> { let chain_config = ecosystem_config .load_current_chain() .context(MSG_CHAIN_NOT_FOUND_ERR)?; - let args = args.fill_values_with_prompt(&chain_config); + let args = args.fill_values_with_prompt(&chain_config).await; init_configs(&args, shell, &ecosystem_config, &chain_config).await?; logger::outro(MSG_CHAIN_CONFIGS_INITIALIZED); diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/init/mod.rs b/zkstack_cli/crates/zkstack/src/commands/chain/init/mod.rs index d92c56d2eb10..909ed2a0180c 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/init/mod.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/init/mod.rs @@ -58,7 +58,7 @@ async fn run_init(args: InitArgs, shell: &Shell) -> anyhow::Result<()> { let chain_config = config .load_current_chain() .context(MSG_CHAIN_NOT_FOUND_ERR)?; - let args = args.fill_values_with_prompt(&chain_config); + let args = args.fill_values_with_prompt(&chain_config).await; logger::note(MSG_SELECTED_CONFIG, logger::object_to_string(&chain_config)); logger::info(msg_initializing_chain("")); diff --git a/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/init.rs b/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/init.rs index 09115fd49ba7..da54d0fe7646 100644 --- a/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/init.rs +++ b/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/init.rs @@ -7,13 +7,13 @@ use types::L1Network; use url::Url; use crate::{ - commands::chain::args::genesis::GenesisArgs, + commands::{args::run::Mode, chain::args::genesis::GenesisArgs}, defaults::LOCAL_RPC_URL, messages::{ MSG_DEPLOY_ECOSYSTEM_PROMPT, MSG_DEPLOY_ERC20_PROMPT, MSG_DEV_ARG_HELP, - MSG_L1_RPC_URL_HELP, MSG_L1_RPC_URL_INVALID_ERR, MSG_L1_RPC_URL_PROMPT, - MSG_NO_PORT_REALLOCATION_HELP, MSG_OBSERVABILITY_HELP, MSG_OBSERVABILITY_PROMPT, - MSG_SERVER_DB_NAME_HELP, MSG_SERVER_DB_URL_HELP, + MSG_DOCKER_IMAGE_TAG_OPTION, MSG_L1_RPC_URL_HELP, MSG_L1_RPC_URL_INVALID_ERR, + MSG_L1_RPC_URL_PROMPT, MSG_NO_PORT_REALLOCATION_HELP, MSG_OBSERVABILITY_HELP, + MSG_OBSERVABILITY_PROMPT, MSG_SERVER_DB_NAME_HELP, MSG_SERVER_DB_URL_HELP, }, }; @@ -86,6 +86,10 @@ pub struct EcosystemInitArgs { /// Deploy Paymaster contract #[clap(long, default_missing_value = "true", num_args = 0..=1)] pub deploy_paymaster: Option, + #[arg(long, default_value = "release")] + pub mode: Mode, + #[arg(long, help = MSG_DOCKER_IMAGE_TAG_OPTION)] + pub tag: Option, #[clap(long, help = MSG_SERVER_DB_URL_HELP)] pub server_db_url: Option, #[clap(long, help = MSG_SERVER_DB_NAME_HELP)] @@ -106,6 +110,8 @@ pub struct EcosystemInitArgs { impl EcosystemInitArgs { pub fn get_genesis_args(&self) -> GenesisArgs { GenesisArgs { + mode: self.mode.clone(), + tag: self.tag.clone(), server_db_url: self.server_db_url.clone(), server_db_name: self.server_db_name.clone(), dev: self.dev, diff --git a/zkstack_cli/crates/zkstack/src/commands/ecosystem/init.rs b/zkstack_cli/crates/zkstack/src/commands/ecosystem/init.rs index 7b01abf03b9a..d67c15803162 100644 --- a/zkstack_cli/crates/zkstack/src/commands/ecosystem/init.rs +++ b/zkstack_cli/crates/zkstack/src/commands/ecosystem/init.rs @@ -363,6 +363,8 @@ async fn init_chains( let chain_init_args = chain::args::init::InitArgs { forge_args: final_init_args.forge_args.clone(), + mode: genesis_args.mode.clone(), + tag: genesis_args.tag.clone(), server_db_url: genesis_args.server_db_url.clone(), server_db_name: genesis_args.server_db_name.clone(), dont_drop: genesis_args.dont_drop, @@ -371,7 +373,7 @@ async fn init_chains( no_port_reallocation: final_init_args.no_port_reallocation, dev: final_init_args.dev, }; - let final_chain_init_args = chain_init_args.fill_values_with_prompt(&chain_config); + let final_chain_init_args = chain_init_args.fill_values_with_prompt(&chain_config).await; chain::init::init( &final_chain_init_args, diff --git a/zkstack_cli/crates/zkstack/src/commands/prover/args/run.rs b/zkstack_cli/crates/zkstack/src/commands/prover/args/run.rs index 4b3a16a38fca..cc6a8d2089e4 100644 --- a/zkstack_cli/crates/zkstack/src/commands/prover/args/run.rs +++ b/zkstack_cli/crates/zkstack/src/commands/prover/args/run.rs @@ -16,8 +16,8 @@ use crate::{ WITNESS_VECTOR_GENERATOR_DOCKER_IMAGE, }, messages::{ - MSG_ROUND_SELECT_PROMPT, MSG_RUN_COMPONENT_PROMPT, MSG_THREADS_PROMPT, - MSG_WITNESS_GENERATOR_ROUND_ERR, + MSG_DOCKER_IMAGE_TAG_OPTION, MSG_ROUND_SELECT_PROMPT, MSG_RUN_COMPONENT_PROMPT, + MSG_THREADS_PROMPT, MSG_WITNESS_GENERATOR_ROUND_ERR, }, }; @@ -35,7 +35,7 @@ pub struct ProverRunArgs { pub circuit_prover_args: CircuitProverArgs, #[clap(long)] pub docker: Option, - #[clap(long)] + #[arg(long, help = MSG_DOCKER_IMAGE_TAG_OPTION)] pub tag: Option, } diff --git a/zkstack_cli/crates/zkstack/src/commands/server.rs b/zkstack_cli/crates/zkstack/src/commands/server.rs deleted file mode 100644 index 10f267fb8526..000000000000 --- a/zkstack_cli/crates/zkstack/src/commands/server.rs +++ /dev/null @@ -1,92 +0,0 @@ -use anyhow::Context; -use common::{ - cmd::Cmd, - config::global_config, - logger, - server::{Server, ServerMode}, -}; -use config::{ - traits::FileConfigWithDefaultName, ChainConfig, ContractsConfig, EcosystemConfig, - GeneralConfig, GenesisConfig, SecretsConfig, WalletsConfig, -}; -use xshell::{cmd, Shell}; - -use crate::{ - commands::args::{RunServerArgs, ServerArgs, ServerCommand, WaitArgs}, - messages::{ - msg_waiting_for_server_success, MSG_BUILDING_SERVER, MSG_CHAIN_NOT_INITIALIZED, - MSG_FAILED_TO_BUILD_SERVER_ERR, MSG_FAILED_TO_RUN_SERVER_ERR, MSG_STARTING_SERVER, - MSG_WAITING_FOR_SERVER, - }, -}; - -pub async fn run(shell: &Shell, args: ServerArgs) -> anyhow::Result<()> { - let ecosystem_config = EcosystemConfig::from_file(shell)?; - let chain_config = ecosystem_config - .load_current_chain() - .context(MSG_CHAIN_NOT_INITIALIZED)?; - - match ServerCommand::from(args) { - ServerCommand::Run(args) => run_server(args, &chain_config, shell), - ServerCommand::Build => build_server(&chain_config, shell), - ServerCommand::Wait(args) => wait_for_server(args, &chain_config).await, - } -} - -fn build_server(chain_config: &ChainConfig, shell: &Shell) -> anyhow::Result<()> { - let _dir_guard = shell.push_dir(&chain_config.link_to_code); - - logger::info(MSG_BUILDING_SERVER); - - let mut cmd = Cmd::new(cmd!(shell, "cargo build --release --bin zksync_server")); - cmd = cmd.with_force_run(); - cmd.run().context(MSG_FAILED_TO_BUILD_SERVER_ERR) -} - -fn run_server( - args: RunServerArgs, - chain_config: &ChainConfig, - shell: &Shell, -) -> anyhow::Result<()> { - logger::info(MSG_STARTING_SERVER); - let server = Server::new( - args.components.clone(), - chain_config.link_to_code.clone(), - args.uring, - ); - - let mode = if args.genesis { - ServerMode::Genesis - } else { - ServerMode::Normal - }; - server - .run( - shell, - mode, - GenesisConfig::get_path_with_base_path(&chain_config.configs), - WalletsConfig::get_path_with_base_path(&chain_config.configs), - GeneralConfig::get_path_with_base_path(&chain_config.configs), - SecretsConfig::get_path_with_base_path(&chain_config.configs), - ContractsConfig::get_path_with_base_path(&chain_config.configs), - vec![], - ) - .context(MSG_FAILED_TO_RUN_SERVER_ERR) -} - -async fn wait_for_server(args: WaitArgs, chain_config: &ChainConfig) -> anyhow::Result<()> { - let verbose = global_config().verbose; - - let health_check_port = chain_config - .get_general_config()? - .api_config - .as_ref() - .context("no API config")? - .healthcheck - .port; - - logger::info(MSG_WAITING_FOR_SERVER); - args.poll_health_check(health_check_port, verbose).await?; - logger::info(msg_waiting_for_server_success(health_check_port)); - Ok(()) -} diff --git a/zkstack_cli/crates/zkstack/src/commands/server/build.rs b/zkstack_cli/crates/zkstack/src/commands/server/build.rs new file mode 100644 index 000000000000..adffefcb448d --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/commands/server/build.rs @@ -0,0 +1,16 @@ +use anyhow::Context; +use common::{cmd::Cmd, logger}; +use config::ChainConfig; +use xshell::{cmd, Shell}; + +use crate::messages::{MSG_BUILDING_SERVER, MSG_FAILED_TO_BUILD_SERVER_ERR}; + +pub(super) fn build_server(chain_config: &ChainConfig, shell: &Shell) -> anyhow::Result<()> { + let _dir_guard = shell.push_dir(&chain_config.link_to_code); + + logger::info(MSG_BUILDING_SERVER); + + let mut cmd = Cmd::new(cmd!(shell, "cargo build --release --bin zksync_server")); + cmd = cmd.with_force_run(); + cmd.run().context(MSG_FAILED_TO_BUILD_SERVER_ERR) +} diff --git a/zkstack_cli/crates/zkstack/src/commands/server/mod.rs b/zkstack_cli/crates/zkstack/src/commands/server/mod.rs new file mode 100644 index 000000000000..6c5c45eb2ae7 --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/commands/server/mod.rs @@ -0,0 +1,28 @@ +use anyhow::Context; +use build::build_server; +use config::EcosystemConfig; +use run::run_server; +use wait::wait_for_server; +use xshell::Shell; + +use crate::{ + commands::args::{ServerArgs, ServerCommand}, + messages::MSG_CHAIN_NOT_INITIALIZED, +}; + +mod build; +mod run; +mod wait; + +pub async fn run(shell: &Shell, args: ServerArgs) -> anyhow::Result<()> { + let ecosystem_config = EcosystemConfig::from_file(shell)?; + let chain_config = ecosystem_config + .load_current_chain() + .context(MSG_CHAIN_NOT_INITIALIZED)?; + + match ServerCommand::from(args) { + ServerCommand::Run(args) => run_server(args, &chain_config, shell).await, + ServerCommand::Build => build_server(&chain_config, shell), + ServerCommand::Wait(args) => wait_for_server(args, &chain_config).await, + } +} diff --git a/zkstack_cli/crates/zkstack/src/commands/server/run.rs b/zkstack_cli/crates/zkstack/src/commands/server/run.rs new file mode 100644 index 000000000000..c5671a498335 --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/commands/server/run.rs @@ -0,0 +1,56 @@ +use anyhow::Context; +use common::{ + logger, + server::{Server, ServerMode}, +}; +use config::{ + traits::FileConfigWithDefaultName, ChainConfig, ContractsConfig, GeneralConfig, GenesisConfig, + SecretsConfig, WalletsConfig, +}; +use xshell::Shell; + +use crate::{ + commands::args::run::RunServerArgs, + messages::{MSG_FAILED_TO_RUN_SERVER_ERR, MSG_STARTING_SERVER}, + utils::{docker::adjust_host_to_execution_mode, ports::EcosystemPortsScanner}, +}; + +pub(super) async fn run_server( + args: RunServerArgs, + chain_config: &ChainConfig, + shell: &Shell, +) -> anyhow::Result<()> { + let args = args.fill_values_with_prompt().await; + let ports = EcosystemPortsScanner::scan(shell)?; + + logger::info(MSG_STARTING_SERVER); + let server = Server::new( + args.components.clone(), + chain_config.link_to_code.clone(), + args.uring, + ); + + let server_mode = if args.genesis { + ServerMode::Genesis + } else { + ServerMode::Normal + }; + + adjust_host_to_execution_mode(shell, &args.mode, chain_config)?; + + server + .run( + shell, + args.mode, + server_mode, + GenesisConfig::get_path_with_base_path(&chain_config.configs), + WalletsConfig::get_path_with_base_path(&chain_config.configs), + GeneralConfig::get_path_with_base_path(&chain_config.configs), + SecretsConfig::get_path_with_base_path(&chain_config.configs), + ContractsConfig::get_path_with_base_path(&chain_config.configs), + vec![], + ports.ports.keys().map(|p| p.to_owned()).collect(), + ) + .await + .context(MSG_FAILED_TO_RUN_SERVER_ERR) +} diff --git a/zkstack_cli/crates/zkstack/src/commands/server/wait.rs b/zkstack_cli/crates/zkstack/src/commands/server/wait.rs new file mode 100644 index 000000000000..36d042f0d349 --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/commands/server/wait.rs @@ -0,0 +1,28 @@ +use anyhow::Context; +use common::{config::global_config, logger}; +use config::ChainConfig; + +use crate::{ + commands::args::WaitArgs, + messages::{msg_waiting_for_server_success, MSG_WAITING_FOR_SERVER}, +}; + +pub(super) async fn wait_for_server( + args: WaitArgs, + chain_config: &ChainConfig, +) -> anyhow::Result<()> { + let verbose = global_config().verbose; + + let health_check_port = chain_config + .get_general_config()? + .api_config + .as_ref() + .context("no API config")? + .healthcheck + .port; + + logger::info(MSG_WAITING_FOR_SERVER); + args.poll_health_check(health_check_port, verbose).await?; + logger::info(msg_waiting_for_server_success(health_check_port)); + Ok(()) +} diff --git a/zkstack_cli/crates/zkstack/src/messages.rs b/zkstack_cli/crates/zkstack/src/messages.rs index 14b89be773f1..f0e5bd9b1df9 100644 --- a/zkstack_cli/crates/zkstack/src/messages.rs +++ b/zkstack_cli/crates/zkstack/src/messages.rs @@ -268,6 +268,8 @@ pub(super) const MSG_SERVER_GENESIS_HELP: &str = "Run server in genesis mode"; pub(super) const MSG_SERVER_ADDITIONAL_ARGS_HELP: &str = "Additional arguments that can be passed through the CLI"; pub(super) const MSG_SERVER_URING_HELP: &str = "Enables uring support for RocksDB"; +pub(super) const MSG_SERVER_SELECT_DOCKER_IMAGE_TAG: &str = "Select Docker image tag:"; +pub(super) const MSG_DOCKER_IMAGE_TAG_OPTION: &str = "Select a specific Docker image tag"; /// Accept ownership related messages pub(super) const MSG_ACCEPTING_GOVERNANCE_SPINNER: &str = "Accepting governance..."; diff --git a/zkstack_cli/crates/zkstack/src/utils/docker.rs b/zkstack_cli/crates/zkstack/src/utils/docker.rs new file mode 100644 index 000000000000..2450eb0583d0 --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/utils/docker.rs @@ -0,0 +1,90 @@ +use common::{github::GitHubTagFetcher, server::ExecutionMode, PromptSelect}; +use config::{traits::SaveConfigWithBasePath, ChainConfig}; +use xshell::Shell; + +use crate::messages::MSG_SERVER_SELECT_DOCKER_IMAGE_TAG; + +const DOCKER_INTERNAL: &str = "host.docker.internal"; +const LOCALHOST: &str = "localhost"; + +pub async fn select_tag() -> anyhow::Result { + let fetcher = GitHubTagFetcher::new(None)?; + let gh_tags = fetcher.get_newest_core_tags(Some(5)).await?; + + let tags: Vec = std::iter::once("latest".to_string()) + .chain( + gh_tags + .iter() + .map(|r| r.name.trim_start_matches("core-").to_string()), + ) + .collect(); + + Ok(PromptSelect::new(MSG_SERVER_SELECT_DOCKER_IMAGE_TAG, tags).ask()) +} + +pub fn adjust_host_to_execution_mode( + shell: &Shell, + mode: &ExecutionMode, + chain_config: &ChainConfig, +) -> anyhow::Result<()> { + let mut secrets = chain_config.get_secrets_config()?; + let mut general = chain_config.get_general_config()?; + + match mode { + ExecutionMode::Release | ExecutionMode::Debug => { + if let Some(host) = general.prometheus_host() { + if host == DOCKER_INTERNAL { + general.set_prometheus_host(LOCALHOST)?; + } + } + + if let Some(host) = secrets.prover_url_host() { + if host == DOCKER_INTERNAL { + secrets.set_prover_url_host(LOCALHOST)?; + } + } + if let Some(host) = secrets.server_url_host() { + if host == DOCKER_INTERNAL { + secrets.set_server_url_host(LOCALHOST)?; + } + } + if let Some(host) = secrets.l1_rpc_url_host() { + if host == DOCKER_INTERNAL { + secrets.set_l1_rpc_url_host(LOCALHOST)?; + } + } + } + ExecutionMode::Docker { tag: _ } => { + if let Some(host) = general.prometheus_host() { + if is_localhost(host.as_str()) { + general.set_prometheus_host(DOCKER_INTERNAL)?; + } + } + + if let Some(host) = secrets.prover_url_host() { + if is_localhost(host.as_str()) { + secrets.set_prover_url_host(DOCKER_INTERNAL)?; + } + } + if let Some(host) = secrets.server_url_host() { + if is_localhost(host.as_str()) { + secrets.set_server_url_host(DOCKER_INTERNAL)?; + } + } + if let Some(host) = secrets.l1_rpc_url_host() { + if is_localhost(host.as_str()) { + secrets.set_l1_rpc_url_host(DOCKER_INTERNAL)?; + } + } + } + } + + secrets.save_with_base_path(shell, &chain_config.configs)?; + general.save_with_base_path(shell, &chain_config.configs)?; + + Ok(()) +} + +fn is_localhost(host: &str) -> bool { + host == "127.0.0.1" || host == "localhost" +} diff --git a/zkstack_cli/crates/zkstack/src/utils/mod.rs b/zkstack_cli/crates/zkstack/src/utils/mod.rs index a8bdc00d73fc..87f5fb2d2c57 100644 --- a/zkstack_cli/crates/zkstack/src/utils/mod.rs +++ b/zkstack_cli/crates/zkstack/src/utils/mod.rs @@ -1,4 +1,5 @@ pub mod consensus; +pub mod docker; pub mod forge; pub mod link_to_code; pub mod ports;