reth_evm_ethereum/
config.rs

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