1use alloy_consensus::Header;
2use reth_chainspec::{ChainSpec, EthereumHardforks};
3use reth_ethereum_forks::EthereumHardfork;
4use revm::primitives::hardfork::SpecId;
5
6pub 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
11pub 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}