Skip to main content

anvil/
config.rs

1use crate::{
2    EthereumHardfork, FeeManager, PrecompileFactory,
3    eth::{
4        backend::{
5            db::{Db, SerializableState},
6            fork::{ClientFork, ClientForkConfig},
7            genesis::GenesisConfig,
8            mem::fork_db::ForkedDatabase,
9            time::duration_since_unix_epoch,
10        },
11        fees::{INITIAL_BASE_FEE, INITIAL_GAS_PRICE},
12        pool::transactions::{PoolTransaction, TransactionOrder},
13    },
14    mem::{self, in_memory_db::MemDb},
15};
16use alloy_consensus::BlockHeader;
17use alloy_eips::{eip1559::BaseFeeParams, eip7840::BlobParams};
18use alloy_evm::EvmEnv;
19use alloy_genesis::Genesis;
20use alloy_network::{AnyNetwork, BlockResponse, TransactionResponse};
21use alloy_primitives::{Address, BlockNumber, TxHash, U256, hex, map::HashMap, utils::Unit};
22use alloy_provider::Provider;
23use alloy_rpc_types::BlockNumberOrTag;
24use alloy_signer::Signer;
25use alloy_signer_local::{
26    MnemonicBuilder, PrivateKeySigner,
27    coins_bip39::{English, Mnemonic},
28};
29use alloy_transport::TransportError;
30use anvil_server::ServerConfig;
31use eyre::{Context, Result};
32use foundry_common::{
33    ALCHEMY_FREE_TIER_CUPS, NON_ARCHIVE_NODE_WARNING, REQUEST_TIMEOUT,
34    provider::{ProviderBuilder, RetryProvider},
35};
36use foundry_config::Config;
37use foundry_evm::{
38    backend::{BlockchainDb, BlockchainDbMeta, SharedBackend},
39    constants::DEFAULT_CREATE2_DEPLOYER,
40    hardfork::FoundryHardfork,
41    utils::{
42        apply_chain_and_block_specific_env_changes, block_env_from_header,
43        get_blob_base_fee_update_fraction,
44    },
45};
46use foundry_primitives::FoundryTxEnvelope;
47use itertools::Itertools;
48use parking_lot::RwLock;
49use rand_08::thread_rng;
50use revm::{
51    context::{BlockEnv, CfgEnv},
52    context_interface::block::BlobExcessGasAndPrice,
53    primitives::hardfork::SpecId,
54};
55use serde_json::{Value, json};
56use std::{
57    fmt::Write as FmtWrite,
58    net::{IpAddr, Ipv4Addr},
59    path::PathBuf,
60    sync::Arc,
61    time::Duration,
62};
63use tempo_chainspec::hardfork::TempoHardfork;
64use tokio::sync::RwLock as TokioRwLock;
65use yansi::Paint;
66
67pub use foundry_common::version::SHORT_VERSION as VERSION_MESSAGE;
68use foundry_evm::{
69    traces::{CallTraceDecoderBuilder, identifier::SignaturesIdentifier},
70    utils::get_blob_params,
71};
72use foundry_evm_networks::NetworkConfigs;
73
74/// Default port the rpc will open
75pub const NODE_PORT: u16 = 8545;
76/// Default chain id of the node
77pub const CHAIN_ID: u64 = 31337;
78/// The default gas limit for all transactions
79pub const DEFAULT_GAS_LIMIT: u64 = 30_000_000;
80/// The default number of slots in an epoch used for safe/finalized block tags.
81pub const DEFAULT_SLOTS_IN_AN_EPOCH: u64 = 32;
82/// Default mnemonic for dev accounts
83pub const DEFAULT_MNEMONIC: &str = "test test test test test test test test test test test junk";
84
85/// The default IPC endpoint
86pub const DEFAULT_IPC_ENDPOINT: &str =
87    if cfg!(unix) { "/tmp/anvil.ipc" } else { r"\\.\pipe\anvil.ipc" };
88
89const BANNER: &str = r"
90                             _   _
91                            (_) | |
92      __ _   _ __   __   __  _  | |
93     / _` | | '_ \  \ \ / / | | | |
94    | (_| | | | | |  \ V /  | | | |
95     \__,_| |_| |_|   \_/   |_| |_|
96";
97
98/// Configurations of the EVM node
99#[derive(Clone, Debug)]
100pub struct NodeConfig {
101    /// Chain ID of the EVM chain
102    pub chain_id: Option<u64>,
103    /// Default gas limit for all txs
104    pub gas_limit: Option<u64>,
105    /// If set to `true`, disables the block gas limit
106    pub disable_block_gas_limit: bool,
107    /// If set to `true`, enables the tx gas limit as imposed by Osaka (EIP-7825)
108    pub enable_tx_gas_limit: bool,
109    /// Default gas price for all txs
110    pub gas_price: Option<u128>,
111    /// Default base fee
112    pub base_fee: Option<u64>,
113    /// If set to `true`, disables the enforcement of a minimum suggested priority fee
114    pub disable_min_priority_fee: bool,
115    /// Default blob excess gas and price
116    pub blob_excess_gas_and_price: Option<BlobExcessGasAndPrice>,
117    /// The hardfork to use
118    pub hardfork: Option<FoundryHardfork>,
119    /// Signer accounts that will be initialised with `genesis_balance` in the genesis block
120    pub genesis_accounts: Vec<PrivateKeySigner>,
121    /// Native token balance of every genesis account in the genesis block
122    pub genesis_balance: U256,
123    /// Genesis block timestamp
124    pub genesis_timestamp: Option<u64>,
125    /// Genesis block number
126    pub genesis_block_number: Option<u64>,
127    /// Signer accounts that can sign messages/transactions from the EVM node
128    pub signer_accounts: Vec<PrivateKeySigner>,
129    /// Configured block time for the EVM chain. Use `None` for instant/auto mining.
130    pub block_time: Option<Duration>,
131    /// Disable auto and interval mining mode and use `MiningMode::None` instead.
132    pub no_mining: bool,
133    /// Enables auto and interval mining mode
134    pub mixed_mining: bool,
135    /// port to use for the server
136    pub port: u16,
137    /// maximum number of transactions in a block
138    pub max_transactions: usize,
139    /// Fork URLs for RPC calls. The first entry is the primary endpoint.
140    /// When multiple URLs are provided, requests are distributed using
141    /// round-robin load balancing with retry-based failover.
142    pub fork_urls: Vec<String>,
143    /// pins the block number or transaction hash for the state fork
144    pub fork_choice: Option<ForkChoice>,
145    /// headers to use with fork RPC endpoints
146    pub fork_headers: Vec<String>,
147    /// specifies chain id for cache to skip fetching from remote in offline-start mode
148    pub fork_chain_id: Option<U256>,
149    /// The generator used to generate the dev accounts
150    pub account_generator: Option<AccountGenerator>,
151    /// whether to enable tracing
152    pub enable_tracing: bool,
153    /// Explicitly disables the use of RPC caching.
154    pub no_storage_caching: bool,
155    /// How to configure the server
156    pub server_config: ServerConfig,
157    /// The host the server will listen on
158    pub host: Vec<IpAddr>,
159    /// How transactions are sorted in the mempool
160    pub transaction_order: TransactionOrder,
161    /// Filename to write anvil output as json
162    pub config_out: Option<PathBuf>,
163    /// The genesis to use to initialize the node
164    pub genesis: Option<Genesis>,
165    /// Timeout in for requests sent to remote JSON-RPC server in forking mode
166    pub fork_request_timeout: Duration,
167    /// Number of request retries for spurious networks
168    pub fork_request_retries: u32,
169    /// The initial retry backoff
170    pub fork_retry_backoff: Duration,
171    /// available CUPS
172    pub compute_units_per_second: u64,
173    /// The ipc path
174    pub ipc_path: Option<Option<String>>,
175    /// Enable transaction/call steps tracing for debug calls returning geth-style traces
176    pub enable_steps_tracing: bool,
177    /// Enable printing of `console.log` invocations.
178    pub print_logs: bool,
179    /// Enable printing of traces.
180    pub print_traces: bool,
181    /// Enable auto impersonation of accounts on startup
182    pub enable_auto_impersonate: bool,
183    /// Configure the code size limit
184    pub code_size_limit: Option<usize>,
185    /// Configures how to remove historic state.
186    ///
187    /// If set to `Some(num)` keep latest num state in memory only.
188    pub prune_history: PruneStateHistoryConfig,
189    /// Max number of states cached on disk.
190    pub max_persisted_states: Option<usize>,
191    /// The file where to load the state from
192    pub init_state: Option<SerializableState>,
193    /// max number of blocks with transactions in memory
194    pub transaction_block_keeper: Option<usize>,
195    /// Disable the default CREATE2 deployer
196    pub disable_default_create2_deployer: bool,
197    /// Disable pool balance checks
198    pub disable_pool_balance_checks: bool,
199    /// Slots in an epoch
200    pub slots_in_an_epoch: u64,
201    /// The memory limit per EVM execution in bytes.
202    pub memory_limit: Option<u64>,
203    /// Factory used by `anvil` to extend the EVM's precompiles.
204    pub precompile_factory: Option<Arc<dyn PrecompileFactory>>,
205    /// Networks to enable features for.
206    pub networks: NetworkConfigs,
207    /// Do not print log messages.
208    pub silent: bool,
209    /// The path where persisted states are cached (used with `max_persisted_states`).
210    /// This does not affect the fork RPC cache location.
211    pub cache_path: Option<PathBuf>,
212    /// Accounts to fund with specific balances on startup (address -> balance in wei).
213    pub funded_accounts: HashMap<Address, U256>,
214}
215
216impl NodeConfig {
217    fn as_string(&self, fork: Option<&ClientFork>) -> String {
218        let mut s: String = String::new();
219        let _ = write!(s, "\n{}", BANNER.green());
220        let _ = write!(s, "\n    {VERSION_MESSAGE}");
221        let _ = write!(s, "\n    {}", "https://github.com/foundry-rs/foundry".green());
222
223        let _ = write!(
224            s,
225            r#"
226
227Available Accounts
228==================
229"#
230        );
231        let balance = alloy_primitives::utils::format_ether(self.genesis_balance);
232        for (idx, wallet) in self.genesis_accounts.iter().enumerate() {
233            write!(s, "\n({idx}) {} ({balance} ETH)", wallet.address()).unwrap();
234        }
235
236        let _ = write!(
237            s,
238            r#"
239
240Private Keys
241==================
242"#
243        );
244
245        for (idx, wallet) in self.genesis_accounts.iter().enumerate() {
246            let hex = hex::encode(wallet.credential().to_bytes());
247            let _ = write!(s, "\n({idx}) 0x{hex}");
248        }
249
250        if let Some(generator) = &self.account_generator {
251            let _ = write!(
252                s,
253                r#"
254
255Wallet
256==================
257Mnemonic:          {}
258Derivation path:   {}
259"#,
260                generator.phrase,
261                generator.get_derivation_path()
262            );
263        }
264
265        if let Some(fork) = fork {
266            let _ = write!(
267                s,
268                r#"
269
270Fork
271==================
272Endpoint:       {}
273Block number:   {}
274Block hash:     {:?}
275Chain ID:       {}
276"#,
277                fork.eth_rpc_url().as_deref().unwrap_or("none"),
278                fork.block_number(),
279                fork.block_hash(),
280                fork.chain_id()
281            );
282
283            if self.fork_urls.len() > 1 {
284                let _ = writeln!(s, "Endpoints:      {}", self.fork_urls.len());
285                for (i, url) in self.fork_urls.iter().enumerate() {
286                    let _ = writeln!(s, "  ({i}) {url}");
287                }
288            }
289
290            if let Some(tx_hash) = fork.transaction_hash() {
291                let _ = writeln!(s, "Transaction hash: {tx_hash}");
292            }
293        } else {
294            let _ = write!(
295                s,
296                r#"
297
298Chain ID
299==================
300
301{}
302"#,
303                self.get_chain_id().green()
304            );
305        }
306
307        if (SpecId::from(self.get_hardfork()) as u8) < (SpecId::LONDON as u8) {
308            let _ = write!(
309                s,
310                r#"
311Gas Price
312==================
313
314{}
315"#,
316                self.get_gas_price().green()
317            );
318        } else {
319            let _ = write!(
320                s,
321                r#"
322Base Fee
323==================
324
325{}
326"#,
327                self.get_base_fee().green()
328            );
329        }
330
331        let _ = write!(
332            s,
333            r#"
334Gas Limit
335==================
336
337{}
338"#,
339            {
340                if self.disable_block_gas_limit {
341                    "Disabled".to_string()
342                } else {
343                    self.gas_limit.map(|l| l.to_string()).unwrap_or_else(|| {
344                        if self.fork_choice.is_some() {
345                            "Forked".to_string()
346                        } else {
347                            DEFAULT_GAS_LIMIT.to_string()
348                        }
349                    })
350                }
351            }
352            .green()
353        );
354
355        let _ = write!(
356            s,
357            r#"
358Genesis Timestamp
359==================
360
361{}
362"#,
363            self.get_genesis_timestamp().green()
364        );
365
366        let _ = write!(
367            s,
368            r#"
369Genesis Number
370==================
371
372{}
373"#,
374            self.get_genesis_number().green()
375        );
376
377        s
378    }
379
380    fn as_json(&self, fork: Option<&ClientFork>) -> Value {
381        let mut wallet_description = HashMap::new();
382        let mut available_accounts = Vec::with_capacity(self.genesis_accounts.len());
383        let mut private_keys = Vec::with_capacity(self.genesis_accounts.len());
384
385        for wallet in &self.genesis_accounts {
386            available_accounts.push(format!("{:?}", wallet.address()));
387            private_keys.push(format!("0x{}", hex::encode(wallet.credential().to_bytes())));
388        }
389
390        if let Some(generator) = &self.account_generator {
391            let phrase = generator.get_phrase().to_string();
392            let derivation_path = generator.get_derivation_path().to_string();
393
394            wallet_description.insert("derivation_path".to_string(), derivation_path);
395            wallet_description.insert("mnemonic".to_string(), phrase);
396        };
397
398        let gas_limit = match self.gas_limit {
399            // if we have a disabled flag we should max out the limit
400            Some(_) | None if self.disable_block_gas_limit => Some(u64::MAX.to_string()),
401            Some(limit) => Some(limit.to_string()),
402            _ => None,
403        };
404
405        if let Some(fork) = fork {
406            json!({
407              "available_accounts": available_accounts,
408              "private_keys": private_keys,
409              "endpoint": fork.eth_rpc_url().unwrap_or_default(),
410              "block_number": fork.block_number(),
411              "block_hash": fork.block_hash(),
412              "chain_id": fork.chain_id(),
413              "wallet": wallet_description,
414              "base_fee": format!("{}", self.get_base_fee()),
415              "gas_price": format!("{}", self.get_gas_price()),
416              "gas_limit": gas_limit,
417            })
418        } else {
419            json!({
420              "available_accounts": available_accounts,
421              "private_keys": private_keys,
422              "wallet": wallet_description,
423              "base_fee": format!("{}", self.get_base_fee()),
424              "gas_price": format!("{}", self.get_gas_price()),
425              "gas_limit": gas_limit,
426              "genesis_timestamp": format!("{}", self.get_genesis_timestamp()),
427            })
428        }
429    }
430}
431
432impl NodeConfig {
433    /// Returns a new config intended to be used in tests, which does not print and binds to a
434    /// random, free port by setting it to `0`
435    #[doc(hidden)]
436    pub fn test() -> Self {
437        Self { enable_tracing: true, port: 0, silent: true, ..Default::default() }
438    }
439
440    /// Returns a test config with Tempo network enabled.
441    #[doc(hidden)]
442    pub fn test_tempo() -> Self {
443        Self { networks: NetworkConfigs::with_tempo(), ..Self::test() }
444    }
445
446    /// Returns a new config which does not initialize any accounts on node startup.
447    pub fn empty_state() -> Self {
448        Self {
449            genesis_accounts: vec![],
450            signer_accounts: vec![],
451            disable_default_create2_deployer: true,
452            ..Default::default()
453        }
454    }
455}
456
457impl Default for NodeConfig {
458    fn default() -> Self {
459        // generate some random wallets
460        let genesis_accounts = AccountGenerator::new(10)
461            .phrase(DEFAULT_MNEMONIC)
462            .generate()
463            .expect("Invalid mnemonic.");
464        Self {
465            chain_id: None,
466            gas_limit: None,
467            disable_block_gas_limit: false,
468            enable_tx_gas_limit: false,
469            gas_price: None,
470            hardfork: None,
471            signer_accounts: genesis_accounts.clone(),
472            genesis_timestamp: None,
473            genesis_block_number: None,
474            genesis_accounts,
475            // 100ETH default balance
476            genesis_balance: Unit::ETHER.wei().saturating_mul(U256::from(100u64)),
477            block_time: None,
478            no_mining: false,
479            mixed_mining: false,
480            port: NODE_PORT,
481            max_transactions: 1_000,
482            fork_urls: vec![],
483            fork_choice: None,
484            account_generator: None,
485            base_fee: None,
486            disable_min_priority_fee: false,
487            blob_excess_gas_and_price: None,
488            enable_tracing: true,
489            enable_steps_tracing: false,
490            print_logs: true,
491            print_traces: false,
492            enable_auto_impersonate: false,
493            no_storage_caching: false,
494            server_config: Default::default(),
495            host: vec![IpAddr::V4(Ipv4Addr::LOCALHOST)],
496            transaction_order: Default::default(),
497            config_out: None,
498            genesis: None,
499            fork_request_timeout: REQUEST_TIMEOUT,
500            fork_headers: vec![],
501            fork_request_retries: 5,
502            fork_retry_backoff: Duration::from_millis(1_000),
503            fork_chain_id: None,
504            // alchemy max cpus <https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second>
505            compute_units_per_second: ALCHEMY_FREE_TIER_CUPS,
506            ipc_path: None,
507            code_size_limit: None,
508            prune_history: Default::default(),
509            max_persisted_states: None,
510            init_state: None,
511            transaction_block_keeper: None,
512            disable_default_create2_deployer: false,
513            disable_pool_balance_checks: false,
514            slots_in_an_epoch: DEFAULT_SLOTS_IN_AN_EPOCH,
515            memory_limit: None,
516            precompile_factory: None,
517            networks: Default::default(),
518            silent: false,
519            cache_path: None,
520            funded_accounts: HashMap::default(),
521        }
522    }
523}
524
525impl NodeConfig {
526    /// Returns the memory limit of the node
527    #[must_use]
528    pub const fn with_memory_limit(mut self, mems_value: Option<u64>) -> Self {
529        self.memory_limit = mems_value;
530        self
531    }
532
533    /// Returns the base fee to use.
534    ///
535    /// In Tempo mode, uses the hardfork-specific base fee (10 gwei pre-T1, 20 gwei T1+).
536    pub fn get_base_fee(&self) -> u64 {
537        let default = if self.networks.is_tempo() {
538            TempoHardfork::from(self.get_hardfork()).base_fee()
539        } else {
540            INITIAL_BASE_FEE
541        };
542        self.base_fee
543            .or_else(|| self.genesis.as_ref().and_then(|g| g.base_fee_per_gas.map(|g| g as u64)))
544            .unwrap_or(default)
545    }
546
547    /// Returns the gas price to use.
548    ///
549    /// In Tempo mode, defaults to the hardfork-specific base fee.
550    pub fn get_gas_price(&self) -> u128 {
551        let default = if self.networks.is_tempo() {
552            TempoHardfork::from(self.get_hardfork()).base_fee() as u128
553        } else {
554            INITIAL_GAS_PRICE
555        };
556        self.gas_price.unwrap_or(default)
557    }
558
559    pub fn get_blob_excess_gas_and_price(&self) -> BlobExcessGasAndPrice {
560        if let Some(value) = self.blob_excess_gas_and_price {
561            value
562        } else {
563            let excess_blob_gas =
564                self.genesis.as_ref().and_then(|g| g.excess_blob_gas).unwrap_or(0);
565            BlobExcessGasAndPrice::new(
566                excess_blob_gas,
567                get_blob_base_fee_update_fraction(
568                    self.get_chain_id(),
569                    self.get_genesis_timestamp(),
570                ),
571            )
572        }
573    }
574
575    /// Returns the [`BlobParams`] that should be used.
576    pub fn get_blob_params(&self) -> BlobParams {
577        get_blob_params(self.get_chain_id(), self.get_genesis_timestamp())
578    }
579
580    /// Returns the hardfork to use
581    pub fn get_hardfork(&self) -> FoundryHardfork {
582        if let Some(hardfork) = self.hardfork {
583            return hardfork;
584        }
585        if self.networks.is_tempo()
586            && let Some(hardfork) = TempoHardfork::from_chain_and_timestamp(
587                self.get_chain_id(),
588                self.get_genesis_timestamp(),
589            )
590        {
591            return hardfork.into();
592        }
593        #[cfg(feature = "optimism")]
594        if self.networks.is_optimism() {
595            return foundry_evm::hardforks::OpHardfork::default().into();
596        }
597        if self.networks.is_tempo() {
598            return TempoHardfork::default().into();
599        }
600        EthereumHardfork::default().into()
601    }
602
603    /// Sets a custom code size limit
604    #[must_use]
605    pub const fn with_code_size_limit(mut self, code_size_limit: Option<usize>) -> Self {
606        self.code_size_limit = code_size_limit;
607        self
608    }
609    /// Disables  code size limit
610    #[must_use]
611    pub const fn disable_code_size_limit(mut self, disable_code_size_limit: bool) -> Self {
612        if disable_code_size_limit {
613            self.code_size_limit = Some(usize::MAX);
614        }
615        self
616    }
617
618    /// Sets the init state if any
619    #[must_use]
620    pub fn with_init_state(mut self, init_state: Option<SerializableState>) -> Self {
621        self.init_state = init_state;
622        self
623    }
624
625    /// Loads the init state from a file if it exists
626    #[must_use]
627    #[cfg(feature = "cmd")]
628    pub fn with_init_state_path(mut self, path: impl AsRef<std::path::Path>) -> Self {
629        self.init_state = crate::cmd::StateFile::parse_path(path).ok().and_then(|file| file.state);
630        self
631    }
632
633    /// Sets the chain ID
634    #[must_use]
635    pub fn with_chain_id<U: Into<u64>>(mut self, chain_id: Option<U>) -> Self {
636        self.set_chain_id(chain_id);
637        self
638    }
639
640    /// Returns the chain ID to use
641    pub fn get_chain_id(&self) -> u64 {
642        self.chain_id
643            .or_else(|| self.genesis.as_ref().map(|g| g.config.chain_id))
644            .unwrap_or(CHAIN_ID)
645    }
646
647    /// Sets the chain id and updates all wallets
648    pub fn set_chain_id(&mut self, chain_id: Option<impl Into<u64>>) {
649        self.chain_id = chain_id.map(Into::into);
650        let chain_id = self.get_chain_id();
651        self.networks = self.networks.with_chain_id(chain_id);
652        self.genesis_accounts.iter_mut().for_each(|wallet| {
653            *wallet = wallet.clone().with_chain_id(Some(chain_id));
654        });
655        self.signer_accounts.iter_mut().for_each(|wallet| {
656            *wallet = wallet.clone().with_chain_id(Some(chain_id));
657        })
658    }
659
660    /// Sets the gas limit
661    #[must_use]
662    pub const fn with_gas_limit(mut self, gas_limit: Option<u64>) -> Self {
663        self.gas_limit = gas_limit;
664        self
665    }
666
667    /// Disable block gas limit check
668    ///
669    /// If set to `true` block gas limit will not be enforced
670    #[must_use]
671    pub const fn disable_block_gas_limit(mut self, disable_block_gas_limit: bool) -> Self {
672        self.disable_block_gas_limit = disable_block_gas_limit;
673        self
674    }
675
676    /// Enable tx gas limit check
677    ///
678    /// If set to `true`, enables the tx gas limit as imposed by Osaka (EIP-7825)
679    #[must_use]
680    pub const fn enable_tx_gas_limit(mut self, enable_tx_gas_limit: bool) -> Self {
681        self.enable_tx_gas_limit = enable_tx_gas_limit;
682        self
683    }
684
685    /// Sets the gas price
686    #[must_use]
687    pub const fn with_gas_price(mut self, gas_price: Option<u128>) -> Self {
688        self.gas_price = gas_price;
689        self
690    }
691
692    /// Sets prune history status.
693    #[must_use]
694    pub fn set_pruned_history(mut self, prune_history: Option<Option<usize>>) -> Self {
695        self.prune_history = PruneStateHistoryConfig::from_args(prune_history);
696        self
697    }
698
699    /// Sets max number of states to cache on disk.
700    #[must_use]
701    pub fn with_max_persisted_states<U: Into<usize>>(
702        mut self,
703        max_persisted_states: Option<U>,
704    ) -> Self {
705        self.max_persisted_states = max_persisted_states.map(Into::into);
706        self
707    }
708
709    /// Sets the max number of transactions in a block
710    #[must_use]
711    pub const fn with_max_transactions(mut self, max_transactions: Option<usize>) -> Self {
712        if let Some(max_transactions) = max_transactions {
713            self.max_transactions = max_transactions;
714        }
715        self
716    }
717
718    /// Sets max number of blocks with transactions to keep in memory
719    #[must_use]
720    pub fn with_transaction_block_keeper<U: Into<usize>>(
721        mut self,
722        transaction_block_keeper: Option<U>,
723    ) -> Self {
724        self.transaction_block_keeper = transaction_block_keeper.map(Into::into);
725        self
726    }
727
728    /// Sets the base fee
729    #[must_use]
730    pub const fn with_base_fee(mut self, base_fee: Option<u64>) -> Self {
731        self.base_fee = base_fee;
732        self
733    }
734
735    /// Disable the enforcement of a minimum suggested priority fee
736    #[must_use]
737    pub const fn disable_min_priority_fee(mut self, disable_min_priority_fee: bool) -> Self {
738        self.disable_min_priority_fee = disable_min_priority_fee;
739        self
740    }
741
742    /// Sets the init genesis (genesis.json)
743    #[must_use]
744    pub fn with_genesis(mut self, genesis: Option<Genesis>) -> Self {
745        self.genesis = genesis;
746        self
747    }
748
749    /// Returns the genesis timestamp to use
750    pub fn get_genesis_timestamp(&self) -> u64 {
751        self.genesis_timestamp
752            .or_else(|| self.genesis.as_ref().map(|g| g.timestamp))
753            .unwrap_or_else(|| duration_since_unix_epoch().as_secs())
754    }
755
756    /// Sets the genesis timestamp
757    #[must_use]
758    pub fn with_genesis_timestamp<U: Into<u64>>(mut self, timestamp: Option<U>) -> Self {
759        if let Some(timestamp) = timestamp {
760            self.genesis_timestamp = Some(timestamp.into());
761        }
762        self
763    }
764
765    /// Sets the genesis number
766    #[must_use]
767    pub fn with_genesis_block_number<U: Into<u64>>(mut self, number: Option<U>) -> Self {
768        if let Some(number) = number {
769            self.genesis_block_number = Some(number.into());
770        }
771        self
772    }
773
774    /// Returns the genesis number
775    pub fn get_genesis_number(&self) -> u64 {
776        self.genesis_block_number
777            .or_else(|| self.genesis.as_ref().and_then(|g| g.number))
778            .unwrap_or(0)
779    }
780
781    /// Sets the hardfork
782    #[must_use]
783    pub const fn with_hardfork(mut self, hardfork: Option<FoundryHardfork>) -> Self {
784        self.hardfork = hardfork;
785        self
786    }
787
788    /// Sets the genesis accounts
789    #[must_use]
790    pub fn with_genesis_accounts(mut self, accounts: Vec<PrivateKeySigner>) -> Self {
791        self.genesis_accounts = accounts;
792        self
793    }
794
795    /// Sets the signer accounts
796    #[must_use]
797    pub fn with_signer_accounts(mut self, accounts: Vec<PrivateKeySigner>) -> Self {
798        self.signer_accounts = accounts;
799        self
800    }
801
802    /// Sets both the genesis accounts and the signer accounts
803    /// so that `genesis_accounts == accounts`
804    pub fn with_account_generator(mut self, generator: AccountGenerator) -> eyre::Result<Self> {
805        let accounts = generator.generate()?;
806        self.account_generator = Some(generator);
807        Ok(self.with_signer_accounts(accounts.clone()).with_genesis_accounts(accounts))
808    }
809
810    /// Sets the balance of the genesis accounts in the genesis block
811    #[must_use]
812    pub fn with_genesis_balance<U: Into<U256>>(mut self, balance: U) -> Self {
813        self.genesis_balance = balance.into();
814        self
815    }
816
817    /// Sets the block time to automine blocks
818    #[must_use]
819    pub fn with_blocktime<D: Into<Duration>>(mut self, block_time: Option<D>) -> Self {
820        self.block_time = block_time.map(Into::into);
821        self
822    }
823
824    #[must_use]
825    pub fn with_mixed_mining<D: Into<Duration>>(
826        mut self,
827        mixed_mining: bool,
828        block_time: Option<D>,
829    ) -> Self {
830        self.block_time = block_time.map(Into::into);
831        self.mixed_mining = mixed_mining;
832        self
833    }
834
835    /// If set to `true` auto mining will be disabled
836    #[must_use]
837    pub const fn with_no_mining(mut self, no_mining: bool) -> Self {
838        self.no_mining = no_mining;
839        self
840    }
841
842    /// Sets the slots in an epoch
843    #[must_use]
844    pub const fn with_slots_in_an_epoch(mut self, slots_in_an_epoch: u64) -> Self {
845        self.slots_in_an_epoch = slots_in_an_epoch;
846        self
847    }
848
849    /// Sets the port to use
850    #[must_use]
851    pub const fn with_port(mut self, port: u16) -> Self {
852        self.port = port;
853        self
854    }
855
856    /// Sets the ipc path to use
857    ///
858    /// Note: this is a double Option for
859    ///     - `None` -> no ipc
860    ///     - `Some(None)` -> use default path
861    ///     - `Some(Some(path))` -> use custom path
862    #[must_use]
863    pub fn with_ipc(mut self, ipc_path: Option<Option<String>>) -> Self {
864        self.ipc_path = ipc_path;
865        self
866    }
867
868    /// Sets the file path to write the Anvil node's config info to.
869    #[must_use]
870    pub fn set_config_out(mut self, config_out: Option<PathBuf>) -> Self {
871        self.config_out = config_out;
872        self
873    }
874
875    #[must_use]
876    pub const fn with_no_storage_caching(mut self, no_storage_caching: bool) -> Self {
877        self.no_storage_caching = no_storage_caching;
878        self
879    }
880
881    /// Sets the `eth_rpc_url` to use when forking (single endpoint convenience).
882    #[must_use]
883    pub fn with_eth_rpc_url<U: Into<String>>(mut self, eth_rpc_url: Option<U>) -> Self {
884        if let Some(url) = eth_rpc_url {
885            self.fork_urls = vec![url.into()];
886        }
887        self
888    }
889
890    /// Sets the fork URLs for load-balanced multi-endpoint forking.
891    #[must_use]
892    pub fn with_fork_urls(mut self, fork_urls: Vec<String>) -> Self {
893        self.fork_urls = fork_urls;
894        self
895    }
896
897    /// Sets the `fork_choice` to use to fork off from based on a block number
898    #[must_use]
899    pub fn with_fork_block_number<U: Into<u64>>(self, fork_block_number: Option<U>) -> Self {
900        self.with_fork_choice(fork_block_number.map(Into::into))
901    }
902
903    /// Sets the `fork_choice` to use to fork off from based on a transaction hash
904    #[must_use]
905    pub fn with_fork_transaction_hash<U: Into<TxHash>>(
906        self,
907        fork_transaction_hash: Option<U>,
908    ) -> Self {
909        self.with_fork_choice(fork_transaction_hash.map(Into::into))
910    }
911
912    /// Sets the `fork_choice` to use to fork off from
913    #[must_use]
914    pub fn with_fork_choice<U: Into<ForkChoice>>(mut self, fork_choice: Option<U>) -> Self {
915        self.fork_choice = fork_choice.map(Into::into);
916        self
917    }
918
919    /// Sets the `fork_chain_id` to use to fork off local cache from
920    #[must_use]
921    pub const fn with_fork_chain_id(mut self, fork_chain_id: Option<U256>) -> Self {
922        self.fork_chain_id = fork_chain_id;
923        self
924    }
925
926    /// Sets the `fork_headers` to use with fork RPC endpoints
927    #[must_use]
928    pub fn with_fork_headers(mut self, headers: Vec<String>) -> Self {
929        self.fork_headers = headers;
930        self
931    }
932
933    /// Sets the `fork_request_timeout` to use for requests
934    #[must_use]
935    pub const fn fork_request_timeout(mut self, fork_request_timeout: Option<Duration>) -> Self {
936        if let Some(fork_request_timeout) = fork_request_timeout {
937            self.fork_request_timeout = fork_request_timeout;
938        }
939        self
940    }
941
942    /// Sets the `fork_request_retries` to use for spurious networks
943    #[must_use]
944    pub const fn fork_request_retries(mut self, fork_request_retries: Option<u32>) -> Self {
945        if let Some(fork_request_retries) = fork_request_retries {
946            self.fork_request_retries = fork_request_retries;
947        }
948        self
949    }
950
951    /// Sets the initial `fork_retry_backoff` for rate limits
952    #[must_use]
953    pub const fn fork_retry_backoff(mut self, fork_retry_backoff: Option<Duration>) -> Self {
954        if let Some(fork_retry_backoff) = fork_retry_backoff {
955            self.fork_retry_backoff = fork_retry_backoff;
956        }
957        self
958    }
959
960    /// Sets the number of assumed available compute units per second
961    ///
962    /// See also, <https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second>
963    #[must_use]
964    pub const fn fork_compute_units_per_second(
965        mut self,
966        compute_units_per_second: Option<u64>,
967    ) -> Self {
968        if let Some(compute_units_per_second) = compute_units_per_second {
969            self.compute_units_per_second = compute_units_per_second;
970        }
971        self
972    }
973
974    /// Sets whether to enable tracing
975    #[must_use]
976    pub const fn with_tracing(mut self, enable_tracing: bool) -> Self {
977        self.enable_tracing = enable_tracing;
978        self
979    }
980
981    /// Sets whether to enable steps tracing
982    #[must_use]
983    pub const fn with_steps_tracing(mut self, enable_steps_tracing: bool) -> Self {
984        self.enable_steps_tracing = enable_steps_tracing;
985        self
986    }
987
988    /// Sets whether to print `console.log` invocations to stdout.
989    #[must_use]
990    pub const fn with_print_logs(mut self, print_logs: bool) -> Self {
991        self.print_logs = print_logs;
992        self
993    }
994
995    /// Sets whether to print traces to stdout.
996    #[must_use]
997    pub const fn with_print_traces(mut self, print_traces: bool) -> Self {
998        self.print_traces = print_traces;
999        self
1000    }
1001
1002    /// Sets whether to enable autoImpersonate
1003    #[must_use]
1004    pub const fn with_auto_impersonate(mut self, enable_auto_impersonate: bool) -> Self {
1005        self.enable_auto_impersonate = enable_auto_impersonate;
1006        self
1007    }
1008
1009    #[must_use]
1010    pub fn with_server_config(mut self, config: ServerConfig) -> Self {
1011        self.server_config = config;
1012        self
1013    }
1014
1015    /// Sets the host the server will listen on
1016    #[must_use]
1017    pub fn with_host(mut self, host: Vec<IpAddr>) -> Self {
1018        self.host = if host.is_empty() { vec![IpAddr::V4(Ipv4Addr::LOCALHOST)] } else { host };
1019        self
1020    }
1021
1022    #[must_use]
1023    pub const fn with_transaction_order(mut self, transaction_order: TransactionOrder) -> Self {
1024        self.transaction_order = transaction_order;
1025        self
1026    }
1027
1028    /// Returns the ipc path for the ipc endpoint if any
1029    pub fn get_ipc_path(&self) -> Option<String> {
1030        match &self.ipc_path {
1031            Some(path) => path.clone().or_else(|| Some(DEFAULT_IPC_ENDPOINT.to_string())),
1032            None => None,
1033        }
1034    }
1035
1036    /// Prints the config info
1037    pub fn print(&self, fork: Option<&ClientFork>) -> Result<()> {
1038        if let Some(path) = &self.config_out {
1039            let value = self.as_json(fork);
1040            foundry_common::fs::write_json_file(path, &value).wrap_err("failed writing JSON")?;
1041        }
1042        if !self.silent {
1043            sh_println!("{}", self.as_string(fork))?;
1044        }
1045        Ok(())
1046    }
1047
1048    /// Returns the path where the cache file should be stored
1049    ///
1050    /// See also [ Config::foundry_block_cache_file()]
1051    pub fn block_cache_path(&self, block: u64) -> Option<PathBuf> {
1052        if self.no_storage_caching || self.fork_urls.is_empty() {
1053            return None;
1054        }
1055        let chain_id = self.get_chain_id();
1056
1057        Config::foundry_block_cache_file(chain_id, block)
1058    }
1059
1060    /// Sets whether to disable the default create2 deployer
1061    #[must_use]
1062    pub const fn with_disable_default_create2_deployer(mut self, yes: bool) -> Self {
1063        self.disable_default_create2_deployer = yes;
1064        self
1065    }
1066
1067    /// Sets whether to disable pool balance checks
1068    #[must_use]
1069    pub const fn with_disable_pool_balance_checks(mut self, yes: bool) -> Self {
1070        self.disable_pool_balance_checks = yes;
1071        self
1072    }
1073
1074    /// Injects precompiles to `anvil`'s EVM.
1075    #[must_use]
1076    pub fn with_precompile_factory(mut self, factory: impl PrecompileFactory + 'static) -> Self {
1077        self.precompile_factory = Some(Arc::new(factory));
1078        self
1079    }
1080
1081    /// Enable features for provided networks.
1082    #[must_use]
1083    pub const fn with_networks(mut self, networks: NetworkConfigs) -> Self {
1084        self.networks = networks;
1085        self
1086    }
1087
1088    /// Enable Tempo network features.
1089    #[must_use]
1090    pub fn with_tempo(mut self) -> Self {
1091        self.networks = NetworkConfigs::with_tempo();
1092        self
1093    }
1094
1095    /// Enable Optimism network features.
1096    #[cfg(feature = "optimism")]
1097    #[must_use]
1098    pub fn with_optimism(mut self) -> Self {
1099        self.networks = NetworkConfigs::with_optimism();
1100        self
1101    }
1102
1103    /// Makes the node silent to not emit anything on stdout
1104    #[must_use]
1105    pub const fn silent(self) -> Self {
1106        self.set_silent(true)
1107    }
1108
1109    #[must_use]
1110    pub const fn set_silent(mut self, silent: bool) -> Self {
1111        self.silent = silent;
1112        self
1113    }
1114
1115    /// Sets the path where persisted states are cached (used with `max_persisted_states`).
1116    ///
1117    /// Note: This does not control the fork RPC cache location (`storage.json`), which uses
1118    /// `~/.foundry/cache/rpc/<chain>/<block>/` via [`Config::foundry_block_cache_file`].
1119    #[must_use]
1120    pub fn with_cache_path(mut self, cache_path: Option<PathBuf>) -> Self {
1121        self.cache_path = cache_path;
1122        self
1123    }
1124
1125    /// Sets accounts to fund with custom balances on startup.
1126    #[must_use]
1127    pub fn with_funded_accounts(mut self, accounts: HashMap<Address, U256>) -> Self {
1128        self.funded_accounts = accounts;
1129        self
1130    }
1131
1132    /// Configures everything related to env, backend and database and returns the
1133    /// [Backend](mem::Backend)
1134    ///
1135    /// *Note*: only memory based backend for now
1136    pub(crate) async fn setup<N>(&mut self) -> Result<mem::Backend<N>>
1137    where
1138        N: alloy_network::Network<
1139                TxEnvelope = foundry_primitives::FoundryTxEnvelope,
1140                ReceiptEnvelope = foundry_primitives::FoundryReceiptEnvelope,
1141            >,
1142    {
1143        // configure the revm environment
1144
1145        let mut cfg = CfgEnv::default();
1146        cfg.spec = self.get_hardfork().into();
1147
1148        cfg.chain_id = self.get_chain_id();
1149        cfg.limit_contract_code_size = self.code_size_limit;
1150        // EIP-3607 rejects transactions from senders with deployed code.
1151        // If EIP-3607 is enabled it can cause issues during fuzz/invariant tests if the
1152        // caller is a contract. So we disable the check by default.
1153        cfg.disable_eip3607 = true;
1154        cfg.disable_block_gas_limit = self.disable_block_gas_limit;
1155
1156        if !self.enable_tx_gas_limit {
1157            cfg.tx_gas_limit_cap = Some(u64::MAX);
1158        }
1159
1160        if let Some(value) = self.memory_limit {
1161            cfg.memory_limit = value;
1162        }
1163
1164        let spec_id = cfg.spec;
1165        let mut evm_env = EvmEnv::new(
1166            cfg,
1167            BlockEnv {
1168                gas_limit: self.gas_limit(),
1169                basefee: self.get_base_fee(),
1170                ..Default::default()
1171            },
1172        );
1173
1174        let base_fee_params: BaseFeeParams =
1175            self.networks.base_fee_params(self.get_genesis_timestamp());
1176
1177        let fees = FeeManager::new(
1178            spec_id,
1179            self.get_base_fee(),
1180            !self.disable_min_priority_fee,
1181            self.get_gas_price(),
1182            self.get_blob_excess_gas_and_price(),
1183            self.get_blob_params(),
1184            base_fee_params,
1185        );
1186
1187        let (db, fork): (Arc<TokioRwLock<Box<dyn Db>>>, Option<ClientFork>) =
1188            if let Some(eth_rpc_url) = self.fork_urls.first().cloned() {
1189                self.setup_fork_db(eth_rpc_url, &mut evm_env, &fees).await?
1190            } else {
1191                (Arc::new(TokioRwLock::new(Box::<MemDb>::default())), None)
1192            };
1193
1194        // if provided use all settings of `genesis.json`
1195        if let Some(ref genesis) = self.genesis {
1196            // --chain-id flag gets precedence over the genesis.json chain id
1197            // <https://github.com/foundry-rs/foundry/issues/10059>
1198            if self.chain_id.is_none() {
1199                evm_env.cfg_env.chain_id = genesis.config.chain_id;
1200            }
1201            evm_env.block_env.timestamp = U256::from(genesis.timestamp);
1202            if let Some(base_fee) = genesis.base_fee_per_gas {
1203                evm_env.block_env.basefee = base_fee.try_into()?;
1204            }
1205            if let Some(number) = genesis.number {
1206                evm_env.block_env.number = U256::from(number);
1207            }
1208            evm_env.block_env.beneficiary = genesis.coinbase;
1209        }
1210
1211        let genesis = GenesisConfig {
1212            number: self.get_genesis_number(),
1213            timestamp: self.get_genesis_timestamp(),
1214            balance: self.genesis_balance,
1215            accounts: self.genesis_accounts.iter().map(|acc| acc.address()).collect(),
1216            genesis_init: self.genesis.clone(),
1217        };
1218
1219        let mut decoder_builder = CallTraceDecoderBuilder::new();
1220        if self.print_traces {
1221            // if traces should get printed we configure the decoder with the signatures cache
1222            if let Ok(identifier) = SignaturesIdentifier::new(false) {
1223                debug!(target: "node", "using signature identifier");
1224                decoder_builder = decoder_builder.with_signature_identifier(identifier);
1225            }
1226        }
1227
1228        // only memory based backend for now
1229        let backend = mem::Backend::with_genesis(
1230            db,
1231            Arc::new(RwLock::new(evm_env)),
1232            self.networks,
1233            genesis,
1234            fees,
1235            Arc::new(RwLock::new(fork)),
1236            self.enable_steps_tracing,
1237            self.print_logs,
1238            self.print_traces,
1239            Arc::new(decoder_builder.build()),
1240            self.prune_history,
1241            self.max_persisted_states,
1242            self.transaction_block_keeper,
1243            self.block_time,
1244            self.cache_path.clone(),
1245            Arc::new(TokioRwLock::new(self.clone())),
1246        )
1247        .await?;
1248
1249        // Writes the default create2 deployer to the backend,
1250        // if the option is not disabled and we are not forking.
1251        if !self.disable_default_create2_deployer && self.fork_urls.is_empty() {
1252            backend
1253                .set_create2_deployer(DEFAULT_CREATE2_DEPLOYER)
1254                .await
1255                .wrap_err("failed to create default create2 deployer")?;
1256        }
1257
1258        if !self.funded_accounts.is_empty() {
1259            for (address, balance) in &self.funded_accounts {
1260                backend
1261                    .set_balance(*address, *balance)
1262                    .await
1263                    .wrap_err_with(|| format!("failed to fund account {address}"))?;
1264            }
1265        }
1266
1267        Ok(backend)
1268    }
1269
1270    /// Configures everything related to forking based on the passed `eth_rpc_url`:
1271    ///  - returning a tuple of a [ForkedDatabase] wrapped in an [Arc] [RwLock](TokioRwLock) and
1272    ///    [ClientFork] wrapped in an [Option] which can be used in a [Backend](mem::Backend) to
1273    ///    fork from.
1274    ///  - modifying some parameters of the passed `env`
1275    ///  - mutating some members of `self`
1276    pub async fn setup_fork_db(
1277        &mut self,
1278        eth_rpc_url: String,
1279        evm_env: &mut EvmEnv,
1280        fees: &FeeManager,
1281    ) -> Result<(Arc<TokioRwLock<Box<dyn Db>>>, Option<ClientFork>)> {
1282        let (db, config) = self.setup_fork_db_config(eth_rpc_url, evm_env, fees).await?;
1283        let db: Arc<TokioRwLock<Box<dyn Db>>> = Arc::new(TokioRwLock::new(Box::new(db)));
1284        let fork = ClientFork::new(config, Arc::clone(&db));
1285        Ok((db, Some(fork)))
1286    }
1287
1288    /// Configures everything related to forking based on the passed `eth_rpc_url`:
1289    ///  - returning a tuple of a [ForkedDatabase] and [ClientForkConfig] which can be used to build
1290    ///    a [ClientFork] to fork from.
1291    ///  - modifying some parameters of the passed `env`
1292    ///  - mutating some members of `self`
1293    pub async fn setup_fork_db_config(
1294        &mut self,
1295        eth_rpc_url: String,
1296        evm_env: &mut EvmEnv,
1297        fees: &FeeManager,
1298    ) -> Result<(ForkedDatabase<AnyNetwork>, ClientForkConfig)> {
1299        debug!(target: "node", ?eth_rpc_url, "setting up fork db");
1300
1301        // Always bootstrap with the primary URL only to avoid race conditions
1302        // where discovery calls (get_chain_id, find_latest_fork_block, get_block)
1303        // hit different endpoints that may be at different chain tips.
1304        let provider = Arc::new(
1305            ProviderBuilder::new(&eth_rpc_url)
1306                .timeout(self.fork_request_timeout)
1307                .initial_backoff(self.fork_retry_backoff.as_millis() as u64)
1308                .compute_units_per_second(self.compute_units_per_second)
1309                .max_retry(self.fork_request_retries)
1310                .headers(self.fork_headers.clone())
1311                .build()
1312                .wrap_err("failed to establish provider to fork url")?,
1313        );
1314
1315        let (fork_block_number, fork_chain_id, force_transactions) = if let Some(fork_choice) =
1316            &self.fork_choice
1317        {
1318            let (fork_block_number, force_transactions) =
1319                derive_block_and_transactions(fork_choice, &provider).await.wrap_err(
1320                    "failed to derive fork block number and force transactions from fork choice",
1321                )?;
1322            let chain_id = if let Some(chain_id) = self.fork_chain_id {
1323                Some(chain_id)
1324            } else if self.hardfork.is_none() {
1325                let chain_id =
1326                    provider.get_chain_id().await.wrap_err("failed to fetch network chain ID")?;
1327                Some(U256::from(chain_id))
1328            } else {
1329                None
1330            };
1331
1332            (fork_block_number, chain_id, force_transactions)
1333        } else {
1334            // pick the last block number but also ensure it's not pending anymore
1335            let bn = find_latest_fork_block(&provider)
1336                .await
1337                .wrap_err("failed to get fork block number")?;
1338            (bn, None, None)
1339        };
1340
1341        let block = provider
1342            .get_block(BlockNumberOrTag::Number(fork_block_number).into())
1343            .await
1344            .wrap_err("failed to get fork block")?;
1345
1346        let block = if let Some(block) = block {
1347            block
1348        } else {
1349            if let Ok(latest_block) = provider.get_block_number().await {
1350                let mut message = format!(
1351                    "Failed to get block for block number: {fork_block_number}\n\
1352latest block number: {latest_block}"
1353                );
1354                // If the `eth_getBlockByNumber` call succeeds, but returns null instead of
1355                // the block, and the block number is less than equal the latest block, then
1356                // the user is forking from a non-archive node with an older block number.
1357                if fork_block_number <= latest_block {
1358                    message.push_str(&format!("\n{NON_ARCHIVE_NODE_WARNING}"));
1359                }
1360                eyre::bail!("{message}");
1361            }
1362            eyre::bail!("failed to get block for block number: {fork_block_number}")
1363        };
1364
1365        let gas_limit = self.fork_gas_limit(&block);
1366        self.gas_limit = Some(gas_limit);
1367
1368        evm_env.block_env = BlockEnv {
1369            gas_limit,
1370            // Keep previous `coinbase` and `basefee` value
1371            beneficiary: evm_env.block_env.beneficiary,
1372            basefee: evm_env.block_env.basefee,
1373            ..block_env_from_header(&block.header)
1374        };
1375
1376        // Determine chain_id early so we can use it consistently
1377        let chain_id = if let Some(chain_id) = self.chain_id {
1378            chain_id
1379        } else {
1380            let chain_id = if let Some(fork_chain_id) = fork_chain_id {
1381                fork_chain_id.to()
1382            } else {
1383                provider.get_chain_id().await.wrap_err("failed to fetch network chain ID")?
1384            };
1385
1386            // need to update the dev signers and env with the chain id
1387            self.set_chain_id(Some(chain_id));
1388            evm_env.cfg_env.chain_id = chain_id;
1389            chain_id
1390        };
1391
1392        // Auto-detect hardfork from chain activation data if not explicitly set.
1393        if self.hardfork.is_none()
1394            && let Some(hardfork) =
1395                FoundryHardfork::from_chain_and_timestamp(chain_id, block.header.timestamp())
1396        {
1397            evm_env.cfg_env.spec = SpecId::from(hardfork);
1398            self.hardfork = Some(hardfork);
1399        }
1400
1401        // if not set explicitly we use the base fee of the latest block
1402        if self.base_fee.is_none()
1403            && let Some(base_fee) = block.header.base_fee_per_gas()
1404        {
1405            self.base_fee = Some(base_fee);
1406            evm_env.block_env.basefee = base_fee;
1407            // this is the base fee of the current block, but we need the base fee of
1408            // the next block
1409            let next_block_base_fee = fees.get_next_block_base_fee_per_gas(
1410                block.header.gas_used(),
1411                gas_limit,
1412                block.header.base_fee_per_gas().unwrap_or_default(),
1413            );
1414
1415            // update next base fee
1416            fees.set_base_fee(next_block_base_fee);
1417        }
1418
1419        if let (Some(blob_excess_gas), Some(blob_gas_used)) =
1420            (block.header.excess_blob_gas(), block.header.blob_gas_used())
1421        {
1422            // Derive blob params using the fork block timestamp regardless of explicit base fee.
1423            let blob_params = get_blob_params(chain_id, block.header.timestamp());
1424
1425            evm_env.block_env.blob_excess_gas_and_price = Some(BlobExcessGasAndPrice::new(
1426                blob_excess_gas,
1427                blob_params.update_fraction as u64,
1428            ));
1429
1430            fees.set_blob_params(blob_params);
1431
1432            let next_block_blob_excess_gas =
1433                fees.get_next_block_blob_excess_gas(blob_excess_gas, blob_gas_used);
1434            fees.set_blob_excess_gas_and_price(BlobExcessGasAndPrice::new(
1435                next_block_blob_excess_gas,
1436                blob_params.update_fraction as u64,
1437            ));
1438        }
1439
1440        // use remote gas price
1441        if self.gas_price.is_none()
1442            && let Ok(gas_price) = provider.get_gas_price().await
1443        {
1444            self.gas_price = Some(gas_price);
1445            fees.set_gas_price(gas_price);
1446        }
1447
1448        let block_hash = block.header.hash;
1449
1450        let override_chain_id = self.chain_id;
1451        // apply changes such as difficulty -> prevrandao and chain specifics for current chain id
1452        apply_chain_and_block_specific_env_changes::<AnyNetwork, _, _>(
1453            evm_env,
1454            &block,
1455            self.networks,
1456        );
1457
1458        let meta = BlockchainDbMeta::new(evm_env.block_env.clone(), eth_rpc_url.clone());
1459        let block_chain_db = if self.fork_chain_id.is_some() {
1460            BlockchainDb::new_skip_check(meta, self.block_cache_path(fork_block_number))
1461        } else {
1462            BlockchainDb::new(meta, self.block_cache_path(fork_block_number))
1463        };
1464
1465        // After bootstrap, rebuild the provider with round-robin if multiple URLs are
1466        // configured. This ensures bootstrap used only the primary endpoint for consistency,
1467        // while ongoing requests are distributed across all endpoints.
1468        let provider = if self.fork_urls.len() > 1 {
1469            debug!(target: "node", urls=?self.fork_urls, "using multi-endpoint round-robin provider");
1470            Arc::new(
1471                ProviderBuilder::new(&eth_rpc_url)
1472                    .timeout(self.fork_request_timeout)
1473                    .initial_backoff(self.fork_retry_backoff.as_millis() as u64)
1474                    .compute_units_per_second(self.compute_units_per_second)
1475                    .max_retry(self.fork_request_retries)
1476                    .headers(self.fork_headers.clone())
1477                    .build_fallback(self.fork_urls.clone())
1478                    .wrap_err("failed to establish round-robin provider to fork urls")?,
1479            )
1480        } else {
1481            provider
1482        };
1483
1484        // This will spawn the background thread that will use the provider to fetch
1485        // blockchain data from the other client
1486        let backend = SharedBackend::spawn_backend(
1487            Arc::clone(&provider),
1488            block_chain_db.clone(),
1489            Some(fork_block_number.into()),
1490        )
1491        .await;
1492
1493        let config = ClientForkConfig {
1494            fork_urls: self.fork_urls.clone(),
1495            block_number: fork_block_number,
1496            block_hash,
1497            transaction_hash: self.fork_choice.and_then(|fc| fc.transaction_hash()),
1498            provider,
1499            chain_id,
1500            override_chain_id,
1501            hardfork: self.hardfork,
1502            timestamp: block.header.timestamp(),
1503            base_fee: block.header.base_fee_per_gas().map(|g| g as u128),
1504            timeout: self.fork_request_timeout,
1505            retries: self.fork_request_retries,
1506            backoff: self.fork_retry_backoff,
1507            compute_units_per_second: self.compute_units_per_second,
1508            headers: self.fork_headers.clone(),
1509            total_difficulty: block.header.total_difficulty.unwrap_or_default(),
1510            blob_gas_used: block.header.blob_gas_used().map(|g| g as u128),
1511            blob_excess_gas_and_price: evm_env.block_env.blob_excess_gas_and_price,
1512            force_transactions,
1513        };
1514
1515        debug!(target: "node", fork_number=config.block_number, fork_hash=%config.block_hash, "set up fork db");
1516
1517        let mut db = ForkedDatabase::new(backend, block_chain_db);
1518
1519        // need to insert the forked block's hash
1520        db.insert_block_hash(U256::from(config.block_number), config.block_hash);
1521
1522        Ok((db, config))
1523    }
1524
1525    /// we only use the gas limit value of the block if it is non-zero and the block gas
1526    /// limit is enabled, since there are networks where this is not used and is always
1527    /// `0x0` which would inevitably result in `OutOfGas` errors as soon as the evm is about to record gas, See also <https://github.com/foundry-rs/foundry/issues/3247>
1528    pub(crate) fn fork_gas_limit<B: BlockResponse<Header: BlockHeader>>(&self, block: &B) -> u64 {
1529        if !self.disable_block_gas_limit {
1530            if let Some(gas_limit) = self.gas_limit {
1531                return gas_limit;
1532            } else if block.header().gas_limit() > 0 {
1533                return block.header().gas_limit();
1534            }
1535        }
1536
1537        u64::MAX
1538    }
1539
1540    /// Returns the gas limit for a non forked anvil instance
1541    ///
1542    /// Checks the config for the `disable_block_gas_limit` flag
1543    pub(crate) fn gas_limit(&self) -> u64 {
1544        if self.disable_block_gas_limit {
1545            return u64::MAX;
1546        }
1547
1548        self.gas_limit.unwrap_or(DEFAULT_GAS_LIMIT)
1549    }
1550}
1551
1552/// If the fork choice is a block number, simply return it with an empty list of transactions.
1553/// If the fork choice is a transaction hash, determine the block that the transaction was mined in,
1554/// and return the block number before the fork block along with all transactions in the fork block
1555/// that are before (and including) the fork transaction.
1556async fn derive_block_and_transactions(
1557    fork_choice: &ForkChoice,
1558    provider: &Arc<RetryProvider>,
1559) -> eyre::Result<(BlockNumber, Option<Vec<PoolTransaction<FoundryTxEnvelope>>>)> {
1560    match fork_choice {
1561        ForkChoice::Block(block_number) => {
1562            let block_number = *block_number;
1563            if block_number >= 0 {
1564                return Ok((block_number as u64, None));
1565            }
1566            // subtract from latest block number
1567            let latest = provider.get_block_number().await?;
1568
1569            Ok((block_number.saturating_add(latest as i128) as u64, None))
1570        }
1571        ForkChoice::Transaction(transaction_hash) => {
1572            // Determine the block that this transaction was mined in
1573            let transaction = provider
1574                .get_transaction_by_hash(transaction_hash.0.into())
1575                .await?
1576                .ok_or_else(|| eyre::eyre!("failed to get fork transaction by hash"))?;
1577            let transaction_block_number = transaction.block_number().ok_or_else(|| {
1578                eyre::eyre!("fork transaction is not mined yet (no block number)")
1579            })?;
1580
1581            // Get the block pertaining to the fork transaction
1582            let transaction_block = provider
1583                .get_block_by_number(transaction_block_number.into())
1584                .full()
1585                .await?
1586                .ok_or_else(|| eyre::eyre!("failed to get fork block by number"))?;
1587
1588            // Filter out transactions that are after the fork transaction
1589            let filtered_transactions = transaction_block
1590                .transactions
1591                .as_transactions()
1592                .ok_or_else(|| eyre::eyre!("failed to get transactions from full fork block"))?
1593                .iter()
1594                .take_while_inclusive(|&transaction| transaction.tx_hash() != transaction_hash.0)
1595                .collect::<Vec<_>>();
1596
1597            // Convert the transactions to PoolTransactions
1598            let force_transactions = filtered_transactions
1599                .iter()
1600                .map(|&transaction| PoolTransaction::try_from(transaction.clone()))
1601                .collect::<Result<Vec<_>, _>>()
1602                .map_err(|e| eyre::eyre!("Err converting to pool transactions {e}"))?;
1603            Ok((transaction_block_number.saturating_sub(1), Some(force_transactions)))
1604        }
1605    }
1606}
1607
1608/// Fork delimiter used to specify which block or transaction to fork from.
1609#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1610pub enum ForkChoice {
1611    /// Block number to fork from.
1612    ///
1613    /// If negative, the given value is subtracted from the `latest` block number.
1614    Block(i128),
1615    /// Transaction hash to fork from.
1616    Transaction(TxHash),
1617}
1618
1619impl ForkChoice {
1620    /// Returns the block number to fork from
1621    pub const fn block_number(&self) -> Option<i128> {
1622        match self {
1623            Self::Block(block_number) => Some(*block_number),
1624            Self::Transaction(_) => None,
1625        }
1626    }
1627
1628    /// Returns the transaction hash to fork from
1629    pub const fn transaction_hash(&self) -> Option<TxHash> {
1630        match self {
1631            Self::Block(_) => None,
1632            Self::Transaction(transaction_hash) => Some(*transaction_hash),
1633        }
1634    }
1635}
1636
1637/// Convert a transaction hash into a ForkChoice
1638impl From<TxHash> for ForkChoice {
1639    fn from(tx_hash: TxHash) -> Self {
1640        Self::Transaction(tx_hash)
1641    }
1642}
1643
1644/// Convert a decimal block number into a ForkChoice
1645impl From<u64> for ForkChoice {
1646    fn from(block: u64) -> Self {
1647        Self::Block(block as i128)
1648    }
1649}
1650
1651#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
1652pub struct PruneStateHistoryConfig {
1653    pub enabled: bool,
1654    pub max_memory_history: Option<usize>,
1655}
1656
1657impl PruneStateHistoryConfig {
1658    /// Returns `true` if writing state history is supported
1659    pub const fn is_state_history_supported(&self) -> bool {
1660        if !self.enabled {
1661            return true;
1662        }
1663
1664        match self.max_memory_history {
1665            Some(limit) => limit > 0,
1666            None => false,
1667        }
1668    }
1669
1670    /// Returns true if this setting was enabled.
1671    pub const fn is_config_enabled(&self) -> bool {
1672        self.enabled
1673    }
1674
1675    pub fn from_args(val: Option<Option<usize>>) -> Self {
1676        val.map(|max_memory_history| Self {
1677            enabled: true,
1678            max_memory_history: max_memory_history.filter(|limit| *limit > 0),
1679        })
1680        .unwrap_or_default()
1681    }
1682}
1683
1684/// Can create dev accounts
1685#[derive(Clone, Debug)]
1686pub struct AccountGenerator {
1687    chain_id: u64,
1688    amount: usize,
1689    phrase: String,
1690    derivation_path: Option<String>,
1691}
1692
1693impl AccountGenerator {
1694    pub fn new(amount: usize) -> Self {
1695        Self {
1696            chain_id: CHAIN_ID,
1697            amount,
1698            phrase: Mnemonic::<English>::new(&mut thread_rng()).to_phrase(),
1699            derivation_path: None,
1700        }
1701    }
1702
1703    #[must_use]
1704    pub fn phrase(mut self, phrase: impl Into<String>) -> Self {
1705        self.phrase = phrase.into();
1706        self
1707    }
1708
1709    fn get_phrase(&self) -> &str {
1710        &self.phrase
1711    }
1712
1713    #[must_use]
1714    pub fn chain_id(mut self, chain_id: impl Into<u64>) -> Self {
1715        self.chain_id = chain_id.into();
1716        self
1717    }
1718
1719    #[must_use]
1720    pub fn derivation_path(mut self, derivation_path: impl Into<String>) -> Self {
1721        let mut derivation_path = derivation_path.into();
1722        if !derivation_path.ends_with('/') {
1723            derivation_path.push('/');
1724        }
1725        self.derivation_path = Some(derivation_path);
1726        self
1727    }
1728
1729    fn get_derivation_path(&self) -> &str {
1730        self.derivation_path.as_deref().unwrap_or("m/44'/60'/0'/0/")
1731    }
1732}
1733
1734impl AccountGenerator {
1735    pub fn generate(&self) -> eyre::Result<Vec<PrivateKeySigner>> {
1736        let builder = MnemonicBuilder::<English>::default().phrase(self.phrase.as_str());
1737
1738        // use the derivation path
1739        let derivation_path = self.get_derivation_path();
1740
1741        let mut wallets = Vec::with_capacity(self.amount);
1742        for idx in 0..self.amount {
1743            let builder =
1744                builder.clone().derivation_path(format!("{derivation_path}{idx}")).unwrap();
1745            let wallet = builder.build()?.with_chain_id(Some(self.chain_id));
1746            wallets.push(wallet)
1747        }
1748        Ok(wallets)
1749    }
1750}
1751
1752/// Returns the path to anvil dir `~/.foundry/anvil`
1753pub fn anvil_dir() -> Option<PathBuf> {
1754    Config::foundry_dir().map(|p| p.join("anvil"))
1755}
1756
1757/// Returns the root path to anvil's temporary storage `~/.foundry/anvil/`
1758pub fn anvil_tmp_dir() -> Option<PathBuf> {
1759    anvil_dir().map(|p| p.join("tmp"))
1760}
1761
1762/// Finds the latest appropriate block to fork
1763///
1764/// This fetches the "latest" block and checks whether the `Block` is fully populated (`hash` field
1765/// is present). This prevents edge cases where anvil forks the "latest" block but `eth_getBlockByNumber` still returns a pending block, <https://github.com/foundry-rs/foundry/issues/2036>
1766async fn find_latest_fork_block<P: Provider<AnyNetwork>>(
1767    provider: P,
1768) -> Result<u64, TransportError> {
1769    let mut num = provider.get_block_number().await?;
1770
1771    // walk back from the head of the chain, but at most 2 blocks, which should be more than enough
1772    // leeway
1773    for _ in 0..2 {
1774        if let Some(block) = provider.get_block(num.into()).await?
1775            && !block.header.hash.is_zero()
1776        {
1777            break;
1778        }
1779        // block not actually finalized, so we try the block before
1780        num = num.saturating_sub(1)
1781    }
1782
1783    Ok(num)
1784}
1785
1786#[cfg(test)]
1787mod tests {
1788    use super::*;
1789
1790    #[test]
1791    fn test_prune_history() {
1792        let config = PruneStateHistoryConfig::default();
1793        assert!(config.is_state_history_supported());
1794        let config = PruneStateHistoryConfig::from_args(Some(None));
1795        assert!(!config.is_state_history_supported());
1796        let config = PruneStateHistoryConfig::from_args(Some(Some(0)));
1797        assert!(config.is_config_enabled());
1798        assert!(!config.is_state_history_supported());
1799        let config = PruneStateHistoryConfig::from_args(Some(Some(10)));
1800        assert!(config.is_state_history_supported());
1801    }
1802
1803    #[cfg(feature = "optimism")]
1804    #[test]
1805    fn set_chain_id_updates_network_config() {
1806        let mut config = NodeConfig::test();
1807        config.set_chain_id(Some(10u64));
1808
1809        assert!(config.networks.is_optimism());
1810    }
1811
1812    #[test]
1813    fn get_hardfork_on_tempo_never_returns_non_tempo_variant() {
1814        // Post-Shanghai timestamp on Ethereum mainnet.
1815        let shanghai_ts = 1_681_338_455u64;
1816
1817        let config = NodeConfig::test_tempo()
1818            .with_chain_id(Some(1u64))
1819            .with_genesis_timestamp(Some(shanghai_ts));
1820
1821        assert!(config.networks.is_tempo());
1822        assert!(matches!(config.get_hardfork(), FoundryHardfork::Tempo(_)));
1823    }
1824}