reth_ethereum_forks/hardforks/
mod.rs1mod ethereum;
3pub use ethereum::EthereumHardforks;
4
5use crate::{ForkCondition, ForkFilter, ForkId, Hardfork, Head};
6#[cfg(feature = "std")]
7use rustc_hash::FxHashMap;
8#[cfg(feature = "std")]
9use std::collections::hash_map::Entry;
10
11#[cfg(not(feature = "std"))]
12use alloc::collections::btree_map::Entry;
13use alloc::{boxed::Box, vec::Vec};
14
15#[auto_impl::auto_impl(&, Arc)]
17pub trait Hardforks: Clone {
18 fn fork<H: Hardfork>(&self, fork: H) -> ForkCondition;
21
22 fn forks_iter(&self) -> impl Iterator<Item = (&dyn Hardfork, ForkCondition)>;
24
25 fn is_fork_active_at_timestamp<H: Hardfork>(&self, fork: H, timestamp: u64) -> bool {
27 self.fork(fork).active_at_timestamp(timestamp)
28 }
29
30 fn is_fork_active_at_block<H: Hardfork>(&self, fork: H, block_number: u64) -> bool {
32 self.fork(fork).active_at_block(block_number)
33 }
34
35 fn fork_id(&self, head: &Head) -> ForkId;
37
38 fn latest_fork_id(&self) -> ForkId;
40
41 fn fork_filter(&self, head: Head) -> ForkFilter;
43}
44
45#[derive(Default, Clone, PartialEq, Eq)]
47pub struct ChainHardforks {
48 forks: Vec<(Box<dyn Hardfork>, ForkCondition)>,
49 #[cfg(feature = "std")]
50 map: FxHashMap<&'static str, ForkCondition>,
51 #[cfg(not(feature = "std"))]
52 map: alloc::collections::BTreeMap<&'static str, ForkCondition>,
53}
54
55impl ChainHardforks {
56 pub fn new(forks: Vec<(Box<dyn Hardfork>, ForkCondition)>) -> Self {
60 let map = forks.iter().map(|(fork, condition)| (fork.name(), *condition)).collect();
61
62 Self { forks, map }
63 }
64
65 pub fn len(&self) -> usize {
67 self.forks.len()
68 }
69
70 pub fn is_empty(&self) -> bool {
72 self.forks.is_empty()
73 }
74
75 pub fn fork<H: Hardfork>(&self, fork: H) -> ForkCondition {
78 self.get(fork).unwrap_or_default()
79 }
80
81 pub fn get<H: Hardfork>(&self, fork: H) -> Option<ForkCondition> {
83 self.map.get(fork.name()).copied()
84 }
85
86 pub fn fork_block<H: Hardfork>(&self, fork: H) -> Option<u64> {
88 match self.fork(fork) {
89 ForkCondition::Block(block) => Some(block),
90 ForkCondition::TTD { fork_block, .. } => fork_block,
91 ForkCondition::Timestamp(ts) => Some(ts),
92 ForkCondition::Never => None,
93 }
94 }
95
96 pub fn forks_iter(&self) -> impl Iterator<Item = (&dyn Hardfork, ForkCondition)> {
98 self.forks.iter().map(|(f, b)| (&**f, *b))
99 }
100
101 pub fn last(&self) -> Option<(Box<dyn Hardfork>, ForkCondition)> {
103 self.forks.last().map(|(f, b)| (f.clone(), *b))
104 }
105
106 pub fn is_fork_active_at_timestamp<H: Hardfork>(&self, fork: H, timestamp: u64) -> bool {
108 self.fork(fork).active_at_timestamp(timestamp)
109 }
110
111 pub fn is_fork_active_at_block<H: Hardfork>(&self, fork: H, block_number: u64) -> bool {
113 self.fork(fork).active_at_block(block_number)
114 }
115
116 pub fn insert<H: Hardfork>(&mut self, fork: H, condition: ForkCondition) {
118 match self.map.entry(fork.name()) {
119 Entry::Occupied(mut entry) => {
120 *entry.get_mut() = condition;
121 if let Some((_, inner)) =
122 self.forks.iter_mut().find(|(inner, _)| inner.name() == fork.name())
123 {
124 *inner = condition;
125 }
126 }
127 Entry::Vacant(entry) => {
128 entry.insert(condition);
129 self.forks.push((Box::new(fork), condition));
130 }
131 }
132 }
133
134 pub fn remove<H: Hardfork>(&mut self, fork: H) {
136 self.forks.retain(|(inner_fork, _)| inner_fork.name() != fork.name());
137 self.map.remove(fork.name());
138 }
139}
140
141impl core::fmt::Debug for ChainHardforks {
142 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
143 f.debug_struct("ChainHardforks")
144 .field("0", &self.forks_iter().map(|(hf, cond)| (hf.name(), cond)).collect::<Vec<_>>())
145 .finish()
146 }
147}