reth_evm_ethereum/
config.rs

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