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 eyre::WrapErr;
7use foundry_common::NON_ARCHIVE_NODE_WARNING;
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 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) -> eyre::Result<(Env, N::BlockResponse)> {
23 let block_number = if let Some(pin_block) = pin_block {
24 pin_block
25 } else {
26 provider.get_block_number().await.wrap_err("failed to get latest block number")?
27 };
28 let (fork_gas_price, rpc_chain_id, block) = tokio::try_join!(
29 provider.get_gas_price(),
30 provider.get_chain_id(),
31 provider.get_block_by_number(BlockNumberOrTag::Number(block_number))
32 )?;
33 let block = if let Some(block) = block {
34 block
35 } else {
36 if let Ok(latest_block) = provider.get_block_number().await {
37 if block_number <= latest_block {
41 error!("{NON_ARCHIVE_NODE_WARNING}");
42 }
43 eyre::bail!(
44 "failed to get block for block number: {block_number}; \
45 latest block number: {latest_block}"
46 );
47 }
48 eyre::bail!("failed to get block for block number: {block_number}")
49 };
50
51 let cfg = configure_env(
52 override_chain_id.unwrap_or(rpc_chain_id),
53 memory_limit,
54 disable_block_gas_limit,
55 enable_tx_gas_limit,
56 );
57
58 let mut env = Env {
59 evm_env: EvmEnv {
60 cfg_env: cfg,
61 block_env: BlockEnv {
62 number: U256::from(block.header().number()),
63 timestamp: U256::from(block.header().timestamp()),
64 beneficiary: block.header().beneficiary(),
65 difficulty: block.header().difficulty(),
66 prevrandao: block.header().mix_hash(),
67 basefee: block.header().base_fee_per_gas().unwrap_or_default(),
68 gas_limit: block.header().gas_limit(),
69 ..Default::default()
70 },
71 },
72 tx: TxEnv {
73 caller: origin,
74 gas_price: gas_price.unwrap_or(fork_gas_price),
75 chain_id: Some(override_chain_id.unwrap_or(rpc_chain_id)),
76 gas_limit: block.header().gas_limit() as u64,
77 ..Default::default()
78 },
79 };
80
81 apply_chain_and_block_specific_env_changes::<N>(env.as_env_mut(), &block);
82
83 Ok((env, block))
84}
85
86pub fn configure_env(
88 chain_id: u64,
89 memory_limit: u64,
90 disable_block_gas_limit: bool,
91 enable_tx_gas_limit: bool,
92) -> CfgEnv {
93 let mut cfg = CfgEnv::default();
94 cfg.chain_id = chain_id;
95 cfg.memory_limit = memory_limit;
96 cfg.limit_contract_code_size = Some(usize::MAX);
97 cfg.disable_eip3607 = true;
101 cfg.disable_block_gas_limit = disable_block_gas_limit;
102 cfg.disable_nonce_check = true;
103 if !enable_tx_gas_limit {
106 cfg.tx_gas_limit_cap = Some(u64::MAX);
107 }
108 cfg
109}