diff --git a/.github/workflows/ci-core-reusable.yml b/.github/workflows/ci-core-reusable.yml index 7cada37610c0..6dce6c64c6ba 100644 --- a/.github/workflows/ci-core-reusable.yml +++ b/.github/workflows/ci-core-reusable.yml @@ -147,7 +147,8 @@ jobs: --base-token-price-denominator 1 \ --set-as-default false \ --ignore-prerequisites \ - --legacy-bridge + --legacy-bridge \ + --evm-emulator false ci_run zkstack ecosystem init --dev --verbose ci_run zkstack dev contracts --test-contracts @@ -262,7 +263,8 @@ jobs: --base-token-price-nominator 1 \ --base-token-price-denominator 1 \ --set-as-default false \ - --ignore-prerequisites + --ignore-prerequisites \ + --evm-emulator false ci_run zkstack chain init \ --deploy-paymaster \ @@ -283,7 +285,8 @@ jobs: --base-token-price-nominator 314 \ --base-token-price-denominator 1000 \ --set-as-default false \ - --ignore-prerequisites + --ignore-prerequisites \ + --evm-emulator false ci_run zkstack chain init \ --deploy-paymaster \ @@ -304,7 +307,8 @@ jobs: --base-token-price-nominator 1 \ --base-token-price-denominator 1 \ --set-as-default false \ - --ignore-prerequisites + --ignore-prerequisites \ + --evm-emulator false ci_run zkstack chain build-transactions --chain offline_chain --l1-rpc-url http://127.0.0.1:8545 @@ -339,7 +343,8 @@ jobs: --base-token-price-nominator 314 \ --base-token-price-denominator 1000 \ --set-as-default false \ - --ignore-prerequisites + --ignore-prerequisites \ + --evm-emulator false ci_run zkstack chain init \ --deploy-paymaster \ diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/args/create.rs b/zkstack_cli/crates/zkstack/src/commands/chain/args/create.rs index ae08d4712b34..ec37f9ba0304 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/args/create.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/args/create.rs @@ -1,22 +1,14 @@ -use std::{ - path::{Path, PathBuf}, - str::FromStr, -}; +use std::{path::PathBuf, str::FromStr}; use anyhow::{bail, Context}; use clap::{Parser, ValueEnum, ValueHint}; use common::{Prompt, PromptConfirm, PromptSelect}; -use config::{ - forge_interface::deploy_ecosystem::output::Erc20Token, traits::ReadConfigWithBasePath, - EcosystemConfig, -}; +use config::forge_interface::deploy_ecosystem::output::Erc20Token; use serde::{Deserialize, Serialize}; use slugify_rs::slugify; use strum::{Display, EnumIter, IntoEnumIterator}; use types::{BaseToken, L1BatchCommitmentMode, L1Network, ProverMode, WalletCreation}; -use xshell::Shell; use zksync_basic_types::H160; -use zksync_config::GenesisConfig; use crate::{ defaults::L2_CHAIN_ID, @@ -26,7 +18,7 @@ use crate::{ MSG_BASE_TOKEN_PRICE_DENOMINATOR_PROMPT, MSG_BASE_TOKEN_PRICE_NOMINATOR_HELP, MSG_BASE_TOKEN_PRICE_NOMINATOR_PROMPT, MSG_BASE_TOKEN_SELECTION_PROMPT, MSG_CHAIN_ID_HELP, MSG_CHAIN_ID_PROMPT, MSG_CHAIN_ID_VALIDATOR_ERR, MSG_CHAIN_NAME_PROMPT, - MSG_EVM_EMULATOR_HASH_MISSING_ERR, MSG_EVM_EMULATOR_HELP, MSG_EVM_EMULATOR_PROMPT, + MSG_EVM_EMULATOR_HELP, MSG_EVM_EMULATOR_PROMPT, MSG_L1_BATCH_COMMIT_DATA_GENERATOR_MODE_PROMPT, MSG_L1_COMMIT_DATA_GENERATOR_MODE_HELP, MSG_NUMBER_VALIDATOR_GREATHER_THAN_ZERO_ERR, MSG_NUMBER_VALIDATOR_NOT_ZERO_ERR, MSG_PROVER_MODE_HELP, MSG_PROVER_VERSION_PROMPT, MSG_SET_AS_DEFAULT_HELP, @@ -83,11 +75,10 @@ pub struct ChainCreateArgs { impl ChainCreateArgs { pub fn fill_values_with_prompt( self, - shell: &Shell, number_of_chains: u32, l1_network: &L1Network, possible_erc20: Vec, - link_to_code: &Path, + link_to_code: String, ) -> anyhow::Result { let mut chain_name = self .chain_name @@ -224,24 +215,11 @@ impl ChainCreateArgs { } }; - let default_genesis_config = GenesisConfig::read_with_base_path( - shell, - EcosystemConfig::default_configs_path(link_to_code), - ) - .context("failed reading genesis config")?; - let has_evm_emulation_support = default_genesis_config.evm_emulator_hash.is_some(); let evm_emulator = self.evm_emulator.unwrap_or_else(|| { - if !has_evm_emulation_support { - false - } else { - PromptConfirm::new(MSG_EVM_EMULATOR_PROMPT) - .default(false) - .ask() - } + PromptConfirm::new(MSG_EVM_EMULATOR_PROMPT) + .default(false) + .ask() }); - if !has_evm_emulation_support && evm_emulator { - bail!(MSG_EVM_EMULATOR_HASH_MISSING_ERR); - } let set_as_default = self.set_as_default.unwrap_or_else(|| { PromptConfirm::new(MSG_SET_AS_DEFAULT_PROMPT) @@ -260,6 +238,7 @@ impl ChainCreateArgs { set_as_default, legacy_bridge: self.legacy_bridge, evm_emulator, + link_to_code, }) } } @@ -276,6 +255,7 @@ pub struct ChainCreateArgsFinal { pub set_as_default: bool, pub legacy_bridge: bool, pub evm_emulator: bool, + pub link_to_code: String, } #[derive(Debug, Clone, EnumIter, Display, PartialEq, Eq)] diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/create.rs b/zkstack_cli/crates/zkstack/src/commands/chain/create.rs index bdf5711e3213..730c1df8d3f2 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/create.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/create.rs @@ -3,8 +3,9 @@ use std::cell::OnceCell; use anyhow::Context; use common::{logger, spinner::Spinner}; use config::{ - create_local_configs_dir, create_wallets, traits::SaveConfigWithBasePath, ChainConfig, - EcosystemConfig, + create_local_configs_dir, create_wallets, + traits::{ReadConfigWithBasePath, SaveConfigWithBasePath}, + ChainConfig, EcosystemConfig, GenesisConfig, }; use xshell::Shell; use zksync_basic_types::L2ChainId; @@ -13,8 +14,10 @@ use crate::{ commands::chain::args::create::{ChainCreateArgs, ChainCreateArgsFinal}, messages::{ MSG_ARGS_VALIDATOR_ERR, MSG_CHAIN_CREATED, MSG_CREATING_CHAIN, - MSG_CREATING_CHAIN_CONFIGURATIONS_SPINNER, MSG_SELECTED_CONFIG, + MSG_CREATING_CHAIN_CONFIGURATIONS_SPINNER, MSG_EVM_EMULATOR_HASH_MISSING_ERR, + MSG_SELECTED_CONFIG, }, + utils::link_to_code::resolve_link_to_code, }; pub fn run(args: ChainCreateArgs, shell: &Shell) -> anyhow::Result<()> { @@ -30,11 +33,10 @@ fn create( let tokens = ecosystem_config.get_erc20_tokens(); let args = args .fill_values_with_prompt( - shell, ecosystem_config.list_of_chains().len() as u32, &ecosystem_config.l1_network, tokens, - &ecosystem_config.link_to_code, + ecosystem_config.link_to_code.clone().display().to_string(), ) .context(MSG_ARGS_VALIDATOR_ERR)?; @@ -74,6 +76,15 @@ pub(crate) fn create_chain_inner( (L2ChainId::from(args.chain_id), None) }; let internal_id = ecosystem_config.list_of_chains().len() as u32; + let link_to_code = resolve_link_to_code(shell, chain_path.clone(), args.link_to_code.clone())?; + let default_genesis_config = GenesisConfig::read_with_base_path( + shell, + EcosystemConfig::default_configs_path(&link_to_code), + )?; + let has_evm_emulation_support = default_genesis_config.evm_emulator_hash.is_some(); + if args.evm_emulator && !has_evm_emulation_support { + anyhow::bail!(MSG_EVM_EMULATOR_HASH_MISSING_ERR); + } let chain_config = ChainConfig { id: internal_id, diff --git a/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/create.rs b/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/create.rs index 6b6c1236d363..53d9c27be60b 100644 --- a/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/create.rs +++ b/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/create.rs @@ -1,23 +1,20 @@ -use std::path::{Path, PathBuf}; +use std::path::PathBuf; -use anyhow::bail; use clap::{Parser, ValueHint}; -use common::{cmd::Cmd, logger, Prompt, PromptConfirm, PromptSelect}; +use common::{Prompt, PromptConfirm, PromptSelect}; use serde::{Deserialize, Serialize}; use slugify_rs::slugify; -use strum::{EnumIter, IntoEnumIterator}; +use strum::IntoEnumIterator; use types::{L1Network, WalletCreation}; -use xshell::{cmd, Shell}; +use xshell::Shell; use crate::{ commands::chain::{args::create::ChainCreateArgs, ChainCreateArgsFinal}, messages::{ - msg_path_to_zksync_does_not_exist_err, MSG_CONFIRM_STILL_USE_FOLDER, MSG_ECOSYSTEM_NAME_PROMPT, MSG_L1_NETWORK_HELP, MSG_L1_NETWORK_PROMPT, - MSG_LINK_TO_CODE_HELP, MSG_LINK_TO_CODE_PROMPT, MSG_LINK_TO_CODE_SELECTION_CLONE, - MSG_LINK_TO_CODE_SELECTION_PATH, MSG_NOT_MAIN_REPO_OR_FORK_ERR, - MSG_REPOSITORY_ORIGIN_PROMPT, MSG_START_CONTAINERS_HELP, MSG_START_CONTAINERS_PROMPT, + MSG_LINK_TO_CODE_HELP, MSG_START_CONTAINERS_HELP, MSG_START_CONTAINERS_PROMPT, }, + utils::link_to_code::get_link_to_code, }; #[derive(Debug, Serialize, Deserialize, Parser)] @@ -47,23 +44,7 @@ impl EcosystemCreateArgs { .unwrap_or_else(|| Prompt::new(MSG_ECOSYSTEM_NAME_PROMPT).ask()); ecosystem_name = slugify!(&ecosystem_name, separator = "_"); - let link_to_code = self.link_to_code.unwrap_or_else(|| { - let link_to_code_selection = - PromptSelect::new(MSG_REPOSITORY_ORIGIN_PROMPT, LinkToCodeSelection::iter()).ask(); - match link_to_code_selection { - LinkToCodeSelection::Clone => "".to_string(), - LinkToCodeSelection::Path => { - let mut path: String = Prompt::new(MSG_LINK_TO_CODE_PROMPT).ask(); - if let Err(err) = check_link_to_code(shell, &path) { - logger::warn(err); - if !PromptConfirm::new(MSG_CONFIRM_STILL_USE_FOLDER).ask() { - path = pick_new_link_to_code(shell); - } - } - path - } - } - }); + let link_to_code = self.link_to_code.unwrap_or_else(|| get_link_to_code(shell)); let l1_network = self .l1_network @@ -71,13 +52,9 @@ impl EcosystemCreateArgs { // Make the only chain as a default one self.chain.set_as_default = Some(true); - let chain = self.chain.fill_values_with_prompt( - shell, - 0, - &l1_network, - vec![], - Path::new(&link_to_code), - )?; + let chain = + self.chain + .fill_values_with_prompt(0, &l1_network, vec![], link_to_code.clone())?; let start_containers = self.start_containers.unwrap_or_else(|| { PromptConfirm::new(MSG_START_CONTAINERS_PROMPT) @@ -113,55 +90,3 @@ impl EcosystemCreateArgsFinal { self.chain_args.clone() } } - -#[derive(Debug, Clone, EnumIter, PartialEq, Eq)] -enum LinkToCodeSelection { - Clone, - Path, -} - -impl std::fmt::Display for LinkToCodeSelection { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - LinkToCodeSelection::Clone => write!(f, "{MSG_LINK_TO_CODE_SELECTION_CLONE}"), - LinkToCodeSelection::Path => write!(f, "{MSG_LINK_TO_CODE_SELECTION_PATH}"), - } - } -} - -fn check_link_to_code(shell: &Shell, path: &str) -> anyhow::Result<()> { - let path = Path::new(path); - if !shell.path_exists(path) { - bail!(msg_path_to_zksync_does_not_exist_err( - path.to_str().unwrap() - )); - } - - let _guard = shell.push_dir(path); - let out = String::from_utf8( - Cmd::new(cmd!(shell, "git remote -v")) - .run_with_output()? - .stdout, - )?; - - if !out.contains("matter-labs/zksync-era") { - bail!(MSG_NOT_MAIN_REPO_OR_FORK_ERR); - } - - Ok(()) -} - -fn pick_new_link_to_code(shell: &Shell) -> String { - let link_to_code: String = Prompt::new(MSG_LINK_TO_CODE_PROMPT).ask(); - match check_link_to_code(shell, &link_to_code) { - Ok(_) => link_to_code, - Err(err) => { - logger::warn(err); - if !PromptConfirm::new(MSG_CONFIRM_STILL_USE_FOLDER).ask() { - pick_new_link_to_code(shell) - } else { - link_to_code - } - } - } -} diff --git a/zkstack_cli/crates/zkstack/src/commands/ecosystem/create.rs b/zkstack_cli/crates/zkstack/src/commands/ecosystem/create.rs index 356b5322980f..203c667ade65 100644 --- a/zkstack_cli/crates/zkstack/src/commands/ecosystem/create.rs +++ b/zkstack_cli/crates/zkstack/src/commands/ecosystem/create.rs @@ -1,11 +1,8 @@ -use std::{path::PathBuf, str::FromStr}; - use anyhow::{bail, Context}; -use common::{git, logger, spinner::Spinner}; +use common::{logger, spinner::Spinner}; use config::{ create_local_configs_dir, create_wallets, get_default_era_chain_id, traits::SaveConfigWithBasePath, EcosystemConfig, EcosystemConfigFromFileError, - ZKSYNC_ERA_GIT_REPO, }; use xshell::Shell; @@ -22,11 +19,12 @@ use crate::{ }, }, messages::{ - msg_created_ecosystem, MSG_ARGS_VALIDATOR_ERR, MSG_CLONING_ERA_REPO_SPINNER, - MSG_CREATING_DEFAULT_CHAIN_SPINNER, MSG_CREATING_ECOSYSTEM, - MSG_CREATING_INITIAL_CONFIGURATIONS_SPINNER, MSG_ECOSYSTEM_ALREADY_EXISTS_ERR, - MSG_ECOSYSTEM_CONFIG_INVALID_ERR, MSG_SELECTED_CONFIG, MSG_STARTING_CONTAINERS_SPINNER, + msg_created_ecosystem, MSG_ARGS_VALIDATOR_ERR, MSG_CREATING_DEFAULT_CHAIN_SPINNER, + MSG_CREATING_ECOSYSTEM, MSG_CREATING_INITIAL_CONFIGURATIONS_SPINNER, + MSG_ECOSYSTEM_ALREADY_EXISTS_ERR, MSG_ECOSYSTEM_CONFIG_INVALID_ERR, MSG_SELECTED_CONFIG, + MSG_STARTING_CONTAINERS_SPINNER, }, + utils::link_to_code::resolve_link_to_code, }; pub fn run(args: EcosystemCreateArgs, shell: &Shell) -> anyhow::Result<()> { @@ -55,21 +53,7 @@ fn create(args: EcosystemCreateArgs, shell: &Shell) -> anyhow::Result<()> { let configs_path = create_local_configs_dir(shell, ".")?; - let link_to_code = if args.link_to_code.is_empty() { - let spinner = Spinner::new(MSG_CLONING_ERA_REPO_SPINNER); - let link_to_code = git::clone( - shell, - shell.current_dir(), - ZKSYNC_ERA_GIT_REPO, - "zksync-era", - )?; - spinner.finish(); - link_to_code - } else { - let path = PathBuf::from_str(&args.link_to_code)?; - git::submodule_update(shell, path.clone())?; - path - }; + let link_to_code = resolve_link_to_code(shell, shell.current_dir(), args.link_to_code.clone())?; let spinner = Spinner::new(MSG_CREATING_INITIAL_CONFIGURATIONS_SPINNER); let chain_config = args.chain_config(); diff --git a/zkstack_cli/crates/zkstack/src/utils/link_to_code.rs b/zkstack_cli/crates/zkstack/src/utils/link_to_code.rs new file mode 100644 index 000000000000..1f2eb487849d --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/utils/link_to_code.rs @@ -0,0 +1,109 @@ +use std::{ + path::{Path, PathBuf}, + str::FromStr, +}; + +use anyhow::bail; +use common::{cmd::Cmd, git, logger, spinner::Spinner, Prompt, PromptConfirm, PromptSelect}; +use config::ZKSYNC_ERA_GIT_REPO; +use strum::{EnumIter, IntoEnumIterator}; +use xshell::{cmd, Shell}; + +use crate::messages::{ + msg_path_to_zksync_does_not_exist_err, MSG_CLONING_ERA_REPO_SPINNER, + MSG_CONFIRM_STILL_USE_FOLDER, MSG_LINK_TO_CODE_PROMPT, MSG_LINK_TO_CODE_SELECTION_CLONE, + MSG_LINK_TO_CODE_SELECTION_PATH, MSG_NOT_MAIN_REPO_OR_FORK_ERR, MSG_REPOSITORY_ORIGIN_PROMPT, +}; + +#[derive(Debug, Clone, EnumIter, PartialEq, Eq)] +enum LinkToCodeSelection { + Clone, + Path, +} + +impl std::fmt::Display for LinkToCodeSelection { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + LinkToCodeSelection::Clone => write!(f, "{MSG_LINK_TO_CODE_SELECTION_CLONE}"), + LinkToCodeSelection::Path => write!(f, "{MSG_LINK_TO_CODE_SELECTION_PATH}"), + } + } +} + +fn check_link_to_code(shell: &Shell, path: &str) -> anyhow::Result<()> { + let path = Path::new(path); + if !shell.path_exists(path) { + bail!(msg_path_to_zksync_does_not_exist_err( + path.to_str().unwrap() + )); + } + + let _guard = shell.push_dir(path); + let out = String::from_utf8( + Cmd::new(cmd!(shell, "git remote -v")) + .run_with_output()? + .stdout, + )?; + + if !out.contains("matter-labs/zksync-era") { + bail!(MSG_NOT_MAIN_REPO_OR_FORK_ERR); + } + + Ok(()) +} + +fn pick_new_link_to_code(shell: &Shell) -> String { + let link_to_code: String = Prompt::new(MSG_LINK_TO_CODE_PROMPT).ask(); + match check_link_to_code(shell, &link_to_code) { + Ok(_) => link_to_code, + Err(err) => { + logger::warn(err); + if !PromptConfirm::new(MSG_CONFIRM_STILL_USE_FOLDER).ask() { + pick_new_link_to_code(shell) + } else { + link_to_code + } + } + } +} + +pub(crate) fn get_link_to_code(shell: &Shell) -> String { + let link_to_code_selection = + PromptSelect::new(MSG_REPOSITORY_ORIGIN_PROMPT, LinkToCodeSelection::iter()).ask(); + match link_to_code_selection { + LinkToCodeSelection::Clone => "".to_string(), + LinkToCodeSelection::Path => { + let mut path: String = Prompt::new(MSG_LINK_TO_CODE_PROMPT).ask(); + if let Err(err) = check_link_to_code(shell, &path) { + logger::warn(err); + if !PromptConfirm::new(MSG_CONFIRM_STILL_USE_FOLDER).ask() { + path = pick_new_link_to_code(shell); + } + } + path + } + } +} + +pub(crate) fn resolve_link_to_code( + shell: &Shell, + base_path: PathBuf, + link_to_code: String, +) -> anyhow::Result { + if link_to_code.is_empty() { + if base_path.join("zksync-era").exists() { + return Ok(base_path.join("zksync-era")); + } + let spinner = Spinner::new(MSG_CLONING_ERA_REPO_SPINNER); + if !base_path.exists() { + shell.create_dir(&base_path)?; + } + let link_to_code = git::clone(shell, base_path, ZKSYNC_ERA_GIT_REPO, "zksync-era")?; + spinner.finish(); + Ok(link_to_code) + } else { + let path = PathBuf::from_str(&link_to_code)?; + git::submodule_update(shell, path.clone())?; + Ok(path) + } +} diff --git a/zkstack_cli/crates/zkstack/src/utils/mod.rs b/zkstack_cli/crates/zkstack/src/utils/mod.rs index cf7a7ef48182..a8bdc00d73fc 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 forge; +pub mod link_to_code; pub mod ports; pub mod rocks_db;