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::{H256, ProtocolVersionId, U256};
20
21pub const VERSION_MESSAGE: &str = concat!(env!("CARGO_PKG_VERSION"));
22
23pub const DEFAULT_PROTOCOL_VERSION: ProtocolVersionId = ProtocolVersionId::Version29;
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)]
46pub struct DebugTraceConfig {
47 pub fork_url: String,
48 pub tx: H256,
49 pub only_top: bool,
50}
51
52#[derive(Debug, Clone)]
54pub struct TestNodeConfig {
55 pub config_out: Option<String>,
57 pub port: u16,
59 pub show_node_config: bool,
61 pub show_storage_logs: ShowStorageLogs,
63 pub show_vm_details: ShowVMDetails,
65 pub show_gas_details: ShowGasDetails,
67 pub verbosity: u8,
69 pub silent: bool,
71 pub system_contracts_options: SystemContractsOptions,
73 pub system_contracts_path: Option<PathBuf>,
75 pub protocol_version: Option<ProtocolVersionId>,
78 pub override_bytecodes_dir: Option<String>,
80 pub bytecode_compression: bool,
82 pub use_evm_interpreter: bool,
84 pub zksync_os: ZKsyncOsConfig,
86 pub chain_id: Option<u32>,
88 pub l1_gas_price: Option<u64>,
90 pub l2_gas_price: Option<u64>,
92 pub l1_pubdata_price: Option<u64>,
94 pub price_scale_factor: Option<f64>,
96 pub limit_scale_factor: Option<f32>,
98 pub log_level: LogLevel,
100 pub log_file_path: String,
102 pub cache_dir: String,
104 pub cache_config: CacheConfig,
106 pub genesis_accounts: Vec<PrivateKeySigner>,
108 pub genesis_balance: U256,
110 pub account_generator: Option<AccountGenerator>,
112 pub signer_accounts: Vec<PrivateKeySigner>,
114 pub genesis: Option<Genesis>,
116 pub genesis_timestamp: Option<u64>,
118 pub enable_auto_impersonate: bool,
120 pub offline: bool,
122 pub host: Vec<IpAddr>,
124 pub health_check_endpoint: bool,
126 pub block_time: Option<Duration>,
129 pub max_transactions: usize,
131 pub no_mining: bool,
133 pub allow_origin: String,
135 pub no_cors: bool,
137 pub transaction_order: TransactionOrder,
139 pub state: Option<PathBuf>,
141 pub dump_state: Option<PathBuf>,
143 pub state_interval: Option<u64>,
145 pub preserve_historical_states: bool,
147 pub load_state: Option<PathBuf>,
149 pub l1_config: Option<L1Config>,
151 pub auto_execute_l1: bool,
153 pub base_token_config: BaseTokenConfig,
155 pub debug_trace: Option<DebugTraceConfig>,
157}
158
159#[derive(Debug, Clone)]
160pub enum L1Config {
161 Spawn {
163 port: u16,
165 },
166 External {
168 address: String,
170 },
171}
172
173#[derive(Debug, Clone)]
174pub struct BaseTokenConfig {
175 pub symbol: String,
177 pub ratio: BaseTokenConversionRatio,
179}
180
181impl Default for BaseTokenConfig {
182 fn default() -> Self {
183 Self {
184 symbol: "ETH".to_string(),
185 ratio: BaseTokenConversionRatio::default(),
186 }
187 }
188}
189
190impl Default for TestNodeConfig {
191 fn default() -> Self {
192 let genesis_accounts = AccountGenerator::new(10)
194 .phrase(DEFAULT_MNEMONIC)
195 .generate();
196 Self {
197 config_out: None,
199 port: NODE_PORT,
200 show_node_config: true,
201 show_storage_logs: Default::default(),
202 show_vm_details: Default::default(),
203 show_gas_details: Default::default(),
204 verbosity: 0,
205 silent: false,
206 system_contracts_options: Default::default(),
207 system_contracts_path: None,
208 protocol_version: None,
209 override_bytecodes_dir: None,
210 bytecode_compression: false,
211 use_evm_interpreter: false,
212 zksync_os: Default::default(),
213 chain_id: None,
214
215 l1_gas_price: None,
217 l2_gas_price: None,
218 l1_pubdata_price: None,
219 price_scale_factor: None,
220 limit_scale_factor: None,
221
222 log_level: Default::default(),
224 log_file_path: String::from(DEFAULT_LOG_FILE_PATH),
225
226 cache_dir: String::from(DEFAULT_DISK_CACHE_DIR),
228 cache_config: Default::default(),
229
230 account_generator: None,
232 genesis_accounts: genesis_accounts.clone(),
233 signer_accounts: genesis_accounts,
234 enable_auto_impersonate: false,
235 genesis_balance: U256::from(100u128 * 10u128.pow(18)),
237 genesis_timestamp: Some(NON_FORK_FIRST_BLOCK_TIMESTAMP),
238 genesis: None,
239
240 offline: false,
242 host: vec![IpAddr::V4(Ipv4Addr::LOCALHOST)],
243 health_check_endpoint: false,
244
245 block_time: None,
247 no_mining: false,
248
249 max_transactions: 1000,
250 transaction_order: TransactionOrder::Fifo,
251
252 allow_origin: "*".to_string(),
254 no_cors: false,
255
256 state: None,
258 dump_state: None,
259 state_interval: None,
260 preserve_historical_states: false,
261 load_state: None,
262 l1_config: None,
263 auto_execute_l1: false,
264 base_token_config: BaseTokenConfig::default(),
265
266 debug_trace: None,
268 }
269 }
270}
271
272impl TestNodeConfig {
273 pub fn protocol_version(&self) -> ProtocolVersionId {
274 match self.system_contracts_options {
275 SystemContractsOptions::BuiltIn => self
276 .protocol_version
277 .unwrap_or(DEFAULT_PROTOCOL_VERSION),
278 SystemContractsOptions::Local =>
279 self.protocol_version.expect("cannot deduce protocol version when using local contracts; please specify --protocol-version explicitly"),
280 SystemContractsOptions::BuiltInWithoutSecurity => self
281 .protocol_version
282 .unwrap_or(DEFAULT_PROTOCOL_VERSION),
283 }
284 }
285}
286
287impl TestNodeConfig {
288 pub fn print(&self, fork_details: Option<&ForkPrintInfo>) {
289 if let Some(config_out) = self.config_out.as_deref() {
290 let file = File::create(config_out)
291 .expect("Unable to create anvil-zksync config description file");
292 to_writer(&file, &self.as_json(fork_details)).expect("Failed writing json");
293 }
294
295 if self.silent || !self.show_node_config {
296 return;
297 }
298
299 let color = CustomColor::new(13, 71, 198);
300
301 sh_println!(
303 r#"
304{}
305Version: {}
306Repository: {}
307
308"#,
309 BANNER.custom_color(color),
310 VERSION_MESSAGE.green(),
311 "https://github.com/matter-labs/anvil-zksync".green()
312 );
313
314 let balance = format_eth(self.genesis_balance);
316 let mut rich_accounts = String::new();
317 for (idx, account) in self.genesis_accounts.iter().enumerate() {
318 rich_accounts.push_str(&format!("({}) {} ({})\n", idx, account.address(), balance));
319 }
320 sh_println!(
321 r#"
322Rich Accounts
323========================
324{}
325"#,
326 rich_accounts
327 );
328
329 let mut private_keys = String::new();
331 for (idx, account) in self.genesis_accounts.iter().enumerate() {
332 let private_key = hex::encode(account.credential().to_bytes());
333 private_keys.push_str(&format!("({idx}) 0x{private_key}\n"));
334 }
335 sh_println!(
336 r#"
337Private Keys
338========================
339{}
340"#,
341 private_keys
342 );
343
344 if let Some(ref generator) = self.account_generator {
346 sh_println!(
347 r#"
348Wallet
349========================
350Mnemonic: {}
351Derivation path: {}
352"#,
353 generator.get_phrase().green(),
354 generator.get_derivation_path().green()
355 );
356 }
357
358 if let Some(fd) = fork_details {
360 sh_println!(
361 r#"
362Fork Details
363========================
364Network RPC: {}
365Chain ID: {}
366L1 Batch #: {}
367L2 Block #: {}
368Block Timestamp: {}
369Fork Block Hash: {}
370Compute Overhead Part: {}
371Pubdata Overhead Part: {}
372Batch Overhead L1 Gas: {}
373Max Gas Per Batch: {}
374Max Pubdata Per Batch: {}
375"#,
376 fd.network_rpc.green(),
377 self.get_chain_id().to_string().green(),
378 fd.l1_block.green(),
379 fd.l2_block.green(),
380 fd.block_timestamp.to_string().green(),
381 format!("{:#}", fd.fork_block_hash).green(),
382 fd.fee_model_config_v2
383 .compute_overhead_part
384 .to_string()
385 .green(),
386 fd.fee_model_config_v2
387 .pubdata_overhead_part
388 .to_string()
389 .green(),
390 fd.fee_model_config_v2
391 .batch_overhead_l1_gas
392 .to_string()
393 .green(),
394 fd.fee_model_config_v2.max_gas_per_batch.to_string().green(),
395 fd.fee_model_config_v2
396 .max_pubdata_per_batch
397 .to_string()
398 .green()
399 );
400 } else {
401 sh_println!(
402 r#"
403Network Configuration
404========================
405Chain ID: {}
406"#,
407 self.chain_id
408 .unwrap_or(TEST_NODE_NETWORK_ID)
409 .to_string()
410 .green()
411 );
412 }
413
414 sh_println!(
416 r#"
417Gas Configuration
418========================
419L1 Gas Price (gwei): {}
420L2 Gas Price (gwei): {}
421L1 Pubdata Price (gwei): {}
422Estimated Gas Price Scale Factor: {}
423Estimated Gas Limit Scale Factor: {}
424"#,
425 format_gwei(self.get_l1_gas_price().into()).green(),
426 format_gwei(self.get_l2_gas_price().into()).green(),
427 format_gwei(self.get_l1_pubdata_price().into()).green(),
428 self.get_price_scale().to_string().green(),
429 self.get_gas_limit_scale().to_string().green()
430 );
431
432 sh_println!(
434 r#"
435Genesis Timestamp
436========================
437{}
438"#,
439 self.get_genesis_timestamp().to_string().green()
440 );
441
442 sh_println!(
444 r#"
445Node Configuration
446========================
447Port: {}
448EVM Interpreter: {}
449Health Check Endpoint: {}
450ZKsync OS: {}
451L1: {}
452"#,
453 self.port,
454 if self.use_evm_interpreter {
455 "Enabled".green()
456 } else {
457 "Disabled".red()
458 },
459 if self.health_check_endpoint {
460 "Enabled".green()
461 } else {
462 "Disabled".red()
463 },
464 if self.zksync_os.zksync_os {
465 "Enabled".green()
466 } else {
467 "Disabled".red()
468 },
469 if self.l1_config.is_some() {
470 "Enabled".green()
471 } else {
472 "Disabled".red()
473 }
474 );
475
476 match self.l1_config.as_ref() {
478 Some(L1Config::Spawn { port }) => {
479 sh_println!(
480 r#"
481L1 Configuration (Spawned)
482========================
483Port: {port}
484"#
485 );
486 }
487 Some(L1Config::External { address }) => {
488 sh_println!(
489 r#"
490L1 Configuration (External)
491========================
492Address: {address}
493"#
494 );
495 }
496 None => {}
497 }
498
499 let mut listening = String::new();
501 listening.push_str("\n========================================\n");
502 for host in &self.host {
503 listening.push_str(&format!(
504 " Listening on {}:{}\n",
505 host.to_string().green(),
506 self.port.to_string().green()
507 ));
508 }
509 listening.push_str("========================================\n");
510 sh_println!("{}", listening);
511 }
512
513 fn as_json(&self, fork: Option<&ForkPrintInfo>) -> Value {
514 let mut wallet_description = HashMap::new();
515 let mut available_accounts = Vec::with_capacity(self.genesis_accounts.len());
516 let mut private_keys = Vec::with_capacity(self.genesis_accounts.len());
517
518 for wallet in &self.genesis_accounts {
519 available_accounts.push(format!("{:?}", wallet.address()));
520 private_keys.push(format!("0x{}", hex::encode(wallet.credential().to_bytes())));
521 }
522
523 if let Some(generator) = &self.account_generator {
524 let phrase = generator.get_phrase().to_string();
525 let derivation_path = generator.get_derivation_path().to_string();
526
527 wallet_description.insert("derivation_path".to_string(), derivation_path);
528 wallet_description.insert("mnemonic".to_string(), phrase);
529 };
530
531 if let Some(fork) = fork {
532 json!({
533 "available_accounts": available_accounts,
534 "private_keys": private_keys,
535 "endpoint": fork.network_rpc,
536 "l1_block": fork.l1_block,
537 "l2_block": fork.l2_block,
538 "block_hash": fork.fork_block_hash,
539 "chain_id": self.get_chain_id(),
540 "wallet": wallet_description,
541 "l1_gas_price": format!("{}", self.get_l1_gas_price()),
542 "l2_gas_price": format!("{}", self.get_l2_gas_price()),
543 "l1_pubdata_price": format!("{}", self.get_l1_pubdata_price()),
544 "price_scale_factor": format!("{}", self.get_price_scale()),
545 "limit_scale_factor": format!("{}", self.get_gas_limit_scale()),
546 "fee_model_config_v2": fork.fee_model_config_v2,
547 })
548 } else {
549 json!({
550 "available_accounts": available_accounts,
551 "private_keys": private_keys,
552 "wallet": wallet_description,
553 "chain_id": self.get_chain_id(),
554 "l1_gas_price": format!("{}", self.get_l1_gas_price()),
555 "l2_gas_price": format!("{}", self.get_l2_gas_price()),
556 "l1_pubdata_price": format!("{}", self.get_l1_pubdata_price()),
557 "price_scale_factor": format!("{}", self.get_price_scale()),
558 "limit_scale_factor": format!("{}", self.get_gas_limit_scale()),
559 })
560 }
561 }
562
563 #[must_use]
565 pub fn set_config_out(mut self, config_out: Option<String>) -> Self {
566 self.config_out = config_out;
567 self
568 }
569
570 #[must_use]
572 pub fn with_port(mut self, port: Option<u16>) -> Self {
573 if let Some(port) = port {
574 self.port = port;
575 }
576 self
577 }
578
579 pub fn get_port(&self) -> u16 {
581 self.port
582 }
583
584 #[must_use]
586 pub fn with_chain_id(mut self, chain_id: Option<u32>) -> Self {
587 if let Some(chain_id) = chain_id {
588 self.chain_id = Some(chain_id);
589 }
590 self
591 }
592
593 pub fn get_chain_id(&self) -> u32 {
595 self.chain_id.unwrap_or(TEST_NODE_NETWORK_ID)
596 }
597
598 pub fn update_chain_id(&mut self, chain_id: Option<u32>) -> &mut Self {
600 self.chain_id = chain_id;
601 self
602 }
603
604 #[must_use]
606 pub fn with_system_contracts(mut self, option: Option<SystemContractsOptions>) -> Self {
607 if let Some(option) = option {
608 self.system_contracts_options = option;
609 }
610 self
611 }
612
613 #[must_use]
615 pub fn with_system_contracts_path(mut self, path: Option<PathBuf>) -> Self {
616 if let Some(path) = path {
617 self.system_contracts_path = Some(path);
618 }
619 self
620 }
621
622 #[must_use]
624 pub fn with_protocol_version(mut self, protocol_version: Option<ProtocolVersionId>) -> Self {
625 self.protocol_version = protocol_version;
626 self
627 }
628
629 pub fn get_system_contracts(&self) -> SystemContractsOptions {
631 self.system_contracts_options
632 }
633
634 #[must_use]
636 pub fn with_override_bytecodes_dir(mut self, dir: Option<String>) -> Self {
637 if let Some(dir) = dir {
638 self.override_bytecodes_dir = Some(dir);
639 }
640 self
641 }
642
643 pub fn get_override_bytecodes_dir(&self) -> Option<&String> {
645 self.override_bytecodes_dir.as_ref()
646 }
647
648 #[must_use]
650 pub fn with_enforce_bytecode_compression(mut self, enforce: Option<bool>) -> Self {
651 if let Some(enforce) = enforce {
652 self.bytecode_compression = enforce;
653 }
654 self
655 }
656
657 pub fn is_bytecode_compression_enforced(&self) -> bool {
659 self.bytecode_compression
660 }
661
662 #[must_use]
664 pub fn with_evm_interpreter(mut self, enable: Option<bool>) -> Self {
665 if let Some(enable) = enable {
666 self.use_evm_interpreter = enable;
667 }
668 self
669 }
670
671 #[must_use]
673 pub fn with_zksync_os(mut self, zksync_os: ZKsyncOsConfig) -> Self {
674 self.zksync_os = zksync_os;
675 self
676 }
677
678 pub fn is_evm_interpreter_enabled(&self) -> bool {
680 self.use_evm_interpreter
681 }
682
683 #[must_use]
685 pub fn with_l1_gas_price(mut self, price: Option<u64>) -> Self {
686 if let Some(price) = price {
687 self.l1_gas_price = Some(price);
688 }
689 self
690 }
691
692 pub fn get_l1_gas_price(&self) -> u64 {
694 self.l1_gas_price.unwrap_or(DEFAULT_L1_GAS_PRICE)
695 }
696
697 pub fn update_l1_gas_price(&mut self, price: Option<u64>) -> &mut Self {
699 self.l1_gas_price = price;
700 self
701 }
702
703 #[must_use]
705 pub fn with_l2_gas_price(mut self, price: Option<u64>) -> Self {
706 if let Some(price) = price {
707 self.l2_gas_price = Some(price);
708 }
709 self
710 }
711
712 pub fn get_l2_gas_price(&self) -> u64 {
714 self.l2_gas_price.unwrap_or(DEFAULT_L2_GAS_PRICE)
715 }
716
717 pub fn update_l2_gas_price(&mut self, price: Option<u64>) -> &mut Self {
719 self.l2_gas_price = price;
720 self
721 }
722
723 #[must_use]
725 pub fn with_l1_pubdata_price(mut self, price: Option<u64>) -> Self {
726 self.l1_pubdata_price = price;
727 self
728 }
729
730 pub fn get_l1_pubdata_price(&self) -> u64 {
732 self.l1_pubdata_price.unwrap_or(DEFAULT_FAIR_PUBDATA_PRICE)
733 }
734
735 pub fn update_l1_pubdata_price(&mut self, price: Option<u64>) -> &mut Self {
737 self.l1_pubdata_price = price;
738 self
739 }
740
741 #[must_use]
743 pub fn with_log_level(mut self, level: Option<LogLevel>) -> Self {
744 if let Some(level) = level {
745 self.log_level = level;
746 }
747 self
748 }
749
750 pub fn get_log_level(&self) -> LogLevel {
752 self.log_level
753 }
754
755 pub fn get_cache_dir(&self) -> &str {
757 &self.cache_dir
758 }
759
760 #[must_use]
762 pub fn with_cache_dir(mut self, dir: Option<String>) -> Self {
763 if let Some(dir) = dir {
764 self.cache_dir = dir;
765 }
766 self
767 }
768
769 #[must_use]
771 pub fn with_cache_config(mut self, config: Option<CacheConfig>) -> Self {
772 if let Some(config) = config {
773 self.cache_config = config;
774 }
775 self
776 }
777
778 pub fn get_cache_config(&self) -> &CacheConfig {
780 &self.cache_config
781 }
782
783 #[must_use]
785 pub fn with_log_file_path(mut self, path: Option<String>) -> Self {
786 if let Some(path) = path {
787 self.log_file_path = path;
788 }
789 self
790 }
791
792 pub fn get_log_file_path(&self) -> &str {
794 &self.log_file_path
795 }
796
797 #[must_use]
799 pub fn with_verbosity_level(mut self, verbosity: u8) -> Self {
800 self.verbosity = verbosity;
801 self
802 }
803
804 pub fn get_verbosity_level(&self) -> u8 {
806 self.verbosity
807 }
808
809 #[must_use]
811 pub fn with_silent(mut self, silent: Option<bool>) -> Self {
812 if let Some(silent) = silent {
813 self.silent = silent;
814 }
815 self
816 }
817
818 #[must_use]
820 pub fn with_show_node_config(mut self, show_node_config: Option<bool>) -> Self {
821 if let Some(show_node_config) = show_node_config {
822 self.show_node_config = show_node_config;
823 }
824 self
825 }
826
827 #[must_use]
829 pub fn with_show_storage_logs(mut self, show_storage_logs: Option<ShowStorageLogs>) -> Self {
830 if let Some(show_storage_logs) = show_storage_logs {
831 self.show_storage_logs = show_storage_logs;
832 }
833 self
834 }
835
836 pub fn get_show_storage_logs(&self) -> ShowStorageLogs {
838 self.show_storage_logs
839 }
840
841 #[must_use]
843 pub fn with_vm_log_detail(mut self, detail: Option<ShowVMDetails>) -> Self {
844 if let Some(detail) = detail {
845 self.show_vm_details = detail;
846 }
847 self
848 }
849
850 pub fn get_vm_log_detail(&self) -> ShowVMDetails {
852 self.show_vm_details
853 }
854
855 #[must_use]
857 pub fn with_show_gas_details(mut self, show_gas_details: Option<ShowGasDetails>) -> Self {
858 if let Some(show_gas_details) = show_gas_details {
859 self.show_gas_details = show_gas_details;
860 }
861 self
862 }
863
864 pub fn get_show_gas_details(&self) -> ShowGasDetails {
866 self.show_gas_details
867 }
868
869 #[must_use]
871 pub fn with_gas_limit_scale(mut self, scale: Option<f32>) -> Self {
872 if let Some(scale) = scale {
873 self.limit_scale_factor = Some(scale);
874 }
875 self
876 }
877
878 pub fn get_gas_limit_scale(&self) -> f32 {
880 self.limit_scale_factor
881 .unwrap_or(DEFAULT_ESTIMATE_GAS_SCALE_FACTOR)
882 }
883
884 pub fn update_gas_limit_scale(&mut self, scale: Option<f32>) -> &mut Self {
886 self.limit_scale_factor = scale;
887 self
888 }
889
890 #[must_use]
892 pub fn with_price_scale(mut self, scale: Option<f64>) -> Self {
893 if let Some(scale) = scale {
894 self.price_scale_factor = Some(scale);
895 }
896 self
897 }
898
899 pub fn get_price_scale(&self) -> f64 {
901 self.price_scale_factor
902 .unwrap_or(DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR)
903 }
904
905 pub fn update_price_scale(&mut self, scale: Option<f64>) -> &mut Self {
907 self.price_scale_factor = scale;
908 self
909 }
910
911 #[must_use]
913 pub fn with_genesis_balance<U: Into<U256>>(mut self, balance: U) -> Self {
914 self.genesis_balance = balance.into();
915 self
916 }
917
918 #[must_use]
920 pub fn with_genesis_accounts(mut self, accounts: Vec<PrivateKeySigner>) -> Self {
921 self.genesis_accounts = accounts;
922 self
923 }
924
925 #[must_use]
927 pub fn with_signer_accounts(mut self, accounts: Vec<PrivateKeySigner>) -> Self {
928 self.signer_accounts = accounts;
929 self
930 }
931
932 #[must_use]
935 pub fn with_account_generator(mut self, generator: AccountGenerator) -> Self {
936 let accounts = generator.generate();
937 self.account_generator = Some(generator);
938 self.with_signer_accounts(accounts.clone())
939 .with_genesis_accounts(accounts)
940 }
941
942 #[must_use]
944 pub fn with_genesis_timestamp(mut self, timestamp: Option<u64>) -> Self {
945 self.genesis_timestamp = timestamp;
946 self
947 }
948
949 pub fn get_genesis_timestamp(&self) -> u64 {
951 self.genesis_timestamp
952 .unwrap_or(NON_FORK_FIRST_BLOCK_TIMESTAMP)
953 }
954
955 #[must_use]
957 pub fn with_genesis(mut self, genesis: Option<Genesis>) -> Self {
958 self.genesis = genesis;
959 self
960 }
961
962 #[must_use]
964 pub fn with_auto_impersonate(mut self, enable_auto_impersonate: bool) -> Self {
965 self.enable_auto_impersonate = enable_auto_impersonate;
966 self
967 }
968
969 #[must_use]
971 pub fn with_offline(mut self, offline: Option<bool>) -> Self {
972 if let Some(offline) = offline {
973 self.offline = offline;
974 }
975 self
976 }
977
978 pub fn is_offline(&self) -> bool {
980 self.offline
981 }
982
983 #[must_use]
985 pub fn with_host(mut self, host: Vec<IpAddr>) -> Self {
986 self.host = if host.is_empty() {
987 vec![IpAddr::V4(Ipv4Addr::LOCALHOST)]
988 } else {
989 host
990 };
991 self
992 }
993 #[must_use]
995 pub fn with_health_check_endpoint(mut self, health_check_endpoint: Option<bool>) -> Self {
996 if let Some(health_check_endpoint) = health_check_endpoint {
997 self.health_check_endpoint = health_check_endpoint;
998 }
999 self
1000 }
1001
1002 pub fn is_health_check_endpoint_endpoint_enabled(&self) -> bool {
1004 self.health_check_endpoint
1005 }
1006
1007 #[must_use]
1009 pub fn with_block_time(mut self, block_time: Option<Duration>) -> Self {
1010 self.block_time = block_time;
1011 self
1012 }
1013
1014 #[must_use]
1016 pub fn with_no_mining(mut self, no_mining: bool) -> Self {
1017 self.no_mining = no_mining;
1018 self
1019 }
1020
1021 #[must_use]
1023 pub fn with_transaction_order(mut self, transaction_order: TransactionOrder) -> Self {
1024 self.transaction_order = transaction_order;
1025 self
1026 }
1027
1028 #[must_use]
1030 pub fn with_allow_origin(mut self, allow_origin: String) -> Self {
1031 self.allow_origin = allow_origin;
1032 self
1033 }
1034
1035 #[must_use]
1037 pub fn with_no_cors(mut self, no_cors: bool) -> Self {
1038 self.no_cors = no_cors;
1039 self
1040 }
1041
1042 #[must_use]
1044 pub fn with_state(mut self, state: Option<PathBuf>) -> Self {
1045 self.state = state;
1046 self
1047 }
1048
1049 #[must_use]
1051 pub fn with_dump_state(mut self, dump_state: Option<PathBuf>) -> Self {
1052 self.dump_state = dump_state;
1053 self
1054 }
1055
1056 #[must_use]
1058 pub fn with_state_interval(mut self, state_interval: Option<u64>) -> Self {
1059 self.state_interval = state_interval;
1060 self
1061 }
1062
1063 #[must_use]
1065 pub fn with_preserve_historical_states(mut self, preserve_historical_states: bool) -> Self {
1066 self.preserve_historical_states = preserve_historical_states;
1067 self
1068 }
1069
1070 #[must_use]
1072 pub fn with_load_state(mut self, load_state: Option<PathBuf>) -> Self {
1073 self.load_state = load_state;
1074 self
1075 }
1076
1077 #[must_use]
1079 pub fn with_l1_config(mut self, l1_config: Option<L1Config>) -> Self {
1080 self.l1_config = l1_config;
1081 self
1082 }
1083
1084 #[must_use]
1086 pub fn with_auto_execute_l1(mut self, auto_execute_l1: Option<bool>) -> Self {
1087 self.auto_execute_l1 = auto_execute_l1.unwrap_or(false);
1088 self
1089 }
1090
1091 #[must_use]
1093 pub fn with_base_token_config(mut self, base_token_config: BaseTokenConfig) -> Self {
1094 self.base_token_config = base_token_config;
1095 self
1096 }
1097
1098 #[must_use]
1099 pub fn with_debug_trace(mut self, debug: Option<DebugTraceConfig>) -> Self {
1100 self.debug_trace = debug;
1101 self
1102 }
1103
1104 pub fn get_debug_trace(&self) -> Option<&DebugTraceConfig> {
1106 self.debug_trace.as_ref()
1107 }
1108}