anvil/
config.rs

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