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 evm_emulator_path: Option<PathBuf>,
78 pub protocol_version: Option<ProtocolVersionId>,
81 pub override_bytecodes_dir: Option<String>,
83 pub bytecode_compression: bool,
85 pub use_evm_interpreter: bool,
87 pub zksync_os: ZKsyncOsConfig,
89 pub chain_id: Option<u32>,
91 pub l1_gas_price: Option<u64>,
93 pub l2_gas_price: Option<u64>,
95 pub l1_pubdata_price: Option<u64>,
97 pub price_scale_factor: Option<f64>,
99 pub limit_scale_factor: Option<f32>,
101 pub log_level: LogLevel,
103 pub log_file_path: String,
105 pub cache_dir: String,
107 pub cache_config: CacheConfig,
109 pub genesis_accounts: Vec<PrivateKeySigner>,
111 pub genesis_balance: U256,
113 pub account_generator: Option<AccountGenerator>,
115 pub signer_accounts: Vec<PrivateKeySigner>,
117 pub genesis: Option<Genesis>,
119 pub genesis_timestamp: Option<u64>,
121 pub enable_auto_impersonate: bool,
123 pub offline: bool,
125 pub host: Vec<IpAddr>,
127 pub health_check_endpoint: bool,
129 pub block_time: Option<Duration>,
132 pub max_transactions: usize,
134 pub no_mining: bool,
136 pub allow_origin: String,
138 pub no_cors: bool,
140 pub transaction_order: TransactionOrder,
142 pub state: Option<PathBuf>,
144 pub dump_state: Option<PathBuf>,
146 pub state_interval: Option<u64>,
148 pub preserve_historical_states: bool,
150 pub load_state: Option<PathBuf>,
152 pub l1_config: Option<L1Config>,
154 pub auto_execute_l1: bool,
156 pub base_token_config: BaseTokenConfig,
158 pub debug_trace: Option<DebugTraceConfig>,
160}
161
162#[derive(Debug, Clone)]
163pub enum L1Config {
164 Spawn {
166 port: u16,
168 },
169 External {
171 address: String,
173 },
174}
175
176#[derive(Debug, Clone)]
177pub struct BaseTokenConfig {
178 pub symbol: String,
180 pub ratio: BaseTokenConversionRatio,
182}
183
184impl Default for BaseTokenConfig {
185 fn default() -> Self {
186 Self {
187 symbol: "ETH".to_string(),
188 ratio: BaseTokenConversionRatio::default(),
189 }
190 }
191}
192
193impl Default for TestNodeConfig {
194 fn default() -> Self {
195 let genesis_accounts = AccountGenerator::new(10)
197 .phrase(DEFAULT_MNEMONIC)
198 .generate();
199 Self {
200 config_out: None,
202 port: NODE_PORT,
203 show_node_config: true,
204 show_storage_logs: Default::default(),
205 show_vm_details: Default::default(),
206 show_gas_details: Default::default(),
207 verbosity: 0,
208 silent: false,
209 system_contracts_options: Default::default(),
210 system_contracts_path: None,
211 evm_emulator_path: None,
212 protocol_version: None,
213 override_bytecodes_dir: None,
214 bytecode_compression: false,
215 use_evm_interpreter: false,
216 zksync_os: Default::default(),
217 chain_id: None,
218
219 l1_gas_price: None,
221 l2_gas_price: None,
222 l1_pubdata_price: None,
223 price_scale_factor: None,
224 limit_scale_factor: None,
225
226 log_level: Default::default(),
228 log_file_path: String::from(DEFAULT_LOG_FILE_PATH),
229
230 cache_dir: String::from(DEFAULT_DISK_CACHE_DIR),
232 cache_config: Default::default(),
233
234 account_generator: None,
236 genesis_accounts: genesis_accounts.clone(),
237 signer_accounts: genesis_accounts,
238 enable_auto_impersonate: false,
239 genesis_balance: U256::from(100u128 * 10u128.pow(18)),
241 genesis_timestamp: Some(NON_FORK_FIRST_BLOCK_TIMESTAMP),
242 genesis: None,
243
244 offline: false,
246 host: vec![IpAddr::V4(Ipv4Addr::LOCALHOST)],
247 health_check_endpoint: false,
248
249 block_time: None,
251 no_mining: false,
252
253 max_transactions: 1000,
254 transaction_order: TransactionOrder::Fifo,
255
256 allow_origin: "*".to_string(),
258 no_cors: false,
259
260 state: None,
262 dump_state: None,
263 state_interval: None,
264 preserve_historical_states: false,
265 load_state: None,
266 l1_config: None,
267 auto_execute_l1: false,
268 base_token_config: BaseTokenConfig::default(),
269
270 debug_trace: None,
272 }
273 }
274}
275
276impl TestNodeConfig {
277 pub fn protocol_version(&self) -> ProtocolVersionId {
278 match self.system_contracts_options {
279 SystemContractsOptions::BuiltIn => self
280 .protocol_version
281 .unwrap_or(DEFAULT_PROTOCOL_VERSION),
282 SystemContractsOptions::Local =>
283 self.protocol_version.expect("cannot deduce protocol version when using local contracts; please specify --protocol-version explicitly"),
284 SystemContractsOptions::BuiltInWithoutSecurity => self
285 .protocol_version
286 .unwrap_or(DEFAULT_PROTOCOL_VERSION),
287 }
288 }
289}
290
291impl TestNodeConfig {
292 pub fn print(&self, fork_details: Option<&ForkPrintInfo>) {
293 if let Some(config_out) = self.config_out.as_deref() {
294 let file = File::create(config_out)
295 .expect("Unable to create anvil-zksync config description file");
296 to_writer(&file, &self.as_json(fork_details)).expect("Failed writing json");
297 }
298
299 if self.silent || !self.show_node_config {
300 return;
301 }
302
303 let color = CustomColor::new(13, 71, 198);
304
305 sh_println!(
307 r#"
308{}
309Version: {}
310Repository: {}
311
312"#,
313 BANNER.custom_color(color),
314 VERSION_MESSAGE.green(),
315 "https://github.com/matter-labs/anvil-zksync".green()
316 );
317
318 let balance = format_eth(self.genesis_balance);
320 let mut rich_accounts = String::new();
321 for (idx, account) in self.genesis_accounts.iter().enumerate() {
322 rich_accounts.push_str(&format!("({}) {} ({})\n", idx, account.address(), balance));
323 }
324 sh_println!(
325 r#"
326Rich Accounts
327========================
328{}
329"#,
330 rich_accounts
331 );
332
333 let mut private_keys = String::new();
335 for (idx, account) in self.genesis_accounts.iter().enumerate() {
336 let private_key = hex::encode(account.credential().to_bytes());
337 private_keys.push_str(&format!("({idx}) 0x{private_key}\n"));
338 }
339 sh_println!(
340 r#"
341Private Keys
342========================
343{}
344"#,
345 private_keys
346 );
347
348 if let Some(ref generator) = self.account_generator {
350 sh_println!(
351 r#"
352Wallet
353========================
354Mnemonic: {}
355Derivation path: {}
356"#,
357 generator.get_phrase().green(),
358 generator.get_derivation_path().green()
359 );
360 }
361
362 if let Some(fd) = fork_details {
364 sh_println!(
365 r#"
366Fork Details
367========================
368Network RPC: {}
369Chain ID: {}
370L1 Batch #: {}
371L2 Block #: {}
372Block Timestamp: {}
373Fork Block Hash: {}
374Compute Overhead Part: {}
375Pubdata Overhead Part: {}
376Batch Overhead L1 Gas: {}
377Max Gas Per Batch: {}
378Max Pubdata Per Batch: {}
379"#,
380 fd.network_rpc.green(),
381 self.get_chain_id().to_string().green(),
382 fd.l1_block.green(),
383 fd.l2_block.green(),
384 fd.block_timestamp.to_string().green(),
385 format!("{:#}", fd.fork_block_hash).green(),
386 fd.fee_model_config_v2
387 .compute_overhead_part
388 .to_string()
389 .green(),
390 fd.fee_model_config_v2
391 .pubdata_overhead_part
392 .to_string()
393 .green(),
394 fd.fee_model_config_v2
395 .batch_overhead_l1_gas
396 .to_string()
397 .green(),
398 fd.fee_model_config_v2.max_gas_per_batch.to_string().green(),
399 fd.fee_model_config_v2
400 .max_pubdata_per_batch
401 .to_string()
402 .green()
403 );
404 } else {
405 sh_println!(
406 r#"
407Network Configuration
408========================
409Chain ID: {}
410"#,
411 self.chain_id
412 .unwrap_or(TEST_NODE_NETWORK_ID)
413 .to_string()
414 .green()
415 );
416 }
417
418 sh_println!(
420 r#"
421Gas Configuration
422========================
423L1 Gas Price (gwei): {}
424L2 Gas Price (gwei): {}
425L1 Pubdata Price (gwei): {}
426Estimated Gas Price Scale Factor: {}
427Estimated Gas Limit Scale Factor: {}
428"#,
429 format_gwei(self.get_l1_gas_price().into()).green(),
430 format_gwei(self.get_l2_gas_price().into()).green(),
431 format_gwei(self.get_l1_pubdata_price().into()).green(),
432 self.get_price_scale().to_string().green(),
433 self.get_gas_limit_scale().to_string().green()
434 );
435
436 sh_println!(
438 r#"
439Genesis Timestamp
440========================
441{}
442"#,
443 self.get_genesis_timestamp().to_string().green()
444 );
445
446 sh_println!(
448 r#"
449Node Configuration
450========================
451Port: {}
452EVM Interpreter: {}
453Health Check Endpoint: {}
454ZKsync OS: {}
455L1: {}
456"#,
457 self.port,
458 if self.use_evm_interpreter {
459 "Enabled".green()
460 } else {
461 "Disabled".red()
462 },
463 if self.health_check_endpoint {
464 "Enabled".green()
465 } else {
466 "Disabled".red()
467 },
468 if self.zksync_os.zksync_os {
469 "Enabled".green()
470 } else {
471 "Disabled".red()
472 },
473 if self.l1_config.is_some() {
474 "Enabled".green()
475 } else {
476 "Disabled".red()
477 }
478 );
479
480 match self.l1_config.as_ref() {
482 Some(L1Config::Spawn { port }) => {
483 sh_println!(
484 r#"
485L1 Configuration (Spawned)
486========================
487Port: {port}
488"#
489 );
490 }
491 Some(L1Config::External { address }) => {
492 sh_println!(
493 r#"
494L1 Configuration (External)
495========================
496Address: {address}
497"#
498 );
499 }
500 None => {}
501 }
502
503 let mut listening = String::new();
505 listening.push_str("\n========================================\n");
506 for host in &self.host {
507 listening.push_str(&format!(
508 " Listening on {}:{}\n",
509 host.to_string().green(),
510 self.port.to_string().green()
511 ));
512 }
513 listening.push_str("========================================\n");
514 sh_println!("{}", listening);
515 }
516
517 fn as_json(&self, fork: Option<&ForkPrintInfo>) -> Value {
518 let mut wallet_description = HashMap::new();
519 let mut available_accounts = Vec::with_capacity(self.genesis_accounts.len());
520 let mut private_keys = Vec::with_capacity(self.genesis_accounts.len());
521
522 for wallet in &self.genesis_accounts {
523 available_accounts.push(format!("{:?}", wallet.address()));
524 private_keys.push(format!("0x{}", hex::encode(wallet.credential().to_bytes())));
525 }
526
527 if let Some(generator) = &self.account_generator {
528 let phrase = generator.get_phrase().to_string();
529 let derivation_path = generator.get_derivation_path().to_string();
530
531 wallet_description.insert("derivation_path".to_string(), derivation_path);
532 wallet_description.insert("mnemonic".to_string(), phrase);
533 };
534
535 if let Some(fork) = fork {
536 json!({
537 "available_accounts": available_accounts,
538 "private_keys": private_keys,
539 "endpoint": fork.network_rpc,
540 "l1_block": fork.l1_block,
541 "l2_block": fork.l2_block,
542 "block_hash": fork.fork_block_hash,
543 "chain_id": self.get_chain_id(),
544 "wallet": wallet_description,
545 "l1_gas_price": format!("{}", self.get_l1_gas_price()),
546 "l2_gas_price": format!("{}", self.get_l2_gas_price()),
547 "l1_pubdata_price": format!("{}", self.get_l1_pubdata_price()),
548 "price_scale_factor": format!("{}", self.get_price_scale()),
549 "limit_scale_factor": format!("{}", self.get_gas_limit_scale()),
550 "fee_model_config_v2": fork.fee_model_config_v2,
551 })
552 } else {
553 json!({
554 "available_accounts": available_accounts,
555 "private_keys": private_keys,
556 "wallet": wallet_description,
557 "chain_id": self.get_chain_id(),
558 "l1_gas_price": format!("{}", self.get_l1_gas_price()),
559 "l2_gas_price": format!("{}", self.get_l2_gas_price()),
560 "l1_pubdata_price": format!("{}", self.get_l1_pubdata_price()),
561 "price_scale_factor": format!("{}", self.get_price_scale()),
562 "limit_scale_factor": format!("{}", self.get_gas_limit_scale()),
563 })
564 }
565 }
566
567 #[must_use]
569 pub fn set_config_out(mut self, config_out: Option<String>) -> Self {
570 self.config_out = config_out;
571 self
572 }
573
574 #[must_use]
576 pub fn with_port(mut self, port: Option<u16>) -> Self {
577 if let Some(port) = port {
578 self.port = port;
579 }
580 self
581 }
582
583 pub fn get_port(&self) -> u16 {
585 self.port
586 }
587
588 #[must_use]
590 pub fn with_chain_id(mut self, chain_id: Option<u32>) -> Self {
591 if let Some(chain_id) = chain_id {
592 self.chain_id = Some(chain_id);
593 }
594 self
595 }
596
597 pub fn get_chain_id(&self) -> u32 {
599 self.chain_id.unwrap_or(TEST_NODE_NETWORK_ID)
600 }
601
602 pub fn update_chain_id(&mut self, chain_id: Option<u32>) -> &mut Self {
604 self.chain_id = chain_id;
605 self
606 }
607
608 #[must_use]
610 pub fn with_system_contracts(mut self, option: Option<SystemContractsOptions>) -> Self {
611 if let Some(option) = option {
612 self.system_contracts_options = option;
613 }
614 self
615 }
616
617 #[must_use]
619 pub fn with_system_contracts_path(mut self, path: Option<PathBuf>) -> Self {
620 if let Some(path) = path {
621 self.system_contracts_path = Some(path);
622 }
623 self
624 }
625
626 #[must_use]
628 pub fn with_evm_emulator_path(mut self, path: Option<PathBuf>) -> Self {
629 if let Some(path) = path {
630 self.evm_emulator_path = Some(path);
631 }
632 self
633 }
634
635 #[must_use]
637 pub fn with_protocol_version(mut self, protocol_version: Option<ProtocolVersionId>) -> Self {
638 self.protocol_version = protocol_version;
639 self
640 }
641
642 pub fn get_system_contracts(&self) -> SystemContractsOptions {
644 self.system_contracts_options
645 }
646
647 #[must_use]
649 pub fn with_override_bytecodes_dir(mut self, dir: Option<String>) -> Self {
650 if let Some(dir) = dir {
651 self.override_bytecodes_dir = Some(dir);
652 }
653 self
654 }
655
656 pub fn get_override_bytecodes_dir(&self) -> Option<&String> {
658 self.override_bytecodes_dir.as_ref()
659 }
660
661 #[must_use]
663 pub fn with_enforce_bytecode_compression(mut self, enforce: Option<bool>) -> Self {
664 if let Some(enforce) = enforce {
665 self.bytecode_compression = enforce;
666 }
667 self
668 }
669
670 pub fn is_bytecode_compression_enforced(&self) -> bool {
672 self.bytecode_compression
673 }
674
675 #[must_use]
677 pub fn with_evm_interpreter(mut self, enable: Option<bool>) -> Self {
678 if let Some(enable) = enable {
679 self.use_evm_interpreter = enable;
680 }
681 self
682 }
683
684 #[must_use]
686 pub fn with_zksync_os(mut self, zksync_os: ZKsyncOsConfig) -> Self {
687 self.zksync_os = zksync_os;
688 self
689 }
690
691 pub fn is_evm_interpreter_enabled(&self) -> bool {
693 self.use_evm_interpreter
694 }
695
696 #[must_use]
698 pub fn with_l1_gas_price(mut self, price: Option<u64>) -> Self {
699 if let Some(price) = price {
700 self.l1_gas_price = Some(price);
701 }
702 self
703 }
704
705 pub fn get_l1_gas_price(&self) -> u64 {
707 self.l1_gas_price.unwrap_or(DEFAULT_L1_GAS_PRICE)
708 }
709
710 pub fn update_l1_gas_price(&mut self, price: Option<u64>) -> &mut Self {
712 self.l1_gas_price = price;
713 self
714 }
715
716 #[must_use]
718 pub fn with_l2_gas_price(mut self, price: Option<u64>) -> Self {
719 if let Some(price) = price {
720 self.l2_gas_price = Some(price);
721 }
722 self
723 }
724
725 pub fn get_l2_gas_price(&self) -> u64 {
727 self.l2_gas_price.unwrap_or(DEFAULT_L2_GAS_PRICE)
728 }
729
730 pub fn update_l2_gas_price(&mut self, price: Option<u64>) -> &mut Self {
732 self.l2_gas_price = price;
733 self
734 }
735
736 #[must_use]
738 pub fn with_l1_pubdata_price(mut self, price: Option<u64>) -> Self {
739 self.l1_pubdata_price = price;
740 self
741 }
742
743 pub fn get_l1_pubdata_price(&self) -> u64 {
745 self.l1_pubdata_price.unwrap_or(DEFAULT_FAIR_PUBDATA_PRICE)
746 }
747
748 pub fn update_l1_pubdata_price(&mut self, price: Option<u64>) -> &mut Self {
750 self.l1_pubdata_price = price;
751 self
752 }
753
754 #[must_use]
756 pub fn with_log_level(mut self, level: Option<LogLevel>) -> Self {
757 if let Some(level) = level {
758 self.log_level = level;
759 }
760 self
761 }
762
763 pub fn get_log_level(&self) -> LogLevel {
765 self.log_level
766 }
767
768 pub fn get_cache_dir(&self) -> &str {
770 &self.cache_dir
771 }
772
773 #[must_use]
775 pub fn with_cache_dir(mut self, dir: Option<String>) -> Self {
776 if let Some(dir) = dir {
777 self.cache_dir = dir;
778 }
779 self
780 }
781
782 #[must_use]
784 pub fn with_cache_config(mut self, config: Option<CacheConfig>) -> Self {
785 if let Some(config) = config {
786 self.cache_config = config;
787 }
788 self
789 }
790
791 pub fn get_cache_config(&self) -> &CacheConfig {
793 &self.cache_config
794 }
795
796 #[must_use]
798 pub fn with_log_file_path(mut self, path: Option<String>) -> Self {
799 if let Some(path) = path {
800 self.log_file_path = path;
801 }
802 self
803 }
804
805 pub fn get_log_file_path(&self) -> &str {
807 &self.log_file_path
808 }
809
810 #[must_use]
812 pub fn with_verbosity_level(mut self, verbosity: u8) -> Self {
813 self.verbosity = verbosity;
814 self
815 }
816
817 pub fn get_verbosity_level(&self) -> u8 {
819 self.verbosity
820 }
821
822 #[must_use]
824 pub fn with_silent(mut self, silent: Option<bool>) -> Self {
825 if let Some(silent) = silent {
826 self.silent = silent;
827 }
828 self
829 }
830
831 #[must_use]
833 pub fn with_show_node_config(mut self, show_node_config: Option<bool>) -> Self {
834 if let Some(show_node_config) = show_node_config {
835 self.show_node_config = show_node_config;
836 }
837 self
838 }
839
840 #[must_use]
842 pub fn with_show_storage_logs(mut self, show_storage_logs: Option<ShowStorageLogs>) -> Self {
843 if let Some(show_storage_logs) = show_storage_logs {
844 self.show_storage_logs = show_storage_logs;
845 }
846 self
847 }
848
849 pub fn get_show_storage_logs(&self) -> ShowStorageLogs {
851 self.show_storage_logs
852 }
853
854 #[must_use]
856 pub fn with_vm_log_detail(mut self, detail: Option<ShowVMDetails>) -> Self {
857 if let Some(detail) = detail {
858 self.show_vm_details = detail;
859 }
860 self
861 }
862
863 pub fn get_vm_log_detail(&self) -> ShowVMDetails {
865 self.show_vm_details
866 }
867
868 #[must_use]
870 pub fn with_show_gas_details(mut self, show_gas_details: Option<ShowGasDetails>) -> Self {
871 if let Some(show_gas_details) = show_gas_details {
872 self.show_gas_details = show_gas_details;
873 }
874 self
875 }
876
877 pub fn get_show_gas_details(&self) -> ShowGasDetails {
879 self.show_gas_details
880 }
881
882 #[must_use]
884 pub fn with_gas_limit_scale(mut self, scale: Option<f32>) -> Self {
885 if let Some(scale) = scale {
886 self.limit_scale_factor = Some(scale);
887 }
888 self
889 }
890
891 pub fn get_gas_limit_scale(&self) -> f32 {
893 self.limit_scale_factor
894 .unwrap_or(DEFAULT_ESTIMATE_GAS_SCALE_FACTOR)
895 }
896
897 pub fn update_gas_limit_scale(&mut self, scale: Option<f32>) -> &mut Self {
899 self.limit_scale_factor = scale;
900 self
901 }
902
903 #[must_use]
905 pub fn with_price_scale(mut self, scale: Option<f64>) -> Self {
906 if let Some(scale) = scale {
907 self.price_scale_factor = Some(scale);
908 }
909 self
910 }
911
912 pub fn get_price_scale(&self) -> f64 {
914 self.price_scale_factor
915 .unwrap_or(DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR)
916 }
917
918 pub fn update_price_scale(&mut self, scale: Option<f64>) -> &mut Self {
920 self.price_scale_factor = scale;
921 self
922 }
923
924 #[must_use]
926 pub fn with_genesis_balance<U: Into<U256>>(mut self, balance: U) -> Self {
927 self.genesis_balance = balance.into();
928 self
929 }
930
931 #[must_use]
933 pub fn with_genesis_accounts(mut self, accounts: Vec<PrivateKeySigner>) -> Self {
934 self.genesis_accounts = accounts;
935 self
936 }
937
938 #[must_use]
940 pub fn with_signer_accounts(mut self, accounts: Vec<PrivateKeySigner>) -> Self {
941 self.signer_accounts = accounts;
942 self
943 }
944
945 #[must_use]
948 pub fn with_account_generator(mut self, generator: AccountGenerator) -> Self {
949 let accounts = generator.generate();
950 self.account_generator = Some(generator);
951 self.with_signer_accounts(accounts.clone())
952 .with_genesis_accounts(accounts)
953 }
954
955 #[must_use]
957 pub fn with_genesis_timestamp(mut self, timestamp: Option<u64>) -> Self {
958 self.genesis_timestamp = timestamp;
959 self
960 }
961
962 pub fn get_genesis_timestamp(&self) -> u64 {
964 self.genesis_timestamp
965 .unwrap_or(NON_FORK_FIRST_BLOCK_TIMESTAMP)
966 }
967
968 #[must_use]
970 pub fn with_genesis(mut self, genesis: Option<Genesis>) -> Self {
971 self.genesis = genesis;
972 self
973 }
974
975 #[must_use]
977 pub fn with_auto_impersonate(mut self, enable_auto_impersonate: bool) -> Self {
978 self.enable_auto_impersonate = enable_auto_impersonate;
979 self
980 }
981
982 #[must_use]
984 pub fn with_offline(mut self, offline: Option<bool>) -> Self {
985 if let Some(offline) = offline {
986 self.offline = offline;
987 }
988 self
989 }
990
991 pub fn is_offline(&self) -> bool {
993 self.offline
994 }
995
996 #[must_use]
998 pub fn with_host(mut self, host: Vec<IpAddr>) -> Self {
999 self.host = if host.is_empty() {
1000 vec![IpAddr::V4(Ipv4Addr::LOCALHOST)]
1001 } else {
1002 host
1003 };
1004 self
1005 }
1006 #[must_use]
1008 pub fn with_health_check_endpoint(mut self, health_check_endpoint: Option<bool>) -> Self {
1009 if let Some(health_check_endpoint) = health_check_endpoint {
1010 self.health_check_endpoint = health_check_endpoint;
1011 }
1012 self
1013 }
1014
1015 pub fn is_health_check_endpoint_endpoint_enabled(&self) -> bool {
1017 self.health_check_endpoint
1018 }
1019
1020 #[must_use]
1022 pub fn with_block_time(mut self, block_time: Option<Duration>) -> Self {
1023 self.block_time = block_time;
1024 self
1025 }
1026
1027 #[must_use]
1029 pub fn with_no_mining(mut self, no_mining: bool) -> Self {
1030 self.no_mining = no_mining;
1031 self
1032 }
1033
1034 #[must_use]
1036 pub fn with_transaction_order(mut self, transaction_order: TransactionOrder) -> Self {
1037 self.transaction_order = transaction_order;
1038 self
1039 }
1040
1041 #[must_use]
1043 pub fn with_allow_origin(mut self, allow_origin: String) -> Self {
1044 self.allow_origin = allow_origin;
1045 self
1046 }
1047
1048 #[must_use]
1050 pub fn with_no_cors(mut self, no_cors: bool) -> Self {
1051 self.no_cors = no_cors;
1052 self
1053 }
1054
1055 #[must_use]
1057 pub fn with_state(mut self, state: Option<PathBuf>) -> Self {
1058 self.state = state;
1059 self
1060 }
1061
1062 #[must_use]
1064 pub fn with_dump_state(mut self, dump_state: Option<PathBuf>) -> Self {
1065 self.dump_state = dump_state;
1066 self
1067 }
1068
1069 #[must_use]
1071 pub fn with_state_interval(mut self, state_interval: Option<u64>) -> Self {
1072 self.state_interval = state_interval;
1073 self
1074 }
1075
1076 #[must_use]
1078 pub fn with_preserve_historical_states(mut self, preserve_historical_states: bool) -> Self {
1079 self.preserve_historical_states = preserve_historical_states;
1080 self
1081 }
1082
1083 #[must_use]
1085 pub fn with_load_state(mut self, load_state: Option<PathBuf>) -> Self {
1086 self.load_state = load_state;
1087 self
1088 }
1089
1090 #[must_use]
1092 pub fn with_l1_config(mut self, l1_config: Option<L1Config>) -> Self {
1093 self.l1_config = l1_config;
1094 self
1095 }
1096
1097 #[must_use]
1099 pub fn with_auto_execute_l1(mut self, auto_execute_l1: Option<bool>) -> Self {
1100 self.auto_execute_l1 = auto_execute_l1.unwrap_or(false);
1101 self
1102 }
1103
1104 #[must_use]
1106 pub fn with_base_token_config(mut self, base_token_config: BaseTokenConfig) -> Self {
1107 self.base_token_config = base_token_config;
1108 self
1109 }
1110
1111 #[must_use]
1112 pub fn with_debug_trace(mut self, debug: Option<DebugTraceConfig>) -> Self {
1113 self.debug_trace = debug;
1114 self
1115 }
1116
1117 pub fn get_debug_trace(&self) -> Option<&DebugTraceConfig> {
1119 self.debug_trace.as_ref()
1120 }
1121}