1use std::{
7 collections::VecDeque,
8 fmt::{Display, Formatter},
9};
10
11pub use cuprate_types::{HardFork, HardForkError};
12
13#[cfg(test)]
14mod tests;
15
16pub const NUMB_OF_HARD_FORKS: usize = 16;
17
18pub fn check_block_version_vote(
22 hf: &HardFork,
23 version: &HardFork,
24 vote: &HardFork,
25) -> Result<(), HardForkError> {
26 if hf != version {
28 return Err(HardForkError::VersionIncorrect);
29 }
30 if hf > vote {
31 return Err(HardForkError::VoteTooLow);
32 }
33
34 Ok(())
35}
36
37const FORKED_TIME: u64 = 31_557_600; const UPDATE_TIME: u64 = FORKED_TIME / 2;
48
49#[derive(Debug, Clone, Copy, Eq, PartialEq)]
53#[repr(u32)]
54pub enum HardForkState {
55 LikelyForked = 0,
56 UpdateNeeded = 1,
57 Ready = 2,
58}
59
60impl From<HardForkState> for u32 {
61 fn from(state: HardForkState) -> Self {
62 state as Self
63 }
64}
65
66#[derive(Debug, Clone, Copy, Eq, PartialEq)]
68pub struct HFInfo {
69 height: usize,
70 threshold: usize,
71 time: u64,
72}
73impl HFInfo {
74 pub const fn height(&self) -> usize {
75 self.height
76 }
77
78 pub const fn threshold(&self) -> usize {
79 self.threshold
80 }
81
82 pub const fn time(&self) -> u64 {
83 self.time
84 }
85
86 pub const fn new(height: usize, threshold: usize, time: u64) -> Self {
87 Self {
88 height,
89 threshold,
90 time,
91 }
92 }
93}
94
95#[derive(Debug, Clone, Copy, Eq, PartialEq)]
97pub struct HFsInfo([HFInfo; NUMB_OF_HARD_FORKS]);
98
99impl HFsInfo {
100 pub const fn info_for_hf(&self, hf: &HardFork) -> HFInfo {
101 self.0[*hf as usize - 1]
102 }
103
104 pub const fn new(hfs: [HFInfo; NUMB_OF_HARD_FORKS]) -> Self {
105 Self(hfs)
106 }
107
108 pub const fn hard_fork_state(&self, current_time: u64) -> HardForkState {
117 let last_fork_time = self.0[NUMB_OF_HARD_FORKS - 1].time;
118 if current_time >= last_fork_time.saturating_add(FORKED_TIME) {
119 HardForkState::LikelyForked
120 } else if current_time >= last_fork_time.saturating_add(UPDATE_TIME) {
121 HardForkState::UpdateNeeded
122 } else {
123 HardForkState::Ready
124 }
125 }
126
127 pub const fn main_net() -> Self {
131 Self([
132 HFInfo::new(0, 0, 1341378000),
133 HFInfo::new(1009827, 0, 1442763710),
134 HFInfo::new(1141317, 0, 1458558528),
135 HFInfo::new(1220516, 0, 1483574400),
136 HFInfo::new(1288616, 0, 1489520158),
137 HFInfo::new(1400000, 0, 1503046577),
138 HFInfo::new(1546000, 0, 1521303150),
139 HFInfo::new(1685555, 0, 1535889547),
140 HFInfo::new(1686275, 0, 1535889548),
141 HFInfo::new(1788000, 0, 1549792439),
142 HFInfo::new(1788720, 0, 1550225678),
143 HFInfo::new(1978433, 0, 1571419280),
144 HFInfo::new(2210000, 0, 1598180817),
145 HFInfo::new(2210720, 0, 1598180818),
146 HFInfo::new(2688888, 0, 1656629117),
147 HFInfo::new(2689608, 0, 1656629118),
148 ])
149 }
150
151 pub const fn test_net() -> Self {
155 Self([
156 HFInfo::new(0, 0, 1341378000),
157 HFInfo::new(624634, 0, 1445355000),
158 HFInfo::new(800500, 0, 1472415034),
159 HFInfo::new(801219, 0, 1472415035),
160 HFInfo::new(802660, 0, 1472415036 + 86400 * 180),
161 HFInfo::new(971400, 0, 1501709789),
162 HFInfo::new(1057027, 0, 1512211236),
163 HFInfo::new(1057058, 0, 1533211200),
164 HFInfo::new(1057778, 0, 1533297600),
165 HFInfo::new(1154318, 0, 1550153694),
166 HFInfo::new(1155038, 0, 1550225678),
167 HFInfo::new(1308737, 0, 1569582000),
168 HFInfo::new(1543939, 0, 1599069376),
169 HFInfo::new(1544659, 0, 1599069377),
170 HFInfo::new(1982800, 0, 1652727000),
171 HFInfo::new(1983520, 0, 1652813400),
172 ])
173 }
174
175 pub const fn fake_chain() -> Self {
179 let mut hfs = [HFInfo::new(1, 0, 0); NUMB_OF_HARD_FORKS];
180 hfs[0] = HFInfo::new(0, 0, 0);
181 Self(hfs)
182 }
183
184 pub const fn stage_net() -> Self {
188 Self([
189 HFInfo::new(0, 0, 1341378000),
190 HFInfo::new(32000, 0, 1521000000),
191 HFInfo::new(33000, 0, 1521120000),
192 HFInfo::new(34000, 0, 1521240000),
193 HFInfo::new(35000, 0, 1521360000),
194 HFInfo::new(36000, 0, 1521480000),
195 HFInfo::new(37000, 0, 1521600000),
196 HFInfo::new(176456, 0, 1537821770),
197 HFInfo::new(177176, 0, 1537821771),
198 HFInfo::new(269000, 0, 1550153694),
199 HFInfo::new(269720, 0, 1550225678),
200 HFInfo::new(454721, 0, 1571419280),
201 HFInfo::new(675405, 0, 1598180817),
202 HFInfo::new(676125, 0, 1598180818),
203 HFInfo::new(1151000, 0, 1656629117),
204 HFInfo::new(1151720, 0, 1656629118),
205 ])
206 }
207}
208
209#[derive(Debug, Clone, Eq, PartialEq)]
211pub struct HFVotes {
212 votes: [usize; NUMB_OF_HARD_FORKS],
213 vote_list: VecDeque<HardFork>,
214 window_size: usize,
215}
216
217impl Display for HFVotes {
218 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
219 f.debug_struct("HFVotes")
220 .field("total", &self.total_votes())
221 .field("V1", &self.votes_for_hf(&HardFork::V1))
222 .field("V2", &self.votes_for_hf(&HardFork::V2))
223 .field("V3", &self.votes_for_hf(&HardFork::V3))
224 .field("V4", &self.votes_for_hf(&HardFork::V4))
225 .field("V5", &self.votes_for_hf(&HardFork::V5))
226 .field("V6", &self.votes_for_hf(&HardFork::V6))
227 .field("V7", &self.votes_for_hf(&HardFork::V7))
228 .field("V8", &self.votes_for_hf(&HardFork::V8))
229 .field("V9", &self.votes_for_hf(&HardFork::V9))
230 .field("V10", &self.votes_for_hf(&HardFork::V10))
231 .field("V11", &self.votes_for_hf(&HardFork::V11))
232 .field("V12", &self.votes_for_hf(&HardFork::V12))
233 .field("V13", &self.votes_for_hf(&HardFork::V13))
234 .field("V14", &self.votes_for_hf(&HardFork::V14))
235 .field("V15", &self.votes_for_hf(&HardFork::V15))
236 .field("V16", &self.votes_for_hf(&HardFork::V16))
237 .finish()
238 }
239}
240
241impl HFVotes {
242 pub fn new(window_size: usize) -> Self {
243 Self {
244 votes: [0; NUMB_OF_HARD_FORKS],
245 vote_list: VecDeque::with_capacity(window_size),
246 window_size,
247 }
248 }
249
250 pub fn add_vote_for_hf(&mut self, hf: &HardFork) {
252 self.vote_list.push_back(*hf);
253 self.votes[*hf as usize - 1] += 1;
254 if self.vote_list.len() > self.window_size {
255 let hf = self.vote_list.pop_front().unwrap();
256 self.votes[hf as usize - 1] -= 1;
257 }
258 }
259
260 pub fn reverse_blocks(&mut self, numb_blocks: usize, old_block_votes: Self) {
270 assert!(old_block_votes.vote_list.len() <= numb_blocks);
271
272 for hf in self.vote_list.drain(self.vote_list.len() - numb_blocks..) {
273 self.votes[hf as usize - 1] -= 1;
274 }
275
276 for old_vote in old_block_votes.vote_list.into_iter().rev() {
277 self.vote_list.push_front(old_vote);
278 self.votes[old_vote as usize - 1] += 1;
279 }
280 }
281
282 pub fn votes_for_hf(&self, hf: &HardFork) -> usize {
286 self.votes[*hf as usize - 1..].iter().sum()
287 }
288
289 pub fn total_votes(&self) -> usize {
291 self.vote_list.len()
292 }
293
294 pub fn current_fork(
299 &self,
300 current_hf: &HardFork,
301 current_height: usize,
302 window: usize,
303 hfs_info: &HFsInfo,
304 ) -> HardFork {
305 let mut current_hf = *current_hf;
306
307 while let Some(next_hf) = current_hf.next_fork() {
308 let hf_info = hfs_info.info_for_hf(&next_hf);
309 if current_height >= hf_info.height
310 && self.votes_for_hf(&next_hf) >= votes_needed(hf_info.threshold, window)
311 {
312 current_hf = next_hf;
313 } else {
314 return current_hf;
319 }
320 }
321 current_hf
322 }
323}
324
325pub const fn votes_needed(threshold: usize, window: usize) -> usize {
329 (threshold * window).div_ceil(100)
330}