foundry_evm_core/fork/
init.rs
1use crate::{utils::apply_chain_and_block_specific_env_changes, AsEnvMut, Env, EvmEnv};
2use alloy_consensus::BlockHeader;
3use alloy_primitives::Address;
4use alloy_provider::{network::BlockResponse, Network, Provider};
5use alloy_rpc_types::BlockNumberOrTag;
6use eyre::WrapErr;
7use foundry_common::NON_ARCHIVE_NODE_WARNING;
8use revm::context::{BlockEnv, CfgEnv, TxEnv};
9
10pub async fn environment<N: Network, P: Provider<N>>(
13 provider: &P,
14 memory_limit: u64,
15 gas_price: Option<u128>,
16 override_chain_id: Option<u64>,
17 pin_block: Option<u64>,
18 origin: Address,
19 disable_block_gas_limit: bool,
20) -> eyre::Result<(Env, N::BlockResponse)> {
21 let block_number = if let Some(pin_block) = pin_block {
22 pin_block
23 } else {
24 provider.get_block_number().await.wrap_err("failed to get latest block number")?
25 };
26 let (fork_gas_price, rpc_chain_id, block) = tokio::try_join!(
27 provider.get_gas_price(),
28 provider.get_chain_id(),
29 provider.get_block_by_number(BlockNumberOrTag::Number(block_number))
30 )?;
31 let block = if let Some(block) = block {
32 block
33 } else {
34 if let Ok(latest_block) = provider.get_block_number().await {
35 if block_number <= latest_block {
39 error!("{NON_ARCHIVE_NODE_WARNING}");
40 }
41 eyre::bail!(
42 "failed to get block for block number: {block_number}; \
43 latest block number: {latest_block}"
44 );
45 }
46 eyre::bail!("failed to get block for block number: {block_number}")
47 };
48
49 let cfg = configure_env(
50 override_chain_id.unwrap_or(rpc_chain_id),
51 memory_limit,
52 disable_block_gas_limit,
53 );
54
55 let mut env = Env {
56 evm_env: EvmEnv {
57 cfg_env: cfg,
58 block_env: BlockEnv {
59 number: block.header().number(),
60 timestamp: block.header().timestamp(),
61 beneficiary: block.header().beneficiary(),
62 difficulty: block.header().difficulty(),
63 prevrandao: block.header().mix_hash(),
64 basefee: block.header().base_fee_per_gas().unwrap_or_default(),
65 gas_limit: block.header().gas_limit(),
66 ..Default::default()
67 },
68 },
69 tx: TxEnv {
70 caller: origin,
71 gas_price: gas_price.unwrap_or(fork_gas_price),
72 chain_id: Some(override_chain_id.unwrap_or(rpc_chain_id)),
73 gas_limit: block.header().gas_limit() as u64,
74 ..Default::default()
75 },
76 };
77
78 apply_chain_and_block_specific_env_changes::<N>(env.as_env_mut(), &block);
79
80 Ok((env, block))
81}
82
83pub fn configure_env(chain_id: u64, memory_limit: u64, disable_block_gas_limit: bool) -> CfgEnv {
85 let mut cfg = CfgEnv::default();
86 cfg.chain_id = chain_id;
87 cfg.memory_limit = memory_limit;
88 cfg.limit_contract_code_size = Some(usize::MAX);
89 cfg.disable_eip3607 = true;
93 cfg.disable_block_gas_limit = disable_block_gas_limit;
94 cfg.disable_nonce_check = true;
95 cfg
96}