Skip to main content

anvil/
config.rs

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