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