Skip to main content

anvil/
config.rs

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