anvil/
config.rs

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