foundry_evm_core/fork/
init.rs1use crate::{AsEnvMut, Env, EvmEnv, utils::apply_chain_and_block_specific_env_changes};
2use alloy_consensus::BlockHeader;
3use alloy_primitives::{Address, U256};
4use alloy_provider::{Network, Provider, network::BlockResponse};
5use alloy_rpc_types::BlockNumberOrTag;
6use foundry_common::NON_ARCHIVE_NODE_WARNING;
7use foundry_evm_networks::NetworkConfigs;
8use revm::context::{BlockEnv, CfgEnv, TxEnv};
9
10#[allow(clippy::too_many_arguments)]
13pub async fn environment<N: Network, P: Provider<N>>(
14 provider: &P,
15 memory_limit: u64,
16 override_gas_price: Option<u128>,
17 override_chain_id: Option<u64>,
18 pin_block: Option<u64>,
19 origin: Address,
20 disable_block_gas_limit: bool,
21 enable_tx_gas_limit: bool,
22 configs: NetworkConfigs,
23) -> eyre::Result<(Env, N::BlockResponse)> {
24 trace!(
25 %memory_limit,
26 ?override_gas_price,
27 ?override_chain_id,
28 ?pin_block,
29 %origin,
30 %disable_block_gas_limit,
31 %enable_tx_gas_limit,
32 ?configs,
33 "creating fork environment"
34 );
35 let bn = match pin_block {
36 Some(bn) => BlockNumberOrTag::Number(bn),
37 None => BlockNumberOrTag::Latest,
38 };
39 let (gas_price, chain_id, block) = tokio::try_join!(
40 option_try_or_else(override_gas_price, async || provider.get_gas_price().await),
41 option_try_or_else(override_chain_id, async || provider.get_chain_id().await),
42 provider.get_block_by_number(bn)
43 )?;
44 let Some(block) = block else {
45 let bn_msg = match bn {
46 BlockNumberOrTag::Number(bn) => format!("block number: {bn}"),
47 bn => format!("{bn} block"),
48 };
49 let latest_msg = if let Ok(latest_block) = provider.get_block_number().await {
50 if let Some(block_number) = pin_block
54 && block_number <= latest_block
55 {
56 error!("{NON_ARCHIVE_NODE_WARNING}");
57 }
58 format!("; latest block number: {latest_block}")
59 } else {
60 Default::default()
61 };
62 eyre::bail!("failed to get {bn_msg}{latest_msg}");
63 };
64
65 let cfg = configure_env(chain_id, memory_limit, disable_block_gas_limit, enable_tx_gas_limit);
66
67 let mut env = Env {
68 evm_env: EvmEnv {
69 cfg_env: cfg,
70 block_env: BlockEnv {
71 number: U256::from(block.header().number()),
72 timestamp: U256::from(block.header().timestamp()),
73 beneficiary: block.header().beneficiary(),
74 difficulty: block.header().difficulty(),
75 prevrandao: block.header().mix_hash(),
76 basefee: block.header().base_fee_per_gas().unwrap_or_default(),
77 gas_limit: block.header().gas_limit(),
78 ..Default::default()
79 },
80 },
81 tx: TxEnv {
82 caller: origin,
83 gas_price,
84 chain_id: Some(chain_id),
85 gas_limit: block.header().gas_limit(),
86 ..Default::default()
87 },
88 };
89
90 apply_chain_and_block_specific_env_changes::<N>(env.as_env_mut(), &block, configs);
91
92 Ok((env, block))
93}
94
95async fn option_try_or_else<T, E>(
96 option: Option<T>,
97 f: impl AsyncFnOnce() -> Result<T, E>,
98) -> Result<T, E> {
99 if let Some(value) = option { Ok(value) } else { f().await }
100}
101
102pub fn configure_env(
104 chain_id: u64,
105 memory_limit: u64,
106 disable_block_gas_limit: bool,
107 enable_tx_gas_limit: bool,
108) -> CfgEnv {
109 let mut cfg = CfgEnv::default();
110 cfg.chain_id = chain_id;
111 cfg.memory_limit = memory_limit;
112 cfg.limit_contract_code_size = Some(usize::MAX);
113 cfg.disable_eip3607 = true;
117 cfg.disable_block_gas_limit = disable_block_gas_limit;
118 cfg.disable_nonce_check = true;
119 if !enable_tx_gas_limit {
122 cfg.tx_gas_limit_cap = Some(u64::MAX);
123 }
124 cfg
125}