alloy_hardforks/
forkcondition.rs1use alloy_primitives::{BlockNumber, U256};
2
3#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6pub enum ForkCondition {
7 Block(BlockNumber),
9 TTD {
11 activation_block_number: BlockNumber,
17 fork_block: Option<BlockNumber>,
24 total_difficulty: U256,
26 },
27 Timestamp(u64),
29 #[default]
31 Never,
32}
33
34impl ForkCondition {
35 pub const ZERO_BLOCK: Self = Self::Block(0);
37
38 pub const ZERO_TIMESTAMP: Self = Self::Timestamp(0);
40
41 pub const fn is_timestamp(&self) -> bool {
43 matches!(self, Self::Timestamp(_))
44 }
45
46 pub const fn active_at_block(&self, current_block: BlockNumber) -> bool {
54 matches!(self, Self::Block(block)
55 | Self::TTD { activation_block_number: block, .. } if current_block >= *block)
56 }
57
58 pub const fn transitions_at_block(&self, current_block: BlockNumber) -> bool {
62 matches!(self, Self::Block(block) if current_block == *block)
63 }
64
65 pub fn active_at_ttd(&self, ttd: U256, difficulty: U256) -> bool {
75 matches!(self, Self::TTD { total_difficulty, .. }
76 if ttd.saturating_sub(difficulty) >= *total_difficulty)
77 }
78
79 pub const fn active_at_timestamp(&self, timestamp: u64) -> bool {
83 matches!(self, Self::Timestamp(time) if timestamp >= *time)
84 }
85
86 pub const fn transitions_at_timestamp(&self, timestamp: u64, parent_timestamp: u64) -> bool {
90 matches!(self, Self::Timestamp(time) if timestamp >= *time && parent_timestamp < *time)
91 }
92
93 pub const fn active_at_timestamp_or_number(&self, timestamp: u64, block_number: u64) -> bool {
95 self.active_at_timestamp(timestamp) || self.active_at_block(block_number)
96 }
97
98 pub const fn ttd(&self) -> Option<U256> {
102 match self {
103 Self::TTD { total_difficulty, .. } => Some(*total_difficulty),
104 _ => None,
105 }
106 }
107
108 pub const fn as_timestamp(&self) -> Option<u64> {
110 match self {
111 Self::Timestamp(timestamp) => Some(*timestamp),
112 _ => None,
113 }
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120 use alloy_primitives::U256;
121
122 #[test]
123 fn test_active_at_block() {
124 let fork_condition = ForkCondition::Block(10);
126 assert!(fork_condition.active_at_block(10), "The condition should be active at block 10");
127
128 assert!(
130 !fork_condition.active_at_block(9),
131 "The condition should not be active at block 9"
132 );
133
134 let fork_condition = ForkCondition::TTD {
136 activation_block_number: 10,
137 fork_block: Some(10),
138 total_difficulty: U256::from(1000),
139 };
140 assert!(
141 fork_condition.active_at_block(10),
142 "The TTD condition should be active at block 10"
143 );
144 }
145
146 #[test]
147 fn test_transitions_at_block() {
148 let fork_condition = ForkCondition::Block(10);
150 assert!(
151 fork_condition.transitions_at_block(10),
152 "The condition should transition at block 10"
153 );
154
155 assert!(
157 !fork_condition.transitions_at_block(9),
158 "The condition should not transition at a different block number"
159 );
160 assert!(
161 !fork_condition.transitions_at_block(11),
162 "The condition should not transition at a different block number"
163 );
164 }
165
166 #[test]
167 fn test_active_at_ttd() {
168 let fork_condition = ForkCondition::TTD {
170 activation_block_number: 10,
171 fork_block: Some(10),
172 total_difficulty: U256::from(1000),
173 };
174 assert!(
175 fork_condition.active_at_ttd(U256::from(1000000), U256::from(100)),
176 "The TTD condition should be active when the total difficulty matches"
177 );
178
179 assert!(
181 !fork_condition.active_at_ttd(U256::from(900), U256::from(100)),
182 "The TTD condition should not be active when the total difficulty is lower"
183 );
184
185 assert!(
187 !fork_condition.active_at_ttd(U256::from(900), U256::from(1000)),
188 "The TTD condition should not be active when the subtraction saturates"
189 );
190 }
191
192 #[test]
193 fn test_active_at_timestamp() {
194 let fork_condition = ForkCondition::Timestamp(12345);
196 assert!(
197 fork_condition.active_at_timestamp(12345),
198 "The condition should be active at timestamp 12345"
199 );
200
201 assert!(
203 !fork_condition.active_at_timestamp(12344),
204 "The condition should not be active at an earlier timestamp"
205 );
206 }
207
208 #[test]
209 fn test_transitions_at_timestamp() {
210 let fork_condition = ForkCondition::Timestamp(12345);
212 assert!(
213 fork_condition.transitions_at_timestamp(12345, 12344),
214 "The condition should transition at timestamp 12345"
215 );
216
217 assert!(
219 !fork_condition.transitions_at_timestamp(12345, 12345),
220 "The condition should not transition if the parent timestamp is already 12345"
221 );
222 assert!(
224 !fork_condition.transitions_at_timestamp(123, 122),
225 "The condition should not transition if the parent timestamp is earlier"
226 );
227 }
228}