anvil_zksync_config/
config.rs

1use crate::constants::*;
2use crate::types::*;
3use alloy::primitives::hex;
4use alloy::signers::local::PrivateKeySigner;
5use anvil_zksync_common::cache::{CacheConfig, DEFAULT_DISK_CACHE_DIR};
6use anvil_zksync_common::sh_println;
7use anvil_zksync_common::utils::cost::{format_eth, format_gwei};
8use anvil_zksync_types::{
9    LogLevel, ShowGasDetails, ShowStorageLogs, ShowVMDetails, TransactionOrder,
10};
11use colored::{Colorize, CustomColor};
12use serde_json::{Value, json, to_writer};
13use std::collections::HashMap;
14use std::fs::File;
15use std::net::{IpAddr, Ipv4Addr};
16use std::path::PathBuf;
17use std::time::Duration;
18use zksync_types::fee_model::{BaseTokenConversionRatio, FeeModelConfigV2};
19use zksync_types::{ProtocolVersionId, U256};
20
21pub const VERSION_MESSAGE: &str = concat!(env!("CARGO_PKG_VERSION"));
22
23/// Protocol version that is used in anvil-zksync by default. Should match what is currently
24/// deployed to mainnet.
25pub const DEFAULT_PROTOCOL_VERSION: ProtocolVersionId = ProtocolVersionId::Version27;
26
27const BANNER: &str = r#"
28                      _  _         _____ _  __
29  __ _  _ __  __   __(_)| |       |__  /| |/ / ___  _   _  _ __    ___
30 / _` || '_ \ \ \ / /| || | _____   / / | ' / / __|| | | || '_ \  / __|
31| (_| || | | | \ V / | || ||_____| / /_ | . \ \__ \| |_| || | | || (__
32 \__,_||_| |_|  \_/  |_||_|       /____||_|\_\|___/ \__, ||_| |_| \___|
33                                                    |___/
34"#;
35/// Struct to hold the details of the fork for display purposes
36pub struct ForkPrintInfo {
37    pub network_rpc: String,
38    pub l1_block: String,
39    pub l2_block: String,
40    pub block_timestamp: String,
41    pub fork_block_hash: String,
42    pub fee_model_config_v2: FeeModelConfigV2,
43}
44
45/// Defines the configuration parameters for the [InMemoryNode].
46#[derive(Debug, Clone)]
47pub struct TestNodeConfig {
48    /// Filename to write anvil-zksync output as json
49    pub config_out: Option<String>,
50    /// Port the node will listen on
51    pub port: u16,
52    /// Print node config on startup if true
53    pub show_node_config: bool,
54    /// Level of detail for storage logs
55    pub show_storage_logs: ShowStorageLogs,
56    /// Level of detail for VM execution logs
57    pub show_vm_details: ShowVMDetails,
58    /// Level of detail for gas usage logs
59    pub show_gas_details: ShowGasDetails,
60    /// Numeric verbosity derived from repeated `-v` flags (e.g. -v = 1, -vv = 2, etc.).
61    pub verbosity: u8,
62    /// Don’t print anything on startup if true
63    pub silent: bool,
64    /// Configuration for system contracts
65    pub system_contracts_options: SystemContractsOptions,
66    /// Path to the system contracts directory
67    pub system_contracts_path: Option<PathBuf>,
68    /// Protocol version to use for new blocks. Also affects revision of built-in contracts that
69    /// will get deployed (if applicable)
70    pub protocol_version: Option<ProtocolVersionId>,
71    /// Directory to override bytecodes
72    pub override_bytecodes_dir: Option<String>,
73    /// Enable bytecode compression
74    pub bytecode_compression: bool,
75    /// Enables EVM interpreter mode
76    pub use_evm_interpreter: bool,
77    /// Enables ZKsyncOS mode (experimental)
78    pub zksync_os: ZKsyncOsConfig,
79    /// Optional chain ID for the node
80    pub chain_id: Option<u32>,
81    /// L1 gas price (optional override)
82    pub l1_gas_price: Option<u64>,
83    /// L2 gas price (optional override)
84    pub l2_gas_price: Option<u64>,
85    /// Price for pubdata on L1
86    pub l1_pubdata_price: Option<u64>,
87    /// L1 gas price scale factor for gas estimation
88    pub price_scale_factor: Option<f64>,
89    /// The factor by which to scale the gasLimit
90    pub limit_scale_factor: Option<f32>,
91    /// Logging verbosity level
92    pub log_level: LogLevel,
93    /// Path to the log file
94    pub log_file_path: String,
95    /// Directory to store cache files (defaults to `./cache`)
96    pub cache_dir: String,
97    /// Cache configuration for the test node
98    pub cache_config: CacheConfig,
99    /// Signer accounts that will be initialized with `genesis_balance` in the genesis block.
100    pub genesis_accounts: Vec<PrivateKeySigner>,
101    /// Native token balance of every genesis account in the genesis block
102    pub genesis_balance: U256,
103    /// The generator used to generate the dev accounts
104    pub account_generator: Option<AccountGenerator>,
105    /// Signer accounts that can sign messages/transactions
106    pub signer_accounts: Vec<PrivateKeySigner>,
107    /// The genesis to use to initialize the node
108    pub genesis: Option<Genesis>,
109    /// Genesis block timestamp
110    pub genesis_timestamp: Option<u64>,
111    /// Enable auto impersonation of accounts on startup
112    pub enable_auto_impersonate: bool,
113    /// Whether the node operates in offline mode
114    pub offline: bool,
115    /// The host the server will listen on
116    pub host: Vec<IpAddr>,
117    /// Whether we need to enable the health check endpoint.
118    pub health_check_endpoint: bool,
119    /// Block time in seconds for interval sealing.
120    /// If unset, node seals a new block as soon as there is at least one transaction.
121    pub block_time: Option<Duration>,
122    /// Maximum number of transactions per block
123    pub max_transactions: usize,
124    /// Disable automatic sealing mode and use `BlockSealer::Noop` instead
125    pub no_mining: bool,
126    /// The cors `allow_origin` header
127    pub allow_origin: String,
128    /// Disable CORS if true
129    pub no_cors: bool,
130    /// How transactions are sorted in the mempool
131    pub transaction_order: TransactionOrder,
132    /// Path to load/dump the state from
133    pub state: Option<PathBuf>,
134    /// Path to dump the state to
135    pub dump_state: Option<PathBuf>,
136    /// Interval to dump the state
137    pub state_interval: Option<u64>,
138    /// Preserve historical states
139    pub preserve_historical_states: bool,
140    /// State to load
141    pub load_state: Option<PathBuf>,
142    /// L1 configuration, disabled if `None`
143    pub l1_config: Option<L1Config>,
144    /// Whether to automatically execute L1 batches
145    pub auto_execute_l1: bool,
146    /// Base token configuration
147    pub base_token_config: BaseTokenConfig,
148}
149
150#[derive(Debug, Clone)]
151pub enum L1Config {
152    /// Spawn a separate `anvil` process and initialize it to use as L1.
153    Spawn {
154        /// Port the spawned L1 anvil node will listen on
155        port: u16,
156    },
157    /// Use externally set up L1.
158    External {
159        /// Address of L1 node's JSON-RPC endpoint
160        address: String,
161    },
162}
163
164#[derive(Debug, Clone)]
165pub struct BaseTokenConfig {
166    /// Base token symbol to use instead of 'ETH'.
167    pub symbol: String,
168    /// Base token conversion ratio (e.g., '40000', '628/17').
169    pub ratio: BaseTokenConversionRatio,
170}
171
172impl Default for BaseTokenConfig {
173    fn default() -> Self {
174        Self {
175            symbol: "ETH".to_string(),
176            ratio: BaseTokenConversionRatio::default(),
177        }
178    }
179}
180
181impl Default for TestNodeConfig {
182    fn default() -> Self {
183        // generate some random wallets
184        let genesis_accounts = AccountGenerator::new(10)
185            .phrase(DEFAULT_MNEMONIC)
186            .generate();
187        Self {
188            // Node configuration defaults
189            config_out: None,
190            port: NODE_PORT,
191            show_node_config: true,
192            show_storage_logs: Default::default(),
193            show_vm_details: Default::default(),
194            show_gas_details: Default::default(),
195            verbosity: 0,
196            silent: false,
197            system_contracts_options: Default::default(),
198            system_contracts_path: None,
199            protocol_version: None,
200            override_bytecodes_dir: None,
201            bytecode_compression: false,
202            use_evm_interpreter: false,
203            zksync_os: Default::default(),
204            chain_id: None,
205
206            // Gas configuration defaults
207            l1_gas_price: None,
208            l2_gas_price: None,
209            l1_pubdata_price: None,
210            price_scale_factor: None,
211            limit_scale_factor: None,
212
213            // Log configuration defaults
214            log_level: Default::default(),
215            log_file_path: String::from(DEFAULT_LOG_FILE_PATH),
216
217            // Cache configuration default
218            cache_dir: String::from(DEFAULT_DISK_CACHE_DIR),
219            cache_config: Default::default(),
220
221            // Account generator
222            account_generator: None,
223            genesis_accounts: genesis_accounts.clone(),
224            signer_accounts: genesis_accounts,
225            enable_auto_impersonate: false,
226            // 100ETH default balance
227            genesis_balance: U256::from(100u128 * 10u128.pow(18)),
228            genesis_timestamp: Some(NON_FORK_FIRST_BLOCK_TIMESTAMP),
229            genesis: None,
230
231            // Offline mode disabled by default
232            offline: false,
233            host: vec![IpAddr::V4(Ipv4Addr::LOCALHOST)],
234            health_check_endpoint: false,
235
236            // Block sealing configuration default
237            block_time: None,
238            no_mining: false,
239
240            max_transactions: 1000,
241            transaction_order: TransactionOrder::Fifo,
242
243            // Server configuration
244            allow_origin: "*".to_string(),
245            no_cors: false,
246
247            // state configuration
248            state: None,
249            dump_state: None,
250            state_interval: None,
251            preserve_historical_states: false,
252            load_state: None,
253            l1_config: None,
254            auto_execute_l1: false,
255            base_token_config: BaseTokenConfig::default(),
256        }
257    }
258}
259
260impl TestNodeConfig {
261    pub fn protocol_version(&self) -> ProtocolVersionId {
262        match self.system_contracts_options {
263            SystemContractsOptions::BuiltIn => self
264                .protocol_version
265                .unwrap_or(DEFAULT_PROTOCOL_VERSION),
266            SystemContractsOptions::Local =>
267                self.protocol_version.expect("cannot deduce protocol version when using local contracts; please specify --protocol-version explicitly"),
268            SystemContractsOptions::BuiltInWithoutSecurity => self
269                .protocol_version
270                .unwrap_or(DEFAULT_PROTOCOL_VERSION),
271        }
272    }
273}
274
275impl TestNodeConfig {
276    pub fn print(&self, fork_details: Option<&ForkPrintInfo>) {
277        if let Some(config_out) = self.config_out.as_deref() {
278            let file = File::create(config_out)
279                .expect("Unable to create anvil-zksync config description file");
280            to_writer(&file, &self.as_json(fork_details)).expect("Failed writing json");
281        }
282
283        if self.silent || !self.show_node_config {
284            return;
285        }
286
287        let color = CustomColor::new(13, 71, 198);
288
289        // Banner, version and repository section.
290        sh_println!(
291            r#"
292{}
293Version:        {}
294Repository:     {}
295
296"#,
297            BANNER.custom_color(color),
298            VERSION_MESSAGE.green(),
299            "https://github.com/matter-labs/anvil-zksync".green()
300        );
301
302        // Rich Accounts.
303        let balance = format_eth(self.genesis_balance);
304        let mut rich_accounts = String::new();
305        for (idx, account) in self.genesis_accounts.iter().enumerate() {
306            rich_accounts.push_str(&format!("({}) {} ({})\n", idx, account.address(), balance));
307        }
308        sh_println!(
309            r#"
310Rich Accounts
311========================
312{}
313"#,
314            rich_accounts
315        );
316
317        // Private Keys.
318        let mut private_keys = String::new();
319        for (idx, account) in self.genesis_accounts.iter().enumerate() {
320            let private_key = hex::encode(account.credential().to_bytes());
321            private_keys.push_str(&format!("({idx}) 0x{private_key}\n"));
322        }
323        sh_println!(
324            r#"
325Private Keys
326========================
327{}
328"#,
329            private_keys
330        );
331
332        // Wallet configuration.
333        if let Some(ref generator) = self.account_generator {
334            sh_println!(
335                r#"
336Wallet
337========================
338Mnemonic:            {}
339Derivation path:     {}
340"#,
341                generator.get_phrase().green(),
342                generator.get_derivation_path().green()
343            );
344        }
345
346        // Either print Fork Details (if provided) or the Network Configuration.
347        if let Some(fd) = fork_details {
348            sh_println!(
349                r#"
350Fork Details
351========================
352Network RPC:               {}
353Chain ID:                  {}
354L1 Batch #:                {}
355L2 Block #:                {}
356Block Timestamp:           {}
357Fork Block Hash:           {}
358Compute Overhead Part:     {}
359Pubdata Overhead Part:     {}
360Batch Overhead L1 Gas:     {}
361Max Gas Per Batch:         {}
362Max Pubdata Per Batch:     {}
363"#,
364                fd.network_rpc.green(),
365                self.get_chain_id().to_string().green(),
366                fd.l1_block.green(),
367                fd.l2_block.green(),
368                fd.block_timestamp.to_string().green(),
369                format!("{:#}", fd.fork_block_hash).green(),
370                fd.fee_model_config_v2
371                    .compute_overhead_part
372                    .to_string()
373                    .green(),
374                fd.fee_model_config_v2
375                    .pubdata_overhead_part
376                    .to_string()
377                    .green(),
378                fd.fee_model_config_v2
379                    .batch_overhead_l1_gas
380                    .to_string()
381                    .green(),
382                fd.fee_model_config_v2.max_gas_per_batch.to_string().green(),
383                fd.fee_model_config_v2
384                    .max_pubdata_per_batch
385                    .to_string()
386                    .green()
387            );
388        } else {
389            sh_println!(
390                r#"
391Network Configuration
392========================
393Chain ID: {}
394"#,
395                self.chain_id
396                    .unwrap_or(TEST_NODE_NETWORK_ID)
397                    .to_string()
398                    .green()
399            );
400        }
401
402        // Gas Configuration.
403        sh_println!(
404            r#"
405Gas Configuration
406========================
407L1 Gas Price (gwei):               {}
408L2 Gas Price (gwei):               {}
409L1 Pubdata Price (gwei):           {}
410Estimated Gas Price Scale Factor:  {}
411Estimated Gas Limit Scale Factor:  {}
412"#,
413            format_gwei(self.get_l1_gas_price().into()).green(),
414            format_gwei(self.get_l2_gas_price().into()).green(),
415            format_gwei(self.get_l1_pubdata_price().into()).green(),
416            self.get_price_scale().to_string().green(),
417            self.get_gas_limit_scale().to_string().green()
418        );
419
420        // Genesis Timestamp.
421        sh_println!(
422            r#"
423Genesis Timestamp
424========================
425{}
426"#,
427            self.get_genesis_timestamp().to_string().green()
428        );
429
430        // Node Configuration.
431        sh_println!(
432            r#"
433Node Configuration
434========================
435Port:                  {}
436EVM Interpreter:       {}
437Health Check Endpoint: {}
438ZKsync OS:             {}
439L1:                    {}
440"#,
441            self.port,
442            if self.use_evm_interpreter {
443                "Enabled".green()
444            } else {
445                "Disabled".red()
446            },
447            if self.health_check_endpoint {
448                "Enabled".green()
449            } else {
450                "Disabled".red()
451            },
452            if self.zksync_os.zksync_os {
453                "Enabled".green()
454            } else {
455                "Disabled".red()
456            },
457            if self.l1_config.is_some() {
458                "Enabled".green()
459            } else {
460                "Disabled".red()
461            }
462        );
463
464        // L1 Configuration
465        match self.l1_config.as_ref() {
466            Some(L1Config::Spawn { port }) => {
467                sh_println!(
468                    r#"
469L1 Configuration (Spawned)
470========================
471Port: {port}
472"#
473                );
474            }
475            Some(L1Config::External { address }) => {
476                sh_println!(
477                    r#"
478L1 Configuration (External)
479========================
480Address: {address}
481"#
482                );
483            }
484            None => {}
485        }
486
487        // Listening addresses.
488        let mut listening = String::new();
489        listening.push_str("\n========================================\n");
490        for host in &self.host {
491            listening.push_str(&format!(
492                "  Listening on {}:{}\n",
493                host.to_string().green(),
494                self.port.to_string().green()
495            ));
496        }
497        listening.push_str("========================================\n");
498        sh_println!("{}", listening);
499    }
500
501    fn as_json(&self, fork: Option<&ForkPrintInfo>) -> Value {
502        let mut wallet_description = HashMap::new();
503        let mut available_accounts = Vec::with_capacity(self.genesis_accounts.len());
504        let mut private_keys = Vec::with_capacity(self.genesis_accounts.len());
505
506        for wallet in &self.genesis_accounts {
507            available_accounts.push(format!("{:?}", wallet.address()));
508            private_keys.push(format!("0x{}", hex::encode(wallet.credential().to_bytes())));
509        }
510
511        if let Some(generator) = &self.account_generator {
512            let phrase = generator.get_phrase().to_string();
513            let derivation_path = generator.get_derivation_path().to_string();
514
515            wallet_description.insert("derivation_path".to_string(), derivation_path);
516            wallet_description.insert("mnemonic".to_string(), phrase);
517        };
518
519        if let Some(fork) = fork {
520            json!({
521              "available_accounts": available_accounts,
522              "private_keys": private_keys,
523              "endpoint": fork.network_rpc,
524              "l1_block": fork.l1_block,
525              "l2_block": fork.l2_block,
526              "block_hash": fork.fork_block_hash,
527              "chain_id": self.get_chain_id(),
528              "wallet": wallet_description,
529              "l1_gas_price": format!("{}", self.get_l1_gas_price()),
530              "l2_gas_price": format!("{}", self.get_l2_gas_price()),
531              "l1_pubdata_price": format!("{}", self.get_l1_pubdata_price()),
532              "price_scale_factor": format!("{}", self.get_price_scale()),
533              "limit_scale_factor": format!("{}", self.get_gas_limit_scale()),
534              "fee_model_config_v2": fork.fee_model_config_v2,
535            })
536        } else {
537            json!({
538              "available_accounts": available_accounts,
539              "private_keys": private_keys,
540              "wallet": wallet_description,
541              "chain_id": self.get_chain_id(),
542              "l1_gas_price": format!("{}", self.get_l1_gas_price()),
543              "l2_gas_price": format!("{}", self.get_l2_gas_price()),
544              "l1_pubdata_price": format!("{}", self.get_l1_pubdata_price()),
545              "price_scale_factor": format!("{}", self.get_price_scale()),
546              "limit_scale_factor": format!("{}", self.get_gas_limit_scale()),
547            })
548        }
549    }
550
551    /// Sets the file path to write the anvil-zksync config info to.
552    #[must_use]
553    pub fn set_config_out(mut self, config_out: Option<String>) -> Self {
554        self.config_out = config_out;
555        self
556    }
557
558    /// Set the port for the test node
559    #[must_use]
560    pub fn with_port(mut self, port: Option<u16>) -> Self {
561        if let Some(port) = port {
562            self.port = port;
563        }
564        self
565    }
566
567    /// Get the port for the test node
568    pub fn get_port(&self) -> u16 {
569        self.port
570    }
571
572    /// Set the chain ID for the test node
573    #[must_use]
574    pub fn with_chain_id(mut self, chain_id: Option<u32>) -> Self {
575        if let Some(chain_id) = chain_id {
576            self.chain_id = Some(chain_id);
577        }
578        self
579    }
580
581    /// Get the chain ID for the test node
582    pub fn get_chain_id(&self) -> u32 {
583        self.chain_id.unwrap_or(TEST_NODE_NETWORK_ID)
584    }
585
586    /// Update the chain ID
587    pub fn update_chain_id(&mut self, chain_id: Option<u32>) -> &mut Self {
588        self.chain_id = chain_id;
589        self
590    }
591
592    /// Set the system contracts configuration option
593    #[must_use]
594    pub fn with_system_contracts(mut self, option: Option<SystemContractsOptions>) -> Self {
595        if let Some(option) = option {
596            self.system_contracts_options = option;
597        }
598        self
599    }
600
601    /// Set the system contracts path
602    #[must_use]
603    pub fn with_system_contracts_path(mut self, path: Option<PathBuf>) -> Self {
604        if let Some(path) = path {
605            self.system_contracts_path = Some(path);
606        }
607        self
608    }
609
610    /// Set the protocol version configuration option
611    #[must_use]
612    pub fn with_protocol_version(mut self, protocol_version: Option<ProtocolVersionId>) -> Self {
613        self.protocol_version = protocol_version;
614        self
615    }
616
617    /// Get the system contracts configuration option
618    pub fn get_system_contracts(&self) -> SystemContractsOptions {
619        self.system_contracts_options
620    }
621
622    /// Set the override bytecodes directory
623    #[must_use]
624    pub fn with_override_bytecodes_dir(mut self, dir: Option<String>) -> Self {
625        if let Some(dir) = dir {
626            self.override_bytecodes_dir = Some(dir);
627        }
628        self
629    }
630
631    /// Get the override bytecodes directory
632    pub fn get_override_bytecodes_dir(&self) -> Option<&String> {
633        self.override_bytecodes_dir.as_ref()
634    }
635
636    /// Set whether bytecode compression is enforced
637    #[must_use]
638    pub fn with_enforce_bytecode_compression(mut self, enforce: Option<bool>) -> Self {
639        if let Some(enforce) = enforce {
640            self.bytecode_compression = enforce;
641        }
642        self
643    }
644
645    /// Check if bytecode compression enforcement is enabled
646    pub fn is_bytecode_compression_enforced(&self) -> bool {
647        self.bytecode_compression
648    }
649
650    /// Enable or disable EVM emulation
651    #[must_use]
652    pub fn with_evm_interpreter(mut self, enable: Option<bool>) -> Self {
653        if let Some(enable) = enable {
654            self.use_evm_interpreter = enable;
655        }
656        self
657    }
658
659    /// Enable or disable ZKsync OS
660    #[must_use]
661    pub fn with_zksync_os(mut self, zksync_os: ZKsyncOsConfig) -> Self {
662        self.zksync_os = zksync_os;
663        self
664    }
665
666    /// Get the EVM interpreter status
667    pub fn is_evm_interpreter_enabled(&self) -> bool {
668        self.use_evm_interpreter
669    }
670
671    /// Set the L1 gas price
672    #[must_use]
673    pub fn with_l1_gas_price(mut self, price: Option<u64>) -> Self {
674        if let Some(price) = price {
675            self.l1_gas_price = Some(price);
676        }
677        self
678    }
679
680    /// Get the L1 gas price
681    pub fn get_l1_gas_price(&self) -> u64 {
682        self.l1_gas_price.unwrap_or(DEFAULT_L1_GAS_PRICE)
683    }
684
685    /// Update the L1 gas price
686    pub fn update_l1_gas_price(&mut self, price: Option<u64>) -> &mut Self {
687        self.l1_gas_price = price;
688        self
689    }
690
691    /// Set the L2 gas price
692    #[must_use]
693    pub fn with_l2_gas_price(mut self, price: Option<u64>) -> Self {
694        if let Some(price) = price {
695            self.l2_gas_price = Some(price);
696        }
697        self
698    }
699
700    /// Get the L2 gas price
701    pub fn get_l2_gas_price(&self) -> u64 {
702        self.l2_gas_price.unwrap_or(DEFAULT_L2_GAS_PRICE)
703    }
704
705    /// Update the L2 gas price
706    pub fn update_l2_gas_price(&mut self, price: Option<u64>) -> &mut Self {
707        self.l2_gas_price = price;
708        self
709    }
710
711    /// Set the L1 pubdata price
712    #[must_use]
713    pub fn with_l1_pubdata_price(mut self, price: Option<u64>) -> Self {
714        self.l1_pubdata_price = price;
715        self
716    }
717
718    /// Get the L1 pubdata price
719    pub fn get_l1_pubdata_price(&self) -> u64 {
720        self.l1_pubdata_price.unwrap_or(DEFAULT_FAIR_PUBDATA_PRICE)
721    }
722
723    /// Update the L1 pubdata price
724    pub fn update_l1_pubdata_price(&mut self, price: Option<u64>) -> &mut Self {
725        self.l1_pubdata_price = price;
726        self
727    }
728
729    /// Set the log level
730    #[must_use]
731    pub fn with_log_level(mut self, level: Option<LogLevel>) -> Self {
732        if let Some(level) = level {
733            self.log_level = level;
734        }
735        self
736    }
737
738    /// Get the log level
739    pub fn get_log_level(&self) -> LogLevel {
740        self.log_level
741    }
742
743    /// Gets the cache directory
744    pub fn get_cache_dir(&self) -> &str {
745        &self.cache_dir
746    }
747
748    /// Set the cache directory
749    #[must_use]
750    pub fn with_cache_dir(mut self, dir: Option<String>) -> Self {
751        if let Some(dir) = dir {
752            self.cache_dir = dir;
753        }
754        self
755    }
756
757    /// Set the cache configuration
758    #[must_use]
759    pub fn with_cache_config(mut self, config: Option<CacheConfig>) -> Self {
760        if let Some(config) = config {
761            self.cache_config = config;
762        }
763        self
764    }
765
766    /// Get the cache configuration
767    pub fn get_cache_config(&self) -> &CacheConfig {
768        &self.cache_config
769    }
770
771    /// Set the log file path
772    #[must_use]
773    pub fn with_log_file_path(mut self, path: Option<String>) -> Self {
774        if let Some(path) = path {
775            self.log_file_path = path;
776        }
777        self
778    }
779
780    /// Get the log file path
781    pub fn get_log_file_path(&self) -> &str {
782        &self.log_file_path
783    }
784
785    /// Sets the numeric verbosity derived from repeated `-v` flags
786    #[must_use]
787    pub fn with_verbosity_level(mut self, verbosity: u8) -> Self {
788        self.verbosity = verbosity;
789        self
790    }
791
792    /// Get the numeric verbosity derived from repeated `-v` flags
793    pub fn get_verbosity_level(&self) -> u8 {
794        self.verbosity
795    }
796
797    /// Enable or disable silent mode
798    #[must_use]
799    pub fn with_silent(mut self, silent: Option<bool>) -> Self {
800        if let Some(silent) = silent {
801            self.silent = silent;
802        }
803        self
804    }
805
806    /// Enable or disable printing node config on startup
807    #[must_use]
808    pub fn with_show_node_config(mut self, show_node_config: Option<bool>) -> Self {
809        if let Some(show_node_config) = show_node_config {
810            self.show_node_config = show_node_config;
811        }
812        self
813    }
814
815    /// Set the visibility of storage logs
816    #[must_use]
817    pub fn with_show_storage_logs(mut self, show_storage_logs: Option<ShowStorageLogs>) -> Self {
818        if let Some(show_storage_logs) = show_storage_logs {
819            self.show_storage_logs = show_storage_logs;
820        }
821        self
822    }
823
824    /// Get the visibility of storage logs
825    pub fn get_show_storage_logs(&self) -> ShowStorageLogs {
826        self.show_storage_logs
827    }
828
829    /// Set the detail level of VM execution logs
830    #[must_use]
831    pub fn with_vm_log_detail(mut self, detail: Option<ShowVMDetails>) -> Self {
832        if let Some(detail) = detail {
833            self.show_vm_details = detail;
834        }
835        self
836    }
837
838    /// Get the detail level of VM execution logs
839    pub fn get_vm_log_detail(&self) -> ShowVMDetails {
840        self.show_vm_details
841    }
842
843    /// Set the visibility of gas usage logs
844    #[must_use]
845    pub fn with_show_gas_details(mut self, show_gas_details: Option<ShowGasDetails>) -> Self {
846        if let Some(show_gas_details) = show_gas_details {
847            self.show_gas_details = show_gas_details;
848        }
849        self
850    }
851
852    /// Get the visibility of gas usage logs
853    pub fn get_show_gas_details(&self) -> ShowGasDetails {
854        self.show_gas_details
855    }
856
857    /// Set the gas limit scale factor
858    #[must_use]
859    pub fn with_gas_limit_scale(mut self, scale: Option<f32>) -> Self {
860        if let Some(scale) = scale {
861            self.limit_scale_factor = Some(scale);
862        }
863        self
864    }
865
866    /// Get the gas limit scale factor
867    pub fn get_gas_limit_scale(&self) -> f32 {
868        self.limit_scale_factor
869            .unwrap_or(DEFAULT_ESTIMATE_GAS_SCALE_FACTOR)
870    }
871
872    /// Update the gas limit scale factor
873    pub fn update_gas_limit_scale(&mut self, scale: Option<f32>) -> &mut Self {
874        self.limit_scale_factor = scale;
875        self
876    }
877
878    /// Set the price scale factor
879    #[must_use]
880    pub fn with_price_scale(mut self, scale: Option<f64>) -> Self {
881        if let Some(scale) = scale {
882            self.price_scale_factor = Some(scale);
883        }
884        self
885    }
886
887    /// Get the price scale factor
888    pub fn get_price_scale(&self) -> f64 {
889        self.price_scale_factor
890            .unwrap_or(DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR)
891    }
892
893    /// Updates the price scale factor
894    pub fn update_price_scale(&mut self, scale: Option<f64>) -> &mut Self {
895        self.price_scale_factor = scale;
896        self
897    }
898
899    /// Sets the balance of the genesis accounts in the genesis block
900    #[must_use]
901    pub fn with_genesis_balance<U: Into<U256>>(mut self, balance: U) -> Self {
902        self.genesis_balance = balance.into();
903        self
904    }
905
906    /// Sets the genesis accounts.
907    #[must_use]
908    pub fn with_genesis_accounts(mut self, accounts: Vec<PrivateKeySigner>) -> Self {
909        self.genesis_accounts = accounts;
910        self
911    }
912
913    /// Sets the signer accounts
914    #[must_use]
915    pub fn with_signer_accounts(mut self, accounts: Vec<PrivateKeySigner>) -> Self {
916        self.signer_accounts = accounts;
917        self
918    }
919
920    /// Sets both the genesis accounts and the signer accounts
921    /// so that `genesis_accounts == accounts`
922    #[must_use]
923    pub fn with_account_generator(mut self, generator: AccountGenerator) -> Self {
924        let accounts = generator.generate();
925        self.account_generator = Some(generator);
926        self.with_signer_accounts(accounts.clone())
927            .with_genesis_accounts(accounts)
928    }
929
930    /// Sets the genesis timestamp
931    #[must_use]
932    pub fn with_genesis_timestamp(mut self, timestamp: Option<u64>) -> Self {
933        self.genesis_timestamp = timestamp;
934        self
935    }
936
937    /// Returns the genesis timestamp to use
938    pub fn get_genesis_timestamp(&self) -> u64 {
939        self.genesis_timestamp
940            .unwrap_or(NON_FORK_FIRST_BLOCK_TIMESTAMP)
941    }
942
943    /// Sets the init genesis (genesis.json)
944    #[must_use]
945    pub fn with_genesis(mut self, genesis: Option<Genesis>) -> Self {
946        self.genesis = genesis;
947        self
948    }
949
950    /// Sets whether to enable autoImpersonate
951    #[must_use]
952    pub fn with_auto_impersonate(mut self, enable_auto_impersonate: bool) -> Self {
953        self.enable_auto_impersonate = enable_auto_impersonate;
954        self
955    }
956
957    /// Set the offline mode
958    #[must_use]
959    pub fn with_offline(mut self, offline: Option<bool>) -> Self {
960        if let Some(offline) = offline {
961            self.offline = offline;
962        }
963        self
964    }
965
966    /// Get the offline mode status
967    pub fn is_offline(&self) -> bool {
968        self.offline
969    }
970
971    /// Sets the host the server will listen on
972    #[must_use]
973    pub fn with_host(mut self, host: Vec<IpAddr>) -> Self {
974        self.host = if host.is_empty() {
975            vec![IpAddr::V4(Ipv4Addr::LOCALHOST)]
976        } else {
977            host
978        };
979        self
980    }
981    /// Set the health check endpoint mode
982    #[must_use]
983    pub fn with_health_check_endpoint(mut self, health_check_endpoint: Option<bool>) -> Self {
984        if let Some(health_check_endpoint) = health_check_endpoint {
985            self.health_check_endpoint = health_check_endpoint;
986        }
987        self
988    }
989
990    /// Get the health check endpoint mode status
991    pub fn is_health_check_endpoint_endpoint_enabled(&self) -> bool {
992        self.health_check_endpoint
993    }
994
995    /// Set the block time
996    #[must_use]
997    pub fn with_block_time(mut self, block_time: Option<Duration>) -> Self {
998        self.block_time = block_time;
999        self
1000    }
1001
1002    /// If set to `true` auto sealing will be disabled
1003    #[must_use]
1004    pub fn with_no_mining(mut self, no_mining: bool) -> Self {
1005        self.no_mining = no_mining;
1006        self
1007    }
1008
1009    // Set transactions order in the mempool
1010    #[must_use]
1011    pub fn with_transaction_order(mut self, transaction_order: TransactionOrder) -> Self {
1012        self.transaction_order = transaction_order;
1013        self
1014    }
1015
1016    /// Set allow_origin CORS header
1017    #[must_use]
1018    pub fn with_allow_origin(mut self, allow_origin: String) -> Self {
1019        self.allow_origin = allow_origin;
1020        self
1021    }
1022
1023    /// Enable or disable CORS
1024    #[must_use]
1025    pub fn with_no_cors(mut self, no_cors: bool) -> Self {
1026        self.no_cors = no_cors;
1027        self
1028    }
1029
1030    /// Set the state
1031    #[must_use]
1032    pub fn with_state(mut self, state: Option<PathBuf>) -> Self {
1033        self.state = state;
1034        self
1035    }
1036
1037    /// Set the state dump path
1038    #[must_use]
1039    pub fn with_dump_state(mut self, dump_state: Option<PathBuf>) -> Self {
1040        self.dump_state = dump_state;
1041        self
1042    }
1043
1044    /// Set the state dump interval
1045    #[must_use]
1046    pub fn with_state_interval(mut self, state_interval: Option<u64>) -> Self {
1047        self.state_interval = state_interval;
1048        self
1049    }
1050
1051    /// Set preserve historical states
1052    #[must_use]
1053    pub fn with_preserve_historical_states(mut self, preserve_historical_states: bool) -> Self {
1054        self.preserve_historical_states = preserve_historical_states;
1055        self
1056    }
1057
1058    /// Set the state to load
1059    #[must_use]
1060    pub fn with_load_state(mut self, load_state: Option<PathBuf>) -> Self {
1061        self.load_state = load_state;
1062        self
1063    }
1064
1065    /// Set the L1 config
1066    #[must_use]
1067    pub fn with_l1_config(mut self, l1_config: Option<L1Config>) -> Self {
1068        self.l1_config = l1_config;
1069        self
1070    }
1071
1072    /// Set the auto L1 execution
1073    #[must_use]
1074    pub fn with_auto_execute_l1(mut self, auto_execute_l1: Option<bool>) -> Self {
1075        self.auto_execute_l1 = auto_execute_l1.unwrap_or(false);
1076        self
1077    }
1078
1079    /// Set the base token config
1080    #[must_use]
1081    pub fn with_base_token_config(mut self, base_token_config: BaseTokenConfig) -> Self {
1082        self.base_token_config = base_token_config;
1083        self
1084    }
1085}