Skip to content

Commit

Permalink
feat(zk_toolbox): Add EVM emulator option to zkstack CLI (#3139)
Browse files Browse the repository at this point in the history
## What ❔

Allows to enable EVM emulation support from `zkstack chain create` by
specifying the `--evm-emulator` command-line arg or answering the
corresponding prompt. The prompt only activates if the EVM emulator
bytecode hash is specified in the template genesis config (currently,
it's not); more generally, it is impossible to create a chain with EVM
emulation support if its bytecode hash is unknown.

## Why ❔

Part of efforts to enable EVM emulation.

## Checklist

- [x] PR title corresponds to the body of PR (we generate changelog
entries from PRs).
- [x] Documentation comments have been added / updated.
- [x] Code has been formatted via `zkstack dev fmt` and `zkstack dev
lint`.
  • Loading branch information
slowli authored Oct 24, 2024
1 parent 8089b78 commit ffa18e1
Show file tree
Hide file tree
Showing 14 changed files with 93 additions and 11 deletions.
2 changes: 1 addition & 1 deletion etc/env/file_based/genesis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ prover:
dummy_verifier: true
genesis_protocol_semantic_version: 0.25.0
l1_batch_commit_data_generator_mode: Rollup
# Uncomment to enable EVM emulation (requires to run genesis)
# TODO: uncomment once EVM emulator is present in the `contracts` submodule
# evm_emulator_hash: 0x01000e53aa35d9d19fa99341c2e2901cf93b3668f01569dd5c6ca409c7696b91
4 changes: 4 additions & 0 deletions zkstack_cli/crates/config/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ pub struct ChainConfigInternal {
pub wallet_creation: WalletCreation,
#[serde(skip_serializing_if = "Option::is_none")]
pub legacy_bridge: Option<bool>,
#[serde(default)] // for backward compatibility
pub evm_emulator: bool,
}

/// Chain configuration file. This file is created in the chain
Expand All @@ -61,6 +63,7 @@ pub struct ChainConfig {
pub wallet_creation: WalletCreation,
pub shell: OnceCell<Shell>,
pub legacy_bridge: Option<bool>,
pub evm_emulator: bool,
}

impl Serialize for ChainConfig {
Expand Down Expand Up @@ -157,6 +160,7 @@ impl ChainConfig {
base_token: self.base_token.clone(),
wallet_creation: self.wallet_creation,
legacy_bridge: self.legacy_bridge,
evm_emulator: self.evm_emulator,
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion zkstack_cli/crates/config/src/ecosystem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ impl EcosystemConfig {
.artifacts_path
.unwrap_or_else(|| self.get_chain_artifacts_path(name)),
legacy_bridge: config.legacy_bridge,
evm_emulator: config.evm_emulator,
})
}

Expand Down Expand Up @@ -232,7 +233,11 @@ impl EcosystemConfig {
}

pub fn get_default_configs_path(&self) -> PathBuf {
self.link_to_code.join(CONFIGS_PATH)
Self::default_configs_path(&self.link_to_code)
}

pub fn default_configs_path(link_to_code: &Path) -> PathBuf {
link_to_code.join(CONFIGS_PATH)
}

/// Path to the predefined ecosystem configs
Expand Down
15 changes: 14 additions & 1 deletion zkstack_cli/crates/config/src/genesis.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::path::Path;

use anyhow::Context as _;
use xshell::Shell;
use zksync_basic_types::L1ChainId;
pub use zksync_config::GenesisConfig;
Expand All @@ -11,11 +12,23 @@ use crate::{
ChainConfig,
};

pub fn update_from_chain_config(genesis: &mut GenesisConfig, config: &ChainConfig) {
pub fn update_from_chain_config(
genesis: &mut GenesisConfig,
config: &ChainConfig,
) -> anyhow::Result<()> {
genesis.l2_chain_id = config.chain_id;
// TODO(EVM-676): for now, the settlement layer is always the same as the L1 network
genesis.l1_chain_id = L1ChainId(config.l1_network.chain_id());
genesis.l1_batch_commit_data_generator_mode = config.l1_batch_commit_data_generator_mode;
genesis.evm_emulator_hash = if config.evm_emulator {
Some(genesis.evm_emulator_hash.context(
"impossible to initialize a chain with EVM emulator: the template genesis config \
does not contain EVM emulator hash",
)?)
} else {
None
};
Ok(())
}

impl FileConfigWithDefaultName for GenesisConfig {
Expand Down
2 changes: 2 additions & 0 deletions zkstack_cli/crates/zkstack/completion/_zkstack.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ in-file\:"Specify file with wallets"))' \
'--base-token-price-nominator=[Base token nominator]:BASE_TOKEN_PRICE_NOMINATOR: ' \
'--base-token-price-denominator=[Base token denominator]:BASE_TOKEN_PRICE_DENOMINATOR: ' \
'--set-as-default=[Set as default chain]' \
'--evm-emulator=[Enable EVM emulator]' \
'--start-containers=[Start reth and postgres containers after creation]' \
'--chain=[Chain to use]:CHAIN: ' \
'--legacy-bridge[]' \
Expand Down Expand Up @@ -241,6 +242,7 @@ in-file\:"Specify file with wallets"))' \
'--base-token-price-nominator=[Base token nominator]:BASE_TOKEN_PRICE_NOMINATOR: ' \
'--base-token-price-denominator=[Base token denominator]:BASE_TOKEN_PRICE_DENOMINATOR: ' \
'--set-as-default=[Set as default chain]' \
'--evm-emulator=[Enable EVM emulator]' \
'--chain=[Chain to use]:CHAIN: ' \
'--legacy-bridge[]' \
'-v[Verbose mode]' \
Expand Down
2 changes: 2 additions & 0 deletions zkstack_cli/crates/zkstack/completion/zkstack.fish
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ 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 create" -l base-token-price-nominator -d 'Base token nominator' -r
complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from create" -l base-token-price-denominator -d 'Base token denominator' -r
complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from create" -l set-as-default -d 'Set as default chain' -r -f -a "{true\t'',false\t''}"
complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from create" -l evm-emulator -d 'Enable EVM emulator' -r -f -a "{true\t'',false\t''}"
complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from create" -l start-containers -d 'Start reth and postgres containers after creation' -r -f -a "{true\t'',false\t''}"
complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from create" -l chain -d 'Chain to use' -r
complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from create" -l legacy-bridge
Expand Down Expand Up @@ -156,6 +157,7 @@ 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 create" -l base-token-price-nominator -d 'Base token nominator' -r
complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from create" -l base-token-price-denominator -d 'Base token denominator' -r
complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from create" -l set-as-default -d 'Set as default chain' -r -f -a "{true\t'',false\t''}"
complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from create" -l evm-emulator -d 'Enable EVM emulator' -r -f -a "{true\t'',false\t''}"
complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from create" -l chain -d 'Chain to use' -r
complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from create" -l legacy-bridge
complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from create" -s v -l verbose -d 'Verbose mode'
Expand Down
12 changes: 10 additions & 2 deletions zkstack_cli/crates/zkstack/completion/zkstack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1162,7 +1162,7 @@ _zkstack() {
return 0
;;
zkstack__chain__create)
opts="-v -h --chain-name --chain-id --prover-mode --wallet-creation --wallet-path --l1-batch-commit-data-generator-mode --base-token-address --base-token-price-nominator --base-token-price-denominator --set-as-default --legacy-bridge --verbose --chain --ignore-prerequisites --help"
opts="-v -h --chain-name --chain-id --prover-mode --wallet-creation --wallet-path --l1-batch-commit-data-generator-mode --base-token-address --base-token-price-nominator --base-token-price-denominator --set-as-default --legacy-bridge --evm-emulator --verbose --chain --ignore-prerequisites --help"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
Expand Down Expand Up @@ -1219,6 +1219,10 @@ _zkstack() {
COMPREPLY=($(compgen -W "true false" -- "${cur}"))
return 0
;;
--evm-emulator)
COMPREPLY=($(compgen -W "true false" -- "${cur}"))
return 0
;;
--chain)
COMPREPLY=($(compgen -f "${cur}"))
return 0
Expand Down Expand Up @@ -4643,7 +4647,7 @@ _zkstack() {
return 0
;;
zkstack__ecosystem__create)
opts="-v -h --ecosystem-name --l1-network --link-to-code --chain-name --chain-id --prover-mode --wallet-creation --wallet-path --l1-batch-commit-data-generator-mode --base-token-address --base-token-price-nominator --base-token-price-denominator --set-as-default --legacy-bridge --start-containers --verbose --chain --ignore-prerequisites --help"
opts="-v -h --ecosystem-name --l1-network --link-to-code --chain-name --chain-id --prover-mode --wallet-creation --wallet-path --l1-batch-commit-data-generator-mode --base-token-address --base-token-price-nominator --base-token-price-denominator --set-as-default --legacy-bridge --evm-emulator --start-containers --verbose --chain --ignore-prerequisites --help"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
Expand Down Expand Up @@ -4715,6 +4719,10 @@ _zkstack() {
COMPREPLY=($(compgen -W "true false" -- "${cur}"))
return 0
;;
--evm-emulator)
COMPREPLY=($(compgen -W "true false" -- "${cur}"))
return 0
;;
--start-containers)
COMPREPLY=($(compgen -W "true false" -- "${cur}"))
return 0
Expand Down
38 changes: 36 additions & 2 deletions zkstack_cli/crates/zkstack/src/commands/chain/args/create.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
use std::{path::PathBuf, str::FromStr};
use std::{
path::{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;
use config::{
forge_interface::deploy_ecosystem::output::Erc20Token, traits::ReadConfigWithBasePath,
EcosystemConfig,
};
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,
Expand All @@ -18,6 +26,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_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,
Expand Down Expand Up @@ -67,14 +76,18 @@ pub struct ChainCreateArgs {
pub(crate) set_as_default: Option<bool>,
#[clap(long, default_value = "false")]
pub(crate) legacy_bridge: bool,
#[arg(long, help = MSG_EVM_EMULATOR_HELP, default_missing_value = "true", num_args = 0..=1)]
evm_emulator: Option<bool>,
}

impl ChainCreateArgs {
pub fn fill_values_with_prompt(
self,
shell: &Shell,
number_of_chains: u32,
l1_network: &L1Network,
possible_erc20: Vec<Erc20Token>,
link_to_code: &Path,
) -> anyhow::Result<ChainCreateArgsFinal> {
let mut chain_name = self
.chain_name
Expand Down Expand Up @@ -211,6 +224,25 @@ 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()
}
});
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)
.default(true)
Expand All @@ -227,6 +259,7 @@ impl ChainCreateArgs {
base_token,
set_as_default,
legacy_bridge: self.legacy_bridge,
evm_emulator,
})
}
}
Expand All @@ -242,6 +275,7 @@ pub struct ChainCreateArgsFinal {
pub base_token: BaseToken,
pub set_as_default: bool,
pub legacy_bridge: bool,
pub evm_emulator: bool,
}

