Skip to content

Commit

Permalink
feat: adds config-out cli option (#394)
Browse files Browse the repository at this point in the history
  • Loading branch information
dutterbutter authored Nov 20, 2024
1 parent febc5e2 commit 5e17d02
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 7 deletions.
15 changes: 10 additions & 5 deletions src/config/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::system_contracts::Options as SystemContractsOptions;
use super::DEFAULT_DISK_CACHE_DIR;
use alloy_signer_local::coins_bip39::{English, Mnemonic};

#[derive(Debug, Parser)]
#[derive(Debug, Parser, Clone)]
#[command(
author = "Matter Labs",
version,
Expand All @@ -31,6 +31,10 @@ pub struct Cli {
/// Run in offline mode (disables all network requests).
pub offline: bool,

/// Writes output of `era-test-node` as json to user-specified file.
#[arg(long, value_name = "OUT_FILE", help_heading = "General Options")]
pub config_out: Option<String>,

#[arg(long, default_value = "8011", help_heading = "Network Options")]
/// Port to listen on (default: 8011).
pub port: Option<u16>,
Expand Down Expand Up @@ -173,7 +177,7 @@ pub struct Cli {
pub derivation_path: Option<String>,
}

#[derive(Debug, Subcommand)]
#[derive(Debug, Subcommand, Clone)]
pub enum Command {
/// Starts a new empty local network.
#[command(name = "run")]
Expand All @@ -186,7 +190,7 @@ pub enum Command {
ReplayTx(ReplayArgs),
}

#[derive(Debug, Parser)]
#[derive(Debug, Parser, Clone)]
pub struct ForkArgs {
/// Whether to fork from existing network.
/// If not set - will start a new network from genesis.
Expand All @@ -210,7 +214,7 @@ pub struct ForkArgs {
pub fork_block_number: Option<u64>,
}

#[derive(Debug, Parser)]
#[derive(Debug, Parser, Clone)]
pub struct ReplayArgs {
/// Whether to fork from existing network.
/// If not set - will start a new network from genesis.
Expand Down Expand Up @@ -240,7 +244,7 @@ impl Cli {
}
}
/// Converts the CLI arguments to a `TestNodeConfig`.
pub fn to_test_node_config(&self) -> eyre::Result<TestNodeConfig> {
pub fn into_test_node_config(self) -> eyre::Result<TestNodeConfig> {
let genesis_balance = U256::from(100u128 * 10u128.pow(18));

let vm_log_detail = if let Some(output) = self.show_outputs {
Expand Down Expand Up @@ -288,6 +292,7 @@ impl Cli {
}
}))
.with_chain_id(self.chain_id)
.set_config_out(self.config_out)
.with_evm_emulator(if self.emulate_evm { Some(true) } else { None });

if self.emulate_evm && self.dev_system_contracts != Some(SystemContractsOptions::Local) {
Expand Down
80 changes: 80 additions & 0 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ use colored::{Colorize, CustomColor};
use observability::LogLevel;
use rand::thread_rng;
use serde::Deserialize;
use serde_json::{json, to_writer, Value};
use std::collections::HashMap;
use std::fs::File;
use zksync_types::fee_model::FeeModelConfigV2;
use zksync_types::U256;

Expand Down Expand Up @@ -46,6 +49,8 @@ pub struct ForkPrintInfo {
/// Defines the configuration parameters for the [InMemoryNode].

Check warning on line 49 in src/config/mod.rs

View workflow job for this annotation

GitHub Actions / deploy

unresolved link to `InMemoryNode`
#[derive(Debug, Clone)]
pub struct TestNodeConfig {
/// Filename to write era-test-node output as json
pub config_out: Option<String>,
/// Port the node will listen on
pub port: u16,
/// Controls visibility of call logs
Expand Down Expand Up @@ -102,6 +107,7 @@ impl Default for TestNodeConfig {
let genesis_accounts = AccountGenerator::new(10).phrase(DEFAULT_MNEMONIC).gen();
Self {
// Node configuration defaults
config_out: None,
port: NODE_PORT,
show_calls: Default::default(),
show_outputs: false,
Expand Down Expand Up @@ -143,6 +149,15 @@ impl Default for TestNodeConfig {

impl TestNodeConfig {
pub fn print(&self, fork_details: Option<&ForkPrintInfo>) {
if self.config_out.is_some() {
let config_out = self.config_out.as_deref().unwrap();
to_writer(
&File::create(config_out)
.expect("Unable to create era-test-node config description file"),
&self.as_json(fork_details),
)
.expect("Failed writing json");
}
let color = CustomColor::new(13, 71, 198);

println!("{}", BANNER.custom_color(color));
Expand Down Expand Up @@ -283,6 +298,63 @@ impl TestNodeConfig {
println!("\n");
}

fn as_json(&self, fork: Option<&ForkPrintInfo>) -> Value {
let mut wallet_description = HashMap::new();
let mut available_accounts = Vec::with_capacity(self.genesis_accounts.len());
let mut private_keys = Vec::with_capacity(self.genesis_accounts.len());

for wallet in &self.genesis_accounts {
available_accounts.push(format!("{:?}", wallet.address()));
private_keys.push(format!("0x{}", hex::encode(wallet.credential().to_bytes())));
}

if let Some(ref gen) = self.account_generator {
let phrase = gen.get_phrase().to_string();
let derivation_path = gen.get_derivation_path().to_string();

wallet_description.insert("derivation_path".to_string(), derivation_path);
wallet_description.insert("mnemonic".to_string(), phrase);
};

if let Some(fork) = fork {
json!({
"available_accounts": available_accounts,
"private_keys": private_keys,
"endpoint": fork.network_rpc,
"l1_block": fork.l1_block,
"l2_block": fork.l2_block,
"block_hash": fork.fork_block_hash,
"chain_id": self.get_chain_id(),
"wallet": wallet_description,
"l1_gas_price": format!("{}", self.get_l1_gas_price()),
"l2_gas_price": format!("{}", self.get_l2_gas_price()),
"l1_pubdata_price": format!("{}", self.get_l1_pubdata_price()),
"price_scale_factor": format!("{}", self.get_price_scale()),
"limit_scale_factor": format!("{}", self.get_gas_limit_scale()),
"fee_model_config_v2": fork.fee_model_config_v2,
})
} else {
json!({
"available_accounts": available_accounts,
"private_keys": private_keys,
"wallet": wallet_description,
"chain_id": self.get_chain_id(),
"l1_gas_price": format!("{}", self.get_l1_gas_price()),
"l2_gas_price": format!("{}", self.get_l2_gas_price()),
"l1_pubdata_price": format!("{}", self.get_l1_pubdata_price()),
"price_scale_factor": format!("{}", self.get_price_scale()),
"limit_scale_factor": format!("{}", self.get_gas_limit_scale()),
})
}
}

/// Sets the file path to write the Era-test-node's config info to.
#[must_use]
pub fn set_config_out(mut self, config_out: Option<String>) -> Self {
self.config_out = config_out;
self
}

/// Set the port for the test node
#[must_use]
pub fn with_port(mut self, port: Option<u16>) -> Self {
Expand Down Expand Up @@ -579,6 +651,10 @@ impl AccountGenerator {
self
}

fn get_phrase(&self) -> &str {
&self.phrase
}

#[must_use]
pub fn chain_id(mut self, chain_id: impl Into<u32>) -> Self {
self.chain_id = chain_id.into();
Expand All @@ -595,6 +671,10 @@ impl AccountGenerator {
self
}

fn get_derivation_path(&self) -> &str {
self.derivation_path.as_deref().unwrap_or(DERIVATION_PATH)
}

pub fn gen(&self) -> Vec<PrivateKeySigner> {
let builder = MnemonicBuilder::<English>::default().phrase(self.phrase.as_str());

Expand Down
5 changes: 3 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,9 @@ async fn main() -> anyhow::Result<()> {
Cli::deprecated_config_option();

let opt = Cli::parse();
let command = opt.command.clone();

let mut config = opt.to_test_node_config().map_err(|e| anyhow!(e))?;
let mut config = opt.into_test_node_config().map_err(|e| anyhow!(e))?;

let log_level_filter = LevelFilter::from(config.log_level);
let log_file = File::create(&config.log_file_path)?;
Expand All @@ -118,7 +119,7 @@ async fn main() -> anyhow::Result<()> {
Observability::init(vec!["era_test_node".into()], log_level_filter, log_file)?;

// Use `Command::Run` as default.
let command = opt.command.as_ref().unwrap_or(&Command::Run);
let command = command.as_ref().unwrap_or(&Command::Run);
let fork_details = match command {
Command::Run => {
if config.offline {
Expand Down

0 comments on commit 5e17d02

Please sign in to comment.