1use crate::hashes::{Blake3Hash, blake3_hash, blake3_hash_list};
4use crate::pieces::RecordChunk;
5use core::fmt;
6use core::iter::Step;
7use core::num::NonZeroU8;
8use core::str::FromStr;
9use core::time::Duration;
10use derive_more::{
11 Add, AddAssign, AsMut, AsRef, Deref, DerefMut, Display, Div, DivAssign, From, Into, Mul,
12 MulAssign, Sub, SubAssign,
13};
14#[cfg(feature = "scale-codec")]
15use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
16#[cfg(feature = "scale-codec")]
17use scale_info::TypeInfo;
18#[cfg(feature = "serde")]
19use serde::{Deserialize, Serialize};
20#[cfg(feature = "serde")]
21use serde::{Deserializer, Serializer};
22
23#[derive(
25 Debug, Display, Default, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, From, Into,
26)]
27#[cfg_attr(
28 feature = "scale-codec",
29 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
30)]
31#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
32#[repr(transparent)]
33pub struct SlotDuration(u16);
34
35impl SlotDuration {
36 pub const SIZE: usize = size_of::<u16>();
38
39 #[inline(always)]
41 pub const fn from_millis(n: u16) -> Self {
42 Self(n)
43 }
44
45 #[inline(always)]
47 pub const fn as_millis(self) -> u16 {
48 self.0
49 }
50
51 #[inline(always)]
53 pub const fn as_duration(self) -> Duration {
54 Duration::from_millis(self.as_millis() as u64)
55 }
56}
57
58#[derive(
60 Debug,
61 Display,
62 Default,
63 Copy,
64 Clone,
65 Ord,
66 PartialOrd,
67 Eq,
68 PartialEq,
69 Hash,
70 From,
71 Into,
72 Add,
73 AddAssign,
74 Sub,
75 SubAssign,
76 Mul,
77 MulAssign,
78 Div,
79 DivAssign,
80)]
81#[cfg_attr(
82 feature = "scale-codec",
83 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
84)]
85#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
86#[repr(transparent)]
87pub struct SlotNumber(u64);
88
89impl Step for SlotNumber {
90 #[inline(always)]
91 fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
92 u64::steps_between(&start.0, &end.0)
93 }
94
95 #[inline(always)]
96 fn forward_checked(start: Self, count: usize) -> Option<Self> {
97 u64::forward_checked(start.0, count).map(Self)
98 }
99
100 #[inline(always)]
101 fn backward_checked(start: Self, count: usize) -> Option<Self> {
102 u64::backward_checked(start.0, count).map(Self)
103 }
104}
105
106impl From<SlotNumber> for u128 {
107 #[inline(always)]
108 fn from(original: SlotNumber) -> Self {
109 u128::from(original.0)
110 }
111}
112
113impl SlotNumber {
114 pub const SIZE: usize = size_of::<u64>();
116 pub const ZERO: Self = Self(0);
118 pub const ONE: Self = Self(1);
120 pub const MAX: Self = Self(u64::MAX);
122
123 #[inline(always)]
125 pub const fn new(n: u64) -> Self {
126 Self(n)
127 }
128
129 #[inline(always)]
131 pub const fn as_u64(self) -> u64 {
132 self.0
133 }
134
135 #[inline(always)]
137 pub const fn from_bytes(bytes: [u8; Self::SIZE]) -> Self {
138 Self(u64::from_le_bytes(bytes))
139 }
140
141 #[inline(always)]
143 pub const fn to_bytes(self) -> [u8; Self::SIZE] {
144 self.0.to_le_bytes()
145 }
146
147 #[inline]
149 pub fn checked_add(self, rhs: Self) -> Option<Self> {
150 self.0.checked_add(rhs.0).map(Self)
151 }
152
153 #[inline]
155 pub fn checked_sub(self, rhs: Self) -> Option<Self> {
156 self.0.checked_sub(rhs.0).map(Self)
157 }
158}
159
160#[derive(Default, Copy, Clone, Eq, PartialEq, From, Into, AsRef, AsMut, Deref, DerefMut)]
162#[cfg_attr(
163 feature = "scale-codec",
164 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
165)]
166pub struct PotKey([u8; PotKey::SIZE]);
167
168impl fmt::Debug for PotKey {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 for byte in self.0 {
171 write!(f, "{byte:02x}")?;
172 }
173 Ok(())
174 }
175}
176
177#[cfg(feature = "serde")]
178#[derive(Serialize, Deserialize)]
179#[serde(transparent)]
180struct PotKeyBinary([u8; PotKey::SIZE]);
181
182#[cfg(feature = "serde")]
183#[derive(Serialize, Deserialize)]
184#[serde(transparent)]
185struct PotKeyHex(#[serde(with = "hex")] [u8; PotKey::SIZE]);
186
187#[cfg(feature = "serde")]
188impl Serialize for PotKey {
189 #[inline]
190 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
191 where
192 S: Serializer,
193 {
194 if serializer.is_human_readable() {
195 PotKeyHex(self.0).serialize(serializer)
196 } else {
197 PotKeyBinary(self.0).serialize(serializer)
198 }
199 }
200}
201
202#[cfg(feature = "serde")]
203impl<'de> Deserialize<'de> for PotKey {
204 #[inline]
205 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
206 where
207 D: Deserializer<'de>,
208 {
209 Ok(Self(if deserializer.is_human_readable() {
210 PotKeyHex::deserialize(deserializer)?.0
211 } else {
212 PotKeyBinary::deserialize(deserializer)?.0
213 }))
214 }
215}
216
217impl fmt::Display for PotKey {
218 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219 for byte in self.0 {
220 write!(f, "{byte:02x}")?;
221 }
222 Ok(())
223 }
224}
225
226impl FromStr for PotKey {
227 type Err = hex::FromHexError;
228
229 #[inline]
230 fn from_str(s: &str) -> Result<Self, Self::Err> {
231 let mut key = Self::default();
232 hex::decode_to_slice(s, key.as_mut())?;
233
234 Ok(key)
235 }
236}
237
238impl PotKey {
239 pub const SIZE: usize = 16;
241}
242
243#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, From, Into, AsRef, AsMut, Deref, DerefMut)]
245#[cfg_attr(
246 feature = "scale-codec",
247 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
248)]
249pub struct PotSeed([u8; PotSeed::SIZE]);
250
251impl fmt::Debug for PotSeed {
252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253 for byte in self.0 {
254 write!(f, "{byte:02x}")?;
255 }
256 Ok(())
257 }
258}
259
260#[cfg(feature = "serde")]
261#[derive(Serialize, Deserialize)]
262#[serde(transparent)]
263struct PotSeedBinary([u8; PotSeed::SIZE]);
264
265#[cfg(feature = "serde")]
266#[derive(Serialize, Deserialize)]
267#[serde(transparent)]
268struct PotSeedHex(#[serde(with = "hex")] [u8; PotSeed::SIZE]);
269
270#[cfg(feature = "serde")]
271impl Serialize for PotSeed {
272 #[inline]
273 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
274 where
275 S: Serializer,
276 {
277 if serializer.is_human_readable() {
278 PotSeedHex(self.0).serialize(serializer)
279 } else {
280 PotSeedBinary(self.0).serialize(serializer)
281 }
282 }
283}
284
285#[cfg(feature = "serde")]
286impl<'de> Deserialize<'de> for PotSeed {
287 #[inline]
288 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
289 where
290 D: Deserializer<'de>,
291 {
292 Ok(Self(if deserializer.is_human_readable() {
293 PotSeedHex::deserialize(deserializer)?.0
294 } else {
295 PotSeedBinary::deserialize(deserializer)?.0
296 }))
297 }
298}
299
300impl fmt::Display for PotSeed {
301 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
302 for byte in self.0 {
303 write!(f, "{byte:02x}")?;
304 }
305 Ok(())
306 }
307}
308
309impl PotSeed {
310 pub const SIZE: usize = 16;
312
313 #[inline]
315 pub fn from_genesis(genesis_block_hash: &[u8], external_entropy: &[u8]) -> Self {
316 let hash = blake3_hash_list(&[genesis_block_hash, external_entropy]);
317 let mut seed = Self::default();
318 seed.copy_from_slice(&hash[..Self::SIZE]);
319 seed
320 }
321
322 #[inline]
324 pub fn key(&self) -> PotKey {
325 let mut key = PotKey::default();
326 key.copy_from_slice(&blake3_hash(&self.0)[..Self::SIZE]);
327 key
328 }
329}
330
331#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, From, Into, AsRef, AsMut, Deref, DerefMut)]
333#[cfg_attr(
334 feature = "scale-codec",
335 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
336)]
337pub struct PotOutput([u8; PotOutput::SIZE]);
338
339impl fmt::Debug for PotOutput {
340 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
341 for byte in self.0 {
342 write!(f, "{byte:02x}")?;
343 }
344 Ok(())
345 }
346}
347
348#[cfg(feature = "serde")]
349#[derive(Serialize, Deserialize)]
350#[serde(transparent)]
351struct PotOutputBinary([u8; PotOutput::SIZE]);
352
353#[cfg(feature = "serde")]
354#[derive(Serialize, Deserialize)]
355#[serde(transparent)]
356struct PotOutputHex(#[serde(with = "hex")] [u8; PotOutput::SIZE]);
357
358#[cfg(feature = "serde")]
359impl Serialize for PotOutput {
360 #[inline]
361 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
362 where
363 S: Serializer,
364 {
365 if serializer.is_human_readable() {
366 PotOutputHex(self.0).serialize(serializer)
367 } else {
368 PotOutputBinary(self.0).serialize(serializer)
369 }
370 }
371}
372
373#[cfg(feature = "serde")]
374impl<'de> Deserialize<'de> for PotOutput {
375 #[inline]
376 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
377 where
378 D: Deserializer<'de>,
379 {
380 Ok(Self(if deserializer.is_human_readable() {
381 PotOutputHex::deserialize(deserializer)?.0
382 } else {
383 PotOutputBinary::deserialize(deserializer)?.0
384 }))
385 }
386}
387
388impl fmt::Display for PotOutput {
389 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
390 for byte in self.0 {
391 write!(f, "{byte:02x}")?;
392 }
393 Ok(())
394 }
395}
396
397impl PotOutput {
398 pub const SIZE: usize = 16;
400
401 #[inline]
403 pub fn derive_global_challenge(&self, slot: SlotNumber) -> Blake3Hash {
404 blake3_hash_list(&[&self.0, &slot.to_bytes()])
405 }
406
407 #[inline]
409 pub fn seed(&self) -> PotSeed {
410 PotSeed(self.0)
411 }
412
413 #[inline]
415 pub fn seed_with_entropy(&self, entropy: &Blake3Hash) -> PotSeed {
416 let hash = blake3_hash_list(&[entropy.as_ref(), &self.0]);
417 let mut seed = PotSeed::default();
418 seed.copy_from_slice(&hash[..Self::SIZE]);
419 seed
420 }
421
422 #[inline]
424 pub fn derive_pot_entropy(&self, solution_chunk: &RecordChunk) -> Blake3Hash {
425 blake3_hash_list(&[solution_chunk.as_ref(), &self.0])
426 }
427}
428
429#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Deref, DerefMut)]
431#[cfg_attr(
432 feature = "scale-codec",
433 derive(Encode, Decode, TypeInfo, MaxEncodedLen)
434)]
435pub struct PotCheckpoints([PotOutput; PotCheckpoints::NUM_CHECKPOINTS.get() as usize]);
436
437impl PotCheckpoints {
438 pub const NUM_CHECKPOINTS: NonZeroU8 = NonZeroU8::new(8).expect("Not zero; qed");
440
441 #[inline]
443 pub fn output(&self) -> PotOutput {
444 self.0[Self::NUM_CHECKPOINTS.get() as usize - 1]
445 }
446}