1use crate::{
2 eth::{
3 backend::{
4 db::{Db, SerializableState},
5 fork::{ClientFork, ClientForkConfig},
6 genesis::GenesisConfig,
7 mem::fork_db::ForkedDatabase,
8 time::duration_since_unix_epoch,
9 },
10 fees::{INITIAL_BASE_FEE, INITIAL_GAS_PRICE},
11 pool::transactions::{PoolTransaction, TransactionOrder},
12 },
13 hardfork::{ChainHardfork, OptimismHardfork},
14 mem::{self, in_memory_db::MemDb},
15 EthereumHardfork, FeeManager, PrecompileFactory,
16};
17use alloy_consensus::BlockHeader;
18use alloy_genesis::Genesis;
19use alloy_network::{AnyNetwork, TransactionResponse};
20use alloy_primitives::{hex, map::HashMap, utils::Unit, BlockNumber, TxHash, U256};
21use alloy_provider::Provider;
22use alloy_rpc_types::{Block, BlockNumberOrTag};
23use alloy_signer::Signer;
24use alloy_signer_local::{
25 coins_bip39::{English, Mnemonic},
26 MnemonicBuilder, PrivateKeySigner,
27};
28use alloy_transport::TransportError;
29use anvil_server::ServerConfig;
30use eyre::{Context, Result};
31use foundry_common::{
32 provider::{ProviderBuilder, RetryProvider},
33 ALCHEMY_FREE_TIER_CUPS, NON_ARCHIVE_NODE_WARNING, REQUEST_TIMEOUT,
34};
35use foundry_config::Config;
36use foundry_evm::{
37 backend::{BlockchainDb, BlockchainDbMeta, SharedBackend},
38 constants::DEFAULT_CREATE2_DEPLOYER,
39 revm::primitives::{BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, SpecId, TxEnv},
40 utils::apply_chain_and_block_specific_env_changes,
41};
42use itertools::Itertools;
43use parking_lot::RwLock;
44use rand::thread_rng;
45use revm::primitives::BlobExcessGasAndPrice;
46use serde_json::{json, Value};
47use std::{
48 fmt::Write as FmtWrite,
49 fs::File,
50 io,
51 net::{IpAddr, Ipv4Addr},
52 path::PathBuf,
53 sync::Arc,
54 time::Duration,
55};
56use tokio::sync::RwLock as TokioRwLock;
57use yansi::Paint;
58
59pub use foundry_common::version::SHORT_VERSION as VERSION_MESSAGE;
60
61pub const NODE_PORT: u16 = 8545;
63pub const CHAIN_ID: u64 = 31337;
65pub const DEFAULT_GAS_LIMIT: u128 = 30_000_000;
67pub const DEFAULT_MNEMONIC: &str = "test test test test test test test test test test test junk";
69
70pub const DEFAULT_IPC_ENDPOINT: &str =
72 if cfg!(unix) { "/tmp/anvil.ipc" } else { r"\\.\pipe\anvil.ipc" };
73
74const BANNER: &str = r"
75 _ _
76 (_) | |
77 __ _ _ __ __ __ _ | |
78 / _` | | '_ \ \ \ / / | | | |
79 | (_| | | | | | \ V / | | | |
80 \__,_| |_| |_| \_/ |_| |_|
81";
82
83#[derive(Clone, Debug)]
85pub struct NodeConfig {
86 pub chain_id: Option<u64>,
88 pub gas_limit: Option<u128>,
90 pub disable_block_gas_limit: bool,
92 pub gas_price: Option<u128>,
94 pub base_fee: Option<u64>,
96 pub disable_min_priority_fee: bool,
98 pub blob_excess_gas_and_price: Option<BlobExcessGasAndPrice>,
100 pub hardfork: Option<ChainHardfork>,
102 pub genesis_accounts: Vec<PrivateKeySigner>,
104 pub genesis_balance: U256,
106 pub genesis_timestamp: Option<u64>,
108 pub genesis_block_number: Option<u64>,
110 pub signer_accounts: Vec<PrivateKeySigner>,
112 pub block_time: Option<Duration>,
114 pub no_mining: bool,
116 pub mixed_mining: bool,
118 pub port: u16,
120 pub max_transactions: usize,
122 pub eth_rpc_url: Option<String>,
124 pub fork_choice: Option<ForkChoice>,
126 pub fork_headers: Vec<String>,
128 pub fork_chain_id: Option<U256>,
130 pub account_generator: Option<AccountGenerator>,
132 pub enable_tracing: bool,
134 pub no_storage_caching: bool,
136 pub server_config: ServerConfig,
138 pub host: Vec<IpAddr>,
140 pub transaction_order: TransactionOrder,
142 pub config_out: Option<PathBuf>,
144 pub genesis: Option<Genesis>,
146 pub fork_request_timeout: Duration,
148 pub fork_request_retries: u32,
150 pub fork_retry_backoff: Duration,
152 pub compute_units_per_second: u64,
154 pub ipc_path: Option<Option<String>>,
156 pub enable_steps_tracing: bool,
158 pub print_logs: bool,
160 pub print_traces: bool,
162 pub enable_auto_impersonate: bool,
164 pub code_size_limit: Option<usize>,
166 pub prune_history: PruneStateHistoryConfig,
170 pub max_persisted_states: Option<usize>,
172 pub init_state: Option<SerializableState>,
174 pub transaction_block_keeper: Option<usize>,
176 pub disable_default_create2_deployer: bool,
178 pub enable_optimism: bool,
180 pub slots_in_an_epoch: u64,
182 pub memory_limit: Option<u64>,
184 pub precompile_factory: Option<Arc<dyn PrecompileFactory>>,
186 pub odyssey: bool,
188 pub silent: bool,
190 pub cache_path: Option<PathBuf>,
192}
193
194impl NodeConfig {
195 fn as_string(&self, fork: Option<&ClientFork>) -> String {
196 let mut s: String = String::new();
197 let _ = write!(s, "\n{}", BANNER.green());
198 let _ = write!(s, "\n {VERSION_MESSAGE}");
199 let _ = write!(s, "\n {}", "https://github.com/foundry-rs/foundry".green());
200
201 let _ = write!(
202 s,
203 r#"
204
205Available Accounts
206==================
207"#
208 );
209 let balance = alloy_primitives::utils::format_ether(self.genesis_balance);
210 for (idx, wallet) in self.genesis_accounts.iter().enumerate() {
211 write!(s, "\n({idx}) {} ({balance} ETH)", wallet.address()).unwrap();
212 }
213
214 let _ = write!(
215 s,
216 r#"
217
218Private Keys
219==================
220"#
221 );
222
223 for (idx, wallet) in self.genesis_accounts.iter().enumerate() {
224 let hex = hex::encode(wallet.credential().to_bytes());
225 let _ = write!(s, "\n({idx}) 0x{hex}");
226 }
227
228 if let Some(ref gen) = self.account_generator {
229 let _ = write!(
230 s,
231 r#"
232
233Wallet
234==================
235Mnemonic: {}
236Derivation path: {}
237"#,
238 gen.phrase,
239 gen.get_derivation_path()
240 );
241 }
242
243 if let Some(fork) = fork {
244 let _ = write!(
245 s,
246 r#"
247
248Fork
249==================
250Endpoint: {}
251Block number: {}
252Block hash: {:?}
253Chain ID: {}
254"#,
255 fork.eth_rpc_url(),
256 fork.block_number(),
257 fork.block_hash(),
258 fork.chain_id()
259 );
260
261 if let Some(tx_hash) = fork.transaction_hash() {
262 let _ = writeln!(s, "Transaction hash: {tx_hash}");
263 }
264 } else {
265 let _ = write!(
266 s,
267 r#"
268
269Chain ID
270==================
271
272{}
273"#,
274 self.get_chain_id().green()
275 );
276 }
277
278 if (SpecId::from(self.get_hardfork()) as u8) < (SpecId::LONDON as u8) {
279 let _ = write!(
280 s,
281 r#"
282Gas Price
283==================
284
285{}
286"#,
287 self.get_gas_price().green()
288 );
289 } else {
290 let _ = write!(
291 s,
292 r#"
293Base Fee
294==================
295
296{}
297"#,
298 self.get_base_fee().green()
299 );
300 }
301
302 let _ = write!(
303 s,
304 r#"
305Gas Limit
306==================
307
308{}
309"#,
310 {
311 if self.disable_block_gas_limit {
312 "Disabled".to_string()
313 } else {
314 self.gas_limit.map(|l| l.to_string()).unwrap_or_else(|| {
315 if self.fork_choice.is_some() {
316 "Forked".to_string()
317 } else {
318 DEFAULT_GAS_LIMIT.to_string()
319 }
320 })
321 }
322 }
323 .green()
324 );
325
326 let _ = write!(
327 s,
328 r#"
329Genesis Timestamp
330==================
331
332{}
333"#,
334 self.get_genesis_timestamp().green()
335 );
336
337 let _ = write!(
338 s,
339 r#"
340Genesis Number
341==================
342
343{}
344"#,
345 self.get_genesis_number().green()
346 );
347
348 s
349 }
350
351 fn as_json(&self, fork: Option<&ClientFork>) -> Value {
352 let mut wallet_description = HashMap::new();
353 let mut available_accounts = Vec::with_capacity(self.genesis_accounts.len());
354 let mut private_keys = Vec::with_capacity(self.genesis_accounts.len());
355
356 for wallet in &self.genesis_accounts {
357 available_accounts.push(format!("{:?}", wallet.address()));
358 private_keys.push(format!("0x{}", hex::encode(wallet.credential().to_bytes())));
359 }
360
361 if let Some(ref gen) = self.account_generator {
362 let phrase = gen.get_phrase().to_string();
363 let derivation_path = gen.get_derivation_path().to_string();
364
365 wallet_description.insert("derivation_path".to_string(), derivation_path);
366 wallet_description.insert("mnemonic".to_string(), phrase);
367 };
368
369 let gas_limit = match self.gas_limit {
370 Some(_) | None if self.disable_block_gas_limit => Some(u64::MAX.to_string()),
372 Some(limit) => Some(limit.to_string()),
373 _ => None,
374 };
375
376 if let Some(fork) = fork {
377 json!({
378 "available_accounts": available_accounts,
379 "private_keys": private_keys,
380 "endpoint": fork.eth_rpc_url(),
381 "block_number": fork.block_number(),
382 "block_hash": fork.block_hash(),
383 "chain_id": fork.chain_id(),
384 "wallet": wallet_description,
385 "base_fee": format!("{}", self.get_base_fee()),
386 "gas_price": format!("{}", self.get_gas_price()),
387 "gas_limit": gas_limit,
388 })
389 } else {
390 json!({
391 "available_accounts": available_accounts,
392 "private_keys": private_keys,
393 "wallet": wallet_description,
394 "base_fee": format!("{}", self.get_base_fee()),
395 "gas_price": format!("{}", self.get_gas_price()),
396 "gas_limit": gas_limit,
397 "genesis_timestamp": format!("{}", self.get_genesis_timestamp()),
398 })
399 }
400 }
401}
402
403impl NodeConfig {
404 #[doc(hidden)]
407 pub fn test() -> Self {
408 Self { enable_tracing: true, port: 0, silent: true, ..Default::default() }
409 }
410
411 pub fn empty_state() -> Self {
413 Self {
414 genesis_accounts: vec![],
415 signer_accounts: vec![],
416 disable_default_create2_deployer: true,
417 ..Default::default()
418 }
419 }
420}
421
422impl Default for NodeConfig {
423 fn default() -> Self {
424 let genesis_accounts =
426 AccountGenerator::new(10).phrase(DEFAULT_MNEMONIC).gen().expect("Invalid mnemonic.");
427 Self {
428 chain_id: None,
429 gas_limit: None,
430 disable_block_gas_limit: false,
431 gas_price: None,
432 hardfork: None,
433 signer_accounts: genesis_accounts.clone(),
434 genesis_timestamp: None,
435 genesis_block_number: None,
436 genesis_accounts,
437 genesis_balance: Unit::ETHER.wei().saturating_mul(U256::from(100u64)),
439 block_time: None,
440 no_mining: false,
441 mixed_mining: false,
442 port: NODE_PORT,
443 max_transactions: 1_000,
445 eth_rpc_url: None,
446 fork_choice: None,
447 account_generator: None,
448 base_fee: None,
449 disable_min_priority_fee: false,
450 blob_excess_gas_and_price: None,
451 enable_tracing: true,
452 enable_steps_tracing: false,
453 print_logs: true,
454 print_traces: false,
455 enable_auto_impersonate: false,
456 no_storage_caching: false,
457 server_config: Default::default(),
458 host: vec![IpAddr::V4(Ipv4Addr::LOCALHOST)],
459 transaction_order: Default::default(),
460 config_out: None,
461 genesis: None,
462 fork_request_timeout: REQUEST_TIMEOUT,
463 fork_headers: vec![],
464 fork_request_retries: 5,
465 fork_retry_backoff: Duration::from_millis(1_000),
466 fork_chain_id: None,
467 compute_units_per_second: ALCHEMY_FREE_TIER_CUPS,
469 ipc_path: None,
470 code_size_limit: None,
471 prune_history: Default::default(),
472 max_persisted_states: None,
473 init_state: None,
474 transaction_block_keeper: None,
475 disable_default_create2_deployer: false,
476 enable_optimism: false,
477 slots_in_an_epoch: 32,
478 memory_limit: None,
479 precompile_factory: None,
480 odyssey: false,
481 silent: false,
482 cache_path: None,
483 }
484 }
485}
486
487impl NodeConfig {
488 #[must_use]
490 pub fn with_memory_limit(mut self, mems_value: Option<u64>) -> Self {
491 self.memory_limit = mems_value;
492 self
493 }
494 pub fn get_base_fee(&self) -> u64 {
496 self.base_fee
497 .or_else(|| self.genesis.as_ref().and_then(|g| g.base_fee_per_gas.map(|g| g as u64)))
498 .unwrap_or(INITIAL_BASE_FEE)
499 }
500
501 pub fn get_gas_price(&self) -> u128 {
503 self.gas_price.unwrap_or(INITIAL_GAS_PRICE)
504 }
505
506 pub fn get_blob_excess_gas_and_price(&self) -> BlobExcessGasAndPrice {
507 if let Some(blob_excess_gas_and_price) = &self.blob_excess_gas_and_price {
508 blob_excess_gas_and_price.clone()
509 } else if let Some(excess_blob_gas) = self.genesis.as_ref().and_then(|g| g.excess_blob_gas)
510 {
511 BlobExcessGasAndPrice::new(excess_blob_gas, false)
512 } else {
513 BlobExcessGasAndPrice::new(0, false)
515 }
516 }
517
518 pub fn get_hardfork(&self) -> ChainHardfork {
520 if self.odyssey {
521 return ChainHardfork::Ethereum(EthereumHardfork::PragueEOF);
522 }
523 if let Some(hardfork) = self.hardfork {
524 return hardfork;
525 }
526 if self.enable_optimism {
527 return OptimismHardfork::default().into();
528 }
529 EthereumHardfork::default().into()
530 }
531
532 #[must_use]
534 pub fn with_code_size_limit(mut self, code_size_limit: Option<usize>) -> Self {
535 self.code_size_limit = code_size_limit;
536 self
537 }
538 #[must_use]
540 pub fn disable_code_size_limit(mut self, disable_code_size_limit: bool) -> Self {
541 if disable_code_size_limit {
542 self.code_size_limit = Some(usize::MAX);
543 }
544 self
545 }
546
547 #[must_use]
549 pub fn with_init_state(mut self, init_state: Option<SerializableState>) -> Self {
550 self.init_state = init_state;
551 self
552 }
553
554 #[must_use]
556 #[cfg(feature = "cmd")]
557 pub fn with_init_state_path(mut self, path: impl AsRef<std::path::Path>) -> Self {
558 self.init_state = crate::cmd::StateFile::parse_path(path).ok().and_then(|file| file.state);
559 self
560 }
561
562 #[must_use]
564 pub fn with_chain_id<U: Into<u64>>(mut self, chain_id: Option<U>) -> Self {
565 self.set_chain_id(chain_id);
566 self
567 }
568
569 pub fn get_chain_id(&self) -> u64 {
571 self.chain_id
572 .or_else(|| self.genesis.as_ref().map(|g| g.config.chain_id))
573 .unwrap_or(CHAIN_ID)
574 }
575
576 pub fn set_chain_id(&mut self, chain_id: Option<impl Into<u64>>) {
578 self.chain_id = chain_id.map(Into::into);
579 let chain_id = self.get_chain_id();
580 self.genesis_accounts.iter_mut().for_each(|wallet| {
581 *wallet = wallet.clone().with_chain_id(Some(chain_id));
582 });
583 self.signer_accounts.iter_mut().for_each(|wallet| {
584 *wallet = wallet.clone().with_chain_id(Some(chain_id));
585 })
586 }
587
588 #[must_use]
590 pub fn with_gas_limit(mut self, gas_limit: Option<u128>) -> Self {
591 self.gas_limit = gas_limit;
592 self
593 }
594
595 #[must_use]
599 pub fn disable_block_gas_limit(mut self, disable_block_gas_limit: bool) -> Self {
600 self.disable_block_gas_limit = disable_block_gas_limit;
601 self
602 }
603
604 #[must_use]
606 pub fn with_gas_price(mut self, gas_price: Option<u128>) -> Self {
607 self.gas_price = gas_price;
608 self
609 }
610
611 #[must_use]
613 pub fn set_pruned_history(mut self, prune_history: Option<Option<usize>>) -> Self {
614 self.prune_history = PruneStateHistoryConfig::from_args(prune_history);
615 self
616 }
617
618 #[must_use]
620 pub fn with_max_persisted_states<U: Into<usize>>(
621 mut self,
622 max_persisted_states: Option<U>,
623 ) -> Self {
624 self.max_persisted_states = max_persisted_states.map(Into::into);
625 self
626 }
627
628 #[must_use]
630 pub fn with_transaction_block_keeper<U: Into<usize>>(
631 mut self,
632 transaction_block_keeper: Option<U>,
633 ) -> Self {
634 self.transaction_block_keeper = transaction_block_keeper.map(Into::into);
635 self
636 }
637
638 #[must_use]
640 pub fn with_base_fee(mut self, base_fee: Option<u64>) -> Self {
641 self.base_fee = base_fee;
642 self
643 }
644
645 #[must_use]
647 pub fn disable_min_priority_fee(mut self, disable_min_priority_fee: bool) -> Self {
648 self.disable_min_priority_fee = disable_min_priority_fee;
649 self
650 }
651
652 #[must_use]
654 pub fn with_genesis(mut self, genesis: Option<Genesis>) -> Self {
655 self.genesis = genesis;
656 self
657 }
658
659 pub fn get_genesis_timestamp(&self) -> u64 {
661 self.genesis_timestamp
662 .or_else(|| self.genesis.as_ref().map(|g| g.timestamp))
663 .unwrap_or_else(|| duration_since_unix_epoch().as_secs())
664 }
665
666 #[must_use]
668 pub fn with_genesis_timestamp<U: Into<u64>>(mut self, timestamp: Option<U>) -> Self {
669 if let Some(timestamp) = timestamp {
670 self.genesis_timestamp = Some(timestamp.into());
671 }
672 self
673 }
674
675 #[must_use]
677 pub fn with_genesis_block_number<U: Into<u64>>(mut self, number: Option<U>) -> Self {
678 if let Some(number) = number {
679 self.genesis_block_number = Some(number.into());
680 }
681 self
682 }
683
684 pub fn get_genesis_number(&self) -> u64 {
686 self.genesis_block_number
687 .or_else(|| self.genesis.as_ref().and_then(|g| g.number))
688 .unwrap_or(0)
689 }
690
691 #[must_use]
693 pub fn with_hardfork(mut self, hardfork: Option<ChainHardfork>) -> Self {
694 self.hardfork = hardfork;
695 self
696 }
697
698 #[must_use]
700 pub fn with_genesis_accounts(mut self, accounts: Vec<PrivateKeySigner>) -> Self {
701 self.genesis_accounts = accounts;
702 self
703 }
704
705 #[must_use]
707 pub fn with_signer_accounts(mut self, accounts: Vec<PrivateKeySigner>) -> Self {
708 self.signer_accounts = accounts;
709 self
710 }
711
712 pub fn with_account_generator(mut self, generator: AccountGenerator) -> eyre::Result<Self> {
715 let accounts = generator.gen()?;
716 self.account_generator = Some(generator);
717 Ok(self.with_signer_accounts(accounts.clone()).with_genesis_accounts(accounts))
718 }
719
720 #[must_use]
722 pub fn with_genesis_balance<U: Into<U256>>(mut self, balance: U) -> Self {
723 self.genesis_balance = balance.into();
724 self
725 }
726
727 #[must_use]
729 pub fn with_blocktime<D: Into<Duration>>(mut self, block_time: Option<D>) -> Self {
730 self.block_time = block_time.map(Into::into);
731 self
732 }
733
734 #[must_use]
735 pub fn with_mixed_mining<D: Into<Duration>>(
736 mut self,
737 mixed_mining: bool,
738 block_time: Option<D>,
739 ) -> Self {
740 self.block_time = block_time.map(Into::into);
741 self.mixed_mining = mixed_mining;
742 self
743 }
744
745 #[must_use]
747 pub fn with_no_mining(mut self, no_mining: bool) -> Self {
748 self.no_mining = no_mining;
749 self
750 }
751
752 #[must_use]
754 pub fn with_slots_in_an_epoch(mut self, slots_in_an_epoch: u64) -> Self {
755 self.slots_in_an_epoch = slots_in_an_epoch;
756 self
757 }
758
759 #[must_use]
761 pub fn with_port(mut self, port: u16) -> Self {
762 self.port = port;
763 self
764 }
765
766 #[must_use]
773 pub fn with_ipc(mut self, ipc_path: Option<Option<String>>) -> Self {
774 self.ipc_path = ipc_path;
775 self
776 }
777
778 #[must_use]
780 pub fn set_config_out(mut self, config_out: Option<PathBuf>) -> Self {
781 self.config_out = config_out;
782 self
783 }
784
785 #[must_use]
787 pub fn no_storage_caching(self) -> Self {
788 self.with_storage_caching(true)
789 }
790
791 #[must_use]
792 pub fn with_storage_caching(mut self, storage_caching: bool) -> Self {
793 self.no_storage_caching = storage_caching;
794 self
795 }
796
797 #[must_use]
799 pub fn with_eth_rpc_url<U: Into<String>>(mut self, eth_rpc_url: Option<U>) -> Self {
800 self.eth_rpc_url = eth_rpc_url.map(Into::into);
801 self
802 }
803
804 #[must_use]
806 pub fn with_fork_block_number<U: Into<u64>>(self, fork_block_number: Option<U>) -> Self {
807 self.with_fork_choice(fork_block_number.map(Into::into))
808 }
809
810 #[must_use]
812 pub fn with_fork_transaction_hash<U: Into<TxHash>>(
813 self,
814 fork_transaction_hash: Option<U>,
815 ) -> Self {
816 self.with_fork_choice(fork_transaction_hash.map(Into::into))
817 }
818
819 #[must_use]
821 pub fn with_fork_choice<U: Into<ForkChoice>>(mut self, fork_choice: Option<U>) -> Self {
822 self.fork_choice = fork_choice.map(Into::into);
823 self
824 }
825
826 #[must_use]
828 pub fn with_fork_chain_id(mut self, fork_chain_id: Option<U256>) -> Self {
829 self.fork_chain_id = fork_chain_id;
830 self
831 }
832
833 #[must_use]
835 pub fn with_fork_headers(mut self, headers: Vec<String>) -> Self {
836 self.fork_headers = headers;
837 self
838 }
839
840 #[must_use]
842 pub fn fork_request_timeout(mut self, fork_request_timeout: Option<Duration>) -> Self {
843 if let Some(fork_request_timeout) = fork_request_timeout {
844 self.fork_request_timeout = fork_request_timeout;
845 }
846 self
847 }
848
849 #[must_use]
851 pub fn fork_request_retries(mut self, fork_request_retries: Option<u32>) -> Self {
852 if let Some(fork_request_retries) = fork_request_retries {
853 self.fork_request_retries = fork_request_retries;
854 }
855 self
856 }
857
858 #[must_use]
860 pub fn fork_retry_backoff(mut self, fork_retry_backoff: Option<Duration>) -> Self {
861 if let Some(fork_retry_backoff) = fork_retry_backoff {
862 self.fork_retry_backoff = fork_retry_backoff;
863 }
864 self
865 }
866
867 #[must_use]
871 pub fn fork_compute_units_per_second(mut self, compute_units_per_second: Option<u64>) -> Self {
872 if let Some(compute_units_per_second) = compute_units_per_second {
873 self.compute_units_per_second = compute_units_per_second;
874 }
875 self
876 }
877
878 #[must_use]
880 pub fn with_tracing(mut self, enable_tracing: bool) -> Self {
881 self.enable_tracing = enable_tracing;
882 self
883 }
884
885 #[must_use]
887 pub fn with_steps_tracing(mut self, enable_steps_tracing: bool) -> Self {
888 self.enable_steps_tracing = enable_steps_tracing;
889 self
890 }
891
892 #[must_use]
894 pub fn with_print_logs(mut self, print_logs: bool) -> Self {
895 self.print_logs = print_logs;
896 self
897 }
898
899 #[must_use]
901 pub fn with_print_traces(mut self, print_traces: bool) -> Self {
902 self.print_traces = print_traces;
903 self
904 }
905
906 #[must_use]
908 pub fn with_auto_impersonate(mut self, enable_auto_impersonate: bool) -> Self {
909 self.enable_auto_impersonate = enable_auto_impersonate;
910 self
911 }
912
913 #[must_use]
914 pub fn with_server_config(mut self, config: ServerConfig) -> Self {
915 self.server_config = config;
916 self
917 }
918
919 #[must_use]
921 pub fn with_host(mut self, host: Vec<IpAddr>) -> Self {
922 self.host = if host.is_empty() { vec![IpAddr::V4(Ipv4Addr::LOCALHOST)] } else { host };
923 self
924 }
925
926 #[must_use]
927 pub fn with_transaction_order(mut self, transaction_order: TransactionOrder) -> Self {
928 self.transaction_order = transaction_order;
929 self
930 }
931
932 pub fn get_ipc_path(&self) -> Option<String> {
934 match &self.ipc_path {
935 Some(path) => path.clone().or_else(|| Some(DEFAULT_IPC_ENDPOINT.to_string())),
936 None => None,
937 }
938 }
939
940 pub fn print(&self, fork: Option<&ClientFork>) -> Result<()> {
942 if let Some(path) = &self.config_out {
943 let file = io::BufWriter::new(
944 File::create(path).wrap_err("unable to create anvil config description file")?,
945 );
946 let value = self.as_json(fork);
947 serde_json::to_writer(file, &value).wrap_err("failed writing JSON")?;
948 }
949 if !self.silent {
950 sh_println!("{}", self.as_string(fork))?;
951 }
952 Ok(())
953 }
954
955 pub fn block_cache_path(&self, block: u64) -> Option<PathBuf> {
959 if self.no_storage_caching || self.eth_rpc_url.is_none() {
960 return None;
961 }
962 let chain_id = self.get_chain_id();
963
964 Config::foundry_block_cache_file(chain_id, block)
965 }
966
967 #[must_use]
969 pub fn with_optimism(mut self, enable_optimism: bool) -> Self {
970 self.enable_optimism = enable_optimism;
971 self
972 }
973
974 #[must_use]
976 pub fn with_disable_default_create2_deployer(mut self, yes: bool) -> Self {
977 self.disable_default_create2_deployer = yes;
978 self
979 }
980
981 #[must_use]
983 pub fn with_precompile_factory(mut self, factory: impl PrecompileFactory + 'static) -> Self {
984 self.precompile_factory = Some(Arc::new(factory));
985 self
986 }
987
988 #[must_use]
990 pub fn with_odyssey(mut self, odyssey: bool) -> Self {
991 self.odyssey = odyssey;
992 self
993 }
994
995 #[must_use]
997 pub fn silent(self) -> Self {
998 self.set_silent(true)
999 }
1000
1001 #[must_use]
1002 pub fn set_silent(mut self, silent: bool) -> Self {
1003 self.silent = silent;
1004 self
1005 }
1006
1007 #[must_use]
1009 pub fn with_cache_path(mut self, cache_path: Option<PathBuf>) -> Self {
1010 self.cache_path = cache_path;
1011 self
1012 }
1013
1014 pub(crate) async fn setup(&mut self) -> Result<mem::Backend> {
1019 let mut cfg =
1022 CfgEnvWithHandlerCfg::new_with_spec_id(CfgEnv::default(), self.get_hardfork().into());
1023 cfg.chain_id = self.get_chain_id();
1024 cfg.limit_contract_code_size = self.code_size_limit;
1025 cfg.disable_eip3607 = true;
1029 cfg.disable_block_gas_limit = self.disable_block_gas_limit;
1030 cfg.handler_cfg.is_optimism = self.enable_optimism;
1031
1032 if let Some(value) = self.memory_limit {
1033 cfg.memory_limit = value;
1034 }
1035
1036 let env = revm::primitives::Env {
1037 cfg: cfg.cfg_env,
1038 block: BlockEnv {
1039 gas_limit: U256::from(self.gas_limit()),
1040 basefee: U256::from(self.get_base_fee()),
1041 ..Default::default()
1042 },
1043 tx: TxEnv { chain_id: self.get_chain_id().into(), ..Default::default() },
1044 };
1045 let mut env = EnvWithHandlerCfg::new(Box::new(env), cfg.handler_cfg);
1046
1047 let fees = FeeManager::new(
1048 cfg.handler_cfg.spec_id,
1049 self.get_base_fee(),
1050 !self.disable_min_priority_fee,
1051 self.get_gas_price(),
1052 self.get_blob_excess_gas_and_price(),
1053 );
1054
1055 let (db, fork): (Arc<TokioRwLock<Box<dyn Db>>>, Option<ClientFork>) =
1056 if let Some(eth_rpc_url) = self.eth_rpc_url.clone() {
1057 self.setup_fork_db(eth_rpc_url, &mut env, &fees).await?
1058 } else {
1059 (Arc::new(TokioRwLock::new(Box::<MemDb>::default())), None)
1060 };
1061
1062 if let Some(ref genesis) = self.genesis {
1064 if self.chain_id.is_none() {
1067 env.cfg.chain_id = genesis.config.chain_id;
1068 }
1069 env.block.timestamp = U256::from(genesis.timestamp);
1070 if let Some(base_fee) = genesis.base_fee_per_gas {
1071 env.block.basefee = U256::from(base_fee);
1072 }
1073 if let Some(number) = genesis.number {
1074 env.block.number = U256::from(number);
1075 }
1076 env.block.coinbase = genesis.coinbase;
1077 }
1078
1079 let genesis = GenesisConfig {
1080 number: self.get_genesis_number(),
1081 timestamp: self.get_genesis_timestamp(),
1082 balance: self.genesis_balance,
1083 accounts: self.genesis_accounts.iter().map(|acc| acc.address()).collect(),
1084 genesis_init: self.genesis.clone(),
1085 };
1086
1087 let backend = mem::Backend::with_genesis(
1089 db,
1090 Arc::new(RwLock::new(env)),
1091 genesis,
1092 fees,
1093 Arc::new(RwLock::new(fork)),
1094 self.enable_steps_tracing,
1095 self.print_logs,
1096 self.print_traces,
1097 self.odyssey,
1098 self.prune_history,
1099 self.max_persisted_states,
1100 self.transaction_block_keeper,
1101 self.block_time,
1102 self.cache_path.clone(),
1103 Arc::new(TokioRwLock::new(self.clone())),
1104 )
1105 .await?;
1106
1107 if !self.disable_default_create2_deployer && self.eth_rpc_url.is_none() {
1110 backend
1111 .set_create2_deployer(DEFAULT_CREATE2_DEPLOYER)
1112 .await
1113 .wrap_err("failed to create default create2 deployer")?;
1114 }
1115
1116 if let Some(state) = self.init_state.clone() {
1117 backend.load_state(state).await.wrap_err("failed to load init state")?;
1118 }
1119
1120 Ok(backend)
1121 }
1122
1123 pub async fn setup_fork_db(
1130 &mut self,
1131 eth_rpc_url: String,
1132 env: &mut EnvWithHandlerCfg,
1133 fees: &FeeManager,
1134 ) -> Result<(Arc<TokioRwLock<Box<dyn Db>>>, Option<ClientFork>)> {
1135 let (db, config) = self.setup_fork_db_config(eth_rpc_url, env, fees).await?;
1136 let db: Arc<TokioRwLock<Box<dyn Db>>> = Arc::new(TokioRwLock::new(Box::new(db)));
1137 let fork = ClientFork::new(config, Arc::clone(&db));
1138 Ok((db, Some(fork)))
1139 }
1140
1141 pub async fn setup_fork_db_config(
1147 &mut self,
1148 eth_rpc_url: String,
1149 env: &mut EnvWithHandlerCfg,
1150 fees: &FeeManager,
1151 ) -> Result<(ForkedDatabase, ClientForkConfig)> {
1152 let provider = Arc::new(
1154 ProviderBuilder::new(ð_rpc_url)
1155 .timeout(self.fork_request_timeout)
1156 .initial_backoff(self.fork_retry_backoff.as_millis() as u64)
1157 .compute_units_per_second(self.compute_units_per_second)
1158 .max_retry(self.fork_request_retries)
1159 .initial_backoff(1000)
1160 .headers(self.fork_headers.clone())
1161 .build()
1162 .wrap_err("failed to establish provider to fork url")?,
1163 );
1164
1165 let (fork_block_number, fork_chain_id, force_transactions) = if let Some(fork_choice) =
1166 &self.fork_choice
1167 {
1168 let (fork_block_number, force_transactions) =
1169 derive_block_and_transactions(fork_choice, &provider).await.wrap_err(
1170 "failed to derive fork block number and force transactions from fork choice",
1171 )?;
1172 let chain_id = if let Some(chain_id) = self.fork_chain_id {
1173 Some(chain_id)
1174 } else if self.hardfork.is_none() {
1175 let chain_id =
1177 provider.get_chain_id().await.wrap_err("failed to fetch network chain ID")?;
1178 if alloy_chains::NamedChain::Mainnet == chain_id {
1179 let hardfork: EthereumHardfork = fork_block_number.into();
1180 env.handler_cfg.spec_id = hardfork.into();
1181 self.hardfork = Some(ChainHardfork::Ethereum(hardfork));
1182 }
1183 Some(U256::from(chain_id))
1184 } else {
1185 None
1186 };
1187
1188 (fork_block_number, chain_id, force_transactions)
1189 } else {
1190 let bn = find_latest_fork_block(&provider)
1192 .await
1193 .wrap_err("failed to get fork block number")?;
1194 (bn, None, None)
1195 };
1196
1197 let block = provider
1198 .get_block(BlockNumberOrTag::Number(fork_block_number).into())
1199 .await
1200 .wrap_err("failed to get fork block")?;
1201
1202 let block = if let Some(block) = block {
1203 block
1204 } else {
1205 if let Ok(latest_block) = provider.get_block_number().await {
1206 let mut message = format!(
1207 "Failed to get block for block number: {fork_block_number}\n\
1208latest block number: {latest_block}"
1209 );
1210 if fork_block_number <= latest_block {
1214 message.push_str(&format!("\n{NON_ARCHIVE_NODE_WARNING}"));
1215 }
1216 eyre::bail!("{message}");
1217 }
1218 eyre::bail!("failed to get block for block number: {fork_block_number}")
1219 };
1220
1221 let gas_limit = self.fork_gas_limit(&block);
1222 self.gas_limit = Some(gas_limit);
1223
1224 env.block = BlockEnv {
1225 number: U256::from(fork_block_number),
1226 timestamp: U256::from(block.header.timestamp),
1227 difficulty: block.header.difficulty,
1228 prevrandao: Some(block.header.mix_hash.unwrap_or_default()),
1230 gas_limit: U256::from(gas_limit),
1231 coinbase: env.block.coinbase,
1233 basefee: env.block.basefee,
1234 ..Default::default()
1235 };
1236
1237 if self.base_fee.is_none() {
1239 if let Some(base_fee) = block.header.base_fee_per_gas {
1240 self.base_fee = Some(base_fee);
1241 env.block.basefee = U256::from(base_fee);
1242 let next_block_base_fee = fees.get_next_block_base_fee_per_gas(
1245 block.header.gas_used as u128,
1246 gas_limit,
1247 block.header.base_fee_per_gas.unwrap_or_default(),
1248 );
1249
1250 fees.set_base_fee(next_block_base_fee);
1252 }
1253 if let (Some(blob_excess_gas), Some(blob_gas_used)) =
1254 (block.header.excess_blob_gas, block.header.blob_gas_used)
1255 {
1256 env.block.blob_excess_gas_and_price =
1257 Some(BlobExcessGasAndPrice::new(blob_excess_gas, false));
1258 let next_block_blob_excess_gas = fees
1259 .get_next_block_blob_excess_gas(blob_excess_gas as u128, blob_gas_used as u128);
1260 fees.set_blob_excess_gas_and_price(BlobExcessGasAndPrice::new(
1261 next_block_blob_excess_gas,
1262 false,
1263 ));
1264 }
1265 }
1266
1267 if self.gas_price.is_none() {
1269 if let Ok(gas_price) = provider.get_gas_price().await {
1270 self.gas_price = Some(gas_price);
1271 fees.set_gas_price(gas_price);
1272 }
1273 }
1274
1275 let block_hash = block.header.hash;
1276
1277 let chain_id = if let Some(chain_id) = self.chain_id {
1278 chain_id
1279 } else {
1280 let chain_id = if let Some(fork_chain_id) = fork_chain_id {
1281 fork_chain_id.to()
1282 } else {
1283 provider.get_chain_id().await.wrap_err("failed to fetch network chain ID")?
1284 };
1285
1286 self.set_chain_id(Some(chain_id));
1288 env.cfg.chain_id = chain_id;
1289 env.tx.chain_id = chain_id.into();
1290 chain_id
1291 };
1292 let override_chain_id = self.chain_id;
1293 apply_chain_and_block_specific_env_changes::<AnyNetwork>(env, &block);
1295
1296 let meta = BlockchainDbMeta::new(*env.env.clone(), eth_rpc_url.clone());
1297 let block_chain_db = if self.fork_chain_id.is_some() {
1298 BlockchainDb::new_skip_check(meta, self.block_cache_path(fork_block_number))
1299 } else {
1300 BlockchainDb::new(meta, self.block_cache_path(fork_block_number))
1301 };
1302
1303 let backend = SharedBackend::spawn_backend_thread(
1306 Arc::clone(&provider),
1307 block_chain_db.clone(),
1308 Some(fork_block_number.into()),
1309 );
1310
1311 let config = ClientForkConfig {
1312 eth_rpc_url,
1313 block_number: fork_block_number,
1314 block_hash,
1315 transaction_hash: self.fork_choice.and_then(|fc| fc.transaction_hash()),
1316 provider,
1317 chain_id,
1318 override_chain_id,
1319 timestamp: block.header.timestamp,
1320 base_fee: block.header.base_fee_per_gas.map(|g| g as u128),
1321 timeout: self.fork_request_timeout,
1322 retries: self.fork_request_retries,
1323 backoff: self.fork_retry_backoff,
1324 compute_units_per_second: self.compute_units_per_second,
1325 total_difficulty: block.header.total_difficulty.unwrap_or_default(),
1326 blob_gas_used: block.header.blob_gas_used.map(|g| g as u128),
1327 blob_excess_gas_and_price: env.block.blob_excess_gas_and_price.clone(),
1328 force_transactions,
1329 };
1330
1331 let mut db = ForkedDatabase::new(backend, block_chain_db);
1332
1333 db.insert_block_hash(U256::from(config.block_number), config.block_hash);
1335
1336 Ok((db, config))
1337 }
1338
1339 pub(crate) fn fork_gas_limit<T: TransactionResponse, H: BlockHeader>(
1343 &self,
1344 block: &Block<T, H>,
1345 ) -> u128 {
1346 if !self.disable_block_gas_limit {
1347 if let Some(gas_limit) = self.gas_limit {
1348 return gas_limit;
1349 } else if block.header.gas_limit() > 0 {
1350 return block.header.gas_limit() as u128;
1351 }
1352 }
1353
1354 u64::MAX as u128
1355 }
1356
1357 pub(crate) fn gas_limit(&self) -> u128 {
1361 if self.disable_block_gas_limit {
1362 return u64::MAX as u128;
1363 }
1364
1365 self.gas_limit.unwrap_or(DEFAULT_GAS_LIMIT)
1366 }
1367}
1368
1369async fn derive_block_and_transactions(
1374 fork_choice: &ForkChoice,
1375 provider: &Arc<RetryProvider>,
1376) -> eyre::Result<(BlockNumber, Option<Vec<PoolTransaction>>)> {
1377 match fork_choice {
1378 ForkChoice::Block(block_number) => {
1379 let block_number = *block_number;
1380 if block_number >= 0 {
1381 return Ok((block_number as u64, None))
1382 }
1383 let latest = provider.get_block_number().await?;
1385
1386 Ok((block_number.saturating_add(latest as i128) as u64, None))
1387 }
1388 ForkChoice::Transaction(transaction_hash) => {
1389 let transaction = provider
1391 .get_transaction_by_hash(transaction_hash.0.into())
1392 .await?
1393 .ok_or_else(|| eyre::eyre!("failed to get fork transaction by hash"))?;
1394 let transaction_block_number = transaction.block_number.unwrap();
1395
1396 let transaction_block = provider
1398 .get_block_by_number(transaction_block_number.into())
1399 .full()
1400 .await?
1401 .ok_or_else(|| eyre::eyre!("failed to get fork block by number"))?;
1402
1403 let filtered_transactions = transaction_block
1405 .transactions
1406 .as_transactions()
1407 .ok_or_else(|| eyre::eyre!("failed to get transactions from full fork block"))?
1408 .iter()
1409 .take_while_inclusive(|&transaction| transaction.tx_hash() != transaction_hash.0)
1410 .collect::<Vec<_>>();
1411
1412 let force_transactions = filtered_transactions
1414 .iter()
1415 .map(|&transaction| PoolTransaction::try_from(transaction.clone()))
1416 .collect::<Result<Vec<_>, _>>()
1417 .map_err(|e| eyre::eyre!("Err converting to pool transactions {e}"))?;
1418 Ok((transaction_block_number.saturating_sub(1), Some(force_transactions)))
1419 }
1420 }
1421}
1422
1423#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1425pub enum ForkChoice {
1426 Block(i128),
1430 Transaction(TxHash),
1432}
1433
1434impl ForkChoice {
1435 pub fn block_number(&self) -> Option<i128> {
1437 match self {
1438 Self::Block(block_number) => Some(*block_number),
1439 Self::Transaction(_) => None,
1440 }
1441 }
1442
1443 pub fn transaction_hash(&self) -> Option<TxHash> {
1445 match self {
1446 Self::Block(_) => None,
1447 Self::Transaction(transaction_hash) => Some(*transaction_hash),
1448 }
1449 }
1450}
1451
1452impl From<TxHash> for ForkChoice {
1454 fn from(tx_hash: TxHash) -> Self {
1455 Self::Transaction(tx_hash)
1456 }
1457}
1458
1459impl From<u64> for ForkChoice {
1461 fn from(block: u64) -> Self {
1462 Self::Block(block as i128)
1463 }
1464}
1465
1466#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
1467pub struct PruneStateHistoryConfig {
1468 pub enabled: bool,
1469 pub max_memory_history: Option<usize>,
1470}
1471
1472impl PruneStateHistoryConfig {
1473 pub fn is_state_history_supported(&self) -> bool {
1475 !self.enabled || self.max_memory_history.is_some()
1476 }
1477
1478 pub fn is_config_enabled(&self) -> bool {
1480 self.enabled
1481 }
1482
1483 pub fn from_args(val: Option<Option<usize>>) -> Self {
1484 val.map(|max_memory_history| Self { enabled: true, max_memory_history }).unwrap_or_default()
1485 }
1486}
1487
1488#[derive(Clone, Debug)]
1490pub struct AccountGenerator {
1491 chain_id: u64,
1492 amount: usize,
1493 phrase: String,
1494 derivation_path: Option<String>,
1495}
1496
1497impl AccountGenerator {
1498 pub fn new(amount: usize) -> Self {
1499 Self {
1500 chain_id: CHAIN_ID,
1501 amount,
1502 phrase: Mnemonic::<English>::new(&mut thread_rng()).to_phrase(),
1503 derivation_path: None,
1504 }
1505 }
1506
1507 #[must_use]
1508 pub fn phrase(mut self, phrase: impl Into<String>) -> Self {
1509 self.phrase = phrase.into();
1510 self
1511 }
1512
1513 fn get_phrase(&self) -> &str {
1514 &self.phrase
1515 }
1516
1517 #[must_use]
1518 pub fn chain_id(mut self, chain_id: impl Into<u64>) -> Self {
1519 self.chain_id = chain_id.into();
1520 self
1521 }
1522
1523 #[must_use]
1524 pub fn derivation_path(mut self, derivation_path: impl Into<String>) -> Self {
1525 let mut derivation_path = derivation_path.into();
1526 if !derivation_path.ends_with('/') {
1527 derivation_path.push('/');
1528 }
1529 self.derivation_path = Some(derivation_path);
1530 self
1531 }
1532
1533 fn get_derivation_path(&self) -> &str {
1534 self.derivation_path.as_deref().unwrap_or("m/44'/60'/0'/0/")
1535 }
1536}
1537
1538impl AccountGenerator {
1539 pub fn gen(&self) -> eyre::Result<Vec<PrivateKeySigner>> {
1540 let builder = MnemonicBuilder::<English>::default().phrase(self.phrase.as_str());
1541
1542 let derivation_path = self.get_derivation_path();
1544
1545 let mut wallets = Vec::with_capacity(self.amount);
1546 for idx in 0..self.amount {
1547 let builder =
1548 builder.clone().derivation_path(format!("{derivation_path}{idx}")).unwrap();
1549 let wallet = builder.build()?.with_chain_id(Some(self.chain_id));
1550 wallets.push(wallet)
1551 }
1552 Ok(wallets)
1553 }
1554}
1555
1556pub fn anvil_dir() -> Option<PathBuf> {
1558 Config::foundry_dir().map(|p| p.join("anvil"))
1559}
1560
1561pub fn anvil_tmp_dir() -> Option<PathBuf> {
1563 anvil_dir().map(|p| p.join("tmp"))
1564}
1565
1566async fn find_latest_fork_block<P: Provider<AnyNetwork>>(
1571 provider: P,
1572) -> Result<u64, TransportError> {
1573 let mut num = provider.get_block_number().await?;
1574
1575 for _ in 0..2 {
1578 if let Some(block) = provider.get_block(num.into()).await? {
1579 if !block.header.hash.is_zero() {
1580 break;
1581 }
1582 }
1583 num = num.saturating_sub(1)
1585 }
1586
1587 Ok(num)
1588}
1589
1590#[cfg(test)]
1591mod tests {
1592 use super::*;
1593
1594 #[test]
1595 fn test_prune_history() {
1596 let config = PruneStateHistoryConfig::default();
1597 assert!(config.is_state_history_supported());
1598 let config = PruneStateHistoryConfig::from_args(Some(None));
1599 assert!(!config.is_state_history_supported());
1600 let config = PruneStateHistoryConfig::from_args(Some(Some(10)));
1601 assert!(config.is_state_history_supported());
1602 }
1603}