Skip to main content

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