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