foundry_evm_core/
utils.rs1use crate::{EvmEnv, FoundryBlock};
2use alloy_chains::Chain;
3use alloy_consensus::{BlockHeader, private::alloy_eips::eip7840::BlobParams};
4use alloy_hardforks::EthereumHardfork;
5use alloy_json_abi::{Function, JsonAbi};
6use alloy_primitives::{B256, ChainId, Selector, U256};
7use alloy_provider::{Network, network::BlockResponse};
8use foundry_config::NamedChain;
9use foundry_evm_networks::NetworkConfigs;
10use revm::primitives::hardfork::SpecId;
11pub use revm::state::EvmState as StateChangeset;
12
13#[cold]
15#[inline(always)]
16pub const fn cold_path() {
17 }
19
20pub fn block_env_from_header<BLOCK: FoundryBlock + Default>(header: &impl BlockHeader) -> BLOCK {
22 let mut block = BLOCK::default();
23 block.set_number(U256::from(header.number()));
24 block.set_beneficiary(header.beneficiary());
25 block.set_timestamp(U256::from(header.timestamp()));
26 block.set_difficulty(header.difficulty());
27 block.set_prevrandao(header.mix_hash());
28 block.set_basefee(header.base_fee_per_gas().unwrap_or_default());
29 block.set_gas_limit(header.gas_limit());
30 block
31}
32
33pub fn apply_chain_and_block_specific_env_changes<
41 N: Network,
42 SPEC: Into<SpecId> + Copy,
43 BLOCK: FoundryBlock,
44>(
45 evm_env: &mut EvmEnv<SPEC, BLOCK>,
46 block: &N::BlockResponse,
47 configs: NetworkConfigs,
48) {
49 use NamedChain::{BinanceSmartChain, BinanceSmartChainTestnet, Mainnet};
50
51 if let Ok(chain) = NamedChain::try_from(evm_env.cfg_env.chain_id) {
52 let block_number = block.header().number();
53
54 match chain {
55 Mainnet => {
56 if block_number >= 15_537_351u64 {
58 evm_env
59 .block_env
60 .set_difficulty(evm_env.block_env.prevrandao().unwrap_or_default().into());
61 }
62
63 return;
64 }
65 BinanceSmartChain | BinanceSmartChainTestnet => {
66 evm_env.block_env.set_prevrandao(Some(evm_env.block_env.difficulty().into()));
73 return;
74 }
75 c if c.is_arbitrum() => {
76 if let Some(l1_block_number) = block
79 .other_fields()
80 .and_then(|other| other.get("l1BlockNumber").cloned())
81 .and_then(|l1_block_number| {
82 serde_json::from_value::<U256>(l1_block_number).ok()
83 })
84 {
85 evm_env.block_env.set_number(l1_block_number);
86 }
87 }
88 _ => {}
89 }
90 }
91
92 if configs.bypass_prevrandao(evm_env.cfg_env.chain_id)
93 && evm_env.block_env.prevrandao().is_none()
94 {
95 evm_env.block_env.set_prevrandao(Some(B256::random()));
97 }
98
99 if block.header().difficulty().is_zero() {
101 evm_env.block_env.set_difficulty(evm_env.block_env.prevrandao().unwrap_or_default().into());
102 }
103}
104
105pub fn get_blob_params(chain_id: ChainId, timestamp: u64) -> BlobParams {
110 let hardfork = EthereumHardfork::from_chain_and_timestamp(Chain::from_id(chain_id), timestamp)
111 .unwrap_or_default();
112
113 match hardfork {
114 EthereumHardfork::Prague => BlobParams::prague(),
115 EthereumHardfork::Osaka => BlobParams::osaka(),
116 EthereumHardfork::Bpo1 => BlobParams::bpo1(),
117 EthereumHardfork::Bpo2 => BlobParams::bpo2(),
118
119 EthereumHardfork::Bpo3 => BlobParams::bpo2(),
121 EthereumHardfork::Bpo4 => BlobParams::bpo2(),
122 EthereumHardfork::Bpo5 => BlobParams::bpo2(),
123 EthereumHardfork::Amsterdam => BlobParams::bpo2(),
124
125 _ => BlobParams::cancun(),
127 }
128}
129
130pub fn get_blob_base_fee_update_fraction(chain_id: ChainId, timestamp: u64) -> u64 {
133 get_blob_params(chain_id, timestamp).update_fraction as u64
134}
135
136pub fn get_blob_params_by_spec_id(spec: SpecId) -> BlobParams {
138 if spec >= SpecId::AMSTERDAM {
139 BlobParams::bpo2()
140 } else if spec >= SpecId::OSAKA {
141 BlobParams::osaka()
142 } else if spec >= SpecId::PRAGUE {
143 BlobParams::prague()
144 } else {
145 BlobParams::cancun()
146 }
147}
148
149pub fn get_blob_base_fee_update_fraction_by_spec_id(spec: SpecId) -> u64 {
151 get_blob_params_by_spec_id(spec).update_fraction as u64
152}
153
154pub fn get_function<'a>(
156 contract_name: &str,
157 selector: Selector,
158 abi: &'a JsonAbi,
159) -> eyre::Result<&'a Function> {
160 abi.functions()
161 .find(|func| func.selector() == selector)
162 .ok_or_else(|| eyre::eyre!("{contract_name} does not have the selector {selector}"))
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn blob_params_by_spec_id_tracks_latest_known_blob_schedule() {
171 assert_eq!(get_blob_params_by_spec_id(SpecId::CANCUN), BlobParams::cancun());
172 assert_eq!(get_blob_params_by_spec_id(SpecId::PRAGUE), BlobParams::prague());
173 assert_eq!(get_blob_params_by_spec_id(SpecId::OSAKA), BlobParams::osaka());
174 assert_eq!(get_blob_params_by_spec_id(SpecId::AMSTERDAM), BlobParams::bpo2());
175 assert_eq!(
176 get_blob_base_fee_update_fraction_by_spec_id(SpecId::AMSTERDAM),
177 BlobParams::bpo2().update_fraction as u64
178 );
179 }
180}