reth_evm_ethereum/
config.rs

1use reth_chainspec::{EthChainSpec, EthereumHardforks};
2use reth_ethereum_forks::{EthereumHardfork, Hardforks};
3use reth_primitives_traits::BlockHeader;
4use revm::primitives::hardfork::SpecId;
5
6/// Map the latest active hardfork at the given header to a revm [`SpecId`].
7pub fn revm_spec<C, H>(chain_spec: &C, header: &H) -> SpecId
8where
9    C: EthereumHardforks + EthChainSpec + Hardforks,
10    H: BlockHeader,
11{
12    revm_spec_by_timestamp_and_block_number(chain_spec, header.timestamp(), header.number())
13}
14
15/// Map the latest active hardfork at the given timestamp or block number to a revm [`SpecId`].
16pub fn revm_spec_by_timestamp_and_block_number<C>(
17    chain_spec: &C,
18    timestamp: u64,
19    block_number: u64,
20) -> SpecId
21where
22    C: EthereumHardforks + EthChainSpec + Hardforks,
23{
24    if chain_spec
25        .fork(EthereumHardfork::Osaka)
26        .active_at_timestamp_or_number(timestamp, block_number)
27    {
28        SpecId::OSAKA
29    } else if chain_spec
30        .fork(EthereumHardfork::Prague)
31        .active_at_timestamp_or_number(timestamp, block_number)
32    {
33        SpecId::PRAGUE
34    } else if chain_spec
35        .fork(EthereumHardfork::Cancun)
36        .active_at_timestamp_or_number(timestamp, block_number)
37    {
38        SpecId::CANCUN
39    } else if chain_spec
40        .fork(EthereumHardfork::Shanghai)
41        .active_at_timestamp_or_number(timestamp, block_number)
42    {
43        SpecId::SHANGHAI
44    } else if chain_spec.is_paris_active_at_block(block_number) {
45        SpecId::MERGE
46    } else if chain_spec
47        .fork(EthereumHardfork::London)
48        .active_at_timestamp_or_number(timestamp, block_number)
49    {
50        SpecId::LONDON
51    } else if chain_spec
52        .fork(EthereumHardfork::Berlin)
53        .active_at_timestamp_or_number(timestamp, block_number)
54    {
55        SpecId::BERLIN
56    } else if chain_spec
57        .fork(EthereumHardfork::Istanbul)
58        .active_at_timestamp_or_number(timestamp, block_number)
59    {
60        SpecId::ISTANBUL
61    } else if chain_spec
62        .fork(EthereumHardfork::Petersburg)
63        .active_at_timestamp_or_number(timestamp, block_number)
64    {
65        SpecId::PETERSBURG
66    } else if chain_spec
67        .fork(EthereumHardfork::Byzantium)
68        .active_at_timestamp_or_number(timestamp, block_number)
69    {
70        SpecId::BYZANTIUM
71    } else if chain_spec
72        .fork(EthereumHardfork::SpuriousDragon)
73        .active_at_timestamp_or_number(timestamp, block_number)
74    {
75        SpecId::SPURIOUS_DRAGON
76    } else if chain_spec
77        .fork(EthereumHardfork::Tangerine)
78        .active_at_timestamp_or_number(timestamp, block_number)
79    {
80        SpecId::TANGERINE
81    } else if chain_spec
82        .fork(EthereumHardfork::Homestead)
83        .active_at_timestamp_or_number(timestamp, block_number)
84    {
85        SpecId::HOMESTEAD
86    } else if chain_spec
87        .fork(EthereumHardfork::Frontier)
88        .active_at_timestamp_or_number(timestamp, block_number)
89    {
90        SpecId::FRONTIER
91    } else {
92        panic!(
93            "invalid hardfork chainspec: expected at least one hardfork, got {}",
94            chain_spec.display_hardforks()
95        )
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102    use crate::U256;
103    use alloy_consensus::Header;
104    use reth_chainspec::{ChainSpecBuilder, MAINNET};
105
106    #[test]
107    fn test_revm_spec_by_timestamp() {
108        assert_eq!(
109            revm_spec_by_timestamp_and_block_number(
110                &ChainSpecBuilder::mainnet().cancun_activated().build(),
111                0,
112                0
113            ),
114            SpecId::CANCUN
115        );
116        assert_eq!(
117            revm_spec_by_timestamp_and_block_number(
118                &ChainSpecBuilder::mainnet().shanghai_activated().build(),
119                0,
120                0
121            ),
122            SpecId::SHANGHAI
123        );
124        let mainnet = ChainSpecBuilder::mainnet().build();
125        assert_eq!(
126            revm_spec_by_timestamp_and_block_number(&mainnet, 0, mainnet.paris_block().unwrap()),
127            SpecId::MERGE
128        );
129    }
130
131    #[test]
132    fn test_to_revm_spec() {
133        assert_eq!(
134            revm_spec(&ChainSpecBuilder::mainnet().cancun_activated().build(), &Header::default()),
135            SpecId::CANCUN
136        );
137        assert_eq!(
138            revm_spec(
139                &ChainSpecBuilder::mainnet().shanghai_activated().build(),
140                &Header::default()
141            ),
142            SpecId::SHANGHAI
143        );
144        assert_eq!(
145            revm_spec(&ChainSpecBuilder::mainnet().paris_activated().build(), &Header::default()),
146            SpecId::MERGE
147        );
148        assert_eq!(
149            revm_spec(&ChainSpecBuilder::mainnet().london_activated().build(), &Header::default()),
150            SpecId::LONDON
151        );
152        assert_eq!(
153            revm_spec(&ChainSpecBuilder::mainnet().berlin_activated().build(), &Header::default()),
154            SpecId::BERLIN
155        );
156        assert_eq!(
157            revm_spec(
158                &ChainSpecBuilder::mainnet().istanbul_activated().build(),
159                &Header::default()
160            ),
161            SpecId::ISTANBUL
162        );
163        assert_eq!(
164            revm_spec(
165                &ChainSpecBuilder::mainnet().petersburg_activated().build(),
166                &Header::default()
167            ),
168            SpecId::PETERSBURG
169        );
170        assert_eq!(
171            revm_spec(
172                &ChainSpecBuilder::mainnet().byzantium_activated().build(),
173                &Header::default()
174            ),
175            SpecId::BYZANTIUM
176        );
177        assert_eq!(
178            revm_spec(
179                &ChainSpecBuilder::mainnet().spurious_dragon_activated().build(),
180                &Header::default()
181            ),
182            SpecId::SPURIOUS_DRAGON
183        );
184        assert_eq!(
185            revm_spec(
186                &ChainSpecBuilder::mainnet().tangerine_whistle_activated().build(),
187                &Header::default()
188            ),
189            SpecId::TANGERINE
190        );
191        assert_eq!(
192            revm_spec(
193                &ChainSpecBuilder::mainnet().homestead_activated().build(),
194                &Header::default()
195            ),
196            SpecId::HOMESTEAD
197        );
198        assert_eq!(
199            revm_spec(
200                &ChainSpecBuilder::mainnet().frontier_activated().build(),
201                &Header::default()
202            ),
203            SpecId::FRONTIER
204        );
205    }
206
207    #[test]
208    fn test_eth_spec() {
209        assert_eq!(
210            revm_spec(&*MAINNET, &Header { timestamp: 1710338135, ..Default::default() }),
211            SpecId::CANCUN
212        );
213        assert_eq!(
214            revm_spec(&*MAINNET, &Header { timestamp: 1681338455, ..Default::default() }),
215            SpecId::SHANGHAI
216        );
217
218        assert_eq!(
219            revm_spec(
220                &*MAINNET,
221                &Header { difficulty: U256::from(10_u128), number: 15537394, ..Default::default() }
222            ),
223            SpecId::MERGE
224        );
225        assert_eq!(
226            revm_spec(&*MAINNET, &Header { number: 15537394 - 10, ..Default::default() }),
227            SpecId::LONDON
228        );
229        assert_eq!(
230            revm_spec(&*MAINNET, &Header { number: 12244000 + 10, ..Default::default() }),
231            SpecId::BERLIN
232        );
233        assert_eq!(
234            revm_spec(&*MAINNET, &Header { number: 12244000 - 10, ..Default::default() }),
235            SpecId::ISTANBUL
236        );
237        assert_eq!(
238            revm_spec(&*MAINNET, &Header { number: 7280000 + 10, ..Default::default() }),
239            SpecId::PETERSBURG
240        );
241        assert_eq!(
242            revm_spec(&*MAINNET, &Header { number: 7280000 - 10, ..Default::default() }),
243            SpecId::BYZANTIUM
244        );
245        assert_eq!(
246            revm_spec(&*MAINNET, &Header { number: 2675000 + 10, ..Default::default() }),
247            SpecId::SPURIOUS_DRAGON
248        );
249        assert_eq!(
250            revm_spec(&*MAINNET, &Header { number: 2675000 - 10, ..Default::default() }),
251            SpecId::TANGERINE
252        );
253        assert_eq!(
254            revm_spec(&*MAINNET, &Header { number: 1150000 + 10, ..Default::default() }),
255            SpecId::HOMESTEAD
256        );
257        assert_eq!(
258            revm_spec(&*MAINNET, &Header { number: 1150000 - 10, ..Default::default() }),
259            SpecId::FRONTIER
260        );
261    }
262}