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
23pub const DEFAULT_PROTOCOL_VERSION: ProtocolVersionId = ProtocolVersionId::Version27;
26
27const BANNER: &str = r#"
28 _ _ _____ _ __
29 __ _ _ __ __ __(_)| | |__ /| |/ / ___ _ _ _ __ ___
30 / _` || '_ \ \ \ / /| || | _____ / / | ' / / __|| | | || '_ \ / __|
31| (_| || | | | \ V / | || ||_____| / /_ | . \ \__ \| |_| || | | || (__
32 \__,_||_| |_| \_/ |_||_| /____||_|\_\|___/ \__, ||_| |_| \___|
33 |___/
34"#;
35pub 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#[derive(Debug, Clone)]
47pub struct TestNodeConfig {
48 pub config_out: Option<String>,
50 pub port: u16,
52 pub show_node_config: bool,
54 pub show_storage_logs: ShowStorageLogs,
56 pub show_vm_details: ShowVMDetails,
58 pub show_gas_details: ShowGasDetails,
60 pub verbosity: u8,
62 pub silent: bool,
64 pub system_contracts_options: SystemContractsOptions,
66 pub system_contracts_path: Option<PathBuf>,
68 pub protocol_version: Option<ProtocolVersionId>,
71 pub override_bytecodes_dir: Option<String>,
73 pub bytecode_compression: bool,
75 pub use_evm_interpreter: bool,
77 pub zksync_os: ZKsyncOsConfig,
79 pub chain_id: Option<u32>,
81 pub l1_gas_price: Option<u64>,
83 pub l2_gas_price: Option<u64>,
85 pub l1_pubdata_price: Option<u64>,
87 pub price_scale_factor: Option<f64>,
89 pub limit_scale_factor: Option<f32>,
91 pub log_level: LogLevel,
93 pub log_file_path: String,
95 pub cache_dir: String,
97 pub cache_config: CacheConfig,
99 pub genesis_accounts: Vec<PrivateKeySigner>,
101 pub genesis_balance: U256,
103 pub account_generator: Option<AccountGenerator>,
105 pub signer_accounts: Vec<PrivateKeySigner>,
107 pub genesis: Option<Genesis>,
109 pub genesis_timestamp: Option<u64>,
111 pub enable_auto_impersonate: bool,
113 pub offline: bool,
115 pub host: Vec<IpAddr>,
117 pub health_check_endpoint: bool,
119 pub block_time: Option<Duration>,
122 pub max_transactions: usize,
124 pub no_mining: bool,
126 pub allow_origin: String,
128 pub no_cors: bool,
130 pub transaction_order: TransactionOrder,
132 pub state: Option<PathBuf>,
134 pub dump_state: Option<PathBuf>,
136 pub state_interval: Option<u64>,
138 pub preserve_historical_states: bool,
140 pub load_state: Option<PathBuf>,
142 pub l1_config: Option<L1Config>,
144 pub auto_execute_l1: bool,
146 pub base_token_config: BaseTokenConfig,
148}
149
150#[derive(Debug, Clone)]
151pub enum L1Config {
152 Spawn {
154 port: u16,
156 },
157 External {
159 address: String,
161 },
162}
163
164#[derive(Debug, Clone)]
165pub struct BaseTokenConfig {
166 pub symbol: String,
168 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 let genesis_accounts = AccountGenerator::new(10)
185 .phrase(DEFAULT_MNEMONIC)
186 .generate();
187 Self {
188 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 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_level: Default::default(),
215 log_file_path: String::from(DEFAULT_LOG_FILE_PATH),
216
217 cache_dir: String::from(DEFAULT_DISK_CACHE_DIR),
219 cache_config: Default::default(),
220
221 account_generator: None,
223 genesis_accounts: genesis_accounts.clone(),
224 signer_accounts: genesis_accounts,
225 enable_auto_impersonate: false,
226 genesis_balance: U256::from(100u128 * 10u128.pow(18)),
228 genesis_timestamp: Some(NON_FORK_FIRST_BLOCK_TIMESTAMP),
229 genesis: None,
230
231 offline: false,
233 host: vec![IpAddr::V4(Ipv4Addr::LOCALHOST)],
234 health_check_endpoint: false,
235
236 block_time: None,
238 no_mining: false,
239
240 max_transactions: 1000,
241 transaction_order: TransactionOrder::Fifo,
242
243 allow_origin: "*".to_string(),
245 no_cors: false,
246
247 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 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 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 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 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 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 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 sh_println!(
422 r#"
423Genesis Timestamp
424========================
425{}
426"#,
427 self.get_genesis_timestamp().to_string().green()
428 );
429
430 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 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 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 #[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 #[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 pub fn get_port(&self) -> u16 {
569 self.port
570 }
571
572 #[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 pub fn get_chain_id(&self) -> u32 {
583 self.chain_id.unwrap_or(TEST_NODE_NETWORK_ID)
584 }
585
586 pub fn update_chain_id(&mut self, chain_id: Option<u32>) -> &mut Self {
588 self.chain_id = chain_id;
589 self
590 }
591
592 #[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 #[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 #[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 pub fn get_system_contracts(&self) -> SystemContractsOptions {
619 self.system_contracts_options
620 }
621
622 #[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 pub fn get_override_bytecodes_dir(&self) -> Option<&String> {
633 self.override_bytecodes_dir.as_ref()
634 }
635
636 #[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 pub fn is_bytecode_compression_enforced(&self) -> bool {
647 self.bytecode_compression
648 }
649
650 #[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 #[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 pub fn is_evm_interpreter_enabled(&self) -> bool {
668 self.use_evm_interpreter
669 }
670
671 #[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 pub fn get_l1_gas_price(&self) -> u64 {
682 self.l1_gas_price.unwrap_or(DEFAULT_L1_GAS_PRICE)
683 }
684
685 pub fn update_l1_gas_price(&mut self, price: Option<u64>) -> &mut Self {
687 self.l1_gas_price = price;
688 self
689 }
690
691 #[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 pub fn get_l2_gas_price(&self) -> u64 {
702 self.l2_gas_price.unwrap_or(DEFAULT_L2_GAS_PRICE)
703 }
704
705 pub fn update_l2_gas_price(&mut self, price: Option<u64>) -> &mut Self {
707 self.l2_gas_price = price;
708 self
709 }
710
711 #[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 pub fn get_l1_pubdata_price(&self) -> u64 {
720 self.l1_pubdata_price.unwrap_or(DEFAULT_FAIR_PUBDATA_PRICE)
721 }
722
723 pub fn update_l1_pubdata_price(&mut self, price: Option<u64>) -> &mut Self {
725 self.l1_pubdata_price = price;
726 self
727 }
728
729 #[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 pub fn get_log_level(&self) -> LogLevel {
740 self.log_level
741 }
742
743 pub fn get_cache_dir(&self) -> &str {
745 &self.cache_dir
746 }
747
748 #[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 #[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 pub fn get_cache_config(&self) -> &CacheConfig {
768 &self.cache_config
769 }
770
771 #[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 pub fn get_log_file_path(&self) -> &str {
782 &self.log_file_path
783 }
784
785 #[must_use]
787 pub fn with_verbosity_level(mut self, verbosity: u8) -> Self {
788 self.verbosity = verbosity;
789 self
790 }
791
792 pub fn get_verbosity_level(&self) -> u8 {
794 self.verbosity
795 }
796
797 #[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 #[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 #[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 pub fn get_show_storage_logs(&self) -> ShowStorageLogs {
826 self.show_storage_logs
827 }
828
829 #[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 pub fn get_vm_log_detail(&self) -> ShowVMDetails {
840 self.show_vm_details
841 }
842
843 #[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 pub fn get_show_gas_details(&self) -> ShowGasDetails {
854 self.show_gas_details
855 }
856
857 #[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 pub fn get_gas_limit_scale(&self) -> f32 {
868 self.limit_scale_factor
869 .unwrap_or(DEFAULT_ESTIMATE_GAS_SCALE_FACTOR)
870 }
871
872 pub fn update_gas_limit_scale(&mut self, scale: Option<f32>) -> &mut Self {
874 self.limit_scale_factor = scale;
875 self
876 }
877
878 #[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 pub fn get_price_scale(&self) -> f64 {
889 self.price_scale_factor
890 .unwrap_or(DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR)
891 }
892
893 pub fn update_price_scale(&mut self, scale: Option<f64>) -> &mut Self {
895 self.price_scale_factor = scale;
896 self
897 }
898
899 #[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 #[must_use]
908 pub fn with_genesis_accounts(mut self, accounts: Vec<PrivateKeySigner>) -> Self {
909 self.genesis_accounts = accounts;
910 self
911 }
912
913 #[must_use]
915 pub fn with_signer_accounts(mut self, accounts: Vec<PrivateKeySigner>) -> Self {
916 self.signer_accounts = accounts;
917 self
918 }
919
920 #[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 #[must_use]
932 pub fn with_genesis_timestamp(mut self, timestamp: Option<u64>) -> Self {
933 self.genesis_timestamp = timestamp;
934 self
935 }
936
937 pub fn get_genesis_timestamp(&self) -> u64 {
939 self.genesis_timestamp
940 .unwrap_or(NON_FORK_FIRST_BLOCK_TIMESTAMP)
941 }
942
943 #[must_use]
945 pub fn with_genesis(mut self, genesis: Option<Genesis>) -> Self {
946 self.genesis = genesis;
947 self
948 }
949
950 #[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 #[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 pub fn is_offline(&self) -> bool {
968 self.offline
969 }
970
971 #[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 #[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 pub fn is_health_check_endpoint_endpoint_enabled(&self) -> bool {
992 self.health_check_endpoint
993 }
994
995 #[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 #[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 #[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 #[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 #[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 #[must_use]
1032 pub fn with_state(mut self, state: Option<PathBuf>) -> Self {
1033 self.state = state;
1034 self
1035 }
1036
1037 #[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 #[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 #[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 #[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 #[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 #[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 #[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}