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