1
1
//! The [`HardFork`] type.
2
2
use std:: time:: Duration ;
3
3
4
+ use strum:: {
5
+ AsRefStr , Display , EnumCount , EnumIs , EnumString , FromRepr , IntoStaticStr , VariantArray ,
6
+ } ;
7
+
4
8
use monero_serai:: block:: BlockHeader ;
5
9
6
10
/// Target block time for hf 1.
@@ -27,7 +31,25 @@ pub enum HardForkError {
27
31
}
28
32
29
33
/// An identifier for every hard-fork Monero has had.
30
- #[ derive( Default , Debug , PartialEq , Eq , PartialOrd , Ord , Copy , Clone , Hash ) ]
34
+ #[ derive(
35
+ Default ,
36
+ Debug ,
37
+ PartialEq ,
38
+ Eq ,
39
+ PartialOrd ,
40
+ Ord ,
41
+ Copy ,
42
+ Clone ,
43
+ Hash ,
44
+ EnumCount ,
45
+ Display ,
46
+ AsRefStr ,
47
+ EnumIs ,
48
+ EnumString ,
49
+ FromRepr ,
50
+ IntoStaticStr ,
51
+ VariantArray ,
52
+ ) ]
31
53
#[ cfg_attr( any( feature = "proptest" ) , derive( proptest_derive:: Arbitrary ) ) ]
32
54
#[ repr( u8 ) ]
33
55
pub enum HardFork {
@@ -47,58 +69,75 @@ pub enum HardFork {
47
69
V13 ,
48
70
V14 ,
49
71
V15 ,
50
- // remember to update from_vote!
51
72
V16 ,
52
73
}
53
74
54
75
impl HardFork {
76
+ /// The latest [`HardFork`].
77
+ ///
78
+ /// ```rust
79
+ /// # use cuprate_types::HardFork;
80
+ /// assert_eq!(HardFork::LATEST, HardFork::V16);
81
+ /// ```
82
+ pub const LATEST : Self = Self :: VARIANTS [ Self :: COUNT - 1 ] ;
83
+
55
84
/// Returns the hard-fork for a blocks [`BlockHeader::hardfork_version`] field.
56
85
///
57
86
/// ref: <https://monero-book.cuprate.org/consensus_rules/hardforks.html#blocks-version-and-vote>
58
87
///
59
88
/// # Errors
60
- ///
61
89
/// Will return [`Err`] if the version is not a valid [`HardFork`].
90
+ ///
91
+ /// ```rust
92
+ /// # use cuprate_types::{HardFork, HardForkError};
93
+ /// # use strum::VariantArray;
94
+ /// assert_eq!(HardFork::from_version(0), Err(HardForkError::HardForkUnknown));
95
+ /// assert_eq!(HardFork::from_version(17), Err(HardForkError::HardForkUnknown));
96
+ ///
97
+ /// for (version, hf) in HardFork::VARIANTS.iter().enumerate() {
98
+ /// // +1 because enumerate starts at 0, hf starts at 1.
99
+ /// assert_eq!(*hf, HardFork::from_version(version as u8 + 1).unwrap());
100
+ /// }
101
+ /// ```
62
102
#[ inline]
63
103
pub const fn from_version ( version : u8 ) -> Result < Self , HardForkError > {
64
- Ok ( match version {
65
- 1 => Self :: V1 ,
66
- 2 => Self :: V2 ,
67
- 3 => Self :: V3 ,
68
- 4 => Self :: V4 ,
69
- 5 => Self :: V5 ,
70
- 6 => Self :: V6 ,
71
- 7 => Self :: V7 ,
72
- 8 => Self :: V8 ,
73
- 9 => Self :: V9 ,
74
- 10 => Self :: V10 ,
75
- 11 => Self :: V11 ,
76
- 12 => Self :: V12 ,
77
- 13 => Self :: V13 ,
78
- 14 => Self :: V14 ,
79
- 15 => Self :: V15 ,
80
- 16 => Self :: V16 ,
81
- _ => return Err ( HardForkError :: HardForkUnknown ) ,
82
- } )
104
+ match Self :: from_repr ( version) {
105
+ Some ( this) => Ok ( this) ,
106
+ None => Err ( HardForkError :: HardForkUnknown ) ,
107
+ }
83
108
}
84
109
85
110
/// Returns the hard-fork for a blocks [`BlockHeader::hardfork_signal`] (vote) field.
86
111
///
87
112
/// <https://monero-book.cuprate.org/consensus_rules/hardforks.html#blocks-version-and-vote>
113
+ ///
114
+ /// ```rust
115
+ /// # use cuprate_types::{HardFork, HardForkError};
116
+ /// # use strum::VariantArray;
117
+ /// // 0 is interpreted as 1.
118
+ /// assert_eq!(HardFork::from_vote(0), HardFork::V1);
119
+ /// // Unknown defaults to `LATEST`.
120
+ /// assert_eq!(HardFork::from_vote(17), HardFork::V16);
121
+ ///
122
+ /// for (vote, hf) in HardFork::VARIANTS.iter().enumerate() {
123
+ /// // +1 because enumerate starts at 0, hf starts at 1.
124
+ /// assert_eq!(*hf, HardFork::from_vote(vote as u8 + 1));
125
+ /// }
126
+ /// ```
88
127
#[ inline]
89
128
pub fn from_vote ( vote : u8 ) -> Self {
90
129
if vote == 0 {
91
130
// A vote of 0 is interpreted as 1 as that's what Monero used to default to.
92
- return Self :: V1 ;
131
+ Self :: V1
132
+ } else {
133
+ // This must default to the latest hard-fork!
134
+ Self :: from_version ( vote) . unwrap_or ( Self :: LATEST )
93
135
}
94
- // This must default to the latest hard-fork!
95
- Self :: from_version ( vote) . unwrap_or ( Self :: V16 )
96
136
}
97
137
98
138
/// Returns the [`HardFork`] version and vote from this block header.
99
139
///
100
140
/// # Errors
101
- ///
102
141
/// Will return [`Err`] if the [`BlockHeader::hardfork_version`] is not a valid [`HardFork`].
103
142
#[ inline]
104
143
pub fn from_block_header ( header : & BlockHeader ) -> Result < ( Self , Self ) , HardForkError > {
@@ -109,22 +148,49 @@ impl HardFork {
109
148
}
110
149
111
150
/// Returns the raw hard-fork value, as it would appear in [`BlockHeader::hardfork_version`].
112
- pub const fn as_u8 ( & self ) -> u8 {
113
- * self as u8
151
+ ///
152
+ /// ```rust
153
+ /// # use cuprate_types::{HardFork, HardForkError};
154
+ /// # use strum::VariantArray;
155
+ /// for (i, hf) in HardFork::VARIANTS.iter().enumerate() {
156
+ /// // +1 because enumerate starts at 0, hf starts at 1.
157
+ /// assert_eq!(hf.as_u8(), i as u8 + 1);
158
+ /// }
159
+ /// ```
160
+ pub const fn as_u8 ( self ) -> u8 {
161
+ self as u8
114
162
}
115
163
116
164
/// Returns the next hard-fork.
117
- pub fn next_fork ( & self ) -> Option < Self > {
118
- Self :: from_version ( * self as u8 + 1 ) . ok ( )
165
+ pub fn next_fork ( self ) -> Option < Self > {
166
+ Self :: from_version ( self as u8 + 1 ) . ok ( )
119
167
}
120
168
121
169
/// Returns the target block time for this hardfork.
122
170
///
123
171
/// ref: <https://monero-book.cuprate.org/consensus_rules/blocks/difficulty.html#target-seconds>
124
- pub const fn block_time ( & self ) -> Duration {
172
+ pub const fn block_time ( self ) -> Duration {
125
173
match self {
126
174
Self :: V1 => BLOCK_TIME_V1 ,
127
175
_ => BLOCK_TIME_V2 ,
128
176
}
129
177
}
178
+
179
+ /// Returns `true` if `self` is [`Self::LATEST`].
180
+ ///
181
+ /// ```rust
182
+ /// # use cuprate_types::HardFork;
183
+ /// # use strum::VariantArray;
184
+ ///
185
+ /// for hf in HardFork::VARIANTS.iter() {
186
+ /// if *hf == HardFork::LATEST {
187
+ /// assert!(hf.is_latest());
188
+ /// } else {
189
+ /// assert!(!hf.is_latest());
190
+ /// }
191
+ /// }
192
+ /// ```
193
+ pub const fn is_latest ( self ) -> bool {
194
+ matches ! ( self , Self :: LATEST )
195
+ }
130
196
}
0 commit comments