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