#[derive(Debug, Clone, EnumIter, Display, PartialEq, Eq)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub(crate) async fn run(args: BuildTransactionsArgs, shell: &Shell) -> anyhow::R
logger::note(MSG_SELECTED_CONFIG, logger::object_to_string(&chain_config));

let mut genesis_config = chain_config.get_genesis_config()?;
update_from_chain_config(&mut genesis_config, &chain_config);
update_from_chain_config(&mut genesis_config, &chain_config)?;

// Copy ecosystem contracts
let mut contracts_config = config
Expand Down
3 changes: 3 additions & 0 deletions zkstack_cli/crates/zkstack/src/commands/chain/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ 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,
)
.context(MSG_ARGS_VALIDATOR_ERR)?;

Expand Down Expand Up @@ -89,6 +91,7 @@ pub(crate) fn create_chain_inner(
wallet_creation: args.wallet_creation,
shell: OnceCell::from(shell.clone()),
legacy_bridge,
evm_emulator: args.evm_emulator,
};

create_wallets(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub async fn init_configs(

// Initialize genesis config
let mut genesis_config = chain_config.get_genesis_config()?;
update_from_chain_config(&mut genesis_config, chain_config);
update_from_chain_config(&mut genesis_config, chain_config)?;
genesis_config.save_with_base_path(shell, &chain_config.configs)?;

// Initialize contracts config
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,13 @@ 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(0, &l1_network, vec![])?;
let chain = self.chain.fill_values_with_prompt(
shell,
0,
&l1_network,
vec![],
Path::new(&link_to_code),
)?;

let start_containers = self.start_containers.unwrap_or_else(|| {
PromptConfirm::new(MSG_START_CONTAINERS_PROMPT)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub async fn deploy_l1(
let deploy_config_path = DEPLOY_ECOSYSTEM_SCRIPT_PARAMS.input(&config.link_to_code);
let default_genesis_config =
GenesisConfig::read_with_base_path(shell, config.get_default_configs_path())
.context("Context")?;
.context("failed reading genesis config")?;

let wallets_config = config.get_wallets()?;
// For deploying ecosystem we only need genesis batch params
Expand Down
5 changes: 5 additions & 0 deletions zkstack_cli/crates/zkstack/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ pub(super) const MSG_BASE_TOKEN_ADDRESS_HELP: &str = "Base token address";
pub(super) const MSG_BASE_TOKEN_PRICE_NOMINATOR_HELP: &str = "Base token nominator";
pub(super) const MSG_BASE_TOKEN_PRICE_DENOMINATOR_HELP: &str = "Base token denominator";
pub(super) const MSG_SET_AS_DEFAULT_HELP: &str = "Set as default chain";
pub(super) const MSG_EVM_EMULATOR_HELP: &str = "Enable EVM emulator";
pub(super) const MSG_CHAIN_NAME_PROMPT: &str = "What do you want to name the chain?";
pub(super) const MSG_CHAIN_ID_PROMPT: &str = "What's the chain id?";
pub(super) const MSG_WALLET_CREATION_PROMPT: &str = "Select how do you want to create the wallet";
Expand All @@ -170,6 +171,7 @@ pub(super) const MSG_BASE_TOKEN_PRICE_NOMINATOR_PROMPT: &str =
pub(super) const MSG_BASE_TOKEN_PRICE_DENOMINATOR_PROMPT: &str =
"What is the base token price denominator?";
pub(super) const MSG_SET_AS_DEFAULT_PROMPT: &str = "Set this chain as default?";
pub(super) const MSG_EVM_EMULATOR_PROMPT: &str = "Enable EVM emulator?";
pub(super) const MSG_WALLET_PATH_INVALID_ERR: &str = "Invalid path";
pub(super) const MSG_NUMBER_VALIDATOR_NOT_ZERO_ERR: &str = "Number is not zero";
pub(super) const MSG_NUMBER_VALIDATOR_GREATHER_THAN_ZERO_ERR: &str =
Expand All @@ -184,6 +186,9 @@ pub(super) const MSG_WALLET_CREATION_VALIDATOR_ERR: &str =
"Localhost wallet is not supported for external networks";
pub(super) const MSG_WALLET_TOKEN_MULTIPLIER_SETTER_NOT_FOUND: &str =
"Token Multiplier Setter not found. Specify it in a wallet config";
pub(super) const MSG_EVM_EMULATOR_HASH_MISSING_ERR: &str =
"Impossible to initialize a chain with EVM emulator: the template genesis config \
does not contain EVM emulator hash";

/// Chain genesis related messages
pub(super) const MSG_L1_SECRETS_MUST_BE_PRESENTED: &str = "L1 secret must be presented";
Expand Down

0 comments on commit ffa18e1

Please sign in to comment.